diff --git a/.gn b/.gn index 7940a2e..0c36ec4 100644 --- a/.gn +++ b/.gn
@@ -80,6 +80,7 @@ "//testing/*", #"//third_party/*", # May not ever want this. + "//third_party/kasko/*", "//third_party/WebKit/Source/*", "//tools/*",
diff --git a/DEPS b/DEPS index 0b58cf0..5830ad3c 100644 --- a/DEPS +++ b/DEPS
@@ -39,11 +39,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': '5423ee17ed5a1becd0aeaa89d8faaaa5e2696cbb', + 'skia_revision': '3061af4a5f2b8ef00fc4a34b04cf99dfb780f1a1', # 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': '10096e649fa353ed7526cbf7ff5e60ba32d99ed8', + 'v8_revision': '9c547f806b7b8c1be770bcb6608e631d291d39aa', # 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. @@ -51,7 +51,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'e1743f37a9844a7b315c1703d4cf94bd3fce46ca', + 'angle_revision': '539146e1b65f7bea639a6e7e938b893bf6670b90', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -220,7 +220,7 @@ Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248 'src/third_party/libyuv': - Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '1ccbf8fb7b1d84d37eabb26de933f841daf0ade7', # from version 1557 + Var('chromium_git') + '/libyuv/libyuv.git' + '@' + 'fc52d8ded269e9cd40c7a763e36758a08f177da0', # from version 1563 'src/third_party/smhasher/src': Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f', @@ -271,7 +271,7 @@ 'src/third_party/catapult': Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' + - 'b80c94349cc85fcc8490d2d01c32c8dbd6e794bc', + '5bb87c077c8030b35fa344d553ddd7d41b49ba71', 'src/third_party/openh264/src': Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488',
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS index 45a102a..30b7aca 100644 --- a/android_webview/browser/DEPS +++ b/android_webview/browser/DEPS
@@ -13,6 +13,7 @@ "+components/autofill/core/browser", "+components/autofill/core/common", "+components/cdm/browser", + "+components/crash/content/browser", "+components/data_reduction_proxy/core/browser", "+components/navigation_interception", "+components/policy/core/browser",
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc index 04d9c68..ff72061 100644 --- a/android_webview/browser/aw_browser_main_parts.cc +++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -18,6 +18,7 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/path_service.h" +#include "components/crash/content/browser/crash_micro_dump_manager_android.h" #include "content/public/browser/android/synchronous_compositor.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" @@ -75,6 +76,11 @@ base::android::MemoryPressureListenerAndroid::RegisterSystemCallback( base::android::AttachCurrentThread()); DeferredGpuCommandService::SetInstance(); + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSingleProcess)) { + // Create the renderers crash manager on the UI thread. + breakpad::CrashMicroDumpManager::GetInstance(); + } return content::RESULT_CODE_NORMAL_EXIT; }
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index 23052380..5c3aaf9 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -26,8 +26,10 @@ #include "base/android/locale_utils.h" #include "base/base_paths_android.h" #include "base/command_line.h" +#include "base/files/scoped_file.h" #include "base/path_service.h" #include "components/cdm/browser/cdm_message_filter_android.h" +#include "components/crash/content/browser/crash_micro_dump_manager_android.h" #include "components/navigation_interception/intercept_navigation_delegate.h" #include "content/public/browser/access_token_store.h" #include "content/public/browser/browser_message_filter.h" @@ -433,9 +435,15 @@ } bool AwContentBrowserClient::IsFastShutdownPossible() { - NOTREACHED() << "Android WebView is single process, so IsFastShutdownPossible" - << " should never be called"; - return false; + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSingleProcess)) { + NOTREACHED() + << "Android WebView is single process, so IsFastShutdownPossible" + << " should never be called"; + return false; + } else { + return true; + } } void AwContentBrowserClient::ClearCache(content::RenderFrameHost* rfh) { @@ -487,6 +495,14 @@ fd = ui::GetLocalePackFd(&(*regions)[kAndroidWebViewLocalePakDescriptor]); mappings->Share(kAndroidWebViewLocalePakDescriptor, fd); + + base::ScopedFD crash_signal_file = + breakpad::CrashMicroDumpManager::GetInstance()->CreateCrashInfoChannel( + child_process_id); + if (crash_signal_file.is_valid()) { + mappings->Transfer(kAndroidWebViewCrashSignalDescriptor, + std::move(crash_signal_file)); + } } void AwContentBrowserClient::OverrideWebkitPrefs(
diff --git a/android_webview/common/aw_descriptors.h b/android_webview/common/aw_descriptors.h index 1b2a12b0..a3f22af4 100644 --- a/android_webview/common/aw_descriptors.h +++ b/android_webview/common/aw_descriptors.h
@@ -10,6 +10,7 @@ enum { kAndroidWebViewLocalePakDescriptor = kContentIPCDescriptorMax + 1, kAndroidWebViewMainPakDescriptor, + kAndroidWebViewCrashSignalDescriptor, }; #endif // ANDROID_WEBVIEW_COMMON_AW_DESCRIPTORS_H_
diff --git a/android_webview/crash_reporter/aw_microdump_crash_reporter.cc b/android_webview/crash_reporter/aw_microdump_crash_reporter.cc index aac36e8..af5c07c 100644 --- a/android_webview/crash_reporter/aw_microdump_crash_reporter.cc +++ b/android_webview/crash_reporter/aw_microdump_crash_reporter.cc
@@ -13,6 +13,7 @@ #include "build/build_config.h" #include "components/crash/content/app/breakpad_linux.h" #include "components/crash/content/app/crash_reporter_client.h" +#include "content/public/common/content_switches.h" namespace android_webview { namespace crash_reporter { @@ -23,6 +24,9 @@ public: AwCrashReporterClient() : dump_fd_(-1) {} + // Does not use lock, can only be called immediately after creation. + void set_crash_signal_fd(int fd) { dump_fd_ = fd; } + // crash_reporter::CrashReporterClient implementation. bool IsRunningUnattended() override { return false; } bool GetCollectStatsConsent() override { return false; } @@ -40,6 +44,7 @@ int GetAndroidMinidumpDescriptor() override { return dump_fd_; } bool DumpWithoutCrashingToFd(int fd) { + DCHECK(dump_fd_ == -1); base::AutoLock lock(dump_lock_); dump_fd_ = fd; base::debug::DumpWithoutCrashing(); @@ -109,7 +114,8 @@ } // namespace -void EnableMicrodumpCrashReporter(const std::string& process_type) { +void EnableMicrodumpCrashReporter(const std::string& process_type, + int crash_signal_fd) { if (g_enabled) { NOTREACHED() << "EnableMicrodumpCrashReporter called more than once"; return; @@ -122,7 +128,11 @@ } #endif - ::crash_reporter::SetCrashReporterClient(g_crash_reporter_client.Pointer()); + AwCrashReporterClient* client = g_crash_reporter_client.Pointer(); + if (process_type == switches::kRendererProcess && crash_signal_fd != -1) { + client->set_crash_signal_fd(crash_signal_fd); + } + ::crash_reporter::SetCrashReporterClient(client); breakpad::InitMicrodumpCrashHandlerIfNecessary(process_type); g_enabled = true;
diff --git a/android_webview/crash_reporter/aw_microdump_crash_reporter.h b/android_webview/crash_reporter/aw_microdump_crash_reporter.h index ae567a8a..33dcc344 100644 --- a/android_webview/crash_reporter/aw_microdump_crash_reporter.h +++ b/android_webview/crash_reporter/aw_microdump_crash_reporter.h
@@ -10,7 +10,8 @@ namespace android_webview { namespace crash_reporter { -void EnableMicrodumpCrashReporter(const std::string& process_type); +void EnableMicrodumpCrashReporter(const std::string& process_type, + int crash_signal_fd); void AddGpuFingerprintToMicrodumpCrashHandler( const std::string& gpu_fingerprint); bool DumpWithoutCrashingToFd(int fd);
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc index c9340ff8..7025687 100644 --- a/android_webview/lib/main/aw_main_delegate.cc +++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -141,6 +141,7 @@ if (cl->HasSwitch(switches::kWebViewSandboxedRenderer)) { cl->AppendSwitch(switches::kInProcessGPU); cl->AppendSwitchASCII(switches::kRendererProcessLimit, "1"); + cl->AppendSwitch(switches::kDisableRendererBackgrounding); } return false; @@ -157,6 +158,7 @@ *base::CommandLine::ForCurrentProcess(); std::string process_type = command_line.GetSwitchValueASCII(switches::kProcessType); + int crash_signal_fd = -1; if (process_type == switches::kRendererProcess) { auto global_descriptors = base::GlobalDescriptors::GetInstance(); int pak_fd = global_descriptors->Get(kAndroidWebViewLocalePakDescriptor); @@ -169,6 +171,8 @@ global_descriptors->GetRegion(kAndroidWebViewMainPakDescriptor); ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion( base::File(pak_fd), pak_region, ui::SCALE_FACTOR_NONE); + crash_signal_fd = + global_descriptors->Get(kAndroidWebViewCrashSignalDescriptor); } if (process_type.empty() && command_line.HasSwitch(switches::kSingleProcess)) { @@ -176,7 +180,7 @@ process_type = "webview"; } - crash_reporter::EnableMicrodumpCrashReporter(process_type); + crash_reporter::EnableMicrodumpCrashReporter(process_type, crash_signal_fd); } int AwMainDelegate::RunProcess(
diff --git a/base/win/win_util.cc b/base/win/win_util.cc index 9e90d10c..a37e0f27 100644 --- a/base/win/win_util.cc +++ b/base/win/win_util.cc
@@ -101,6 +101,12 @@ L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}" L"\\LocalServer32"; +// Returns the current platform role. We use the PowerDeterminePlatformRoleEx +// API for that. +POWER_PLATFORM_ROLE GetPlatformRole() { + return PowerDeterminePlatformRoleEx(POWER_PLATFORM_ROLE_V2); +} + } // namespace // Returns true if a physical keyboard is detected on Windows 8 and up. @@ -111,7 +117,7 @@ bool IsKeyboardPresentOnSlate(std::string* reason) { bool result = false; - if (GetVersion() < VERSION_WIN7) { + if (GetVersion() < VERSION_WIN8) { *reason = "Detection not supported"; return false; } @@ -135,10 +141,13 @@ } } - // If the device is docked, the user is treating the device as a PC. - if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) { + if (IsTabletDevice(reason)) { + if (reason) + *reason += "Tablet device.\n"; + return true; + } else { if (reason) { - *reason += "SM_SYSTEMDOCKED\n"; + *reason += "Not a tablet device"; result = true; } else { return true; @@ -184,23 +193,6 @@ } } - // Check if the device is being used as a laptop or a tablet. This can be - // checked by first checking the role of the device and then the - // corresponding system metric (SM_CONVERTIBLESLATEMODE). If it is being used - // as a tablet then we want the OSK to show up. - POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole(); - - if (((role == PlatformRoleMobile) || (role == PlatformRoleSlate)) && - (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0)) { - if (reason) { - *reason += (role == PlatformRoleMobile) ? "PlatformRoleMobile\n" : - "PlatformRoleSlate\n"; - // Don't change result here if it's already true. - } else { - return false; - } - } - const GUID KEYBOARD_CLASS_GUID = { 0x4D36E96B, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }; @@ -392,30 +384,56 @@ signal(SIGABRT, ForceCrashOnSigAbort); } -bool IsTabletDevice() { - if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0) +bool IsTabletDevice(std::string* reason) { + if (GetVersion() < VERSION_WIN8) { + if (reason) + *reason = "Tablet device detection not supported below Windows 8\n"; return false; + } - Version version = GetVersion(); - if (version == VERSION_XP) - return (GetSystemMetrics(SM_TABLETPC) != 0); + if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0) { + if (reason) { + *reason += "Device does not support touch.\n"; + } else { + return false; + } + } // If the device is docked, the user is treating the device as a PC. - if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) - return false; + if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) { + if (reason) { + *reason += "SM_SYSTEMDOCKED\n"; + } else { + return false; + } + } - // PlatformRoleSlate was only added in Windows 8, but prior to Win8 it is - // still possible to check for a mobile power profile. - POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole(); + // PlatformRoleSlate was added in Windows 8+. + POWER_PLATFORM_ROLE role = GetPlatformRole(); bool mobile_power_profile = (role == PlatformRoleMobile); - bool slate_power_profile = false; - if (version >= VERSION_WIN8) - slate_power_profile = (role == PlatformRoleSlate); + bool slate_power_profile = (role == PlatformRoleSlate); - if (mobile_power_profile || slate_power_profile) - return (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0); + bool is_tablet = false; - return false; + if (mobile_power_profile || slate_power_profile) { + is_tablet = !GetSystemMetrics(SM_CONVERTIBLESLATEMODE); + if (!is_tablet) { + if (reason) { + *reason += "Not in slate mode.\n"; + } else { + return false; + } + } else { + if (reason) { + *reason += (role == PlatformRoleMobile) ? "PlatformRoleMobile\n" : + "PlatformRoleSlate\n"; + } + } + } else { + if (reason) + *reason += "Device role is not mobile or slate.\n"; + } + return is_tablet; } bool DisplayVirtualKeyboard() {
diff --git a/base/win/win_util.h b/base/win/win_util.h index 78a06085..6162b51 100644 --- a/base/win/win_util.h +++ b/base/win/win_util.h
@@ -123,9 +123,14 @@ BASE_EXPORT void SetAbortBehaviorForCrashReporting(); // A tablet is a device that is touch enabled and also is being used -// "like a tablet". This is used primarily for metrics in order to gain some -// insight into how users use Chrome. -BASE_EXPORT bool IsTabletDevice(); +// "like a tablet". This is used by the following:- +// 1. Metrics:- To gain insight into how users use Chrome. +// 2. Physical keyboard presence :- If a device is in tablet mode, it means +// that there is no physical keyboard attached. +// This function optionally sets the |reason| parameter to determine as to why +// or why not a device was deemed to be a tablet. +// Returns true if the device is in tablet mode. +BASE_EXPORT bool IsTabletDevice(std::string* reason); // A slate is a touch device that may have a keyboard attached. This function // returns true if a keyboard is attached and optionally will set the reason
diff --git a/blimp/engine/Dockerfile b/blimp/engine/Dockerfile index 344809b..d939115 100644 --- a/blimp/engine/Dockerfile +++ b/blimp/engine/Dockerfile
@@ -2,12 +2,10 @@ # Run the command below to update the lib list. # ldd ./blimp_engine_app | grep usr/lib | awk '{print $3}' | xargs -n1 \ -# dpkg-query -S | awk -F: '{print $1}' +# dpkg-query -S | awk -F: '{print $1}' | sort | uniq RUN apt-get update && \ - apt-get install -yq libnss3 libnss3 libnss3 libnspr4 libnspr4 libnspr4 \ - libfreetype6 libfontconfig1 libdrm2 libasound2 libcups2 libgssapi-krb5-2 \ - libkrb5-3 libk5crypto3 libstdc++6 libgnutls26 libavahi-common3 \ - libavahi-client3 libkrb5support0 libtasn1-6 libp11-kit0 libffi6 + apt-get install -yq libdrm2 libfontconfig1 libfreetype6 libgraphite2-3 \ + libharfbuzz0b libnspr4 libnss3 libstdc++6 RUN mkdir /engine
diff --git a/build/android/adb_gdb b/build/android/adb_gdb index 361f1bf8..d6de00c 100755 --- a/build/android/adb_gdb +++ b/build/android/adb_gdb
@@ -21,11 +21,6 @@ # Location of Chromium-top-level sources. CHROMIUM_SRC=$(cd "$PROGDIR"/../.. >/dev/null && pwd 2>/dev/null) -# Location of Chromium out/ directory. -if [ -z "$CHROMIUM_OUT_DIR" ]; then - CHROMIUM_OUT_DIR=out -fi - TMPDIR= GDBSERVER_PIDFILE= TARGET_GDBSERVER= @@ -189,6 +184,9 @@ --symbol-dir=*) SYMBOL_DIR=$optarg ;; + --output-dir=*) + CHROMIUM_OUTPUT_DIR=$optarg + ;; --out-dir=*) CHROMIUM_OUT_DIR=$optarg ;; @@ -223,11 +221,6 @@ esac done -print_help_options () { - cat <<EOF -EOF -} - if [ "$HELP" ]; then if [ "$ADB_GDB_PROGNAME" ]; then # Assume wrapper scripts all provide a default package name. @@ -269,13 +262,11 @@ The script tries to find the most recent version of the debug version of shared libraries under one of the following directories: - \$CHROMIUM_SRC/<out>/Release/lib/ (used by GYP builds) - \$CHROMIUM_SRC/<out>/Debug/lib/ (used by GYP builds) - \$CHROMIUM_SRC/<out>/Release/lib.unstripped/ (used by GN builds) - \$CHROMIUM_SRC/<out>/Debug/lib.unstripped/ (used by GN builds) + \$CHROMIUM_SRC/<out>/lib/ (used by GYP builds) + \$CHROMIUM_SRC/<out>/lib.unstripped/ (used by GN builds) -Where <out> is 'out' by default, unless the --out=<name> option is used or -the CHROMIUM_OUT_DIR environment variable is defined. +Where <out> is 'out' is determined by CHROMIUM_OUT_DIR, CHROMIUM_OUTPUT_DIR, or +the --out-dir, --output-dir flags. You can restrict this search by using --release or --debug to specify the build type, or simply use --symbol-dir=<path> to specify the file manually. @@ -319,7 +310,8 @@ --sandboxed Debug first sandboxed process we find. --sandboxed=<num> Debug specific sandboxed process. --symbol-dir=<path> Specify directory with symbol shared libraries. - --out-dir=<path> Specify the out directory. + --out-dir=<path> Specify the out directory (e.g. "out"). + --output-dir=<path> Specify the output directory (e.g. "out/Debug"). --package-name=<name> Specify package name (alternative to 1st argument). --privileged Debug first privileged process we find. --privileged=<num> Debug specific privileged process. @@ -703,25 +695,37 @@ # Detect the build type and symbol directory. This is done by finding # the most recent sub-directory containing debug shared libraries under -# $CHROMIUM_SRC/$CHROMIUM_OUT_DIR/ +# (in order of priority): +# 1. $CHROMIUM_OUTPUT_DIR +# 2. $CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$BUILDTYPE (if $BUILDTYPE is set) +# 3. $CHROMIUM_SRC/$CHROMIUM_OUT_DIR/{Debug,Release} # -# $1: $BUILDTYPE value, can be empty # Out: nothing, but this sets SYMBOL_DIR # detect_symbol_dir () { - local SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP + local PARENT_DIR SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP # GYP places unstripped libraries under out/$BUILDTYPE/lib # GN places them under out/$BUILDTYPE/lib.unstripped - if [ "$1" ]; then - SUBDIRS="$1/lib $1/lib.unstripped" + if [[ -n "$CHROMIUM_OUTPUT_DIR" ]]; then + PARENT_DIR="$CHROMIUM_OUTPUT_DIR" + SUBDIRS="lib.unstripped lib" else - SUBDIRS="Release/lib Debug/lib" - SUBDIRS+=" Release/lib.unstripped Debug/lib.unstripped" + PARENT_DIR="$CHROMIUM_OUT_DIR" + if [[ -n "$BUILDTYPE" ]]; then + PARENT_DIR="$PARENT_DIR/$BUILDTYPE" + SUBDIRS="lib.unstripped lib" + else + SUBDIRS="Release/lib.unstripped Debug/lib.unstripped " + SUBDIRS+="Release/lib Debug/lib" + fi + fi + if [[ ! -e "$PARENT_DIR" ]]; then + PARENT_DIR="$CHROMIUM_SRC/$PARENT_DIR" fi LIST=$TMPDIR/scan-subdirs-$$.txt printf "" > "$LIST" for SUBDIR in $SUBDIRS; do - DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR + DIR="$PARENT_DIR/$SUBDIR" if [ -d "$DIR" ]; then # Ignore build directories that don't contain symbol versions # of the shared libraries. @@ -737,22 +741,17 @@ SUBDIR=$(cat $LIST | sort -r | head -1 | cut -d" " -f2) rm -f "$LIST" - if [ -z "$SUBDIR" ]; then - if [ -z "$1" ]; then - panic "Could not find any build directory under \ -$CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Please build the program first!" - else - panic "Could not find any $1 directory under \ -$CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Check your build type!" - fi + if [[ -z "$SUBDIR" ]]; then + panic "Could not find any build directory under \ +$PARENT_DIR/{${SUBDIRS// /,}}. Please build the program first!" fi - SYMBOL_DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR + SYMBOL_DIR=$PARENT_DIR/$SUBDIR log "Auto-config: --symbol-dir=$SYMBOL_DIR" } if [ -z "$SYMBOL_DIR" ]; then - detect_symbol_dir "$BUILDTYPE" + detect_symbol_dir fi # Allow several concurrent debugging sessions
diff --git a/build/android/devil_chromium.py b/build/android/devil_chromium.py index 2ebad4d..c7142ed6 100644 --- a/build/android/devil_chromium.py +++ b/build/android/devil_chromium.py
@@ -47,7 +47,7 @@ ], 'forwarder_host': [ { - 'platform': 'linux', + 'platform': 'linux2', 'arch': 'x86_64', 'name': 'host_forwarder', }, @@ -86,7 +86,7 @@ ], 'md5sum_host': [ { - 'platform': 'linux', + 'platform': 'linux2', 'arch': 'x86_64', 'name': 'md5sum_bin_host', },
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml index 2ab10b8..1739e354 100644 --- a/build/android/lint/suppressions.xml +++ b/build/android/lint/suppressions.xml
@@ -55,7 +55,8 @@ <ignore path="chrome/android/java/res/drawable-xxxhdpi"/> <ignore path="ui/android/java/res/drawable-xxhdpi"/> <ignore path="ui/android/java/res/drawable-xxxhdpi"/> - <ignore regexp=".*: data_reduction_illustration.png, google_icon_sprite.png, tabs_moved_htc.png, tabs_moved_nexus.png, tabs_moved_samsung.png$"/> + <!-- The large assets below only include a few densities to reduce APK size. --> + <ignore regexp=".*: data_reduction_illustration.png, google_icon_sprite.png, physical_web_logo.png, physical_web_logo_anim1.png, physical_web_logo_anim2.png, tabs_moved_htc.png, tabs_moved_nexus.png, tabs_moved_samsung.png$"/> </issue> <issue id="IconDipSize"> <ignore regexp=".*google_icon_sprite.png.*"/>
diff --git a/build/common.gypi b/build/common.gypi index f63b0114..dbb7669 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -482,6 +482,9 @@ # Enable crash reporting via Kasko. 'kasko%': 0, + # Enable hang reports in Kasko. + 'kasko_hang_reports%': 0, + # Enable building with LSan (Clang's -fsanitize=leak option). # -fsanitize=leak only works with clang, but lsan=1 implies clang=1 # See https://sites.google.com/a/chromium.org/dev/developers/testing/leaksanitizer @@ -1192,6 +1195,7 @@ 'use_sanitizer_options%': '<(use_sanitizer_options)', 'syzyasan%': '<(syzyasan)', 'kasko%': '<(kasko)', + 'kasko_hang_reports%': '<(kasko_hang_reports)', 'syzygy_optimize%': '<(syzygy_optimize)', 'lsan%': '<(lsan)', 'msan%': '<(msan)', @@ -2891,14 +2895,6 @@ 'MEMORY_SANITIZER_INITIAL_SIZE', ], }], - ['kasko==1', { - 'defines': [ - 'KASKO', - ], - 'include_dirs': [ - '<(DEPTH)/third_party/kasko/include', - ], - }], ['OS=="win"', { 'defines': [ '__STD_C', @@ -5044,8 +5040,12 @@ 'mac_bundle': 0, 'xcode_settings': { 'ALWAYS_SEARCH_USER_PATHS': 'NO', + 'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', # -std=c++11 # Don't link in libarclite_macosx.a, see http://crbug.com/156530. 'CLANG_LINK_OBJC_RUNTIME': 'NO', # -fno-objc-link-runtime + # Warn if automatic synthesis is triggered with + # the -Wobjc-missing-property-synthesis flag. + 'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES', 'COPY_PHASE_STRIP': 'NO', 'GCC_C_LANGUAGE_STANDARD': 'c99', # -std=c99 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks @@ -5055,11 +5055,9 @@ # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', 'GCC_OBJC_CALL_CXX_CDTORS': 'YES', # -fobjc-call-cxx-cdtors - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics 'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES', # -Werror - 'GCC_VERSION': '4.2', - 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof + 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', 'USE_HEADERMAP': 'NO', 'WARNING_CFLAGS': [ '-Wall', @@ -5069,6 +5067,11 @@ # Don't warn about the "struct foo f = {0};" initialization # pattern. '-Wno-missing-field-initializers', + # This warns on selectors from Cocoa headers (-length, -set). + # cfe-dev is currently discussing the merits of this warning. + # TODO(thakis): Reevaluate what to do with this, based on the + # cfe-dev discussion. + '-Wno-selector-type-mismatch', ], 'conditions': [ ['chromium_mac_pch', {'GCC_PRECOMPILE_PREFIX_HEADER': 'YES'}, @@ -5076,25 +5079,9 @@ ], # Note that the prebuilt Clang binaries should not be used for iOS # development except for ASan builds. - ['clang==1', { - 'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', # -std=c++11 - # Warn if automatic synthesis is triggered with - # the -Wobjc-missing-property-synthesis flag. - 'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES', - 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', - 'WARNING_CFLAGS': [ - # This warns on selectors from Cocoa headers (-length, -set). - # cfe-dev is currently discussing the merits of this warning. - # TODO(thakis): Reevaluate what to do with this, based one - # cfe-dev discussion. - '-Wno-selector-type-mismatch', - ], - 'conditions': [ - ['clang_xcode==0', { - 'CC': '$(SOURCE_ROOT)/<(clang_dir)/clang', - 'LDPLUSPLUS': '$(SOURCE_ROOT)/<(clang_dir)/clang++', - }], - ], + ['clang_xcode==0', { + 'CC': '$(SOURCE_ROOT)/<(clang_dir)/clang', + 'LDPLUSPLUS': '$(SOURCE_ROOT)/<(clang_dir)/clang++', }], ['clang==1 and clang_xcode==0 and clang_use_chrome_plugins==1', { 'OTHER_CFLAGS': [ @@ -5168,6 +5155,29 @@ }], ], }], + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden + }, + }], + ['OS=="ios"', { + 'configurations': { + 'Debug': { + 'xcode_settings': { + # XCTests inject a dynamic library into the application. If + # fvisibility is set to hidden, then some symbols needed by + # XCTests are not available. Disable this setting for + # Debug configuration. + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'NO', + }, + }, + 'Release': { + 'xcode_settings': { + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden + }, + }, + }, + }], ], 'target_conditions': [ ['_type!="static_library"', {
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index d52185a..d08ede4 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -312,17 +312,19 @@ # C++11 compiler flags setup. # --------------------------- - if (is_linux || is_android || (is_nacl && is_clang)) { + if (is_linux || is_android || + (is_nacl && (is_clang || current_cpu == "arm"))) { # gnu++11 instead of c++11 is needed because some code uses typeof() (a # GNU extension). # TODO(thakis): Eventually switch this to c++11 instead, # http://crbug.com/427584 cflags_cc += [ "-std=gnu++11" ] - } else if (!is_win && !is_nacl) { - # TODO(mcgrathr) - the NaCl GCC toolchain doesn't support either gnu++11 - # or c++11; we technically don't need this toolchain any more, but there - # are still a few buildbots using it, so until those are turned off - # we need the !is_nacl clause and the (is_nacl && is_clang) clause, above. + } else if (is_nacl) { + # The NaCl x86 GCC toolchain doesn't support either gnu++11 + # or c++11, but it does support gnu++0x. This toolchain is + # used only for the nacl_x86_glibc PPAPI tests. + cflags_cc += [ "-std=gnu++0x" ] + } else if (!is_win) { cflags_cc += [ "-std=c++11" ] } @@ -788,14 +790,11 @@ cflags += [ "-Werror" ] } - if (is_mac) { - cflags += [ "-Wnewline-eof" ] - if (!is_nacl) { - # When compiling Objective-C, warns if a method is used whose - # availability is newer than the deployment target. This is not - # required when compiling Chrome for iOS. - cflags += [ "-Wpartial-availability" ] - } + if (is_mac && !is_nacl) { + # When compiling Objective-C, warns if a method is used whose + # availability is newer than the deployment target. This is not + # required when compiling Chrome for iOS. + cflags += [ "-Wpartial-availability" ] } if (gcc_version >= 48) {
diff --git a/cc/base/contiguous_container.h b/cc/base/contiguous_container.h index bad1511..af82b7e 100644 --- a/cc/base/contiguous_container.h +++ b/cc/base/contiguous_container.h
@@ -6,6 +6,7 @@ #define CC_BASE_CONTIGUOUS_CONTAINER_H_ #include <stddef.h> +#include <utility> #include "base/logging.h" #include "base/macros.h" @@ -164,12 +165,12 @@ } template <class DerivedElementType, typename... Args> - DerivedElementType& AllocateAndConstruct(const Args&... args) { + DerivedElementType& AllocateAndConstruct(Args&&... args) { static_assert(alignment % ALIGNOF(DerivedElementType) == 0, "Derived type requires stronger alignment."); size_t alloc_size = Align(sizeof(DerivedElementType)); - // TODO(enne): This should forward the args. - return *new (Allocate(alloc_size)) DerivedElementType(args...); + return *new (Allocate(alloc_size)) + DerivedElementType(std::forward<Args>(args)...); } void RemoveLast() {
diff --git a/cc/base/rtree.cc b/cc/base/rtree.cc index 0b389f42..e0fdc0d 100644 --- a/cc/base/rtree.cc +++ b/cc/base/rtree.cc
@@ -95,6 +95,7 @@ void RTree::Search(const gfx::Rect& query, std::vector<size_t>* results) const { if (num_data_elements_ > 0 && query.Intersects(root_.bounds)) SearchRecursive(root_.subtree, query, results); + DCHECK(results->empty() || ContainsItemInRect(query)); } void RTree::SearchRecursive(Node* node, @@ -110,6 +111,25 @@ } } +bool RTree::ContainsItemInRect(const gfx::Rect& query) const { + if (num_data_elements_ == 0 || !query.Intersects(root_.bounds)) + return false; + return ContainsItemInRectRecursive(root_.subtree, query); +} + +bool RTree::ContainsItemInRectRecursive(Node* node, + const gfx::Rect& query) const { + for (uint16_t i = 0; i < node->num_children; ++i) { + if (!query.Intersects(node->children[i].bounds)) + continue; + if (node->level == 0 || + ContainsItemInRectRecursive(node->children[i].subtree, query)) { + return true; + } + } + return false; +} + gfx::Rect RTree::GetBounds() const { return root_.bounds; }
diff --git a/cc/base/rtree.h b/cc/base/rtree.h index 21cd920..22f64437 100644 --- a/cc/base/rtree.h +++ b/cc/base/rtree.h
@@ -78,6 +78,10 @@ void Search(const gfx::Rect& query, std::vector<size_t>* results) const; + // Equivalent, behaviorally, to checking if |Search| added anything to + // |results|. This is faster, however. + bool ContainsItemInRect(const gfx::Rect& query) const; + gfx::Rect GetBounds() const; private: @@ -108,6 +112,8 @@ const gfx::Rect& query, std::vector<size_t>* results) const; + bool ContainsItemInRectRecursive(Node* node, const gfx::Rect& query) const; + // Consumes the input array. Branch BuildRecursive(std::vector<Branch>* branches, int level); Node* AllocateNodeAtLevel(int level);
diff --git a/cc/layers/append_quads_data.h b/cc/layers/append_quads_data.h index f4e82bc..0e2715b 100644 --- a/cc/layers/append_quads_data.h +++ b/cc/layers/append_quads_data.h
@@ -11,30 +11,22 @@ namespace cc { +// Set by the layer appending quads. struct AppendQuadsData { - AppendQuadsData() - : num_incomplete_tiles(0), - num_missing_tiles(0), - visible_layer_area(0), - approximated_visible_content_area(0), - checkerboarded_visible_content_area(0), - checkerboarded_no_recording_content_area(0), - checkerboarded_needs_raster_content_area(0) {} + int64_t num_incomplete_tiles = 0; + int64_t num_missing_tiles = 0; + int64_t visible_layer_area = 0; + int64_t approximated_visible_content_area = 0; - // Set by the layer appending quads. - int64_t num_incomplete_tiles; - // Set by the layer appending quads. - int64_t num_missing_tiles; - // Set by the layer appending quads. - int64_t visible_layer_area; - // Set by the layer appending quads. - int64_t approximated_visible_content_area; - // Set by the layer appending quads. This is total of the following two areas. - int64_t checkerboarded_visible_content_area; - // Set by the layer appending quads. This is the area outside interest rect. - int64_t checkerboarded_no_recording_content_area; - // Set by the layer appending quads. This is the area within interest rect. - int64_t checkerboarded_needs_raster_content_area; + // This is total of the following two areas. + int64_t checkerboarded_visible_content_area = 0; + // This is the area outside interest rect. + int64_t checkerboarded_no_recording_content_area = 0; + // This is the area within interest rect. + int64_t checkerboarded_needs_raster_content_area = 0; + + int64_t num_missing_tiles_no_image_content = 0; + int64_t num_missing_tiles_some_image_content = 0; }; } // namespace cc
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index b3590d4..04ac9ad 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -14,6 +14,7 @@ #include "base/time/time.h" #include "base/trace_event/trace_event_argument.h" +#include "cc/base/histograms.h" #include "cc/base/math_util.h" #include "cc/debug/debug_colors.h" #include "cc/debug/micro_benchmark_impl.h" @@ -349,6 +350,14 @@ if (geometry_rect.Intersects(scaled_viewport_for_tile_priority)) { append_quads_data->num_missing_tiles++; ++missing_tile_count; + // We only keep track of discardable images if we're using raster tasks, + // so we only gather stats in this case. + if (layer_tree_impl()->settings().image_decode_tasks_enabled) { + if (raster_source_->HasDiscardableImageInRect(geometry_rect)) + append_quads_data->num_missing_tiles_some_image_content++; + else + append_quads_data->num_missing_tiles_no_image_content++; + } } int64_t checkerboarded_area = visible_geometry_rect.width() * visible_geometry_rect.height();
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 10c95b4..5d16d8f69 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -97,10 +97,10 @@ class PictureLayerImplTest : public testing::Test { public: - PictureLayerImplTest() + explicit PictureLayerImplTest(const LayerTreeSettings& settings) : task_runner_provider_(base::ThreadTaskRunnerHandle::Get()), output_surface_(FakeOutputSurface::Create3d()), - host_impl_(LowResTilingsSettings(), + host_impl_(settings, &task_runner_provider_, &shared_bitmap_manager_, &task_graph_runner_), @@ -112,17 +112,7 @@ host_impl_.SetViewportSize(gfx::Size(10000, 10000)); } - explicit PictureLayerImplTest(const LayerTreeSettings& settings) - : task_runner_provider_(base::ThreadTaskRunnerHandle::Get()), - output_surface_(FakeOutputSurface::Create3d()), - host_impl_(settings, - &task_runner_provider_, - &shared_bitmap_manager_, - &task_graph_runner_), - root_id_(6), - id_(7) { - host_impl_.SetViewportSize(gfx::Size(10000, 10000)); - } + PictureLayerImplTest() : PictureLayerImplTest(LowResTilingsSettings()) {} ~PictureLayerImplTest() override {} @@ -2141,6 +2131,76 @@ EXPECT_TRUE(active_layer_->only_used_low_res_last_append_quads()); } +class ImageDecodeTasksSettings : public PictureLayerImplTestSettings { + public: + ImageDecodeTasksSettings() { image_decode_tasks_enabled = true; } +}; + +class ImageDecodeTasksTest : public PictureLayerImplTest { + public: + ImageDecodeTasksTest() : PictureLayerImplTest(ImageDecodeTasksSettings()) {} +}; + +TEST_F(ImageDecodeTasksTest, CheckerboardWithNoImageContent) { + host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); + + gfx::Size tile_size(100, 100); + gfx::Size layer_bounds(200, 200); + gfx::Rect recorded_viewport(0, 0, 150, 150); + + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreatePartiallyFilled(layer_bounds, + recorded_viewport); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); + ActivateTree(); + + scoped_ptr<RenderPass> render_pass = RenderPass::Create(); + AppendQuadsData data; + active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr); + active_layer_->AppendQuads(render_pass.get(), &data); + active_layer_->DidDraw(nullptr); + + EXPECT_EQ(1u, render_pass->quad_list.size()); + EXPECT_EQ(1u, data.num_missing_tiles); + EXPECT_EQ(0u, data.num_incomplete_tiles); + EXPECT_EQ(1u, data.num_missing_tiles_no_image_content); + EXPECT_EQ(0u, data.num_missing_tiles_some_image_content); + EXPECT_EQ(40000, data.checkerboarded_visible_content_area); + EXPECT_EQ(17500, data.checkerboarded_no_recording_content_area); + EXPECT_EQ(22500, data.checkerboarded_needs_raster_content_area); + EXPECT_TRUE(active_layer_->only_used_low_res_last_append_quads()); +} + +TEST_F(ImageDecodeTasksTest, CheckerboardWithSomeImageContent) { + host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); + + gfx::Size tile_size(100, 100); + gfx::Size layer_bounds(200, 200); + gfx::Rect recorded_viewport(0, 0, 150, 150); + + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreatePartiallyFilledWithImages( + layer_bounds, recorded_viewport); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); + ActivateTree(); + + scoped_ptr<RenderPass> render_pass = RenderPass::Create(); + AppendQuadsData data; + active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr); + active_layer_->AppendQuads(render_pass.get(), &data); + active_layer_->DidDraw(nullptr); + + EXPECT_EQ(1u, render_pass->quad_list.size()); + EXPECT_EQ(1u, data.num_missing_tiles); + EXPECT_EQ(0u, data.num_incomplete_tiles); + EXPECT_EQ(0u, data.num_missing_tiles_no_image_content); + EXPECT_EQ(1u, data.num_missing_tiles_some_image_content); + EXPECT_EQ(40000, data.checkerboarded_visible_content_area); + EXPECT_EQ(17500, data.checkerboarded_no_recording_content_area); + EXPECT_EQ(22500, data.checkerboarded_needs_raster_content_area); + EXPECT_TRUE(active_layer_->only_used_low_res_last_append_quads()); +} + TEST_F(PictureLayerImplTest, HighResRequiredWhenActiveAllReady) { gfx::Size layer_bounds(400, 400); gfx::Size tile_size(100, 100);
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index 977bfe7..01830684 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc
@@ -2719,7 +2719,12 @@ } GetFramebufferTexture(texture_id, RGBA_8888, window_rect); - gpu::SyncToken sync_token(gl_->InsertSyncPointCHROMIUM()); + const GLuint64 fence_sync = gl_->InsertFenceSyncCHROMIUM(); + gl_->ShallowFlushCHROMIUM(); + + gpu::SyncToken sync_token; + gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); + TextureMailbox texture_mailbox(mailbox, sync_token, GL_TEXTURE_2D); scoped_ptr<SingleReleaseCallback> release_callback;
diff --git a/cc/playback/discardable_image_map.cc b/cc/playback/discardable_image_map.cc index 93ee2c5e..b52bb02 100644 --- a/cc/playback/discardable_image_map.cc +++ b/cc/playback/discardable_image_map.cc
@@ -139,6 +139,11 @@ images->push_back(all_images_[index].first.ApplyScale(raster_scale)); } +bool DiscardableImageMap::HasDiscardableImageInRect( + const gfx::Rect& rect) const { + return images_rtree_.ContainsItemInRect(rect); +} + DiscardableImageMap::ScopedMetadataGenerator::ScopedMetadataGenerator( DiscardableImageMap* image_map, const gfx::Size& bounds)
diff --git a/cc/playback/discardable_image_map.h b/cc/playback/discardable_image_map.h index 0306e1b..f0535c1 100644 --- a/cc/playback/discardable_image_map.h +++ b/cc/playback/discardable_image_map.h
@@ -45,6 +45,7 @@ void GetDiscardableImagesInRect(const gfx::Rect& rect, float raster_scale, std::vector<DrawImage>* images) const; + bool HasDiscardableImageInRect(const gfx::Rect& rect) const; private: friend class ScopedMetadataGenerator;
diff --git a/cc/playback/display_item_list.cc b/cc/playback/display_item_list.cc index 19b97d8..e523316 100644 --- a/cc/playback/display_item_list.cc +++ b/cc/playback/display_item_list.cc
@@ -304,4 +304,9 @@ image_map_.GetDiscardableImagesInRect(rect, raster_scale, images); } +bool DisplayItemList::HasDiscardableImageInRect( + const gfx::Rect& layer_rect) const { + return image_map_.HasDiscardableImageInRect(layer_rect); +} + } // namespace cc
diff --git a/cc/playback/display_item_list.h b/cc/playback/display_item_list.h index 7b68e07..bcad05c9 100644 --- a/cc/playback/display_item_list.h +++ b/cc/playback/display_item_list.h
@@ -6,6 +6,7 @@ #define CC_PLAYBACK_DISPLAY_ITEM_LIST_H_ #include <stddef.h> +#include <utility> #include "base/gtest_prod_util.h" #include "base/macros.h" @@ -70,10 +71,10 @@ // type needs to be const, to prevent set-after-processing mistakes. template <typename DisplayItemType, typename... Args> const DisplayItemType& CreateAndAppendItem(const gfx::Rect& visual_rect, - const Args&... args) { + Args&&... args) { visual_rects_.push_back(visual_rect); - // TODO(enne): This should forward the args. - auto* item = &items_.AllocateAndConstruct<DisplayItemType>(args...); + auto* item = &items_.AllocateAndConstruct<DisplayItemType>( + std::forward<Args>(args)...); approximate_op_count_ += item->ApproximateOpCount(); // TODO(crbug.com/513016): None of the items might individually trigger a // veto even though they collectively have enough "bad" operations that a @@ -104,6 +105,8 @@ float raster_scale, std::vector<DrawImage>* images); + bool HasDiscardableImageInRect(const gfx::Rect& layer_rect) const; + gfx::Rect VisualRectForTesting(int index) { return visual_rects_[index]; } private:
diff --git a/cc/playback/display_list_raster_source.cc b/cc/playback/display_list_raster_source.cc index 4fc0f63..e94b9f6 100644 --- a/cc/playback/display_list_raster_source.cc +++ b/cc/playback/display_list_raster_source.cc
@@ -243,6 +243,11 @@ display_list_->GetDiscardableImagesInRect(layer_rect, raster_scale, images); } +bool DisplayListRasterSource::HasDiscardableImageInRect( + const gfx::Rect& layer_rect) const { + return display_list_->HasDiscardableImageInRect(layer_rect); +} + bool DisplayListRasterSource::CoversRect(const gfx::Rect& layer_rect) const { if (size_.IsEmpty()) return false;
diff --git a/cc/playback/display_list_raster_source.h b/cc/playback/display_list_raster_source.h index 377e081..8466542e 100644 --- a/cc/playback/display_list_raster_source.h +++ b/cc/playback/display_list_raster_source.h
@@ -80,6 +80,8 @@ float raster_scale, std::vector<DrawImage>* images) const; + bool HasDiscardableImageInRect(const gfx::Rect& layer_rect) const; + // Return true iff this raster source can raster the given rect in layer // space. bool CoversRect(const gfx::Rect& layer_rect) const;
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index f1a4cf2e..3637422 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc
@@ -586,8 +586,11 @@ if (resource->gl_id) { gl->DeleteTextures(1, &resource->gl_id); resource->gl_id = 0; - if (!lost_resource) - sync_token = gpu::SyncToken(gl->InsertSyncPointCHROMIUM()); + if (!lost_resource) { + const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM(); + gl->ShallowFlushCHROMIUM(); + gl->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); + } } } else { DCHECK(resource->mailbox.IsSharedMemory()); @@ -1441,7 +1444,11 @@ } if (need_sync_token && child_info->needs_sync_tokens) { DCHECK(gl); - gpu::SyncToken sync_token(gl->InsertSyncPointCHROMIUM()); + const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM(); + gl->ShallowFlushCHROMIUM(); + + gpu::SyncToken sync_token; + gl->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); for (size_t i = 0; i < to_return.size(); ++i) { if (!to_return[i].sync_token.HasData()) to_return[i].sync_token = sync_token;
diff --git a/cc/test/fake_display_list_raster_source.cc b/cc/test/fake_display_list_raster_source.cc index 163559b..6c99e7d 100644 --- a/cc/test/fake_display_list_raster_source.cc +++ b/cc/test/fake_display_list_raster_source.cc
@@ -8,7 +8,9 @@ #include "base/synchronization/waitable_event.h" #include "cc/test/fake_display_list_recording_source.h" +#include "cc/test/skia_common.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkSurface.h" #include "ui/gfx/geometry/size.h" namespace cc { @@ -105,6 +107,36 @@ } scoped_refptr<FakeDisplayListRasterSource> +FakeDisplayListRasterSource::CreatePartiallyFilledWithImages( + const gfx::Size& size, + const gfx::Rect& recorded_viewport) { + DCHECK(recorded_viewport.IsEmpty() || + gfx::Rect(size).Contains(recorded_viewport)); + auto recording_source = FakeDisplayListRecordingSource::CreateRecordingSource( + recorded_viewport, size); + recording_source->SetGenerateDiscardableImagesMetadata(true); + + SkPaint red_paint; + red_paint.setColor(SK_ColorRED); + recording_source->add_draw_rect_with_paint(gfx::Rect(size), red_paint); + + gfx::Size smaller_size(size.width() - 10, size.height() - 10); + SkPaint green_paint; + green_paint.setColor(SK_ColorGREEN); + recording_source->add_draw_rect_with_paint(gfx::Rect(smaller_size), + green_paint); + + skia::RefPtr<SkImage> image = CreateDiscardableImage(smaller_size); + recording_source->add_draw_image(image.get(), gfx::Point()); + + recording_source->Rerecord(); + recording_source->SetRecordedViewport(recorded_viewport); + + return make_scoped_refptr( + new FakeDisplayListRasterSource(recording_source.get(), false)); +} + +scoped_refptr<FakeDisplayListRasterSource> FakeDisplayListRasterSource::CreateEmpty(const gfx::Size& size) { auto recording_source = FakeDisplayListRecordingSource::CreateFilledRecordingSource(size);
diff --git a/cc/test/fake_display_list_raster_source.h b/cc/test/fake_display_list_raster_source.h index 4dcbfa9..3bff562 100644 --- a/cc/test/fake_display_list_raster_source.h +++ b/cc/test/fake_display_list_raster_source.h
@@ -27,9 +27,11 @@ static scoped_refptr<FakeDisplayListRasterSource> CreatePartiallyFilled( const gfx::Size& size, const gfx::Rect& recorded_viewport); + static scoped_refptr<FakeDisplayListRasterSource> + CreatePartiallyFilledWithImages(const gfx::Size& size, + const gfx::Rect& recorded_viewport); static scoped_refptr<FakeDisplayListRasterSource> CreateEmpty( const gfx::Size& size); - static scoped_refptr<FakeDisplayListRasterSource> CreateFromRecordingSource( const DisplayListRecordingSource* recording_source, bool can_use_lcd);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 9d74110f..4ff964e 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -886,6 +886,8 @@ const DrawMode draw_mode = GetDrawMode(); int num_missing_tiles = 0; + int num_missing_tiles_no_image_content = 0; + int num_missing_tiles_some_image_content = 0; int num_incomplete_tiles = 0; int64_t checkerboarded_no_recording_content_area = 0; int64_t checkerboarded_needs_raster_content_area = 0; @@ -970,6 +972,10 @@ append_quads_data.checkerboarded_needs_raster_content_area); num_missing_tiles += append_quads_data.num_missing_tiles; + num_missing_tiles_no_image_content += + append_quads_data.num_missing_tiles_no_image_content; + num_missing_tiles_some_image_content += + append_quads_data.num_missing_tiles_some_image_content; num_incomplete_tiles += append_quads_data.num_incomplete_tiles; checkerboarded_no_recording_content_area += append_quads_data.checkerboarded_no_recording_content_area; @@ -1054,6 +1060,21 @@ "Compositing.RenderPass.AppendQuadData." "CheckerboardedNeedRasterContentArea", checkerboarded_needs_raster_content_area); + + if (settings_.image_decode_tasks_enabled && num_missing_tiles) { + if (const char* client_name = GetClientNameForMetrics()) { + UMA_HISTOGRAM_COUNTS_100( + base::StringPrintf("Compositing.%s.RenderPass.AppendQuadData." + "NumMissingTilesSomeImageContent", + client_name), + num_missing_tiles_some_image_content); + UMA_HISTOGRAM_COUNTS_100( + base::StringPrintf("Compositing.%s.RenderPass.AppendQuadData." + "NumMissingTilesNoImageContent", + client_name), + num_missing_tiles_no_image_content); + } + } } // Should only have one render pass in resourceless software mode.
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc index c7ce754..314e484 100644 --- a/cc/trees/layer_tree_host_unittest_context.cc +++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -955,7 +955,12 @@ gpu::Mailbox mailbox; gl->GenMailboxCHROMIUM(mailbox.name); - gpu::SyncToken sync_token(gl->InsertSyncPointCHROMIUM()); + + const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM(); + gl->ShallowFlushCHROMIUM(); + + gpu::SyncToken sync_token; + gl->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); scoped_refptr<Layer> root = Layer::Create(layer_settings()); root->SetBounds(gfx::Size(10, 10));
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc index 97362f4..9db6485 100644 --- a/cc/trees/layer_tree_host_unittest_copyrequest.cc +++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -975,7 +975,11 @@ gpu::gles2::GLES2Interface* gl = external_context_provider_->ContextGL(); gpu::Mailbox mailbox; gl->GenMailboxCHROMIUM(mailbox.name); - sync_token_ = gpu::SyncToken(gl->InsertSyncPointCHROMIUM()); + + const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM(); + gl->ShallowFlushCHROMIUM(); + gl->GenSyncTokenCHROMIUM(fence_sync, sync_token_.GetData()); + request->SetTextureMailbox( TextureMailbox(mailbox, sync_token_, GL_TEXTURE_2D)); EXPECT_TRUE(request->has_texture_mailbox());
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index 11eb786..cc14b819 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -316,6 +316,7 @@ "//base/trace_event/etw_manifest:chrome_events_win", "//chrome/app/theme:chrome_unscaled_resources", "//chrome_elf", + "//components/crash/content/app", "//content/app/resources", "//crypto", "//net:net_resources",
diff --git a/chrome/android/java/res/drawable-hdpi/physical_web_logo.png b/chrome/android/java/res/drawable-hdpi/physical_web_logo.png deleted file mode 100644 index 3255d19..0000000 --- a/chrome/android/java/res/drawable-hdpi/physical_web_logo.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/physical_web_logo_anim1.png b/chrome/android/java/res/drawable-hdpi/physical_web_logo_anim1.png deleted file mode 100644 index d4042ef..0000000 --- a/chrome/android/java/res/drawable-hdpi/physical_web_logo_anim1.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/physical_web_logo_anim2.png b/chrome/android/java/res/drawable-hdpi/physical_web_logo_anim2.png deleted file mode 100644 index a35a22c..0000000 --- a/chrome/android/java/res/drawable-hdpi/physical_web_logo_anim2.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/physical_web_logo.png b/chrome/android/java/res/drawable-mdpi/physical_web_logo.png index 27d1f2a..4ed62264 100644 --- a/chrome/android/java/res/drawable-mdpi/physical_web_logo.png +++ b/chrome/android/java/res/drawable-mdpi/physical_web_logo.png Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/physical_web_logo_anim1.png b/chrome/android/java/res/drawable-mdpi/physical_web_logo_anim1.png index 496ea1e5..e011946 100644 --- a/chrome/android/java/res/drawable-mdpi/physical_web_logo_anim1.png +++ b/chrome/android/java/res/drawable-mdpi/physical_web_logo_anim1.png Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/physical_web_logo_anim2.png b/chrome/android/java/res/drawable-mdpi/physical_web_logo_anim2.png index 1142cd38..70c36de 100644 --- a/chrome/android/java/res/drawable-mdpi/physical_web_logo_anim2.png +++ b/chrome/android/java/res/drawable-mdpi/physical_web_logo_anim2.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/physical_web_logo.png b/chrome/android/java/res/drawable-xhdpi/physical_web_logo.png deleted file mode 100644 index b5cfa65c..0000000 --- a/chrome/android/java/res/drawable-xhdpi/physical_web_logo.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/physical_web_logo_anim1.png b/chrome/android/java/res/drawable-xhdpi/physical_web_logo_anim1.png deleted file mode 100644 index a346967d..0000000 --- a/chrome/android/java/res/drawable-xhdpi/physical_web_logo_anim1.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/physical_web_logo_anim2.png b/chrome/android/java/res/drawable-xhdpi/physical_web_logo_anim2.png deleted file mode 100644 index ad8a13e..0000000 --- a/chrome/android/java/res/drawable-xhdpi/physical_web_logo_anim2.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/physical_web_logo.png b/chrome/android/java/res/drawable-xxhdpi/physical_web_logo.png index 5ebccf6..ffe49981 100644 --- a/chrome/android/java/res/drawable-xxhdpi/physical_web_logo.png +++ b/chrome/android/java/res/drawable-xxhdpi/physical_web_logo.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/physical_web_logo_anim1.png b/chrome/android/java/res/drawable-xxhdpi/physical_web_logo_anim1.png index 124b636..2b9fd76 100644 --- a/chrome/android/java/res/drawable-xxhdpi/physical_web_logo_anim1.png +++ b/chrome/android/java/res/drawable-xxhdpi/physical_web_logo_anim1.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/physical_web_logo_anim2.png b/chrome/android/java/res/drawable-xxhdpi/physical_web_logo_anim2.png index 52fed04b..73eb38c 100644 --- a/chrome/android/java/res/drawable-xxhdpi/physical_web_logo_anim2.png +++ b/chrome/android/java/res/drawable-xxhdpi/physical_web_logo_anim2.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/physical_web_logo.png b/chrome/android/java/res/drawable-xxxhdpi/physical_web_logo.png deleted file mode 100644 index 3cd708e..0000000 --- a/chrome/android/java/res/drawable-xxxhdpi/physical_web_logo.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/physical_web_logo_anim1.png b/chrome/android/java/res/drawable-xxxhdpi/physical_web_logo_anim1.png deleted file mode 100644 index 4affeb9..0000000 --- a/chrome/android/java/res/drawable-xxxhdpi/physical_web_logo_anim1.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/physical_web_logo_anim2.png b/chrome/android/java/res/drawable-xxxhdpi/physical_web_logo_anim2.png deleted file mode 100644 index 3ea22c39..0000000 --- a/chrome/android/java/res/drawable-xxxhdpi/physical_web_logo_anim2.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java index a0aeebf..6a3e498c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java
@@ -149,7 +149,7 @@ /** * Ratio of dps per pixel. */ - private float mPxToDp; + protected float mPxToDp; /** * The approximate Y coordinate of the selection in pixels.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java index 732ca69..0d2e285 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java
@@ -280,6 +280,17 @@ } @Override + public float getOffsetY() { + float toolbarOffset = 0.0f; + if (mActivity != null) { + toolbarOffset = -mActivity.getFullscreenManager().getControlOffset() * mPxToDp; + } + // This will cause the reader mode bar to behave like the top controls; sliding out of + // view as the page scrolls. + return super.getOffsetY() + toolbarOffset; + } + + @Override public float getArrowIconOpacity() { // TODO(mdjones): This will not be needed once Reader Mode has its own scene layer. // Never show the arrow icon.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java index 0485ad8d..02ec4b2b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
@@ -15,8 +15,10 @@ import android.view.View; import android.widget.TextView; +import org.chromium.base.annotations.CalledByNative; import org.chromium.chrome.R; import org.chromium.chrome.browser.ContentSettingsType; +import org.chromium.chrome.browser.ResourceId; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.base.WindowAndroid.PermissionCallback; @@ -220,4 +222,31 @@ int action = isPrimaryButton ? ActionType.OK : ActionType.CANCEL; onButtonClicked(action); } + + /** + * Creates and begins the process for showing a ConfirmInfoBar. + * @param windowAndroid The owning window for the infobar. + * @param enumeratedIconId ID corresponding to the icon that will be shown for the infobar. + * The ID must have been mapped using the ResourceMapper class before + * passing it to this function. + * @param iconBitmap Bitmap to use if there is no equivalent Java resource for + * enumeratedIconId. + * @param message Message to display to the user indicating what the infobar is for. + * @param linkText Link text to display in addition to the message. + * @param buttonOk String to display on the OK button. + * @param buttonCancel String to display on the Cancel button. + * @param contentSettings The list of ContentSettingTypes being requested by this infobar. + */ + @CalledByNative + private static ConfirmInfoBar create(WindowAndroid windowAndroid, int enumeratedIconId, + Bitmap iconBitmap, String message, String linkText, String buttonOk, + String buttonCancel, int[] contentSettings) { + int drawableId = ResourceId.mapToDrawableId(enumeratedIconId); + + ConfirmInfoBar infoBar = new ConfirmInfoBar( + null, drawableId, iconBitmap, message, linkText, buttonOk, buttonCancel); + infoBar.setContentSettings(windowAndroid, contentSettings); + + return infoBar; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java deleted file mode 100644 index 5ca3708..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java +++ /dev/null
@@ -1,52 +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. - -package org.chromium.chrome.browser.infobar; - -import android.graphics.Bitmap; - -import org.chromium.base.annotations.CalledByNative; -import org.chromium.chrome.browser.ResourceId; -import org.chromium.ui.base.WindowAndroid; - -/** - * Provides JNI methods for ConfirmInfoBars - */ -public class ConfirmInfoBarDelegate { - - private ConfirmInfoBarDelegate() { - } - - @CalledByNative - public static ConfirmInfoBarDelegate create() { - return new ConfirmInfoBarDelegate(); - } - - /** - * Creates and begins the process for showing a ConfirmInfoBar. - * @param windowAndroid The owning window for the infobar. - * @param enumeratedIconId ID corresponding to the icon that will be shown for the InfoBar. - * The ID must have been mapped using the ResourceMapper class before - * passing it to this function. - * @param iconBitmap Bitmap to use if there is no equivalent Java resource for - * enumeratedIconId. - * @param message Message to display to the user indicating what the InfoBar is for. - * @param linkText Link text to display in addition to the message. - * @param buttonOk String to display on the OK button. - * @param buttonCancel String to display on the Cancel button. - * @param contentSettings The list of ContentSettingTypes being requested by this infobar. - */ - @CalledByNative - InfoBar showConfirmInfoBar(WindowAndroid windowAndroid, int enumeratedIconId, - Bitmap iconBitmap, String message, String linkText, String buttonOk, - String buttonCancel, int[] contentSettings) { - int drawableId = ResourceId.mapToDrawableId(enumeratedIconId); - - ConfirmInfoBar infoBar = new ConfirmInfoBar( - null, drawableId, iconBitmap, message, linkText, buttonOk, buttonCancel); - infoBar.setContentSettings(windowAndroid, contentSettings); - - return infoBar; - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/VariationsSession.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/VariationsSession.java index c6f763c..5775e7a2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/VariationsSession.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/VariationsSession.java
@@ -6,6 +6,8 @@ import android.content.Context; +import org.chromium.base.Callback; + /** * Sets up communication with the VariationsService. This is primarily used for * triggering seed fetches on application startup. @@ -22,15 +24,30 @@ mInitialized = true; // Check the restrict mode only once initially to avoid doing extra work each time the // app enters foreground. - mRestrictMode = getRestrictMode(context); + getRestrictMode(context, new Callback<String>() { + @Override + public void onResult(String restrictMode) { + assert restrictMode != null; + mRestrictMode = restrictMode; + nativeStartVariationsSession(mRestrictMode); + } + }); + // If |mRestrictMode| is null, async initialization is in progress and + // nativeStartVariationsSession will be called when it completes. + } else if (mRestrictMode != null) { + nativeStartVariationsSession(mRestrictMode); } - nativeStartVariationsSession(mRestrictMode); } /** - * Returns the value of the "restrict" URL param that the variations service should use for - * variation seed requests. + * Asynchronously returns the value of the "restrict" URL param that the variations service + * should use for variation seed requests. */ + protected void getRestrictMode(Context context, Callback<String> callback) { + callback.onResult(getRestrictMode(context)); + } + + // TODO(maxbogue): Remove once downstream is updated to be async. protected String getRestrictMode(Context context) { return ""; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java index 6554c24..862c875 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
@@ -46,6 +46,7 @@ private ImageView mScanningImageView; private SwipeRefreshWidget mSwipeRefreshWidget; private boolean mIsInitialDisplayRecorded; + private boolean mIsRefreshing; private boolean mIsRefreshUserInitiated; @Override @@ -76,6 +77,7 @@ PhysicalWebUma.onNotificationPressed(this); } mIsInitialDisplayRecorded = false; + mIsRefreshing = false; mIsRefreshUserInitiated = false; } @@ -165,6 +167,11 @@ } private void startRefresh(boolean isUserInitiated, boolean isSwipeInitiated) { + if (mIsRefreshing) { + return; + } + + mIsRefreshing = true; mIsRefreshUserInitiated = isUserInitiated; // Clear the list adapter to trigger the empty list display. @@ -213,6 +220,8 @@ PhysicalWebUma.onUrlsDisplayed(this, mAdapter.getCount()); } // TODO(mattreynolds): add UMA for user-initiated refreshes. + + mIsRefreshing = false; } private void fetchIcon(String iconUrl) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java index 84682c8f..6ac520b2e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
@@ -4,8 +4,10 @@ package org.chromium.chrome.browser.input; +import android.test.suitebuilder.annotation.LargeTest; + import org.chromium.base.ThreadUtils; -import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.WebContentsFactory; @@ -62,11 +64,9 @@ * Tests that the showing select popup does not get closed because an unrelated ContentView * gets destroyed. * - * @LargeTest - * @Feature({"Browser"}) - * BUG 172967 - */ - @DisabledTest + */ + @LargeTest + @Feature({"Browser"}) public void testPopupNotClosedByOtherContentView() throws InterruptedException, Exception, Throwable { // Load the test page.
diff --git a/chrome/app/DEPS b/chrome/app/DEPS index f306bcb..5d647ee 100644 --- a/chrome/app/DEPS +++ b/chrome/app/DEPS
@@ -11,6 +11,7 @@ "+chrome_elf/chrome_elf_main.h", "+chromeos/chromeos_paths.h", "+chromeos/chromeos_switches.h", + "+chromeos/hugepage_text/hugepage_text.h", "+components/browser_watcher", "+components/component_updater", "+components/content_settings/core/common/content_settings_pattern.h", @@ -31,4 +32,5 @@ "+sandbox", "+syzygy/kasko/api", "+third_party/crashpad/crashpad", + "+third_party/kasko", ]
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index 9f29057..e4fa69a 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -91,6 +91,7 @@ #include "chrome/browser/chromeos/boot_times_recorder.h" #include "chromeos/chromeos_paths.h" #include "chromeos/chromeos_switches.h" +#include "chromeos/hugepage_text/hugepage_text.h" #endif #if BUILDFLAG(ANDROID_JAVA_UI) @@ -944,6 +945,10 @@ #elif defined(OS_POSIX) && !defined(OS_ANDROID) void ChromeMainDelegate::ZygoteStarting( ScopedVector<content::ZygoteForkDelegate>* delegates) { +#if defined(OS_CHROMEOS) + chromeos::ReloadElfTextInHugePages(); +#endif + #if !defined(DISABLE_NACL) nacl::AddNaClZygoteForkDelegates(delegates); #endif
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index cd299f2..0d534e22 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -5181,6 +5181,9 @@ <message name="IDS_IME_NAME_INPUTMETHOD_ZHUYIN" desc="The input method name shows in system tray menu, this is Zhuyin input method for Traditional Chinese."> Zhuyin input method </message> + <message name="IDS_IME_NAME_INPUTMETHOD_CANTONESE" desc="The input method name shows in system tray menu, this is Cantonese input method for Traditional Chinese."> + Cantonese input method + </message> <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL" desc="The input method name shows in system tray menu, this is Korean Hangul input method."> Korean input method </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 12131f3..196fa8a 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -7656,6 +7656,12 @@ <message name="IDS_FEEDBACK_SEND_REPORT" desc="Text for OK button of the send feedback dialog"> Send feedback </message> + <message name="IDS_FEEDBACK_SYSINFO_PAGE_TITLE" desc="The title of the system information preview page"> + System Information Preview + </message> + <message name="IDS_FEEDBACK_SYSINFO_PAGE_LOADING" desc="The message showing the status of the system information preview page that it is still loading"> + Loading... + </message> </if> <!-- Clear Browsing Data -->
diff --git a/chrome/app/kasko_client.cc b/chrome/app/kasko_client.cc index afc5c07c..ab44bac 100644 --- a/chrome/app/kasko_client.cc +++ b/chrome/app/kasko_client.cc
@@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#if defined(KASKO) #include "chrome/app/kasko_client.h" +#if BUILDFLAG(ENABLE_KASKO) + #include <windows.h> #include <stddef.h> @@ -115,4 +116,4 @@ nullptr, nullptr); } -#endif // defined(KASKO) +#endif // BUILDFLAG(ENABLE_KASKO)
diff --git a/chrome/app/kasko_client.h b/chrome/app/kasko_client.h index 9f3da7d..aeb816f 100644 --- a/chrome/app/kasko_client.h +++ b/chrome/app/kasko_client.h
@@ -5,7 +5,9 @@ #ifndef CHROME_APP_KASKO_CLIENT_H_ #define CHROME_APP_KASKO_CLIENT_H_ -#if defined(KASKO) +#include "third_party/kasko/kasko_features.h" + +#if BUILDFLAG(ENABLE_KASKO) #include "base/macros.h" #include "syzygy/kasko/api/minidump_type.h" @@ -28,6 +30,6 @@ DISALLOW_COPY_AND_ASSIGN(KaskoClient); }; -#endif // KASKO +#endif // BUILDFLAG(ENABLE_KASKO) #endif // CHROME_APP_KASKO_CLIENT_H_
diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc index 3ab9f69..8ef34fe 100644 --- a/chrome/app/main_dll_loader_win.cc +++ b/chrome/app/main_dll_loader_win.cc
@@ -122,7 +122,10 @@ typedef int (*InitMetro)(); -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) + +// For ::GetProfileType(). +#pragma comment(lib, "userenv.lib") // For ::GetProfileType(). #pragma comment(lib, "userenv.lib") @@ -156,7 +159,7 @@ return profile_type; } -#endif // KASKO +#endif // BUILDFLAG(ENABLE_KASKO) } // namespace @@ -317,9 +320,9 @@ private: scoped_ptr<ChromeWatcherClient> chrome_watcher_client_; -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) scoped_ptr<KaskoClient> kasko_client_; -#endif // KASKO +#endif }; void ChromeDllLoader::OnBeforeLaunch(const std::string& process_type, @@ -340,7 +343,7 @@ chrome_watcher_client_.reset(new ChromeWatcherClient( base::Bind(&GenerateChromeWatcherCommandLine, exe_path))); if (chrome_watcher_client_->LaunchWatcher()) { -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) kasko::api::MinidumpType minidump_type = kasko::api::SMALL_DUMP_TYPE; if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kFullMemoryCrashReport)) { @@ -359,7 +362,7 @@ kasko_client_.reset( new KaskoClient(chrome_watcher_client_.get(), minidump_type)); -#endif // KASKO +#endif // BUILDFLAG(ENABLE_KASKO) } } } @@ -382,9 +385,9 @@ ClearDidRun(dll_path); } -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) kasko_client_.reset(); -#endif // KASKO +#endif chrome_watcher_client_.reset(); return return_code;
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 08ae2fd5..6ddd539 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -608,6 +608,12 @@ Manage other people </message> + <if expr="not chromeos"> + <message name="IDS_SETTINGS_EDIT_PERSON" desc="Title of the edit person subpage"> + Edit person + </message> + </if> + <message name="IDS_SETTINGS_SYNC_OVERVIEW" desc="The message that appears in the options dialog when sync has not been set up by the user."> Sign in to get your bookmarks, history, passwords and other settings on all your devices. You'll also automatically be signed in to your Google services. </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index dad6c5b..427c725 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -369,6 +369,7 @@ "//storage/common", "//third_party/WebKit/public:image_resources", "//third_party/WebKit/public:resources", + "//third_party/kasko", "//third_party/leveldatabase", "//third_party/libaddressinput", "//third_party/libyuv", @@ -843,6 +844,7 @@ ] deps += [ ":chrome_process_finder", + "//chrome/chrome_watcher:client", "//chrome/common:version_header", "//chrome/installer/util:strings", "//chrome_elf",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index 1f815d0..dfcf809 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -171,6 +171,7 @@ "+sync/util", # Sync utilities like GetSessionName. "+syzygy/kasko", "+third_party/cros_system_api", + "+third_party/kasko", "+win8/util", # chrome only needs switches from cc. All usage of the compositor is from
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index 33ce239..6fd378de 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -231,7 +231,7 @@ media_router::MediaRouterDialogControllerAndroid::Register}, #endif {"CompositorView", RegisterCompositorView}, - {"ConfirmInfoBarDelegate", RegisterConfirmInfoBarDelegate}, + {"ConfirmInfoBar", RegisterConfirmInfoBar}, {"ConnectionInfoPopupAndroid", ConnectionInfoPopupAndroid::RegisterConnectionInfoPopupAndroid}, {"SecurityStateModel", RegisterSecurityStateModelAndroid},
diff --git a/chrome/browser/banners/app_banner_data_fetcher.h b/chrome/browser/banners/app_banner_data_fetcher.h index 24236a1..fe943f2 100644 --- a/chrome/browser/banners/app_banner_data_fetcher.h +++ b/chrome/browser/banners/app_banner_data_fetcher.h
@@ -12,6 +12,7 @@ #include "base/observer_list.h" #include "base/time/time.h" #include "chrome/common/web_application_info.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/common/manifest.h" @@ -30,9 +31,10 @@ // Fetches data required to show a web app banner for the URL currently shown by // the WebContents. -class AppBannerDataFetcher - : public base::RefCounted<AppBannerDataFetcher>, - public content::WebContentsObserver { +class AppBannerDataFetcher : public base::RefCountedThreadSafe< + AppBannerDataFetcher, + content::BrowserThread::DeleteOnUIThread>, + public content::WebContentsObserver { public: class Observer { public: @@ -188,6 +190,9 @@ base::string16 app_title_; content::Manifest web_app_data_; + friend struct content::BrowserThread::DeleteOnThread< + content::BrowserThread::UI>; + friend class base::DeleteHelper<AppBannerDataFetcher>; friend class AppBannerDataFetcherUnitTest; friend class base::RefCounted<AppBannerDataFetcher>; DISALLOW_COPY_AND_ASSIGN(AppBannerDataFetcher);
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc index 0a1238b..139d8b9 100644 --- a/chrome/browser/chrome_browser_main_win.cc +++ b/chrome/browser/chrome_browser_main_win.cc
@@ -74,7 +74,7 @@ #include "chrome/browser/google/did_run_updater_win.h" #endif -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) #include "syzygy/kasko/api/reporter.h" #endif @@ -122,7 +122,7 @@ new ChromeUtilityHostMsg_BuildDirectWriteFontCache(path)); } -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) void ObserveFailedCrashReportDirectory(const base::FilePath& path, bool error) { DCHECK(!error); if (error) @@ -155,7 +155,7 @@ ObserveFailedCrashReportDirectory(permanent_failure_directory, false); } } -#endif +#endif // BUILDFLAG(ENABLE_KASKO) void DetectFaultTolerantHeap() { enum FTHFlags { @@ -376,7 +376,7 @@ void ChromeBrowserMainPartsWin::PostBrowserStart() { ChromeBrowserMainParts::PostBrowserStart(); - UMA_HISTOGRAM_BOOLEAN("Windows.Tablet", base::win::IsTabletDevice()); + UMA_HISTOGRAM_BOOLEAN("Windows.Tablet", base::win::IsTabletDevice(nullptr)); // Set up a task to verify installed modules in the current process. content::BrowserThread::PostAfterStartupTask( @@ -385,13 +385,13 @@ InitializeChromeElf(); -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) content::BrowserThread::PostDelayedTask( content::BrowserThread::FILE, FROM_HERE, base::Bind(&StartFailedKaskoCrashReportWatcher, base::Unretained(&failed_kasko_crash_report_watcher_)), base::TimeDelta::FromMinutes(5)); -#endif +#endif // BUILDFLAG(ENABLE_KASKO) #if defined(GOOGLE_CHROME_BUILD) did_run_updater_.reset(new DidRunUpdater);
diff --git a/chrome/browser/chrome_browser_main_win.h b/chrome/browser/chrome_browser_main_win.h index 254b487..c948edbf 100644 --- a/chrome/browser/chrome_browser_main_win.h +++ b/chrome/browser/chrome_browser_main_win.h
@@ -10,6 +10,7 @@ #include "base/files/file_path_watcher.h" #include "base/macros.h" #include "chrome/browser/chrome_browser_main.h" +#include "third_party/kasko/kasko_features.h" class DidRunUpdater; @@ -72,7 +73,7 @@ #if defined(GOOGLE_CHROME_BUILD) scoped_ptr<DidRunUpdater> did_run_updater_; #endif -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) // Cleans up Kasko crash reports that exceeded the maximum upload attempts. base::FilePathWatcher failed_kasko_crash_report_watcher_; #endif
diff --git a/chrome/browser/chromeos/accessibility/chromevox_panel.cc b/chrome/browser/chromeos/accessibility/chromevox_panel.cc index 28a8f90c5..3710d53 100644 --- a/chrome/browser/chromeos/accessibility/chromevox_panel.cc +++ b/chrome/browser/chromeos/accessibility/chromevox_panel.cc
@@ -8,8 +8,10 @@ #include "base/macros.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #include "chrome/browser/chromeos/accessibility/chromevox_panel.h" +#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" #include "chrome/common/extensions/extension_constants.h" #include "content/public/browser/web_contents.h" +#include "extensions/browser/view_type_utils.h" #include "ui/chromeos/accessibility_types.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/layout/fill_layout.h" @@ -64,8 +66,12 @@ url += kChromeVoxPanelRelativeUrl; views::WebView* web_view = new views::WebView(browser_context); + content::WebContents* contents = web_view->GetWebContents(); web_contents_observer_.reset( - new ChromeVoxPanelWebContentsObserver(web_view->GetWebContents(), this)); + new ChromeVoxPanelWebContentsObserver(contents, this)); + extensions::SetViewType(contents, extensions::VIEW_TYPE_COMPONENT); + extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( + contents); web_view->LoadInitialURL(GURL(url)); web_view_ = web_view;
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc index 8ab1920..e3856f8b 100644 --- a/chrome/browser/chromeos/input_method/input_method_util.cc +++ b/chrome/browser/chromeos/input_method/input_method_util.cc
@@ -206,6 +206,7 @@ } kInputMethodNameMap[] = { {"__MSG_INPUTMETHOD_ARRAY__", IDS_IME_NAME_INPUTMETHOD_ARRAY}, {"__MSG_INPUTMETHOD_CANGJIE__", IDS_IME_NAME_INPUTMETHOD_CANGJIE}, + {"__MSG_INPUTMETHOD_CANTONESE__", IDS_IME_NAME_INPUTMETHOD_CANTONESE}, {"__MSG_INPUTMETHOD_DAYI__", IDS_IME_NAME_INPUTMETHOD_DAYI}, {"__MSG_INPUTMETHOD_HANGUL_2_SET__", IDS_IME_NAME_INPUTMETHOD_HANGUL_2_SET}, {"__MSG_INPUTMETHOD_HANGUL_3_SET_390__",
diff --git a/chrome/browser/chromeos/login/screens/network_screen.cc b/chrome/browser/chromeos/login/screens/network_screen.cc index 4f8c808..b10458f 100644 --- a/chrome/browser/chromeos/login/screens/network_screen.cc +++ b/chrome/browser/chromeos/login/screens/network_screen.cc
@@ -118,6 +118,9 @@ if (view_ == view) { view_ = nullptr; timezone_subscription_.reset(); + // Ownership of NetworkScreen is complicated; ensure that we remove + // this as a NetworkStateHandler observer when the view is destroyed. + UnsubscribeNetworkNotification(); } }
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc index 72d23d1..b4acbd58 100644 --- a/chrome/browser/chromeos/login/ui/webui_login_view.cc +++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -41,6 +41,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/common/renderer_preferences.h" +#include "extensions/browser/view_type_utils.h" #include "third_party/WebKit/public/web/WebInputEvent.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -196,6 +197,7 @@ SetDelegate(this); web_contents->SetDelegate(this); + extensions::SetViewType(web_contents, extensions::VIEW_TYPE_COMPONENT); extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( web_contents); content::RendererPreferences* prefs = web_contents->GetMutableRendererPrefs();
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc index b42c3d6..587cce1 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -640,12 +640,9 @@ account_id) && user->HasGaiaAccount()) || user->GetType() == user_manager::USER_TYPE_GUEST) { + LOG(ERROR) << "User is ephemeral or guest! Fallback to default wallpaper."; InitInitialUserWallpaper(account_id, false); GetPendingWallpaper(account_id, delayed)->ResetSetDefaultWallpaper(); - if (base::SysInfo::IsRunningOnChromeOS()) { - LOG(ERROR) - << "User is ephemeral or guest! Fallback to default wallpaper."; - } return; }
diff --git a/chrome/browser/chromeos/mobile/mobile_activator_unittest.cc b/chrome/browser/chromeos/mobile/mobile_activator_unittest.cc index 7135da7..5205b4b6 100644 --- a/chrome/browser/chromeos/mobile/mobile_activator_unittest.cc +++ b/chrome/browser/chromeos/mobile/mobile_activator_unittest.cc
@@ -122,6 +122,7 @@ NetworkHandler::Initialize(); } void TearDown() override { + mobile_activator_.TerminateActivation(); NetworkHandler::Shutdown(); DBusThreadManager::Shutdown(); }
diff --git a/chrome/browser/chromeos/proxy_config_service_impl.cc b/chrome/browser/chromeos/proxy_config_service_impl.cc index 4e63069..6e07ba70 100644 --- a/chrome/browser/chromeos/proxy_config_service_impl.cc +++ b/chrome/browser/chromeos/proxy_config_service_impl.cc
@@ -117,6 +117,13 @@ DetermineEffectiveConfigFromDefaultNetwork(); } +void ProxyConfigServiceImpl::OnShuttingDown() { + // Ownership of this class is complicated. Stop observing NetworkStateHandler + // when the class shuts down. + NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, + FROM_HERE); +} + // static bool ProxyConfigServiceImpl::IgnoreProxy(const PrefService* profile_prefs, const std::string network_profile_path, @@ -167,6 +174,9 @@ } void ProxyConfigServiceImpl::DetermineEffectiveConfigFromDefaultNetwork() { + if (!NetworkHandler::IsInitialized()) + return; + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); const NetworkState* network = handler->DefaultNetwork();
diff --git a/chrome/browser/chromeos/proxy_config_service_impl.h b/chrome/browser/chromeos/proxy_config_service_impl.h index 3276fc6..8a1fc6a 100644 --- a/chrome/browser/chromeos/proxy_config_service_impl.h +++ b/chrome/browser/chromeos/proxy_config_service_impl.h
@@ -52,6 +52,7 @@ // NetworkStateHandlerObserver implementation. void DefaultNetworkChanged(const NetworkState* network) override; + void OnShuttingDown() override; protected: friend class UIProxyConfigService;
diff --git a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc index d7fbbf93..91307a8 100644 --- a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc +++ b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
@@ -427,10 +427,6 @@ return T::kConfigured ? &config_desc_ : nullptr; } - bool Close(scoped_refptr<UsbDeviceHandle> handle) override { - return true; - } - std::set<int> claimed_interfaces_; protected:
diff --git a/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc b/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc index 9c785c2c..2bb5d6d 100644 --- a/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc +++ b/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc
@@ -147,9 +147,13 @@ install_prompt_.reset(new ExtensionInstallPrompt(web_contents)); install_prompt_->ShowDialog( - this, dummy_extension_.get(), &icon, std::move(prompt), + base::Bind( + &DashboardPrivateShowPermissionPromptForDelegatedInstallFunction:: + OnInstallPromptDone, + this), + dummy_extension_.get(), &icon, std::move(prompt), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); - // Control flow finishes up in InstallUIProceed or InstallUIAbort. + // Control flow finishes up in OnInstallPromptDone(). } void DashboardPrivateShowPermissionPromptForDelegatedInstallFunction:: @@ -167,20 +171,16 @@ } void DashboardPrivateShowPermissionPromptForDelegatedInstallFunction:: - InstallUIProceed() { - Respond(BuildResponse(api::dashboard_private::RESULT_SUCCESS, std::string())); + OnInstallPromptDone(ExtensionInstallPrompt::Result result) { + if (result == ExtensionInstallPrompt::Result::ACCEPTED) { + Respond( + BuildResponse(api::dashboard_private::RESULT_SUCCESS, std::string())); + } else { + Respond(BuildResponse(api::dashboard_private::RESULT_USER_CANCELLED, + kUserCancelledError)); + } - // Matches the AddRef in Run(). - Release(); -} - -void DashboardPrivateShowPermissionPromptForDelegatedInstallFunction:: - InstallUIAbort(bool user_initiated) { - Respond(BuildResponse(api::dashboard_private::RESULT_USER_CANCELLED, - kUserCancelledError)); - - // Matches the AddRef in Run(). - Release(); + Release(); // Matches the AddRef in Run(). } ExtensionFunction::ResponseValue
diff --git a/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.h b/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.h index d181966..11e2da8 100644 --- a/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.h +++ b/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_delegate.h" #include "chrome/browser/extensions/bundle_installer.h" @@ -29,7 +30,6 @@ class DashboardPrivateShowPermissionPromptForDelegatedInstallFunction : public UIThreadExtensionFunction, - public ExtensionInstallPrompt::Delegate, public WebstoreInstallHelper::Delegate { public: DECLARE_EXTENSION_FUNCTION( @@ -55,9 +55,7 @@ InstallHelperResultCode result, const std::string& error_message) override; - // ExtensionInstallPrompt::Delegate: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); ExtensionFunction::ResponseValue BuildResponse( api::dashboard_private::Result result, @@ -74,6 +72,9 @@ scoped_refptr<Extension> dummy_extension_; scoped_ptr<ExtensionInstallPrompt> install_prompt_; + + DISALLOW_COPY_AND_ASSIGN( + DashboardPrivateShowPermissionPromptForDelegatedInstallFunction); }; class DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction
diff --git a/chrome/browser/extensions/api/developer_private/inspectable_views_finder.cc b/chrome/browser/extensions/api/developer_private/inspectable_views_finder.cc index e588caf..f12df3a 100644 --- a/chrome/browser/extensions/api/developer_private/inspectable_views_finder.cc +++ b/chrome/browser/extensions/api/developer_private/inspectable_views_finder.cc
@@ -54,6 +54,9 @@ case VIEW_TYPE_BACKGROUND_CONTENTS: view->type = api::developer_private::VIEW_TYPE_BACKGROUND_CONTENTS; break; + case VIEW_TYPE_COMPONENT: + view->type = api::developer_private::VIEW_TYPE_COMPONENT; + break; case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE: view->type = api::developer_private::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE; break; @@ -75,9 +78,6 @@ case VIEW_TYPE_TAB_CONTENTS: view->type = api::developer_private::VIEW_TYPE_TAB_CONTENTS; break; - case VIEW_TYPE_VIRTUAL_KEYBOARD: - view->type = api::developer_private::VIEW_TYPE_VIRTUAL_KEYBOARD; - break; default: NOTREACHED(); }
diff --git a/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc b/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc index d791ed1..8019d38c 100644 --- a/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc +++ b/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc
@@ -83,29 +83,30 @@ ExtensionInstallPrompt::POST_INSTALL_PERMISSIONS_PROMPT)); prompt->set_retained_files(retained_file_paths); prompt->set_retained_device_messages(retained_device_messages); - prompt_->ShowDialog(this, extension, nullptr, std::move(prompt), - ExtensionInstallPrompt::GetDefaultShowDialogCallback()); + // Unretained() is safe because this class manages its own lifetime and + // deletes itself in OnInstallPromptDone(). + prompt_->ShowDialog( + base::Bind(&ShowPermissionsDialogHelper::OnInstallPromptDone, + base::Unretained(this)), + extension, nullptr, std::move(prompt), + ExtensionInstallPrompt::GetDefaultShowDialogCallback()); } -// This is called when the user clicks "Revoke File Access." -void ShowPermissionsDialogHelper::InstallUIProceed() { - const Extension* extension = - ExtensionRegistry::Get(profile_)->GetExtensionById( - extension_id_, ExtensionRegistry::EVERYTHING); +void ShowPermissionsDialogHelper::OnInstallPromptDone( + ExtensionInstallPrompt::Result result) { + if (result == ExtensionInstallPrompt::Result::ACCEPTED) { + // This is true when the user clicks "Revoke File Access." + const Extension* extension = + ExtensionRegistry::Get(profile_) + ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING); - if (extension) - apps::SavedFilesService::Get(profile_)->ClearQueue(extension); - apps::AppLoadService::Get(profile_) - ->RestartApplicationIfRunning(extension_id_); + if (extension) + apps::SavedFilesService::Get(profile_)->ClearQueue(extension); + apps::AppLoadService::Get(profile_) + ->RestartApplicationIfRunning(extension_id_); + } on_complete_.Run(); - - delete this; -} - -void ShowPermissionsDialogHelper::InstallUIAbort(bool user_initiated) { - on_complete_.Run(); - delete this; }
diff --git a/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.h b/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.h index 40bc916f..aafd468 100644 --- a/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.h +++ b/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.h
@@ -23,7 +23,7 @@ // Helper class to handle showing a permissions dialog for an extension. Will // show either the newer AppInfo-style permissions dialog, or the traditional, // install-prompt style dialog. -class ShowPermissionsDialogHelper : public ExtensionInstallPrompt::Delegate { +class ShowPermissionsDialogHelper { public: static void Show(content::BrowserContext* browser_context, content::WebContents* web_contents, @@ -34,15 +34,13 @@ private: ShowPermissionsDialogHelper(Profile* profile, const base::Closure& on_complete); - ~ShowPermissionsDialogHelper() override; // Manages its own lifetime. + ~ShowPermissionsDialogHelper(); // Manages its own lifetime. // Shows the old-style (not AppInfo) permissions dialog. void ShowPermissionsDialog(content::WebContents* web_contents, const Extension* extension); - // ExtensionInstallPrompt::Delegate: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); scoped_ptr<ExtensionInstallPrompt> prompt_;
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc index a139877..64381675 100644 --- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc +++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
@@ -132,6 +132,15 @@ SET_STRING("privacy-note", IDS_FEEDBACK_PRIVACY_NOTE); SET_STRING("performance-trace", IDS_FEEDBACK_INCLUDE_PERFORMANCE_TRACE_CHECKBOX); + // Add the localized strings needed for the "system information" page. + SET_STRING("sysinfoPageTitle", IDS_FEEDBACK_SYSINFO_PAGE_TITLE); + SET_STRING("sysinfoPageDescription", IDS_ABOUT_SYS_DESC); + SET_STRING("sysinfoPageTableTitle", IDS_ABOUT_SYS_TABLE_TITLE); + SET_STRING("sysinfoPageExpandAllBtn", IDS_ABOUT_SYS_EXPAND_ALL); + SET_STRING("sysinfoPageCollapseAllBtn", IDS_ABOUT_SYS_COLLAPSE_ALL); + SET_STRING("sysinfoPageExpandBtn", IDS_ABOUT_SYS_EXPAND); + SET_STRING("sysinfoPageCollapseBtn", IDS_ABOUT_SYS_COLLAPSE); + SET_STRING("sysinfoPageStatusLoading", IDS_FEEDBACK_SYSINFO_PAGE_LOADING); #undef SET_STRING const std::string& app_locale = g_browser_process->GetApplicationLocale();
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc index 2ee92b5b..d15eef3 100644 --- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc +++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/extensions/api/management/chrome_management_api_delegate.h" +#include "base/callback_helpers.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/extensions/bookmark_app_helper.h" @@ -41,38 +42,43 @@ namespace { class ManagementSetEnabledFunctionInstallPromptDelegate - : public ExtensionInstallPrompt::Delegate, - public extensions::InstallPromptDelegate { + : public extensions::InstallPromptDelegate { public: ManagementSetEnabledFunctionInstallPromptDelegate( - extensions::ManagementSetEnabledFunction* function, - const extensions::Extension* extension) - : function_(function) { - install_prompt_.reset( - new ExtensionInstallPrompt(function->GetSenderWebContents())); + content::WebContents* web_contents, + content::BrowserContext* browser_context, + const extensions::Extension* extension, + const base::Callback<void(bool)>& callback) + : install_prompt_(new ExtensionInstallPrompt(web_contents)), + callback_(callback), + weak_factory_(this) { ExtensionInstallPrompt::PromptType type = ExtensionInstallPrompt::GetReEnablePromptTypeForExtension( - function->browser_context(), extension); + browser_context, extension); install_prompt_->ShowDialog( - this, extension, nullptr, + base::Bind(&ManagementSetEnabledFunctionInstallPromptDelegate:: + OnInstallPromptDone, + weak_factory_.GetWeakPtr()), + extension, nullptr, make_scoped_ptr(new ExtensionInstallPrompt::Prompt(type)), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); } ~ManagementSetEnabledFunctionInstallPromptDelegate() override {} - protected: - // ExtensionInstallPrompt::Delegate. - void InstallUIProceed() override { function_->InstallUIProceed(); } - void InstallUIAbort(bool user_initiated) override { - function_->InstallUIAbort(user_initiated); - } - private: - extensions::ManagementSetEnabledFunction* function_; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result) { + base::ResetAndReturn(&callback_).Run( + result == ExtensionInstallPrompt::Result::ACCEPTED); + } // Used for prompting to re-enable items with permissions escalation updates. scoped_ptr<ExtensionInstallPrompt> install_prompt_; + base::Callback<void(bool)> callback_; + + base::WeakPtrFactory<ManagementSetEnabledFunctionInstallPromptDelegate> + weak_factory_; + DISALLOW_COPY_AND_ASSIGN(ManagementSetEnabledFunctionInstallPromptDelegate); }; @@ -209,11 +215,13 @@ scoped_ptr<extensions::InstallPromptDelegate> ChromeManagementAPIDelegate::SetEnabledFunctionDelegate( - extensions::ManagementSetEnabledFunction* function, - const extensions::Extension* extension) const { + content::WebContents* web_contents, + content::BrowserContext* browser_context, + const extensions::Extension* extension, + const base::Callback<void(bool)>& callback) const { return scoped_ptr<ManagementSetEnabledFunctionInstallPromptDelegate>( - new ManagementSetEnabledFunctionInstallPromptDelegate(function, - extension)); + new ManagementSetEnabledFunctionInstallPromptDelegate( + web_contents, browser_context, extension, callback)); } scoped_ptr<extensions::RequirementsChecker>
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.h b/chrome/browser/extensions/api/management/chrome_management_api_delegate.h index 1c16eab7..73c417a 100644 --- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.h +++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.h
@@ -31,8 +31,10 @@ extensions::ManagementGetPermissionWarningsByManifestFunction* function, const std::string& manifest_str) const override; scoped_ptr<extensions::InstallPromptDelegate> SetEnabledFunctionDelegate( - extensions::ManagementSetEnabledFunction* function, - const extensions::Extension* extension) const override; + content::WebContents* web_contents, + content::BrowserContext* browser_context, + const extensions::Extension* extension, + const base::Callback<void(bool)>& callback) const override; scoped_ptr<extensions::RequirementsChecker> CreateRequirementsChecker() const override; scoped_ptr<extensions::UninstallDialogDelegate> UninstallFunctionDelegate(
diff --git a/chrome/browser/extensions/api/management/management_api_browsertest.cc b/chrome/browser/extensions/api/management/management_api_browsertest.cc index f55175e..3bfa548b 100644 --- a/chrome/browser/extensions/api/management/management_api_browsertest.cc +++ b/chrome/browser/extensions/api/management/management_api_browsertest.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_function_test_utils.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/install_verifier.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -44,6 +45,9 @@ content::CrashTab(background_host->host_contents()); return true; } + + private: + ScopedInstallVerifierBypassForTest install_verifier_bypass_; }; // We test this here instead of in an ExtensionApiTest because normal extensions @@ -234,14 +238,8 @@ const char ExtensionManagementApiEscalationTest::kId[] = "pgdpcfcocojkjfbgpiianjngphoopgmo"; -// Temporarily disabled in official builds. See crbug.com/567497 for details. -#if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN) -#define MAYBE_DisabledReason DISABLED_DisabledReason -#else -#define MAYBE_DisabledReason DisabledReason -#endif // defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN) IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest, - MAYBE_DisabledReason) { + DisabledReason) { scoped_refptr<ManagementGetFunction> function = new ManagementGetFunction(); scoped_ptr<base::Value> result(util::RunFunctionAndReturnSingleResult( @@ -257,13 +255,8 @@ EXPECT_EQ(reason, std::string(keys::kDisabledReasonPermissionsIncrease)); } -// Temporarily disabled in official builds. See crbug.com/567497 for details. -#if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN) -#define MAYBE_SetEnabled DISABLED_SetEnabled -#else -#define MAYBE_SetEnabled SetEnabled -#endif // defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN) -IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest, MAYBE_SetEnabled) { +IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest, + SetEnabled) { // Expect an error about no gesture. SetEnabled(true, false, keys::kGestureNeededForEscalationError);
diff --git a/chrome/browser/extensions/api/management/management_browsertest.cc b/chrome/browser/extensions/api/management/management_browsertest.cc index fcac075..86ff346 100644 --- a/chrome/browser/extensions/api/management/management_browsertest.cc +++ b/chrome/browser/extensions/api/management/management_browsertest.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_management.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/install_verifier.h" #include "chrome/browser/extensions/updater/extension_updater.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" @@ -108,6 +109,7 @@ private: policy::MockConfigurationPolicyProvider policy_provider_; + extensions::ScopedInstallVerifierBypassForTest install_verifier_bypass_; }; #if defined(OS_LINUX) || defined(OS_WIN) @@ -439,13 +441,7 @@ notification_listener.Reset(); } -// Temporarily disabled in official builds. See crbug.com/567497 for details. -#if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN) -#define MAYBE_ExternalUrlUpdate DISABLED_ExternalUrlUpdate -#else -#define MAYBE_ExternalUrlUpdate ExternalUrlUpdate -#endif // defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN) -IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, MAYBE_ExternalUrlUpdate) { +IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) { ExtensionService* service = extensions::ExtensionSystem::Get( browser()->profile())->extension_service(); const char kExtensionId[] = "ogjcoiohnmldgjemafoockdghcjciccf";
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.cc b/chrome/browser/extensions/api/permissions/permissions_api.cc index 82f7aac..464b0f6 100644 --- a/chrome/browser/extensions/api/permissions/permissions_api.cc +++ b/chrome/browser/extensions/api/permissions/permissions_api.cc
@@ -141,22 +141,6 @@ PermissionsRequestFunction::PermissionsRequestFunction() {} -void PermissionsRequestFunction::InstallUIProceed() { - PermissionsUpdater perms_updater(GetProfile()); - perms_updater.AddPermissions(extension(), *requested_permissions_); - - results_ = Request::Results::Create(true); - SendResponse(true); - - Release(); // Balanced in RunAsync(). -} - -void PermissionsRequestFunction::InstallUIAbort(bool user_initiated) { - SendResponse(true); - - Release(); // Balanced in RunAsync(). -} - PermissionsRequestFunction::~PermissionsRequestFunction() {} bool PermissionsRequestFunction::RunAsync() { @@ -227,7 +211,7 @@ *requested_permissions_, extension()->permissions_data()->active_permissions()); - AddRef(); // Balanced in InstallUIProceed() / InstallUIAbort(). + AddRef(); // Balanced in OnInstallPromptDone(). // We don't need to show the prompt if there are no new warnings, or if // we're skipping the confirmation UI. All extension types but INTERNAL @@ -241,15 +225,16 @@ .empty(); if (auto_confirm_for_tests == PROCEED || has_no_warnings || extension_->location() == Manifest::COMPONENT) { - InstallUIProceed(); + OnInstallPromptDone(ExtensionInstallPrompt::Result::ACCEPTED); } else if (auto_confirm_for_tests == ABORT) { // Pretend the user clicked cancel. - InstallUIAbort(true); + OnInstallPromptDone(ExtensionInstallPrompt::Result::USER_CANCELED); } else { CHECK_EQ(DO_NOT_SKIP, auto_confirm_for_tests); install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents())); install_ui_->ShowDialog( - this, extension(), nullptr, + base::Bind(&PermissionsRequestFunction::OnInstallPromptDone, this), + extension(), nullptr, make_scoped_ptr(new ExtensionInstallPrompt::Prompt( ExtensionInstallPrompt::PERMISSIONS_PROMPT)), requested_permissions_->Clone(), @@ -259,4 +244,17 @@ return true; } +void PermissionsRequestFunction::OnInstallPromptDone( + ExtensionInstallPrompt::Result result) { + if (result == ExtensionInstallPrompt::Result::ACCEPTED) { + PermissionsUpdater perms_updater(GetProfile()); + perms_updater.AddPermissions(extension(), *requested_permissions_); + + results_ = Request::Results::Create(true); + } + + SendResponse(true); + Release(); // Balanced in RunAsync(). +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.h b/chrome/browser/extensions/api/permissions/permissions_api.h index cff53326..47884da 100644 --- a/chrome/browser/extensions/api/permissions/permissions_api.h +++ b/chrome/browser/extensions/api/permissions/permissions_api.h
@@ -8,6 +8,7 @@ #include <string> #include "base/compiler_specific.h" +#include "base/macros.h" #include "chrome/browser/extensions/chrome_extension_function.h" #include "chrome/browser/extensions/extension_install_prompt.h" #include "extensions/common/permissions/permission_set.h" @@ -51,8 +52,7 @@ }; // chrome.permissions.request -class PermissionsRequestFunction : public ChromeAsyncExtensionFunction, - public ExtensionInstallPrompt::Delegate { +class PermissionsRequestFunction : public ChromeAsyncExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("permissions.request", PERMISSIONS_REQUEST) @@ -62,10 +62,6 @@ static void SetAutoConfirmForTests(bool should_proceed); static void SetIgnoreUserGestureForTests(bool ignore); - // ExtensionInstallPrompt::Delegate: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; - protected: ~PermissionsRequestFunction() override; @@ -73,8 +69,12 @@ bool RunAsync() override; private: + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); + scoped_ptr<ExtensionInstallPrompt> install_ui_; scoped_ptr<const PermissionSet> requested_permissions_; + + DISALLOW_COPY_AND_ASSIGN(PermissionsRequestFunction); }; } // namespace extensions
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc index 6b8c944..a1176106 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -988,13 +988,20 @@ continue; } - if (!title.empty() && !base::MatchPattern(web_contents->GetTitle(), - base::UTF8ToUTF16(title))) - continue; + // "title" and "url" properties are considered privileged data and can + // only be checked if the extension has the "tabs" permission. Otherwise, + // these properties are ignored. + if (extension_->permissions_data()->HasAPIPermissionForTab( + ExtensionTabUtil::GetTabId(web_contents), APIPermission::kTab)) { + if (!title.empty() && + !base::MatchPattern(web_contents->GetTitle(), + base::UTF8ToUTF16(title))) + continue; - if (!url_patterns.is_empty() && - !url_patterns.MatchesURL(web_contents->GetURL())) - continue; + if (!url_patterns.is_empty() && + !url_patterns.MatchesURL(web_contents->GetURL())) + continue; + } if (loading_status_set && loading != web_contents->IsLoading()) continue;
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc new file mode 100644 index 0000000..dcc07b0 --- /dev/null +++ b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -0,0 +1,130 @@ +// 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 "base/strings/utf_string_conversions.h" +#include "chrome/browser/extensions/api/tabs/tabs_api.h" +#include "chrome/browser/extensions/extension_function_test_utils.h" +#include "chrome/browser/extensions/extension_service_test_base.h" +#include "chrome/browser/extensions/extension_tab_util.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/host_desktop.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/test/base/test_browser_window.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/test/test_web_contents_factory.h" +#include "content/public/test/web_contents_tester.h" +#include "extensions/common/extension_builder.h" +#include "extensions/common/test_util.h" + +namespace extensions { + +namespace { + +scoped_ptr<base::ListValue> RunTabsQueryFunction( + Browser* browser, + const Extension* extension, + const std::string& query_info) { + scoped_refptr<TabsQueryFunction> function(new TabsQueryFunction()); + function->set_extension(extension); + scoped_ptr<base::Value> value( + extension_function_test_utils::RunFunctionAndReturnSingleResult( + function.get(), query_info, browser, + extension_function_test_utils::NONE)); + return base::ListValue::From(std::move(value)); +} + +} // namespace + +class TabsApiUnitTest : public ExtensionServiceTestBase { + protected: + TabsApiUnitTest() {} + ~TabsApiUnitTest() override {} + + Browser* browser() { return browser_.get(); } + + private: + // ExtensionServiceTestBase: + void SetUp() override; + void TearDown() override; + + // The browser (and accompanying window). + scoped_ptr<TestBrowserWindow> browser_window_; + scoped_ptr<Browser> browser_; + + DISALLOW_COPY_AND_ASSIGN(TabsApiUnitTest); +}; + +void TabsApiUnitTest::SetUp() { + ExtensionServiceTestBase::SetUp(); + InitializeEmptyExtensionService(); + + browser_window_.reset(new TestBrowserWindow()); + Browser::CreateParams params(profile(), chrome::HOST_DESKTOP_TYPE_NATIVE); + params.type = Browser::TYPE_TABBED; + params.window = browser_window_.get(); + browser_.reset(new Browser(params)); +} + +void TabsApiUnitTest::TearDown() { + browser_.reset(); + browser_window_.reset(); + ExtensionServiceTestBase::TearDown(); +} + +TEST_F(TabsApiUnitTest, QueryWithoutTabsPermission) { + GURL tab_urls[] = {GURL("http://www.google.com"), + GURL("http://www.example.com"), + GURL("https://www.google.com")}; + std::string tab_titles[] = {"", "Sample title", "Sample title"}; + + // Add 3 web contentses to the browser. + content::TestWebContentsFactory factory; + content::WebContents* web_contentses[arraysize(tab_urls)]; + for (size_t i = 0; i < arraysize(tab_urls); ++i) { + content::WebContents* web_contents = factory.CreateWebContents(profile()); + web_contentses[i] = web_contents; + browser()->tab_strip_model()->AppendWebContents(web_contents, true); + EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(), + web_contents); + content::WebContentsTester* web_contents_tester = + content::WebContentsTester::For(web_contents); + web_contents_tester->NavigateAndCommit(tab_urls[i]); + web_contents->GetController().GetVisibleEntry()->SetTitle( + base::ASCIIToUTF16(tab_titles[i])); + } + + const char* kTitleAndURLQueryInfo = + "[{\"title\": \"Sample title\", \"url\": \"*://www.google.com/*\"}]"; + + // An extension without "tabs" permission will see all 3 tabs, because the + // query_info filter will be ignored. + scoped_refptr<const Extension> extension = test_util::CreateEmptyExtension(); + scoped_ptr<base::ListValue> tabs_list_without_permission( + RunTabsQueryFunction(browser(), extension.get(), kTitleAndURLQueryInfo)); + ASSERT_TRUE(tabs_list_without_permission); + EXPECT_EQ(3u, tabs_list_without_permission->GetSize()); + + // An extension with "tabs" permission however will only see the third tab. + scoped_refptr<const Extension> extension_with_permission = + ExtensionBuilder() + .SetManifest(std::move( + DictionaryBuilder() + .Set("name", "Extension with tabs permission") + .Set("version", "1.0") + .Set("manifest_version", 2) + .Set("permissions", std::move(ListBuilder().Append("tabs"))))) + .Build(); + scoped_ptr<base::ListValue> tabs_list_with_permission(RunTabsQueryFunction( + browser(), extension_with_permission.get(), kTitleAndURLQueryInfo)); + ASSERT_TRUE(tabs_list_with_permission); + ASSERT_EQ(1u, tabs_list_with_permission->GetSize()); + + const base::DictionaryValue* third_tab_info; + ASSERT_TRUE(tabs_list_with_permission->GetDictionary(0, &third_tab_info)); + int third_tab_id; + ASSERT_TRUE(third_tab_info->GetInteger("id", &third_tab_id)); + EXPECT_EQ(ExtensionTabUtil::GetTabId(web_contentses[2]), third_tab_id); +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc b/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc index 01e9c51c..b45809c6 100644 --- a/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc +++ b/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
@@ -118,6 +118,17 @@ VpnProviderApiTest() {} ~VpnProviderApiTest() override {} + void SetUpOnMainThread() override { + ExtensionApiTest::SetUpOnMainThread(); + NetworkHandler::Get()->network_configuration_handler()->AddObserver(this); + } + + void TearDownOnMainThread() override { + ExtensionApiTest::TearDownOnMainThread(); + NetworkHandler::Get()->network_configuration_handler()->RemoveObserver( + this); + } + void SetUpInProcessBrowserTestFixture() override { ExtensionApiTest::SetUpInProcessBrowserTestFixture(); test_client_ = new TestShillThirdPartyVpnDriverClient(); @@ -135,7 +146,6 @@ } void LoadVpnExtension() { - NetworkHandler::Get()->network_configuration_handler()->AddObserver(this); extension_ = LoadExtension(test_data_dir_.AppendASCII("vpn_provider")); extension_id_ = extension_->id(); service_ = VpnServiceFactory::GetForBrowserContext(profile());
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc index ca0831a..c88e10e 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -291,9 +291,12 @@ } install_prompt_.reset(new ExtensionInstallPrompt(web_contents)); install_prompt_->ShowDialog( - this, dummy_extension_.get(), &icon_, + base::Bind(&WebstorePrivateBeginInstallWithManifest3Function:: + OnInstallPromptDone, + this), + dummy_extension_.get(), &icon_, ExtensionInstallPrompt::GetDefaultShowDialogCallback()); - // Control flow finishes up in InstallUIProceed or InstallUIAbort. + // Control flow finishes up in OnInstallPromptDone. } void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseFailure( @@ -309,7 +312,19 @@ Release(); } -void WebstorePrivateBeginInstallWithManifest3Function::InstallUIProceed() { +void WebstorePrivateBeginInstallWithManifest3Function::OnInstallPromptDone( + ExtensionInstallPrompt::Result result) { + if (result == ExtensionInstallPrompt::Result::ACCEPTED) { + HandleInstallProceed(); + } else { + HandleInstallAbort(result == ExtensionInstallPrompt::Result::USER_CANCELED); + } + + // Matches the AddRef in Run(). + Release(); +} + +void WebstorePrivateBeginInstallWithManifest3Function::HandleInstallProceed() { // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in // the future we may also want to add time-based expiration, where a whitelist // entry is only valid for some number of minutes. @@ -338,12 +353,9 @@ dummy_extension_.get(), "WebStoreInstall"); Respond(BuildResponse(api::webstore_private::RESULT_SUCCESS, std::string())); - - // Matches the AddRef in Run(). - Release(); } -void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbort( +void WebstorePrivateBeginInstallWithManifest3Function::HandleInstallAbort( bool user_initiated) { // The web store install histograms are a subset of the install histograms. // We need to record both histograms here since CrxInstaller::InstallUIAbort @@ -359,9 +371,6 @@ Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED, kUserCancelledError)); - - // Matches the AddRef in Run(). - Release(); } ExtensionFunction::ResponseValue
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h index 457a18f..91a94b6 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
@@ -46,7 +46,6 @@ class WebstorePrivateBeginInstallWithManifest3Function : public UIThreadExtensionFunction, - public ExtensionInstallPrompt::Delegate, public WebstoreInstallHelper::Delegate { public: DECLARE_EXTENSION_FUNCTION("webstorePrivate.beginInstallWithManifest3", @@ -70,9 +69,10 @@ InstallHelperResultCode result, const std::string& error_message) override; - // ExtensionInstallPrompt::Delegate: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); + + void HandleInstallProceed(); + void HandleInstallAbort(bool user_initiated); ExtensionFunction::ResponseValue BuildResponse( api::webstore_private::Result result,
diff --git a/chrome/browser/extensions/bundle_installer.cc b/chrome/browser/extensions/bundle_installer.cc index 7e6d269..c710559 100644 --- a/chrome/browser/extensions/bundle_installer.cc +++ b/chrome/browser/extensions/bundle_installer.cc
@@ -113,7 +113,8 @@ authuser_(authuser), delegated_username_(delegated_username), host_desktop_type_(browser->host_desktop_type()), - profile_(browser->profile()) { + profile_(browser->profile()), + weak_factory_(this) { BrowserList::AddObserver(this); for (size_t i = 0; i < items.size(); ++i) { items_[items[i].id] = items[i]; @@ -270,9 +271,9 @@ } if (g_auto_approve_for_test == PROCEED) { - InstallUIProceed(); + OnInstallPromptDone(ExtensionInstallPrompt::Result::ACCEPTED); } else if (g_auto_approve_for_test == ABORT) { - InstallUIAbort(true); + OnInstallPromptDone(ExtensionInstallPrompt::Result::USER_CANCELED); } else { Browser* browser = browser_; if (!browser) { @@ -295,7 +296,9 @@ } prompt->set_bundle(this); install_ui_->ShowDialog( - this, nullptr, &icon_, std::move(prompt), std::move(permissions), + base::Bind(&BundleInstaller::OnInstallPromptDone, + weak_factory_.GetWeakPtr()), + nullptr, &icon_, std::move(prompt), std::move(permissions), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); } } @@ -332,16 +335,21 @@ ShowPromptIfDoneParsing(); } -void BundleInstaller::InstallUIProceed() { - approved_ = true; - approval_callback_.Run(APPROVED); -} +void BundleInstaller::OnInstallPromptDone( + ExtensionInstallPrompt::Result result) { + ApprovalState state = APPROVED; + if (result == ExtensionInstallPrompt::Result::ACCEPTED) { + approved_ = true; + state = APPROVED; + } else { + for (std::pair<const std::string, Item>& entry : items_) + entry.second.state = Item::STATE_FAILED; -void BundleInstaller::InstallUIAbort(bool user_initiated) { - for (std::pair<const std::string, Item>& entry : items_) - entry.second.state = Item::STATE_FAILED; - - approval_callback_.Run(user_initiated ? USER_CANCELED : APPROVAL_ERROR); + state = result == ExtensionInstallPrompt::Result::USER_CANCELED + ? USER_CANCELED + : APPROVAL_ERROR; + } + approval_callback_.Run(state); } void BundleInstaller::OnExtensionInstallSuccess(const std::string& id) {
diff --git a/chrome/browser/extensions/bundle_installer.h b/chrome/browser/extensions/bundle_installer.h index 8945f82..cd8fe90 100644 --- a/chrome/browser/extensions/bundle_installer.h +++ b/chrome/browser/extensions/bundle_installer.h
@@ -14,6 +14,7 @@ #include "base/macros.h" #include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/strings/string16.h" #include "chrome/browser/extensions/extension_install_prompt.h" #include "chrome/browser/extensions/webstore_install_helper.h" @@ -44,7 +45,6 @@ // 2) CompleteInstall: install the CRXs and show confirmation bubble // class BundleInstaller : public WebstoreInstallHelper::Delegate, - public ExtensionInstallPrompt::Delegate, public WebstoreInstaller::Delegate, public chrome::BrowserListObserver { public: @@ -158,10 +158,6 @@ InstallHelperResultCode result_code, const std::string& error_message) override; - // ExtensionInstallPrompt::Delegate implementation: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; - // WebstoreInstaller::Delegate implementation: void OnExtensionInstallSuccess(const std::string& id) override; void OnExtensionInstallFailure( @@ -172,6 +168,8 @@ // chrome::BrowserListObserver implementation: void OnBrowserRemoved(Browser* browser) override; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); + // Holds the Extensions used to generate the permission warnings. ExtensionList dummy_extensions_; @@ -213,6 +211,8 @@ ApprovalCallback approval_callback_; base::Closure install_callback_; + base::WeakPtrFactory<BundleInstaller> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(BundleInstaller); };
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc index 2849e123..9221e8da 100644 --- a/chrome/browser/extensions/chrome_extensions_browser_client.cc +++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -358,11 +358,11 @@ ViewType view_type) { switch (view_type) { case VIEW_TYPE_APP_WINDOW: + case VIEW_TYPE_COMPONENT: case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE: case VIEW_TYPE_EXTENSION_DIALOG: case VIEW_TYPE_EXTENSION_POPUP: case VIEW_TYPE_LAUNCHER_PAGE: - case VIEW_TYPE_VIRTUAL_KEYBOARD: // These are the only types that are tracked by the ExtensionTag. task_management::WebContentsTags::CreateForExtension(web_contents, view_type);
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc index 3663a17..372bb926 100644 --- a/chrome/browser/extensions/crx_installer.cc +++ b/chrome/browser/extensions/crx_installer.cc
@@ -627,8 +627,9 @@ if (client_ && (!allow_silent_install_ || !approved_) && !update_from_settings_page_) { - AddRef(); // Balanced in InstallUIProceed() and InstallUIAbort(). - client_->ShowDialog(this, extension(), nullptr, show_dialog_callback_); + AddRef(); // Balanced in OnInstallPromptDone(). + client_->ShowDialog(base::Bind(&CrxInstaller::OnInstallPromptDone, this), + extension(), nullptr, show_dialog_callback_); } else { if (!installer_task_runner_->PostTask( FROM_HERE, @@ -638,37 +639,30 @@ return; } -void CrxInstaller::InstallUIProceed() { +void CrxInstaller::OnInstallPromptDone(ExtensionInstallPrompt::Result result) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - ExtensionService* service = service_weak_.get(); - if (!service || service->browser_terminating()) - return; - // If update_from_settings_page_ boolean is true, this functions is // getting called in response to ExtensionInstallPrompt::ConfirmReEnable() // and if it is false, this function is called in response to // ExtensionInstallPrompt::ShowDialog(). - if (update_from_settings_page_) { - service->GrantPermissionsAndEnableExtension(extension()); - } else { - if (!installer_task_runner_->PostTask( - FROM_HERE, - base::Bind(&CrxInstaller::CompleteInstall, this))) + if (result == ExtensionInstallPrompt::Result::ACCEPTED) { + ExtensionService* service = service_weak_.get(); + if (!service || service->browser_terminating()) + return; + + if (update_from_settings_page_) { + service->GrantPermissionsAndEnableExtension(extension()); + } else if (!installer_task_runner_->PostTask( + FROM_HERE, + base::Bind(&CrxInstaller::CompleteInstall, this))) { NOTREACHED(); - } - - Release(); // balanced in ConfirmInstall() or ConfirmReEnable(). -} - -void CrxInstaller::InstallUIAbort(bool user_initiated) { - // If update_from_settings_page_ boolean is true, this functions is - // getting called in response to ExtensionInstallPrompt::ConfirmReEnable() - // and if it is false, this function is called in response to - // ExtensionInstallPrompt::ShowDialog(). - if (!update_from_settings_page_) { - const char* histogram_name = user_initiated ? "InstallCancel" - : "InstallAbort"; + } + } else if (!update_from_settings_page_) { + const char* histogram_name = + result == ExtensionInstallPrompt::Result::USER_CANCELED + ? "InstallCancel" + : "InstallAbort"; ExtensionService::RecordPermissionMessagesHistogram( extension(), histogram_name); @@ -676,9 +670,6 @@ } Release(); // balanced in ConfirmInstall() or ConfirmReEnable(). - - // We're done. Since we don't post any more tasks to ourself, our ref count - // should go to zero and we die. The destructor will clean up the temp dir. } void CrxInstaller::CompleteInstall() { @@ -912,13 +903,13 @@ return; if (client_) { - AddRef(); // Balanced in InstallUIProceed() and InstallUIAbort(). + AddRef(); // Balanced in OnInstallPromptDone(). ExtensionInstallPrompt::PromptType type = ExtensionInstallPrompt::GetReEnablePromptTypeForExtension( service->profile(), extension()); client_->ShowDialog( - this, extension(), nullptr, - make_scoped_ptr(new ExtensionInstallPrompt::Prompt(type)), + base::Bind(&CrxInstaller::OnInstallPromptDone, this), extension(), + nullptr, make_scoped_ptr(new ExtensionInstallPrompt::Prompt(type)), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); } }
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h index 963bdb5..1b72eec 100644 --- a/chrome/browser/extensions/crx_installer.h +++ b/chrome/browser/extensions/crx_installer.h
@@ -67,9 +67,7 @@ // terminating during the install. We can't listen for the app termination // notification here in this class because it can be destroyed on any thread // and won't safely be able to clean up UI thread notification listeners. -class CrxInstaller - : public SandboxedUnpackerClient, - public ExtensionInstallPrompt::Delegate { +class CrxInstaller : public SandboxedUnpackerClient { public: // Used in histograms; do not change order. enum OffStoreInstallAllowReason { @@ -108,9 +106,7 @@ // Convert the specified web app into an extension and install it. void InstallWebApp(const WebApplicationInfo& web_app); - // Overridden from ExtensionInstallPrompt::Delegate: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); int creation_flags() const { return creation_flags_; } void set_creation_flags(int val) { creation_flags_ = val; }
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc index 2c91df6..835f441d 100644 --- a/chrome/browser/extensions/extension_disabled_ui.cc +++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/lazy_instance.h" #include "base/location.h" +#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/metrics/histogram.h" @@ -68,28 +69,24 @@ // ExtensionDisabledDialogDelegate -------------------------------------------- -class ExtensionDisabledDialogDelegate - : public ExtensionInstallPrompt::Delegate, - public base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate> { +class ExtensionDisabledDialogDelegate { public: ExtensionDisabledDialogDelegate(ExtensionService* service, scoped_ptr<ExtensionInstallPrompt> install_ui, const Extension* extension); private: - friend class base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate>; + ~ExtensionDisabledDialogDelegate(); - ~ExtensionDisabledDialogDelegate() override; - - // ExtensionInstallPrompt::Delegate: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + void InstallPromptDone(ExtensionInstallPrompt::Result result); // The UI for showing the install dialog when enabling. scoped_ptr<ExtensionInstallPrompt> install_ui_; ExtensionService* service_; const Extension* extension_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionDisabledDialogDelegate); }; ExtensionDisabledDialogDelegate::ExtensionDisabledDialogDelegate( @@ -99,12 +96,15 @@ : install_ui_(std::move(install_ui)), service_(service), extension_(extension) { - AddRef(); // Balanced in Proceed or Abort. ExtensionInstallPrompt::PromptType type = ExtensionInstallPrompt::GetReEnablePromptTypeForExtension( service_->profile(), extension); + // Unretained() is safe since this object manages its own lifetime and deletes + // itself only once the prompt finishes. install_ui_->ShowDialog( - this, extension_, nullptr, + base::Bind(&ExtensionDisabledDialogDelegate::InstallPromptDone, + base::Unretained(this)), + extension_, nullptr, make_scoped_ptr(new ExtensionInstallPrompt::Prompt(type)), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); } @@ -112,19 +112,21 @@ ExtensionDisabledDialogDelegate::~ExtensionDisabledDialogDelegate() { } -void ExtensionDisabledDialogDelegate::InstallUIProceed() { - service_->GrantPermissionsAndEnableExtension(extension_); - Release(); -} +void ExtensionDisabledDialogDelegate::InstallPromptDone( + ExtensionInstallPrompt::Result result) { + if (result == ExtensionInstallPrompt::Result::ACCEPTED) { + service_->GrantPermissionsAndEnableExtension(extension_); + } else { + const char* histogram_name = + result == ExtensionInstallPrompt::Result::USER_CANCELED + ? "ReEnableCancel" + : "ReEnableAbort"; + ExtensionService::RecordPermissionMessagesHistogram(extension_, + histogram_name); + // Do nothing. The extension will remain disabled. + } -void ExtensionDisabledDialogDelegate::InstallUIAbort(bool user_initiated) { - std::string histogram_name = user_initiated ? "ReEnableCancel" - : "ReEnableAbort"; - ExtensionService::RecordPermissionMessagesHistogram( - extension_, histogram_name.c_str()); - - // Do nothing. The extension will remain disabled. - Release(); + delete this; } // ExtensionDisabledGlobalError -----------------------------------------------
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc index 2a0a016a..879d05e 100644 --- a/chrome/browser/extensions/extension_install_prompt.cc +++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/callback_helpers.h" #include "base/location.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -147,25 +148,22 @@ // If auto confirm is enabled then posts a task to proceed with or cancel the // install and returns true. Otherwise returns false. -bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate* delegate) { +bool AutoConfirmPrompt(ExtensionInstallPrompt::DoneCallback* callback) { switch (extensions::ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) { case extensions::ScopedTestDialogAutoConfirm::NONE: return false; - // We use PostTask instead of calling the delegate directly here, because in + // We use PostTask instead of calling the callback directly here, because in // the real implementations it's highly likely the message loop will be // pumping a few times before the user clicks accept or cancel. case extensions::ScopedTestDialogAutoConfirm::ACCEPT: base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed, - base::Unretained(delegate))); + FROM_HERE, base::Bind(base::ResetAndReturn(callback), + ExtensionInstallPrompt::Result::ACCEPTED)); return true; case extensions::ScopedTestDialogAutoConfirm::CANCEL: base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort, - base::Unretained(delegate), - true)); + FROM_HERE, base::Bind(base::ResetAndReturn(callback), + ExtensionInstallPrompt::Result::USER_CANCELED)); return true; } @@ -625,7 +623,6 @@ install_ui_(extensions::CreateExtensionInstallUI( ProfileForWebContents(contents))), show_params_(new ExtensionInstallPromptShowParams(contents)), - delegate_(NULL), did_call_show_dialog_(false) { } @@ -637,7 +634,6 @@ install_ui_(extensions::CreateExtensionInstallUI(profile)), show_params_( new ExtensionInstallPromptShowParams(profile, native_window)), - delegate_(NULL), did_call_show_dialog_(false) { } @@ -645,26 +641,26 @@ } void ExtensionInstallPrompt::ShowDialog( - Delegate* delegate, + const DoneCallback& done_callback, const Extension* extension, const SkBitmap* icon, const ShowDialogCallback& show_dialog_callback) { - ShowDialog(delegate, extension, icon, + ShowDialog(done_callback, extension, icon, make_scoped_ptr(new Prompt(INSTALL_PROMPT)), show_dialog_callback); } void ExtensionInstallPrompt::ShowDialog( - Delegate* delegate, + const DoneCallback& done_callback, const Extension* extension, const SkBitmap* icon, scoped_ptr<Prompt> prompt, const ShowDialogCallback& show_dialog_callback) { - ShowDialog(delegate, extension, icon, std::move(prompt), nullptr, + ShowDialog(done_callback, extension, icon, std::move(prompt), nullptr, show_dialog_callback); } void ExtensionInstallPrompt::ShowDialog( - Delegate* delegate, + const DoneCallback& done_callback, const Extension* extension, const SkBitmap* icon, scoped_ptr<Prompt> prompt, @@ -673,7 +669,7 @@ DCHECK(ui_loop_ == base::MessageLoop::current()); DCHECK(prompt); extension_ = extension; - delegate_ = delegate; + done_callback_ = done_callback; if (icon && !icon->empty()) SetIcon(icon); prompt_ = std::move(prompt); @@ -690,7 +686,7 @@ if (extension->is_theme()) { if (extension->from_webstore() || extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) { - delegate->InstallUIProceed(); + base::ResetAndReturn(&done_callback_).Run(Result::ACCEPTED); return; } } @@ -834,20 +830,19 @@ prompt_->set_icon(gfx::Image::CreateFrom1xBitmap(icon_)); if (show_params_->WasParentDestroyed()) { - delegate_->InstallUIAbort(false); + base::ResetAndReturn(&done_callback_).Run(Result::ABORTED); return; } g_last_prompt_type_for_tests = prompt_->type(); did_call_show_dialog_ = true; - if (AutoConfirmPrompt(delegate_)) + if (AutoConfirmPrompt(&done_callback_)) return; if (show_dialog_callback_.is_null()) - GetDefaultShowDialogCallback().Run(show_params_.get(), delegate_, - std::move(prompt_)); - else - show_dialog_callback_.Run(show_params_.get(), delegate_, - std::move(prompt_)); + show_dialog_callback_ = GetDefaultShowDialogCallback(); + base::ResetAndReturn(&show_dialog_callback_) + .Run(show_params_.get(), base::ResetAndReturn(&done_callback_), + std::move(prompt_)); }
diff --git a/chrome/browser/extensions/extension_install_prompt.h b/chrome/browser/extensions/extension_install_prompt.h index be05e42..f26d42a 100644 --- a/chrome/browser/extensions/extension_install_prompt.h +++ b/chrome/browser/extensions/extension_install_prompt.h
@@ -259,21 +259,16 @@ static const int kMinExtensionRating = 0; static const int kMaxExtensionRating = 5; - class Delegate { - public: - // We call this method to signal that the installation should continue. - virtual void InstallUIProceed() = 0; - - // We call this method to signal that the installation should stop, with - // |user_initiated| true if the installation was stopped by the user. - virtual void InstallUIAbort(bool user_initiated) = 0; - - protected: - virtual ~Delegate() {} + enum class Result { + ACCEPTED, + USER_CANCELED, + ABORTED, }; + using DoneCallback = base::Callback<void(Result result)>; + typedef base::Callback<void(ExtensionInstallPromptShowParams*, - ExtensionInstallPrompt::Delegate*, + const DoneCallback&, scoped_ptr<ExtensionInstallPrompt::Prompt>)> ShowDialogCallback; @@ -323,12 +318,12 @@ // |custom_permissions| will be used if provided; otherwise, the extensions // current permissions are used. // - // We *MUST* eventually call either Proceed() or Abort() on |delegate|. - void ShowDialog(Delegate* delegate, + // The |install_callback| *MUST* eventually be called. + void ShowDialog(const DoneCallback& install_callback, const extensions::Extension* extension, const SkBitmap* icon, const ShowDialogCallback& show_dialog_callback); - void ShowDialog(Delegate* delegate, + void ShowDialog(const DoneCallback& install_callback, const extensions::Extension* extension, const SkBitmap* icon, scoped_ptr<Prompt> prompt, @@ -337,7 +332,7 @@ // Note: if all you want to do is automatically confirm or cancel, prefer // ScopedTestDialogAutoConfirm from extension_dialog_auto_confirm.h virtual void ShowDialog( - Delegate* delegate, + const DoneCallback& install_callback, const extensions::Extension* extension, const SkBitmap* icon, scoped_ptr<Prompt> prompt, @@ -396,8 +391,8 @@ // Parameters to show the confirmation UI. scoped_ptr<ExtensionInstallPromptShowParams> show_params_; - // The delegate we will call Proceed/Abort on after confirmation UI. - Delegate* delegate_; + // The callback to run with the result. + DoneCallback done_callback_; // A pre-filled prompt. scoped_ptr<Prompt> prompt_;
diff --git a/chrome/browser/extensions/extension_install_prompt_browsertest.cc b/chrome/browser/extensions/extension_install_prompt_browsertest.cc index fe3dd93..9bdb94e1 100644 --- a/chrome/browser/extensions/extension_install_prompt_browsertest.cc +++ b/chrome/browser/extensions/extension_install_prompt_browsertest.cc
@@ -7,15 +7,19 @@ #include "base/macros.h" #include "base/run_loop.h" #include "chrome/browser/extensions/extension_install_prompt_show_params.h" +#include "chrome/browser/extensions/extension_install_prompt_test_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "content/public/test/test_utils.h" +#include "extensions/browser/extension_dialog_auto_confirm.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" #include "extensions/common/value_builder.h" +using extensions::ScopedTestDialogAutoConfirm; + namespace { scoped_refptr<extensions::Extension> BuildTestExtension() { @@ -26,49 +30,6 @@ .Build(); } -// ExtensionInstallPrompt::ShowDialogCallback which proceeds without showing the -// prompt. -void TestShowDialogCallback(ExtensionInstallPromptShowParams* params, - ExtensionInstallPrompt::Delegate* delegate, - scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) { - delegate->InstallUIProceed(); -} - -class TestExtensionInstallPromptDelegate - : public ExtensionInstallPrompt::Delegate { - public: - explicit TestExtensionInstallPromptDelegate(const base::Closure& quit_closure) - : quit_closure_(quit_closure), proceeded_(false), aborted_(false) {} - - ~TestExtensionInstallPromptDelegate() override { - } - - bool DidProceed() { - return proceeded_; - } - - bool DidAbort() { - return aborted_; - } - - private: - void InstallUIProceed() override { - proceeded_ = true; - quit_closure_.Run(); - } - - void InstallUIAbort(bool user_initiated) override { - aborted_ = true; - quit_closure_.Run(); - } - - base::Closure quit_closure_; - bool proceeded_; - bool aborted_; - - DISALLOW_COPY_AND_ASSIGN(TestExtensionInstallPromptDelegate); -}; - } // namespace typedef InProcessBrowserTest ExtensionInstallPromptBrowserTest; @@ -86,17 +47,21 @@ int web_contents_index = tab_strip_model->GetIndexOfWebContents(web_contents); scoped_refptr<extensions::Extension> extension(BuildTestExtension()); + ScopedTestDialogAutoConfirm auto_confirm(ScopedTestDialogAutoConfirm::ACCEPT); + ExtensionInstallPrompt prompt(web_contents); tab_strip_model->CloseWebContentsAt(web_contents_index, TabStripModel::CLOSE_NONE); content::RunAllPendingInMessageLoop(); base::RunLoop run_loop; - TestExtensionInstallPromptDelegate delegate(run_loop.QuitClosure()); - prompt.ShowDialog(&delegate, extension.get(), nullptr, - base::Bind(&TestShowDialogCallback)); + ExtensionInstallPromptTestHelper helper(run_loop.QuitClosure()); + prompt.ShowDialog( + helper.GetCallback(), + extension.get(), nullptr, + ExtensionInstallPrompt::GetDefaultShowDialogCallback()); run_loop.Run(); - EXPECT_TRUE(delegate.DidAbort()); + EXPECT_EQ(ExtensionInstallPrompt::Result::ABORTED, helper.result()); } // Test that ExtensionInstallPrompt aborts the install if the gfx::NativeWindow @@ -109,17 +74,21 @@ scoped_refptr<extensions::Extension> extension(BuildTestExtension()); + ScopedTestDialogAutoConfirm auto_confirm(ScopedTestDialogAutoConfirm::ACCEPT); + ExtensionInstallPrompt prompt(browser()->profile(), browser()->window()->GetNativeWindow()); browser()->window()->Close(); content::RunAllPendingInMessageLoop(); base::RunLoop run_loop; - TestExtensionInstallPromptDelegate delegate(run_loop.QuitClosure()); - prompt.ShowDialog(&delegate, extension.get(), nullptr, - base::Bind(&TestShowDialogCallback)); + ExtensionInstallPromptTestHelper helper(run_loop.QuitClosure()); + prompt.ShowDialog( + helper.GetCallback(), + extension.get(), nullptr, + ExtensionInstallPrompt::GetDefaultShowDialogCallback()); run_loop.Run(); - EXPECT_TRUE(delegate.DidAbort()); + EXPECT_EQ(ExtensionInstallPrompt::Result::ABORTED, helper.result()); } // Test that ExtensionInstallPrompt shows the dialog normally if no parent @@ -128,13 +97,15 @@ IN_PROC_BROWSER_TEST_F(ExtensionInstallPromptBrowserTest, NoParent) { scoped_refptr<extensions::Extension> extension(BuildTestExtension()); + ScopedTestDialogAutoConfirm auto_confirm(ScopedTestDialogAutoConfirm::ACCEPT); + ExtensionInstallPrompt prompt(browser()->profile(), NULL); base::RunLoop run_loop; - TestExtensionInstallPromptDelegate delegate(run_loop.QuitClosure()); - prompt.ShowDialog(&delegate, extension.get(), nullptr, - base::Bind(&TestShowDialogCallback)); + ExtensionInstallPromptTestHelper helper(run_loop.QuitClosure()); + prompt.ShowDialog( + helper.GetCallback(), + extension.get(), nullptr, + ExtensionInstallPrompt::GetDefaultShowDialogCallback()); run_loop.Run(); - - // TestShowDialogCallback() should have signaled the install to proceed. - EXPECT_TRUE(delegate.DidProceed()); + EXPECT_EQ(ExtensionInstallPrompt::Result::ACCEPTED, helper.result()); }
diff --git a/chrome/browser/extensions/extension_install_prompt_test_helper.cc b/chrome/browser/extensions/extension_install_prompt_test_helper.cc new file mode 100644 index 0000000..2f3460fe --- /dev/null +++ b/chrome/browser/extensions/extension_install_prompt_test_helper.cc
@@ -0,0 +1,38 @@ +// 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/extensions/extension_install_prompt_test_helper.h" + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" + +ExtensionInstallPromptTestHelper::ExtensionInstallPromptTestHelper() {} +ExtensionInstallPromptTestHelper::ExtensionInstallPromptTestHelper( + const base::Closure& quit_closure) : quit_closure_(quit_closure) {} +ExtensionInstallPromptTestHelper::~ExtensionInstallPromptTestHelper() {} + +ExtensionInstallPrompt::DoneCallback +ExtensionInstallPromptTestHelper::GetCallback() { + return base::Bind(&ExtensionInstallPromptTestHelper::HandleResult, + base::Unretained(this)); +} + +ExtensionInstallPrompt::Result +ExtensionInstallPromptTestHelper::result() const { + if (!result_.get()) { + ADD_FAILURE() << "Result was never set!"; + return ExtensionInstallPrompt::Result::ACCEPTED; // Avoid crashing. + } + return *result_; +} + +void ExtensionInstallPromptTestHelper::HandleResult( + ExtensionInstallPrompt::Result result) { + if (result_.get()) + ADD_FAILURE() << "HandleResult() called twice!"; + if (!quit_closure_.is_null()) + base::ResetAndReturn(&quit_closure_).Run(); + result_.reset(new ExtensionInstallPrompt::Result(result)); +}
diff --git a/chrome/browser/extensions/extension_install_prompt_test_helper.h b/chrome/browser/extensions/extension_install_prompt_test_helper.h new file mode 100644 index 0000000..dd7d2a9 --- /dev/null +++ b/chrome/browser/extensions/extension_install_prompt_test_helper.h
@@ -0,0 +1,39 @@ +// 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_EXTENSIONS_EXTENSION_INSTALL_PROMPT_TEST_HELPER_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_TEST_HELPER_H_ + +#include "base/macros.h" +#include "chrome/browser/extensions/extension_install_prompt.h" + +// A helper class to be used with ExtensionInstallPrompt that keeps track of the +// result. Note that this class does no lifetime management. +class ExtensionInstallPromptTestHelper { + public: + ExtensionInstallPromptTestHelper(); + explicit ExtensionInstallPromptTestHelper(const base::Closure& quit_closure); + ~ExtensionInstallPromptTestHelper(); + + // Returns a callback to be used with the ExtensionInstallPrompt. + ExtensionInstallPrompt::DoneCallback GetCallback(); + + // Note: This ADD_FAILURE()s if result_ has not been set. + ExtensionInstallPrompt::Result result() const; + + bool has_result() const { return result_.get() != nullptr; } + + private: + void HandleResult(ExtensionInstallPrompt::Result result); + + scoped_ptr<ExtensionInstallPrompt::Result> result_; + + // A closure to run once HandleResult() has been called; used for exiting + // run loops in tests. + base::Closure quit_closure_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionInstallPromptTestHelper); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_TEST_HELPER_H_
diff --git a/chrome/browser/extensions/extension_install_prompt_unittest.cc b/chrome/browser/extensions/extension_install_prompt_unittest.cc index 65eebf62..9ec8c3a 100644 --- a/chrome/browser/extensions/extension_install_prompt_unittest.cc +++ b/chrome/browser/extensions/extension_install_prompt_unittest.cc
@@ -40,7 +40,7 @@ const base::Closure& quit_closure, const SkBitmap& expected_bitmap, ExtensionInstallPromptShowParams* params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) { EXPECT_TRUE(gfx::BitmapsAreEqual(prompt->icon().AsBitmap(), expected_bitmap)); quit_closure.Run(); @@ -51,7 +51,7 @@ size_t regular_permissions_count, size_t withheld_permissions_count, ExtensionInstallPromptShowParams* params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> install_prompt) { ASSERT_TRUE(install_prompt.get()); EXPECT_EQ(regular_permissions_count, @@ -113,8 +113,7 @@ ExtensionInstallPrompt prompt(factory.CreateWebContents(profile())); base::RunLoop run_loop; prompt.ShowDialog( - nullptr, // no delegate - extension.get(), nullptr, + ExtensionInstallPrompt::DoneCallback(), extension.get(), nullptr, make_scoped_ptr(new ExtensionInstallPrompt::Prompt( ExtensionInstallPrompt::PERMISSIONS_PROMPT)), std::move(permission_set), @@ -151,7 +150,7 @@ // We expect <all_hosts> to be withheld, but http://www.google.com/ and tabs // permissions should be granted as regular permissions. prompt.ShowDialog( - nullptr, extension.get(), nullptr, + ExtensionInstallPrompt::DoneCallback(), extension.get(), nullptr, base::Bind(&VerifyPromptPermissionsCallback, run_loop.QuitClosure(), 2u, // |regular_permissions_count|. 1u)); // |withheld_permissions_count|. @@ -183,8 +182,8 @@ ExtensionInstallPrompt::DELEGATED_PERMISSIONS_PROMPT)); sub_prompt->set_delegated_username("Username"); prompt.ShowDialog( - nullptr, // no delegate - extension.get(), nullptr, std::move(sub_prompt), + ExtensionInstallPrompt::DoneCallback(), extension.get(), nullptr, + std::move(sub_prompt), base::Bind(&VerifyPromptPermissionsCallback, run_loop.QuitClosure(), 2u, // |regular_permissions_count|. 0u)); // |withheld_permissions_count|. @@ -221,7 +220,7 @@ { ExtensionInstallPrompt prompt(web_contents); base::RunLoop run_loop; - prompt.ShowDialog(nullptr, // No delegate. + prompt.ShowDialog(ExtensionInstallPrompt::DoneCallback(), extension, nullptr, // Force an icon fetch. base::Bind(&VerifyPromptIconCallback, @@ -233,7 +232,7 @@ ExtensionInstallPrompt prompt(web_contents); base::RunLoop run_loop; gfx::ImageSkia app_icon = util::GetDefaultAppIcon(); - prompt.ShowDialog(nullptr, // No delegate. + prompt.ShowDialog(ExtensionInstallPrompt::DoneCallback(), extension, app_icon.bitmap(), // Use a different icon. base::Bind(&VerifyPromptIconCallback,
diff --git a/chrome/browser/extensions/extension_reenabler.cc b/chrome/browser/extensions/extension_reenabler.cc index c957505a..8f35226 100644 --- a/chrome/browser/extensions/extension_reenabler.cc +++ b/chrome/browser/extensions/extension_reenabler.cc
@@ -70,7 +70,8 @@ callback_(callback), show_dialog_callback_(show_dialog_callback), finished_(false), - registry_observer_(this) { + registry_observer_(this), + weak_factory_(this) { DCHECK(extension_.get()); registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); @@ -90,32 +91,46 @@ ExtensionInstallPrompt::GetReEnablePromptTypeForExtension( browser_context, extension.get()); install_prompt_->ShowDialog( - this, extension.get(), nullptr, + base::Bind(&ExtensionReenabler::OnInstallPromptDone, + weak_factory_.GetWeakPtr()), + extension.get(), nullptr, make_scoped_ptr(new ExtensionInstallPrompt::Prompt(type)), show_dialog_callback_); } } -void ExtensionReenabler::InstallUIProceed() { - // Stop observing - we don't want to see our own enablement. - registry_observer_.RemoveAll(); +void ExtensionReenabler::OnInstallPromptDone( + ExtensionInstallPrompt::Result install_result) { + ReenableResult result = ABORTED; + switch (install_result) { + case ExtensionInstallPrompt::Result::ACCEPTED: { + // Stop observing - we don't want to see our own enablement. + registry_observer_.RemoveAll(); - ExtensionService* extension_service = - ExtensionSystem::Get(browser_context_)->extension_service(); - if (extension_service->browser_terminating()) { - Finish(ABORTED); - } else { - extension_service->GrantPermissionsAndEnableExtension(extension_.get()); - // The re-enable could have failed if the extension is disallowed by - // policy. - bool enabled = ExtensionRegistry::Get(browser_context_)-> - enabled_extensions().GetByID(extension_->id()) != nullptr; - Finish(enabled ? REENABLE_SUCCESS : NOT_ALLOWED); + ExtensionService* extension_service = + ExtensionSystem::Get(browser_context_)->extension_service(); + if (extension_service->browser_terminating()) { + result = ABORTED; + } else { + extension_service->GrantPermissionsAndEnableExtension(extension_.get()); + // The re-enable could have failed if the extension is disallowed by + // policy. + bool enabled = ExtensionRegistry::Get(browser_context_) + ->enabled_extensions() + .GetByID(extension_->id()) != nullptr; + result = enabled ? REENABLE_SUCCESS : NOT_ALLOWED; + } + break; + } + case ExtensionInstallPrompt::Result::USER_CANCELED: + result = USER_CANCELED; + break; + case ExtensionInstallPrompt::Result::ABORTED: + result = ABORTED; + break; } -} -void ExtensionReenabler::InstallUIAbort(bool user_initiated) { - Finish(user_initiated ? USER_CANCELED : ABORTED); + Finish(result); } void ExtensionReenabler::OnExtensionLoaded( @@ -152,7 +167,9 @@ ExtensionInstallPrompt::GetReEnablePromptTypeForExtension( browser_context_, extension_.get()); install_prompt_->ShowDialog( - this, extension_.get(), nullptr, + base::Bind(&ExtensionReenabler::OnInstallPromptDone, + weak_factory_.GetWeakPtr()), + extension_.get(), nullptr, make_scoped_ptr(new ExtensionInstallPrompt::Prompt(type)), show_dialog_callback_); }
diff --git a/chrome/browser/extensions/extension_reenabler.h b/chrome/browser/extensions/extension_reenabler.h index a87cbaf..7acd068 100644 --- a/chrome/browser/extensions/extension_reenabler.h +++ b/chrome/browser/extensions/extension_reenabler.h
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/scoped_observer.h" #include "chrome/browser/extensions/extension_install_prompt.h" #include "chrome/browser/extensions/webstore_data_fetcher_delegate.h" @@ -28,8 +29,7 @@ // increase. // TODO(devlin): Once we get the UI figured out, we should also have this handle // other disable reasons. -class ExtensionReenabler : public ExtensionInstallPrompt::Delegate, - public ExtensionRegistryObserver, +class ExtensionReenabler : public ExtensionRegistryObserver, public WebstoreDataFetcherDelegate { public: enum ReenableResult { @@ -72,9 +72,7 @@ content::WebContents* web_contents, const ExtensionInstallPrompt::ShowDialogCallback& show_callback); - // ExtensionInstallPrompt::Delegate: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); // ExtensionRegistryObserver: void OnExtensionLoaded(content::BrowserContext* browser_context, @@ -120,6 +118,8 @@ ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> registry_observer_; + base::WeakPtrFactory<ExtensionReenabler> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(ExtensionReenabler); };
diff --git a/chrome/browser/extensions/extension_reenabler_unittest.cc b/chrome/browser/extensions/extension_reenabler_unittest.cc index e6328c2..f0a0f12 100644 --- a/chrome/browser/extensions/extension_reenabler_unittest.cc +++ b/chrome/browser/extensions/extension_reenabler_unittest.cc
@@ -80,7 +80,7 @@ // The callback to run when a test ExtensionInstallPrompt is ready to show. void OnShow(ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) { DCHECK(!quit_closure_.is_null()); quit_closure_.Run();
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 511226ed..bdeb43d6 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -6042,13 +6042,15 @@ // Accept the first extension, this will remove the error associated with // this extension. Also verify the other errors still exist. - GetError(extension_ids[0])->InstallUIProceed(); + GetError(extension_ids[0])->OnInstallPromptDone( + ExtensionInstallPrompt::Result::ACCEPTED); EXPECT_FALSE(GetError(extension_ids[0])); ASSERT_TRUE(GetError(extension_ids[1])); EXPECT_TRUE(GetError(extension_ids[2])); // Abort the second extension. - GetError(extension_ids[1])->InstallUIAbort(true); + GetError(extension_ids[1])->OnInstallPromptDone( + ExtensionInstallPrompt::Result::USER_CANCELED); EXPECT_FALSE(GetError(extension_ids[0])); EXPECT_FALSE(GetError(extension_ids[1])); ASSERT_TRUE(GetError(extension_ids[2])); @@ -6160,7 +6162,7 @@ // Click the negative response. service_->external_install_manager() ->GetErrorsForTesting()[0] - ->InstallUIAbort(true); + ->OnInstallPromptDone(ExtensionInstallPrompt::Result::USER_CANCELED); // The Extension should be uninstalled. EXPECT_FALSE(registry()->GetExtensionById(updates_from_webstore, ExtensionRegistry::EVERYTHING)); @@ -6203,7 +6205,7 @@ // Accept the extension. service_->external_install_manager() ->GetErrorsForTesting()[0] - ->InstallUIProceed(); + ->OnInstallPromptDone(ExtensionInstallPrompt::Result::ACCEPTED); // It should be enabled again. EXPECT_TRUE(registry()->enabled_extensions().GetByID(updates_from_webstore));
diff --git a/chrome/browser/extensions/external_install_error.cc b/chrome/browser/extensions/external_install_error.cc index e704895..fc3c50e 100644 --- a/chrome/browser/extensions/external_install_error.cc +++ b/chrome/browser/extensions/external_install_error.cc
@@ -265,12 +265,12 @@ void ExternalInstallBubbleAlert::BubbleViewAcceptButtonPressed( Browser* browser) { - error_->InstallUIProceed(); + error_->OnInstallPromptDone(ExtensionInstallPrompt::Result::ACCEPTED); } void ExternalInstallBubbleAlert::BubbleViewCancelButtonPressed( Browser* browser) { - error_->InstallUIAbort(true); + error_->OnInstallPromptDone(ExtensionInstallPrompt::Result::USER_CANCELED); } } // namespace @@ -303,34 +303,37 @@ error_service_->RemoveGlobalError(global_error_.get()); } -void ExternalInstallError::InstallUIProceed() { +void ExternalInstallError::OnInstallPromptDone( + ExtensionInstallPrompt::Result result) { const Extension* extension = GetExtension(); - if (extension) { - ExtensionSystem::Get(browser_context_) - ->extension_service() - ->GrantPermissionsAndEnableExtension(extension); - // Since the manager listens for the extension to be loaded, this will - // remove the error... - } else { - // ... Otherwise we have to do it explicitly. - manager_->RemoveExternalInstallError(extension_id_); + bool did_remove_error = false; + switch (result) { + case ExtensionInstallPrompt::Result::ACCEPTED: + if (extension) { + ExtensionSystem::Get(browser_context_) + ->extension_service() + ->GrantPermissionsAndEnableExtension(extension); + // Since the manager listens for the extension to be loaded, this will + // remove the error. + did_remove_error = true; + } + break; + case ExtensionInstallPrompt::Result::USER_CANCELED: + if (extension) { + ExtensionSystem::Get(browser_context_) + ->extension_service() + ->UninstallExtension(extension_id_, + extensions::UNINSTALL_REASON_INSTALL_CANCELED, + base::Bind(&base::DoNothing), + nullptr); // Ignore error. + did_remove_error = true; + } + break; + case ExtensionInstallPrompt::Result::ABORTED: + break; } -} - -void ExternalInstallError::InstallUIAbort(bool user_initiated) { - if (user_initiated && GetExtension()) { - ExtensionSystem::Get(browser_context_) - ->extension_service() - ->UninstallExtension(extension_id_, - extensions::UNINSTALL_REASON_INSTALL_CANCELED, - base::Bind(&base::DoNothing), - NULL); // Ignore error. - // Since the manager listens for the extension to be removed, this will - // remove the error... - } else { - // ... Otherwise we have to do it explicitly. + if (!did_remove_error) manager_->RemoveExternalInstallError(extension_id_); - } } void ExternalInstallError::ShowDialog(Browser* browser) { @@ -342,7 +345,10 @@ install_ui_show_params_.reset( new ExtensionInstallPromptShowParams(web_contents)); ExtensionInstallPrompt::GetDefaultShowDialogCallback().Run( - install_ui_show_params_.get(), this, std::move(prompt_)); + install_ui_show_params_.get(), + base::Bind(&ExternalInstallError::OnInstallPromptDone, + weak_factory_.GetWeakPtr()), + std::move(prompt_)); } const Extension* ExternalInstallError::GetExtension() const { @@ -389,7 +395,9 @@ new ExtensionInstallPrompt(Profile::FromBrowserContext(browser_context_), NULL)); // NULL native window. - install_ui_->ShowDialog(this, GetExtension(), + install_ui_->ShowDialog(base::Bind(&ExternalInstallError::OnInstallPromptDone, + weak_factory_.GetWeakPtr()), + GetExtension(), nullptr, // Force a fetch of the icon. std::move(prompt_), base::Bind(&ExternalInstallError::OnDialogReady, @@ -398,9 +406,8 @@ void ExternalInstallError::OnDialogReady( ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* prompt_delegate, + const ExtensionInstallPrompt::DoneCallback& callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) { - DCHECK_EQ(this, prompt_delegate); prompt_ = std::move(prompt); if (alert_type_ == BUBBLE_ALERT) {
diff --git a/chrome/browser/extensions/external_install_error.h b/chrome/browser/extensions/external_install_error.h index ccad2d3d..6d6c2a6 100644 --- a/chrome/browser/extensions/external_install_error.h +++ b/chrome/browser/extensions/external_install_error.h
@@ -33,8 +33,7 @@ // possible) and will handle adding itself to the GlobalErrorService when // initialized and removing itself from the GlobalErrorService upon // destruction. -class ExternalInstallError : public ExtensionInstallPrompt::Delegate, - public WebstoreDataFetcherDelegate { +class ExternalInstallError : public WebstoreDataFetcherDelegate { public: // The possible types of errors to show. A menu alert adds a menu item to the // wrench, which spawns an extension install dialog when clicked. The bubble @@ -51,9 +50,7 @@ ExternalInstallManager* manager); ~ExternalInstallError() override; - // ExtensionInstallPrompt::Delegate implementation. - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); // Show the associated dialog. This should only be called once the dialog is // ready. @@ -78,7 +75,7 @@ // Called when the dialog has been successfully populated, and is ready to be // shown. void OnDialogReady(ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* prompt_delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt); // The associated BrowserContext.
diff --git a/chrome/browser/extensions/install_verifier.cc b/chrome/browser/extensions/install_verifier.cc index 8cc3a60..bae7e97b 100644 --- a/chrome/browser/extensions/install_verifier.cc +++ b/chrome/browser/extensions/install_verifier.cc
@@ -39,6 +39,9 @@ namespace { +// This should only be set during tests. +bool g_bypass_for_test = false; + enum VerifyStatus { NONE = 0, // Do not request install signatures, and do not enforce them. BOOTSTRAP, // Request install signatures, but do not enforce them. @@ -110,7 +113,10 @@ } VerifyStatus GetStatus() { - return std::max(GetExperimentStatus(), GetCommandLineStatus()); + if (g_bypass_for_test) + return NONE; + else + return std::max(GetExperimentStatus(), GetCommandLineStatus()); } bool ShouldFetchSignature() { @@ -653,4 +659,18 @@ BeginFetch(); } +ScopedInstallVerifierBypassForTest::ScopedInstallVerifierBypassForTest() + : old_value_(ShouldBypass()) { + g_bypass_for_test = true; +} + +ScopedInstallVerifierBypassForTest::~ScopedInstallVerifierBypassForTest() { + g_bypass_for_test = old_value_; +} + +// static +bool ScopedInstallVerifierBypassForTest::ShouldBypass() { + return g_bypass_for_test; +} + } // namespace extensions
diff --git a/chrome/browser/extensions/install_verifier.h b/chrome/browser/extensions/install_verifier.h index 6caa364..e92b5c9 100644 --- a/chrome/browser/extensions/install_verifier.h +++ b/chrome/browser/extensions/install_verifier.h
@@ -181,6 +181,21 @@ DISALLOW_COPY_AND_ASSIGN(InstallVerifier); }; +// Instances of this class can be constructed to disable install verification +// during tests. +class ScopedInstallVerifierBypassForTest { + public: + ScopedInstallVerifierBypassForTest(); + ~ScopedInstallVerifierBypassForTest(); + + // Should install verification be bypassed? + static bool ShouldBypass(); + + private: + bool old_value_; + DISALLOW_COPY_AND_ASSIGN(ScopedInstallVerifierBypassForTest); +}; + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_INSTALL_VERIFIER_H_
diff --git a/chrome/browser/extensions/navigation_observer.cc b/chrome/browser/extensions/navigation_observer.cc index a7755836..f865ece 100644 --- a/chrome/browser/extensions/navigation_observer.cc +++ b/chrome/browser/extensions/navigation_observer.cc
@@ -19,7 +19,8 @@ namespace extensions { -NavigationObserver::NavigationObserver(Profile* profile) : profile_(profile) { +NavigationObserver::NavigationObserver(Profile* profile) + : profile_(profile), weak_factory_(this) { RegisterForNotifications(); } @@ -72,7 +73,7 @@ ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_); if (extension_prefs->DidExtensionEscalatePermissions(extension->id())) { // Keep track of the extension id and nav controller we're prompting for. - // These must be reset in InstallUIProceed and InstallUIAbort. + // These must be reset in OnInstallPromptDone. in_progress_prompt_extension_id_ = extension->id(); in_progress_prompt_navigation_controller_ = nav_controller; @@ -82,45 +83,42 @@ ExtensionInstallPrompt::GetReEnablePromptTypeForExtension(profile_, extension); extension_install_prompt_->ShowDialog( - this, extension, nullptr, + base::Bind(&NavigationObserver::OnInstallPromptDone, + weak_factory_.GetWeakPtr()), + extension, nullptr, make_scoped_ptr(new ExtensionInstallPrompt::Prompt(type)), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); } } -void NavigationObserver::InstallUIProceed() { - ExtensionService* extension_service = - extensions::ExtensionSystem::Get(profile_)->extension_service(); - const Extension* extension = extension_service->GetExtensionById( - in_progress_prompt_extension_id_, true); - NavigationController* nav_controller = - in_progress_prompt_navigation_controller_; - CHECK(extension); - CHECK(nav_controller); - - in_progress_prompt_extension_id_ = ""; - in_progress_prompt_navigation_controller_ = NULL; - extension_install_prompt_.reset(); - - // Grant permissions, re-enable the extension, and then reload the tab. - extension_service->GrantPermissionsAndEnableExtension(extension); - nav_controller->Reload(true); -} - -void NavigationObserver::InstallUIAbort(bool user_initiated) { +void NavigationObserver::OnInstallPromptDone( + ExtensionInstallPrompt::Result result) { ExtensionService* extension_service = extensions::ExtensionSystem::Get(profile_)->extension_service(); const Extension* extension = extension_service->GetExtensionById( in_progress_prompt_extension_id_, true); - in_progress_prompt_extension_id_ = ""; - in_progress_prompt_navigation_controller_ = NULL; - extension_install_prompt_.reset(); + if (result == ExtensionInstallPrompt::Result::ACCEPTED) { + NavigationController* nav_controller = + in_progress_prompt_navigation_controller_; + CHECK(extension); + CHECK(nav_controller); - std::string histogram_name = user_initiated ? "ReEnableCancel" - : "ReEnableAbort"; - ExtensionService::RecordPermissionMessagesHistogram( - extension, histogram_name.c_str()); + // Grant permissions, re-enable the extension, and then reload the tab. + extension_service->GrantPermissionsAndEnableExtension(extension); + nav_controller->Reload(true); + } else { + std::string histogram_name = + result == ExtensionInstallPrompt::Result::USER_CANCELED + ? "ReEnableCancel" + : "ReEnableAbort"; + ExtensionService::RecordPermissionMessagesHistogram(extension, + histogram_name.c_str()); + } + + in_progress_prompt_extension_id_ = std::string(); + in_progress_prompt_navigation_controller_ = nullptr; + extension_install_prompt_.reset(); } } // namespace extensions
diff --git a/chrome/browser/extensions/navigation_observer.h b/chrome/browser/extensions/navigation_observer.h index eae903c..fb2ca98 100644 --- a/chrome/browser/extensions/navigation_observer.h +++ b/chrome/browser/extensions/navigation_observer.h
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "chrome/browser/extensions/extension_install_prompt.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -26,8 +27,7 @@ // navigates into an extension that has been disabled due to a permission // increase, it prompts the user to accept the new permissions and re-enables // the extension. -class NavigationObserver : public ExtensionInstallPrompt::Delegate, - public content::NotificationObserver { +class NavigationObserver : public content::NotificationObserver { public: explicit NavigationObserver(Profile* profile); ~NavigationObserver() override; @@ -47,9 +47,7 @@ void PromptToEnableExtensionIfNecessary( content::NavigationController* nav_controller); - // ExtensionInstallPrompt::Delegate callbacks used for the permissions prompt. - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); content::NotificationRegistrar registrar_; @@ -65,6 +63,8 @@ // The extension ids we've already prompted the user about. std::set<std::string> prompted_extensions_; + base::WeakPtrFactory<NavigationObserver> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(NavigationObserver); };
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc index 4e9ddf7c7..3b0b2ec3 100644 --- a/chrome/browser/extensions/service_worker_apitest.cc +++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -384,6 +384,33 @@ NavigateAndExtractInnerText(extension->GetResourceURL(""))); } +IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) { + const Extension* extension = + StartTestFromBackgroundPage("replace_background.js", kExpectSuccess); + ExtensionHost* background_page = + process_manager()->GetBackgroundHostForExtension(extension->id()); + ASSERT_TRUE(background_page); + + // Close the background page and start it again so that the service worker + // will start controlling pages. + background_page->Close(); + BackgroundPageWatcher(process_manager(), extension).WaitForClose(); + background_page = nullptr; + process_manager()->WakeEventPage(extension->id(), + base::Bind(&DoNothingWithBool)); + BackgroundPageWatcher(process_manager(), extension).WaitForOpen(); + + // Since the SW is now controlling the extension, the SW serves the background + // script. page.html sends a message to the background script and we verify + // that the SW served background script correctly receives the message/event. + ExtensionTestMessageListener listener("onMessage/SW BG.", false); + listener.set_failure_message("onMessage/original BG."); + content::WebContents* web_contents = + AddTab(browser(), extension->GetResourceURL("page.html")); + ASSERT_TRUE(web_contents); + EXPECT_TRUE(listener.WaitUntilSatisfied()); +} + IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, LoadingBackgroundPageBypassesServiceWorker) { const Extension* extension =
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc index 1849630d..035aecff 100644 --- a/chrome/browser/extensions/unpacked_installer.cc +++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -47,23 +47,24 @@ const char kImportNotSharedModule[] = "'import' is not a shared module."; // Manages an ExtensionInstallPrompt for a particular extension. -class SimpleExtensionLoadPrompt : public ExtensionInstallPrompt::Delegate { +class SimpleExtensionLoadPrompt { public: SimpleExtensionLoadPrompt(const Extension* extension, Profile* profile, const base::Closure& callback); - ~SimpleExtensionLoadPrompt() override; void ShowPrompt(); - // ExtensionInstallUI::Delegate - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; - private: + ~SimpleExtensionLoadPrompt(); // Manages its own lifetime. + + void OnInstallPromptDone(ExtensionInstallPrompt::Result result); + scoped_ptr<ExtensionInstallPrompt> install_ui_; scoped_refptr<const Extension> extension_; base::Closure callback_; + + DISALLOW_COPY_AND_ASSIGN(SimpleExtensionLoadPrompt); }; SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt( @@ -81,27 +82,30 @@ } void SimpleExtensionLoadPrompt::ShowPrompt() { + // TODO(devlin): The AutoConfirm values should work from the + // ExtensionInstallPrompt code, so these should be unnecessary. switch (extensions::ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) { case extensions::ScopedTestDialogAutoConfirm::NONE: + // Unretained() is safe because this object manages its own lifetime. install_ui_->ShowDialog( - this, extension_.get(), nullptr, + base::Bind(&SimpleExtensionLoadPrompt::OnInstallPromptDone, + base::Unretained(this)), + extension_.get(), nullptr, ExtensionInstallPrompt::GetDefaultShowDialogCallback()); break; case extensions::ScopedTestDialogAutoConfirm::ACCEPT: - InstallUIProceed(); + OnInstallPromptDone(ExtensionInstallPrompt::Result::ACCEPTED); break; case extensions::ScopedTestDialogAutoConfirm::CANCEL: - InstallUIAbort(false); + OnInstallPromptDone(ExtensionInstallPrompt::Result::ABORTED); break; } } -void SimpleExtensionLoadPrompt::InstallUIProceed() { - callback_.Run(); - delete this; -} - -void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) { +void SimpleExtensionLoadPrompt::OnInstallPromptDone( + ExtensionInstallPrompt::Result result) { + if (result == ExtensionInstallPrompt::Result::ACCEPTED) + callback_.Run(); delete this; }
diff --git a/chrome/browser/extensions/webstore_inline_installer_browsertest.cc b/chrome/browser/extensions/webstore_inline_installer_browsertest.cc index ef4b7bb8..8c537654 100644 --- a/chrome/browser/extensions/webstore_inline_installer_browsertest.cc +++ b/chrome/browser/extensions/webstore_inline_installer_browsertest.cc
@@ -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 "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/extensions/extension_install_prompt.h" @@ -64,35 +65,39 @@ : ExtensionInstallPrompt(contents) {} - ~ProgrammableInstallPrompt() override {} + ~ProgrammableInstallPrompt() override { g_done_callback = nullptr; } void ShowDialog( - Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, const Extension* extension, const SkBitmap* icon, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt, scoped_ptr<const extensions::PermissionSet> custom_permissions, - const ShowDialogCallback& callback) override { - delegate_ = delegate; + const ShowDialogCallback& show_dialog_callback) override { + done_callback_ = done_callback; + g_done_callback = &done_callback_; } - static bool Ready() { - return delegate_ != NULL; - } + static bool Ready() { return g_done_callback != nullptr; } static void Accept() { - delegate_->InstallUIProceed(); + g_done_callback->Run(ExtensionInstallPrompt::Result::ACCEPTED); } static void Reject() { - delegate_->InstallUIAbort(true); + g_done_callback->Run(ExtensionInstallPrompt::Result::USER_CANCELED); } private: - static Delegate* delegate_; + static ExtensionInstallPrompt::DoneCallback* g_done_callback; + + ExtensionInstallPrompt::DoneCallback done_callback_; + + DISALLOW_COPY_AND_ASSIGN(ProgrammableInstallPrompt); }; -ExtensionInstallPrompt::Delegate* ProgrammableInstallPrompt::delegate_; +ExtensionInstallPrompt::DoneCallback* + ProgrammableInstallPrompt::g_done_callback = nullptr; // Fake inline installer which creates a programmable prompt in place of // the normal dialog UI.
diff --git a/chrome/browser/extensions/webstore_reinstaller.cc b/chrome/browser/extensions/webstore_reinstaller.cc index 1eb1e3bb..d1a1604 100644 --- a/chrome/browser/extensions/webstore_reinstaller.cc +++ b/chrome/browser/extensions/webstore_reinstaller.cc
@@ -86,7 +86,13 @@ AbortInstall(); } -void WebstoreReinstaller::InstallUIProceed() { +void WebstoreReinstaller::OnInstallPromptDone( + ExtensionInstallPrompt::Result result) { + if (result != ExtensionInstallPrompt::Result::ACCEPTED) { + WebstoreStandaloneInstaller::OnInstallPromptDone(result); + return; + } + if (!ExtensionSystem::Get(profile())->extension_service()->UninstallExtension( id(), UNINSTALL_REASON_REINSTALL, @@ -100,7 +106,8 @@ } void WebstoreReinstaller::OnDeletionDone() { - WebstoreStandaloneInstaller::InstallUIProceed(); + WebstoreStandaloneInstaller::OnInstallPromptDone( + ExtensionInstallPrompt::Result::ACCEPTED); } } // namespace extensions
diff --git a/chrome/browser/extensions/webstore_reinstaller.h b/chrome/browser/extensions/webstore_reinstaller.h index efaddb8..5cc581363 100644 --- a/chrome/browser/extensions/webstore_reinstaller.h +++ b/chrome/browser/extensions/webstore_reinstaller.h
@@ -40,7 +40,7 @@ std::string* error) const override; bool CheckRequestorPermitted(const base::DictionaryValue& webstore_data, std::string* error) const override; - void InstallUIProceed() override; + void OnInstallPromptDone(ExtensionInstallPrompt::Result result) override; // content::WebContentsObserver: void WebContentsDestroyed() override;
diff --git a/chrome/browser/extensions/webstore_standalone_installer.cc b/chrome/browser/extensions/webstore_standalone_installer.cc index 1942084..da7483d 100644 --- a/chrome/browser/extensions/webstore_standalone_installer.cc +++ b/chrome/browser/extensions/webstore_standalone_installer.cc
@@ -135,9 +135,9 @@ install_prompt_ = CreateInstallPrompt(); if (install_prompt_.get()) { ShowInstallUI(); - // Control flow finishes up in InstallUIProceed or InstallUIAbort. + // Control flow finishes up in OnInstallPromptDone(). } else { - InstallUIProceed(); + OnInstallPromptDone(ExtensionInstallPrompt::Result::ACCEPTED); } } @@ -189,12 +189,21 @@ return approval; } -void WebstoreStandaloneInstaller::InstallUIProceed() { - if (!CheckRequestorAlive()) { +void WebstoreStandaloneInstaller::OnInstallPromptDone( + ExtensionInstallPrompt::Result result) { + if (result == ExtensionInstallPrompt::Result::USER_CANCELED) { + CompleteInstall(webstore_install::USER_CANCELLED, kUserCancelledError); + return; + } + + if (result == ExtensionInstallPrompt::Result::ABORTED || + !CheckRequestorAlive()) { CompleteInstall(webstore_install::ABORTED, std::string()); return; } + DCHECK(result == ExtensionInstallPrompt::Result::ACCEPTED); + scoped_ptr<WebstoreInstaller::Approval> approval = CreateApproval(); ExtensionService* extension_service = @@ -228,10 +237,6 @@ installer->Start(); } -void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) { - CompleteInstall(webstore_install::USER_CANCELLED, kUserCancelledError); -} - void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() { OnWebStoreDataFetcherDone(); CompleteInstall(webstore_install::WEBSTORE_REQUEST_ERROR, @@ -404,7 +409,8 @@ install_ui_ = CreateInstallUI(); install_ui_->ShowDialog( - this, localized_extension.get(), &icon_, std::move(install_prompt_), + base::Bind(&WebstoreStandaloneInstaller::OnInstallPromptDone, this), + localized_extension.get(), &icon_, std::move(install_prompt_), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); }
diff --git a/chrome/browser/extensions/webstore_standalone_installer.h b/chrome/browser/extensions/webstore_standalone_installer.h index 70151fa7..5cb43a26 100644 --- a/chrome/browser/extensions/webstore_standalone_installer.h +++ b/chrome/browser/extensions/webstore_standalone_installer.h
@@ -45,7 +45,6 @@ class WebstoreStandaloneInstaller : public base::RefCountedThreadSafe<WebstoreStandaloneInstaller>, - public ExtensionInstallPrompt::Delegate, public WebstoreDataFetcherDelegate, public WebstoreInstaller::Delegate, public WebstoreInstallHelper::Delegate { @@ -152,9 +151,8 @@ // Create an approval to pass installation parameters to the CrxInstaller. virtual scoped_ptr<WebstoreInstaller::Approval> CreateApproval() const; - // ExtensionInstallPrompt::Delegate interface implementation. - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + // Called once the install prompt has finished. + virtual void OnInstallPromptDone(ExtensionInstallPrompt::Result result); // Accessors to be used by subclasses. bool show_user_count() const { return show_user_count_; }
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.cc b/chrome/browser/media/android/remote/remote_media_player_bridge.cc index 04ed303..269e3958 100644 --- a/chrome/browser/media/android/remote/remote_media_player_bridge.cc +++ b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
@@ -79,6 +79,16 @@ Release(); } +bool RemoteMediaPlayerBridge::HasVideo() const { + NOTIMPLEMENTED(); + return true; +} + +bool RemoteMediaPlayerBridge::HasAudio() const { + NOTIMPLEMENTED(); + return true; +} + int RemoteMediaPlayerBridge::GetVideoWidth() { return local_player_->GetVideoWidth(); }
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.h b/chrome/browser/media/android/remote/remote_media_player_bridge.h index 50a3f9d..48bc15d 100644 --- a/chrome/browser/media/android/remote/remote_media_player_bridge.h +++ b/chrome/browser/media/android/remote/remote_media_player_bridge.h
@@ -43,6 +43,8 @@ void SeekTo(base::TimeDelta timestamp) override; void Release() override; void SetVolume(double volume) override; + bool HasVideo() const override; + bool HasAudio() const override; int GetVideoWidth() override; int GetVideoHeight() override; base::TimeDelta GetCurrentTime() override;
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc index 3b75f18..bdd814f 100644 --- a/chrome/browser/printing/print_preview_dialog_controller.cc +++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -176,23 +176,24 @@ // Get the print preview dialog for |initiator|. WebContents* preview_dialog = GetPrintPreviewForContents(initiator); - if (!preview_dialog) + if (preview_dialog) { + // Show the initiator holding the existing preview dialog. + initiator->GetDelegate()->ActivateContents(initiator); + return preview_dialog; + } + + // We should only create a dialog if the initiator has not been proxied. + if (GetProxyDialogTarget(initiator) == initiator) return CreatePrintPreviewDialog(initiator); - // Show the initiator holding the existing preview dialog. - initiator->GetDelegate()->ActivateContents(initiator); - return preview_dialog; + return nullptr; } WebContents* PrintPreviewDialogController::GetPrintPreviewForContents( WebContents* contents) const { // If this WebContents relies on another for its preview dialog, we // need to act as if we are looking for the proxied content's dialog. - PrintPreviewDialogMap::const_iterator proxied = - proxied_dialog_map_.find(contents); - if (proxied != proxied_dialog_map_.end()) { - contents = proxied->second; - } + contents = GetProxyDialogTarget(contents); // |preview_dialog_map_| is keyed by the preview dialog, so if find() // succeeds, then |contents| is the preview dialog. @@ -400,6 +401,13 @@ proxied_dialog_map_.erase(source); } +WebContents* PrintPreviewDialogController::GetProxyDialogTarget( + WebContents* source) const { + PrintPreviewDialogMap::const_iterator proxied = + proxied_dialog_map_.find(source); + return proxied == proxied_dialog_map_.end() ? source : proxied->second; +} + void PrintPreviewDialogController::SaveInitiatorTitle( WebContents* preview_dialog) { WebContents* initiator = GetInitiator(preview_dialog);
diff --git a/chrome/browser/printing/print_preview_dialog_controller.h b/chrome/browser/printing/print_preview_dialog_controller.h index 091c5089..d1315837 100644 --- a/chrome/browser/printing/print_preview_dialog_controller.h +++ b/chrome/browser/printing/print_preview_dialog_controller.h
@@ -84,6 +84,10 @@ void RemoveProxyDialogForWebContents(content::WebContents* source); + // Returns |source|'s |target| if it's a proxy, otherwise returns |source|. + content::WebContents* GetProxyDialogTarget( + content::WebContents* source) const; + private: friend class base::RefCounted<PrintPreviewDialogController>;
diff --git a/chrome/browser/printing/print_preview_dialog_controller_unittest.cc b/chrome/browser/printing/print_preview_dialog_controller_unittest.cc index 4421caa..bbc9c452 100644 --- a/chrome/browser/printing/print_preview_dialog_controller_unittest.cc +++ b/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
@@ -10,10 +10,17 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" #include "content/public/browser/navigation_details.h" +#include "content/public/browser/web_contents_delegate.h" #include "content/public/common/url_constants.h" +#include "content/public/test/web_contents_tester.h" using content::WebContents; +namespace { +// content::WebContentsDelegate destructor is protected: subclass for testing. +class TestWebContentsDelegate : public content::WebContentsDelegate {}; +} // namespace + namespace printing { using PrintPreviewDialogControllerUnitTest = PrintPreviewTest; @@ -119,6 +126,89 @@ EXPECT_EQ(tab_1_index, tab_strip_model->active_index()); } +// Get a preview dialog for a proxied initiator should work. +TEST_F(PrintPreviewDialogControllerUnitTest, ProxyGetOrCreatePreviewDialog) { + // Lets start with one window with one tab. + EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); + EXPECT_EQ(0, browser()->tab_strip_model()->count()); + chrome::NewTab(browser()); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + // Create a reference to initiator contents. + WebContents* initiator = browser()->tab_strip_model()->GetActiveWebContents(); + + PrintPreviewDialogController* dialog_controller = + PrintPreviewDialogController::GetInstance(); + ASSERT_TRUE(dialog_controller); + + // Get the preview dialog for initiator. + PrintViewManager::FromWebContents(initiator)->PrintPreviewNow(false); + WebContents* preview_dialog = + dialog_controller->GetOrCreatePreviewDialog(initiator); + + // New print preview dialog is a constrained window, so the number of tabs is + // still 1. + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + EXPECT_NE(initiator, preview_dialog); + + // Create the proxy web contents. + scoped_ptr<WebContents> proxy( + content::WebContentsTester::CreateTestWebContents(profile(), nullptr)); + TestWebContentsDelegate delegate; + proxy->SetDelegate(&delegate); + dialog_controller->AddProxyDialogForWebContents(proxy.get(), initiator); + + // Get the print preview dialog for the initiator and proxy. + WebContents* initiator_preview_dialog = + dialog_controller->GetOrCreatePreviewDialog(initiator); + WebContents* proxy_preview_dialog = + dialog_controller->GetOrCreatePreviewDialog(proxy.get()); + + // Preview dialog already exists. Tab count remains the same. + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + // 1:1 relationship between initiator and preview dialog. + EXPECT_EQ(initiator_preview_dialog, preview_dialog); + EXPECT_EQ(proxy_preview_dialog, preview_dialog); + + dialog_controller->RemoveProxyDialogForWebContents(proxy.get()); +} + +// Create a preview dialog for a proxied initiator should fail. +TEST_F(PrintPreviewDialogControllerUnitTest, ProxyNoGetOrCreatePreviewDialog) { + // Lets start with one window with one tab. + EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); + EXPECT_EQ(0, browser()->tab_strip_model()->count()); + chrome::NewTab(browser()); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + // Create a reference to initiator contents. + WebContents* initiator = browser()->tab_strip_model()->GetActiveWebContents(); + + PrintPreviewDialogController* dialog_controller = + PrintPreviewDialogController::GetInstance(); + ASSERT_TRUE(dialog_controller); + + // Create the proxy web contents. + scoped_ptr<WebContents> proxy( + content::WebContentsTester::CreateTestWebContents(profile(), nullptr)); + TestWebContentsDelegate delegate; + proxy->SetDelegate(&delegate); + dialog_controller->AddProxyDialogForWebContents(proxy.get(), initiator); + + // Get the print preview dialog for the proxy. + WebContents* proxy_preview_dialog = + dialog_controller->GetOrCreatePreviewDialog(proxy.get()); + + // Preview dialog shouldn't be created. Tab count remains the same. + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + // A proxy should not create a dialog, only re-use. + EXPECT_EQ(proxy_preview_dialog, nullptr); + + dialog_controller->RemoveProxyDialogForWebContents(proxy.get()); +} + // Check clearing the initiator details associated with a print preview dialog // allows the initiator to create another print preview dialog. TEST_F(PrintPreviewDialogControllerUnitTest, ClearInitiatorDetails) {
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/pdf_processor.js b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/pdf_processor.js index 92650ce..531a0ad 100644 --- a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/pdf_processor.js +++ b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/pdf_processor.js
@@ -5,18 +5,16 @@ /** * @fileoverview Logic to process PDFs + * + * This file runs when ChromeVox is injected into Chrome's component + * extension that implements PDF support. The extension wraps a + * PDFium plug-in object. */ goog.provide('cvox.PdfProcessor'); goog.require('cvox.QueueMode'); /** - * The array of PDFs yet to process. - * @type {Array<HTMLEmbedElement>} - */ -cvox.PdfProcessor.pdfEmbeds = []; - -/** * The current PDF we're processing, or null if we're not processing one. * @type {HTMLEmbedElement} */ @@ -52,46 +50,40 @@ return; } - var pdfEmbeds = document.querySelectorAll('embed[type="application/pdf"]'); + var pdfEmbeds = document.querySelectorAll( + 'embed[type="application/x-google-chrome-pdf"]'); if (pdfEmbeds.length == 0) { return; } - - // Convert it to an Array so we can slice off one at a time, and stick - // it in a class variable. The responses from the plug-in come as a - // generic 'message' event to the window with no context, so we have - // to use global state to keep track of progress. - cvox.PdfProcessor.pdfEmbeds = Array.prototype.slice.call(pdfEmbeds); + cvox.PdfProcessor.pdfEmbed = pdfEmbeds[0]; // Install our event listener for responses. window.addEventListener('message', /** @type {EventListener} */(cvox.PdfProcessor.onMessage)); - // Start processing the first one. - cvox.PdfProcessor.processNextPdf(); + // Start processing the pdf. + cvox.PdfProcessor.process(); }; /** - * Pull off the next <embed> element from |cvox.PdfProcessor.pdfEmbeds| - * and send a message to it to begin processing. If there are no more + * Send a message to the plug-in to begin processing. If there are no more * elements in the array, remove the event listener and reset * NavigationManager so that it lands at the top of the now-modified page. */ -cvox.PdfProcessor.processNextPdf = function() { - if (cvox.PdfProcessor.pdfEmbeds.length == 0) { - window.removeEventListener('message', - /** @type {EventListener} */(cvox.PdfProcessor.onMessage)); - cvox.PdfProcessor.pdfEmbeds = null; - cvox.PdfProcessor.pdfEmbed = null; - - cvox.ChromeVox.navigationManager.reset(); - return; - } - - cvox.PdfProcessor.pdfEmbed = cvox.PdfProcessor.pdfEmbeds.shift(); +cvox.PdfProcessor.process = function() { cvox.PdfProcessor.pageCount = null; cvox.PdfProcessor.pageIndex = null; - cvox.PdfProcessor.pdfEmbed.postMessage({'type': 'getAccessibilityJSON'}); + window.postMessage({'type': 'getAccessibilityJSON'}, '*'); +}; + +/** + * Called after finishing the pdf. + */ +cvox.PdfProcessor.finish = function() { + window.removeEventListener('message', + /** @type {EventListener} */(cvox.PdfProcessor.onMessage)); + cvox.PdfProcessor.pdfEmbed = null; + cvox.ChromeVox.navigationManager.reset(); }; /** @@ -127,9 +119,8 @@ // whether it's loaded, whether it's copyable, and how many total pages // there are. if (!info.loaded) { - cvox.PdfProcessor.pdfEmbeds.unshift(cvox.PdfProcessor.pdfEmbed); cvox.PdfProcessor.pdfEmbed = null; - window.setTimeout(cvox.PdfProcessor.processNextPdf, 100); + window.setTimeout(cvox.PdfProcessor.finish, 100); return; } @@ -186,7 +177,7 @@ cvox.PdfProcessor.pdfEmbed.style.display = 'none'; cvox.PdfProcessor.pdfEmbed.parentElement.appendChild( cvox.PdfProcessor.documentDiv); - cvox.PdfProcessor.processNextPdf(); + cvox.PdfProcessor.finish(); return; }
diff --git a/chrome/browser/resources/chromeos/input_method/google_input_tools_manifest.json b/chrome/browser/resources/chromeos/input_method/google_input_tools_manifest.json index 20651dd..1b6c5048 100644 --- a/chrome/browser/resources/chromeos/input_method/google_input_tools_manifest.json +++ b/chrome/browser/resources/chromeos/input_method/google_input_tools_manifest.json
@@ -101,6 +101,20 @@ "input_view": "inputview.html#id=quick&language=zh-TW&passwordLayout=quick&name=inputmethod_quick" }, { + "name": "__MSG_inputmethod_cantonese__", + "type": "ime", + "id": "yue-hant-t-i0-und", + "indicator": "\u7CA4", + "description": "Cantonese", + "language": [ + "zh-TW" + ], + "layouts": [ + "us" + ], + "input_view": "inputview.html#id=us&language=zh-CN&passwordLayout=us&name=inputmethod_cantonese" + }, + { "name": "__MSG_inputmethod_wubi__", "type": "ime", "id": "zh-t-i0-wubi-1986",
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd index d09d6ec..80e80afc 100644 --- a/chrome/browser/resources/component_extension_resources.grd +++ b/chrome/browser/resources/component_extension_resources.grd
@@ -101,8 +101,10 @@ </if> <if expr="not is_android"> <include name="IDR_FEEDBACK_DEFAULT_HTML" file="feedback/html/default.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> + <include name="IDR_FEEDBACK_SYSINFO_HTML" file="feedback/html/sys_info.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_FEEDBACK_EVENT_HANDLER_JS" file="feedback/js/event_handler.js" flattenhtml="true" type="BINDATA" /> <include name="IDR_FEEDBACK_FEEDBACK_JS" file="feedback/js/feedback.js" flattenhtml="true" type="BINDATA" /> + <include name="IDR_FEEDBACK_SYSINFO_JS" file="feedback/js/sys_info.js" flattenhtml="true" type="BINDATA" /> <include name="IDR_FEEDBACK_TAKE_SCREENSHOT_JS" file="feedback/js/take_screenshot.js" flattenhtml="true" type="BINDATA" /> <include name="IDR_FEEDBACK_TOPBAR_HANDLER_JS" file="feedback/js/topbar_handlers.js" flattenhtml="true" type="BINDATA" /> <include name="IDR_FEEDBACK_FEEDBACK_CSS" file="feedback/css/feedback.css" type="BINDATA" />
diff --git a/chrome/browser/resources/feedback/html/sys_info.html b/chrome/browser/resources/feedback/html/sys_info.html new file mode 100644 index 0000000..30fd6a5 --- /dev/null +++ b/chrome/browser/resources/feedback/html/sys_info.html
@@ -0,0 +1,32 @@ +<!doctype html> +<html i18n-values="dir:textdirection;lang:language"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title i18n-content="sysinfoPageTitle"></title> + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> + <link rel="stylesheet" href="../../about_sys/about_sys.css"> + <script src="chrome://resources/js/util.js"></script> + <script src="chrome://resources/js/i18n_template_no_process.js"></script> + <script src="chrome://resources/js/jstemplate_compiled.js"></script> + <script src="../js/sys_info.js"></script> + <style> + html, body { + overflow: visible; + } + </style> + </head> + <body> + <div id="header"> + <h1 id="title" i18n-content="sysinfoPageTitle"></h1> + <p id="description" i18n-content="sysinfoPageDescription"></p> + </div> + <div id="content"> + <h2 id="tableTitle" i18n-content="sysinfoPageTableTitle"></h2> + <div id="anchor"></div> + <button id="expandAllBtn" class="global-button" i18n-content="sysinfoPageExpandAllBtn"></button> + <button id="collapseAllBtn" class="global-button" i18n-content="sysinfoPageCollapseAllBtn"></button> + <p id="status" i18n-content="sysinfoPageStatusLoading"></p> + <table class="list" id="detailsTable"></table> + </div> + </body> +</html> \ No newline at end of file
diff --git a/chrome/browser/resources/feedback/js/feedback.js b/chrome/browser/resources/feedback/js/feedback.js index e0775f5..b903be5 100644 --- a/chrome/browser/resources/feedback/js/feedback.js +++ b/chrome/browser/resources/feedback/js/feedback.js
@@ -49,6 +49,9 @@ var feedbackInfo = null; var systemInfo = null; +var isSystemInfoReady = false; +var onSystemInfoReadyCallback = null; + /** * Reads the selected file when the user selects a file. * @param {Event} fileSelectedEvent The onChanged event for the file input box. @@ -233,6 +236,17 @@ } /** + * @return {Object} the full anonymized system information we got from the + * system as well as the extra-app added data. + */ +function getFullSystemInformation() { + var sysInfo = feedbackInfo.systemInformation; + if (systemInfo != null) + sysInfo = sysInfo.concat(systemInfo); + return sysInfo; +} + +/** * Initializes our page. * Flow: * .) DOMContent Loaded -> . Request feedbackInfo object @@ -273,6 +287,9 @@ chrome.feedbackPrivate.getSystemInformation(function(sysInfo) { systemInfo = sysInfo; + isSystemInfoReady = true; + if (onSystemInfoReadyCallback != null) + onSystemInfoReadyCallback(getFullSystemInformation()); }); // An extension called us with an attached file. @@ -298,9 +315,38 @@ i18nTemplate.process(document, loadTimeData); if ($('sys-info-url')) { - // Opens a new window showing the current system info. - $('sys-info-url').onclick = - windowOpener(SYSINFO_WINDOW_ID, 'chrome://system'); + // Opens a new window showing the full anonymized system+app + // information. + $('sys-info-url').onclick = function() { + var win = chrome.app.window.get('sys-info-window'); + if (win) { + win.show(); + return; + } + chrome.app.window.create( + '/html/sys_info.html', { + frame: 'chrome', + id: 'sys-info-window', + width: 600, + height: 400, + hidden: false, + resizable: true + }, function(appWindow) { + // Define two functions for the newly created window so that it + // can retrieve its needed data. + appWindow.contentWindow.getFullSystemInfo = + function(onSysInfoReady) { + if (isSystemInfoReady) { + onSysInfoReady(getFullSystemInformation()); + return; + } + onSystemInfoReadyCallback = onSysInfoReady; + }; + appWindow.contentWindow.getLoadTimeData = function() { + return loadTimeData; + }; + }); + }; } if ($('histograms-url')) { // Opens a new window showing the histogram metrics.
diff --git a/chrome/browser/resources/feedback/js/sys_info.js b/chrome/browser/resources/feedback/js/sys_info.js new file mode 100644 index 0000000..fcbd37c --- /dev/null +++ b/chrome/browser/resources/feedback/js/sys_info.js
@@ -0,0 +1,156 @@ +// 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. + +/** + * The global load time data that contains the localized strings that we will + * get from the main page when this page first loads. + */ +var loadTimeData = null; + +function getValueDivForButton(button) { + return $(button.id.substr(0, button.id.length - 4)); +} + +function getButtonForValueDiv(valueDiv) { + return $(valueDiv.id + '-btn'); +} + +/** + * Toggles whether an item is collapsed or expanded. + */ +function changeCollapsedStatus() { + var valueDiv = getValueDivForButton(this); + if (valueDiv.parentNode.className == 'number-collapsed') { + valueDiv.parentNode.className = 'number-expanded'; + this.textContent = loadTimeData.getString('sysinfoPageCollapseBtn'); + } else { + valueDiv.parentNode.className = 'number-collapsed'; + this.textContent = loadTimeData.getString('sysinfoPageExpandBtn'); + } +} + +/** + * Collapses all log items. + */ +function collapseAll() { + var valueDivs = document.getElementsByClassName('stat-value'); + for (var i = 0; i < valueDivs.length; i++) { + var button = getButtonForValueDiv(valueDivs[i]); + if (button && button.className != 'button-hidden') { + button.textContent = loadTimeData.getString('sysinfoPageExpandBtn'); + valueDivs[i].parentNode.className = 'number-collapsed'; + } + } +} + +/** + * Expands all log items. + */ +function expandAll() { + var valueDivs = document.getElementsByClassName('stat-value'); + for (var i = 0; i < valueDivs.length; i++) { + var button = getButtonForValueDiv(valueDivs[i]); + if (button && button.className != 'button-hidden') { + button.textContent = loadTimeData.getString('sysinfoPageCollapseBtn'); + valueDivs[i].parentNode.className = 'number-expanded'; + } + } +} + +/** + * Collapse only those log items with multi-line values. + */ +function collapseMultiLineStrings() { + var valueDivs = document.getElementsByClassName('stat-value'); + var nameDivs = document.getElementsByClassName('stat-name'); + for (var i = 0; i < valueDivs.length; i++) { + var button = getButtonForValueDiv(valueDivs[i]); + button.onclick = changeCollapsedStatus; + if (valueDivs[i].scrollHeight > (nameDivs[i].scrollHeight * 2)) { + button.className = ''; + button.textContent = loadTimeData.getString('sysinfoPageExpandBtn'); + valueDivs[i].parentNode.className = 'number-collapsed'; + } else { + button.className = 'button-hidden'; + valueDivs[i].parentNode.className = 'number'; + } + } +} + +function createNameCell(key) { + var nameCell = document.createElement('td'); + nameCell.setAttribute('class', 'name'); + var nameDiv = document.createElement('div'); + nameDiv.setAttribute('class', 'stat-name'); + nameDiv.appendChild(document.createTextNode(key)); + nameCell.appendChild(nameDiv); + return nameCell; +} + +function createButtonCell(key) { + var buttonCell = document.createElement('td'); + buttonCell.setAttribute('class', 'button-cell'); + var button = document.createElement('button'); + button.setAttribute('id', '' + key + '-value-btn'); + buttonCell.appendChild(button); + return buttonCell; +} + +function createValueCell(key, value) { + var valueCell = document.createElement('td'); + var valueDiv = document.createElement('div'); + valueDiv.setAttribute('class', 'stat-value'); + valueDiv.setAttribute('id', '' + key + '-value'); + valueDiv.appendChild(document.createTextNode(value)); + valueCell.appendChild(valueDiv); + return valueCell; +} + +function createTableRow(key, value) { + var row = document.createElement('tr'); + row.appendChild(createNameCell(key)); + row.appendChild(createButtonCell(key)); + row.appendChild(createValueCell(key, value)); + return row; +} + +/** + * Builds the system information table row by row. + * @param {Element} table The DOM table element to which the newly created rows + * will be appended. + * @param {Object} systemInfo The system information that will be used to fill + * the table. + */ +function createTable(table, systemInfo) { + for (var key in systemInfo) { + var item = systemInfo[key]; + table.appendChild(createTableRow(item['key'], item['value'])); + } +} + +/** + * The callback which will be invoked by the parent window, when the system + * information is ready. + * @param {Object} systemInfo The system information that will be used to fill + * the table. + */ +function onSysInfoReady(systemInfo) { + createTable($('detailsTable'), systemInfo); + + $('collapseAllBtn').onclick = collapseAll; + $('expandAllBtn').onclick = expandAll; + + collapseMultiLineStrings(); + + $('status').textContent = ''; +} + +/** + * Initializes the page when the window is loaded. + */ +window.onload = function() { + loadTimeData = getLoadTimeData(); + i18nTemplate.process(document, loadTimeData); + getFullSystemInfo(onSysInfoReady); +};
diff --git a/chrome/browser/resources/media_router/media_router.js b/chrome/browser/resources/media_router/media_router.js index fe27a8ad..5ee3b78 100644 --- a/chrome/browser/resources/media_router/media_router.js +++ b/chrome/browser/resources/media_router/media_router.js
@@ -38,6 +38,18 @@ } /** + * Reports the selected cast mode. + * Called when the user selects a cast mode from the picker. + * + * @param {{detail: {castModeType: number}}} data + * Parameters in |data|.detail: + * castModeType - type of cast mode selected by the user. + */ + function onCastModeSelected(data) { + media_router.browserApi.reportSelectedCastMode(data.detail.castModeType); + } + + /** * Closes the dialog. * Called when the user clicks the close button on the dialog. */ @@ -64,18 +76,6 @@ } /** - * Reports the selected cast mode. - * Called when the user selects a cast mode from the picker. - * - * @param {{detail: {castModeType: number}}} data - * Parameters in |data|.detail: - * castModeType - type of cast mode selected by the user. - */ - function onCastModeSelected(data) { - media_router.browserApi.reportSelectedCastMode(data.detail.castModeType); - } - - /** * Creates a media route. * Called when the user requests to create a media route. * @@ -102,18 +102,6 @@ } /** - * Reports the index of the sink that was clicked. - * Called when the user selects a sink on the sink list. - * - * @param {{detail: {index: number}}} data - * Paramters in |data|.detail: - * index - the index of the clicked sink. - */ - function onSinkClick(data) { - media_router.browserApi.reportClickedSinkIndex(data.detail.index); - } - - /** * Reports the user navigation to the cast mode view. * Called when the user clicks the drop arrow to navigate to the cast mode * view on the dialog. @@ -144,6 +132,18 @@ } /** + * Reports the index of the sink that was clicked. + * Called when the user selects a sink on the sink list. + * + * @param {{detail: {index: number}}} data + * Paramters in |data|.detail: + * index - the index of the clicked sink. + */ + function onSinkClick(data) { + media_router.browserApi.reportClickedSinkIndex(data.detail.index); + } + + /** * Reports the current sink count. * Called 3 seconds after the dialog is initially opened. *
diff --git a/chrome/browser/resources/settings/on_startup_page/on_startup_page.html b/chrome/browser/resources/settings/on_startup_page/on_startup_page.html index 91f020c..35413cba 100644 --- a/chrome/browser/resources/settings/on_startup_page/on_startup_page.html +++ b/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
@@ -13,7 +13,8 @@ <link rel="import" type="css" href="on_startup_shared.css"> <template> <div class="settings-box"> - <settings-radio-group pref="{{prefs.session.restore_on_startup}}"> + <settings-radio-group id="onStartupRadioGroup" + pref="{{prefs.session.restore_on_startup}}"> <paper-radio-button name="[[prefValues_.OPEN_NEW_TAB]]" i18n-content="onStartupOpenNewTab"> </paper-radio-button>
diff --git a/chrome/browser/resources/settings/people_page/manage_profile.css b/chrome/browser/resources/settings/people_page/manage_profile.css new file mode 100644 index 0000000..fe8c87b --- /dev/null +++ b/chrome/browser/resources/settings/people_page/manage_profile.css
@@ -0,0 +1,12 @@ +/* Copyright (c) 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. */ + +paper-input { + width: 300px; +} + +#availableIcons { + -webkit-margin-start: 16px; + margin-top: 16px; +}
diff --git a/chrome/browser/resources/settings/people_page/manage_profile.html b/chrome/browser/resources/settings/people_page/manage_profile.html new file mode 100644 index 0000000..8228368 --- /dev/null +++ b/chrome/browser/resources/settings/people_page/manage_profile.html
@@ -0,0 +1,26 @@ +<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> +<link rel="import" href="chrome://md-settings/people_page/sync_private_api.html"> + +<dom-module id="settings-manage-profile"> + <link rel="import" type="css" + href="chrome://md-settings/settings_shared.css"> + <link rel="import" type="css" href="manage_profile.css"> + <template> + <div class="settings-box"> + <paper-input value="{{profileName}}" pattern=".*\S.*" auto-validate + on-blur="onProfileNameChanged_"> + </paper-input> + <div id="availableIcons"> + <template is="dom-repeat" items="[[availableIconUrls]]"> + <paper-button toggles active="{{isActiveIcon_(item, profileIconUrl)}}" + on-tap="onIconTap_" data-icon-url$="[[item]]"> + <img src="[[item]]"> + </paper-button> + </template> + </div> + </div> + </template> + <script src="manage_profile.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/manage_profile.js b/chrome/browser/resources/settings/people_page/manage_profile.js new file mode 100644 index 0000000..2d4a7cdc --- /dev/null +++ b/chrome/browser/resources/settings/people_page/manage_profile.js
@@ -0,0 +1,96 @@ +// 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. + +/** + * @fileoverview + * 'settings-manage-profile' is the settings subpage containing controls to + * edit a profile's name, icon, and desktop shortcut. + * + * @group Chrome Settings Elements + * @element settings-manage-profile + */ +Polymer({ + is: 'settings-manage-profile', + + properties: { + /** + * The currently selected profile icon URL. May be a data URL. + */ + profileIconUrl: String, + + /** + * The current profile name. + */ + profileName: String, + + /** + * The available icons for selection. Populated by SyncPrivateApi. + * @type {!Array<!string>} + */ + availableIconUrls: { + type: Array, + value: function() { return []; }, + }, + }, + + /** @override */ + created: function() { + settings.SyncPrivateApi.getAvailableIcons( + this.handleAvailableIcons_.bind(this)); + }, + + /** + * Handler for when the available icons are pushed from SyncPrivateApi. + * @private + * @param {!Array<!string>} iconUrls + */ + handleAvailableIcons_: function(iconUrls) { + this.availableIconUrls = iconUrls; + }, + + /** + * Handler for when the profile name field is changed, then blurred. + * @private + * @param {!Event} event + */ + onProfileNameChanged_: function(event) { + settings.SyncPrivateApi.setProfileIconAndName(this.profileIconUrl, + event.target.value); + }, + + /** + * Handler for when the user clicks a new profile icon. + * @private + * @param {!Event} event + */ + onIconTap_: function(event) { + var element = Polymer.dom(event).rootTarget; + + var iconUrl; + if (element.nodeName == 'IMG') + iconUrl = element.src; + else if (element.dataset && element.dataset.iconUrl) + iconUrl = element.dataset.iconUrl; + + if (!iconUrl) + return; + + settings.SyncPrivateApi.setProfileIconAndName(iconUrl, this.profileName); + + // Button toggle state is controlled by the selected icon URL. Prevent + // tap events from changing the toggle state. + event.preventDefault(); + }, + + /** + * Computed binding determining which profile icon button is toggled on. + * @private + * @param {!string} iconUrl + * @param {!string} paramIconUrl + * @return {boolean} + */ + isActiveIcon_: function(iconUrl, profileIconUrl) { + return iconUrl == profileIconUrl; + }, +});
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html index 0dd91c9..d21fd026 100644 --- a/chrome/browser/resources/settings/people_page/people_page.html +++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -4,6 +4,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.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-dialog/paper-dialog.html"> +<link rel="import" href="chrome://md-settings/people_page/manage_profile.html"> <link rel="import" href="chrome://md-settings/people_page/sync_page.html"> <link rel="import" href="chrome://md-settings/people_page/sync_private_api.html"> <link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html"> @@ -22,9 +23,9 @@ <neon-animatable id="main"> <div class="settings-box"> <div class="split"> - <span class="start"> - <img id="account-picture" src="[[syncStatus.iconURL]]"> - [[syncStatus.name]] + <span class="start" on-tap="onManageProfileTap_"> + <img id="account-picture" src="[[profileIconUrl_]]"> + [[profileName_]] </span> <span> <template is="dom-if" if="[[!syncStatus.signedIn]]"> @@ -80,6 +81,15 @@ <settings-users-page prefs="{{prefs}}"></settings-users-page> <neon-animatable> </if> +<if expr="not chromeos"> + <neon-animatable id="manageProfile"> + <settings-subheader i18n-values="page-title:editPerson"> + </settings-subheader> + <settings-manage-profile profile-icon-url="[[profileIconUrl_]]" + profile-name="[[profileName_]]"> + </settings-manage-profile> + <neon-animatable> +</if> </settings-animated-pages> <paper-dialog modal id="disconnectDialog">
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js index 6a804f5f..a78e2425 100644 --- a/chrome/browser/resources/settings/people_page/people_page.js +++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -45,14 +45,39 @@ * @type {?settings.SyncStatus} */ syncStatus: Object, + + /** + * The currently selected profile icon URL. May be a data URL. + * @private {string} + */ + profileIconUrl_: String, + + /** + * The current profile name. + * @private {string} + */ + profileName_: String, }, + /** @override */ created: function() { + settings.SyncPrivateApi.getProfileInfo(this.handleProfileInfo_.bind(this)); settings.SyncPrivateApi.getSyncStatus( this.handleSyncStatusFetched_.bind(this)); }, /** + * Handler for when the profile's icon and name is updated. + * @private + * @param {!string} name + * @param {!string} iconUrl + */ + handleProfileInfo_: function(name, iconUrl) { + this.profileName_ = name; + this.profileIconUrl_ = iconUrl; + }, + + /** * Handler for when the sync state is pushed from settings.SyncPrivateApi. * @private */ @@ -70,6 +95,14 @@ }, /** @private */ + onManageProfileTap_: function() { +<if expr="not chromeos"> + this.$.pages.setSubpageChain(['manageProfile']); +</if> + // TODO(tommycli): Implement ChromeOS version. January 2016. + }, + + /** @private */ onSigninTap_: function() { settings.SyncPrivateApi.startSignIn(); },
diff --git a/chrome/browser/resources/settings/people_page/sync_private_api.js b/chrome/browser/resources/settings/people_page/sync_private_api.js index 05547fb3..89d51de 100644 --- a/chrome/browser/resources/settings/people_page/sync_private_api.js +++ b/chrome/browser/resources/settings/people_page/sync_private_api.js
@@ -59,9 +59,7 @@ * childUser: (boolean|undefined), * hasError: (boolean|undefined), * hasUnrecoverableError: (boolean|undefined), - * iconURL: (string|undefined), * managed: (boolean|undefined), - * name: (string|undefined), * setupCompleted: (boolean|undefined), * setupInProgress: (boolean|undefined), * signedIn: (boolean|undefined), @@ -92,6 +90,12 @@ */ function SyncPrivateApi() {} + /** @private {?function(!string, !string)} */ + SyncPrivateApi.getProfileInfoCallback_ = null; + + /** @private {?function(!Array<string>)} */ + SyncPrivateApi.getAvailableIconsCallback_ = null; + /** @private {?function(settings.SyncPrefs)} */ SyncPrivateApi.syncPrefsCallback_ = null; @@ -99,6 +103,52 @@ SyncPrivateApi.setPageStatusCallback_ = null; /** + * Called from JavaScript. Gets the current profile name and icon. + * @param {?function(!string, !string)} callback + */ + SyncPrivateApi.getProfileInfo = function(callback) { + SyncPrivateApi.getProfileInfoCallback_ = callback; + chrome.send('getProfileInfo'); + }; + + /** + * Called from C++ as a response to getIconsAndNames. + * @param {!string} name The current profile name. + * @param {!string} iconUrl The current profile icon's URL. Can be a data URL. + */ + SyncPrivateApi.receiveProfileInfo = function(name, iconUrl) { + if (SyncPrivateApi.getProfileInfoCallback_) + SyncPrivateApi.getProfileInfoCallback_(name, iconUrl); + }; + + /** + * Called from JavaScript. Gets the available profile icons to choose from. + * @param {!function(!Array<string>)} callback + */ + SyncPrivateApi.getAvailableIcons = function(callback) { + SyncPrivateApi.getAvailableIconsCallback_ = callback; + chrome.send('requestDefaultProfileIcons'); + }; + + /** + * Called from C++ as a response to getAvailableIcons. + * @param {!Array<string>} iconUrls An array of icon URLs. + */ + SyncPrivateApi.receiveAvailableIcons = function(iconUrls) { + if (SyncPrivateApi.getAvailableIconsCallback_) + SyncPrivateApi.getAvailableIconsCallback_(iconUrls); + }; + + /** + * Called from JavaScript. Sets the profile icon and name. + * @param {!string} iconUrl The new profile URL. + * @param {!string} name The new profile name. + */ + SyncPrivateApi.setProfileIconAndName = function(iconUrl, name) { + chrome.send('setProfileIconAndName', [iconUrl, name]); + }; + + /** * Starts the signin process for the user. Does nothing if the user is * already signed in. * @private
diff --git a/chrome/browser/resources/settings/settings_page/settings_router.js b/chrome/browser/resources/settings/settings_page/settings_router.js index 6331392..5c9c5681 100644 --- a/chrome/browser/resources/settings/settings_page/settings_router.js +++ b/chrome/browser/resources/settings/settings_page/settings_router.js
@@ -132,6 +132,15 @@ subpage: ['search-engines', 'search-engines-advanced'], subpageTitles: ['searchEnginesPageTitle', 'advancedPageTitle'], }, +<if expr="not chromeos"> + { + url: '/manageProfile', + page: 'basic', + section: 'people', + subpage: ['manageProfile'], + subpageTitles: ['editPerson'], + }, +</if> { url: '/syncSetup', page: 'basic',
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index db7cde6..96a8e002d 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -354,6 +354,19 @@ type="chrome_html" flattenhtml="true" allowexternalscript="true" /> + <if expr="not chromeos"> + <structure name="IDR_SETTINGS_PEOPLE_PAGE_MANAGE_PROFILE_CSS" + file="people_page/manage_profile.css" + type="chrome_html" /> + <structure name="IDR_SETTINGS_PEOPLE_PAGE_MANAGE_PROFILE_HTML" + file="people_page/manage_profile.html" + type="chrome_html" + flattenhtml="true" + allowexternalscript="true" /> + <structure name="IDR_SETTINGS_PEOPLE_PAGE_MANAGE_PROFILE_JS" + file="people_page/manage_profile.js" + type="chrome_html" /> + </if> <structure name="IDR_SETTINGS_PREF_UTIL_HTML" file="prefs/pref_util.html" type="chrome_html" />
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index 1406de2..8c43e72 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc
@@ -302,11 +302,9 @@ } if (succeeded) { - if (SessionRestore::GetSmartRestoreMode() != - SessionRestore::SMART_RESTORE_MODE_OFF) { - std::stable_sort(contents_created->begin(), contents_created->end()); - } - // Start Loading tabs. + // Sort the tabs in the order they should be restored, and start loading + // them. + std::stable_sort(contents_created->begin(), contents_created->end()); SessionRestoreDelegate::RestoreTabs(*contents_created, restore_started_); } @@ -520,23 +518,21 @@ base::TimeTicks now = base::TimeTicks::Now(); base::TimeTicks highest_time = base::TimeTicks::UnixEpoch(); if (initial_tab_count == 0) { - if (SessionRestore::GetSmartRestoreMode() == - SessionRestore::SMART_RESTORE_MODE_MRU) { - // The last active time of a WebContents is initially set to the - // creation time of the tab, which is not necessarly the same as the - // loading time, so we have to restore the values. Also, since TimeTicks - // only make sense in their current session, these values have to be - // sanitized first. To do so, we need to first figure out the largest - // time. This will then be used to set the last active time of - // each tab where the most recent tab will have its time set to |now| - // and the rest of the tabs will have theirs set earlier by the same - // delta as they originally had. - for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) { - const sessions::SessionTab& tab = *(window.tabs[i]); - if (tab.last_active_time > highest_time) - highest_time = tab.last_active_time; - } + // The last active time of a WebContents is initially set to the + // creation time of the tab, which is not necessarly the same as the + // loading time, so we have to restore the values. Also, since TimeTicks + // only make sense in their current session, these values have to be + // sanitized first. To do so, we need to first figure out the largest + // time. This will then be used to set the last active time of + // each tab where the most recent tab will have its time set to |now| + // and the rest of the tabs will have theirs set earlier by the same + // delta as they originally had. + for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) { + const sessions::SessionTab& tab = *(window.tabs[i]); + if (tab.last_active_time > highest_time) + highest_time = tab.last_active_time; } + for (int i = 0; i < static_cast<int>(window.tabs.size()); ++i) { const sessions::SessionTab& tab = *(window.tabs[i]); @@ -550,11 +546,8 @@ continue; // Sanitize the last active time. - if (SessionRestore::GetSmartRestoreMode() == - SessionRestore::SMART_RESTORE_MODE_MRU) { - base::TimeDelta delta = highest_time - tab.last_active_time; - contents->SetLastActiveTime(now - delta); - } + base::TimeDelta delta = highest_time - tab.last_active_time; + contents->SetLastActiveTime(now - delta); RestoredTab restored_tab(contents, is_selected_tab, tab.extension_app_id.empty(), tab.pinned); @@ -581,11 +574,8 @@ RestoreTab(tab, tab_index_offset + i, browser, false); if (contents) { // Sanitize the last active time. - if (SessionRestore::GetSmartRestoreMode() == - SessionRestore::SMART_RESTORE_MODE_MRU) { - base::TimeDelta delta = highest_time - tab.last_active_time; - contents->SetLastActiveTime(now - delta); - } + base::TimeDelta delta = highest_time - tab.last_active_time; + contents->SetLastActiveTime(now - delta); RestoredTab restored_tab(contents, false, tab.extension_app_id.empty(), tab.pinned); created_contents->push_back(restored_tab); @@ -861,16 +851,5 @@ } // static -SessionRestore::SmartRestoreMode SessionRestore::GetSmartRestoreMode() { - std::string prioritize_tabs = variations::GetVariationParamValue( - "IntelligentSessionRestore", "PrioritizeTabs"); - if (prioritize_tabs == "mru") - return SMART_RESTORE_MODE_MRU; - if (prioritize_tabs == "simple") - return SMART_RESTORE_MODE_SIMPLE; - return SMART_RESTORE_MODE_OFF; -} - -// static base::CallbackList<void(int)>* SessionRestore::on_session_restored_callbacks_ = nullptr;
diff --git a/chrome/browser/sessions/session_restore.h b/chrome/browser/sessions/session_restore.h index 61774ee..dc4ecf3 100644 --- a/chrome/browser/sessions/session_restore.h +++ b/chrome/browser/sessions/session_restore.h
@@ -41,12 +41,6 @@ SYNCHRONOUS = 1 << 2, }; - enum SmartRestoreMode { - SMART_RESTORE_MODE_OFF, // No sorting of tabs. - SMART_RESTORE_MODE_SIMPLE, // Tabs are sorted using predetermined criteria. - SMART_RESTORE_MODE_MRU // Same as above but takes into account MRU. - }; - // Notification callback list. using CallbackList = base::CallbackList<void(int)>; @@ -106,10 +100,6 @@ static CallbackSubscription RegisterOnSessionRestoredCallback( const base::Callback<void(int)>& callback); - // Returns true if smart session restore is enabled (ie. background tabs are - // sorted before being loaded). - static SmartRestoreMode GetSmartRestoreMode(); - private: SessionRestore();
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index 5bb61c9..6d55d41b 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -206,12 +206,11 @@ const BrowserList* active_browser_list_; }; -// Activates the smart restore behaviour in "simple" mode and tracks the loading -// of tabs. -class SmartSessionRestoreSimpleTest : public SessionRestoreTest, +// Activates the smart restore behaviour and tracks the loading of tabs. +class SmartSessionRestoreTest : public SessionRestoreTest, public content::NotificationObserver { public: - SmartSessionRestoreSimpleTest() {} + SmartSessionRestoreTest() {} void StartObserving(int num_tabs) { // Start by clearing everything so it can be reused in the same test. web_contents_.clear(); @@ -246,13 +245,6 @@ protected: static const int kExpectedNumTabs; static const char* const kUrls[]; - void SetUpCommandLine(base::CommandLine* command_line) override { - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - switches::kForceFieldTrials, "IntelligentSessionRestore/TestGroup/"); - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - switches::kForceFieldTrialParams, - "IntelligentSessionRestore.TestGroup:PrioritizeTabs/simple"); - } private: content::NotificationRegistrar registrar_; @@ -261,30 +253,13 @@ scoped_refptr<content::MessageLoopRunner> message_loop_runner_; int num_tabs_; - DISALLOW_COPY_AND_ASSIGN(SmartSessionRestoreSimpleTest); -}; - -class SmartSessionRestoreMRUTest : public SmartSessionRestoreSimpleTest { - public: - SmartSessionRestoreMRUTest() {} - - protected: - void SetUpCommandLine(base::CommandLine* command_line) override { - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - switches::kForceFieldTrials, "IntelligentSessionRestore/TestGroup/"); - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - switches::kForceFieldTrialParams, - "IntelligentSessionRestore.TestGroup:PrioritizeTabs/mru"); - } - - private: - DISALLOW_COPY_AND_ASSIGN(SmartSessionRestoreMRUTest); + DISALLOW_COPY_AND_ASSIGN(SmartSessionRestoreTest); }; // static -const int SmartSessionRestoreSimpleTest::kExpectedNumTabs = 6; +const int SmartSessionRestoreTest::kExpectedNumTabs = 6; // static -const char* const SmartSessionRestoreSimpleTest::kUrls[] = { +const char* const SmartSessionRestoreTest::kUrls[] = { "http://google.com/1", "http://google.com/2", "http://google.com/3", @@ -1378,78 +1353,7 @@ EXPECT_EQ(1, new_browser->tab_strip_model()->count()); } -IN_PROC_BROWSER_TEST_F(SmartSessionRestoreSimpleTest, CorrectLoadingOrder) { - ASSERT_EQ(SessionRestore::SMART_RESTORE_MODE_SIMPLE, - SessionRestore::GetSmartRestoreMode()); - - // Start observing the loading of tabs, to make sure the order is correct. - StartObserving(kExpectedNumTabs); - - struct TabInfo { - GURL url; - bool pinned; - int expected_load_order; - }; - - TabInfo tab_info[kExpectedNumTabs] = { - // This will be the foreground tab and will always load first. - {GURL("http://google.com/1"), false, 1}, - {GURL("http://google.com/2"), false, 3}, - // Internal page, should load last. - {GURL(chrome::kChromeUINewTabURL), false, 6}, - {GURL("http://google.com/4"), false, 4}, - {GURL("http://google.com/5"), true, 2}, // Pinned, should load second. - {GURL("http://google.com/6"), false, 5}, - }; - - // Set up the restore data. - std::vector<const sessions::SessionWindow*> session; - sessions::SessionWindow window; - sessions::SessionTab tab[kExpectedNumTabs]; - - for (int i = 0; i < kExpectedNumTabs; i++) { - SerializedNavigationEntry nav = - SerializedNavigationEntryTestHelper::CreateNavigation( - tab_info[i].url.spec(), tab_info[i].url.spec().c_str()); - sync_pb::SessionTab sync_data; - sync_data.set_tab_visual_index(0); - sync_data.set_current_navigation_index(0); - sync_data.add_navigation()->CopyFrom(nav.ToSyncData()); - sync_data.set_pinned(tab_info[i].pinned); - tab[i].SetFromSyncData(sync_data, base::Time::Now()); - window.tabs.push_back(tab + i); - } - - session.push_back(&window); - Profile* profile = browser()->profile(); - std::vector<Browser*> browsers = SessionRestore::RestoreForeignSessionWindows( - profile, browser()->host_desktop_type(), session.begin(), session.end()); - - ASSERT_EQ(1u, browsers.size()); - ASSERT_TRUE(browsers[0]); - ASSERT_EQ(kExpectedNumTabs, browsers[0]->tab_strip_model()->count()); - - WaitForAllTabsToStartLoading(); - - ASSERT_EQ(static_cast<size_t>(kExpectedNumTabs), web_contents().size()); - - // Make sure that contents are loaded in the correct order, ie. each tab rank - // is higher that its preceding one. - std::map<GURL, int> ranks; - for (auto t : tab_info) - ranks[t.url] = t.expected_load_order; - for (size_t i = 1; i < web_contents().size(); i++) { - int current_rank = ranks[web_contents()[i]->GetLastCommittedURL()]; - int previous_rank = ranks[web_contents()[i - 1]->GetLastCommittedURL()]; - ASSERT_LT(previous_rank, current_rank); - } - - // The SessionWindow destructor deletes the tabs, so we have to clear them - // here to avoid a crash. - window.tabs.clear(); -} - -IN_PROC_BROWSER_TEST_F(SmartSessionRestoreMRUTest, PRE_CorrectLoadingOrder) { +IN_PROC_BROWSER_TEST_F(SmartSessionRestoreTest, PRE_CorrectLoadingOrder) { Profile* profile = browser()->profile(); int activation_order[] = {4, 2, 1, 5, 0, 3}; @@ -1464,7 +1368,7 @@ ASSERT_EQ(kExpectedNumTabs, browser()->tab_strip_model()->count()); - // Activate the tabs one by one following the random activation order. + // Activate the tabs one by one following the specified activation order. for (auto i : activation_order) browser()->tab_strip_model()->ActivateTabAt(i, true); @@ -1500,7 +1404,7 @@ new_browser->tab_strip_model()->ActivateTabAt(1, true); } -IN_PROC_BROWSER_TEST_F(SmartSessionRestoreMRUTest, CorrectLoadingOrder) { +IN_PROC_BROWSER_TEST_F(SmartSessionRestoreTest, CorrectLoadingOrder) { int activation_order[] = {4, 2, 5, 0, 3, 1}; Profile* profile = browser()->profile();
diff --git a/chrome/browser/sessions/session_restore_delegate.cc b/chrome/browser/sessions/session_restore_delegate.cc index 2c06853..f562d944 100644 --- a/chrome/browser/sessions/session_restore_delegate.cc +++ b/chrome/browser/sessions/session_restore_delegate.cc
@@ -61,12 +61,8 @@ // Apps should be loaded before normal tabs. if (is_app_ != right.is_app_) return is_app_; - // Restore using MRU. Behind an experiment for now. - if (SessionRestore::GetSmartRestoreMode() == - SessionRestore::SMART_RESTORE_MODE_MRU) - return contents_->GetLastActiveTime() > - right.contents_->GetLastActiveTime(); - return false; + // Finally, older tabs should be deferred first. + return contents_->GetLastActiveTime() > right.contents_->GetLastActiveTime(); } // static @@ -83,29 +79,5 @@ favicon_driver->FetchFavicon(favicon_driver->GetActiveURL()); } - // This experiment allows us to have comparative numbers for session restore - // metrics. It will be removed once those numbers are obtained. - // TODO(georgesak): Remove this experiment when stats are collected. - base::FieldTrial* trial = - base::FieldTrialList::Find("IntelligentSessionRestore"); - if (!trial || trial->group_name() != "DontRestoreBackgroundTabs") { - TabLoader::RestoreTabs(tabs, restore_started); - } else { - // A TabLoader will not be used for this session restore, so manually create - // and use a SessionRestoreStatsCollector, normally owned by the TabLoader. - scoped_ptr<SessionRestoreStatsCollector::StatsReportingDelegate> - reporting_delegate( - new SessionRestoreStatsCollector::UmaStatsReportingDelegate()); - scoped_refptr<SessionRestoreStatsCollector> stats_collector = - new SessionRestoreStatsCollector(restore_started, - std::move(reporting_delegate)); - stats_collector->TrackTabs(tabs); - for (const auto& restored_tab : tabs) { - if (!restored_tab.is_active()) { - // Non-active tabs aren't being loaded, so mark them as deferred. - auto tab_controller = &restored_tab.contents()->GetController(); - stats_collector->DeferTab(tab_controller); - } - } - } + TabLoader::RestoreTabs(tabs, restore_started); }
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc index 9bfe60a..6671aeb 100644 --- a/chrome/browser/sessions/session_service.cc +++ b/chrome/browser/sessions/session_service.cc
@@ -743,12 +743,9 @@ sessions::CreatePinnedStateCommand(session_id, true)); } - if (SessionRestore::GetSmartRestoreMode() == - SessionRestore::SMART_RESTORE_MODE_MRU) { - base_session_service_->AppendRebuildCommand( - sessions::CreateLastActiveTimeCommand(session_id, - tab->GetLastActiveTime())); - } + base_session_service_->AppendRebuildCommand( + sessions::CreateLastActiveTimeCommand(session_id, + tab->GetLastActiveTime())); extensions::TabHelper* extensions_tab_helper = extensions::TabHelper::FromWebContents(tab);
diff --git a/chrome/browser/sessions/tab_loader.cc b/chrome/browser/sessions/tab_loader.cc index ba5330f..676db80 100644 --- a/chrome/browser/sessions/tab_loader.cc +++ b/chrome/browser/sessions/tab_loader.cc
@@ -243,13 +243,6 @@ base::MemoryPressureListener::MemoryPressureLevel TabLoader::CurrentMemoryPressureLevel() { -#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) - // Check for explicit memory pressure integration. - std::string react_to_memory_pressure = variations::GetVariationParamValue( - "IntelligentSessionRestore", "ReactToMemoryPressure"); - if (react_to_memory_pressure != "true") - return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; -#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) if (base::MemoryPressureMonitor::Get()) return base::MemoryPressureMonitor::Get()->GetCurrentPressureLevel(); @@ -258,16 +251,6 @@ void TabLoader::OnMemoryPressure( base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { - // On Windows and Mac this mechanism is only experimentally enabled. -#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) - // If memory pressure integration isn't explicitly enabled then ignore these - // calls. - std::string react_to_memory_pressure = variations::GetVariationParamValue( - "IntelligentSessionRestore", "ReactToMemoryPressure"); - if (react_to_memory_pressure != "true") - return; -#endif - // When receiving a resource pressure level warning, we stop pre-loading more // tabs since we are running in danger of loading more tabs by throwing out // old ones.
diff --git a/chrome/browser/sessions/tab_loader_delegate.cc b/chrome/browser/sessions/tab_loader_delegate.cc index d404163..598996e4 100644 --- a/chrome/browser/sessions/tab_loader_delegate.cc +++ b/chrome/browser/sessions/tab_loader_delegate.cc
@@ -17,6 +17,12 @@ // the loading time is a mix of server response and data bandwidth. static const int kInitialDelayTimerMS = 1500; +// Similar to the above constant, but the timeout that is afforded to the +// visible tab only. Having this be a longer value ensures the visible time has +// more time during which it is the only one loading, decreasing the time to +// first paint and interactivity of the foreground tab. +static const int kFirstTabLoadTimeoutMS = 60000; + class TabLoaderDelegateImpl : public TabLoaderDelegate, public net::NetworkChangeNotifier::ConnectionTypeObserver { @@ -60,27 +66,8 @@ callback->SetTabLoadingEnabled(false); } - // Initialize the timeouts to use from the session restore field trial. - // Default to the usual value if none is specified. - - static const char kIntelligentSessionRestore[] = "IntelligentSessionRestore"; - std::string timeout = variations::GetVariationParamValue( - kIntelligentSessionRestore, "FirstTabLoadTimeoutMs"); - int timeout_ms = 0; - if (timeout.empty() || !base::StringToInt(timeout, &timeout_ms) || - timeout_ms <= 0) { - timeout_ms = kInitialDelayTimerMS; - } - first_timeout_ = base::TimeDelta::FromMilliseconds(timeout_ms); - - timeout = variations::GetVariationParamValue( - kIntelligentSessionRestore, "TabLoadTimeoutMs"); - timeout_ms = 0; - if (timeout.empty() || !base::StringToInt(timeout, &timeout_ms) || - timeout_ms <= 0) { - timeout_ms = kInitialDelayTimerMS; - } - timeout_ = base::TimeDelta::FromMilliseconds(timeout_ms); + first_timeout_ = base::TimeDelta::FromMilliseconds(kFirstTabLoadTimeoutMS); + timeout_ = base::TimeDelta::FromMilliseconds(kInitialDelayTimerMS); } TabLoaderDelegateImpl::~TabLoaderDelegateImpl() {
diff --git a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc index e553c34..1d7a04d2 100644 --- a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc +++ b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc
@@ -424,7 +424,7 @@ if (view_type == extensions::VIEW_TYPE_TAB_CONTENTS || view_type == extensions::VIEW_TYPE_APP_WINDOW || view_type == extensions::VIEW_TYPE_LAUNCHER_PAGE || - view_type == extensions::VIEW_TYPE_VIRTUAL_KEYBOARD || + view_type == extensions::VIEW_TYPE_COMPONENT || view_type == extensions::VIEW_TYPE_EXTENSION_POPUP || view_type == extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { // If it is a tab, we can check for permission. For apps, this means
diff --git a/chrome/browser/ui/android/infobars/confirm_infobar.cc b/chrome/browser/ui/android/infobars/confirm_infobar.cc index acef909..0a16d257 100644 --- a/chrome/browser/ui/android/infobars/confirm_infobar.cc +++ b/chrome/browser/ui/android/infobars/confirm_infobar.cc
@@ -14,20 +14,17 @@ #include "build/build_config.h" #include "chrome/browser/android/resource_mapper.h" #include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/media/media_stream_infobar_delegate_android.h" #include "chrome/browser/permissions/permission_infobar_delegate.h" #include "components/content_settings/core/common/content_settings_types.h" #include "components/infobars/core/confirm_infobar_delegate.h" #include "content/public/browser/android/content_view_core.h" #include "content/public/browser/web_contents.h" -#include "jni/ConfirmInfoBarDelegate_jni.h" +#include "jni/ConfirmInfoBar_jni.h" #include "ui/android/window_android.h" #include "ui/gfx/android/java_bitmap.h" #include "ui/gfx/image/image.h" -#if defined(OS_ANDROID) -#include "chrome/browser/media/media_stream_infobar_delegate_android.h" -#endif - // InfoBarService ------------------------------------------------------------- scoped_ptr<infobars::InfoBar> InfoBarService::CreateConfirmInfoBar( @@ -39,14 +36,13 @@ // ConfirmInfoBar ------------------------------------------------------------- ConfirmInfoBar::ConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate> delegate) - : InfoBarAndroid(std::move(delegate)), java_confirm_delegate_() {} + : InfoBarAndroid(std::move(delegate)) {} ConfirmInfoBar::~ConfirmInfoBar() { } base::android::ScopedJavaLocalRef<jobject> ConfirmInfoBar::CreateRenderInfoBar( JNIEnv* env) { - java_confirm_delegate_.Reset(Java_ConfirmInfoBarDelegate_create(env)); base::android::ScopedJavaLocalRef<jstring> ok_button_text = base::android::ConvertUTF16ToJavaString( env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_OK)); @@ -71,7 +67,6 @@ if (delegate->AsPermissionInfobarDelegate()) { content_settings.push_back( delegate->AsPermissionInfobarDelegate()->content_setting()); -#if defined(OS_ANDROID) } else if (delegate->AsMediaStreamInfoBarDelegateAndroid()) { MediaStreamInfoBarDelegateAndroid* media_delegate = delegate->AsMediaStreamInfoBarDelegateAndroid(); @@ -83,7 +78,6 @@ content_settings.push_back( ContentSettingsType::CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC); } -#endif } content::WebContents* web_contents = @@ -95,9 +89,8 @@ base::android::ScopedJavaLocalRef<jobject> jwindow_android = cvc->GetWindowAndroid()->GetJavaObject(); - return Java_ConfirmInfoBarDelegate_showConfirmInfoBar( - env, java_confirm_delegate_.obj(), - jwindow_android.obj(), GetEnumeratedIconId(), java_bitmap.obj(), + return Java_ConfirmInfoBar_create( + env, jwindow_android.obj(), GetEnumeratedIconId(), java_bitmap.obj(), message_text.obj(), link_text.obj(), ok_button_text.obj(), cancel_button_text.obj(), base::android::ToJavaIntArray(env, content_settings).obj()); @@ -138,6 +131,6 @@ // Native JNI methods --------------------------------------------------------- -bool RegisterConfirmInfoBarDelegate(JNIEnv* env) { +bool RegisterConfirmInfoBar(JNIEnv* env) { return RegisterNativesImpl(env); }
diff --git a/chrome/browser/ui/android/infobars/confirm_infobar.h b/chrome/browser/ui/android/infobars/confirm_infobar.h index 9dfbe86..405d2cde 100644 --- a/chrome/browser/ui/android/infobars/confirm_infobar.h +++ b/chrome/browser/ui/android/infobars/confirm_infobar.h
@@ -28,12 +28,10 @@ private: void ProcessButton(int action) override; - base::android::ScopedJavaGlobalRef<jobject> java_confirm_delegate_; - DISALLOW_COPY_AND_ASSIGN(ConfirmInfoBar); }; // Registers native methods. -bool RegisterConfirmInfoBarDelegate(JNIEnv* env); +bool RegisterConfirmInfoBar(JNIEnv* env); #endif // CHROME_BROWSER_UI_ANDROID_INFOBARS_CONFIRM_INFOBAR_H_
diff --git a/chrome/browser/ui/ash/chrome_keyboard_ui.cc b/chrome/browser/ui/ash/chrome_keyboard_ui.cc index 18efdce..71408e6 100644 --- a/chrome/browser/ui/ash/chrome_keyboard_ui.cc +++ b/chrome/browser/ui/ash/chrome_keyboard_ui.cc
@@ -143,7 +143,7 @@ } void ChromeKeyboardUI::SetupWebContents(content::WebContents* contents) { - extensions::SetViewType(contents, extensions::VIEW_TYPE_VIRTUAL_KEYBOARD); + extensions::SetViewType(contents, extensions::VIEW_TYPE_COMPONENT); extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( contents); Observe(contents);
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 8dd3a53..60f241c 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -1102,14 +1102,11 @@ if (session_service && !tab_strip_model_->closing_all()) { session_service->SetSelectedTabInWindow(session_id(), tab_strip_model_->active_index()); - if (SessionRestore::GetSmartRestoreMode() == - SessionRestore::SMART_RESTORE_MODE_MRU) { - SessionTabHelper* session_tab_helper = - SessionTabHelper::FromWebContents(new_contents); - session_service->SetLastActiveTime(session_id(), - session_tab_helper->session_id(), - base::TimeTicks::Now()); - } + SessionTabHelper* session_tab_helper = + SessionTabHelper::FromWebContents(new_contents); + session_service->SetLastActiveTime(session_id(), + session_tab_helper->session_id(), + base::TimeTicks::Now()); } // This needs to be called after notifying SearchDelegate.
diff --git a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm index 81550a8d..7c5e140a 100644 --- a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm +++ b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm
@@ -107,7 +107,7 @@ withFont:[self textFont] messageColor:HelpTextColor()]; [helpTextView_ addLinkRange:controller_->HelpTextLinkRange().ToNSRange() - withURL:@"about:blank" // using a link here is bad ui + withURL:nil linkColor:HelpLinkColor()]; [helpTextView_ setDelegate:self]; [helpTextView_ setDrawsBackground:YES];
diff --git a/chrome/browser/ui/cocoa/bubble_sync_promo_controller.mm b/chrome/browser/ui/cocoa/bubble_sync_promo_controller.mm index adf2a6f..08345fd 100644 --- a/chrome/browser/ui/cocoa/bubble_sync_promo_controller.mm +++ b/chrome/browser/ui/cocoa/bubble_sync_promo_controller.mm
@@ -99,7 +99,7 @@ withFont:font messageColor:skia::SkColorToDeviceNSColor(kTextColor)]; [textView_ addLinkRange:NSMakeRange(offset, [nsLinkText length]) - withURL:@"about:blank" // using a link here is bad ui + withURL:nil linkColor:linkColor]; [textView_ setRefusesFirstResponder:YES]; [[textView_ textContainer] setLineFragmentPadding:0.0];
diff --git a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm index fb8e64f..5680df4 100644 --- a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm +++ b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm
@@ -244,7 +244,7 @@ messageColor:[NSColor blackColor]]; if ([exitLinkText length] != 0) { [exitLabel_.get() addLinkRange:NSMakeRange(0, [exitLinkText length]) - withURL:@"about:blank" // using link here is bad ui + withURL:nil linkColor:[NSColor blueColor]]; } [exitLabel_.get() setAlignment:NSRightTextAlignment];
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm index b320419..a3b1f6f 100644 --- a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm +++ b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
@@ -4,6 +4,9 @@ #import <Cocoa/Cocoa.h> +#include "base/bind.h" +#include "base/callback.h" +#include "base/callback_helpers.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/stringprintf.h" @@ -12,6 +15,7 @@ #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/ui/browser_window.h" +#import "chrome/browser/ui/cocoa/run_loop_testing.h" #import "chrome/browser/ui/cocoa/app_menu/app_menu_controller.h" #import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/extensions/browser_action_button.h" @@ -124,6 +128,63 @@ @end +// A helper class to wait for a menu to open and close. +@interface MenuWatcher : NSObject { + // The MenuController for the menu this object is watching. + MenuController* menuController_; + + // The closure to run when the menu opens, if any. + base::Closure openClosure_; + + // The closure to run when the menu closes, if any. + base::Closure closeClosure_; +} + +- (id)initWithController:(MenuController*)controller; + +// Notifications from the MenuController. +- (void)menuDidClose:(NSNotification*)notification; +- (void)menuDidOpen:(NSNotification*)notification; + +@property(nonatomic, assign) base::Closure openClosure; +@property(nonatomic, assign) base::Closure closeClosure; + +@end + +@implementation MenuWatcher + +@synthesize openClosure = openClosure_; +@synthesize closeClosure = closeClosure_; + +- (id)initWithController:(MenuController*)controller { + if (self = [super init]) { + menuController_ = controller; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(menuDidOpen:) + name:kMenuControllerMenuWillOpenNotification + object:menuController_]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(menuDidClose:) + name:kMenuControllerMenuDidCloseNotification + object:menuController_]; + } + return self; +} + +- (void)menuDidClose:(NSNotification*)notification { + if (!closeClosure_.is_null()) + base::ResetAndReturn(&closeClosure_).Run(); +} + +- (void)menuDidOpen:(NSNotification*)notification { + if (!openClosure_.is_null()) + base::ResetAndReturn(&openClosure_).Run(); +} + +@end + class BrowserActionButtonUiTest : public ExtensionBrowserTest { protected: BrowserActionButtonUiTest() {} @@ -415,6 +476,7 @@ const base::Closure& closure) { AppMenuController* appMenuController = [toolbarController appMenuController]; + EXPECT_TRUE([appMenuController isMenuOpen]); scoped_refptr<const extensions::Extension> extension = extensions::extension_action_test_util::CreateActionExtension( @@ -427,14 +489,14 @@ // Close the app menu. [appMenuController cancel]; EXPECT_FALSE([appMenuController isMenuOpen]); - base::MessageLoop::current()->PostTask(FROM_HERE, closure); + + closure.Run(); } // Test adding an extension while the app menu is open. Regression test for // crbug.com/561237. -// Flaky: http://crbug.com/564623 IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest, - DISABLED_AddExtensionWithMenuOpen) { + AddExtensionWithMenuOpen) { // Add an extension to ensure the overflow menu is present. scoped_refptr<const extensions::Extension> extension = extensions::extension_action_test_util::CreateActionExtension( @@ -450,11 +512,13 @@ // Click on the app menu, and pass in a callback to continue the test in // AddExtensionWithMenuOpen (due to the blocking nature of Cocoa menus, // passing in runLoop.QuitClosure() is not sufficient here.) - ui_controls::SendMouseEventsNotifyWhenDone( - ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP, + base::scoped_nsobject<MenuWatcher> menuWatcher( + [[MenuWatcher alloc] initWithController:appMenuController()]); + [menuWatcher setOpenClosure: base::Bind(&AddExtensionWithMenuOpen, - base::Unretained(toolbarController()), - extension_service(), - runLoop.QuitClosure())); + base::Unretained(toolbarController()), extension_service(), + runLoop.QuitClosure())]; + ui_controls::SendMouseEvents(ui_controls::LEFT, + ui_controls::DOWN | ui_controls::UP); runLoop.Run(); }
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h index 0596b00..26143ea 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h +++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "chrome/browser/extensions/extension_install_prompt.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h" +#import "chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h" namespace content { class PageNavigator; @@ -26,18 +27,19 @@ // Displays an extension install prompt as a tab modal dialog. class ExtensionInstallDialogController : - public ExtensionInstallPrompt::Delegate, + public ExtensionInstallViewDelegate, public ConstrainedWindowMacDelegate { public: ExtensionInstallDialogController( ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt); ~ExtensionInstallDialogController() override; - // ExtensionInstallPrompt::Delegate implementation. - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + // ExtensionInstallViewDelegate implementation. + void OnOkButtonClicked() override; + void OnCancelButtonClicked() override; + void OnStoreLinkClicked() override; // ConstrainedWindowMacDelegate implementation. void OnConstrainedWindowClosed(ConstrainedWindowMac* window) override; @@ -50,7 +52,10 @@ } private: - ExtensionInstallPrompt::Delegate* delegate_; + void OnPromptButtonClicked(ExtensionInstallPrompt::Result result, + const char* decision_event); + + ExtensionInstallPrompt::DoneCallback done_callback_; base::scoped_nsobject<ExtensionInstallViewController> view_controller_; scoped_ptr<ConstrainedWindowMac> constrained_window_; scoped_ptr<extensions::ExperienceSamplingEvent> sampling_event_;
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm index f43b7e6..826a3bc 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
@@ -4,7 +4,10 @@ #import "chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h" +#include <utility> + #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" @@ -14,7 +17,6 @@ #include "chrome/browser/ui/browser_finder.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h" #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h" -#import "chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h" #import "chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "content/public/browser/web_contents.h" @@ -25,30 +27,32 @@ void ShowExtensionInstallDialogImpl( ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) { // These objects will delete themselves when the dialog closes. if (!show_params->GetParentWebContents()) { - new WindowedInstallDialogController(show_params, delegate, prompt.Pass()); + new WindowedInstallDialogController(show_params, done_callback, + std::move(prompt)); return; } - new ExtensionInstallDialogController(show_params, delegate, prompt.Pass()); + new ExtensionInstallDialogController(show_params, done_callback, + std::move(prompt)); } } // namespace ExtensionInstallDialogController::ExtensionInstallDialogController( ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) - : delegate_(delegate) { + : done_callback_(done_callback) { ExtensionInstallPrompt::PromptType promptType = prompt->type(); view_controller_.reset([[ExtensionInstallViewController alloc] initWithProfile:show_params->profile() navigator:show_params->GetParentWebContents() delegate:this - prompt:prompt.Pass()]); + prompt:std::move(prompt)]); base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc] initWithContentRect:[[view_controller_ view] bounds]]); @@ -68,29 +72,39 @@ ExtensionInstallDialogController::~ExtensionInstallDialogController() { } -void ExtensionInstallDialogController::InstallUIProceed() { - if (sampling_event_.get()) - sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed); - delegate_->InstallUIProceed(); - delegate_ = NULL; - constrained_window_->CloseWebContentsModalDialog(); +void ExtensionInstallDialogController::OnOkButtonClicked() { + OnPromptButtonClicked(ExtensionInstallPrompt::Result::ACCEPTED, + ExperienceSamplingEvent::kProceed); } -void ExtensionInstallDialogController::InstallUIAbort(bool user_initiated) { - if (sampling_event_.get()) - sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny); - delegate_->InstallUIAbort(user_initiated); - delegate_ = NULL; - constrained_window_->CloseWebContentsModalDialog(); +void ExtensionInstallDialogController::OnCancelButtonClicked() { + OnPromptButtonClicked(ExtensionInstallPrompt::Result::USER_CANCELED, + ExperienceSamplingEvent::kDeny); +} + +void ExtensionInstallDialogController::OnStoreLinkClicked() { + OnPromptButtonClicked(ExtensionInstallPrompt::Result::USER_CANCELED, + ExperienceSamplingEvent::kDeny); } void ExtensionInstallDialogController::OnConstrainedWindowClosed( ConstrainedWindowMac* window) { - if (delegate_) - delegate_->InstallUIAbort(false); + if (!done_callback_.is_null()) { + base::ResetAndReturn(&done_callback_).Run( + ExtensionInstallPrompt::Result::ABORTED); + } base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); } +void ExtensionInstallDialogController::OnPromptButtonClicked( + ExtensionInstallPrompt::Result result, + const char* decision_event) { + if (sampling_event_.get()) + sampling_event_->CreateUserDecisionEvent(decision_event); + base::ResetAndReturn(&done_callback_).Run(result); + constrained_window_->CloseWebContentsModalDialog(); +} + // static ExtensionInstallPrompt::ShowDialogCallback ExtensionInstallPrompt::GetDefaultShowDialogCallback() {
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm index 756ef90..2e069dd 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm
@@ -5,6 +5,7 @@ #import "chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h" #include "chrome/browser/extensions/extension_install_prompt_show_params.h" +#include "chrome/browser/extensions/extension_install_prompt_test_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h" #import "chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h" @@ -31,23 +32,27 @@ content::WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(0); ExtensionInstallPromptShowParams show_params(tab); - chrome::MockExtensionInstallPromptDelegate delegate; + ExtensionInstallPromptTestHelper test_helper; scoped_ptr<ExtensionInstallPrompt::Prompt> prompt = chrome::BuildExtensionInstallPrompt(extension_.get()); ExtensionInstallDialogController* controller = - new ExtensionInstallDialogController(&show_params, &delegate, + new ExtensionInstallDialogController(&show_params, + test_helper.GetCallback(), prompt.Pass()); base::scoped_nsobject<NSWindow> window( [[[controller->view_controller() view] window] retain]); EXPECT_TRUE([window isVisible]); - // Press cancel to close the window + // Press cancel to close the window. [[controller->view_controller() cancelButton] performClick:nil]; // Wait for the window to finish closing. EXPECT_FALSE([window isVisible]); + + EXPECT_EQ(ExtensionInstallPrompt::Result::USER_CANCELED, + test_helper.result()); } IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogControllerTest, @@ -55,21 +60,25 @@ content::WebContents* tab = browser()->tab_strip_model()->GetWebContentsAt(0); ExtensionInstallPromptShowParams show_params(tab); - chrome::MockExtensionInstallPromptDelegate delegate; + ExtensionInstallPromptTestHelper test_helper; scoped_ptr<ExtensionInstallPrompt::Prompt> prompt = chrome::BuildExtensionPostInstallPermissionsPrompt(extension_.get()); ExtensionInstallDialogController* controller = - new ExtensionInstallDialogController(&show_params, &delegate, + new ExtensionInstallDialogController(&show_params, + test_helper.GetCallback(), prompt.Pass()); base::scoped_nsobject<NSWindow> window( [[[controller->view_controller() view] window] retain]); EXPECT_TRUE([window isVisible]); - // Press cancel to close the window + // Press cancel to close the window. [[controller->view_controller() cancelButton] performClick:nil]; // Wait for the window to finish closing. EXPECT_FALSE([window isVisible]); + + EXPECT_EQ(ExtensionInstallPrompt::Result::USER_CANCELED, + test_helper.result()); }
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h index a95ba2f..6ecb4af 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h +++ b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h
@@ -10,27 +10,6 @@ namespace chrome { -// A simple delegate implementation that counts the number of times -// |InstallUIProceed| and |InstallUIAbort| are called. -class MockExtensionInstallPromptDelegate - : public ExtensionInstallPrompt::Delegate { - public: - MockExtensionInstallPromptDelegate() - : proceed_count_(0), - abort_count_(0) {} - - // ExtensionInstallPrompt::Delegate overrides. - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; - - int proceed_count() { return proceed_count_; } - int abort_count() { return abort_count_; } - - protected: - int proceed_count_; - int abort_count_; -}; - // Loads the test extension from the given test directory and manifest file. scoped_refptr<extensions::Extension> LoadInstallPromptExtension( const char* extension_dir_name,
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm index 7fa3edf..f04a424 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm
@@ -15,14 +15,6 @@ namespace chrome { -void MockExtensionInstallPromptDelegate::InstallUIProceed() { - ++proceed_count_; -} - -void MockExtensionInstallPromptDelegate::InstallUIAbort(bool user_initiated) { - ++abort_count_; -} - scoped_refptr<extensions::Extension> LoadInstallPromptExtension( const char* extension_dir_name, const char* manifest_file) {
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h index f88d3dc..e906386 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h +++ b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h
@@ -21,8 +21,18 @@ class PageNavigator; } +class ExtensionInstallViewDelegate { + public: + virtual void OnOkButtonClicked() = 0; + virtual void OnCancelButtonClicked() = 0; + virtual void OnStoreLinkClicked() = 0; + + protected: + virtual ~ExtensionInstallViewDelegate() {} +}; + // Displays the extension or bundle install prompt, and notifies the -// ExtensionInstallPrompt::Delegate of success or failure +// Delegate of success or failure. @interface ExtensionInstallViewController : NSViewController <NSOutlineViewDataSource, NSOutlineViewDelegate> { @@ -45,7 +55,7 @@ Profile* profile_; // weak content::PageNavigator* navigator_; // weak - ExtensionInstallPrompt::Delegate* delegate_; // weak + ExtensionInstallViewDelegate* delegate_; // weak scoped_ptr<ExtensionInstallPrompt::Prompt> prompt_; base::scoped_nsobject<NSArray> warnings_; @@ -67,7 +77,7 @@ - (id)initWithProfile:(Profile*)profile navigator:(content::PageNavigator*)navigator - delegate:(ExtensionInstallPrompt::Delegate*)delegate + delegate:(ExtensionInstallViewDelegate*)delegate prompt:(scoped_ptr<ExtensionInstallPrompt::Prompt>)prompt; - (IBAction)storeLinkClicked:(id)sender; // Callback for "View details" link. - (IBAction)cancel:(id)sender;
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm index 58075eb..7960f53 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm
@@ -225,7 +225,7 @@ - (id)initWithProfile:(Profile*)profile navigator:(content::PageNavigator*)navigator - delegate:(ExtensionInstallPrompt::Delegate*)delegate + delegate:(ExtensionInstallViewDelegate*)delegate prompt:(scoped_ptr<ExtensionInstallPrompt::Prompt>)prompt { // We use a different XIB in the case of bundle installs, installs with // webstore data, or no permission warnings. These are laid out nicely for @@ -267,15 +267,15 @@ displayer.browser()->OpenURL(params); } - delegate_->InstallUIAbort(/*user_initiated=*/true); + delegate_->OnStoreLinkClicked(); } - (IBAction)cancel:(id)sender { - delegate_->InstallUIAbort(/*user_initiated=*/true); + delegate_->OnCancelButtonClicked(); } - (IBAction)ok:(id)sender { - delegate_->InstallUIProceed(); + delegate_->OnOkButtonClicked(); } - (void)awakeFromNib {
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm index 02c5791..50697f4 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm
@@ -22,6 +22,38 @@ using extensions::PermissionMessage; using extensions::PermissionMessages; +namespace { + +class MockExtensionInstallViewDelegate : public ExtensionInstallViewDelegate { + public: + enum class Action { + UNDEFINED, + OKAY, + CANCEL, + LINK, + }; + + MockExtensionInstallViewDelegate() : action_(Action::UNDEFINED) {} + ~MockExtensionInstallViewDelegate() override {} + + void OnOkButtonClicked() override { SetAction(Action::OKAY); } + void OnCancelButtonClicked() override { SetAction(Action::CANCEL); } + void OnStoreLinkClicked() override { SetAction(Action::LINK); } + + Action action() const { return action_; } + + private: + void SetAction(Action action) { + if (action_ != Action::UNDEFINED) + ADD_FAILURE() << "SetAction() called twice!"; + action_ = action; + } + + Action action_; + + DISALLOW_COPY_AND_ASSIGN(MockExtensionInstallViewDelegate); +}; + // Base class for our tests. class ExtensionInstallViewControllerTest : public CocoaProfileTest { public: @@ -33,10 +65,12 @@ scoped_refptr<extensions::Extension> extension_; }; +} // namespace + // Test that we can load the two kinds of prompts correctly, that the outlets // are hooked up, and that the dialog calls cancel when cancel is pressed. TEST_F(ExtensionInstallViewControllerTest, BasicsNormalCancel) { - chrome::MockExtensionInstallPromptDelegate delegate; + MockExtensionInstallViewDelegate delegate; scoped_ptr<ExtensionInstallPrompt::Prompt> prompt( chrome::BuildExtensionInstallPrompt(extension_.get())); @@ -86,14 +120,14 @@ EXPECT_NE(0u, [[[controller okButton] stringValue] length]); EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]); - // Test that cancel calls our delegate. + // Test that cancel calls our callback. [controller cancel:nil]; - EXPECT_EQ(1, delegate.abort_count()); - EXPECT_EQ(0, delegate.proceed_count()); + EXPECT_EQ(MockExtensionInstallViewDelegate::Action::CANCEL, + delegate.action()); } TEST_F(ExtensionInstallViewControllerTest, BasicsNormalOK) { - chrome::MockExtensionInstallPromptDelegate delegate; + MockExtensionInstallViewDelegate delegate; scoped_ptr<ExtensionInstallPrompt::Prompt> prompt( chrome::BuildExtensionInstallPrompt(extension_.get())); @@ -114,15 +148,15 @@ [controller view]; // Force nib load. [controller ok:nil]; - EXPECT_EQ(0, delegate.abort_count()); - EXPECT_EQ(1, delegate.proceed_count()); + EXPECT_EQ(MockExtensionInstallViewDelegate::Action::OKAY, + delegate.action()); } // Test that controls get repositioned when there are two warnings vs one // warning. TEST_F(ExtensionInstallViewControllerTest, MultipleWarnings) { - chrome::MockExtensionInstallPromptDelegate delegate1; - chrome::MockExtensionInstallPromptDelegate delegate2; + MockExtensionInstallViewDelegate delegate1; + MockExtensionInstallViewDelegate delegate2; scoped_ptr<ExtensionInstallPrompt::Prompt> one_warning_prompt( chrome::BuildExtensionInstallPrompt(extension_.get())); @@ -171,7 +205,7 @@ // Test that we can load the skinny prompt correctly, and that the outlets are // are hooked up. TEST_F(ExtensionInstallViewControllerTest, BasicsSkinny) { - chrome::MockExtensionInstallPromptDelegate delegate; + MockExtensionInstallViewDelegate delegate; // No warnings should trigger skinny prompt. scoped_ptr<ExtensionInstallPrompt::Prompt> no_warnings_prompt( @@ -213,7 +247,7 @@ // Test that we can load the inline prompt correctly, and that the outlets are // are hooked up. TEST_F(ExtensionInstallViewControllerTest, BasicsInline) { - chrome::MockExtensionInstallPromptDelegate delegate; + MockExtensionInstallViewDelegate delegate; // No warnings should trigger skinny prompt. scoped_ptr<ExtensionInstallPrompt::Prompt> inline_prompt( @@ -273,7 +307,7 @@ } TEST_F(ExtensionInstallViewControllerTest, PostInstallPermissionsPrompt) { - chrome::MockExtensionInstallPromptDelegate delegate; + MockExtensionInstallViewDelegate delegate; scoped_ptr<ExtensionInstallPrompt::Prompt> prompt( chrome::BuildExtensionPostInstallPermissionsPrompt(extension_.get())); @@ -297,12 +331,13 @@ EXPECT_FALSE([controller okButton]); [controller cancel:nil]; - EXPECT_EQ(1, delegate.abort_count()); + EXPECT_EQ(MockExtensionInstallViewDelegate::Action::CANCEL, + delegate.action()); } // Test that permission details show up. TEST_F(ExtensionInstallViewControllerTest, PermissionsDetails) { - chrome::MockExtensionInstallPromptDelegate delegate; + MockExtensionInstallViewDelegate delegate; scoped_ptr<ExtensionInstallPrompt::Prompt> prompt( chrome::BuildExtensionInstallPrompt(extension_.get()));
diff --git a/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h b/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h index c7ea9824..3965ec4 100644 --- a/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h +++ b/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h
@@ -11,6 +11,7 @@ #include "base/mac/scoped_nsobject.h" #include "base/macros.h" #include "chrome/browser/extensions/extension_install_prompt.h" +#import "chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h" class ExtensionInstallPromptShowParams; @class ExtensionInstallViewController; @@ -18,14 +19,13 @@ // Displays an app or extension install or permissions prompt as a standalone // NSPanel. -class WindowedInstallDialogController - : public ExtensionInstallPrompt::Delegate { +class WindowedInstallDialogController : public ExtensionInstallViewDelegate { public: // Initializes the ExtensionInstallViewController and shows the window. This // object will delete itself when the window is closed. WindowedInstallDialogController( ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt); ~WindowedInstallDialogController() override; @@ -33,16 +33,17 @@ // choice is invoked. Releases owned resources, then deletes |this|. void OnWindowClosing(); - // ExtensionInstallPrompt::Delegate: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + // ExtensionInstallViewDelegate: + void OnOkButtonClicked() override; + void OnCancelButtonClicked() override; + void OnStoreLinkClicked() override; private: FRIEND_TEST_ALL_PREFIXES(WindowedInstallDialogControllerBrowserTest, ShowInstallDialog); ExtensionInstallViewController* GetViewController(); - ExtensionInstallPrompt::Delegate* delegate_; + ExtensionInstallPrompt::DoneCallback done_callback_; base::scoped_nsobject<WindowedInstallController> install_controller_; DISALLOW_COPY_AND_ASSIGN(WindowedInstallDialogController);
diff --git a/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.mm b/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.mm index 542a82d..ed06c87 100644 --- a/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.mm +++ b/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.mm
@@ -4,6 +4,7 @@ #import "chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h" +#import "base/callback_helpers.h" #import "base/mac/sdk_forward_declarations.h" #include "base/message_loop/message_loop.h" #include "base/strings/sys_string_conversions.h" @@ -31,9 +32,9 @@ WindowedInstallDialogController::WindowedInstallDialogController( ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) - : delegate_(delegate) { + : done_callback_(done_callback) { install_controller_.reset([[WindowedInstallController alloc] initWithProfile:show_params->profile() navigator:show_params->GetParentWebContents() @@ -44,14 +45,14 @@ WindowedInstallDialogController::~WindowedInstallDialogController() { DCHECK(!install_controller_); - DCHECK(!delegate_); + DCHECK(done_callback_.is_null()); } void WindowedInstallDialogController::OnWindowClosing() { install_controller_.reset(); - if (delegate_) { - delegate_->InstallUIAbort(false); - delegate_ = NULL; + if (!done_callback_.is_null()) { + base::ResetAndReturn(&done_callback_).Run( + ExtensionInstallPrompt::Result::ABORTED); } base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); } @@ -61,15 +62,21 @@ return [install_controller_ viewController]; } -void WindowedInstallDialogController::InstallUIProceed() { - delegate_->InstallUIProceed(); - delegate_ = NULL; +void WindowedInstallDialogController::OnOkButtonClicked() { + base::ResetAndReturn(&done_callback_).Run( + ExtensionInstallPrompt::Result::ACCEPTED); [[install_controller_ window] close]; } -void WindowedInstallDialogController::InstallUIAbort(bool user_initiated) { - delegate_->InstallUIAbort(user_initiated); - delegate_ = NULL; +void WindowedInstallDialogController::OnCancelButtonClicked() { + base::ResetAndReturn(&done_callback_).Run( + ExtensionInstallPrompt::Result::USER_CANCELED); + [[install_controller_ window] close]; +} + +void WindowedInstallDialogController::OnStoreLinkClicked() { + base::ResetAndReturn(&done_callback_).Run( + ExtensionInstallPrompt::Result::USER_CANCELED); [[install_controller_ window] close]; }
diff --git a/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller_browsertest.mm b/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller_browsertest.mm index 839366e..ab2e536 100644 --- a/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller_browsertest.mm +++ b/chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller_browsertest.mm
@@ -4,8 +4,11 @@ #import "chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h" +#include <utility> + #include "base/run_loop.h" #include "base/threading/sequenced_worker_pool.h" +#include "chrome/browser/extensions/extension_install_prompt_test_helper.h" #include "chrome/browser/ui/browser.h" #import "chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h" #import "chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h" @@ -21,10 +24,11 @@ void TestingShowAppListInstallDialogController( WindowedInstallDialogController** controller, ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) { *controller = - new WindowedInstallDialogController(show_params, delegate, prompt.Pass()); + new WindowedInstallDialogController(show_params, done_callback, + std::move(prompt)); } typedef InProcessBrowserTest WindowedInstallDialogControllerBrowserTest; @@ -40,11 +44,11 @@ new ExtensionInstallPrompt(browser()->profile(), NULL)); WindowedInstallDialogController* controller = NULL; - chrome::MockExtensionInstallPromptDelegate delegate; + ExtensionInstallPromptTestHelper test_helper; scoped_refptr<extensions::Extension> extension = chrome::LoadInstallPromptExtension("permissions", "many-apis.json"); prompt->ShowDialog( - &delegate, extension.get(), nullptr, + test_helper.GetCallback(), extension.get(), nullptr, base::Bind(&TestingShowAppListInstallDialogController, &controller)); // The prompt needs to load the image, which happens on the blocking pool. @@ -55,12 +59,13 @@ [[[controller->GetViewController() view] window] retain]); EXPECT_TRUE([window isVisible]); EXPECT_TRUE([window delegate]); - EXPECT_EQ(0, delegate.abort_count()); + EXPECT_FALSE(test_helper.has_result()); // Press cancel to close the window. [[controller->GetViewController() cancelButton] performClick:nil]; EXPECT_FALSE([window delegate]); - EXPECT_EQ(1, delegate.abort_count()); + EXPECT_EQ(ExtensionInstallPrompt::Result::USER_CANCELED, + test_helper.result()); // Ensure the window is closed. EXPECT_FALSE([window isVisible]);
diff --git a/chrome/browser/ui/cocoa/infobars/save_password_infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/save_password_infobar_controller.mm index 42d6bb8e..005e00a 100644 --- a/chrome/browser/ui/cocoa/infobars/save_password_infobar_controller.mm +++ b/chrome/browser/ui/cocoa/infobars/save_password_infobar_controller.mm
@@ -25,9 +25,7 @@ NSColor* linkColor = skia::SkColorToCalibratedNSColor(chrome_style::GetLinkColor()); HyperlinkTextView* view = (HyperlinkTextView*)label_.get(); - [view addLinkRange:linkRange.ToNSRange() - withURL:@"about:blank" // using a link here is bad ui - linkColor:linkColor]; + [view addLinkRange:linkRange.ToNSRange() withURL:nil linkColor:linkColor]; } }
diff --git a/chrome/browser/ui/cocoa/passwords/confirmation_password_saved_view_controller.mm b/chrome/browser/ui/cocoa/passwords/confirmation_password_saved_view_controller.mm index f27e9b1..96fbd4a 100644 --- a/chrome/browser/ui/cocoa/passwords/confirmation_password_saved_view_controller.mm +++ b/chrome/browser/ui/cocoa/passwords/confirmation_password_saved_view_controller.mm
@@ -82,7 +82,7 @@ skia::SkColorToCalibratedNSColor(chrome_style::GetLinkColor()); [confirmationText_ addLinkRange:model_->save_confirmation_link_range().ToNSRange() - withURL:@"about:blank" // using a link here is bad ui + withURL:nil linkColor:linkColor]; [confirmationText_ setDelegate:self]; [[confirmationText_ textContainer] setLineFragmentPadding:0.0f];
diff --git a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm index 088d6cb..9d19017 100644 --- a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm +++ b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm
@@ -105,7 +105,7 @@ NSColor* linkColor = skia::SkColorToCalibratedNSColor(chrome_style::GetLinkColor()); [titleView addLinkRange:titleBrandLinkRange - withURL:@"about:blank" // using a link here is bad ui + withURL:nil linkColor:linkColor]; [titleView.get() setDelegate:self];
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm index a8ad3a2..0fe1b98b 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
@@ -179,7 +179,7 @@ withFont:[NSFont labelFontOfSize:kTextFontSize] messageColor:[NSColor blackColor]]; [text_view addLinkRange:NSMakeRange(link_offset, [link length]) - withURL:@"about:blank" // using a link here is bad ui + withURL:nil linkColor:link_color]; // Removes the underlining from the link.
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm index 7c5e8a9..3ee3d88 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm
@@ -105,7 +105,7 @@ withFont:font messageColor:[NSColor blackColor]]; [textView addLinkRange:NSMakeRange(offset, [linkString length]) - withURL:@"about:blank" // using a link here is bad ui + withURL:nil linkColor:linkColor]; RemoveUnderlining(textView, offset, link.size()); [textView setDelegate:delegate];
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.cc b/chrome/browser/ui/extensions/extension_enable_flow.cc index 6cc42919..2862ac3 100644 --- a/chrome/browser/ui/extensions/extension_enable_flow.cc +++ b/chrome/browser/ui/extensions/extension_enable_flow.cc
@@ -27,8 +27,8 @@ delegate_(delegate), parent_contents_(NULL), parent_window_(NULL), - extension_registry_observer_(this) { -} + extension_registry_observer_(this), + weak_ptr_factory_(this) {} ExtensionEnableFlow::~ExtensionEnableFlow() { } @@ -117,7 +117,9 @@ ExtensionInstallPrompt::PromptType type = ExtensionInstallPrompt::GetReEnablePromptTypeForExtension(profile_, extension); - prompt_->ShowDialog(this, extension, nullptr, + prompt_->ShowDialog(base::Bind(&ExtensionEnableFlow::InstallPromptDone, + weak_ptr_factory_.GetWeakPtr()), + extension, nullptr, make_scoped_ptr(new ExtensionInstallPrompt::Prompt(type)), ExtensionInstallPrompt::GetDefaultShowDialogCallback()); } @@ -170,23 +172,25 @@ } } -void ExtensionEnableFlow::InstallUIProceed() { - ExtensionService* service = - extensions::ExtensionSystem::Get(profile_)->extension_service(); +void ExtensionEnableFlow::InstallPromptDone( + ExtensionInstallPrompt::Result result) { + if (result == ExtensionInstallPrompt::Result::ACCEPTED) { + ExtensionService* service = + extensions::ExtensionSystem::Get(profile_)->extension_service(); - // The extension can be uninstalled in another window while the UI was - // showing. Treat it as a cancellation and notify |delegate_|. - const Extension* extension = service->GetExtensionById(extension_id_, true); - if (!extension) { - delegate_->ExtensionEnableFlowAborted(true); - return; + // The extension can be uninstalled in another window while the UI was + // showing. Treat it as a cancellation and notify |delegate_|. + const Extension* extension = service->GetExtensionById(extension_id_, true); + if (!extension) { + delegate_->ExtensionEnableFlowAborted(true); + return; + } + + service->GrantPermissionsAndEnableExtension(extension); + delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us. + } else { + delegate_->ExtensionEnableFlowAborted( + result == ExtensionInstallPrompt::Result::USER_CANCELED); + // |delegate_| may delete us. } - - service->GrantPermissionsAndEnableExtension(extension); - delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us. -} - -void ExtensionEnableFlow::InstallUIAbort(bool user_initiated) { - delegate_->ExtensionEnableFlowAborted(user_initiated); - // |delegate_| may delete us. }
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.h b/chrome/browser/ui/extensions/extension_enable_flow.h index b84c2c0..02060f8 100644 --- a/chrome/browser/ui/extensions/extension_enable_flow.h +++ b/chrome/browser/ui/extensions/extension_enable_flow.h
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/scoped_observer.h" #include "chrome/browser/extensions/extension_install_prompt.h" #include "content/public/browser/notification_observer.h" @@ -33,8 +34,7 @@ // extension is enabled already). Otherwise, a re-enable install prompt is // shown to user. The extension is enabled when user acknowledges it or the // flow is aborted when user declines it. -class ExtensionEnableFlow : public ExtensionInstallPrompt::Delegate, - public content::NotificationObserver, +class ExtensionEnableFlow : public content::NotificationObserver, public extensions::ExtensionRegistryObserver { public: ExtensionEnableFlow(Profile* profile, @@ -88,9 +88,7 @@ const extensions::Extension* extension, extensions::UninstallReason reason) override; - // ExtensionInstallPrompt::Delegate overrides: - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; + void InstallPromptDone(ExtensionInstallPrompt::Result result); Profile* const profile_; const std::string extension_id_; @@ -116,6 +114,8 @@ extensions::ExtensionRegistryObserver> extension_registry_observer_; + base::WeakPtrFactory<ExtensionEnableFlow> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(ExtensionEnableFlow); };
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc index 715023c..bdeeff9a 100644 --- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc +++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -10,6 +10,7 @@ #include <utility> #include <vector> +#include "base/callback_helpers.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/i18n/rtl.h" @@ -103,13 +104,13 @@ void ShowExtensionInstallDialogImpl( ExtensionInstallPromptShowParams* show_params, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); bool use_tab_modal_dialog = prompt->ShouldUseTabModalDialog(); ExtensionInstallDialogView* dialog = new ExtensionInstallDialogView( - show_params->profile(), show_params->GetParentWebContents(), delegate, - std::move(prompt)); + show_params->profile(), show_params->GetParentWebContents(), + done_callback, std::move(prompt)); if (use_tab_modal_dialog) { content::WebContents* parent_web_contents = show_params->GetParentWebContents(); @@ -198,11 +199,11 @@ ExtensionInstallDialogView::ExtensionInstallDialogView( Profile* profile, content::PageNavigator* navigator, - ExtensionInstallPrompt::Delegate* delegate, + const ExtensionInstallPrompt::DoneCallback& done_callback, scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) : profile_(profile), navigator_(navigator), - delegate_(delegate), + done_callback_(done_callback), prompt_(std::move(prompt)), container_(NULL), scroll_view_(NULL), @@ -211,8 +212,10 @@ } ExtensionInstallDialogView::~ExtensionInstallDialogView() { - if (!handled_result_) - delegate_->InstallUIAbort(true); + if (!handled_result_ && !done_callback_.is_null()) { + base::ResetAndReturn(&done_callback_) + .Run(ExtensionInstallPrompt::Result::USER_CANCELED); + } } void ExtensionInstallDialogView::InitView() { @@ -593,7 +596,8 @@ UpdateInstallResultHistogram(false); if (sampling_event_) sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny); - delegate_->InstallUIAbort(true); + base::ResetAndReturn(&done_callback_) + .Run(ExtensionInstallPrompt::Result::USER_CANCELED); return true; } @@ -604,7 +608,8 @@ UpdateInstallResultHistogram(true); if (sampling_event_) sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed); - delegate_->InstallUIProceed(); + base::ResetAndReturn(&done_callback_) + .Run(ExtensionInstallPrompt::Result::ACCEPTED); return true; }
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.h b/chrome/browser/ui/views/extensions/extension_install_dialog_view.h index d0ee5a2..b2488302 100644 --- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.h +++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.h
@@ -39,10 +39,11 @@ class ExtensionInstallDialogView : public views::DialogDelegateView, public views::LinkListener { public: - ExtensionInstallDialogView(Profile* profile, - content::PageNavigator* navigator, - ExtensionInstallPrompt::Delegate* delegate, - scoped_ptr<ExtensionInstallPrompt::Prompt> prompt); + ExtensionInstallDialogView( + Profile* profile, + content::PageNavigator* navigator, + const ExtensionInstallPrompt::DoneCallback& done_callback, + scoped_ptr<ExtensionInstallPrompt::Prompt> prompt); ~ExtensionInstallDialogView() override; // Returns the interior ScrollView of the dialog. This allows us to inspect @@ -91,7 +92,7 @@ Profile* profile_; content::PageNavigator* navigator_; - ExtensionInstallPrompt::Delegate* delegate_; + ExtensionInstallPrompt::DoneCallback done_callback_; scoped_ptr<ExtensionInstallPrompt::Prompt> prompt_; // The container view that contains all children (heading, icon, webstore @@ -109,8 +110,8 @@ // ExperienceSampling: Track this UI event. scoped_ptr<extensions::ExperienceSamplingEvent> sampling_event_; - // Set to true once the user's selection has been received and the - // |delegate_| has been notified. + // Set to true once the user's selection has been received and the callback + // has been run. bool handled_result_; DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogView);
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc index 7e7513d..98869b8 100644 --- a/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_icon_manager.h" #include "chrome/browser/extensions/extension_install_prompt.h" +#include "chrome/browser/extensions/extension_install_prompt_test_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h" @@ -30,35 +31,6 @@ using extensions::PermissionMessage; using extensions::PermissionMessages; -// A simple delegate implementation that counts the number of times -// |InstallUIProceed| and |InstallUIAbort| are called. -class MockExtensionInstallPromptDelegate - : public ExtensionInstallPrompt::Delegate { - public: - MockExtensionInstallPromptDelegate() - : proceed_count_(0), - abort_count_(0) {} - - // ExtensionInstallPrompt::Delegate overrides. - void InstallUIProceed() override; - void InstallUIAbort(bool user_initiated) override; - - int proceed_count() { return proceed_count_; } - int abort_count() { return abort_count_; } - - protected: - int proceed_count_; - int abort_count_; -}; - -void MockExtensionInstallPromptDelegate::InstallUIProceed() { - ++proceed_count_; -} - -void MockExtensionInstallPromptDelegate::InstallUIAbort(bool user_initiated) { - ++abort_count_; -} - class ExtensionInstallDialogViewTestBase : public ExtensionBrowserTest { protected: explicit ExtensionInstallDialogViewTestBase( @@ -74,13 +46,11 @@ const PermissionMessages& permissions); content::WebContents* web_contents() { return web_contents_; } - MockExtensionInstallPromptDelegate* delegate() { return &delegate_; } private: const extensions::Extension* extension_; ExtensionInstallPrompt::PromptType prompt_type_; content::WebContents* web_contents_; - MockExtensionInstallPromptDelegate delegate_; DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogViewTestBase); }; @@ -131,7 +101,8 @@ bool ScrollbarTest::IsScrollbarVisible( scoped_ptr<ExtensionInstallPrompt::Prompt> prompt) { ExtensionInstallDialogView* dialog = new ExtensionInstallDialogView( - profile(), web_contents(), delegate(), std::move(prompt)); + profile(), web_contents(), ExtensionInstallPrompt::DoneCallback(), + std::move(prompt)); // Create the modal view around the install dialog view. views::Widget* modal = constrained_window::CreateBrowserModalDialogViews( @@ -189,10 +160,10 @@ // cancel the install. IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogViewTest, NotifyDelegate) { { - // The user confirms the install. - MockExtensionInstallPromptDelegate delegate; + ExtensionInstallPromptTestHelper helper; scoped_ptr<ExtensionInstallDialogView> dialog( - new ExtensionInstallDialogView(profile(), web_contents(), &delegate, + new ExtensionInstallDialogView(profile(), web_contents(), + helper.GetCallback(), CreatePrompt())); views::DialogDelegateView* delegate_view = dialog.get(); @@ -200,15 +171,15 @@ delegate_view->OnClosed(); dialog.reset(); - EXPECT_EQ(0, delegate.abort_count()); - EXPECT_EQ(1, delegate.proceed_count()); + EXPECT_EQ(ExtensionInstallPrompt::Result::ACCEPTED, helper.result()); } { // The user cancels the install. - MockExtensionInstallPromptDelegate delegate; + ExtensionInstallPromptTestHelper helper; scoped_ptr<ExtensionInstallDialogView> dialog( - new ExtensionInstallDialogView(profile(), web_contents(), &delegate, + new ExtensionInstallDialogView(profile(), web_contents(), + helper.GetCallback(), CreatePrompt())); views::DialogDelegateView* delegate_view = dialog.get(); @@ -216,20 +187,20 @@ delegate_view->OnClosed(); dialog.reset(); - EXPECT_EQ(1, delegate.abort_count()); - EXPECT_EQ(0, delegate.proceed_count()); + EXPECT_EQ(ExtensionInstallPrompt::Result::USER_CANCELED, helper.result()); } { // Corner case: Dialog is closed without the user explicitly choosing to // proceed or cancel. - MockExtensionInstallPromptDelegate delegate; + ExtensionInstallPromptTestHelper helper; scoped_ptr<ExtensionInstallDialogView> dialog( - new ExtensionInstallDialogView(profile(), web_contents(), &delegate, + new ExtensionInstallDialogView(profile(), web_contents(), + helper.GetCallback(), CreatePrompt())); dialog.reset(); - EXPECT_EQ(1, delegate.abort_count()); - EXPECT_EQ(0, delegate.proceed_count()); + // TODO(devlin): Should this be ABORTED? + EXPECT_EQ(ExtensionInstallPrompt::Result::USER_CANCELED, helper.result()); } }
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc index 0e4fb9b..203f86fc 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -115,7 +115,7 @@ int IconLabelBubbleView::GetImageAndPaddingWidth() const { const int image_width = image_->GetPreferredSize().width(); return image_width - ? image_width - GetLayoutConstant(ICON_LABEL_VIEW_INTERNAL_PADDING) + ? image_width + GetLayoutConstant(ICON_LABEL_VIEW_INTERNAL_PADDING) : 0; }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc index 176ec2a..3703da2c 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc +++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
@@ -212,8 +212,6 @@ const base::string16& text) { scoped_ptr<views::LabelButton> button(new views::LabelButton(listener, text)); button->SetStyle(views::Button::STYLE_BUTTON); - button->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( - ui::ResourceBundle::SmallFont)); return button; } @@ -248,7 +246,7 @@ password_manager::CredentialType type); ManagePasswordsBubbleView* parent_; - views::LabelButton* cancel_button_; + views::Button* cancel_button_; DISALLOW_COPY_AND_ASSIGN(AccountChooserView); }; @@ -367,7 +365,7 @@ base::OneShotTimer timer_; ManagePasswordsBubbleView* parent_; ScopedObserver<views::Widget, views::WidgetObserver> observed_browser_; - views::LabelButton* ok_button_; + views::Button* ok_button_; DISALLOW_COPY_AND_ASSIGN(AutoSigninView); }; @@ -494,8 +492,8 @@ ManagePasswordsBubbleView* parent_; - views::BlueButton* save_button_; - views::LabelButton* never_button_; + views::Button* save_button_; + views::Button* never_button_; DISALLOW_COPY_AND_ASSIGN(PendingView); }; @@ -516,8 +514,6 @@ } save_button_ = new views::BlueButton( this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON)); - save_button_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( - ui::ResourceBundle::SmallFont)); never_button_ = GenerateButton( this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_BUBBLE_BLACKLIST_BUTTON)) @@ -604,7 +600,7 @@ ManagePasswordsBubbleView* parent_; views::Link* manage_link_; - views::LabelButton* done_button_; + views::Button* done_button_; DISALLOW_COPY_AND_ASSIGN(ManageView); }; @@ -646,8 +642,6 @@ // Then add the "manage passwords" link and "Done" button. manage_link_ = new views::Link(parent_->model()->manage_link()); manage_link_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - manage_link_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( - ui::ResourceBundle::SmallFont)); manage_link_->SetUnderline(false); manage_link_->set_listener(this); @@ -703,7 +697,7 @@ int event_flags) override; ManagePasswordsBubbleView* parent_; - views::LabelButton* ok_button_; + views::Button* ok_button_; DISALLOW_COPY_AND_ASSIGN(SaveConfirmationView); }; @@ -836,9 +830,8 @@ CredentialsSelectionView* selection_view_; - views::BlueButton* update_button_; - - views::LabelButton* nope_button_; + views::Button* update_button_; + views::Button* nope_button_; DISALLOW_COPY_AND_ASSIGN(UpdatePendingView); }; @@ -868,9 +861,6 @@ update_button_ = new views::BlueButton( this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_UPDATE_BUTTON)); - update_button_->SetFontList( - ui::ResourceBundle::GetSharedInstance().GetFontList( - ui::ResourceBundle::SmallFont)); // Title row. AddTitleRowWithLink(layout, parent_->model(), this);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index e969027..151d264 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -511,7 +511,7 @@ } else { path->rCubicTo(-0.5 * scale, -1.125 * scale, 0.5 * scale, -scale - 2, scale, -scale - 2); - path->lineTo((width() - 4) * scale - diag_width + 1, scale - 1); + path->lineTo((width() - 4) * scale - diag_width + 1, button_y + scale - 1); path->rCubicTo(0.75 * scale, 0, 1.625 * scale, 0.5 * scale, 2 * scale, 1.5 * scale); path->rLineTo(diag_width, diag_height);
diff --git a/chrome/browser/ui/webui/plugins/plugins_handler.cc b/chrome/browser/ui/webui/plugins/plugins_handler.cc index 29ae46e..a3f2165 100644 --- a/chrome/browser/ui/webui/plugins/plugins_handler.cc +++ b/chrome/browser/ui/webui/plugins/plugins_handler.cc
@@ -283,9 +283,6 @@ base::string16 group_name = plugin_metadata->name(); std::string group_identifier = plugin_metadata->identifier(); bool group_enabled = false; - bool all_plugins_enabled_by_policy = true; - bool all_plugins_disabled_by_policy = true; - bool all_plugins_managed_by_policy = true; const WebPluginInfo* active_plugin = NULL; for (size_t j = 0; j < group_plugins.size(); ++j) { const WebPluginInfo& group_plugin = *group_plugins[j]; @@ -299,37 +296,17 @@ plugin_file->Set("mimeTypes", GetPluginMimeTypes(group_plugin)); bool plugin_enabled = plugin_prefs->IsPluginEnabled(group_plugin); + plugin_file->SetString( + "enabledMode", + GetPluginEnabledMode(group_plugin.name, group_name, plugin_enabled)); + plugin_files->Append(plugin_file); if (!active_plugin || (plugin_enabled && !group_enabled)) active_plugin = &group_plugin; group_enabled = plugin_enabled || group_enabled; - - std::string enabled_mode; - PluginPrefs::PolicyStatus plugin_status = - plugin_prefs->PolicyStatusForPlugin(group_plugin.name); - PluginPrefs::PolicyStatus group_status = - plugin_prefs->PolicyStatusForPlugin(group_name); - if (plugin_status == PluginPrefs::POLICY_ENABLED || - group_status == PluginPrefs::POLICY_ENABLED) { - enabled_mode = "enabledByPolicy"; - all_plugins_disabled_by_policy = false; - } else { - all_plugins_enabled_by_policy = false; - if (plugin_status == PluginPrefs::POLICY_DISABLED || - group_status == PluginPrefs::POLICY_DISABLED) { - enabled_mode = "disabledByPolicy"; - } else { - all_plugins_disabled_by_policy = false; - all_plugins_managed_by_policy = false; - enabled_mode = plugin_enabled ? "enabledByUser" : "disabledByUser"; - } - } - plugin_file->SetString("enabledMode", enabled_mode); - - plugin_files->Append(plugin_file); } - base::DictionaryValue* group_data = new base::DictionaryValue(); + base::DictionaryValue* group_data = new base::DictionaryValue(); group_data->Set("plugin_files", plugin_files); group_data->SetString("name", group_name); group_data->SetString("id", group_identifier); @@ -343,19 +320,8 @@ group_data->SetString("update_url", plugin_metadata->plugin_url().spec()); #endif - std::string enabled_mode; - if (all_plugins_enabled_by_policy) { - enabled_mode = "enabledByPolicy"; - } else if (all_plugins_disabled_by_policy) { - enabled_mode = "disabledByPolicy"; - } else if (all_plugins_managed_by_policy) { - enabled_mode = "managedByPolicy"; - } else if (group_enabled) { - enabled_mode = "enabledByUser"; - } else { - enabled_mode = "disabledByUser"; - } - group_data->SetString("enabledMode", enabled_mode); + group_data->SetString( + "enabledMode", GetPluginGroupEnabledMode(*plugin_files, group_enabled)); bool always_allowed = false; if (group_enabled) { @@ -372,3 +338,56 @@ results.Set("plugins", plugin_groups_data); web_ui()->CallJavascriptFunction("returnPluginsData", results); } + +std::string PluginsHandler::GetPluginEnabledMode( + const base::string16& plugin_name, + const base::string16& group_name, + bool plugin_enabled) const { + Profile* profile = Profile::FromWebUI(web_ui()); + PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get(); + PluginPrefs::PolicyStatus plugin_status = + plugin_prefs->PolicyStatusForPlugin(plugin_name); + PluginPrefs::PolicyStatus group_status = + plugin_prefs->PolicyStatusForPlugin(group_name); + + if (plugin_status == PluginPrefs::POLICY_ENABLED || + group_status == PluginPrefs::POLICY_ENABLED) { + return "enabledByPolicy"; + } + if (plugin_status == PluginPrefs::POLICY_DISABLED || + group_status == PluginPrefs::POLICY_DISABLED) { + return "disabledByPolicy"; + } + return plugin_enabled ? "enabledByUser" : "disabledByUser"; +} + +std::string PluginsHandler::GetPluginGroupEnabledMode( + const base::ListValue& plugin_files, bool group_enabled) const { + bool plugins_enabled_by_policy = true; + bool plugins_disabled_by_policy = true; + bool plugins_managed_by_policy = true; + + for (base::ListValue::const_iterator it = plugin_files.begin(); + it != plugin_files.end(); ++it) { + base::DictionaryValue* plugin_dict; + CHECK((*it)->GetAsDictionary(&plugin_dict)); + std::string plugin_enabled_mode; + CHECK(plugin_dict->GetString("enabledMode", &plugin_enabled_mode)); + + plugins_enabled_by_policy = plugins_enabled_by_policy && + plugin_enabled_mode == "enabledByPolicy"; + plugins_disabled_by_policy = plugins_disabled_by_policy && + plugin_enabled_mode == "disabledByPolicy"; + plugins_managed_by_policy = plugins_managed_by_policy && + (plugin_enabled_mode == "enabledByPolicy" || + plugin_enabled_mode == "disabledByPolicy"); + } + + if (plugins_enabled_by_policy) + return "enabledByPolicy"; + if (plugins_disabled_by_policy) + return "disabledByPolicy"; + if (plugins_managed_by_policy) + return "managedByPolicy"; + return group_enabled ? "enabledByUser" : "disabledByUser"; +}
diff --git a/chrome/browser/ui/webui/plugins/plugins_handler.h b/chrome/browser/ui/webui/plugins/plugins_handler.h index f9d109b..2fba9796 100644 --- a/chrome/browser/ui/webui/plugins/plugins_handler.h +++ b/chrome/browser/ui/webui/plugins/plugins_handler.h
@@ -49,6 +49,17 @@ // Called on the UI thread when the plugin information is ready. void PluginsLoaded(const std::vector<content::WebPluginInfo>& plugins); + // Detect a plugin's enabled mode (one of enabledByUser, disabledByUser, + // enabledByPolicy, disabledByPolicy). + std::string GetPluginEnabledMode(const base::string16& plugin_name, + const base::string16& group_name, + bool plugin_enabled) const; + + // Detect a plugin group's enabled mode (one of enabledByUser, disabledByUser, + // enabledByPolicy, disabledByPolicy, managedByPolicy). + std::string GetPluginGroupEnabledMode(const base::ListValue& plugin_files, + bool group_enabled) const; + content::NotificationRegistrar registrar_; // This pref guards the value whether about:plugins is in the details mode or
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index b2ddb46c..f35481c 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -493,6 +493,11 @@ html_source->AddLocalizedString("peoplePageTitle", IDS_SETTINGS_PEOPLE); html_source->AddLocalizedString("manageOtherPeople", IDS_SETTINGS_PEOPLE_MANAGE_OTHER_PEOPLE); + +#if !defined(OS_CHROMEOS) + html_source->AddLocalizedString("editPerson", IDS_SETTINGS_EDIT_PERSON); +#endif + html_source->AddLocalizedString("syncOverview", IDS_SETTINGS_SYNC_OVERVIEW); html_source->AddLocalizedString("syncSignin", IDS_SETTINGS_SYNC_SIGNIN); html_source->AddLocalizedString("syncDisconnect",
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc index b1de9faa..6138db26 100644 --- a/chrome/browser/ui/webui/settings/md_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -26,6 +26,10 @@ #include "grit/settings_resources.h" #include "grit/settings_resources_map.h" +#if !defined(OS_CHROMEOS) +#include "chrome/browser/ui/webui/settings/settings_manage_profile_handler.h" +#endif + namespace settings { SettingsPageUIHandler::SettingsPageUIHandler() { @@ -36,20 +40,24 @@ MdSettingsUI::MdSettingsUI(content::WebUI* web_ui) : content::WebUIController(web_ui) { + Profile* profile = Profile::FromWebUI(web_ui); AddSettingsPageUIHandler(new AppearanceHandler(web_ui)); AddSettingsPageUIHandler(new ClearBrowsingDataHandler(web_ui)); AddSettingsPageUIHandler(new DefaultBrowserHandler(web_ui)); AddSettingsPageUIHandler(new DownloadsHandler()); AddSettingsPageUIHandler(new FontHandler(web_ui)); AddSettingsPageUIHandler(new LanguagesHandler(web_ui)); - AddSettingsPageUIHandler(new PeopleHandler(Profile::FromWebUI(web_ui))); + AddSettingsPageUIHandler(new PeopleHandler(profile)); AddSettingsPageUIHandler(new StartupPagesHandler(web_ui)); +#if !defined(OS_CHROMEOS) + AddSettingsPageUIHandler(new ManageProfileHandler(profile)); +#endif + content::WebUIDataSource* html_source = content::WebUIDataSource::Create(chrome::kChromeUIMdSettingsHost); - AddSettingsPageUIHandler(ResetSettingsHandler::Create( - html_source, Profile::FromWebUI(web_ui))); + AddSettingsPageUIHandler(ResetSettingsHandler::Create(html_source, profile)); // Add all settings resources. for (size_t i = 0; i < kSettingsResourcesSize; ++i) { @@ -57,7 +65,7 @@ kSettingsResources[i].value); } - AddLocalizedStrings(html_source, Profile::FromWebUI(web_ui)); + AddLocalizedStrings(html_source, profile); html_source->SetDefaultResource(IDR_SETTINGS_SETTINGS_HTML); content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(),
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc index f180eb4a..2cf3fe0c 100644 --- a/chrome/browser/ui/webui/settings/people_handler.cc +++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -215,10 +215,15 @@ ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_)); if (sync_service) sync_service_observer_.Add(sync_service); + + g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this); } PeopleHandler::~PeopleHandler() { - // Just exit if running unit tests (no actual WebUI is attached). + g_browser_process->profile_manager()-> + GetProfileInfoCache().RemoveObserver(this); + + // Early exit if running unit tests (no actual WebUI is attached). if (!web_ui()) return; @@ -258,6 +263,9 @@ void PeopleHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( + "getProfileInfo", + base::Bind(&PeopleHandler::HandleGetProfileInfo, base::Unretained(this))); + web_ui()->RegisterMessageCallback( "SyncSetupDidClosePage", base::Bind(&PeopleHandler::OnDidClosePage, base::Unretained(this))); web_ui()->RegisterMessageCallback( @@ -430,6 +438,16 @@ : nullptr; } +void PeopleHandler::HandleGetProfileInfo(const base::ListValue* args) { + std::string name; + std::string icon_url; + GetAccountNameAndIcon(*profile_, &name, &icon_url); + + web_ui()->CallJavascriptFunction("settings.SyncPrivateApi.receiveProfileInfo", + base::StringValue(name), + base::StringValue(icon_url)); +} + void PeopleHandler::HandleConfigure(const base::ListValue* args) { DCHECK(!sync_startup_tracker_); std::string json; @@ -765,6 +783,17 @@ UpdateSyncState(); } +void PeopleHandler::OnProfileNameChanged( + const base::FilePath& /* profile_path */, + const base::string16& /* old_profile_name */) { + HandleGetProfileInfo(nullptr); +} + +void PeopleHandler::OnProfileAvatarChanged( + const base::FilePath& /* profile_path */) { + HandleGetProfileInfo(nullptr); +} + scoped_ptr<base::DictionaryValue> PeopleHandler::GetSyncStateDictionary() { // The items which are to be written into |sync_status| are also described in // chrome/browser/resources/options/browser_options.js in @typedef @@ -815,12 +844,6 @@ sync_status->SetBoolean("hasUnrecoverableError", service && service->HasUnrecoverableError()); - std::string name; - std::string icon_url; - GetAccountNameAndIcon(*profile_, &name, &icon_url); - sync_status->SetString("name", name); - sync_status->SetString("iconURL", icon_url); - return sync_status; }
diff --git a/chrome/browser/ui/webui/settings/people_handler.h b/chrome/browser/ui/webui/settings/people_handler.h index ac1ec58..016aa5f9 100644 --- a/chrome/browser/ui/webui/settings/people_handler.h +++ b/chrome/browser/ui/webui/settings/people_handler.h
@@ -13,6 +13,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/timer/timer.h" #include "build/build_config.h" +#include "chrome/browser/profiles/profile_info_cache_observer.h" #include "chrome/browser/sync/sync_startup_tracker.h" #include "chrome/browser/ui/webui/signin/login_ui_service.h" #include "components/signin/core/browser/signin_manager_base.h" @@ -38,7 +39,8 @@ public SigninManagerBase::Observer, public SyncStartupTracker::Observer, public LoginUIService::LoginUI, - public sync_driver::SyncServiceObserver { + public sync_driver::SyncServiceObserver, + public ProfileInfoCacheObserver { public: explicit PeopleHandler(Profile* profile); ~PeopleHandler() override; @@ -64,6 +66,11 @@ // sync_driver::SyncServiceObserver implementation. void OnStateChanged() override; + // ProfileInfoCacheObserver implementation. + void OnProfileNameChanged(const base::FilePath& profile_path, + const base::string16& old_profile_name) override; + void OnProfileAvatarChanged(const base::FilePath& profile_path) override; + // Initializes the sync setup flow and shows the setup UI. void OpenSyncSetup(const base::ListValue* args); @@ -118,6 +125,7 @@ private: // Callbacks from the page. + void HandleGetProfileInfo(const base::ListValue* args); void OnDidClosePage(const base::ListValue* args); void HandleConfigure(const base::ListValue* args); void HandlePassphraseEntry(const base::ListValue* args);
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc index 3be38c6b..48db8c87 100644 --- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -27,9 +27,11 @@ #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/testing_profile_manager.h" #include "components/signin/core/browser/fake_auth_status_provider.h" #include "components/signin/core/browser/signin_manager.h" #include "components/sync_driver/sync_prefs.h" +#include "components/syncable_prefs/pref_service_syncable.h" #include "content/public/browser/web_ui.h" #include "content/public/test/test_browser_thread.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -185,21 +187,27 @@ void SetUp() override { error_ = GoogleServiceAuthError::AuthErrorNone(); - TestingProfile::Builder builder; - builder.AddTestingFactory(SigninManagerFactory::GetInstance(), - BuildFakeSigninManagerBase); - profile_ = builder.Build(); + profile_manager_.reset( + new TestingProfileManager(TestingBrowserProcess::GetGlobal())); + ASSERT_TRUE(profile_manager_->SetUp()); + + TestingProfile::TestingFactories testing_factories; + testing_factories.push_back(std::make_pair( + SigninManagerFactory::GetInstance(), BuildFakeSigninManagerBase)); + profile_ = profile_manager_->CreateTestingProfile( + "Person 1", nullptr, base::UTF8ToUTF16("Person 1"), 0, std::string(), + testing_factories); // Sign in the user. mock_signin_ = static_cast<SigninManagerBase*>( - SigninManagerFactory::GetForProfile(profile_.get())); + SigninManagerFactory::GetForProfile(profile_)); std::string username = GetTestUser(); if (!username.empty()) mock_signin_->SetAuthenticatedAccountInfo(username, username); mock_pss_ = static_cast<ProfileSyncServiceMock*>( ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile_.get(), BuildMockProfileSyncService)); + profile_, BuildMockProfileSyncService)); EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_)); ON_CALL(*mock_pss_, GetPassphraseType()).WillByDefault( Return(syncer::IMPLICIT_PASSPHRASE)); @@ -210,7 +218,7 @@ mock_pss_->Initialize(); - handler_.reset(new TestingPeopleHandler(&web_ui_, profile_.get())); + handler_.reset(new TestingPeopleHandler(&web_ui_, profile_)); } // Setup the expectations for calls made when displaying the config page. @@ -270,7 +278,7 @@ handler_->CloseSyncSetup(); EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); } // It's difficult to notify sync listeners when using a ProfileSyncServiceMock @@ -286,7 +294,8 @@ } content::TestBrowserThreadBundle thread_bundle_; - scoped_ptr<Profile> profile_; + scoped_ptr<TestingProfileManager> profile_manager_; + Profile* profile_; ProfileSyncServiceMock* mock_pss_; GoogleServiceAuthError error_; SigninManagerBase* mock_signin_; @@ -314,14 +323,14 @@ // Sync setup hands off control to the gaia login tab. EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); ASSERT_FALSE(handler_->is_configuring_sync()); handler_->CloseSyncSetup(); EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); } TEST_F(PeopleHandlerTest, ShowSyncSetupWhenNotSignedIn) { @@ -338,7 +347,7 @@ ASSERT_FALSE(handler_->is_configuring_sync()); EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); } #endif // !defined(OS_CHROMEOS) @@ -351,7 +360,7 @@ // Sync setup is closed when sync is disabled. EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); ASSERT_FALSE(handler_->is_configuring_sync()); } @@ -373,7 +382,7 @@ EXPECT_EQ(handler_.get(), LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); ExpectSpinnerAndClose(); } @@ -450,7 +459,7 @@ handler_->CloseSyncSetup(); EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); } TEST_F(PeopleHandlerTest, @@ -476,7 +485,7 @@ // On failure, the dialog will be closed. EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); } #if !defined(OS_CHROMEOS) @@ -757,7 +766,7 @@ SetupInitializedProfileSyncService(); mock_signin_->SetAuthenticatedAccountInfo(kTestUser, kTestUser); FakeAuthStatusProvider provider( - SigninErrorControllerFactory::GetForProfile(profile_.get())); + SigninErrorControllerFactory::GetForProfile(profile_)); provider.SetAuthError(kTestUser, error_); EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true)); EXPECT_CALL(*mock_pss_, IsPassphraseRequired()) @@ -773,7 +782,7 @@ // clicking on the button in the UI will sign the user out rather than // displaying a spinner. Should be no visible UI on ChromeOS in this case. EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); #else // On ChromeOS, this should display the spinner while we try to startup the @@ -783,7 +792,7 @@ // Sync setup is closed when re-auth is in progress. EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile( - profile_.get())->current_login_ui()); + profile_)->current_login_ui()); ASSERT_FALSE(handler_->is_configuring_sync()); #endif @@ -862,7 +871,7 @@ ExpectConfig(); // Close the config overlay. - LoginUIServiceFactory::GetForProfile(profile_.get())->LoginUIClosed( + LoginUIServiceFactory::GetForProfile(profile_)->LoginUIClosed( handler_.get()); const content::TestWebUI::CallData& data = *web_ui_.call_data()[0]; const base::DictionaryValue* dictionary = nullptr;
diff --git a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc new file mode 100644 index 0000000..a530704 --- /dev/null +++ b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc
@@ -0,0 +1,260 @@ +// 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/webui/settings/settings_manage_profile_handler.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/prefs/pref_service.h" +#include "base/prefs/scoped_user_pref_update.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/value_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/profiles/gaia_info_update_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_avatar_icon_util.h" +#include "chrome/browser/profiles/profile_info_cache.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/profiles/profile_metrics.h" +#include "chrome/browser/profiles/profile_shortcut_manager.h" +#include "chrome/browser/profiles/profile_window.h" +#include "chrome/browser/profiles/profiles_state.h" +#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/webui/options/options_handlers_helper.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "components/signin/core/browser/signin_manager.h" +#include "components/signin/core/common/profile_management_switches.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/web_ui.h" +#include "google_apis/gaia/gaia_auth_util.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/webui/web_ui_util.h" + +namespace settings { + +ManageProfileHandler::ManageProfileHandler(Profile* profile) + : profile_(profile), weak_factory_(this) { + g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this); +} + +ManageProfileHandler::~ManageProfileHandler() { + g_browser_process->profile_manager()-> + GetProfileInfoCache().RemoveObserver(this); +} + +void ManageProfileHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback("setProfileIconAndName", + base::Bind(&ManageProfileHandler::SetProfileIconAndName, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("requestDefaultProfileIcons", + base::Bind(&ManageProfileHandler::RequestDefaultProfileIcons, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("requestHasProfileShortcuts", + base::Bind(&ManageProfileHandler::RequestHasProfileShortcuts, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("profileIconSelectionChanged", + base::Bind(&ManageProfileHandler::ProfileIconSelectionChanged, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("addProfileShortcut", + base::Bind(&ManageProfileHandler::AddProfileShortcut, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("removeProfileShortcut", + base::Bind(&ManageProfileHandler::RemoveProfileShortcut, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("refreshGaiaPicture", + base::Bind(&ManageProfileHandler::RefreshGaiaPicture, + base::Unretained(this))); +} + +void ManageProfileHandler::OnProfileNameChanged( + const base::FilePath& profile_path, + const base::string16& old_profile_name) { + SendAvailableIcons(); +} + +void ManageProfileHandler::OnProfileAvatarChanged( + const base::FilePath& profile_path) { + SendAvailableIcons(); +} + +void ManageProfileHandler::RequestDefaultProfileIcons( + const base::ListValue* args) { + SendAvailableIcons(); +} + +void ManageProfileHandler::SendAvailableIcons() { + base::ListValue image_url_list; + const ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + + // First add the GAIA picture if it is available. + size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); + if (profile_index != std::string::npos) { + const gfx::Image* icon = + cache.GetGAIAPictureOfProfileAtIndex(profile_index); + if (icon) { + gfx::Image icon2 = profiles::GetAvatarIconForWebUI(*icon, true); + gaia_picture_url_ = webui::GetBitmapDataUrl(icon2.AsBitmap()); + image_url_list.AppendString(gaia_picture_url_); + } + } + + // Next add the default avatar icons and names. + for (size_t i = 0; i < profiles::GetDefaultAvatarIconCount(); i++) { + std::string url = profiles::GetDefaultAvatarIconUrl(i); + image_url_list.AppendString(url); + } + + web_ui()->CallJavascriptFunction( + "settings.SyncPrivateApi.receiveAvailableIcons", + image_url_list); +} + +void ManageProfileHandler::SetProfileIconAndName(const base::ListValue* args) { + DCHECK(args); + + std::string icon_url; + if (!args->GetString(0, &icon_url)) + return; + + PrefService* pref_service = profile_->GetPrefs(); + // Updating the profile preferences will cause the cache to be updated. + + // Metrics logging variable. + bool previously_using_gaia_icon = + pref_service->GetBoolean(prefs::kProfileUsingGAIAAvatar); + + size_t new_icon_index; + if (icon_url == gaia_picture_url_) { + pref_service->SetBoolean(prefs::kProfileUsingDefaultAvatar, false); + pref_service->SetBoolean(prefs::kProfileUsingGAIAAvatar, true); + if (!previously_using_gaia_icon) { + // Only log if they changed to the GAIA photo. + // Selection of GAIA photo as avatar is logged as part of the function + // below. + ProfileMetrics::LogProfileSwitchGaia(ProfileMetrics::GAIA_OPT_IN); + } + } else if (profiles::IsDefaultAvatarIconUrl(icon_url, &new_icon_index)) { + ProfileMetrics::LogProfileAvatarSelection(new_icon_index); + pref_service->SetInteger(prefs::kProfileAvatarIndex, new_icon_index); + pref_service->SetBoolean(prefs::kProfileUsingDefaultAvatar, false); + pref_service->SetBoolean(prefs::kProfileUsingGAIAAvatar, false); + } else { + // Only default avatars and Gaia account photos are supported. + CHECK(false); + } + ProfileMetrics::LogProfileUpdate(profile_->GetPath()); + + if (profile_->IsLegacySupervised()) + return; + + base::string16 new_profile_name; + if (!args->GetString(1, &new_profile_name)) + return; + + base::TrimWhitespace(new_profile_name, base::TRIM_ALL, &new_profile_name); + CHECK(!new_profile_name.empty()); + profiles::UpdateProfileName(profile_, new_profile_name); +} + +void ManageProfileHandler::ProfileIconSelectionChanged( + const base::ListValue* args) { + DCHECK(args); + + std::string icon_url; + if (!args->GetString(0, &icon_url)) + return; + + if (icon_url != gaia_picture_url_) + return; + + // If the selection is the GAIA picture then also show the profile name in the + // text field. This will display either the GAIA given name, if available, + // or the first name. + ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); + if (profile_index == std::string::npos) + return; + base::string16 gaia_name = cache.GetNameOfProfileAtIndex(profile_index); + if (gaia_name.empty()) + return; + + base::StringValue gaia_name_value(gaia_name); + web_ui()->CallJavascriptFunction( + "settings.SyncPrivateApi.setProfileName", + gaia_name_value); +} + +void ManageProfileHandler::RequestHasProfileShortcuts( + const base::ListValue* args) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(ProfileShortcutManager::IsFeatureEnabled()); + + const ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath()); + if (profile_index == std::string::npos) + return; + + // Don't show the add/remove desktop shortcut button in the single user case. + if (cache.GetNumberOfProfiles() <= 1) + return; + + const base::FilePath profile_path = + cache.GetPathOfProfileAtIndex(profile_index); + ProfileShortcutManager* shortcut_manager = + g_browser_process->profile_manager()->profile_shortcut_manager(); + shortcut_manager->HasProfileShortcuts( + profile_path, base::Bind(&ManageProfileHandler::OnHasProfileShortcuts, + weak_factory_.GetWeakPtr())); +} + +void ManageProfileHandler::OnHasProfileShortcuts(bool has_shortcuts) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + const base::FundamentalValue has_shortcuts_value(has_shortcuts); + web_ui()->CallJavascriptFunction( + "settings.SyncPrivateApi.receiveHasProfileShortcuts", + has_shortcuts_value); +} + +void ManageProfileHandler::AddProfileShortcut(const base::ListValue* args) { + DCHECK(ProfileShortcutManager::IsFeatureEnabled()); + ProfileShortcutManager* shortcut_manager = + g_browser_process->profile_manager()->profile_shortcut_manager(); + DCHECK(shortcut_manager); + + shortcut_manager->CreateProfileShortcut(profile_->GetPath()); + + // Update the UI buttons. + OnHasProfileShortcuts(true); +} + +void ManageProfileHandler::RemoveProfileShortcut(const base::ListValue* args) { + DCHECK(ProfileShortcutManager::IsFeatureEnabled()); + ProfileShortcutManager* shortcut_manager = + g_browser_process->profile_manager()->profile_shortcut_manager(); + DCHECK(shortcut_manager); + + shortcut_manager->RemoveProfileShortcuts(profile_->GetPath()); + + // Update the UI buttons. + OnHasProfileShortcuts(false); +} + +void ManageProfileHandler::RefreshGaiaPicture(const base::ListValue* args) { + profiles::UpdateGaiaProfileInfoIfNeeded(Profile::FromWebUI(web_ui())); +} + +} // namespace settings
diff --git a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h new file mode 100644 index 0000000..11f250eb --- /dev/null +++ b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h
@@ -0,0 +1,97 @@ +// 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_WEBUI_SETTINGS_SETTINGS_MANAGE_PROFILE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_MANAGE_PROFILE_HANDLER_H_ + +#include <string> + +#include "base/memory/weak_ptr.h" +#include "chrome/browser/profiles/profile_info_cache_observer.h" +#include "chrome/browser/ui/webui/settings/md_settings_ui.h" + +namespace base { +class StringValue; +} + +class Profile; + +namespace settings { + +// Chrome personal stuff profiles manage overlay UI handler. +class ManageProfileHandler : public settings::SettingsPageUIHandler, + public ProfileInfoCacheObserver { + public: + explicit ManageProfileHandler(Profile* profile); + ~ManageProfileHandler() override; + + // settings::SettingsPageUIHandler: + void RegisterMessages() override; + + // ProfileInfoCacheObserver: + void OnProfileNameChanged(const base::FilePath& profile_path, + const base::string16& old_profile_name) override; + void OnProfileAvatarChanged(const base::FilePath& profile_path) override; + + private: + // Callback for the "requestDefaultProfileIcons" message. + // Sends the array of default profile icon URLs and profile names to WebUI. + // First item of |args| is the dialog mode, i.e. "create" or "manage". + void RequestDefaultProfileIcons(const base::ListValue* args); + + // Send all the available profile icons to choose from. + void SendAvailableIcons(); + + // Callback for the "setProfileIconAndName" message. Sets the name and icon + // of a given profile. + // |args| is of the form: [ + // /*string*/ profileFilePath, + // /*string*/ newProfileIconURL + // /*string*/ newProfileName, + // ] + void SetProfileIconAndName(const base::ListValue* args); + + // Callback for the 'profileIconSelectionChanged' message. Used to update the + // name in the manager profile dialog based on the selected icon. + void ProfileIconSelectionChanged(const base::ListValue* args); + + // Callback for the "requestHasProfileShortcuts" message, which is called + // when editing an existing profile. Asks the profile shortcut manager whether + // the profile has shortcuts and gets the result in |OnHasProfileShortcuts()|. + // |args| is of the form: [ {string} profileFilePath ] + void RequestHasProfileShortcuts(const base::ListValue* args); + + // Callback invoked from the profile manager indicating whether the profile + // being edited has any desktop shortcuts. + void OnHasProfileShortcuts(bool has_shortcuts); + + // Callback for the "addProfileShortcut" message, which is called when editing + // an existing profile and the user clicks the "Add desktop shortcut" button. + // Adds a desktop shortcut for the profile. + void AddProfileShortcut(const base::ListValue* args); + + // Callback for the "removeProfileShortcut" message, which is called when + // editing an existing profile and the user clicks the "Remove desktop + // shortcut" button. Removes the desktop shortcut for the profile. + void RemoveProfileShortcut(const base::ListValue* args); + + // Callback for the "refreshGaiaPicture" message, which is called when the + // user is editing an existing profile. + void RefreshGaiaPicture(const base::ListValue* args); + + // Non-owning pointer to the associated profile. + Profile* profile_; + + // URL for the current profile's GAIA picture. + std::string gaia_picture_url_; + + // For generating weak pointers to itself for callbacks. + base::WeakPtrFactory<ManageProfileHandler> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ManageProfileHandler); +}; + +} // namespace settings + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_MANAGE_PROFILE_HANDLER_H_
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index d8c21a9b..6beaddd 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp
@@ -773,41 +773,5 @@ }, ], }], - ['kasko==1', { - 'variables': { - 'kasko_exe_dir': '<(DEPTH)/third_party/kasko', - }, - 'targets': [ - { - 'target_name': 'kasko_dll', - 'type': 'none', - 'outputs': [ - '<(PRODUCT_DIR)/kasko.dll', - '<(PRODUCT_DIR)/kasko.dll.pdb', - ], - 'copies': [ - { - 'destination': '<(PRODUCT_DIR)', - 'files': [ - '<(kasko_exe_dir)/kasko.dll', - '<(kasko_exe_dir)/kasko.dll.pdb', - ], - }, - ], - 'direct_dependent_settings': { - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalDependencies': [ - 'kasko.dll.lib', - ], - 'AdditionalLibraryDirectories': [ - '<(DEPTH)/third_party/kasko' - ], - }, - }, - }, - }, - ], - }], ], # 'conditions' }
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index c402751..cf84c644 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi
@@ -1917,7 +1917,7 @@ 'android/java/src/org/chromium/chrome/browser/WebContentsFactory.java', 'android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java', 'android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java', - 'android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java', + 'android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java', 'android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBarDelegate.java', 'android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java', 'android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java', @@ -3816,24 +3816,18 @@ '../google_update/google_update.gyp:google_update', '../third_party/iaccessible2/iaccessible2.gyp:iaccessible2', '../third_party/isimpledom/isimpledom.gyp:isimpledom', + '../third_party/kasko/kasko.gyp:kasko', '../ui/metro_viewer/metro_viewer.gyp:metro_viewer_messages', '../ui/views/controls/webview/webview.gyp:webview', '../ui/views/views.gyp:views', '../win8/win8.gyp:metro_viewer', ], 'export_dependent_settings': [ + '../third_party/kasko/kasko.gyp:kasko', '../ui/views/controls/webview/webview.gyp:webview', '../ui/views/views.gyp:views', ], 'conditions': [ - ['kasko==1', { - 'dependencies': [ - 'kasko_dll', - ], - 'export_dependent_settings': [ - 'kasko_dll', - ], - }], ['branding!="Chrome"', { 'dependencies!': [ '../google_update/google_update.gyp:google_update',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index bb04718..4b53e86 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -1996,6 +1996,8 @@ 'browser/ui/webui/settings/settings_clear_browsing_data_handler.h', 'browser/ui/webui/settings/settings_default_browser_handler.cc', 'browser/ui/webui/settings/settings_default_browser_handler.h', + 'browser/ui/webui/settings/settings_manage_profile_handler.cc', + 'browser/ui/webui/settings/settings_manage_profile_handler.h', 'browser/ui/webui/settings/settings_startup_pages_handler.cc', 'browser/ui/webui/settings/settings_startup_pages_handler.h', 'browser/ui/webui/signin/inline_login_handler.cc',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index cbf6331e..bac564e 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi
@@ -352,6 +352,7 @@ '<(DEPTH)/skia/skia.gyp:skia_library', '<(DEPTH)/third_party/icu/icu.gyp:icui18n', '<(DEPTH)/third_party/icu/icu.gyp:icuuc', + '<(DEPTH)/third_party/kasko/kasko.gyp:kasko_features', '<(DEPTH)/third_party/zlib/google/zip.gyp:zip', '<(DEPTH)/ui/gfx/ipc/gfx_ipc.gyp:gfx_ipc', '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources',
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index b6e7634b..a0aa2c1 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi
@@ -351,6 +351,7 @@ '<@(chromium_child_dependencies)', '../components/components.gyp:browser_watcher_client', '../content/content.gyp:content_app_child', + '../third_party/kasko/kasko.gyp:kasko', 'chrome_version_resources', 'policy_path_parser', ],
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi index 4cec0e7a..fda73bc 100644 --- a/chrome/chrome_exe.gypi +++ b/chrome/chrome_exe.gypi
@@ -105,20 +105,13 @@ '../components/components.gyp:browser_watcher_client', '../components/components.gyp:crash_component', '../third_party/crashpad/crashpad/handler/handler.gyp:crashpad_handler_lib', + '../third_party/kasko/kasko.gyp:kasko', ], 'sources': [ 'app/chrome_crash_reporter_client.cc', 'app/chrome_crash_reporter_client.h', ], 'conditions': [ - ['kasko==1', { - 'dependencies': [ - 'kasko_dll', - ], - 'sources': [ - 'app/chrome_crash_reporter_client.cc', - ], - }], ['win_console_app==1', { 'defines': ['WIN_CONSOLE_APP'], }], @@ -433,6 +426,7 @@ '../components/components.gyp:crash_core_common', '../components/components.gyp:flags_ui_switches', '../sandbox/sandbox.gyp:sandbox', + '../third_party/kasko/kasko.gyp:kasko_features', '../ui/gfx/gfx.gyp:gfx', '../win8/metro_driver/metro_driver.gyp:metro_driver', '../win8/delegate_execute/delegate_execute.gyp:*',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 1851588..5fbadac 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi
@@ -242,6 +242,8 @@ 'browser/extensions/extension_icon_source_apitest.cc', 'browser/extensions/extension_incognito_apitest.cc', 'browser/extensions/extension_install_prompt_browsertest.cc', + 'browser/extensions/extension_install_prompt_test_helper.cc', + 'browser/extensions/extension_install_prompt_test_helper.h', 'browser/extensions/extension_install_ui_browsertest.cc', 'browser/extensions/extension_javascript_url_apitest.cc', 'browser/extensions/extension_loading_browsertest.cc', @@ -993,6 +995,7 @@ 'test/data/webui/settings/basic_page_browsertest.js', 'test/data/webui/settings/bluetooth_page_browsertest_chromeos.js', 'test/data/webui/settings/cr_settings_browsertest.js', + 'test/data/webui/settings/on_startup_browsertest.js', 'test/data/webui/settings/settings_page_browsertest.js', 'test/data/webui/settings/settings_passwords_section_browsertest.js', 'test/data/webui/settings/settings_subpage_browsertest.js',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 19f47ce..8f775f7 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -461,6 +461,7 @@ 'browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api_unittest.cc', 'browser/extensions/api/storage/settings_sync_unittest.cc', 'browser/extensions/api/streams_private/streams_private_manifest_unittest.cc', + 'browser/extensions/api/tabs/tabs_api_unittest.cc', 'browser/extensions/api/web_navigation/frame_navigation_state_unittest.cc', 'browser/extensions/api/web_request/web_request_api_unittest.cc', 'browser/extensions/api/web_request/web_request_permissions_unittest.cc', @@ -2889,6 +2890,7 @@ '../components/components.gyp:crash_core_common', '../components/components.gyp:flags_ui_switches', '../content/content.gyp:content_app_both', + '../third_party/kasko/kasko.gyp:kasko_features', # 2) test-specific support libraries: '../base/base.gyp:run_all_unittests', '../testing/gmock.gyp:gmock',
diff --git a/chrome/chrome_watcher/DEPS b/chrome/chrome_watcher/DEPS index d7f54021..7bc4be61 100644 --- a/chrome/chrome_watcher/DEPS +++ b/chrome/chrome_watcher/DEPS
@@ -3,4 +3,5 @@ "+chrome/installer/util", "+components/browser_watcher", "+syzygy/kasko/api", + "+third_party/kasko", ]
diff --git a/chrome/chrome_watcher/chrome_watcher.gypi b/chrome/chrome_watcher/chrome_watcher.gypi index 9836501..f676a267 100644 --- a/chrome/chrome_watcher/chrome_watcher.gypi +++ b/chrome/chrome_watcher/chrome_watcher.gypi
@@ -64,13 +64,7 @@ 'installer_util', '../base/base.gyp:base', '../components/components.gyp:browser_watcher', - ], - 'conditions': [ - ['kasko==1', { - 'dependencies': [ - 'kasko_dll', - ], - }], + '../third_party/kasko/kasko.gyp:kasko', ], 'msvs_settings': { 'VCLinkerTool': {
diff --git a/chrome/chrome_watcher/chrome_watcher_main.cc b/chrome/chrome_watcher/chrome_watcher_main.cc index 01e916b..e28de01 100644 --- a/chrome/chrome_watcher/chrome_watcher_main.cc +++ b/chrome/chrome_watcher/chrome_watcher_main.cc
@@ -37,8 +37,9 @@ #include "components/browser_watcher/endsession_watcher_window_win.h" #include "components/browser_watcher/exit_code_watcher_win.h" #include "components/browser_watcher/window_hang_monitor_win.h" +#include "third_party/kasko/kasko_features.h" -#ifdef KASKO +#if BUILDFLAG(ENABLE_KASKO) #include "syzygy/kasko/api/reporter.h" #endif @@ -194,7 +195,7 @@ } } -#ifdef KASKO +#if BUILDFLAG(ENABLE_KASKO) // Helper function for determining the crash server to use. Defaults to the // standard crash server, but can be overridden via an environment variable. // Enables easy integration testing. @@ -342,7 +343,7 @@ // TODO(erikwright): Copy minidump to some "last dump" location? } -#endif // KASKO +#endif // BUILDFLAG(ENABLE_KASKO) } // namespace @@ -371,7 +372,7 @@ base::Callback<void(const base::Process&)> on_hung_callback; -#ifdef KASKO +#if BUILDFLAG(ENABLE_KASKO) base::string16 crash_server; GetKaskoCrashServerUrl(&crash_server); @@ -389,14 +390,14 @@ .value() .c_str(), &OnCrashReportUpload, nullptr); -#ifdef KASKO_HANG_REPORTS +#if BUILDFLAG(ENABLE_KASKO_HANG_REPORTS) if (launched_kasko && base::StringPiece16(channel_name) == installer::kChromeChannelCanary) { on_hung_callback = base::Bind(&DumpHungBrowserProcess, main_thread_id, channel_name); } -#endif // KASKO_HANG_REPORTS -#endif // KASKO +#endif // BUILDFLAG(ENABLE_KASKO_HANG_REPORTS) +#endif // BUILDFLAG(ENABLE_KASKO) // Run a UI message loop on the main thread. base::MessageLoop msg_loop(base::MessageLoop::TYPE_UI); @@ -420,10 +421,10 @@ run_loop.Run(); } -#ifdef KASKO +#if BUILDFLAG(ENABLE_KASKO) if (launched_kasko) kasko::api::ShutdownReporter(); -#endif // KASKO +#endif // BUILDFLAG(ENABLE_KASKO) // Wind logging down. logging::LogEventProvider::Uninitialize();
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index df5e371..61c533f 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -102,6 +102,7 @@ "//net", "//skia", "//third_party/icu", + "//third_party/kasko:kasko_features", "//third_party/zlib:zip", "//ui/accessibility", "//ui/base",
diff --git a/chrome/common/DEPS b/chrome/common/DEPS index d45be945..84bf958 100644 --- a/chrome/common/DEPS +++ b/chrome/common/DEPS
@@ -32,6 +32,7 @@ "+ppapi/c", "+ppapi/shared_impl", "+ppapi/thunk", + "+third_party/kasko", # FIXME - refactor code and remove these dependencies "+chrome/installer",
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc index bdef33f3..22543051 100644 --- a/chrome/common/crash_keys.cc +++ b/chrome/common/crash_keys.cc
@@ -76,7 +76,7 @@ } // namespace mac #endif -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) const char kKaskoGuid[] = "kasko-guid"; const char kKaskoEquivalentGuid[] = "kasko-equivalent-guid"; #endif @@ -141,7 +141,7 @@ // media/: { "VideoCaptureDeviceQTKit", kSmallSize }, #endif -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) { kKaskoGuid, kSmallSize }, { kKaskoEquivalentGuid, kSmallSize }, #endif
diff --git a/chrome/common/crash_keys.h b/chrome/common/crash_keys.h index 01219e466..335b8d3 100644 --- a/chrome/common/crash_keys.h +++ b/chrome/common/crash_keys.h
@@ -15,6 +15,7 @@ #include "base/macros.h" #include "build/build_config.h" #include "components/crash/core/common/crash_keys.h" +#include "third_party/kasko/kasko_features.h" namespace base { class CommandLine; @@ -118,7 +119,7 @@ } // namespace mac #endif -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) // Used to correlate a report sent via Kasko with one sent via Breakpad. extern const char kKaskoGuid[]; extern const char kKaskoEquivalentGuid[];
diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl index 882c7db..564b1cb 100644 --- a/chrome/common/extensions/api/developer_private.idl +++ b/chrome/common/extensions/api/developer_private.idl
@@ -62,14 +62,14 @@ enum ViewType { APP_WINDOW, BACKGROUND_CONTENTS, + COMPONENT, EXTENSION_BACKGROUND_PAGE, EXTENSION_DIALOG, EXTENSION_GUEST, EXTENSION_POPUP, LAUNCHER_PAGE, PANEL, - TAB_CONTENTS, - VIRTUAL_KEYBOARD + TAB_CONTENTS }; enum ErrorType {
diff --git a/chrome/renderer/page_load_histograms.cc b/chrome/renderer/page_load_histograms.cc index c854281..672875aa 100644 --- a/chrome/renderer/page_load_histograms.cc +++ b/chrome/renderer/page_load_histograms.cc
@@ -138,7 +138,7 @@ if (scheme_type & URLPattern::SCHEME_HTTPS) { \ if (!https_drp_counter) { \ https_drp_counter = base::Histogram::FactoryTimeGet( \ - std::string(name) + "_ HTTPS_DataReductionProxy", \ + std::string(name) + "_HTTPS_DataReductionProxy", \ kPLTMin(), kPLTMax(), kPLTCount, \ base::Histogram::kUmaTargetedHistogramFlag); \ } \
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index e8d2a0f..58b218b 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2154,6 +2154,7 @@ "//chrome/child", "//components/crash/core/common", "//components/flags_ui:switches", + "//third_party/kasko:kasko_features", ] if (cld_version == 2) { # Use whatever CLD2 data access mode that the
diff --git a/chrome/test/base/tracing_browsertest.cc b/chrome/test/base/tracing_browsertest.cc index 1b953594..38e2083 100644 --- a/chrome/test/base/tracing_browsertest.cc +++ b/chrome/test/base/tracing_browsertest.cc
@@ -153,13 +153,19 @@ ASSERT_TRUE(EndTracing(&json_events)); } +#if defined(OS_WIN) +#define MAYBE_TestMemoryInfra DISABLED_TestMemoryInfra +#else +#define MAYBE_TestMemoryInfra TestMemoryInfra +#endif + // Multi-process mode. -IN_PROC_BROWSER_TEST_F(TracingBrowserTest, TestMemoryInfra) { +IN_PROC_BROWSER_TEST_F(TracingBrowserTest, MAYBE_TestMemoryInfra) { PerformDumpMemoryTestActions(); } // Single-process mode. -IN_PROC_BROWSER_TEST_F(SingleProcessTracingBrowserTest, TestMemoryInfra) { +IN_PROC_BROWSER_TEST_F(SingleProcessTracingBrowserTest, MAYBE_TestMemoryInfra) { PerformDumpMemoryTestActions(); }
diff --git a/chrome/test/data/extensions/api_test/content_scripts/about_blank_srcdoc/manifest.json b/chrome/test/data/extensions/api_test/content_scripts/about_blank_srcdoc/manifest.json index 87891fb..f2966dd 100644 --- a/chrome/test/data/extensions/api_test/content_scripts/about_blank_srcdoc/manifest.json +++ b/chrome/test/data/extensions/api_test/content_scripts/about_blank_srcdoc/manifest.json
@@ -14,5 +14,6 @@ "js": ["content_script.js"], "all_frames": true } - ] + ], + "permissions": ["tabs"] }
diff --git a/chrome/test/data/extensions/api_test/service_worker/background/background.js b/chrome/test/data/extensions/api_test/service_worker/background/background.js index d1102c8..5a37ce5 100644 --- a/chrome/test/data/extensions/api_test/service_worker/background/background.js +++ b/chrome/test/data/extensions/api_test/service_worker/background/background.js
@@ -47,3 +47,7 @@ }; }); }; + +chrome.runtime.onMessage.addListener(function(msg, _, sendResponse) { + sendResponse({label: 'onMessage/original BG.'}); +});
diff --git a/chrome/test/data/extensions/api_test/service_worker/background/page.html b/chrome/test/data/extensions/api_test/service_worker/background/page.html new file mode 100644 index 0000000..91aec47 --- /dev/null +++ b/chrome/test/data/extensions/api_test/service_worker/background/page.html
@@ -0,0 +1,2 @@ +<!doctype html> +<script src="page.js"></script>
diff --git a/chrome/test/data/extensions/api_test/service_worker/background/page.js b/chrome/test/data/extensions/api_test/service_worker/background/page.js new file mode 100644 index 0000000..7bd53d9 --- /dev/null +++ b/chrome/test/data/extensions/api_test/service_worker/background/page.js
@@ -0,0 +1,7 @@ +// 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. + +chrome.runtime.sendMessage({sourceCheck: true}, function(e) { + chrome.test.sendMessage(e.label); +});
diff --git a/chrome/test/data/extensions/api_test/service_worker/background/replace_background.js b/chrome/test/data/extensions/api_test/service_worker/background/replace_background.js new file mode 100644 index 0000000..23ca1c8b --- /dev/null +++ b/chrome/test/data/extensions/api_test/service_worker/background/replace_background.js
@@ -0,0 +1,20 @@ +// 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. + +'use strict'; + +var backgroundJS = + 'chrome.runtime.onMessage.addListener(function(msg, _, sendResponse) {' + + ' if (msg.sourceCheck) {' + + ' sendResponse({label: "onMessage/SW BG."});' + + ' }' + + '});'; + +self.onfetch = function(e) { + let requestUrl = new URL(e.request.url); + if (requestUrl.pathname == '/background.js') { + e.respondWith(new Response(backgroundJS)); + } +}; +
diff --git a/chrome/test/data/webui/media_router/media_router_elements_browsertest.js b/chrome/test/data/webui/media_router/media_router_elements_browsertest.js index 799315e2..47d7986 100644 --- a/chrome/test/data/webui/media_router/media_router_elements_browsertest.js +++ b/chrome/test/data/webui/media_router/media_router_elements_browsertest.js
@@ -35,16 +35,6 @@ 'media_router_header_tests.js', 'route_details_tests.js', ]), - - /** @override */ - setUp: function() { - PolymerTest.prototype.setUp.call(this); - - // TODO(apacible): Enable when false positive AX_FOCUS_01 bug is fixed. - // https://github.com/GoogleChrome/accessibility-developer-tools/issues/171 - this.accessibilityAuditConfig.auditRulesToIgnore.push( - 'focusableElementNotVisibleAndNotAriaHidden'); - }, }; // Runs all tests.
diff --git a/chrome/test/data/webui/settings/on_startup_browsertest.js b/chrome/test/data/webui/settings/on_startup_browsertest.js new file mode 100644 index 0000000..04882f8 --- /dev/null +++ b/chrome/test/data/webui/settings/on_startup_browsertest.js
@@ -0,0 +1,91 @@ +// 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. + +/** @fileoverview Runs Polymer OnStartup Settings tests. */ + +GEN_INCLUDE(['settings_page_browsertest.js']); + +/** + * Radio button enum values for restore on startup. + * @enum + */ +var RestoreOnStartupEnum = { + CONTINUE: 1, + OPEN_NEW_TAB: 5, + OPEN_SPECIFIC: 4, +}; + +/** + * Test Polymer On Startup Settings elements. + * @constructor + * @extends {SettingsPageBrowserTest} +*/ +function OnStartupSettingsBrowserTest() {} + +OnStartupSettingsBrowserTest.prototype = { + __proto__: SettingsPageBrowserTest.prototype, + + /** @return {Element} */ + getPageElement: function(selector) { + var section = this.getSection(this.getPage('basic'), 'onStartup'); + assertTrue(!!section); + var module = section.querySelector('settings-on-startup-page'); + assertTrue(!!module); + var result = module.$$(selector); + assertTrue(!!result); + return result; + }, +}; + +TEST_F('OnStartupSettingsBrowserTest', 'uiTests', function() { + /** + * The prefs API that will get a fake implementation. + * @type {!SettingsPrivate} + */ + var settingsPrefs; + var self = this; + + var restoreOnStartup = function() { + return self.getPageElement('#onStartupRadioGroup').querySelector( + '.iron-selected').textContent.trim(); + }; + + suite('OnStartupHandler', function() { + var fakePrefs = [{ + key: 'session.restore_on_startup', + type: chrome.settingsPrivate.PrefType.NUMBER, + value: 1234, + }]; + + suiteSetup(function() { + settingsPrefs = document.querySelector('cr-settings').$$( + 'settings-prefs'); + assertTrue(!!settingsPrefs); + CrSettingsPrefs.resetForTesting(); + settingsPrefs.resetForTesting(); + var fakeApi = new settings.FakeSettingsPrivate(fakePrefs); + settingsPrefs.initializeForTesting(fakeApi); + return CrSettingsPrefs.initialized; + }); + + test('open-continue', function() { + settingsPrefs.set('prefs.session.restore_on_startup.value', + RestoreOnStartupEnum.CONTINUE); + assertEquals('Continue where you left off', restoreOnStartup()); + }); + + test('open-ntp', function() { + settingsPrefs.set('prefs.session.restore_on_startup.value', + RestoreOnStartupEnum.OPEN_NEW_TAB); + assertEquals('Open the New Tab page', restoreOnStartup()); + }); + + test('open-specific', function() { + settingsPrefs.set('prefs.session.restore_on_startup.value', + RestoreOnStartupEnum.OPEN_SPECIFIC); + assertEquals('Open a specific page or set of pages', restoreOnStartup()); + }); + }); + mocha.run(); +});
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index 1388bd76..672ec489 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp
@@ -210,6 +210,8 @@ 'disks/disk_mount_manager.h', 'disks/suspend_unmount_manager.cc', 'disks/suspend_unmount_manager.h', + 'hugepage_text/hugepage_text.cc', + 'hugepage_text/hugepage_text.h', 'geolocation/geoposition.cc', 'geolocation/geoposition.h', 'geolocation/simple_geolocation_provider.cc',
diff --git a/chromeos/hugepage_text/OWNERS b/chromeos/hugepage_text/OWNERS new file mode 100644 index 0000000..7e39036 --- /dev/null +++ b/chromeos/hugepage_text/OWNERS
@@ -0,0 +1,4 @@ +yunlian@chromium.org +llozano@chromium.org +shenhan@chromium.org +cmtice@chromium.org
diff --git a/chromeos/hugepage_text/hugepage_text.cc b/chromeos/hugepage_text/hugepage_text.cc new file mode 100644 index 0000000..a14a2d1c --- /dev/null +++ b/chromeos/hugepage_text/hugepage_text.cc
@@ -0,0 +1,220 @@ +// 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. +// Author: Ken Chen <kenchen@google.com> +// +// hugepage text library to remap process executable segment with hugepages. + +#include "chromeos/hugepage_text/hugepage_text.h" + +#include <link.h> +#include <sys/mman.h> + +#include "base/logging.h" + +namespace chromeos { + +#ifndef MAP_HUGETLB +#define MAP_HUGETLB 0x40000 +#endif + +#ifndef TMPFS_MAGIC +#define TMPFS_MAGIC 0x01021994 +#endif + +#ifndef MADV_HUGEPAGE +#define MADV_HUGEPAGE 14 +#endif + +const int kHpageShift = 21; +const int kHpageSize = (1 << kHpageShift); +const int kHpageMask = (~(kHpageSize - 1)); + +const int kProtection = (PROT_READ | PROT_WRITE); +const int kMmapFlags = (MAP_ANONYMOUS | MAP_SHARED); +const int kMmapHtlbFlags = (kMmapFlags | MAP_HUGETLB); +const int kMremapFlags = (MREMAP_MAYMOVE | MREMAP_FIXED); + +// The number of hugepages we want to use to map chrome text section +// to hugepages. With the help of AutoFDO, the hot functions are grouped +// in to a small area of the binary. +const int kNumHugePages = 15; + +// mremap syscall is always supported for small page segment on all kernels. +// However, it is not the case for hugepage. +// If not used carefully, mremap() a hugepage segment directly onto small page +// text segment will cause irreversible damage to the existing text mapping +// and cause process to segfault. This function will dynamically at run time +// determine whether a process can safely execute mremap on a hugepage segment +// without taking the process down. +// +// Inputs: none +// Return: true if mremap on hugepage segment is supported on the host OS. +static int HugetlbMremapSupported(void) { + void *haddr = 0, *raddr = 0, *taddr; + const size_t size = kHpageSize; + int ret = 0; + + // use a pair of hugepage memory segments to test whether mremap() is + // supported + haddr = mmap(NULL, size, kProtection, kMmapHtlbFlags | MAP_NORESERVE, 0, 0); + if (haddr == MAP_FAILED) { + return 0; + } + taddr = mmap(NULL, size, kProtection, kMmapHtlbFlags | MAP_NORESERVE, 0, 0); + if (taddr == MAP_FAILED) { + munmap(haddr, size); + return 0; + } + + raddr = mremap(haddr, size, size, kMremapFlags, taddr); + if (raddr != MAP_FAILED) { + ret = 1; + // clean up. raddr == taddr; also haddr is implicitly unmapped + munmap(raddr, size); + } else { + // mremap fail, clean up both src and dst segments + munmap(haddr, size); + munmap(taddr, size); + } + + return ret; +} + +// Get an anonymous mapping backed by explicit transparent hugepage +// Return NULL if such mapping can not be established. +static void* GetTransparentHugepageMapping(const size_t hsize) { + // setup explicit transparent hugepage segment + char* addr = static_cast<char*>(mmap(NULL, hsize + kHpageSize, kProtection, + MAP_ANONYMOUS | MAP_PRIVATE, 0, 0)); + if (addr == MAP_FAILED) { + PLOG(INFO) << "unable to mmap anon pages, fall back to small page"; + return NULL; + } + // remove unaligned head and tail regions + size_t head_gap = kHpageSize - (size_t)addr % kHpageSize; + size_t tail_gap = kHpageSize - head_gap; + munmap(addr, head_gap); + munmap(addr + head_gap + hsize, tail_gap); + + void* haddr = addr + head_gap; + if (madvise(haddr, hsize, MADV_HUGEPAGE)) { + PLOG(INFO) << "no transparent hugepage support, fall back to small page"; + munmap(haddr, hsize); + return NULL; + } + return haddr; +} + +// memcpy for word-aligned data which is not instrumented by AddressSanitizer. +ATTRIBUTE_NO_SANITIZE_ADDRESS +static void NoAsanAlignedMemcpy(void* dst, void* src, size_t size) { + DCHECK_EQ(0U, size % sizeof(uintptr_t)); // size is a multiple of word size. + DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(dst) % sizeof(uintptr_t)); + DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(src) % sizeof(uintptr_t)); + uintptr_t* d = reinterpret_cast<uintptr_t*>(dst); + uintptr_t* s = reinterpret_cast<uintptr_t*>(src); + for (size_t i = 0; i < size / sizeof(uintptr_t); i++) + d[i] = s[i]; +} + +// Remaps text segment at address "vaddr" to hugepage backed mapping via mremap +// syscall. The virtual address does not change. When this call returns, the +// backing physical memory will be changed from small page to hugetlb page. +// +// Inputs: vaddr, the starting virtual address to remap to hugepage +// hsize, size of the memory segment to remap in bytes +// Return: none +// Effect: physical backing page changed from small page to hugepage. If there +// are error condition, the remapping operation is aborted. +static void MremapHugetlbText(void* vaddr, const size_t hsize) { + void* haddr = MAP_FAILED; + + if ((reinterpret_cast<intptr_t>(vaddr) & ~kHpageMask) == 0 && + HugetlbMremapSupported()) { + // Try anon hugepage from static hugepage pool only if the source address + // is hugepage aligned, otherwise, mremap below has non-recoverable error. + haddr = mmap(NULL, hsize, kProtection, kMmapHtlbFlags, 0, 0); + } + + if (haddr == MAP_FAILED) { + PLOG(INFO) << "static hugepage not available, trying transparent hugepage"; + haddr = GetTransparentHugepageMapping(hsize); + if (haddr == NULL) + return; + } + + // Copy text segment to hugepage mapping. We are using a non-asan memcpy, + // otherwise it would be flagged as a bunch of out of bounds reads. + NoAsanAlignedMemcpy(haddr, vaddr, hsize); + + // change mapping protection to read only now that it has done the copy + if (mprotect(haddr, hsize, PROT_READ | PROT_EXEC)) { + PLOG(INFO) << "can not change protection to r-x, fall back to small page"; + munmap(haddr, hsize); + return; + } + + // remap hugepage text on top of existing small page mapping + if (mremap(haddr, hsize, hsize, kMremapFlags, vaddr) == MAP_FAILED) { + PLOG(INFO) << "unable to mremap hugepage mapping, fall back to small page"; + munmap(haddr, hsize); + return; + } +} + +// Top level text remapping function. +// +// Inputs: vaddr, the starting virtual address to remap to hugepage +// hsize, size of the memory segment to remap in bytes +// Return: none +// Effect: physical backing page changed from small page to hugepage. If there +// are error condition, the remaping operation is aborted. +static void RemapHugetlbText(void* vaddr, const size_t segsize) { + int hsize = segsize; + if (segsize > kHpageSize * kNumHugePages) + hsize = kHpageSize * kNumHugePages; + hsize = hsize & kHpageMask; + + if (hsize == 0) + return; + + MremapHugetlbText(vaddr, hsize); +} + +// For a given ELF program header descriptor, iterates over all segments within +// it and find the first segment that has PT_LOAD and is executable, call +// RemapHugetlbText(). +// +// Inputs: info: pointer to a struct dl_phdr_info that describes the DSO. +// size: size of the above structure (not used in this function). +// data: user param (not used in this function). +// Return: always return true. The value is propagated by dl_iterate_phdr(). +static int FilterElfHeader(struct dl_phdr_info* info, size_t size, void* data) { + void* vaddr; + int segsize; + + for (int i = 0; i < info->dlpi_phnum; i++) { + if (info->dlpi_phdr[i].p_type == PT_LOAD && + info->dlpi_phdr[i].p_flags == (PF_R | PF_X)) { + vaddr = bit_cast<void*>(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); + segsize = info->dlpi_phdr[i].p_filesz; + + RemapHugetlbText(vaddr, segsize); + // Only re-map the first text segment. + return 1; + } + } + + return 1; +} + +// Main library function. This function will iterate all ELF segments and +// attempt to remap text segment from small page to hugepage. +// If remapping is successful. All error conditions are soft fail such that +// effect will be rolled back and remap operation will be aborted. +void ReloadElfTextInHugePages(void) { + dl_iterate_phdr(FilterElfHeader, 0); +} + +} // namespace chromeos
diff --git a/chromeos/hugepage_text/hugepage_text.h b/chromeos/hugepage_text/hugepage_text.h new file mode 100644 index 0000000..801ac30 --- /dev/null +++ b/chromeos/hugepage_text/hugepage_text.h
@@ -0,0 +1,35 @@ +// 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. + +// Author: Ken Chen <kenchen@google.com> +// +// Library support to remap process executable elf segment with hugepages. +// +// ReloadElfTextInHugePages() will search for an ELF executable segment, +// and remap it using hugepage. + +#ifndef CHROMEOS_HUGEPAGE_TEXT_HUGEPAGE_TEXT_H_ +#define CHROMEOS_HUGEPAGE_TEXT_HUGEPAGE_TEXT_H_ + +#include <string> +#include "chromeos/chromeos_export.h" + +#if defined(__clang__) || defined(__GNUC__) +#define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) +#else +#define ATTRIBUTE_NO_SANITIZE_ADDRESS +#endif + +namespace chromeos { + +// This function will scan ELF +// segments and attempt to remap text segment from small page to hugepage. +// When this function returns, text segments that are naturally aligned on +// hugepage size will be backed by hugepages. In the event of errors, the +// remapping operation will be aborted and rolled back, e.g. they are all +// soft fail. +CHROMEOS_EXPORT extern void ReloadElfTextInHugePages(void); +} // namespace chromeos + +#endif // CHROMEOS_HUGEPAGE_TEXT_HUGEPAGE_TEXT_H_
diff --git a/chromeos/network/auto_connect_handler.cc b/chromeos/network/auto_connect_handler.cc index b444789..4411b18e 100644 --- a/chromeos/network/auto_connect_handler.cc +++ b/chromeos/network/auto_connect_handler.cc
@@ -37,10 +37,12 @@ } AutoConnectHandler::~AutoConnectHandler() { - if (client_cert_resolver_) - client_cert_resolver_->RemoveObserver(this); if (LoginState::IsInitialized()) LoginState::Get()->RemoveObserver(this); + if (client_cert_resolver_) + client_cert_resolver_->RemoveObserver(this); + if (network_connection_handler_) + network_connection_handler_->RemoveObserver(this); if (network_state_handler_) network_state_handler_->RemoveObserver(this, FROM_HERE); if (managed_configuration_handler_)
diff --git a/chromeos/network/client_cert_resolver.h b/chromeos/network/client_cert_resolver.h index 91d7fb5..bc2af20 100644 --- a/chromeos/network/client_cert_resolver.h +++ b/chromeos/network/client_cert_resolver.h
@@ -122,7 +122,7 @@ // instead. base::Time Now() const; - base::ObserverList<Observer> observers_; + base::ObserverList<Observer, true> observers_; // The set of networks that were checked/resolved in previous passes. These // networks are skipped in the NetworkListChanged notification.
diff --git a/chromeos/network/host_resolver_impl_chromeos.cc b/chromeos/network/host_resolver_impl_chromeos.cc index ce0cd18..61a9da9 100644 --- a/chromeos/network/host_resolver_impl_chromeos.cc +++ b/chromeos/network/host_resolver_impl_chromeos.cc
@@ -26,7 +26,7 @@ // // An instance of this class is created on the NetworkHandler (UI) thread and // manages its own lifetime, destroying itself when NetworkStateHandlerObserver -// ::IsShuttingDown() gets called. +// ::OnShuttingDown() gets called. class HostResolverImplChromeOS::NetworkObserver : public chromeos::NetworkStateHandlerObserver { @@ -96,7 +96,7 @@ CallResolverSetIpAddress(ipv4_address, ipv6_address); } - void IsShuttingDown() override { delete this; } + void OnShuttingDown() override { delete this; } void CallResolverSetIpAddress(const std::string& ipv4_address, const std::string& ipv6_address) {
diff --git a/chromeos/network/managed_network_configuration_handler_impl.h b/chromeos/network/managed_network_configuration_handler_impl.h index 76d6c2e..a6337f3d8 100644 --- a/chromeos/network/managed_network_configuration_handler_impl.h +++ b/chromeos/network/managed_network_configuration_handler_impl.h
@@ -215,7 +215,7 @@ // associated set of GUIDs is empty. UserToModifiedPoliciesMap queued_modified_policies_; - base::ObserverList<NetworkPolicyObserver> observers_; + base::ObserverList<NetworkPolicyObserver, true> observers_; // For Shill client callbacks base::WeakPtrFactory<ManagedNetworkConfigurationHandlerImpl>
diff --git a/chromeos/network/network_configuration_handler.h b/chromeos/network/network_configuration_handler.h index 6b0bbbdf..d76be19 100644 --- a/chromeos/network/network_configuration_handler.h +++ b/chromeos/network/network_configuration_handler.h
@@ -205,7 +205,7 @@ // Map of in-progress deleter instances. Owned by this class. std::map<std::string, ProfileEntryDeleter*> profile_entry_deleters_; - base::ObserverList<NetworkConfigurationObserver> observers_; + base::ObserverList<NetworkConfigurationObserver, true> observers_; DISALLOW_COPY_AND_ASSIGN(NetworkConfigurationHandler); };
diff --git a/chromeos/network/network_connection_handler.h b/chromeos/network/network_connection_handler.h index f2ff1a0..fc38ce39 100644 --- a/chromeos/network/network_connection_handler.h +++ b/chromeos/network/network_connection_handler.h
@@ -233,7 +233,7 @@ void HandleShillDisconnectSuccess(const std::string& service_path, const base::Closure& success_callback); - base::ObserverList<NetworkConnectionObserver> observers_; + base::ObserverList<NetworkConnectionObserver, true> observers_; // Local references to the associated handler instances. CertLoader* cert_loader_;
diff --git a/chromeos/network/network_handler.cc b/chromeos/network/network_handler.cc index b10bad7..05f7f0cf 100644 --- a/chromeos/network/network_handler.cc +++ b/chromeos/network/network_handler.cc
@@ -50,6 +50,7 @@ } NetworkHandler::~NetworkHandler() { + network_state_handler_->Shutdown(); } void NetworkHandler::Init() {
diff --git a/chromeos/network/network_profile_handler.h b/chromeos/network/network_profile_handler.h index 5015dd27..f7c70c7 100644 --- a/chromeos/network/network_profile_handler.h +++ b/chromeos/network/network_profile_handler.h
@@ -81,7 +81,7 @@ // properties are retrieved and the path is still in this set, a new profile // object is created. std::set<std::string> pending_profile_creations_; - base::ObserverList<NetworkProfileObserver> observers_; + base::ObserverList<NetworkProfileObserver, true> observers_; // For Shill client callbacks base::WeakPtrFactory<NetworkProfileHandler> weak_ptr_factory_;
diff --git a/chromeos/network/network_sms_handler.h b/chromeos/network/network_sms_handler.h index eb8ed88..1e987fc3 100644 --- a/chromeos/network/network_sms_handler.h +++ b/chromeos/network/network_sms_handler.h
@@ -90,7 +90,7 @@ DBusMethodCallStatus call_status, const base::DictionaryValue& properties); - base::ObserverList<Observer> observers_; + base::ObserverList<Observer, true> observers_; ScopedVector<NetworkSmsDeviceHandler> device_handlers_; ScopedVector<base::DictionaryValue> received_messages_; base::WeakPtrFactory<NetworkSmsHandler> weak_ptr_factory_; @@ -98,6 +98,6 @@ DISALLOW_COPY_AND_ASSIGN(NetworkSmsHandler); }; -} // namespace +} // namespace chromeos #endif // CHROMEOS_NETWORK_NETWORK_SMS_HANDLER_H_
diff --git a/chromeos/network/network_sms_handler_unittest.cc b/chromeos/network/network_sms_handler_unittest.cc index 13b3b58..9ee2b0a 100644 --- a/chromeos/network/network_sms_handler_unittest.cc +++ b/chromeos/network/network_sms_handler_unittest.cc
@@ -81,6 +81,7 @@ } void TearDown() override { + network_sms_handler_->RemoveObserver(test_observer_.get()); network_sms_handler_.reset(); DBusThreadManager::Shutdown(); }
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index 5f4738a6..1d521d9d 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc
@@ -67,15 +67,24 @@ const char NetworkStateHandler::kDefaultCheckPortalList[] = "ethernet,wifi,cellular"; -NetworkStateHandler::NetworkStateHandler() : network_list_sorted_(false) { -} +NetworkStateHandler::NetworkStateHandler() {} NetworkStateHandler::~NetworkStateHandler() { - FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_, IsShuttingDown()); + // Normally Shutdown() will get called in ~NetworkHandler, however unit + // tests do not use that class so this needs to call Shutdown when we + // destry the class. + if (!did_shutdown_) + Shutdown(); STLDeleteContainerPointers(network_list_.begin(), network_list_.end()); STLDeleteContainerPointers(device_list_.begin(), device_list_.end()); } +void NetworkStateHandler::Shutdown() { + DCHECK(!did_shutdown_); + did_shutdown_ = true; + FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_, OnShuttingDown()); +} + void NetworkStateHandler::InitShillPropertyHandler() { shill_property_handler_.reset(new internal::ShillPropertyHandler(this)); shill_property_handler_->Init(); @@ -92,20 +101,27 @@ NetworkStateHandlerObserver* observer, const tracked_objects::Location& from_here) { observers_.AddObserver(observer); - device_event_log::AddEntry(from_here.file_name(), from_here.line_number(), - device_event_log::LOG_TYPE_NETWORK, - device_event_log::LOG_LEVEL_DEBUG, - "NetworkStateHandler::AddObserver"); + device_event_log::AddEntry( + from_here.file_name(), from_here.line_number(), + device_event_log::LOG_TYPE_NETWORK, device_event_log::LOG_LEVEL_DEBUG, + base::StringPrintf("NetworkStateHandler::AddObserver: 0x%p", observer)); + + LOG(ERROR) << "ADD Observer: " << from_here.file_name() << ":" + << from_here.line_number() << ": " << observer; } void NetworkStateHandler::RemoveObserver( NetworkStateHandlerObserver* observer, const tracked_objects::Location& from_here) { observers_.RemoveObserver(observer); - device_event_log::AddEntry(from_here.file_name(), from_here.line_number(), - device_event_log::LOG_TYPE_NETWORK, - device_event_log::LOG_LEVEL_DEBUG, - "NetworkStateHandler::RemoveObserver"); + device_event_log::AddEntry( + from_here.file_name(), from_here.line_number(), + device_event_log::LOG_TYPE_NETWORK, device_event_log::LOG_LEVEL_DEBUG, + base::StringPrintf("NetworkStateHandler::RemoveObserver: 0x%p", + observer)); + + LOG(ERROR) << "REM Observer: " << from_here.file_name() << ":" + << from_here.line_number() << ": " << observer; } NetworkStateHandler::TechnologyState NetworkStateHandler::GetTechnologyState(
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h index 2477c1a..90b5105 100644 --- a/chromeos/network/network_state_handler.h +++ b/chromeos/network/network_state_handler.h
@@ -81,6 +81,10 @@ ~NetworkStateHandler() override; + // Called just before destruction to give observers a chance to remove + // themselves and disable any networking. + void Shutdown(); + // Add/remove observers. void AddObserver(NetworkStateHandlerObserver* observer, const tracked_objects::Location& from_here); @@ -374,14 +378,14 @@ scoped_ptr<internal::ShillPropertyHandler> shill_property_handler_; // Observer list - base::ObserverList<NetworkStateHandlerObserver> observers_; + base::ObserverList<NetworkStateHandlerObserver, true> observers_; // List of managed network states ManagedStateList network_list_; // Set to true when the network list is sorted, cleared when network updates // arrive. Used to trigger sorting when needed. - bool network_list_sorted_; + bool network_list_sorted_ = false; // List of managed device states ManagedStateList device_list_; @@ -396,6 +400,9 @@ // NetworkState that is not saved in a profile. SpecifierGuidMap specifier_guid_map_; + // Ensure that Shutdown() gets called exactly once. + bool did_shutdown_ = false; + DISALLOW_COPY_AND_ASSIGN(NetworkStateHandler); };
diff --git a/chromeos/network/network_state_handler_observer.cc b/chromeos/network/network_state_handler_observer.cc index 56ab375..971439db 100644 --- a/chromeos/network/network_state_handler_observer.cc +++ b/chromeos/network/network_state_handler_observer.cc
@@ -37,7 +37,6 @@ void NetworkStateHandlerObserver::ScanCompleted(const DeviceState* device) { } -void NetworkStateHandlerObserver::IsShuttingDown() { -} +void NetworkStateHandlerObserver::OnShuttingDown() {} } // namespace chromeos
diff --git a/chromeos/network/network_state_handler_observer.h b/chromeos/network/network_state_handler_observer.h index a25dc59..b1a7ae6 100644 --- a/chromeos/network/network_state_handler_observer.h +++ b/chromeos/network/network_state_handler_observer.h
@@ -53,7 +53,7 @@ // Called just before NetworkStateHandler is destroyed so that observers // can safely stop observing. - virtual void IsShuttingDown(); + virtual void OnShuttingDown(); private: DISALLOW_COPY_AND_ASSIGN(NetworkStateHandlerObserver);
diff --git a/components/autofill/core/browser/autofill_country.cc b/components/autofill/core/browser/autofill_country.cc index 1148742..a346d1a2 100644 --- a/components/autofill/core/browser/autofill_country.cc +++ b/components/autofill/core/browser/autofill_country.cc
@@ -30,8 +30,6 @@ namespace autofill { namespace { -using l10n::CollatorWrapper; - // The maximum capacity needed to store a locale up to the country code. const size_t kLocaleCapacity = ULOC_LANG_CAPACITY + ULOC_SCRIPT_CAPACITY + ULOC_COUNTRY_CAPACITY + 1; @@ -865,7 +863,7 @@ // localized to |locale| to their corresponding country codes. Uses a // |collator| which is suitable for the locale. void AddLocalizedNamesForLocale(const std::string& locale, - const CollatorWrapper& collator); + const icu::Collator& collator); // Interprets |country_name| as a full country name localized to the given // |locale| and returns the corresponding country code stored in @@ -876,13 +874,13 @@ // Returns an ICU collator -- i.e. string comparator -- appropriate for the // given |locale|, or null if no collator is available. - const CollatorWrapper* GetCollatorForLocale(const std::string& locale); + const icu::Collator* GetCollatorForLocale(const std::string& locale); // Returns the ICU sort key corresponding to |str| for the given |collator|. // Uses |buffer| as temporary storage, and might resize |buffer| as a side- // effect. |buffer_size| should specify the |buffer|'s size, and is updated if // the |buffer| is resized. - const std::string GetSortKey(const CollatorWrapper& collator, + const std::string GetSortKey(const icu::Collator& collator, const base::string16& str, scoped_ptr<uint8_t[]>* buffer, int32_t* buffer_size) const; @@ -900,7 +898,7 @@ locales_to_localized_names_; // Maps ICU locale names to their corresponding collators. - std::map<std::string, scoped_ptr<CollatorWrapper>> collators_; + std::map<std::string, scoped_ptr<icu::Collator>> collators_; DISALLOW_COPY_AND_ASSIGN(CountryNames); }; @@ -955,7 +953,7 @@ } void CountryNames::AddLocalizedNamesForLocale(const std::string& locale, - const CollatorWrapper& collator) { + const icu::Collator& collator) { // Nothing to do if we've previously added the localized names for the given // |locale|. if (locales_to_localized_names_.count(locale)) @@ -985,7 +983,7 @@ const std::string CountryNames::GetCountryCodeForLocalizedName( const base::string16& country_name, const std::string& locale) { - const CollatorWrapper* collator = GetCollatorForLocale(locale); + const icu::Collator* collator = GetCollatorForLocale(locale); // In very rare cases, the collator fails to initialize. if (!collator) return std::string(); @@ -1013,20 +1011,19 @@ return std::string(); } -const CollatorWrapper* CountryNames::GetCollatorForLocale( +const icu::Collator* CountryNames::GetCollatorForLocale( const std::string& locale) { if (!ContainsKey(collators_, locale)) { - scoped_ptr<CollatorWrapper> collator( + scoped_ptr<icu::Collator> collator( autofill::l10n::GetCollatorForLocale(icu::Locale(locale.c_str()))); if (!collator) return nullptr; // Compare case-insensitively and ignoring punctuation. UErrorCode ignored = U_ZERO_ERROR; - collator->collator()->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, ignored); + collator->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, ignored); ignored = U_ZERO_ERROR; - collator->collator()->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, - ignored); + collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, ignored); collators_[locale] = std::move(collator); } @@ -1034,7 +1031,7 @@ return collators_[locale].get(); } -const std::string CountryNames::GetSortKey(const CollatorWrapper& collator, +const std::string CountryNames::GetSortKey(const icu::Collator& collator, const base::string16& str, scoped_ptr<uint8_t[]>* buffer, int32_t* buffer_size) const { @@ -1042,16 +1039,15 @@ DCHECK(buffer_size); icu::UnicodeString icu_str(str.c_str(), str.length()); - int32_t expected_size = - collator.collator()->getSortKey(icu_str, buffer->get(), *buffer_size); + int32_t expected_size = collator.getSortKey(icu_str, buffer->get(), + *buffer_size); if (expected_size > *buffer_size) { // If there wasn't enough space, grow the buffer and try again. *buffer_size = expected_size; buffer->reset(new uint8_t[*buffer_size]); DCHECK(buffer->get()); - expected_size = - collator.collator()->getSortKey(icu_str, buffer->get(), *buffer_size); + expected_size = collator.getSortKey(icu_str, buffer->get(), *buffer_size); DCHECK_EQ(*buffer_size, expected_size); }
diff --git a/components/autofill/core/common/autofill_l10n_util.cc b/components/autofill/core/common/autofill_l10n_util.cc index a08fc6c..dda5a32 100644 --- a/components/autofill/core/common/autofill_l10n_util.cc +++ b/components/autofill/core/common/autofill_l10n_util.cc
@@ -8,22 +8,13 @@ #include <utility> #include "base/i18n/string_compare.h" +#include "base/logging.h" #include "base/metrics/histogram_macros.h" namespace autofill { namespace l10n { -CollatorWrapper::CollatorWrapper(scoped_ptr<icu::Collator> collator) - : collator_(std::move(collator)), is_valid_(collator_) { - CHECK(is_valid_); -} - -CollatorWrapper::~CollatorWrapper() { - CHECK(is_valid_); - is_valid_ = false; -} - -scoped_ptr<CollatorWrapper> GetCollatorForLocale(const icu::Locale& locale) { +scoped_ptr<icu::Collator> GetCollatorForLocale(const icu::Locale& locale) { UErrorCode ignored = U_ZERO_ERROR; scoped_ptr<icu::Collator> collator( icu::Collator::createInstance(locale, ignored)); @@ -48,9 +39,7 @@ } UMA_HISTOGRAM_BOOLEAN("Autofill.IcuCollatorCreationSuccess", !!collator); - if (!collator) - return nullptr; - return make_scoped_ptr(new CollatorWrapper(std::move(collator))); + return collator; } CaseInsensitiveCompare::CaseInsensitiveCompare() @@ -59,7 +48,7 @@ CaseInsensitiveCompare::CaseInsensitiveCompare(const icu::Locale& locale) : collator_(GetCollatorForLocale(locale)) { if (collator_) - collator_->collator()->setStrength(icu::Collator::PRIMARY); + collator_->setStrength(icu::Collator::PRIMARY); } CaseInsensitiveCompare::~CaseInsensitiveCompare() { @@ -68,8 +57,8 @@ bool CaseInsensitiveCompare::StringsEqual(const base::string16& lhs, const base::string16& rhs) const { if (collator_) { - return base::i18n::CompareString16WithCollator(*collator_->collator(), lhs, - rhs) == UCOL_EQUAL; + return base::i18n::CompareString16WithCollator(*collator_, lhs, rhs) == + UCOL_EQUAL; } return lhs == rhs; }
diff --git a/components/autofill/core/common/autofill_l10n_util.h b/components/autofill/core/common/autofill_l10n_util.h index d3492387..27c7247 100644 --- a/components/autofill/core/common/autofill_l10n_util.h +++ b/components/autofill/core/common/autofill_l10n_util.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_L10N_UTIL_H_ #define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_L10N_UTIL_H_ -#include "base/logging.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" @@ -15,33 +14,9 @@ namespace autofill { namespace l10n { -// TODO(crbug.com/571610): Replace with just icu::Collator once use-after-free -// is eliminated. -// This is a wrapper around icu::Collator checking the collator's validity. -class CollatorWrapper { - public: - explicit CollatorWrapper(scoped_ptr<icu::Collator> collator); - - ~CollatorWrapper(); - - const icu::Collator* collator() const { - CHECK(is_valid_); - return collator_.get(); - } - - icu::Collator* collator() { - return const_cast<icu::Collator*>( - static_cast<const CollatorWrapper*>(this)->collator()); - } - - private: - const scoped_ptr<icu::Collator> collator_; - bool is_valid_; -}; - // Obtains the ICU Collator for this locale. If unsuccessful, attempts to return // the ICU collator for the English locale. If unsuccessful, returns null. -scoped_ptr<CollatorWrapper> GetCollatorForLocale(const icu::Locale& locale); +scoped_ptr<icu::Collator> GetCollatorForLocale(const icu::Locale& locale); // Assists with locale-aware case insensitive string comparisons. class CaseInsensitiveCompare { @@ -54,7 +29,7 @@ bool StringsEqual(const base::string16& lhs, const base::string16& rhs) const; private: - scoped_ptr<CollatorWrapper> collator_; + scoped_ptr<icu::Collator> collator_; DISALLOW_COPY_AND_ASSIGN(CaseInsensitiveCompare); };
diff --git a/components/crash.gypi b/components/crash.gypi index 3571a82..00ee69c 100644 --- a/components/crash.gypi +++ b/components/crash.gypi
@@ -213,6 +213,7 @@ 'crash_component_non_mac_win', 'crash_component_lib', '../base/base.gyp:base', + '../third_party/kasko/kasko.gyp:kasko', ], 'defines': ['CRASH_IMPLEMENTATION'], 'conditions': [ @@ -408,6 +409,8 @@ 'crash/content/browser/crash_dump_manager_android.h', 'crash/content/browser/crash_handler_host_linux.cc', 'crash/content/browser/crash_handler_host_linux.h', + 'crash/content/browser/crash_micro_dump_manager_android.cc', + 'crash/content/browser/crash_micro_dump_manager_android.h', ], 'include_dirs': [ '../breakpad/src',
diff --git a/components/crash/content/app/BUILD.gn b/components/crash/content/app/BUILD.gn index 474b2f2..52140ce 100644 --- a/components/crash/content/app/BUILD.gn +++ b/components/crash/content/app/BUILD.gn
@@ -41,6 +41,7 @@ public_deps = [ ":app_non_mac_win", + "//third_party/kasko", ] deps = [ "//base",
diff --git a/components/crash/content/app/DEPS b/components/crash/content/app/DEPS index dc5e9320..80bc21a3 100644 --- a/components/crash/content/app/DEPS +++ b/components/crash/content/app/DEPS
@@ -4,5 +4,6 @@ "+content/public/common/content_descriptors.h", "+content/public/common/result_codes.h", "+third_party/crashpad", + "+third_party/kasko", "+third_party/lss/linux_syscall_support.h", ]
diff --git a/components/crash/content/app/breakpad_linux.cc b/components/crash/content/app/breakpad_linux.cc index fa9f620..3435f04 100644 --- a/components/crash/content/app/breakpad_linux.cc +++ b/components/crash/content/app/breakpad_linux.cc
@@ -100,8 +100,10 @@ const char* g_asan_report_str = nullptr; #endif #if defined(OS_ANDROID) +const char kWebViewProcessType[] = "webview"; char* g_process_type = nullptr; ExceptionHandler* g_microdump = nullptr; +int g_signal_code_pipe_fd = -1; class MicrodumpInfo { public: @@ -741,7 +743,24 @@ const bool is_browser_process = (context != nullptr); return FinalizeCrashDoneAndroid(is_browser_process); - } +} + +bool WriteSignalCodeToPipe(const void* crash_context, + size_t crash_context_size, + void* context) { + if (g_signal_code_pipe_fd == -1) + return false; + int signo = INT_MAX; + if (crash_context_size == sizeof(ExceptionHandler::CrashContext)) { + const ExceptionHandler::CrashContext* eh_context = + static_cast<const ExceptionHandler::CrashContext*>(crash_context); + signo = eh_context->siginfo.si_signo; + } + sys_write(g_signal_code_pipe_fd, &signo, sizeof(signo)); + IGNORE_RET(sys_close(g_signal_code_pipe_fd)); + g_signal_code_pipe_fd = -1; + return false; +} bool CrashDoneInProcessNoUpload( const google_breakpad::MinidumpDescriptor& descriptor, @@ -834,7 +853,8 @@ const char* android_build_fp) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!g_microdump); - bool is_browser_process = process_type.empty() || process_type == "webview"; + bool is_browser_process = + process_type.empty() || process_type == kWebViewProcessType; MinidumpDescriptor descriptor(MinidumpDescriptor::kMicrodumpOnConsole); @@ -863,7 +883,7 @@ true, // Install handlers. -1); // Server file descriptor. -1 for in-process. - if (process_type == "webview") { + if (process_type == kWebViewProcessType) { // We do not use |DumpProcess()| for handling programatically // generated dumps for WebView because we only know the file // descriptor to which we are dumping at the time of the call to @@ -873,6 +893,11 @@ // time. base::debug::SetDumpWithoutCrashingFunction( &GenerateMinidumpOnDemandForAndroid); + } else if (!process_type.empty()) { + g_signal_code_pipe_fd = + GetCrashReporterClient()->GetAndroidMinidumpDescriptor(); + if (g_signal_code_pipe_fd != -1) + g_microdump->set_crash_handler(WriteSignalCodeToPipe); } }
diff --git a/components/crash/content/app/crashpad.cc b/components/crash/content/app/crashpad.cc index 19a363634..dfe83cac 100644 --- a/components/crash/content/app/crashpad.cc +++ b/components/crash/content/app/crashpad.cc
@@ -243,7 +243,7 @@ }); } -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) void GetCrashKeysForKasko(std::vector<kasko::api::CrashKey>* crash_keys) { // Reserve room for an extra key, the guid. @@ -282,7 +282,7 @@ } } -#endif // KASKO +#endif // BUILDFLAG(ENABLE_KASKO) } // namespace crash_reporter
diff --git a/components/crash/content/app/crashpad.h b/components/crash/content/app/crashpad.h index 59bc5d66f..1f9f007 100644 --- a/components/crash/content/app/crashpad.h +++ b/components/crash/content/app/crashpad.h
@@ -11,10 +11,11 @@ #include <vector> #include "base/files/file_path.h" +#include "third_party/kasko/kasko_features.h" -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) #include "syzygy/kasko/api/crash_key.h" -#endif // KASKO +#endif // BUILDFLAG(ENABLE_KASKO) namespace crash_reporter { @@ -74,10 +75,10 @@ // disabled. void GetUploadedReports(std::vector<UploadedReport>* uploaded_reports); -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) // Returns a copy of the current crash keys for Kasko. void GetCrashKeysForKasko(std::vector<kasko::api::CrashKey>* crash_keys); -#endif // KASKO +#endif // BUILDFLAG(ENABLE_KASKO) namespace internal {
diff --git a/components/crash/content/browser/BUILD.gn b/components/crash/content/browser/BUILD.gn index 850d622d..6eecf54 100644 --- a/components/crash/content/browser/BUILD.gn +++ b/components/crash/content/browser/BUILD.gn
@@ -10,6 +10,8 @@ sources = [ "crash_dump_manager_android.cc", "crash_dump_manager_android.h", + "crash_micro_dump_manager_android.cc", + "crash_micro_dump_manager_android.h", ] deps = [
diff --git a/components/crash/content/browser/crash_micro_dump_manager_android.cc b/components/crash/content/browser/crash_micro_dump_manager_android.cc new file mode 100644 index 0000000..6ac6c3a --- /dev/null +++ b/components/crash/content/browser/crash_micro_dump_manager_android.cc
@@ -0,0 +1,129 @@ +// 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 "components/crash/content/browser/crash_micro_dump_manager_android.h" + +#include <unistd.h> + +#include "base/bind.h" +#include "base/logging.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_data.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "content/public/browser/render_process_host.h" + +using content::BrowserThread; + +namespace breakpad { + +// static +CrashMicroDumpManager* CrashMicroDumpManager::GetInstance() { + return base::Singleton<CrashMicroDumpManager>::get(); +} + +CrashMicroDumpManager::CrashMicroDumpManager() : weak_factory_(this) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + notification_registrar_.Add(this, + content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, + content::NotificationService::AllSources()); + notification_registrar_.Add(this, + content::NOTIFICATION_RENDERER_PROCESS_CLOSED, + content::NotificationService::AllSources()); +} + +CrashMicroDumpManager::~CrashMicroDumpManager() { + base::AutoLock auto_lock(child_process_id_to_pipe_lock_); + child_process_id_to_pipe_.clear(); +} + +base::ScopedFD CrashMicroDumpManager::CreateCrashInfoChannel( + int child_process_id) { + DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + scoped_ptr<base::SyncSocket> local_pipe(new base::SyncSocket()); + scoped_ptr<base::SyncSocket> child_pipe(new base::SyncSocket()); + if (!base::SyncSocket::CreatePair(local_pipe.get(), child_pipe.get())) + return base::ScopedFD(); + { + base::AutoLock auto_lock(child_process_id_to_pipe_lock_); + DCHECK(!ContainsKey(child_process_id_to_pipe_, child_process_id)); + child_process_id_to_pipe_[child_process_id] = std::move(local_pipe); + } + return base::ScopedFD(dup(child_pipe->handle())); +} + +void CrashMicroDumpManager::HandleChildTerminationOnFileThread( + int child_process_id, + base::TerminationStatus termination_status) { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + + scoped_ptr<base::SyncSocket> pipe; + { + base::AutoLock auto_lock(child_process_id_to_pipe_lock_); + const auto& iter = child_process_id_to_pipe_.find(child_process_id); + if (iter == child_process_id_to_pipe_.end()) { + // We might get a NOTIFICATION_RENDERER_PROCESS_TERMINATED and a + // NOTIFICATION_RENDERER_PROCESS_CLOSED. + return; + } + pipe = std::move(iter->second); + child_process_id_to_pipe_.erase(iter); + } + DCHECK(pipe->handle() != base::SyncSocket::kInvalidHandle); + + if (termination_status == base::TERMINATION_STATUS_NORMAL_TERMINATION) + return; + if (pipe->Peek() >= sizeof(int)) { + int exit_code; + pipe->Receive(&exit_code, sizeof(exit_code)); + LOG(FATAL) << "Renderer process crash detected (code " << exit_code + << "). Terminating browser."; + } else { + // The child process hasn't written anything into the pipe. This implies + // that it was terminated via SIGKILL by the low memory killer, and thus we + // need to perform a clean exit. + exit(0); + } +} + +void CrashMicroDumpManager::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + content::RenderProcessHost* rph = + content::Source<content::RenderProcessHost>(source).ptr(); + // In case of a normal termination we just need to close the pipe_fd we kept + // open. + base::TerminationStatus termination_status = + base::TERMINATION_STATUS_NORMAL_TERMINATION; + switch (type) { + case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { + // NOTIFICATION_RENDERER_PROCESS_TERMINATED is sent when the renderer + // process is cleanly shutdown. + break; + } + case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { + // Android fast shutdowns is a known case where the renderer is + // intentionally killed when we are done with it. + if (!rph->FastShutdownStarted()) { + content::RenderProcessHost::RendererClosedDetails* process_details = + content::Details<content::RenderProcessHost::RendererClosedDetails>( + details).ptr(); + termination_status = process_details->status; + } + break; + } + default: + NOTREACHED(); + return; + } + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + base::Bind(&CrashMicroDumpManager::HandleChildTerminationOnFileThread, + weak_factory_.GetWeakPtr(), rph->GetID(), + termination_status)); +} + +} // namespace breakpad
diff --git a/components/crash/content/browser/crash_micro_dump_manager_android.h b/components/crash/content/browser/crash_micro_dump_manager_android.h new file mode 100644 index 0000000..6490e6fa --- /dev/null +++ b/components/crash/content/browser/crash_micro_dump_manager_android.h
@@ -0,0 +1,69 @@ +// 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 COMPONENTS_CRASH_CONTENT_BROWSER_CRASH_MICRO_DUMP_MANAGER_ANDROID_H_ +#define COMPONENTS_CRASH_CONTENT_BROWSER_CRASH_MICRO_DUMP_MANAGER_ANDROID_H_ + +#include <map> + +#include "base/files/scoped_file.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/singleton.h" +#include "base/memory/weak_ptr.h" +#include "base/process/kill.h" +#include "base/sync_socket.h" +#include "base/synchronization/lock.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +namespace breakpad { + +// This class manages behavior of the browser on renderer crashes when +// microdumps are used for capturing the crash stack. Normally, in this case +// the browser doesn't need to do much, because a microdump is written into +// Android log by the renderer process itself. However, the browser may need to +// crash itself on a renderer crash. Since on Android renderers are not child +// processes of the browser, it can't access the exit code. Instead, the browser +// uses a dedicated pipe in order to receive the information about the renderer +// crash status. +class CrashMicroDumpManager : public content::NotificationObserver { + public: + // There is only a single instance of CrashMicroDumpManager per browser + // process. It needs to be created on the UI thread. + static CrashMicroDumpManager* GetInstance(); + + // Returns a pipe that should be used to transfer termination cause of + // |child_process_id|. + base::ScopedFD CreateCrashInfoChannel(int child_process_id); + + private: + friend struct base::DefaultSingletonTraits<CrashMicroDumpManager>; + + CrashMicroDumpManager(); + ~CrashMicroDumpManager() override; + + // NotificationObserver implementation: + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override; + + // Called on child process exit (including crash). + void HandleChildTerminationOnFileThread( + int child_process_id, + base::TerminationStatus termination_status); + + content::NotificationRegistrar notification_registrar_; + + // This map should only be accessed with its lock aquired as it is accessed + // from the PROCESS_LAUNCHER, FILE, and UI threads. + base::Lock child_process_id_to_pipe_lock_; + std::map<int, scoped_ptr<base::SyncSocket>> child_process_id_to_pipe_; + base::WeakPtrFactory<CrashMicroDumpManager> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(CrashMicroDumpManager); +}; + +} // namespace breakpad + +#endif // COMPONENTS_CRASH_CONTENT_BROWSER_CRASH_MICRO_DUMP_MANAGER_ANDROID_H_
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java index 2c1242e..63365334 100644 --- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java +++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -10,6 +10,7 @@ import android.util.Log; import java.io.File; +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Constructor; @@ -19,6 +20,7 @@ import java.net.URLConnection; import java.net.URLStreamHandlerFactory; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; @@ -571,8 +573,10 @@ * @deprecated Use {@link UrlRequest.Builder#build}. */ @Deprecated - public abstract UrlRequest createRequest( - String url, UrlRequest.Callback callback, Executor executor); + public final UrlRequest createRequest( + String url, UrlRequest.Callback callback, Executor executor) { + return createRequest(url, callback, executor, UrlRequest.Builder.REQUEST_PRIORITY_MEDIUM); + } /** * Creates a {@link UrlRequest} object. All callbacks will @@ -590,8 +594,10 @@ * @deprecated Use {@link UrlRequest.Builder#build}. */ @Deprecated - public abstract UrlRequest createRequest(String url, UrlRequest.Callback callback, - Executor executor, @UrlRequest.Builder.RequestPriority int priority); + public final UrlRequest createRequest(String url, UrlRequest.Callback callback, + Executor executor, @UrlRequest.Builder.RequestPriority int priority) { + return createRequest(url, callback, executor, priority, Collections.emptyList()); + } /** * Creates a {@link UrlRequest} object. All callbacks will @@ -781,7 +787,7 @@ * @param url URL of resource to connect to. * @return an {@link java.net.HttpURLConnection} instance implemented by this CronetEngine. */ - public abstract URLConnection openConnection(URL url); + public abstract URLConnection openConnection(URL url) throws IOException; /** * Establishes a new connection to the resource specified by the {@link URL} {@code url} @@ -800,7 +806,7 @@ */ @Deprecated @SuppressWarnings("DepAnn") - public abstract URLConnection openConnection(URL url, Proxy proxy); + public abstract URLConnection openConnection(URL url, Proxy proxy) throws IOException; /** * Creates a {@link URLStreamHandlerFactory} to handle HTTP and HTTPS @@ -853,9 +859,7 @@ cronetEngine = createCronetEngine(builder); } if (cronetEngine == null) { - // TODO(mef): Fallback to stub implementation. Once stub - // implementation is available merge with createCronetFactory. - cronetEngine = createCronetEngine(builder); + cronetEngine = new JavaCronetEngine(builder.getUserAgent()); } Log.i(TAG, "Using network stack: " + cronetEngine.getVersionString()); return cronetEngine;
diff --git a/components/cronet/android/api/src/org/chromium/net/InputStreamChannel.java b/components/cronet/android/api/src/org/chromium/net/InputStreamChannel.java new file mode 100644 index 0000000..cf415e78 --- /dev/null +++ b/components/cronet/android/api/src/org/chromium/net/InputStreamChannel.java
@@ -0,0 +1,75 @@ +// 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.net; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Adapts an {@link InputStream} into a {@link ReadableByteChannel}, exactly like + * {@link java.nio.channels.Channels#newChannel(InputStream)} does, but more efficiently, since it + * does not allocate a temporary buffer if it doesn't have to, and it freely takes advantage of + * {@link FileInputStream}'s trivial conversion to {@link java.nio.channels.FileChannel}. + */ +final class InputStreamChannel implements ReadableByteChannel { + private static final int MAX_TMP_BUFFER_SIZE = 16384; + private static final int MIN_TMP_BUFFER_SIZE = 4096; + private final InputStream mInputStream; + private final AtomicBoolean mIsOpen = new AtomicBoolean(true); + + private InputStreamChannel(InputStream inputStream) { + mInputStream = inputStream; + } + + static ReadableByteChannel wrap(InputStream inputStream) { + if (inputStream instanceof FileInputStream) { + return ((FileInputStream) inputStream).getChannel(); + } + return new InputStreamChannel(inputStream); + } + + @Override + public int read(ByteBuffer dst) throws IOException { + final int read; + if (dst.hasArray()) { + read = mInputStream.read( + dst.array(), dst.arrayOffset() + dst.position(), dst.remaining()); + if (read > 0) { + dst.position(dst.position() + read); + } + } else { + // Since we're allocating a buffer for every read, we want to choose a good size - on + // Android, the only case where a ByteBuffer won't have a backing byte[] is if it was + // created wrapping a void * in native code, or if it represents a memory-mapped file. + // Especially in the latter case, we want to avoid allocating a buffer that could be + // very large. + final int possibleToRead = Math.min( + Math.max(mInputStream.available(), MIN_TMP_BUFFER_SIZE), dst.remaining()); + final int reasonableToRead = Math.min(MAX_TMP_BUFFER_SIZE, possibleToRead); + byte[] tmpBuf = new byte[reasonableToRead]; + read = mInputStream.read(tmpBuf); + if (read > 0) { + dst.put(tmpBuf, 0, read); + } + } + return read; + } + + @Override + public boolean isOpen() { + return mIsOpen.get(); + } + + @Override + public void close() throws IOException { + if (mIsOpen.compareAndSet(true, false)) { + mInputStream.close(); + } + } +}
diff --git a/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java b/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java new file mode 100644 index 0000000..d971961 --- /dev/null +++ b/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java
@@ -0,0 +1,144 @@ +// 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.net; + +import static android.os.Process.THREAD_PRIORITY_BACKGROUND; +import static android.os.Process.THREAD_PRIORITY_MORE_FAVORABLE; + +import java.io.IOException; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +/** + * {@link java.net.HttpURLConnection} backed CronetEngine. + * + * <p>Does not support netlogs, transferred data measurement, bidistream, cache, or priority. + */ +final class JavaCronetEngine extends CronetEngine { + private final String mUserAgent; + + private final ExecutorService mExecutorService = + Executors.newCachedThreadPool(new ThreadFactory() { + @Override + public Thread newThread(final Runnable r) { + return Executors.defaultThreadFactory().newThread(new Runnable() { + @Override + public void run() { + Thread.currentThread().setName("JavaCronetEngine"); + // On android, all background threads (and all threads that are part + // of background processes) are put in a cgroup that is allowed to + // consume up to 5% of CPU - these worker threads spend the vast + // majority of their time waiting on I/O, so making them contend with + // background applications for a slice of CPU doesn't make much sense. + // We want to hurry up and get idle. + android.os.Process.setThreadPriority( + THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE); + r.run(); + } + }); + } + }); + + JavaCronetEngine(String userAgent) { + this.mUserAgent = userAgent; + } + + @Override + public UrlRequest createRequest(String url, UrlRequest.Callback callback, Executor executor, + int priority, Collection<Object> connectionAnnotations) { + return new JavaUrlRequest(callback, mExecutorService, executor, url, mUserAgent); + } + + @Override + BidirectionalStream createBidirectionalStream(String url, BidirectionalStream.Callback callback, + Executor executor, String httpMethod, List<Map.Entry<String, String>> requestHeaders, + @BidirectionalStream.Builder.StreamPriority int priority) { + throw new UnsupportedOperationException( + "Can't create a bidi stream - httpurlconnection doesn't have those APIs"); + } + + @Override + boolean isEnabled() { + return true; + } + + @Override + public String getVersionString() { + return "CronetHttpURLConnection/" + Version.getVersion(); + } + + @Override + public void shutdown() { + mExecutorService.shutdown(); + } + + @Override + public void startNetLogToFile(String fileName, boolean logAll) {} + + @Override + public void stopNetLog() {} + + @Override + public byte[] getGlobalMetricsDeltas() { + return new byte[0]; + } + + @Override + public void enableNetworkQualityEstimator(Executor executor) {} + + @Override + void enableNetworkQualityEstimatorForTesting( + boolean useLocalHostRequests, boolean useSmallerResponses, Executor executor) {} + + @Override + public void addRttListener(NetworkQualityRttListener listener) {} + + @Override + public void removeRttListener(NetworkQualityRttListener listener) {} + + @Override + public void addThroughputListener(NetworkQualityThroughputListener listener) {} + + @Override + public void removeThroughputListener(NetworkQualityThroughputListener listener) {} + + @Override + public void addRequestFinishedListener(RequestFinishedListener listener) {} + + @Override + public void removeRequestFinishedListener(RequestFinishedListener listener) {} + + @Override + public URLConnection openConnection(URL url) throws IOException { + return url.openConnection(); + } + + @Override + public URLConnection openConnection(URL url, Proxy proxy) throws IOException { + return url.openConnection(proxy); + } + + @Override + public URLStreamHandlerFactory createURLStreamHandlerFactory() { + // Returning null causes this factory to pass though, which ends up using the platform's + // implementation. + return new URLStreamHandlerFactory() { + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + return null; + } + }; + } +}
diff --git a/components/cronet/android/api/src/org/chromium/net/JavaUrlRequest.java b/components/cronet/android/api/src/org/chromium/net/JavaUrlRequest.java new file mode 100644 index 0000000..00e9e59 --- /dev/null +++ b/components/cronet/android/api/src/org/chromium/net/JavaUrlRequest.java
@@ -0,0 +1,845 @@ +// 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.net; + +import android.annotation.TargetApi; +import android.net.TrafficStats; +import android.os.Build; +import android.util.Log; + +import java.io.Closeable; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Pure java UrlRequest, backed by {@link HttpURLConnection}. + */ +@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) // TrafficStats only available on ICS +final class JavaUrlRequest implements UrlRequest { + private static final String X_ANDROID = "X-Android"; + private static final String X_ANDROID_SELECTED_TRANSPORT = "X-Android-Selected-Transport"; + private static final String TAG = "JavaUrlConnection"; + private static final int DEFAULT_UPLOAD_BUFFER_SIZE = 8192; + private static final int DEFAULT_CHUNK_LENGTH = DEFAULT_UPLOAD_BUFFER_SIZE; + private static final String USER_AGENT = "User-Agent"; + private final AsyncUrlRequestCallback mCallbackAsync; + private final Executor mExecutor; + private final String mUserAgent; + private final Map<String, String> mRequestHeaders = + new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + private final List<String> mUrlChain = new ArrayList<>(); + /** + * This is the source of thread safety in this class - no other synchronization is performed. + * By compare-and-swapping from one state to another, we guarantee that operations aren't + * running concurrently. Only the winner of a CAS proceeds. + * + * <p>A caller can lose a CAS for three reasons - user error (two calls to read() without + * waiting for the read to succeed), runtime error (network code or user code throws an + * exception), or cancellation. + */ + private final AtomicReference<State> mState = new AtomicReference<>(State.NOT_STARTED); + + /** + * Traffic stats tag to associate this requests' data use with. It's captured when the request + * is created, so that applications doing work on behalf of another app can correctly attribute + * that data use. + */ + private final int mTrafficStatsTag; + + /* These don't change with redirects */ + private String mInitialMethod; + private UploadDataProvider mUploadDataProvider; + private Executor mUploadExecutor; + /** + * Holds a subset of StatusValues - {@link State#STARTED} can represent + * {@link Status#SENDING_REQUEST} or {@link Status#WAITING_FOR_RESPONSE}. While the distinction + * isn't needed to implement the logic in this class, it is needed to implement + * {@link #getStatus(StatusListener)}. + * + * <p>Concurrency notes - this value is not atomically updated with mState, so there is some + * risk that we'd get an inconsistent snapshot of both - however, it also happens that this + * value is only used with the STARTED state, so it's inconsequential. + */ + @Status.StatusValues private volatile int mAdditionalStatusDetails = Status.INVALID; + + /* These change with redirects. */ + private String mCurrentUrl; + private ReadableByteChannel mResponseChannel; + private UrlResponseInfo mUrlResponseInfo; + private String mPendingRedirectUrl; + /** + * The happens-before edges created by the executor submission and AtomicReference setting are + * sufficient to guarantee the correct behavior of this field; however, this is an + * AtomicReference so that we can cleanly dispose of a new connection if we're cancelled during + * a redirect, which requires get-and-set semantics. + * */ + private final AtomicReference<HttpURLConnection> mCurrentUrlConnection = + new AtomicReference<>(); + + /** + * /- AWAITING_FOLLOW_REDIRECT <- REDIRECT_RECEIVED <-\ /- READING <--\ + * | | | | + * \ / \ / + * NOT_STARTED ---> STARTED ----> AWAITING_READ ---> + * COMPLETE + */ + private enum State { + NOT_STARTED, + STARTED, + REDIRECT_RECEIVED, + AWAITING_FOLLOW_REDIRECT, + AWAITING_READ, + READING, + ERROR, + COMPLETE, + CANCELLED, + } + + /** + * @param executor The executor used for reading and writing from sockets + * @param userExecutor The executor used to dispatch to {@code callback} + */ + JavaUrlRequest(Callback callback, final Executor executor, Executor userExecutor, String url, + String userAgent) { + if (url == null) { + throw new NullPointerException("URL is required"); + } + if (callback == null) { + throw new NullPointerException("Listener is required"); + } + if (executor == null) { + throw new NullPointerException("Executor is required"); + } + if (userExecutor == null) { + throw new NullPointerException("userExecutor is required"); + } + this.mCallbackAsync = new AsyncUrlRequestCallback(callback, userExecutor); + this.mTrafficStatsTag = TrafficStats.getThreadStatsTag(); + this.mExecutor = new Executor() { + @Override + public void execute(final Runnable command) { + executor.execute(new Runnable() { + @Override + public void run() { + int oldTag = TrafficStats.getThreadStatsTag(); + TrafficStats.setThreadStatsTag(mTrafficStatsTag); + try { + command.run(); + } finally { + TrafficStats.setThreadStatsTag(oldTag); + } + } + }); + } + }; + this.mCurrentUrl = url; + this.mUserAgent = userAgent; + } + + @Override + public void setHttpMethod(String method) { + checkNotStarted(); + if (method == null) { + throw new NullPointerException("Method is required."); + } + if ("OPTIONS".equalsIgnoreCase(method) || "GET".equalsIgnoreCase(method) + || "HEAD".equalsIgnoreCase(method) || "POST".equalsIgnoreCase(method) + || "PUT".equalsIgnoreCase(method) || "DELETE".equalsIgnoreCase(method) + || "TRACE".equalsIgnoreCase(method) || "PATCH".equalsIgnoreCase(method)) { + mInitialMethod = method; + } else { + throw new IllegalArgumentException("Invalid http method " + method); + } + } + + private void checkNotStarted() { + State state = mState.get(); + if (state != State.NOT_STARTED) { + throw new IllegalStateException("Request is already started. State is: " + state); + } + } + + @Override + public void addHeader(String header, String value) { + checkNotStarted(); + if (!isValidHeaderName(header) || value.contains("\r\n")) { + throw new IllegalArgumentException("Invalid header " + header + "=" + value); + } + if (mRequestHeaders.containsKey(header)) { + mRequestHeaders.remove(header); + } + mRequestHeaders.put(header, value); + } + + private boolean isValidHeaderName(String header) { + for (int i = 0; i < header.length(); i++) { + char c = header.charAt(i); + switch (c) { + case '(': + case ')': + case '<': + case '>': + case '@': + case ',': + case ';': + case ':': + case '\\': + case '\'': + case '/': + case '[': + case ']': + case '?': + case '=': + case '{': + case '}': + return false; + default: { + if (Character.isISOControl(c) || Character.isWhitespace(c)) { + return false; + } + } + } + } + return true; + } + + @Override + public void setUploadDataProvider(UploadDataProvider uploadDataProvider, Executor executor) { + if (uploadDataProvider == null) { + throw new NullPointerException("Invalid UploadDataProvider."); + } + if (!mRequestHeaders.containsKey("Content-Type")) { + throw new IllegalArgumentException( + "Requests with upload data must have a Content-Type."); + } + checkNotStarted(); + if (mInitialMethod == null) { + mInitialMethod = "POST"; + } + this.mUploadDataProvider = uploadDataProvider; + this.mUploadExecutor = executor; + } + + private enum SinkState { + AWAITING_READ_RESULT, + AWAITING_REWIND_RESULT, + UPLOADING, + NOT_STARTED, + } + + private final class OutputStreamDataSink implements UploadDataSink { + final AtomicReference<SinkState> mSinkState = new AtomicReference<>(SinkState.NOT_STARTED); + final Executor mUserExecutor; + final Executor mExecutor; + final HttpURLConnection mUrlConnection; + WritableByteChannel mOutputChannel; + final UploadDataProvider mUploadProvider; + ByteBuffer mBuffer; + /** This holds the total bytes to send (the content-length). -1 if unknown. */ + long mTotalBytes; + /** This holds the bytes written so far */ + long mWrittenBytes = 0; + + OutputStreamDataSink(final Executor userExecutor, Executor executor, + HttpURLConnection urlConnection, UploadDataProvider provider) { + this.mUserExecutor = new Executor() { + @Override + public void execute(Runnable runnable) { + try { + userExecutor.execute(runnable); + } catch (RejectedExecutionException e) { + enterUploadErrorState(e); + } + } + }; + this.mExecutor = executor; + this.mUrlConnection = urlConnection; + this.mUploadProvider = provider; + } + + @Override + public void onReadSucceeded(final boolean finalChunk) { + if (!mSinkState.compareAndSet(SinkState.AWAITING_READ_RESULT, SinkState.UPLOADING)) { + throw new IllegalStateException( + "Not expecting a read result, expecting: " + mSinkState.get()); + } + mExecutor.execute(errorSetting(State.STARTED, new CheckedRunnable() { + @Override + public void run() throws Exception { + mBuffer.flip(); + while (mBuffer.hasRemaining()) { + mWrittenBytes += mOutputChannel.write(mBuffer); + } + if (mWrittenBytes < mTotalBytes || (mTotalBytes == -1 && !finalChunk)) { + mBuffer.clear(); + mSinkState.set(SinkState.AWAITING_READ_RESULT); + mUserExecutor.execute(uploadErrorSetting(new CheckedRunnable() { + @Override + public void run() throws Exception { + mUploadProvider.read(OutputStreamDataSink.this, mBuffer); + } + })); + } else if (mTotalBytes == -1) { + finish(); + } else if (mTotalBytes == mWrittenBytes) { + finish(); + } else { + throw new IllegalStateException("Wrote more bytes than were available"); + } + } + })); + } + + @Override + public void onRewindSucceeded() { + if (!mSinkState.compareAndSet(SinkState.AWAITING_REWIND_RESULT, SinkState.UPLOADING)) { + throw new IllegalStateException("Not expecting a read result"); + } + startRead(); + } + + @Override + public void onReadError(Exception exception) { + enterUploadErrorState(exception); + } + + @Override + public void onRewindError(Exception exception) { + enterUploadErrorState(exception); + } + + void startRead() { + mUserExecutor.execute(uploadErrorSetting(new CheckedRunnable() { + @Override + public void run() throws Exception { + if (mOutputChannel == null) { + mAdditionalStatusDetails = Status.CONNECTING; + mUrlConnection.connect(); + mAdditionalStatusDetails = Status.SENDING_REQUEST; + mOutputChannel = Channels.newChannel(mUrlConnection.getOutputStream()); + } + mSinkState.set(SinkState.AWAITING_READ_RESULT); + mUploadProvider.read(OutputStreamDataSink.this, mBuffer); + } + })); + } + + void finish() throws IOException { + if (mOutputChannel != null) { + mOutputChannel.close(); + } + fireGetHeaders(); + } + + void start(final boolean firstTime) { + mUserExecutor.execute(uploadErrorSetting(new CheckedRunnable() { + @Override + public void run() throws Exception { + mTotalBytes = mUploadProvider.getLength(); + if (mTotalBytes == 0) { + finish(); + } else { + // If we know how much data we have to upload, and it's small, we can save + // memory by allocating a reasonably sized buffer to read into. + if (mTotalBytes > 0 && mTotalBytes < DEFAULT_UPLOAD_BUFFER_SIZE) { + // Allocate one byte more than necessary, to detect callers uploading + // more bytes than they specified in length. + mBuffer = ByteBuffer.allocateDirect((int) mTotalBytes + 1); + } else { + mBuffer = ByteBuffer.allocateDirect(DEFAULT_UPLOAD_BUFFER_SIZE); + } + + if (mTotalBytes > 0 && mTotalBytes <= Integer.MAX_VALUE) { + mUrlConnection.setFixedLengthStreamingMode((int) mTotalBytes); + } else if (mTotalBytes > Integer.MAX_VALUE + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + mUrlConnection.setFixedLengthStreamingMode(mTotalBytes); + } else { + // If we know the length, but we're running pre-kitkat and it's larger + // than an int can hold, we have to use chunked - otherwise we'll end up + // buffering the whole response in memory. + mUrlConnection.setChunkedStreamingMode(DEFAULT_CHUNK_LENGTH); + } + if (firstTime) { + startRead(); + } else { + mSinkState.set(SinkState.AWAITING_REWIND_RESULT); + mUploadProvider.rewind(OutputStreamDataSink.this); + } + } + } + })); + } + } + + @Override + public void start() { + mAdditionalStatusDetails = Status.CONNECTING; + transitionStates(State.NOT_STARTED, State.STARTED, new Runnable() { + @Override + public void run() { + mUrlChain.add(mCurrentUrl); + fireOpenConnection(); + } + }); + } + + private void enterErrorState(State previousState, final UrlRequestException error) { + if (mState.compareAndSet(previousState, State.ERROR)) { + fireDisconnect(); + mCallbackAsync.onFailed(mUrlResponseInfo, error); + } + } + + /** Ends the reqeust with an error, caused by an exception thrown from user code. */ + private void enterUserErrorState(State previousState, final Throwable error) { + enterErrorState(previousState, new UrlRequestException("User Error", error)); + } + + /** Ends the requst with an error, caused by an exception thrown from user code. */ + private void enterUploadErrorState(final Throwable error) { + enterErrorState(State.STARTED, + new UrlRequestException("Exception received from UploadDataProvider", error)); + } + + private void enterCronetErrorState(State previousState, final Throwable error) { + // TODO(clm) mapping from Java exception (UnknownHostException, for example) to net error + // code goes here. + enterErrorState(previousState, new UrlRequestException("System error", error)); + } + + /** + * Atomically swaps from the expected state to a new state. If the swap fails, and it's not + * due to an earlier error or cancellation, throws an exception. + * + * @param afterTransition Callback to run after transition completes successfully. + */ + private void transitionStates(State expected, State newState, Runnable afterTransition) { + if (!mState.compareAndSet(expected, newState)) { + State state = mState.get(); + if (!(state == State.CANCELLED || state == State.ERROR)) { + throw new IllegalStateException( + "Invalid state transition - expected " + expected + " but was " + state); + } + } else { + afterTransition.run(); + } + } + + @Override + public void followRedirect() { + transitionStates(State.AWAITING_FOLLOW_REDIRECT, State.STARTED, new Runnable() { + @Override + public void run() { + mCurrentUrl = mPendingRedirectUrl; + mPendingRedirectUrl = null; + fireOpenConnection(); + } + }); + } + + private void fireGetHeaders() { + mAdditionalStatusDetails = Status.WAITING_FOR_RESPONSE; + mExecutor.execute(errorSetting(State.STARTED, new CheckedRunnable() { + @Override + public void run() throws Exception { + HttpURLConnection connection = mCurrentUrlConnection.get(); + if (connection == null) { + return; // We've been cancelled + } + final List<Map.Entry<String, String>> headerList = new ArrayList<>(); + String selectedTransport = "http/1.1"; + String headerKey; + for (int i = 0; (headerKey = connection.getHeaderFieldKey(i)) != null; i++) { + if (X_ANDROID_SELECTED_TRANSPORT.equalsIgnoreCase(headerKey)) { + selectedTransport = connection.getHeaderField(i); + } + if (!headerKey.startsWith(X_ANDROID)) { + headerList.add(new SimpleEntry<>(headerKey, connection.getHeaderField(i))); + } + } + + int responseCode = connection.getResponseCode(); + // Important to copy the list here, because although we never concurrently modify + // the list ourselves, user code might iterate over it while we're redirecting, and + // that would throw ConcurrentModificationException. + mUrlResponseInfo = new UrlResponseInfo(new ArrayList<>(mUrlChain), responseCode, + connection.getResponseMessage(), Collections.unmodifiableList(headerList), + false, selectedTransport, ""); + // TODO(clm) actual redirect handling? post -> get and whatnot? + if (responseCode >= 300 && responseCode < 400) { + fireRedirectReceived(mUrlResponseInfo.getAllHeaders()); + } else if (responseCode >= 400) { + mResponseChannel = InputStreamChannel.wrap(connection.getErrorStream()); + mCallbackAsync.onResponseStarted(mUrlResponseInfo); + } else { + mResponseChannel = InputStreamChannel.wrap(connection.getInputStream()); + mCallbackAsync.onResponseStarted(mUrlResponseInfo); + } + } + })); + } + + private void fireRedirectReceived(final Map<String, List<String>> headerFields) { + transitionStates(State.STARTED, State.REDIRECT_RECEIVED, new Runnable() { + @Override + public void run() { + mPendingRedirectUrl = URI.create(mCurrentUrl) + .resolve(headerFields.get("location").get(0)) + .toString(); + mUrlChain.add(mPendingRedirectUrl); + transitionStates( + State.REDIRECT_RECEIVED, State.AWAITING_FOLLOW_REDIRECT, new Runnable() { + @Override + public void run() { + mCallbackAsync.onRedirectReceived( + mUrlResponseInfo, mPendingRedirectUrl); + } + }); + } + }); + } + + private void fireOpenConnection() { + mExecutor.execute(errorSetting(State.STARTED, new CheckedRunnable() { + @Override + public void run() throws Exception { + // If we're cancelled, then our old connection will be disconnected for us and + // we shouldn't open a new one. + if (mState.get() == State.CANCELLED) { + return; + } + + final URL url = new URL(mCurrentUrl); + HttpURLConnection newConnection = (HttpURLConnection) url.openConnection(); + HttpURLConnection oldConnection = mCurrentUrlConnection.getAndSet(newConnection); + if (oldConnection != null) { + oldConnection.disconnect(); + } + newConnection.setInstanceFollowRedirects(false); + if (!mRequestHeaders.containsKey(USER_AGENT)) { + mRequestHeaders.put(USER_AGENT, mUserAgent); + } + for (Map.Entry<String, String> entry : mRequestHeaders.entrySet()) { + newConnection.setRequestProperty(entry.getKey(), entry.getValue()); + } + if (mInitialMethod == null) { + mInitialMethod = "GET"; + } + newConnection.setRequestMethod(mInitialMethod); + if (mUploadDataProvider != null) { + OutputStreamDataSink dataSink = new OutputStreamDataSink( + mUploadExecutor, mExecutor, newConnection, mUploadDataProvider); + dataSink.start(mUrlChain.size() == 1); + } else { + mAdditionalStatusDetails = Status.CONNECTING; + newConnection.connect(); + fireGetHeaders(); + } + } + })); + } + + @Override + public void read(final ByteBuffer buffer) { + Preconditions.checkDirect(buffer); + if (!(buffer.capacity() - buffer.position() > 0)) { + throw new IllegalArgumentException("ByteBuffer is already full."); + } + transitionStates(State.AWAITING_READ, State.READING, new Runnable() { + @Override + public void run() { + mExecutor.execute(errorSetting(State.READING, new CheckedRunnable() { + @Override + public void run() throws IOException { + int oldPosition = buffer.position(); + buffer.limit(buffer.capacity()); + int read = mResponseChannel.read(buffer); + buffer.limit(buffer.position()); + buffer.position(oldPosition); + processReadResult(read, buffer); + } + })); + } + }); + } + + private Runnable errorSetting(final State expectedState, final CheckedRunnable delegate) { + return new Runnable() { + @Override + public void run() { + try { + delegate.run(); + } catch (Throwable t) { + enterCronetErrorState(expectedState, t); + } + } + }; + } + + private Runnable userErrorSetting(final State expectedState, final CheckedRunnable delegate) { + return new Runnable() { + @Override + public void run() { + try { + delegate.run(); + } catch (Throwable t) { + enterUserErrorState(expectedState, t); + } + } + }; + } + + private Runnable uploadErrorSetting(final CheckedRunnable delegate) { + return new Runnable() { + @Override + public void run() { + try { + delegate.run(); + } catch (Throwable t) { + enterUploadErrorState(t); + } + } + }; + } + + private interface CheckedRunnable { void run() throws Exception; } + + @Override + public void readNew(final ByteBuffer buffer) { + Preconditions.checkDirect(buffer); + Preconditions.checkHasRemaining(buffer); + transitionStates(State.AWAITING_READ, State.READING, new Runnable() { + @Override + public void run() { + mExecutor.execute(errorSetting(State.READING, new CheckedRunnable() { + @Override + public void run() throws Exception { + int read = mResponseChannel.read(buffer); + processReadResult(read, buffer); + } + })); + } + }); + } + + private void processReadResult(int read, final ByteBuffer buffer) throws IOException { + if (read != -1) { + mCallbackAsync.onReadCompleted(mUrlResponseInfo, buffer); + } else { + mResponseChannel.close(); + if (mState.compareAndSet(State.READING, State.COMPLETE)) { + fireDisconnect(); + mCallbackAsync.onSucceeded(mUrlResponseInfo); + } + } + } + + private void fireDisconnect() { + final HttpURLConnection connection = mCurrentUrlConnection.getAndSet(null); + if (connection != null) { + mExecutor.execute(new Runnable() { + @Override + public void run() { + connection.disconnect(); + } + }); + } + } + + @Override + public void cancel() { + State oldState = mState.getAndSet(State.CANCELLED); + switch (oldState) { + // We've just scheduled some user code to run. When they perform their next operation, + // they'll observe it and fail. However, if user code is cancelling in response to one + // of these callbacks, we'll never actually cancel! + // TODO(clm) figure out if it's possible to avoid concurrency in user callbacks. + case REDIRECT_RECEIVED: + case AWAITING_FOLLOW_REDIRECT: + case AWAITING_READ: + + // User code is waiting on us - cancel away! + case STARTED: + case READING: + fireDisconnect(); + mCallbackAsync.onCanceled(mUrlResponseInfo); + break; + // The rest are all termination cases - we're too late to cancel. + case ERROR: + case COMPLETE: + case CANCELLED: + break; + } + } + + @Override + public boolean isDone() { + State state = mState.get(); + return state == State.COMPLETE | state == State.ERROR | state == State.CANCELLED; + } + + @Override + public void disableCache() { + // We have no cache + } + + @Override + public void getStatus(StatusListener listener) { + State state = mState.get(); + int extraStatus = this.mAdditionalStatusDetails; + + @Status.StatusValues final int status; + switch (state) { + case ERROR: + case COMPLETE: + case CANCELLED: + case NOT_STARTED: + status = Status.INVALID; + break; + case STARTED: + status = extraStatus; + break; + case REDIRECT_RECEIVED: + case AWAITING_FOLLOW_REDIRECT: + case AWAITING_READ: + status = Status.IDLE; + break; + case READING: + status = Status.READING_RESPONSE; + break; + default: + throw new IllegalStateException("Switch is exhaustive: " + state); + } + + mCallbackAsync.sendStatus(listener, status); + } + + /** This wrapper ensures that callbacks are always called on the correct executor */ + private final class AsyncUrlRequestCallback { + final UrlRequest.Callback mCallback; + final Executor mUserExecutor; + + AsyncUrlRequestCallback(Callback callback, final Executor userExecutor) { + this.mCallback = callback; + this.mUserExecutor = userExecutor; + } + + void sendStatus(final StatusListener listener, final int status) { + mUserExecutor.execute(new Runnable() { + @Override + public void run() { + listener.onStatus(status); + } + }); + } + + void execute(State currentState, CheckedRunnable runnable) { + try { + mUserExecutor.execute(userErrorSetting(currentState, runnable)); + } catch (RejectedExecutionException e) { + enterUserErrorState(currentState, e); + } + } + + void onRedirectReceived(final UrlResponseInfo info, final String newLocationUrl) { + execute(State.AWAITING_FOLLOW_REDIRECT, new CheckedRunnable() { + @Override + public void run() throws Exception { + mCallback.onRedirectReceived(JavaUrlRequest.this, info, newLocationUrl); + } + }); + } + + void onResponseStarted(UrlResponseInfo info) { + execute(State.AWAITING_READ, new CheckedRunnable() { + @Override + public void run() { + if (mState.compareAndSet(State.STARTED, State.AWAITING_READ)) { + mCallback.onResponseStarted(JavaUrlRequest.this, mUrlResponseInfo); + } + } + }); + } + + void onReadCompleted(final UrlResponseInfo info, final ByteBuffer byteBuffer) { + execute(State.AWAITING_READ, new CheckedRunnable() { + @Override + public void run() { + if (mState.compareAndSet(State.READING, State.AWAITING_READ)) { + mCallback.onReadCompleted(JavaUrlRequest.this, info, byteBuffer); + } + } + }); + } + + void onCanceled(final UrlResponseInfo info) { + closeQuietly(mResponseChannel); + mUserExecutor.execute(new Runnable() { + @Override + public void run() { + try { + mCallback.onCanceled(JavaUrlRequest.this, info); + } catch (Exception exception) { + Log.e(TAG, "Exception in onCanceled method", exception); + } + } + }); + } + + void onSucceeded(final UrlResponseInfo info) { + mUserExecutor.execute(new Runnable() { + @Override + public void run() { + try { + mCallback.onSucceeded(JavaUrlRequest.this, info); + } catch (Exception exception) { + Log.e(TAG, "Exception in onSucceeded method", exception); + } + } + }); + } + + void onFailed(final UrlResponseInfo urlResponseInfo, final UrlRequestException e) { + closeQuietly(mResponseChannel); + mUserExecutor.execute(new Runnable() { + @Override + public void run() { + try { + mCallback.onFailed(JavaUrlRequest.this, urlResponseInfo, e); + } catch (Exception exception) { + Log.e(TAG, "Exception in onFailed method", exception); + } + } + }); + } + } + + private static void closeQuietly(Closeable closeable) { + if (closeable == null) { + return; + } + try { + closeable.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +}
diff --git a/components/cronet/android/api/src/org/chromium/net/Preconditions.java b/components/cronet/android/api/src/org/chromium/net/Preconditions.java new file mode 100644 index 0000000..babce374 --- /dev/null +++ b/components/cronet/android/api/src/org/chromium/net/Preconditions.java
@@ -0,0 +1,23 @@ +// 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.net; + +import java.nio.ByteBuffer; + +final class Preconditions { + private Preconditions() {} + + static void checkDirect(ByteBuffer buffer) { + if (!buffer.isDirect()) { + throw new IllegalArgumentException("byteBuffer must be a direct ByteBuffer."); + } + } + + static void checkHasRemaining(ByteBuffer buffer) { + if (!buffer.hasRemaining()) { + throw new IllegalArgumentException("ByteBuffer is already full."); + } + } +}
diff --git a/components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java b/components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java index b8f407e..f9461d95 100644 --- a/components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java +++ b/components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java
@@ -61,8 +61,7 @@ if (mHeadersMap != null) { return mHeadersMap; } - Map<String, List<String>> map = - new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER); + Map<String, List<String>> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); for (Map.Entry<String, String> entry : mAllHeadersList) { List<String> values = new ArrayList<String>(); if (map.containsKey(entry.getKey())) { @@ -205,10 +204,12 @@ @Override public String toString() { - return String.format(Locale.ROOT, "UrlResponseInfo[%s]: urlChain = %s, " + return String.format(Locale.ROOT, "UrlResponseInfo@[%s][%s]: urlChain = %s, " + "httpStatus = %d %s, headers = %s, wasCached = %b, " + "negotiatedProtocol = %s, proxyServer= %s, receivedBytesCount = %d", - getUrl(), getUrlChain().toString(), getHttpStatusCode(), getHttpStatusText(), + // Prevent asserting on the contents of this string + Integer.toHexString(System.identityHashCode(this)), getUrl(), + getUrlChain().toString(), getHttpStatusCode(), getHttpStatusText(), getAllHeadersAsList().toString(), wasCached(), getNegotiatedProtocol(), getProxyServer(), getReceivedBytesCount()); }
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequest.java index b20f810..d5692111 100644 --- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequest.java +++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequest.java
@@ -256,6 +256,7 @@ throw new IllegalArgumentException( "ByteBuffer is already full."); } + Preconditions.checkDirect(buffer); if (!mWaitingOnRead) { throw new IllegalStateException("Unexpected read attempt."); @@ -276,21 +277,16 @@ // Still waiting on read. This is just to have consistent // behavior with the other error cases. mWaitingOnRead = true; - // Since accessing byteBuffer's memory failed, it's presumably - // not a direct ByteBuffer. - throw new IllegalArgumentException( - "byteBuffer must be a direct ByteBuffer."); + throw new IllegalArgumentException("Unable to call native read"); } } } @Override public void readNew(ByteBuffer buffer) { + Preconditions.checkHasRemaining(buffer); + Preconditions.checkDirect(buffer); synchronized (mUrlRequestAdapterLock) { - if (!buffer.hasRemaining()) { - throw new IllegalArgumentException("ByteBuffer is already full."); - } - if (!mWaitingOnRead) { throw new IllegalStateException("Unexpected read attempt."); } @@ -305,9 +301,7 @@ // Still waiting on read. This is just to have consistent // behavior with the other error cases. mWaitingOnRead = true; - // Since accessing byteBuffer's memory failed, it's presumably - // not a direct ByteBuffer. - throw new IllegalArgumentException("byteBuffer must be a direct ByteBuffer."); + throw new IllegalArgumentException("Unable to call native read"); } } }
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java index da864df..cac2e32 100644 --- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java +++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
@@ -25,7 +25,6 @@ import java.net.URLConnection; import java.net.URLStreamHandlerFactory; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; @@ -125,22 +124,6 @@ } @Override - public UrlRequest createRequest(String url, UrlRequest.Callback callback, Executor executor) { - return createRequest(url, callback, executor, UrlRequest.Builder.REQUEST_PRIORITY_MEDIUM, - Collections.emptyList()); - } - - @Override - public UrlRequest createRequest(String url, UrlRequest.Callback callback, Executor executor, - @UrlRequest.Builder.RequestPriority int priority) { - synchronized (mLock) { - checkHaveAdapter(); - return new CronetUrlRequest(this, mUrlRequestContextAdapter, url, priority, callback, - executor, Collections.emptyList(), mNetworkQualityEstimatorEnabled); - } - } - - @Override public UrlRequest createRequest(String url, UrlRequest.Callback callback, Executor executor, int priority, Collection<Object> requestAnnotations) { synchronized (mLock) {
diff --git a/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java index 8cf5ea73..1a638967 100644 --- a/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java +++ b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java
@@ -44,7 +44,7 @@ * @return an {@link java.net.HttpURLConnection} instance implemented by Cronet. */ @Override - public URLConnection openConnection(URL url, Proxy proxy) { + public URLConnection openConnection(URL url, Proxy proxy) throws IOException { return mCronetEngine.openConnection(url, proxy); } }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java index 59aad243..30c4856 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java
@@ -24,6 +24,7 @@ private CronetTestFramework mCronetTestFramework; // {@code true} when test is being run against system HttpURLConnection implementation. private boolean mTestingSystemHttpURLConnection; + private boolean mTestingJavaImpl = false; @Override protected void setUp() throws Exception { @@ -95,35 +96,57 @@ return mTestingSystemHttpURLConnection; } + /** + * Returns {@code true} when test is being run against the java implementation of CronetEngine. + */ + protected boolean testingJavaImpl() { + return mTestingJavaImpl; + } + @Override protected void runTest() throws Throwable { mTestingSystemHttpURLConnection = false; - if (!getClass().getPackage().getName().equals( - "org.chromium.net.urlconnection")) { - super.runTest(); - return; - } - try { - Method method = getClass().getMethod(getName(), (Class[]) null); - if (method.isAnnotationPresent(CompareDefaultWithCronet.class)) { - // Run with the default HttpURLConnection implementation first. - mTestingSystemHttpURLConnection = true; - super.runTest(); - // Use Cronet's implementation, and run the same test. - mTestingSystemHttpURLConnection = false; - URL.setURLStreamHandlerFactory(mCronetTestFramework.mStreamHandlerFactory); - super.runTest(); - } else if (method.isAnnotationPresent( - OnlyRunCronetHttpURLConnection.class)) { - // Run only with Cronet's implementation. - URL.setURLStreamHandlerFactory(mCronetTestFramework.mStreamHandlerFactory); - super.runTest(); - } else { - // For all other tests. - super.runTest(); + mTestingJavaImpl = false; + String packageName = getClass().getPackage().getName(); + if (packageName.equals("org.chromium.net.urlconnection")) { + try { + Method method = getClass().getMethod(getName(), (Class[]) null); + if (method.isAnnotationPresent(CompareDefaultWithCronet.class)) { + // Run with the default HttpURLConnection implementation first. + mTestingSystemHttpURLConnection = true; + super.runTest(); + // Use Cronet's implementation, and run the same test. + mTestingSystemHttpURLConnection = false; + URL.setURLStreamHandlerFactory(mCronetTestFramework.mStreamHandlerFactory); + super.runTest(); + } else if (method.isAnnotationPresent(OnlyRunCronetHttpURLConnection.class)) { + // Run only with Cronet's implementation. + URL.setURLStreamHandlerFactory(mCronetTestFramework.mStreamHandlerFactory); + super.runTest(); + } else { + // For all other tests. + super.runTest(); + } + } catch (Throwable e) { + throw new Throwable("CronetTestBase#runTest failed.", e); } - } catch (Throwable e) { - throw new Throwable("CronetTestBase#runTest failed.", e); + } else if (packageName.equals("org.chromium.net")) { + try { + Method method = getClass().getMethod(getName(), (Class[]) null); + super.runTest(); + if (!method.isAnnotationPresent(OnlyRunNativeCronet.class)) { + if (mCronetTestFramework != null) { + mCronetTestFramework.mCronetEngine = + new JavaCronetEngine(UserAgent.from(getContext())); + } + mTestingJavaImpl = true; + super.runTest(); + } + } catch (Throwable e) { + throw new Throwable("CronetTestBase#runTest failed.", e); + } + } else { + super.runTest(); } } @@ -162,4 +185,7 @@ public @interface OnlyRunCronetHttpURLConnection { } + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface OnlyRunNativeCronet {} }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUploadTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUploadTest.java index 65ac9b8..f2101cc1 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUploadTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUploadTest.java
@@ -7,6 +7,7 @@ import android.test.suitebuilder.annotation.SmallTest; import org.chromium.base.test.util.Feature; +import org.chromium.net.CronetTestBase.OnlyRunNativeCronet; import java.util.Arrays; import java.util.List; @@ -49,8 +50,8 @@ */ @SmallTest @Feature({"Cronet"}) - public void testInitTriggersRewindAndInitBeforeRewindCompletes() - throws Exception { + @OnlyRunNativeCronet + public void testInitTriggersRewindAndInitBeforeRewindCompletes() throws Exception { // Init completes synchronously and read succeeds. assertTrue(mHandler.init()); mHandler.read(); @@ -98,8 +99,8 @@ */ @SmallTest @Feature({"Cronet"}) - public void testInitTriggersRewindAndInitAfterRewindCompletes() - throws Exception { + @OnlyRunNativeCronet + public void testInitTriggersRewindAndInitAfterRewindCompletes() throws Exception { // Init completes synchronously and read succeeds. assertTrue(mHandler.init()); mHandler.read(); @@ -146,6 +147,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testReadCompleteTriggerRewind() throws Exception { // Reset and init before read completes. assertTrue(mHandler.init()); @@ -180,6 +182,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testReadCompleteTriggerRewindOnlyOneRewind() throws Exception { testReadCompleteTriggerRewind(); // Reset and Init again, no rewind should happen. @@ -197,8 +200,8 @@ */ @SmallTest @Feature({"Cronet"}) - public void testResetBeforeReadCompleteAndInitTriggerRewind() - throws Exception { + @OnlyRunNativeCronet + public void testResetBeforeReadCompleteAndInitTriggerRewind() throws Exception { // Reset before read completes. Rewind is not triggered. assertTrue(mHandler.init()); mHandler.read(); @@ -232,8 +235,8 @@ */ @SmallTest @Feature({"Cronet"}) - public void testDestroyNativeStreamBeforeReadComplete() - throws Exception { + @OnlyRunNativeCronet + public void testDestroyNativeStreamBeforeReadComplete() throws Exception { // Start a read and wait for it to be pending. assertTrue(mHandler.init()); mHandler.read(); @@ -263,8 +266,8 @@ */ @SmallTest @Feature({"Cronet"}) - public void testDestroyNativeStreamBeforeRewindComplete() - throws Exception { + @OnlyRunNativeCronet + public void testDestroyNativeStreamBeforeRewindComplete() throws Exception { // Start a read and wait for it to complete. assertTrue(mHandler.init()); mHandler.read();
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java index 50f7d82..ce07d6b 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -135,10 +135,15 @@ String userAgentName = "User-Agent"; String userAgentValue = "User-Agent-Value"; CronetEngine.Builder cronetEngineBuilder = new CronetEngine.Builder(getContext()); + if (testingJavaImpl()) { + cronetEngineBuilder.enableLegacyMode(true); + } cronetEngineBuilder.setUserAgent(userAgentValue); cronetEngineBuilder.setLibraryName("cronet_tests"); mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder( TEST_URL, cronetEngineBuilder); + NativeTestServer.shutdownNativeTestServer(); // startNativeTestServer returns false if it's + // already running assertTrue(NativeTestServer.startNativeTestServer(getContext())); TestUrlRequestCallback callback = new TestUrlRequestCallback(); UrlRequest.Builder urlRequestBuilder = @@ -151,6 +156,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // TODO(xunjieli): Remove annotation after crbug.com/539519 is fixed. @SuppressWarnings("deprecation") public void testDataReductionProxyEnabled() throws Exception { @@ -560,6 +566,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // No netlogs for pure java impl public void testNetLog() throws Exception { Context context = getContext(); File directory = new File(PathUtils.getDataDirectory(context)); @@ -662,6 +669,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testNetLogWithBytes() throws Exception { Context context = getContext(); File directory = new File(PathUtils.getDataDirectory(context)); @@ -732,6 +740,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testEnableHttpCacheDisabled() throws Exception { enableCache(CronetEngine.Builder.HTTP_CACHE_DISABLED); String url = NativeTestServer.getFileURL("/cacheable.txt"); @@ -764,6 +773,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testEnableHttpCacheDiskNoHttp() throws Exception { enableCache(CronetEngine.Builder.HTTP_CACHE_DISABLED); String url = NativeTestServer.getFileURL("/cacheable.txt");
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java index 0fce4ac..2ac2bc31 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
@@ -5,15 +5,20 @@ package org.chromium.net; import android.os.ConditionVariable; +import android.test.MoreAsserts; import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; import org.chromium.base.test.util.Feature; import org.chromium.net.TestUrlRequestCallback.FailureType; import org.chromium.net.TestUrlRequestCallback.ResponseStep; import org.chromium.net.test.FailurePhase; +import java.net.ConnectException; import java.nio.ByteBuffer; +import java.util.AbstractMap; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; @@ -125,16 +130,41 @@ assertEquals("GET", callback.mResponseAsString); assertEquals(0, callback.mRedirectCount); assertEquals(callback.mResponseStep, ResponseStep.ON_SUCCEEDED); - assertEquals(String.format("UrlResponseInfo[%s]: urlChain = [%s], httpStatus = 200 OK, " - + "headers = [Connection=close, Content-Length=3, " - + "Content-Type=text/plain], wasCached = false, " - + "negotiatedProtocol = unknown, proxyServer= :0, " - + "receivedBytesCount = 86", - url, url), - callback.mResponseInfo.toString()); + UrlResponseInfo urlResponseInfo = createUrlResponseInfo(new String[] {url}, "OK", 200, 86, + "Connection", "close", "Content-Length", "3", "Content-Type", "text/plain"); + assertResponseEquals(urlResponseInfo, callback.mResponseInfo); checkResponseInfo(callback.mResponseInfo, NativeTestServer.getEchoMethodURL(), 200, "OK"); } + UrlResponseInfo createUrlResponseInfo( + String[] urls, String message, int statusCode, int receivedBytes, String... headers) { + ArrayList<Map.Entry<String, String>> headersList = new ArrayList<>(); + for (int i = 0; i < headers.length; i += 2) { + headersList.add(new AbstractMap.SimpleImmutableEntry<String, String>( + headers[i], headers[i + 1])); + } + UrlResponseInfo unknown = new UrlResponseInfo( + Arrays.asList(urls), statusCode, message, headersList, false, "unknown", ":0"); + unknown.setReceivedBytesCount(receivedBytes); + return unknown; + } + + void assertResponseEquals(UrlResponseInfo expected, UrlResponseInfo actual) { + assertEquals(expected.getAllHeaders(), actual.getAllHeaders()); + assertEquals(expected.getAllHeadersAsList(), actual.getAllHeadersAsList()); + assertEquals(expected.getHttpStatusCode(), actual.getHttpStatusCode()); + assertEquals(expected.getHttpStatusText(), actual.getHttpStatusText()); + assertEquals(expected.getUrlChain(), actual.getUrlChain()); + assertEquals(expected.getUrl(), actual.getUrl()); + // Transferred bytes and proxy server are not supported in pure java + if (!(mTestFramework.mCronetEngine instanceof JavaCronetEngine)) { + assertEquals(expected.getReceivedBytesCount(), actual.getReceivedBytesCount()); + assertEquals(expected.getProxyServer(), actual.getProxyServer()); + // This is a place where behavior intentionally differs between native and java + assertEquals(expected.getNegotiatedProtocol(), actual.getNegotiatedProtocol()); + } + } + /** * Tests a redirect by running it step-by-step. Also tests that delaying a * request works as expected. To make sure there are no unexpected pending @@ -162,13 +192,10 @@ checkResponseInfoHeader( callback.mRedirectResponseInfoList.get(0), "redirect-header", "header-value"); - assertEquals(String.format("UrlResponseInfo[%s]: urlChain = [%s], httpStatus = 302 Found, " - + "headers = [Location=/success.txt, " - + "redirect-header=header-value], wasCached = false, " - + "negotiatedProtocol = unknown, proxyServer= :0, " - + "receivedBytesCount = 74", - NativeTestServer.getRedirectURL(), NativeTestServer.getRedirectURL()), - callback.mRedirectResponseInfoList.get(0).toString()); + UrlResponseInfo expected = + createUrlResponseInfo(new String[] {NativeTestServer.getRedirectURL()}, "Found", + 302, 74, "Location", "/success.txt", "redirect-header", "header-value"); + assertResponseEquals(expected, callback.mRedirectResponseInfoList.get(0)); // Wait for an unrelated request to finish. The request should not // advance until followRedirect is invoked. @@ -213,17 +240,13 @@ assertEquals(ResponseStep.ON_SUCCEEDED, callback.mResponseStep); assertEquals(NativeTestServer.SUCCESS_BODY, callback.mResponseAsString); - assertEquals(String.format("UrlResponseInfo[%s]: urlChain = [%s, %s], httpStatus = 200 OK, " - + "headers = [Content-Type=text/plain, " - + "Access-Control-Allow-Origin=*, header-name=header-value, " - + "multi-header-name=header-value1, " - + "multi-header-name=header-value2], wasCached = false, " - + "negotiatedProtocol = unknown, proxyServer= :0, " - + "receivedBytesCount = 260", - NativeTestServer.getSuccessURL(), NativeTestServer.getRedirectURL(), - NativeTestServer.getSuccessURL()), - callback.mResponseInfo.toString()); + UrlResponseInfo urlResponseInfo = createUrlResponseInfo( + new String[] {NativeTestServer.getRedirectURL(), NativeTestServer.getSuccessURL()}, + "OK", 200, 260, "Content-Type", "text/plain", "Access-Control-Allow-Origin", "*", + "header-name", "header-value", "multi-header-name", "header-value1", + "multi-header-name", "header-value2"); + assertResponseEquals(urlResponseInfo, callback.mResponseInfo); // Make sure there are no other pending messages, which would trigger // asserts in TestUrlRequestCallback. testSimpleGet(); @@ -247,6 +270,7 @@ // See http://crbug.com/468803. @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // No canonical exception to assert on public void testContentLengthMismatchFailsOnce() throws Exception { String url = NativeTestServer.getFileURL( "/content_length_mismatch.html"); @@ -254,7 +278,7 @@ assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); // The entire response body will be read before the error is returned. // This is because the network stack returns data as it's read from the - // socket, and the socket close message which tiggers the error will + // socket, and the socket close message which triggers the error will // only be passed along after all data has been read. assertEquals("Response that lies about content length.", callback.mResponseAsString); assertNotNull(callback.mError); @@ -434,17 +458,13 @@ assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); List<Map.Entry<String, String>> responseHeaders = callback.mResponseInfo.getAllHeadersAsList(); - assertEquals(5, responseHeaders.size()); - assertEquals("Content-Type", responseHeaders.get(0).getKey()); - assertEquals("text/plain", responseHeaders.get(0).getValue()); - assertEquals("Access-Control-Allow-Origin", responseHeaders.get(1).getKey()); - assertEquals("*", responseHeaders.get(1).getValue()); - assertEquals("header-name", responseHeaders.get(2).getKey()); - assertEquals("header-value", responseHeaders.get(2).getValue()); - assertEquals("multi-header-name", responseHeaders.get(3).getKey()); - assertEquals("header-value1", responseHeaders.get(3).getValue()); - assertEquals("multi-header-name", responseHeaders.get(4).getKey()); - assertEquals("header-value2", responseHeaders.get(4).getValue()); + + MoreAsserts.assertContentsInOrder(responseHeaders, + new AbstractMap.SimpleEntry<>("Content-Type", "text/plain"), + new AbstractMap.SimpleEntry<>("Access-Control-Allow-Origin", "*"), + new AbstractMap.SimpleEntry<>("header-name", "header-value"), + new AbstractMap.SimpleEntry<>("multi-header-name", "header-value1"), + new AbstractMap.SimpleEntry<>("multi-header-name", "header-value2")); } @SmallTest @@ -458,39 +478,24 @@ assertEquals(2, callback.mRedirectResponseInfoList.size()); // Check first redirect (multiredirect.html -> redirect.html) + UrlResponseInfo firstExpectedResponseInfo = createUrlResponseInfo( + new String[] {NativeTestServer.getMultiRedirectURL()}, "Found", 302, 77, "Location", + "/redirect.html", "redirect-header0", "header-value"); UrlResponseInfo firstRedirectResponseInfo = callback.mRedirectResponseInfoList.get(0); - assertEquals(1, firstRedirectResponseInfo.getUrlChain().size()); - assertEquals(NativeTestServer.getMultiRedirectURL(), - firstRedirectResponseInfo.getUrlChain().get(0)); - checkResponseInfo( - firstRedirectResponseInfo, NativeTestServer.getMultiRedirectURL(), 302, "Found"); - checkResponseInfoHeader(firstRedirectResponseInfo, - "redirect-header0", "header-value"); - assertEquals(77, firstRedirectResponseInfo.getReceivedBytesCount()); + assertResponseEquals(firstExpectedResponseInfo, firstRedirectResponseInfo); // Check second redirect (redirect.html -> success.txt) - UrlResponseInfo secondRedirectResponseInfo = callback.mRedirectResponseInfoList.get(1); - assertEquals(2, secondRedirectResponseInfo.getUrlChain().size()); - assertEquals(NativeTestServer.getMultiRedirectURL(), - secondRedirectResponseInfo.getUrlChain().get(0)); - assertEquals( - NativeTestServer.getRedirectURL(), secondRedirectResponseInfo.getUrlChain().get(1)); - checkResponseInfo( - secondRedirectResponseInfo, NativeTestServer.getRedirectURL(), 302, "Found"); - checkResponseInfoHeader(secondRedirectResponseInfo, - "redirect-header", "header-value"); - assertEquals(151, secondRedirectResponseInfo.getReceivedBytesCount()); + UrlResponseInfo secondExpectedResponseInfo = createUrlResponseInfo( + new String[] {NativeTestServer.getMultiRedirectURL(), + NativeTestServer.getRedirectURL(), NativeTestServer.getSuccessURL()}, + "OK", 200, 337, "Content-Type", "text/plain", "Access-Control-Allow-Origin", "*", + "header-name", "header-value", "multi-header-name", "header-value1", + "multi-header-name", "header-value2"); - // Check final response (success.txt). - assertEquals(NativeTestServer.getSuccessURL(), mResponseInfo.getUrl()); - assertEquals(3, mResponseInfo.getUrlChain().size()); - assertEquals(NativeTestServer.getMultiRedirectURL(), mResponseInfo.getUrlChain().get(0)); - assertEquals(NativeTestServer.getRedirectURL(), mResponseInfo.getUrlChain().get(1)); - assertEquals(NativeTestServer.getSuccessURL(), mResponseInfo.getUrlChain().get(2)); + assertResponseEquals(secondExpectedResponseInfo, mResponseInfo); assertTrue(callback.mHttpResponseDataLength != 0); assertEquals(2, callback.mRedirectCount); assertEquals(callback.mResponseStep, ResponseStep.ON_SUCCEEDED); - assertEquals(337, mResponseInfo.getReceivedBytesCount()); } @SmallTest @@ -498,8 +503,9 @@ public void testMockNotFound() throws Exception { TestUrlRequestCallback callback = startAndWaitForComplete(NativeTestServer.getNotFoundURL()); - assertEquals(404, callback.mResponseInfo.getHttpStatusCode()); - assertEquals(121, callback.mResponseInfo.getReceivedBytesCount()); + UrlResponseInfo expected = createUrlResponseInfo( + new String[] {NativeTestServer.getNotFoundURL()}, "Not Found", 404, 121); + assertResponseEquals(expected, callback.mResponseInfo); assertTrue(callback.mHttpResponseDataLength != 0); assertEquals(0, callback.mRedirectCount); assertFalse(callback.mOnErrorCalled); @@ -508,6 +514,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // Java impl doesn't support MockUrlRequestJobFactory public void testMockStartAsyncError() throws Exception { final int arbitraryNetError = -3; TestUrlRequestCallback callback = @@ -523,6 +530,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // Java impl doesn't support MockUrlRequestJobFactory public void testMockReadDataSyncError() throws Exception { final int arbitraryNetError = -4; TestUrlRequestCallback callback = @@ -539,6 +547,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // Java impl doesn't support MockUrlRequestJobFactory public void testMockReadDataAsyncError() throws Exception { final int arbitraryNetError = -5; TestUrlRequestCallback callback = @@ -558,6 +567,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testMockClientCertificateRequested() throws Exception { TestUrlRequestCallback callback = startAndWaitForComplete( MockUrlRequestJobFactory.getMockUrlForClientCertificateRequest()); @@ -574,6 +584,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // Java impl doesn't support MockUrlRequestJobFactory public void testMockSSLCertificateError() throws Exception { TestUrlRequestCallback callback = startAndWaitForComplete( MockUrlRequestJobFactory.getMockUrlForSSLCertificateError()); @@ -818,8 +829,6 @@ callback.startNextRead(urlRequest); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("Unexpected read attempt.", - e.getMessage()); } // Verify reading right after start throws an assertion. Both must be @@ -833,8 +842,6 @@ callback.startNextRead(urlRequest); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("Unexpected read attempt.", - e.getMessage()); } } }; @@ -847,8 +854,6 @@ callback.startNextRead(urlRequest); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("Unexpected read attempt.", - e.getMessage()); } urlRequest.followRedirect(); callback.waitForNextStep(); @@ -866,8 +871,6 @@ callback.startNextRead(urlRequest); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("Unexpected read attempt.", - e.getMessage()); } } }; @@ -883,8 +886,6 @@ callback.startNextRead(urlRequest); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("Unexpected read attempt.", - e.getMessage()); } } @@ -903,8 +904,6 @@ urlRequest.followRedirect(); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("No redirect to follow.", - e.getMessage()); } // Try to follow a redirect just after starting the request. Has to be @@ -917,8 +916,6 @@ urlRequest.followRedirect(); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("No redirect to follow.", - e.getMessage()); } } }; @@ -935,8 +932,6 @@ urlRequest.followRedirect(); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("No redirect to follow.", - e.getMessage()); } } }; @@ -951,8 +946,6 @@ urlRequest.followRedirect(); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("No redirect to follow.", - e.getMessage()); } callback.startNextRead(urlRequest); callback.waitForNextStep(); @@ -966,8 +959,6 @@ urlRequest.followRedirect(); fail("Exception not thrown"); } catch (IllegalStateException e) { - assertEquals("No redirect to follow.", - e.getMessage()); } } @@ -992,7 +983,6 @@ builder.build().start(); fail("Exception not thrown"); } catch (IllegalArgumentException e) { - assertEquals("Requests with upload data must have a Content-Type.", e.getMessage()); } } @@ -1394,11 +1384,9 @@ @Feature({"Cronet"}) public void testUploadFailsWithoutInitializingStream() throws Exception { TestUrlRequestCallback callback = new TestUrlRequestCallback(); - UrlRequest.Builder builder = new UrlRequest.Builder(NativeTestServer.getEchoBodyURL(), - callback, callback.getExecutor(), mTestFramework.mCronetEngine); - // Shut down the test server, so connecting to it fails. Note that - // calling shutdown again during teardown is safe. - NativeTestServer.shutdownNativeTestServer(); + // The port for PTP will always refuse a TCP connection + UrlRequest.Builder builder = new UrlRequest.Builder("http://127.0.0.1:319", callback, + callback.getExecutor(), mTestFramework.mCronetEngine); TestUploadDataProvider dataProvider = new TestUploadDataProvider( TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor()); @@ -1409,12 +1397,20 @@ callback.blockForDone(); assertNull(callback.mResponseInfo); - assertEquals("Exception in CronetUrlRequest: net::ERR_CONNECTION_REFUSED", - callback.mError.getMessage()); + if (testingJavaImpl()) { + Throwable cause = callback.mError.getCause(); + assertTrue("Exception was: " + cause, cause instanceof ConnectException); + } else { + assertEquals("Exception in CronetUrlRequest: net::ERR_CONNECTION_REFUSED", + callback.mError.getMessage()); + } } private void throwOrCancel(FailureType failureType, ResponseStep failureStep, boolean expectResponseInfo, boolean expectError) { + if (Log.isLoggable("TESTING", Log.VERBOSE)) { + Log.v("TESTING", "Testing " + failureType + " during " + failureStep); + } TestUrlRequestCallback callback = new TestUrlRequestCallback(); callback.setFailure(failureType, failureStep); UrlRequest.Builder builder = new UrlRequest.Builder(NativeTestServer.getRedirectURL(), @@ -1485,6 +1481,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // No destroyed callback for tests public void testExecutorShutdown() { TestUrlRequestCallback callback = new TestUrlRequestCallback(); @@ -1583,6 +1580,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // No adapter to destroy in pure java // Regression test for crbug.com/564946. public void testDestroyUploadDataStreamAdapterOnSucceededCallback() throws Exception { TestUrlRequestCallback callback = new QuitOnSuccessCallback();
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlTest.java index e4f5e66..f807c38 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlTest.java
@@ -55,6 +55,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet // No NetLog from HttpURLConnection public void testNetLog() throws Exception { Context context = getContext(); File directory = new File(PathUtils.getDataDirectory(context));
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/GetStatusTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/GetStatusTest.java index bbd5507..c57a175 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/GetStatusTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/GetStatusTest.java
@@ -73,8 +73,9 @@ urlRequest.getStatus(statusListener1); statusListener1.waitUntilOnStatusCalled(); assertTrue(statusListener1.mOnStatusCalled); - assertTrue(statusListener1.mStatus >= Status.IDLE); - assertTrue(statusListener1.mStatus <= Status.READING_RESPONSE); + assertTrue("Status is :" + statusListener1.mStatus, statusListener1.mStatus >= Status.IDLE); + assertTrue("Status is :" + statusListener1.mStatus, + statusListener1.mStatus <= Status.READING_RESPONSE); callback.waitForNextStep(); assertEquals(ResponseStep.ON_RESPONSE_STARTED, callback.mResponseStep);
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java index 228efc0a..6b455e9 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java
@@ -8,6 +8,7 @@ import android.test.suitebuilder.annotation.SmallTest; import org.chromium.base.test.util.Feature; +import org.chromium.net.CronetTestBase.OnlyRunNativeCronet; import java.io.File; import java.util.HashMap; @@ -43,6 +44,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testCreateLegacyFactory() { HttpUrlRequestFactoryConfig config = new HttpUrlRequestFactoryConfig(); config.enableLegacyMode(true); @@ -66,6 +68,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testCreateLegacyFactoryUsingUrlRequestContextConfig() { UrlRequestContextConfig config = new UrlRequestContextConfig(); config.enableLegacyMode(true);
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java index c977541..d71bdcc 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/PkpTest.java
@@ -62,6 +62,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testErrorCodeIfPinDoesNotMatch() throws Exception { byte[] nonMatchingHash = generateSomeSha256(); addPkpSha256(mServerHost, nonMatchingHash, EXCLUDE_SUBDOMAINS, DISTANT_FUTURE); @@ -80,6 +81,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testSuccessIfPinMatches() throws Exception { // Get PKP hash of the real certificate X509Certificate cert = readCertFromFileInPemFormat(CERT_USED); @@ -102,6 +104,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testIncludeSubdomainsFlagEqualTrue() throws Exception { byte[] nonMatchingHash = generateSomeSha256(); addPkpSha256(mDomain, nonMatchingHash, INCLUDE_SUBDOMAINS, DISTANT_FUTURE); @@ -121,6 +124,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testIncludeSubdomainsFlagEqualFalse() throws Exception { byte[] nonMatchingHash = generateSomeSha256(); addPkpSha256(mDomain, nonMatchingHash, EXCLUDE_SUBDOMAINS, DISTANT_FUTURE); @@ -140,6 +144,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testSuccessIfNoPinSpecified() throws Exception { byte[] nonMatchingHash = generateSomeSha256(); addPkpSha256("otherhost.com", nonMatchingHash, INCLUDE_SUBDOMAINS, DISTANT_FUTURE); @@ -158,6 +163,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testSoonExpiringPin() throws Exception { final int tenSecondsAhead = 10; byte[] nonMatchingHash = generateSomeSha256(); @@ -177,6 +183,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testRecentlyExpiredPin() throws Exception { final int oneSecondAgo = -1; byte[] nonMatchingHash = generateSomeSha256(); @@ -195,6 +202,7 @@ */ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testPinsAreNotPersisted() throws Exception { byte[] nonMatchingHash = generateSomeSha256(); addPkpSha256(mServerHost, nonMatchingHash, EXCLUDE_SUBDOMAINS, DISTANT_FUTURE);
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java index 015a935..13df2eeb 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
@@ -10,6 +10,7 @@ import org.chromium.base.Log; import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.test.util.Feature; +import org.chromium.net.CronetTestBase.OnlyRunNativeCronet; import org.json.JSONObject; import java.io.File; @@ -63,6 +64,7 @@ @SmallTest @Feature({"Cronet"}) @SuppressWarnings("deprecation") + @OnlyRunNativeCronet public void testQuicLoadUrl_LegacyAPI() throws Exception { String[] commandLineArgs = { CronetTestFramework.LIBRARY_INIT_KEY, CronetTestFramework.LibraryInitType.LEGACY}; @@ -90,6 +92,7 @@ @LargeTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testQuicLoadUrl() throws Exception { mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, mBuilder); registerHostResolver(mTestFramework);
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/SdchTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/SdchTest.java index eaf6265..c00796c9e 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/SdchTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/SdchTest.java
@@ -8,6 +8,7 @@ import android.test.suitebuilder.annotation.SmallTest; import org.chromium.base.test.util.Feature; +import org.chromium.net.CronetTestBase.OnlyRunNativeCronet; import java.io.BufferedReader; import java.io.FileReader; @@ -69,6 +70,7 @@ @SmallTest @Feature({"Cronet"}) @SuppressWarnings("deprecation") + @OnlyRunNativeCronet public void testSdchEnabled_LegacyApi() throws Exception { setUp(Sdch.ENABLED, Api.LEGACY); String targetUrl = NativeTestServer.getSdchURL() + "/sdch/test"; @@ -98,6 +100,7 @@ @SmallTest @Feature({"Cronet"}) @SuppressWarnings("deprecation") + @OnlyRunNativeCronet public void testSdchDisabled_LegacyApi() throws Exception { setUp(Sdch.DISABLED, Api.LEGACY); // Make a request to /sdch/index. @@ -113,6 +116,7 @@ @SmallTest @Feature({"Cronet"}) @SuppressWarnings("deprecation") + @OnlyRunNativeCronet public void testDictionaryNotFound_LegacyApi() throws Exception { setUp(Sdch.ENABLED, Api.LEGACY); // Make a request to /sdch/index which advertises a bad dictionary that @@ -134,6 +138,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testSdchEnabled() throws Exception { setUp(Sdch.ENABLED, Api.ASYNC); String targetUrl = NativeTestServer.getSdchURL() + "/sdch/test"; @@ -187,6 +192,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testSdchDisabled() throws Exception { setUp(Sdch.DISABLED, Api.ASYNC); // Make a request to /sdch. @@ -200,6 +206,7 @@ @SmallTest @Feature({"Cronet"}) + @OnlyRunNativeCronet public void testDictionaryNotFound() throws Exception { setUp(Sdch.ENABLED, Api.ASYNC); // Make a request to /sdch/index which advertises a bad dictionary that
diff --git a/components/exo/buffer_unittest.cc b/components/exo/buffer_unittest.cc index 21a2eea..bf320f3 100644 --- a/components/exo/buffer_unittest.cc +++ b/components/exo/buffer_unittest.cc
@@ -29,9 +29,8 @@ TEST_F(BufferTest, ReleaseCallback) { gfx::Size buffer_size(256, 256); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); // Set the release callback. int release_call_count = 0; @@ -53,9 +52,8 @@ TEST_F(BufferTest, IsLost) { gfx::Size buffer_size(256, 256); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); // Acquire a texture mailbox for the contents of the buffer. cc::TextureMailbox texture_mailbox;
diff --git a/components/exo/keyboard_unittest.cc b/components/exo/keyboard_unittest.cc index 46e37b0..3cdb4bc 100644 --- a/components/exo/keyboard_unittest.cc +++ b/components/exo/keyboard_unittest.cc
@@ -41,9 +41,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit(); @@ -81,9 +80,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit(); @@ -111,9 +109,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit(); @@ -150,9 +147,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit();
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc index 226da85a..df3b1a7 100644 --- a/components/exo/pointer_unittest.cc +++ b/components/exo/pointer_unittest.cc
@@ -38,9 +38,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit(); @@ -62,9 +61,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit(); @@ -89,9 +87,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit(); @@ -117,9 +114,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit(); @@ -147,9 +143,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit();
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc index 3ba3a7d5..333c81d 100644 --- a/components/exo/surface_unittest.cc +++ b/components/exo/surface_unittest.cc
@@ -22,9 +22,8 @@ TEST_F(SurfaceTest, Attach) { gfx::Size buffer_size(256, 256); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); // Set the release callback that will be run when buffer is no longer in use. int release_buffer_call_count = 0; @@ -50,9 +49,8 @@ TEST_F(SurfaceTest, Damage) { gfx::Size buffer_size(256, 256); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); scoped_ptr<Surface> surface(new Surface); // Attach the buffer to the surface. This will update the pending bounds of @@ -93,9 +91,8 @@ TEST_F(SurfaceTest, SetBufferScale) { gfx::Size buffer_size(512, 512); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); scoped_ptr<Surface> surface(new Surface); // Attach the buffer to the surface. This will update the pending bounds of
diff --git a/components/exo/touch_unittest.cc b/components/exo/touch_unittest.cc index afe8fcb..afdeee4 100644 --- a/components/exo/touch_unittest.cc +++ b/components/exo/touch_unittest.cc
@@ -44,9 +44,9 @@ new ShellSurface(bottom_surface.get())); bottom_shell_surface->SetToplevel(); gfx::Size bottom_buffer_size(10, 10); - scoped_ptr<Buffer> bottom_buffer(new Buffer( - exo_test_helper()->CreateGpuMemoryBuffer(bottom_buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> bottom_buffer( + new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(bottom_buffer_size), + GL_TEXTURE_2D)); bottom_surface->Attach(bottom_buffer.get()); bottom_surface->Commit(); ash::wm::CenterWindow(bottom_shell_surface->GetWidget()->GetNativeWindow()); @@ -56,9 +56,9 @@ new ShellSurface(top_surface.get())); top_shell_surface->SetToplevel(); gfx::Size top_buffer_size(8, 8); - scoped_ptr<Buffer> top_buffer(new Buffer( - exo_test_helper()->CreateGpuMemoryBuffer(top_buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> top_buffer( + new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(top_buffer_size), + GL_TEXTURE_2D)); top_surface->Attach(top_buffer.get()); top_surface->Commit(); ash::wm::CenterWindow(top_shell_surface->GetWidget()->GetNativeWindow()); @@ -91,9 +91,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit(); @@ -124,9 +123,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit(); @@ -163,9 +161,8 @@ scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->SetToplevel(); gfx::Size buffer_size(10, 10); - scoped_ptr<Buffer> buffer( - new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), - GL_TEXTURE_2D)); + scoped_ptr<Buffer> buffer(new Buffer( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D)); surface->Attach(buffer.get()); surface->Commit();
diff --git a/components/mus/BUILD.gn b/components/mus/BUILD.gn index e89df7e..2c96d08 100644 --- a/components/mus/BUILD.gn +++ b/components/mus/BUILD.gn
@@ -90,4 +90,8 @@ "//ui/events/platform/x11", ] } + + if (use_ozone) { + deps += [ "//ui/ozone:ozone" ] + } }
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc index ebc9f39..c51fe59 100644 --- a/components/mus/mus_app.cc +++ b/components/mus/mus_app.cc
@@ -28,6 +28,8 @@ #include <X11/Xlib.h> #include "base/command_line.h" #include "ui/platform_window/x11/x11_window.h" +#elif defined(USE_OZONE) +#include "ui/ozone/public/ozone_platform.h" #endif using mojo::ApplicationConnection; @@ -60,6 +62,14 @@ } #endif +#if defined(USE_OZONE) + // The ozone platform can provide its own event source. So initialize the + // platform before creating the default event source. + // TODO(rjkroege): Add tracing here. + ui::OzonePlatform::InitializeForUI(); + ui::OzonePlatform::InitializeForGPU(); +#endif + bool hardware_rendering_available = true; #if !defined(OS_ANDROID) hardware_rendering_available = gfx::GLSurface::InitializeOneOff();
diff --git a/components/mus/ws/BUILD.gn b/components/mus/ws/BUILD.gn index fd9918d..f49255c 100644 --- a/components/mus/ws/BUILD.gn +++ b/components/mus/ws/BUILD.gn
@@ -86,6 +86,10 @@ "//ui/platform_window", "//ui/platform_window:platform_impls", ] + + if (use_ozone) { + deps += [ "//ui/ozone:ozone" ] + } } source_set("test_support") {
diff --git a/components/mus/ws/display_manager.cc b/components/mus/ws/display_manager.cc index 1d53eb1d2..1815dd5b 100644 --- a/components/mus/ws/display_manager.cc +++ b/components/mus/ws/display_manager.cc
@@ -43,6 +43,8 @@ #include "ui/platform_window/x11/x11_window.h" #elif defined(OS_ANDROID) #include "ui/platform_window/android/platform_window_android.h" +#elif defined(USE_OZONE) +#include "ui/ozone/public/ozone_platform.h" #endif using mojo::Rect; @@ -191,7 +193,10 @@ #elif defined(USE_X11) platform_window_.reset(new ui::X11Window(this)); #elif defined(OS_ANDROID) - platform_window_.reset(new ui::PlatformWindowAndroid(this)); + platform_window_. reset(new ui::PlatformWindowAndroid(this)); +#elif defined(USE_OZONE) + platform_window_ = + ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds); #else NOTREACHED() << "Unsupported platform"; #endif
diff --git a/components/nacl/broker/BUILD.gn b/components/nacl/broker/BUILD.gn index 23d8ba18..390f239 100644 --- a/components/nacl/broker/BUILD.gn +++ b/components/nacl/broker/BUILD.gn
@@ -151,6 +151,7 @@ "//components/policy", "//content/public/common:static_switches", "//ipc", + "//third_party/kasko:kasko_features", ] } }
diff --git a/components/nacl/renderer/plugin/pnacl_coordinator.cc b/components/nacl/renderer/plugin/pnacl_coordinator.cc index 28caad5..f80a465 100644 --- a/components/nacl/renderer/plugin/pnacl_coordinator.cc +++ b/components/nacl/renderer/plugin/pnacl_coordinator.cc
@@ -14,8 +14,6 @@ #include "components/nacl/renderer/plugin/pnacl_translate_thread.h" #include "components/nacl/renderer/plugin/service_runtime.h" #include "components/nacl/renderer/plugin/temporary_file.h" -#include "native_client/src/include/portability_io.h" -#include "native_client/src/trusted/service_runtime/include/sys/stat.h" #include "ppapi/c/pp_bool.h" #include "ppapi/c/pp_errors.h" @@ -202,13 +200,7 @@ pexe_bytes_compiled_, expected_pexe_size_); } - nacl_abi_off_t nexe_size = 0; - struct nacl_abi_stat stbuf; - struct NaClDesc* desc = temp_nexe_file_->read_wrapper()->desc(); - if (0 == (*((struct NaClDescVtbl const *)desc->base.vtbl)->Fstat)(desc, - &stbuf)) { - nexe_size = stbuf.nacl_abi_st_size; - } + int64_t nexe_size = temp_nexe_file_->GetLength(); // The nexe is written to the temp_nexe_file_. We must Reset() the file // pointer to be able to read it again from the beginning. temp_nexe_file_->Reset();
diff --git a/components/nacl/renderer/plugin/temporary_file.cc b/components/nacl/renderer/plugin/temporary_file.cc index bd942c5..579352d5 100644 --- a/components/nacl/renderer/plugin/temporary_file.cc +++ b/components/nacl/renderer/plugin/temporary_file.cc
@@ -54,13 +54,17 @@ } bool TempFile::Reset() { - // Use the read_wrapper_ to reset the file pos. The write_wrapper_ is also - // backed by the same file, so it should also reset. - CHECK(read_wrapper_); - nacl_off64_t newpos = read_wrapper_->Seek(0, SEEK_SET); + // file_handle_, read_wrapper_ and write_wrapper_ are all backed by the + // same file handle/descriptor, so resetting the seek position of one + // will reset them all. + int64_t newpos = file_handle_.Seek(base::File::FROM_BEGIN, 0); return newpos == 0; } +int64_t TempFile::GetLength() { + return file_handle_.GetLength(); +} + PP_FileHandle TempFile::TakeFileHandle() { DCHECK(file_handle_.IsValid()); return file_handle_.TakePlatformFile();
diff --git a/components/nacl/renderer/plugin/temporary_file.h b/components/nacl/renderer/plugin/temporary_file.h index 4e4e9af..21663e3 100644 --- a/components/nacl/renderer/plugin/temporary_file.h +++ b/components/nacl/renderer/plugin/temporary_file.h
@@ -51,6 +51,9 @@ // Resets file position of the handle, for reuse. bool Reset(); + // Returns the current size of this file. + int64_t GetLength(); + // Accessors. // The nacl::DescWrapper* for the writeable version of the file. nacl::DescWrapper* write_wrapper() { return write_wrapper_.get(); }
diff --git a/components/web_view/test_runner/register_local_aliases.cc b/components/web_view/test_runner/register_local_aliases.cc index add0a510..4d2e167 100644 --- a/components/web_view/test_runner/register_local_aliases.cc +++ b/components/web_view/test_runner/register_local_aliases.cc
@@ -7,7 +7,7 @@ namespace mojo { namespace runner { -void RegisterLocalAliases(mojo::package_manager::PackageManagerImpl* manager) { +void RegisterLocalAliases(shell::PackageManagerImpl* manager) { } } // namespace runner
diff --git a/content/app/DEPS b/content/app/DEPS index f4792db..7745238 100644 --- a/content/app/DEPS +++ b/content/app/DEPS
@@ -3,6 +3,7 @@ "+content", "+device/battery", "+device/bluetooth", + "+device/usb", "+device/vibration", # For loading V8's initial snapshot from external files. "+gin/public/isolate_holder.h",
diff --git a/content/app/android/library_loader_hooks.cc b/content/app/android/library_loader_hooks.cc index 487d973..21e51b3 100644 --- a/content/app/android/library_loader_hooks.cc +++ b/content/app/android/library_loader_hooks.cc
@@ -26,6 +26,7 @@ #include "content/public/common/content_switches.h" #include "content/public/common/result_codes.h" #include "device/bluetooth/android/bluetooth_jni_registrar.h" +#include "device/usb/android/usb_jni_registrar.h" #include "media/base/android/media_jni_registrar.h" #include "media/midi/midi_jni_registrar.h" #include "net/android/net_jni_registrar.h" @@ -75,6 +76,9 @@ if (!device::android::RegisterBluetoothJni(env)) return false; + if (!device::android::RegisterUsbJni(env)) + return false; + if (!media::RegisterJni(env)) return false;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 624eb3b..7f22a37 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -41,9 +41,9 @@ "//mojo/application/public/cpp:cpp_for_chromium", "//mojo/application/public/interfaces", "//mojo/common", - "//mojo/package_manager", "//mojo/public/cpp/bindings", "//mojo/shell", + "//mojo/shell/package_manager", "//net", "//net:extras", "//skia",
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc index b30463c..2ca1b07d 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -376,6 +376,11 @@ CommitPending(); WebContentsObserver::Observe(WebContents::FromRenderFrameHost(host)); + if (web_contents() && web_contents()->GetCrashedStatus() != + base::TERMINATION_STATUS_STILL_RUNNING) { + current_frame_crashed_ = true; + } + g_instances.Get().push_back(this); AddRef(); // Balanced in RenderFrameHostDestroyed. }
diff --git a/content/browser/frame_host/DEPS b/content/browser/frame_host/DEPS index 09569cb..a6068f73 100644 --- a/content/browser/frame_host/DEPS +++ b/content/browser/frame_host/DEPS
@@ -5,6 +5,8 @@ "-content/public/browser/web_contents.h", "-content/public/browser/web_contents_delegate.h", "-content/public/browser/web_contents_view.h", + + "+third_party/kasko", ] specific_include_rules = {
diff --git a/content/browser/frame_host/debug_urls.cc b/content/browser/frame_host/debug_urls.cc index f095f8e..f3190a74 100644 --- a/content/browser/frame_host/debug_urls.cc +++ b/content/browser/frame_host/debug_urls.cc
@@ -22,6 +22,7 @@ #include "content/public/common/content_constants.h" #include "content/public/common/url_constants.h" #include "ppapi/proxy/ppapi_messages.h" +#include "third_party/kasko/kasko_features.h" #include "url/gurl.h" #if defined(ENABLE_PLUGINS) @@ -42,7 +43,7 @@ const char kAsanCorruptHeap[] = "/browser-corrupt-heap"; #endif -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) // Define the Kasko debug URLs. const char kKaskoCrashDomain[] = "kasko"; const char kKaskoSendReport[] = "/send-report"; @@ -66,7 +67,7 @@ } bool IsKaskoDebugURL(const GURL& url) { -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) return (url.is_valid() && url.SchemeIs(kChromeUIScheme) && url.DomainIs(kKaskoCrashDomain) && url.path() == kKaskoSendReport); @@ -76,7 +77,7 @@ } void HandleKaskoDebugURL() { -#if defined(KASKO) +#if BUILDFLAG(ENABLE_KASKO) // Signature of the exported crash key setting function. using SetCrashKeyValueImplPtr = void(__cdecl *)(const wchar_t*, const wchar_t*);
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc index e20b012..bb33977 100644 --- a/content/browser/media/android/browser_media_player_manager.cc +++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -401,7 +401,11 @@ } bool BrowserMediaPlayerManager::RequestPlay(int player_id, - base::TimeDelta duration) { + base::TimeDelta duration, + bool has_audio) { + if (!has_audio) + return true; + MediaSession::Type media_session_type = duration == base::TimeDelta() || duration.InSeconds() > kMinimumDurationForContentInSeconds
diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h index 061878bd..981c240 100644 --- a/content/browser/media/android/browser_media_player_manager.h +++ b/content/browser/media/android/browser_media_player_manager.h
@@ -104,7 +104,8 @@ media::MediaUrlInterceptor* GetMediaUrlInterceptor() override; media::MediaPlayerAndroid* GetFullscreenPlayer() override; media::MediaPlayerAndroid* GetPlayer(int player_id) override; - bool RequestPlay(int player_id, base::TimeDelta duration) override; + bool RequestPlay(int player_id, base::TimeDelta duration, + bool has_audio) override; #if defined(VIDEO_HOLE) void AttachExternalVideoSurface(int player_id, jobject surface); void DetachExternalVideoSurface(int player_id);
diff --git a/content/browser/media/webrtc_media_recorder_browsertest.cc b/content/browser/media/webrtc_media_recorder_browsertest.cc index 8af0141..381f228 100644 --- a/content/browser/media/webrtc_media_recorder_browsertest.cc +++ b/content/browser/media/webrtc_media_recorder_browsertest.cc
@@ -13,6 +13,7 @@ #if defined(OS_ANDROID) // TODO(cpaulin): when crbug.com/561068 is fixed, enable this test +// on android platform. #define MAYBE_WebRtcMediaRecorderTest DISABLED_WebRtcMediaRecorderTest #else #define MAYBE_WebRtcMediaRecorderTest WebRtcMediaRecorderTest @@ -20,8 +21,7 @@ namespace { -// Blink features necessary to run the test. -static const char kBlinkFeaturesNeeded[] = "GetUserMedia,MediaRecorder"; +static const char kBlinkFeaturesNeeded[] = "GetUserMedia"; static const char kMediaRecorderHtmlFile[] = "/media/mediarecorder_test.html"; @@ -76,7 +76,7 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, MediaRecorderNoResumeWhenRecorderInactive) { - MakeTypicalCall("testNoResumeWhileRecorderInactive();", + MakeTypicalCall("testIllegalResumeThrowsDOMError();", kMediaRecorderHtmlFile); } @@ -132,7 +132,12 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, MediaRecorderIllegalRequestDataThrowsDOMError) { MakeTypicalCall("testIllegalRequestDataThrowsDOMError();", - kMediaRecorderHtmlFile); + kMediaRecorderHtmlFile); +} + +IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, + MediaRecorderPeerConnection) { + MakeTypicalCall("testRecordRemotePeerConnection();", kMediaRecorderHtmlFile); } } // namespace content
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc index 7fff88e..6cdaeb0c 100644 --- a/content/browser/mojo/mojo_shell_context.cc +++ b/content/browser/mojo/mojo_shell_context.cc
@@ -22,12 +22,12 @@ #include "content/public/common/service_registry.h" #include "mojo/application/public/cpp/application_delegate.h" #include "mojo/common/url_type_converters.h" -#include "mojo/package_manager/package_manager_impl.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/string.h" #include "mojo/shell/application_loader.h" #include "mojo/shell/connect_to_application_params.h" #include "mojo/shell/identity.h" +#include "mojo/shell/package_manager/package_manager_impl.h" #include "mojo/shell/static_application_loader.h" #if defined(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS) || \ @@ -206,8 +206,8 @@ // Construct with an empty filepath since mojo: urls can't be registered now // the url scheme registry is locked. - scoped_ptr<mojo::package_manager::PackageManagerImpl> package_manager( - new mojo::package_manager::PackageManagerImpl(base::FilePath(), nullptr)); + scoped_ptr<mojo::shell::PackageManagerImpl> package_manager( + new mojo::shell::PackageManagerImpl(base::FilePath(), nullptr)); application_manager_.reset( new mojo::shell::ApplicationManager(std::move(package_manager)));
diff --git a/content/browser/quota/quota_database_unittest.cc b/content/browser/quota/quota_database_unittest.cc index 6bf0cd9..026a46a4 100644 --- a/content/browser/quota/quota_database_unittest.cc +++ b/content/browser/quota/quota_database_unittest.cc
@@ -367,28 +367,26 @@ EXPECT_TRUE(db.RegisterInitialOriginInfo(origins, kStorageTypeTemporary)); - int used_count = -1; - EXPECT_TRUE(db.FindOriginUsedCount(GURL("http://a/"), - kStorageTypeTemporary, - &used_count)); - EXPECT_EQ(0, used_count); + QuotaDatabase::OriginInfoTableEntry info; + info.used_count = -1; + EXPECT_TRUE(db.GetOriginInfo( + GURL("http://a/"), kStorageTypeTemporary, &info)); + EXPECT_EQ(0, info.used_count); EXPECT_TRUE(db.SetOriginLastAccessTime( GURL("http://a/"), kStorageTypeTemporary, base::Time::FromDoubleT(1.0))); - used_count = -1; - EXPECT_TRUE(db.FindOriginUsedCount(GURL("http://a/"), - kStorageTypeTemporary, - &used_count)); - EXPECT_EQ(1, used_count); + info.used_count = -1; + EXPECT_TRUE(db.GetOriginInfo( + GURL("http://a/"), kStorageTypeTemporary, &info)); + EXPECT_EQ(1, info.used_count); EXPECT_TRUE(db.RegisterInitialOriginInfo(origins, kStorageTypeTemporary)); - used_count = -1; - EXPECT_TRUE(db.FindOriginUsedCount(GURL("http://a/"), - kStorageTypeTemporary, - &used_count)); - EXPECT_EQ(1, used_count); + info.used_count = -1; + EXPECT_TRUE(db.GetOriginInfo( + GURL("http://a/"), kStorageTypeTemporary, &info)); + EXPECT_EQ(1, info.used_count); } template <typename EntryType>
diff --git a/content/browser/tracing/memory_tracing_browsertest.cc b/content/browser/tracing/memory_tracing_browsertest.cc index 13b0923..2e2255d 100644 --- a/content/browser/tracing/memory_tracing_browsertest.cc +++ b/content/browser/tracing/memory_tracing_browsertest.cc
@@ -161,10 +161,15 @@ DisableTracing(); } +#if defined(OS_WIN) +#define MAYBE_RendererInitiatedSingleDump DISABLED_RendererInitiatedSingleDump +#else +#define MAYBE_RendererInitiatedSingleDump RendererInitiatedSingleDump +#endif // Checks that a memory dump initiated from a renderer thread ends up in a // single dump even in single process mode. IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest, - RendererInitiatedSingleDump) { + MAYBE_RendererInitiatedSingleDump) { Navigate(shell()); EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_,_)).WillOnce(Return(true)); @@ -177,7 +182,13 @@ DisableTracing(); } -IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest, ManyInterleavedDumps) { +#if defined(OS_WIN) +#define MAYBE_ManyInterleavedDumps DISABLED_ManyInterleavedDumps +#else +#define MAYBE_ManyInterleavedDumps ManyInterleavedDumps +#endif +IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest, + MAYBE_ManyInterleavedDumps) { Navigate(shell()); EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_,_))
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc index 57ef248..c96c5c2 100644 --- a/content/child/blink_platform_impl.cc +++ b/content/child/blink_platform_impl.cc
@@ -1252,10 +1252,6 @@ return static_cast<size_t>(base::SysInfo::AmountOfVirtualMemoryMB()); } -bool BlinkPlatformImpl::isLowEndDeviceMode() { - return base::SysInfo::IsLowEndDevice(); -} - size_t BlinkPlatformImpl::numberOfProcessors() { return static_cast<size_t>(base::SysInfo::NumberOfProcessors()); }
diff --git a/content/child/blink_platform_impl.h b/content/child/blink_platform_impl.h index 4c3c26f..94f4f38 100644 --- a/content/child/blink_platform_impl.h +++ b/content/child/blink_platform_impl.h
@@ -84,7 +84,6 @@ size_t actualMemoryUsageMB() override; size_t physicalMemoryMB() override; size_t virtualMemoryLimitMB() override; - bool isLowEndDeviceMode() override; size_t numberOfProcessors() override; blink::WebDiscardableMemory* allocateAndLockDiscardableMemory(
diff --git a/content/common/gpu/image_transport_surface_overlay_mac.mm b/content/common/gpu/image_transport_surface_overlay_mac.mm index 594a6d1..03c2eedc 100644 --- a/content/common/gpu/image_transport_surface_overlay_mac.mm +++ b/content/common/gpu/image_transport_surface_overlay_mac.mm
@@ -206,9 +206,6 @@ return; [ca_layer setContents:nil]; [ca_layer removeFromSuperlayer]; - [ca_layer setBorderWidth:0]; - [ca_layer setBorderColor:CGColorGetConstantColor(kCGColorClear)]; - [ca_layer setBackgroundColor:CGColorGetConstantColor(kCGColorClear)]; ca_layer.reset(); } @@ -465,7 +462,7 @@ GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; if (use_remote_layer_api_) { params.ca_context_id = [ca_context_ contextId]; - } else { + } else if (current_root_plane_.get()) { params.io_surface.reset( IOSurfaceCreateMachPort(current_root_plane_->io_surface)); }
diff --git a/content/common/gpu/media/android_copying_backing_strategy.cc b/content/common/gpu/media/android_copying_backing_strategy.cc index 9ca413e..b58cf50 100644 --- a/content/common/gpu/media/android_copying_backing_strategy.cc +++ b/content/common/gpu/media/android_copying_backing_strategy.cc
@@ -132,4 +132,11 @@ media_codec_ = codec; } +void AndroidCopyingBackingStrategy::OnFrameAvailable() { + // TODO(liberato): crbug.com/574948 . The OnFrameAvailable logic can be + // moved into AVDA, and we should wait for it before doing the copy. + // Because there were some test failures, we don't do this now but + // instead preserve the old behavior. +} + } // namespace content
diff --git a/content/common/gpu/media/android_copying_backing_strategy.h b/content/common/gpu/media/android_copying_backing_strategy.h index cbecded..ecb50b26 100644 --- a/content/common/gpu/media/android_copying_backing_strategy.h +++ b/content/common/gpu/media/android_copying_backing_strategy.h
@@ -41,6 +41,7 @@ void CodecChanged( media::VideoCodecBridge*, const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; + void OnFrameAvailable() override; private: // Used for copy the texture from surface texture to picture buffers.
diff --git a/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc b/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc index b2fa8105..6b05495cc 100644 --- a/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc +++ b/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc
@@ -184,4 +184,8 @@ } } +void AndroidDeferredRenderingBackingStrategy::OnFrameAvailable() { + shared_state_->SignalFrameAvailable(); +} + } // namespace content
diff --git a/content/common/gpu/media/android_deferred_rendering_backing_strategy.h b/content/common/gpu/media/android_deferred_rendering_backing_strategy.h index 734d99e..7fc13eb 100644 --- a/content/common/gpu/media/android_deferred_rendering_backing_strategy.h +++ b/content/common/gpu/media/android_deferred_rendering_backing_strategy.h
@@ -49,6 +49,7 @@ void CodecChanged( media::VideoCodecBridge*, const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; + void OnFrameAvailable() override; private: // Release any codec buffer that is associated with the given picture buffer
diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc index 2cc7c32..1ce513f8 100644 --- a/content/common/gpu/media/android_video_decode_accelerator.cc +++ b/content/common/gpu/media/android_video_decode_accelerator.cc
@@ -89,6 +89,57 @@ return base::TimeDelta::FromSeconds(1); } +// Handle OnFrameAvailable callbacks safely. Since they occur asynchronously, +// we take care that the AVDA that wants them still exists. A WeakPtr to +// the AVDA would be preferable, except that OnFrameAvailable callbacks can +// occur off the gpu main thread. We also can't guarantee when the +// SurfaceTexture will quit sending callbacks to coordinate with the +// destruction of the AVDA, so we have a separate object that the cb can own. +class AndroidVideoDecodeAccelerator::OnFrameAvailableHandler + : public base::RefCountedThreadSafe<OnFrameAvailableHandler> { + public: + // We do not retain ownership of |owner|. It must remain valid until + // after ClearOwner() is called. This will register with + // |surface_texture| to receive OnFrameAvailable callbacks. + OnFrameAvailableHandler( + AndroidVideoDecodeAccelerator* owner, + const scoped_refptr<gfx::SurfaceTexture>& surface_texture) + : owner_(owner) { + // Note that the callback owns a strong ref to us. + surface_texture->SetFrameAvailableCallbackOnAnyThread( + base::Bind(&OnFrameAvailableHandler::OnFrameAvailable, + scoped_refptr<OnFrameAvailableHandler>(this))); + } + + // Forget about our owner, which is required before one deletes it. + // No further callbacks will happen once this completes. + void ClearOwner() { + base::AutoLock lock(lock_); + // No callback can happen until we release the lock. + owner_ = nullptr; + } + + // Call back into our owner if it hasn't been deleted. + void OnFrameAvailable() { + base::AutoLock auto_lock(lock_); + // |owner_| can't be deleted while we have the lock. + if (owner_) + owner_->OnFrameAvailable(); + } + + private: + friend class base::RefCountedThreadSafe<OnFrameAvailableHandler>; + virtual ~OnFrameAvailableHandler() {} + + // Protects changes to owner_. + base::Lock lock_; + + // AVDA that wants the OnFrameAvailable callback. + AndroidVideoDecodeAccelerator* owner_; + + DISALLOW_COPY_AND_ASSIGN(OnFrameAvailableHandler); +}; + AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator( const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, const base::Callback<bool(void)>& make_context_current) @@ -155,6 +206,8 @@ strategy_->Initialize(this); surface_texture_ = strategy_->CreateSurfaceTexture(); + on_frame_available_handler_ = + new OnFrameAvailableHandler(this, surface_texture_); if (!ConfigureMediaCodec()) { LOG(ERROR) << "Failed to create MediaCodec instance."; @@ -588,6 +641,13 @@ DCHECK(thread_checker_.CalledOnValidThread()); strategy_->Cleanup(output_picture_buffers_); + + // If we have an OnFrameAvailable handler, tell it that we're going away. + if (on_frame_available_handler_) { + on_frame_available_handler_->ClearOwner(); + on_frame_available_handler_ = nullptr; + } + weak_this_factory_.InvalidateWeakPtrs(); if (media_codec_) { io_timer_.Stop(); @@ -614,6 +674,12 @@ return gl_decoder_; } +void AndroidVideoDecodeAccelerator::OnFrameAvailable() { + // Remember: this may be on any thread. + DCHECK(strategy_); + strategy_->OnFrameAvailable(); +} + void AndroidVideoDecodeAccelerator::PostError( const ::tracked_objects::Location& from_here, media::VideoDecodeAccelerator::Error error) {
diff --git a/content/common/gpu/media/android_video_decode_accelerator.h b/content/common/gpu/media/android_video_decode_accelerator.h index 0d09062e..8cda7d5 100644 --- a/content/common/gpu/media/android_video_decode_accelerator.h +++ b/content/common/gpu/media/android_video_decode_accelerator.h
@@ -84,6 +84,10 @@ // per-image cleanup is needed. virtual void CodecChanged(media::VideoCodecBridge* codec, const OutputBufferMap& buffer_map) = 0; + + // Notify the strategy that a frame is available. This callback can happen + // on any thread at any time. + virtual void OnFrameAvailable() = 0; }; AndroidVideoDecodeAccelerator( @@ -113,6 +117,10 @@ static media::VideoDecodeAccelerator::Capabilities GetCapabilities(); + // Notifies about SurfaceTexture::OnFrameAvailable. This can happen on any + // thread at any time! + void OnFrameAvailable(); + private: enum State { NO_ERROR, @@ -243,6 +251,10 @@ // Backing strategy that we'll use to connect PictureBuffers to frames. scoped_ptr<BackingStrategy> strategy_; + // Helper class that manages asynchronous OnFrameAvailable callbacks. + class OnFrameAvailableHandler; + scoped_refptr<OnFrameAvailableHandler> on_frame_available_handler_; + // Time at which we last did useful work on io_timer_. base::TimeTicks most_recent_work_;
diff --git a/content/common/gpu/media/avda_codec_image.cc b/content/common/gpu/media/avda_codec_image.cc index 4587bb40..e77d15df 100644 --- a/content/common/gpu/media/avda_codec_image.cc +++ b/content/common/gpu/media/avda_codec_image.cc
@@ -6,6 +6,7 @@ #include <string.h> +#include "base/metrics/histogram_macros.h" #include "content/common/gpu/media/avda_shared_state.h" #include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/context_state.h" @@ -132,8 +133,12 @@ // to prevent doing lots of work on the drawing path, we skip it. // The decoder buffer was still pending. - // This must be synchronous. + // This must be synchronous, so wait for OnFrameAvailable. media_codec_->ReleaseOutputBuffer(codec_buffer_index_, true); + { + SCOPED_UMA_HISTOGRAM_TIMER("Media.AvdaCodecImage.WaitTimeForFrame"); + shared_state_->WaitForFrameAvailable(); + } // Don't bother to check if we're rendered again. codec_buffer_index_ = -1;
diff --git a/content/common/gpu/media/avda_shared_state.h b/content/common/gpu/media/avda_shared_state.h index 474037d..f0996f6 100644 --- a/content/common/gpu/media/avda_shared_state.h +++ b/content/common/gpu/media/avda_shared_state.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_COMMON_GPU_AVDA_SHARED_STATE_H_ #define CONTENT_COMMON_GPU_AVDA_SHARED_STATE_H_ +#include "base/synchronization/waitable_event.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "media/base/android/sdk_media_codec_bridge.h" #include "ui/gl/gl_image.h" @@ -22,7 +23,8 @@ // there's an issue with virtual gl contexts. class AVDASharedState : public base::RefCounted<AVDASharedState> { public: - AVDASharedState() : surface_texture_service_id_(0) {} + AVDASharedState() + : surface_texture_service_id_(0), frame_available_event_(false, false) {} GLint surface_texture_service_id() const { return surface_texture_service_id_; @@ -32,11 +34,18 @@ surface_texture_service_id_ = id; } + void SignalFrameAvailable() { frame_available_event_.Signal(); } + + void WaitForFrameAvailable() { frame_available_event_.Wait(); } + private: // Platform gl texture Id for |surface_texture_|. This will be zero if // and only if |texture_owner_| is null. GLint surface_texture_service_id_; + // For signalling OnFrameAvailable(). + base::WaitableEvent frame_available_event_; + protected: virtual ~AVDASharedState() {}
diff --git a/content/content.gyp b/content/content.gyp index cdc758a..ecf8e4d3 100644 --- a/content/content.gyp +++ b/content/content.gyp
@@ -429,6 +429,7 @@ '../base/base.gyp:base', '../device/battery/battery.gyp:device_battery_java', '../device/bluetooth/bluetooth.gyp:device_bluetooth_java', + '../device/usb/usb.gyp:device_usb_java', '../device/vibration/vibration.gyp:device_vibration_java', '../media/media.gyp:media_java', '../mojo/mojo_base.gyp:mojo_application_bindings',
diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 25ef44d6..bc4a497 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi
@@ -24,6 +24,7 @@ '../skia/skia.gyp:skia', '../skia/skia.gyp:skia_mojo', '../sql/sql.gyp:sql', + '../third_party/kasko/kasko.gyp:kasko_features', '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings', '../third_party/re2/re2.gyp:re2', '../third_party/zlib/google/zip.gyp:zip', @@ -1871,6 +1872,7 @@ '../components/mime_util/mime_util.gyp:mime_util', '../components/scheduler/scheduler.gyp:scheduler_common', '../device/bluetooth/bluetooth.gyp:device_bluetooth', + '../device/usb/usb.gyp:device_usb', '../gin/gin.gyp:gin', '../net/net.gyp:http_server', '../storage/storage_browser.gyp:storage',
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index bea70b9e..e726c463 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -35,6 +35,7 @@ "//device/battery:mojo_bindings_java", "//device/battery/android:battery_monitor_android", "//device/bluetooth:java", + "//device/usb:java", "//device/vibration:mojo_bindings_java", "//device/vibration/android:vibration_manager_android", "//media/base/android:media_java",
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java index dda203e57e..459b9a9 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
@@ -6,9 +6,11 @@ import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; +import android.test.suitebuilder.annotation.LargeTest; + import junit.framework.Assert; -import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.UrlUtils; import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; @@ -86,12 +88,9 @@ /** * Tests that showing a select popup and having the page reload while the popup is showing does * not assert. - * - * @LargeTest - * @Feature({"Browser"}) - * BUG 172967 */ - @DisabledTest + @LargeTest + @Feature({"Browser"}) public void testSeparateClicksAreRegisteredOnReload() throws InterruptedException, Exception, Throwable { // Load the test page.
diff --git a/content/renderer/gpu/mailbox_output_surface.cc b/content/renderer/gpu/mailbox_output_surface.cc index 19a7efdb..0b715987 100644 --- a/content/renderer/gpu/mailbox_output_surface.cc +++ b/content/renderer/gpu/mailbox_output_surface.cc
@@ -207,9 +207,15 @@ GL_NO_ERROR); frame->gl_frame_data->mailbox = current_backing_.mailbox; - context_provider_->ContextGL()->Flush(); - frame->gl_frame_data->sync_token = - gpu::SyncToken(context_provider_->ContextGL()->InsertSyncPointCHROMIUM()); + + gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); + + const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM(); + gl->Flush(); + + gl->GenSyncTokenCHROMIUM(fence_sync, + frame->gl_frame_data->sync_token.GetData()); + CompositorOutputSurface::SwapBuffers(frame); pending_textures_.push_back(current_backing_);
diff --git a/content/renderer/media/cdm/pepper_cdm_wrapper_impl.cc b/content/renderer/media/cdm/pepper_cdm_wrapper_impl.cc index 8928f84..8d24724d 100644 --- a/content/renderer/media/cdm/pepper_cdm_wrapper_impl.cc +++ b/content/renderer/media/cdm/pepper_cdm_wrapper_impl.cc
@@ -14,6 +14,7 @@ #include "third_party/WebKit/public/web/WebElement.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebHelperPlugin.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebPlugin.h" #include "third_party/WebKit/public/web/WebPluginContainer.h" #include "third_party/WebKit/public/web/WebView.h" @@ -29,6 +30,18 @@ const std::string& pluginType, const GURL& security_origin) { DCHECK(frame); + + // The frame security origin could be different from the origin where the CDM + // creation was initiated, e.g. due to navigation. + // Note: The code will continue after navigation to the "same" origin, even + // though the CDM is no longer necessary. + // TODO: Consider avoiding this possibility entirely. http://crbug.com/575236 + GURL frame_security_origin(frame->securityOrigin().toString()); + if (frame_security_origin != security_origin) { + LOG(ERROR) << "Frame has a different origin than the EME call."; + return scoped_ptr<PepperCdmWrapper>(); + } + ScopedHelperPlugin helper_plugin(blink::WebHelperPlugin::create( blink::WebString::fromUTF8(pluginType), frame)); if (!helper_plugin) @@ -44,11 +57,10 @@ if (!plugin_instance.get()) return scoped_ptr<PepperCdmWrapper>(); - GURL url(plugin_instance->container()->element().document().url()); - if (security_origin.GetOrigin() != url.GetOrigin()) { - NOTREACHED() << "Pepper instance has a different origin than the EME call."; - return scoped_ptr<PepperCdmWrapper>(); - } + GURL plugin_url(plugin_instance->container()->element().document().url()); + GURL plugin_security_origin = plugin_url.GetOrigin(); + CHECK_EQ(security_origin, plugin_security_origin) + << "Pepper instance has a different origin than the EME call."; if (!plugin_instance->GetContentDecryptorDelegate()) return scoped_ptr<PepperCdmWrapper>();
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 9ea32c4..c9cebe1 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -707,7 +707,7 @@ RenderFrameImpl::Create(render_view, routing_id); WebLocalFrame* web_frame = WebLocalFrame::create(blink::WebTreeScopeType::Document, render_frame); - render_frame->SetWebFrame(web_frame); + render_frame->BindToWebFrame(web_frame); render_view->webview()->setMainFrame(web_frame); render_frame->render_widget_ = RenderWidget::CreateForFrame( widget_routing_id, hidden, screen_info, compositor_deps, web_frame); @@ -775,7 +775,7 @@ render_frame, proxy->web_frame(), replicated_state.sandbox_flags, frame_owner_properties); } - render_frame->SetWebFrame(web_frame); + render_frame->BindToWebFrame(web_frame); CHECK(parent_routing_id != MSG_ROUTING_NONE || !web_frame->parent()); WebFrame* opener = ResolveOpener(opener_routing_id, nullptr); @@ -962,7 +962,7 @@ RenderThread::Get()->RemoveRoute(routing_id_); } -void RenderFrameImpl::SetWebFrame(blink::WebLocalFrame* web_frame) { +void RenderFrameImpl::BindToWebFrame(blink::WebLocalFrame* web_frame) { DCHECK(!frame_); std::pair<FrameMap::iterator, bool> result = g_frame_map.Get().insert( @@ -2522,7 +2522,7 @@ render_view_.get(), child_routing_id); blink::WebLocalFrame* web_frame = WebLocalFrame::create(scope, child_render_frame); - child_render_frame->SetWebFrame(web_frame); + child_render_frame->BindToWebFrame(web_frame); // Add the frame to the frame tree and initialize it. parent->appendChild(web_frame);
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 833cfb28..d072124 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -247,10 +247,6 @@ DevToolsAgent* devtools_agent() { return devtools_agent_; } - // This is called right after creation with the WebLocalFrame for this - // RenderFrame. It must be called before Initialize. - void SetWebFrame(blink::WebLocalFrame* web_frame); - // This method must be called after the frame has been added to the frame // tree. It creates all objects that depend on the frame being at its proper // spot. @@ -693,10 +689,14 @@ // Creates a new RenderFrame. |render_view| is the RenderView object that this // frame belongs to. - // Callers *must* call |SetWebFrame| immediately after creation. + // Callers *must* call |BindToWebFrame| immediately after creation. static RenderFrameImpl* Create(RenderViewImpl* render_view, int32_t routing_id); + // This is called right after creation with the WebLocalFrame for this + // RenderFrame. It must be called before Initialize. + void BindToWebFrame(blink::WebLocalFrame* web_frame); + // Functions to add and remove observers for this object. void AddObserver(RenderFrameObserver* observer); void RemoveObserver(RenderFrameObserver* observer); @@ -945,7 +945,7 @@ media::RendererWebMediaPlayerDelegate* GetWebMediaPlayerDelegate(); // Stores the WebLocalFrame we are associated with. This is null from the - // constructor until SetWebFrame is called, and it is null after + // constructor until BindToWebFrame is called, and it is null after // frameDetached is called until destruction (which is asynchronous in the // case of the main frame, but not subframes). blink::WebLocalFrame* frame_;
diff --git a/content/test/data/media/mediarecorder_test.html b/content/test/data/media/mediarecorder_test.html index c5d4cc1..9b1ccd5 100644 --- a/content/test/data/media/mediarecorder_test.html +++ b/content/test/data/media/mediarecorder_test.html
@@ -6,6 +6,7 @@ <body> <div> Record Real-Time video content browser test.</div> <video id="video" autoplay></video> + <video id="remoteVideo" autoplay></video> </body> <script type="text/javascript" src="mediarecorder_test_utils.js"></script> <script type="text/javascript" src="webrtc_test_utilities.js"></script> @@ -36,6 +37,52 @@ } } +// TODO(cpaulin): factor this method out of here, http://crbug.com/574503. +function setupPeerConnection(stream) { + return new Promise(function(resolve, reject) { + var localStream = stream; + var remoteStream = null; + var localPeerConnection = new webkitRTCPeerConnection(null); + var remotePeerConnection = new webkitRTCPeerConnection(null); + + function createAnswer(description) { + remotePeerConnection.createAnswer(function(description) { + remotePeerConnection.setLocalDescription(description); + localPeerConnection.setRemoteDescription(description); + }); + } + + localPeerConnection.onicecandidate = function(event) { + if (event.candidate) { + remotePeerConnection.addIceCandidate(new RTCIceCandidate( + event.candidate)); + } + }; + remotePeerConnection.onicecandidate = function(event) { + if (event.candidate) { + localPeerConnection.addIceCandidate(new RTCIceCandidate( + event.candidate)); + } + }; + remotePeerConnection.onaddstream = function(event) { + document.getElementById("remoteVideo").src = URL.createObjectURL( + event.stream); + remoteStream = event.stream; + resolve(remoteStream); + }; + + localPeerConnection.addStream(localStream); + + localPeerConnection.createOffer(function(description) { + localPeerConnection.setLocalDescription(description); + remotePeerConnection.setRemoteDescription(description); + createAnswer(description); + }); + + document.getElementById("video").src = URL.createObjectURL(localStream); + }); +} + function createAndStartMediaRecorder(stream, mimeType, slice) { return new Promise(function(resolve, reject) { document.getElementById('video').src = URL.createObjectURL(stream); @@ -235,19 +282,14 @@ } // Tests that is it not possible to resume an inactive MediaRecorder. -function testNoResumeWhileRecorderInactive() { +function testIllegalResumeThrowsDOMError() { navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS) .then(function(stream) { return createMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE); }) .then(function(recorder) { - recorder.resume(); - }) - .then(function() { - return failTest('Recorder resumed recording from inactive state.'); - }) - .catch(function(err) { - reportTestSuccess(); + assertThrows(function() {recorder.resume()}, 'Calling resume() in' + + ' inactive state should cause a DOM error'); }); } @@ -392,7 +434,39 @@ }) .then(function(recorder) { assertThrows(function() {recorder.pause()}, 'Calling pause() in' + - ' inactive state should cause a DOM error'); + ' inactive state should cause a DOM error'); + }); +} + +// Tests that a remote peer connection stream can be successfully recorded. +function testRecordRemotePeerConnection() { + var videoSize = 0; + var timeStamps = []; + navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS) + .then(function(localStream) { + return setupPeerConnection(localStream); + }) + .then(function(remoteStream) { + return createMediaRecorder(remoteStream, DEFAULT_RECORDER_MIME_TYPE); + }) + .then(function(recorder) { + recorder.ondataavailable = function(event) { + timeStamps.push(event.timeStamp); + videoSize += event.data.size; + }; + recorder.start(); + }) + .then(function() { + return waitFor('Making sure the recording has data', + function() { + return videoSize > 0 && timeStamps.length > 100; + }); + }) + .catch(function(err) { + return failTest(err.toString()); + }) + .then(function() { + reportTestSuccess(); }); }
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index a6311cbf..6d6d7d3 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -40,6 +40,9 @@ bug=540900) self.Fail('conformance/textures/misc/cube-incomplete-fbo.html', bug=559362) + # Remove after we roll in https://github.com/KhronosGroup/WebGL/pull/1408. + self.Fail('conformance/textures/misc/tex-input-validation.html', + bug=574618) # Win failures self.Fail('conformance/glsl/bugs/' +
diff --git a/device/test/run_all_unittests.cc b/device/test/run_all_unittests.cc index b70df54..76a4996 100644 --- a/device/test/run_all_unittests.cc +++ b/device/test/run_all_unittests.cc
@@ -11,11 +11,13 @@ #if defined(OS_ANDROID) #include "base/android/jni_android.h" #include "device/bluetooth/android/bluetooth_jni_registrar.h" +#include "device/usb/android/usb_jni_registrar.h" #endif int main(int argc, char** argv) { #if defined(OS_ANDROID) device::android::RegisterBluetoothJni(base::android::AttachCurrentThread()); + device::android::RegisterUsbJni(base::android::AttachCurrentThread()); #endif base::TestSuite test_suite(argc, argv);
diff --git a/device/usb/BUILD.gn b/device/usb/BUILD.gn index 99e12ca..6adc36f 100644 --- a/device/usb/BUILD.gn +++ b/device/usb/BUILD.gn
@@ -6,23 +6,39 @@ assert(!is_ios) +if (is_android) { + import("//build/config/android/rules.gni") # For generate_jni(). +} + source_ids = "//third_party/usb_ids/usb.ids" generated_ids = "$target_gen_dir/usb_ids_gen.cc" source_set("usb") { sources = [ + "android/usb_jni_registrar.cc", + "android/usb_jni_registrar.h", + "usb_configuration_android.cc", + "usb_configuration_android.h", "usb_descriptors.cc", "usb_descriptors.h", "usb_device.cc", "usb_device.h", + "usb_device_android.cc", + "usb_device_android.h", "usb_device_filter.cc", "usb_device_filter.h", "usb_device_handle.cc", "usb_device_handle.h", + "usb_endpoint_android.cc", + "usb_endpoint_android.h", "usb_ids.cc", "usb_ids.h", + "usb_interface_android.cc", + "usb_interface_android.h", "usb_service.cc", "usb_service.h", + "usb_service_android.cc", + "usb_service_android.h", "webusb_descriptors.cc", "webusb_descriptors.h", generated_ids, @@ -42,10 +58,7 @@ } if (is_android) { - sources += [ - "usb_service_android.cc", - "usb_service_android.h", - ] + deps += [ ":jni_headers" ] } else { sources += [ "usb_context.cc", @@ -111,3 +124,32 @@ # Only the device_usb target can depend on us. visibility = [ ":usb" ] } + +if (is_android) { + java_sources_needing_jni = [ + "android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java", + "android/java/src/org/chromium/device/usb/ChromeUsbDevice.java", + "android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java", + "android/java/src/org/chromium/device/usb/ChromeUsbInterface.java", + "android/java/src/org/chromium/device/usb/ChromeUsbService.java", + ] + + generate_jni("jni_headers") { + sources = java_sources_needing_jni + jni_package = "device" + } + + java_cpp_enum("usb_descriptors_javagen") { + sources = [ + "usb_descriptors.h", + ] + } + + android_library("java") { + java_files = java_sources_needing_jni + deps = [ + "//base:base_java", + ] + srcjar_deps = [ ":usb_descriptors_javagen" ] + } +}
diff --git a/device/usb/DEPS b/device/usb/DEPS index 25ff287..b1c259f 100644 --- a/device/usb/DEPS +++ b/device/usb/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+chromeos", "+dbus", + "+jni", "-net", "+net/base",
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java new file mode 100644 index 0000000..90371e5 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java
@@ -0,0 +1,68 @@ +// 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.device.usb; + +import android.annotation.TargetApi; +import android.hardware.usb.UsbConfiguration; +import android.hardware.usb.UsbInterface; +import android.os.Build; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Exposes android.hardware.usb.UsbConfiguration as necessary for C++ + * device::UsbConfigurationAndroid. + * + * Lifetime is controlled by device::UsbConfigurationAndroid. + */ +@JNINamespace("device") +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +final class ChromeUsbConfiguration { + private static final String TAG = "Usb"; + + final UsbConfiguration mConfiguration; + + private ChromeUsbConfiguration(UsbConfiguration configuration) { + mConfiguration = configuration; + Log.v(TAG, "ChromeUsbConfiguration created."); + } + + @CalledByNative + private static ChromeUsbConfiguration create(UsbConfiguration configuration) { + return new ChromeUsbConfiguration(configuration); + } + + @CalledByNative + private int getConfigurationValue() { + return mConfiguration.getId(); + } + + @CalledByNative + private boolean isSelfPowered() { + return mConfiguration.isSelfPowered(); + } + + @CalledByNative + private boolean isRemoteWakeup() { + return mConfiguration.isRemoteWakeup(); + } + + @CalledByNative + private int getMaxPower() { + return mConfiguration.getMaxPower(); + } + + @CalledByNative + private UsbInterface[] getInterfaces() { + int count = mConfiguration.getInterfaceCount(); + UsbInterface[] interfaces = new UsbInterface[count]; + for (int i = 0; i < count; ++i) { + interfaces[i] = mConfiguration.getInterface(i); + } + return interfaces; + } +}
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbDevice.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbDevice.java new file mode 100644 index 0000000..92e4e148 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbDevice.java
@@ -0,0 +1,84 @@ +// 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.device.usb; + +import android.annotation.TargetApi; +import android.hardware.usb.UsbConfiguration; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbInterface; +import android.os.Build; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Exposes android.hardware.usb.UsbDevice as necessary for C++ + * device::UsbDeviceAndroid. + * + * Lifetime is controlled by device::UsbDeviceAndroid. + */ +@JNINamespace("device") +final class ChromeUsbDevice { + private static final String TAG = "Usb"; + + final UsbDevice mDevice; + + private ChromeUsbDevice(UsbDevice device) { + mDevice = device; + Log.v(TAG, "ChromeUsbDevice created."); + } + + @CalledByNative + private static ChromeUsbDevice create(UsbDevice device) { + return new ChromeUsbDevice(device); + } + + @CalledByNative + private int getVendorId() { + return mDevice.getVendorId(); + } + + @CalledByNative + private int getProductId() { + return mDevice.getProductId(); + } + + @CalledByNative + private String getManufacturerName() { + return mDevice.getManufacturerName(); + } + + @CalledByNative + private String getProductName() { + return mDevice.getProductName(); + } + + @CalledByNative + private String getSerialNumber() { + return mDevice.getSerialNumber(); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @CalledByNative + private UsbConfiguration[] getConfigurations() { + int count = mDevice.getConfigurationCount(); + UsbConfiguration[] configurations = new UsbConfiguration[count]; + for (int i = 0; i < count; ++i) { + configurations[i] = mDevice.getConfiguration(i); + } + return configurations; + } + + @CalledByNative + private UsbInterface[] getInterfaces() { + int count = mDevice.getInterfaceCount(); + UsbInterface[] interfaces = new UsbInterface[count]; + for (int i = 0; i < count; ++i) { + interfaces[i] = mDevice.getInterface(i); + } + return interfaces; + } +}
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java new file mode 100644 index 0000000..135dc51 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java
@@ -0,0 +1,83 @@ +// 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.device.usb; + +import android.hardware.usb.UsbConstants; +import android.hardware.usb.UsbEndpoint; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Exposes android.hardware.usb.UsbEndpoint as necessary for C++ + * device::UsbEndpointAndroid. + * + * Lifetime is controlled by device::UsbEndpointAndroid. + */ +@JNINamespace("device") +final class ChromeUsbEndpoint { + private static final String TAG = "Usb"; + + final UsbEndpoint mEndpoint; + + private ChromeUsbEndpoint(UsbEndpoint endpoint) { + mEndpoint = endpoint; + Log.v(TAG, "ChromeUsbEndpoint created."); + } + + @CalledByNative + private static ChromeUsbEndpoint create(UsbEndpoint endpoint) { + return new ChromeUsbEndpoint(endpoint); + } + + @CalledByNative + private int getAddress() { + return mEndpoint.getAddress(); + } + + @CalledByNative + private int getDirection() { + switch (mEndpoint.getDirection()) { + case UsbConstants.USB_DIR_IN: + return UsbEndpointDirection.USB_DIRECTION_INBOUND; + case UsbConstants.USB_DIR_OUT: + return UsbEndpointDirection.USB_DIRECTION_OUTBOUND; + default: + throw new AssertionError(); + } + } + + @CalledByNative + private int getMaxPacketSize() { + return mEndpoint.getMaxPacketSize(); + } + + @CalledByNative + private int getAttributes() { + return mEndpoint.getAttributes(); + } + + @CalledByNative + private int getType() { + switch (mEndpoint.getType()) { + case UsbConstants.USB_ENDPOINT_XFER_CONTROL: + return UsbTransferType.USB_TRANSFER_CONTROL; + case UsbConstants.USB_ENDPOINT_XFER_ISOC: + return UsbTransferType.USB_TRANSFER_ISOCHRONOUS; + case UsbConstants.USB_ENDPOINT_XFER_BULK: + return UsbTransferType.USB_TRANSFER_BULK; + case UsbConstants.USB_ENDPOINT_XFER_INT: + return UsbTransferType.USB_TRANSFER_INTERRUPT; + default: + throw new AssertionError(); + } + } + + @CalledByNative + private int getInterval() { + return mEndpoint.getInterval(); + } +}
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbInterface.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbInterface.java new file mode 100644 index 0000000..cd4f492 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbInterface.java
@@ -0,0 +1,70 @@ +// 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.device.usb; + +import android.hardware.usb.UsbEndpoint; +import android.hardware.usb.UsbInterface; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Exposes android.hardware.usb.UsbInterface as necessary for C++ + * device::UsbInterfaceAndroid. + * + * Lifetime is controlled by device::UsbInterfaceAndroid. + */ +@JNINamespace("device") +final class ChromeUsbInterface { + private static final String TAG = "Usb"; + + final UsbInterface mInterface; + + private ChromeUsbInterface(UsbInterface iface) { + mInterface = iface; + Log.v(TAG, "ChromeUsbInterface created."); + } + + @CalledByNative + private static ChromeUsbInterface create(UsbInterface iface) { + return new ChromeUsbInterface(iface); + } + + @CalledByNative + private int getInterfaceNumber() { + return mInterface.getId(); + } + + @CalledByNative + private int getAlternateSetting() { + return mInterface.getAlternateSetting(); + } + + @CalledByNative + private int getInterfaceClass() { + return mInterface.getInterfaceClass(); + } + + @CalledByNative + private int getInterfaceSubclass() { + return mInterface.getInterfaceSubclass(); + } + + @CalledByNative + private int getInterfaceProtocol() { + return mInterface.getInterfaceProtocol(); + } + + @CalledByNative + private UsbEndpoint[] getEndpoints() { + int count = mInterface.getEndpointCount(); + UsbEndpoint[] endpoints = new UsbEndpoint[count]; + for (int i = 0; i < count; ++i) { + endpoints[i] = mInterface.getEndpoint(i); + } + return endpoints; + } +}
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbService.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbService.java new file mode 100644 index 0000000..834ddb1 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbService.java
@@ -0,0 +1,45 @@ +// 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.device.usb; + +import android.content.Context; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbManager; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +import java.util.HashMap; + +/** + * Exposes android.hardware.usb.UsbManager as necessary for C++ + * device::UsbServiceAndroid. + * + * Lifetime is controlled by device::UsbServiceAndroid. + */ +@JNINamespace("device") +final class ChromeUsbService { + private static final String TAG = "Usb"; + + Context mContext; + + private ChromeUsbService(Context context) { + mContext = context; + Log.v(TAG, "ChromeUsbService created."); + } + + @CalledByNative + private static ChromeUsbService create(Context context) { + return new ChromeUsbService(context); + } + + @CalledByNative + private Object[] getDevices() { + UsbManager manager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); + HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); + return deviceList.values().toArray(); + } +}
diff --git a/device/usb/android/usb_jni_registrar.cc b/device/usb/android/usb_jni_registrar.cc new file mode 100644 index 0000000..1e53c5b --- /dev/null +++ b/device/usb/android/usb_jni_registrar.cc
@@ -0,0 +1,35 @@ +// 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 "device/usb/android/usb_jni_registrar.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_registrar.h" +#include "device/usb/usb_configuration_android.h" +#include "device/usb/usb_device_android.h" +#include "device/usb/usb_endpoint_android.h" +#include "device/usb/usb_interface_android.h" +#include "device/usb/usb_service_android.h" + +namespace device { +namespace android { +namespace { + +const base::android::RegistrationMethod kRegisteredMethods[] = { + {"UsbConfigurationAndroid", device::UsbConfigurationAndroid::RegisterJNI}, + {"UsbDeviceAndroid", device::UsbDeviceAndroid::RegisterJNI}, + {"UsbEndpointAndroid", device::UsbEndpointAndroid::RegisterJNI}, + {"UsbInterfaceAndroid", device::UsbInterfaceAndroid::RegisterJNI}, + {"UsbServiceAndroid", device::UsbServiceAndroid::RegisterJNI}, +}; + +} // namespace + +bool RegisterUsbJni(JNIEnv* env) { + return RegisterNativeMethods(env, kRegisteredMethods, + arraysize(kRegisteredMethods)); +} + +} // namespace android +} // namespace device
diff --git a/device/usb/android/usb_jni_registrar.h b/device/usb/android/usb_jni_registrar.h new file mode 100644 index 0000000..a691583 --- /dev/null +++ b/device/usb/android/usb_jni_registrar.h
@@ -0,0 +1,22 @@ +// 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 DEVICE_USB_ANDROID_USB_JNI_REGISTRAR_H_ +#define DEVICE_USB_ANDROID_USB_JNI_REGISTRAR_H_ + +#include <jni.h> + +namespace device { +namespace android { + +// Registers C++ methods in device/usb classes with JNI. +// See https://www.chromium.org/developers/design-documents/android-jni +// +// Must be called before classes in the USB module are used. +bool RegisterUsbJni(JNIEnv* env); + +} // namespace android +} // namespace device + +#endif // DEVICE_USB_ANDROID_USB_JNI_REGISTRAR_H_
diff --git a/device/usb/mock_usb_device.h b/device/usb/mock_usb_device.h index c25a915b..91bb0bb 100644 --- a/device/usb/mock_usb_device.h +++ b/device/usb/mock_usb_device.h
@@ -5,12 +5,12 @@ #ifndef DEVICE_USB_MOCK_USB_DEVICE_H_ #define DEVICE_USB_MOCK_USB_DEVICE_H_ -#include "device/usb/usb_device.h" - #include <stdint.h> #include <string> +#include <vector> +#include "device/usb/usb_device.h" #include "device/usb/usb_device_handle.h" #include "testing/gmock/include/gmock/gmock.h" @@ -41,7 +41,6 @@ const std::vector<UsbConfigDescriptor>& configurations); MOCK_METHOD1(Open, void(const OpenCallback&)); - MOCK_METHOD1(Close, bool(scoped_refptr<UsbDeviceHandle>)); MOCK_METHOD0(GetActiveConfiguration, const device::UsbConfigDescriptor*()); private:
diff --git a/device/usb/usb.gyp b/device/usb/usb.gyp index 453ba1aa..a68b187b 100644 --- a/device/usb/usb.gyp +++ b/device/usb/usb.gyp
@@ -20,6 +20,10 @@ '../..', ], 'sources': [ + 'android/usb_jni_registrar.cc', + 'android/usb_jni_registrar.h', + 'usb_configuration_android.cc', + 'usb_configuration_android.h', 'usb_context.cc', 'usb_context.h', 'usb_descriptors.cc', @@ -28,18 +32,26 @@ 'usb_device_impl.h', 'usb_device.cc', 'usb_device.h', + 'usb_device_android.cc', + 'usb_device_android.h', 'usb_device_filter.cc', 'usb_device_filter.h', 'usb_device_handle_impl.cc', 'usb_device_handle_impl.h', 'usb_device_handle.cc', 'usb_device_handle.h', + 'usb_endpoint_android.cc', + 'usb_endpoint_android.h', 'usb_error.cc', 'usb_error.h', 'usb_ids.cc', 'usb_ids.h', + 'usb_interface_android.cc', + 'usb_interface_android.h', 'usb_service.cc', 'usb_service.h', + 'usb_service_android.cc', + 'usb_service_android.h', 'usb_service_impl.cc', 'usb_service_impl.h', 'webusb_descriptors.cc', @@ -75,13 +87,14 @@ ], }], ['OS=="android"', { + 'dependencies': [ + 'device_usb_java', + 'device_usb_jni_headers', + ], 'dependencies!': [ '../../third_party/libusb/libusb.gyp:libusb', ], - 'sources': [ - 'usb_service_android.cc', - 'usb_service_android.h', - ], + # These sources are libusb-specific. 'sources!': [ 'usb_context.cc', 'usb_context.h', @@ -122,4 +135,45 @@ ], }, ], + 'conditions': [ + ['OS == "android"', { + 'targets': [ + { + 'target_name': 'device_usb_jni_headers', + 'type': 'none', + 'sources': [ + 'android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java', + 'android/java/src/org/chromium/device/usb/ChromeUsbDevice.java', + 'android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java', + 'android/java/src/org/chromium/device/usb/ChromeUsbInterface.java', + 'android/java/src/org/chromium/device/usb/ChromeUsbService.java', + ], + 'variables': { + 'jni_gen_package': 'device_usb', + }, + 'includes': [ '../../build/jni_generator.gypi' ], + }, + { + 'target_name': 'device_usb_java', + 'type': 'none', + 'dependencies': [ + 'usb_descriptors_javagen', + '../../base/base.gyp:base', + ], + 'variables': { + 'java_in_dir': '../../device/usb/android/java', + }, + 'includes': [ '../../build/java.gypi' ], + }, + { + 'target_name': 'usb_descriptors_javagen', + 'type': 'none', + 'variables': { + 'source_file': 'usb_descriptors.h', + }, + 'includes': [ '../../build/android/java_cpp_enum.gypi' ], + }, + ], + }], + ], }
diff --git a/device/usb/usb_configuration_android.cc b/device/usb/usb_configuration_android.cc new file mode 100644 index 0000000..4a9c712 --- /dev/null +++ b/device/usb/usb_configuration_android.cc
@@ -0,0 +1,49 @@ +// 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 "device/usb/usb_configuration_android.h" + +#include "device/usb/usb_interface_android.h" +#include "jni/ChromeUsbConfiguration_jni.h" + +using base::android::ScopedJavaLocalRef; + +namespace device { + +// static +bool UsbConfigurationAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbConfiguration_jni.h +} + +// static +UsbConfigDescriptor UsbConfigurationAndroid::Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_configuration) { + ScopedJavaLocalRef<jobject> wrapper = + Java_ChromeUsbConfiguration_create(env, usb_configuration.obj()); + + UsbConfigDescriptor config; + config.configuration_value = + Java_ChromeUsbConfiguration_getConfigurationValue(env, wrapper.obj()); + config.self_powered = + Java_ChromeUsbConfiguration_isSelfPowered(env, wrapper.obj()); + config.remote_wakeup = + Java_ChromeUsbConfiguration_isRemoteWakeup(env, wrapper.obj()); + config.maximum_power = + Java_ChromeUsbConfiguration_getMaxPower(env, wrapper.obj()); + + ScopedJavaLocalRef<jobjectArray> interfaces = + Java_ChromeUsbConfiguration_getInterfaces(env, wrapper.obj()); + jsize count = env->GetArrayLength(interfaces.obj()); + config.interfaces.reserve(count); + for (jsize i = 0; i < count; ++i) { + ScopedJavaLocalRef<jobject> interface( + env, env->GetObjectArrayElement(interfaces.obj(), i)); + config.interfaces.push_back(UsbInterfaceAndroid::Convert(env, interface)); + } + + return config; +} + +} // namespace device
diff --git a/device/usb/usb_configuration_android.h b/device/usb/usb_configuration_android.h new file mode 100644 index 0000000..610ac07 --- /dev/null +++ b/device/usb/usb_configuration_android.h
@@ -0,0 +1,25 @@ +// 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 DEVICE_USB_USB_CONFIGURATION_ANDROID_H_ +#define DEVICE_USB_USB_CONFIGURATION_ANDROID_H_ + +#include "base/android/scoped_java_ref.h" +#include "device/usb/usb_descriptors.h" + +namespace device { + +class UsbConfigurationAndroid { + public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + + static UsbConfigDescriptor Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_configuration); +}; + +} // namespace device + +#endif // DEVICE_USB_USB_CONFIGURATION_ANDROID_H_
diff --git a/device/usb/usb_descriptors.h b/device/usb/usb_descriptors.h index 93b6f62..adaa0ab 100644 --- a/device/usb/usb_descriptors.h +++ b/device/usb/usb_descriptors.h
@@ -12,6 +12,8 @@ namespace device { +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.device.usb enum UsbTransferType { USB_TRANSFER_CONTROL = 0, USB_TRANSFER_ISOCHRONOUS, @@ -19,6 +21,8 @@ USB_TRANSFER_INTERRUPT, }; +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.device.usb enum UsbEndpointDirection { USB_DIRECTION_INBOUND = 0, USB_DIRECTION_OUTBOUND,
diff --git a/device/usb/usb_device.h b/device/usb/usb_device.h index 9822a38..92d0e29 100644 --- a/device/usb/usb_device.h +++ b/device/usb/usb_device.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <string> #include <vector> #include "base/callback.h" @@ -59,10 +60,6 @@ // Creates a UsbDeviceHandle for further manipulation. virtual void Open(const OpenCallback& callback) = 0; - // Explicitly closes a device handle. This method will be automatically called - // by the destructor of a UsbDeviceHandle as well. - virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) = 0; - // Gets the UsbConfigDescriptor for the active device configuration or nullptr // if the device is unconfigured. virtual const UsbConfigDescriptor* GetActiveConfiguration() = 0;
diff --git a/device/usb/usb_device_android.cc b/device/usb/usb_device_android.cc new file mode 100644 index 0000000..ee9e93b --- /dev/null +++ b/device/usb/usb_device_android.cc
@@ -0,0 +1,107 @@ +// 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 "device/usb/usb_device_android.h" + +#include "base/android/build_info.h" +#include "base/android/jni_string.h" +#include "base/bind.h" +#include "base/location.h" +#include "base/thread_task_runner_handle.h" +#include "device/usb/usb_configuration_android.h" +#include "device/usb/usb_device_handle.h" +#include "device/usb/usb_interface_android.h" +#include "jni/ChromeUsbDevice_jni.h" + +using base::android::AttachCurrentThread; +using base::android::ConvertJavaStringToUTF16; +using base::android::JavaRef; +using base::android::ScopedJavaLocalRef; + +namespace device { + +// static +bool UsbDeviceAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbDevice_jni.h +} + +// static +scoped_refptr<UsbDeviceAndroid> UsbDeviceAndroid::Create( + JNIEnv* env, + const JavaRef<jobject>& usb_device) { + ScopedJavaLocalRef<jobject> wrapper = + Java_ChromeUsbDevice_create(env, usb_device.obj()); + uint16_t vendor_id = Java_ChromeUsbDevice_getVendorId(env, wrapper.obj()); + uint16_t product_id = Java_ChromeUsbDevice_getProductId(env, wrapper.obj()); + ScopedJavaLocalRef<jstring> manufacturer_string = + Java_ChromeUsbDevice_getManufacturerName(env, wrapper.obj()); + ScopedJavaLocalRef<jstring> product_string = + Java_ChromeUsbDevice_getProductName(env, wrapper.obj()); + ScopedJavaLocalRef<jstring> serial_number = + Java_ChromeUsbDevice_getSerialNumber(env, wrapper.obj()); + return make_scoped_refptr(new UsbDeviceAndroid( + env, vendor_id, product_id, + ConvertJavaStringToUTF16(env, manufacturer_string), + ConvertJavaStringToUTF16(env, product_string), + ConvertJavaStringToUTF16(env, serial_number), wrapper)); +} + +void UsbDeviceAndroid::Open(const OpenCallback& callback) { + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + base::Bind(callback, nullptr)); +} + +const UsbConfigDescriptor* UsbDeviceAndroid::GetActiveConfiguration() { + return nullptr; +} + +UsbDeviceAndroid::UsbDeviceAndroid(JNIEnv* env, + uint16_t vendor_id, + uint16_t product_id, + const base::string16& manufacturer_string, + const base::string16& product_string, + const base::string16& serial_number, + const JavaRef<jobject>& wrapper) + : UsbDevice(vendor_id, + product_id, + manufacturer_string, + product_string, + serial_number) { + j_object_.Reset(wrapper); + + if (base::android::BuildInfo::GetInstance()->sdk_int() >= 21) { + ScopedJavaLocalRef<jobjectArray> configurations = + Java_ChromeUsbDevice_getConfigurations(env, j_object_.obj()); + jsize count = env->GetArrayLength(configurations.obj()); + configurations_.reserve(count); + for (jsize i = 0; i < count; ++i) { + ScopedJavaLocalRef<jobject> config( + env, env->GetObjectArrayElement(configurations.obj(), i)); + configurations_.push_back(UsbConfigurationAndroid::Convert(env, config)); + } + } else { + // Pre-lollipop only the first configuration was supported. Build a basic + // configuration out of the available interfaces. + UsbConfigDescriptor config; + config.configuration_value = 1; // Reasonable guess. + config.self_powered = false; // Arbitrary default. + config.remote_wakeup = false; // Arbitrary default. + config.maximum_power = 0; // Arbitrary default. + + ScopedJavaLocalRef<jobjectArray> interfaces = + Java_ChromeUsbDevice_getInterfaces(env, wrapper.obj()); + jsize count = env->GetArrayLength(interfaces.obj()); + config.interfaces.reserve(count); + for (jsize i = 0; i < count; ++i) { + ScopedJavaLocalRef<jobject> interface( + env, env->GetObjectArrayElement(interfaces.obj(), i)); + config.interfaces.push_back(UsbInterfaceAndroid::Convert(env, interface)); + } + configurations_.push_back(config); + } +} + +UsbDeviceAndroid::~UsbDeviceAndroid() {} + +} // namespace device
diff --git a/device/usb/usb_device_android.h b/device/usb/usb_device_android.h new file mode 100644 index 0000000..ad468913 --- /dev/null +++ b/device/usb/usb_device_android.h
@@ -0,0 +1,42 @@ +// 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 DEVICE_USB_USB_DEVICE_ANDROID_H_ +#define DEVICE_USB_USB_DEVICE_ANDROID_H_ + +#include "base/android/scoped_java_ref.h" +#include "device/usb/usb_device.h" + +namespace device { + +class UsbDeviceAndroid : public UsbDevice { + public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + + static scoped_refptr<UsbDeviceAndroid> Create( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_device); + + // UsbDevice: + void Open(const OpenCallback& callback) override; + const UsbConfigDescriptor* GetActiveConfiguration() override; + + private: + UsbDeviceAndroid(JNIEnv* env, + uint16_t vendor_id, + uint16_t product_id, + const base::string16& manufacturer_string, + const base::string16& product_string, + const base::string16& serial_number, + const base::android::JavaRef<jobject>& wrapper); + ~UsbDeviceAndroid() override; + + // Java object org.chromium.device.usb.ChromeUsbDevice. + base::android::ScopedJavaGlobalRef<jobject> j_object_; +}; + +} // namespace device + +#endif // DEVICE_USB_USB_DEVICE_ANDROID_H_
diff --git a/device/usb/usb_device_impl.cc b/device/usb/usb_device_impl.cc index 874ccad..271b631 100644 --- a/device/usb/usb_device_impl.cc +++ b/device/usb/usb_device_impl.cc
@@ -204,7 +204,7 @@ #endif // defined(OS_CHROMEOS) } -bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) { +void UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) { DCHECK(thread_checker_.CalledOnValidThread()); for (HandlesVector::iterator it = handles_.begin(); it != handles_.end(); @@ -212,10 +212,9 @@ if (it->get() == handle.get()) { (*it)->InternalClose(); handles_.erase(it); - return true; + return; } } - return false; } const UsbConfigDescriptor* UsbDeviceImpl::GetActiveConfiguration() {
diff --git a/device/usb/usb_device_impl.h b/device/usb/usb_device_impl.h index 337c0e86..a64e3d1b 100644 --- a/device/usb/usb_device_impl.h +++ b/device/usb/usb_device_impl.h
@@ -6,6 +6,8 @@ #define DEVICE_USB_USB_DEVICE_IMPL_H_ #include <stdint.h> + +#include <string> #include <utility> #include <vector> @@ -45,7 +47,6 @@ void CheckUsbAccess(const ResultCallback& callback) override; #endif // OS_CHROMEOS void Open(const OpenCallback& callback) override; - bool Close(scoped_refptr<UsbDeviceHandle> handle) override; const UsbConfigDescriptor* GetActiveConfiguration() override; // These functions are used during enumeration only. The values must not @@ -87,6 +88,7 @@ void ReadAllConfigurations(); // Called by UsbDeviceHandleImpl. + void Close(scoped_refptr<UsbDeviceHandle> handle); void RefreshActiveConfiguration(); private:
diff --git a/device/usb/usb_endpoint_android.cc b/device/usb/usb_endpoint_android.cc new file mode 100644 index 0000000..3280b04 --- /dev/null +++ b/device/usb/usb_endpoint_android.cc
@@ -0,0 +1,41 @@ +// 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 "device/usb/usb_endpoint_android.h" + +#include "jni/ChromeUsbEndpoint_jni.h" + +namespace device { + +// static +bool UsbEndpointAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbEndpoint_jni.h +} + +// static +UsbEndpointDescriptor UsbEndpointAndroid::Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_endpoint) { + base::android::ScopedJavaLocalRef<jobject> wrapper = + Java_ChromeUsbEndpoint_create(env, usb_endpoint.obj()); + + UsbEndpointDescriptor endpoint; + endpoint.address = Java_ChromeUsbEndpoint_getAddress(env, wrapper.obj()); + endpoint.direction = static_cast<UsbEndpointDirection>( + Java_ChromeUsbEndpoint_getDirection(env, wrapper.obj())); + endpoint.maximum_packet_size = + Java_ChromeUsbEndpoint_getMaxPacketSize(env, wrapper.obj()); + jint attributes = Java_ChromeUsbEndpoint_getAttributes(env, wrapper.obj()); + endpoint.synchronization_type = + static_cast<UsbSynchronizationType>((attributes >> 2) & 3); + endpoint.usage_type = static_cast<UsbUsageType>((attributes >> 4) & 3); + endpoint.transfer_type = static_cast<UsbTransferType>( + Java_ChromeUsbEndpoint_getType(env, wrapper.obj())); + endpoint.polling_interval = + Java_ChromeUsbEndpoint_getInterval(env, wrapper.obj()); + + return endpoint; +} + +} // namespace device
diff --git a/device/usb/usb_endpoint_android.h b/device/usb/usb_endpoint_android.h new file mode 100644 index 0000000..3fc835c --- /dev/null +++ b/device/usb/usb_endpoint_android.h
@@ -0,0 +1,25 @@ +// 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 DEVICE_USB_USB_ENDPOINT_ANDROID_H_ +#define DEVICE_USB_USB_ENDPOINT_ANDROID_H_ + +#include "base/android/scoped_java_ref.h" +#include "device/usb/usb_descriptors.h" + +namespace device { + +class UsbEndpointAndroid { + public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + + static UsbEndpointDescriptor Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_endpoint); +}; + +} // namespace device + +#endif // DEVICE_USB_USB_ENDPOINT_ANDROID_H_
diff --git a/device/usb/usb_interface_android.cc b/device/usb/usb_interface_android.cc new file mode 100644 index 0000000..60403ae --- /dev/null +++ b/device/usb/usb_interface_android.cc
@@ -0,0 +1,51 @@ +// 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 "device/usb/usb_interface_android.h" + +#include "device/usb/usb_endpoint_android.h" +#include "jni/ChromeUsbInterface_jni.h" + +using base::android::ScopedJavaLocalRef; + +namespace device { + +// static +bool UsbInterfaceAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbInterface_jni.h +} + +// static +UsbInterfaceDescriptor UsbInterfaceAndroid::Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_interface) { + ScopedJavaLocalRef<jobject> wrapper = + Java_ChromeUsbInterface_create(env, usb_interface.obj()); + + UsbInterfaceDescriptor interface; + interface.interface_number = + Java_ChromeUsbInterface_getInterfaceNumber(env, wrapper.obj()); + interface.alternate_setting = + Java_ChromeUsbInterface_getAlternateSetting(env, wrapper.obj()); + interface.interface_class = + Java_ChromeUsbInterface_getInterfaceClass(env, wrapper.obj()); + interface.interface_subclass = + Java_ChromeUsbInterface_getInterfaceSubclass(env, wrapper.obj()); + interface.interface_protocol = + Java_ChromeUsbInterface_getInterfaceProtocol(env, wrapper.obj()); + + ScopedJavaLocalRef<jobjectArray> endpoints = + Java_ChromeUsbInterface_getEndpoints(env, wrapper.obj()); + jsize count = env->GetArrayLength(endpoints.obj()); + interface.endpoints.reserve(count); + for (jsize i = 0; i < count; ++i) { + ScopedJavaLocalRef<jobject> endpoint( + env, env->GetObjectArrayElement(endpoints.obj(), i)); + interface.endpoints.push_back(UsbEndpointAndroid::Convert(env, endpoint)); + } + + return interface; +} + +} // namespace device
diff --git a/device/usb/usb_interface_android.h b/device/usb/usb_interface_android.h new file mode 100644 index 0000000..ec04b61e --- /dev/null +++ b/device/usb/usb_interface_android.h
@@ -0,0 +1,25 @@ +// 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 DEVICE_USB_USB_INTERFACE_ANDROID_H_ +#define DEVICE_USB_USB_INTERFACE_ANDROID_H_ + +#include "base/android/scoped_java_ref.h" +#include "device/usb/usb_descriptors.h" + +namespace device { + +class UsbInterfaceAndroid { + public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + + static UsbInterfaceDescriptor Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_interface); +}; + +} // namespace device + +#endif // DEVICE_USB_USB_INTERFACE_ANDROID_H_
diff --git a/device/usb/usb_service_android.cc b/device/usb/usb_service_android.cc index 45ce499..3bdf3bc6 100644 --- a/device/usb/usb_service_android.cc +++ b/device/usb/usb_service_android.cc
@@ -4,14 +4,30 @@ #include "device/usb/usb_service_android.h" +#include <string> +#include <vector> + +#include "base/android/context_utils.h" #include "base/bind.h" #include "base/location.h" #include "base/thread_task_runner_handle.h" -#include "device/usb/usb_device.h" +#include "device/usb/usb_device_android.h" +#include "jni/ChromeUsbService_jni.h" + +using base::android::AttachCurrentThread; +using base::android::ScopedJavaLocalRef; namespace device { -UsbServiceAndroid::UsbServiceAndroid() {} +// static +bool UsbServiceAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbService_jni.h +} + +UsbServiceAndroid::UsbServiceAndroid() { + j_object_.Reset(Java_ChromeUsbService_create( + AttachCurrentThread(), base::android::GetApplicationContext())); +} UsbServiceAndroid::~UsbServiceAndroid() {} @@ -20,9 +36,20 @@ } void UsbServiceAndroid::GetDevices(const GetDevicesCallback& callback) { - std::vector<scoped_refptr<UsbDevice>> empty; + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobjectArray> devices = + Java_ChromeUsbService_getDevices(env, j_object_.obj()); + jsize length = env->GetArrayLength(devices.obj()); + + std::vector<scoped_refptr<UsbDevice>> results; + for (jsize i = 0; i < length; ++i) { + ScopedJavaLocalRef<jobject> raw_device( + env, env->GetObjectArrayElement(devices.obj(), i)); + results.push_back(UsbDeviceAndroid::Create(env, raw_device)); + } + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - base::Bind(callback, empty)); + base::Bind(callback, results)); } } // namespace device
diff --git a/device/usb/usb_service_android.h b/device/usb/usb_service_android.h index d1ffd9df..9cab4385 100644 --- a/device/usb/usb_service_android.h +++ b/device/usb/usb_service_android.h
@@ -5,6 +5,9 @@ #ifndef DEVICE_USB_USB_SERVICE_ANDROID_H_ #define DEVICE_USB_USB_SERVICE_ANDROID_H_ +#include <string> + +#include "base/android/scoped_java_ref.h" #include "device/usb/usb_service.h" namespace device { @@ -13,11 +16,19 @@ // does not return any devices. class UsbServiceAndroid : public UsbService { public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + UsbServiceAndroid(); ~UsbServiceAndroid() override; + // UsbService: scoped_refptr<UsbDevice> GetDevice(const std::string& guid) override; void GetDevices(const GetDevicesCallback& callback) override; + + private: + // Java object org.chromium.device.usb.ChromeUsbService. + base::android::ScopedJavaGlobalRef<jobject> j_object_; }; } // namespace device
diff --git a/extensions/browser/api/management/management_api.cc b/extensions/browser/api/management/management_api.cc index 81fe012..2511aee5 100644 --- a/extensions/browser/api/management/management_api.cc +++ b/extensions/browser/api/management/management_api.cc
@@ -451,8 +451,10 @@ if (!user_gesture()) return RespondNow(Error(keys::kGestureNeededForEscalationError)); - AddRef(); // Matched in InstallUIProceed/InstallUIAbort - install_prompt_ = delegate->SetEnabledFunctionDelegate(this, extension); + AddRef(); // Matched in OnInstallPromptDone(). + install_prompt_ = delegate->SetEnabledFunctionDelegate( + GetSenderWebContents(), browser_context(), extension, + base::Bind(&ManagementSetEnabledFunction::OnInstallPromptDone, this)); return RespondLater(); } if (prefs->GetDisableReasons(extension_id_) & @@ -474,18 +476,18 @@ return RespondNow(NoArguments()); } -void ManagementSetEnabledFunction::InstallUIProceed() { - ManagementAPI::GetFactoryInstance() - ->Get(browser_context()) - ->GetDelegate() - ->EnableExtension(browser_context(), extension_id_); - Respond(OneArgument(new base::FundamentalValue(true))); - Release(); -} +void ManagementSetEnabledFunction::OnInstallPromptDone(bool did_accept) { + if (did_accept) { + ManagementAPI::GetFactoryInstance() + ->Get(browser_context()) + ->GetDelegate() + ->EnableExtension(browser_context(), extension_id_); + Respond(OneArgument(new base::FundamentalValue(true))); + } else { + Respond(Error(keys::kUserDidNotReEnableError)); + } -void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) { - Respond(Error(keys::kUserDidNotReEnableError)); - Release(); + Release(); // Balanced in Run(). } void ManagementSetEnabledFunction::OnRequirementsChecked(
diff --git a/extensions/browser/api/management/management_api.h b/extensions/browser/api/management/management_api.h index f37e9c91..fc9b563 100644 --- a/extensions/browser/api/management/management_api.h +++ b/extensions/browser/api/management/management_api.h
@@ -114,9 +114,6 @@ ManagementSetEnabledFunction(); - void InstallUIProceed(); - void InstallUIAbort(bool user_initiated); - protected: ~ManagementSetEnabledFunction() override; @@ -124,6 +121,8 @@ ResponseAction Run() override; private: + void OnInstallPromptDone(bool did_accept); + void OnRequirementsChecked(const std::vector<std::string>& requirements); std::string extension_id_;
diff --git a/extensions/browser/api/management/management_api_delegate.h b/extensions/browser/api/management/management_api_delegate.h index f7b15a7..9e127eeb 100644 --- a/extensions/browser/api/management/management_api_delegate.h +++ b/extensions/browser/api/management/management_api_delegate.h
@@ -14,6 +14,7 @@ namespace content { class BrowserContext; +class WebContents; } // namespace content namespace extensions { @@ -78,8 +79,10 @@ // Used to show a dialog prompt in chrome when management.setEnabled extension // function is called. virtual scoped_ptr<InstallPromptDelegate> SetEnabledFunctionDelegate( - ManagementSetEnabledFunction* function, - const Extension* extension) const = 0; + content::WebContents* web_contents, + content::BrowserContext* browser_context, + const Extension* extension, + const base::Callback<void(bool)>& callback) const = 0; // Returns a new RequirementsChecker. virtual scoped_ptr<RequirementsChecker> CreateRequirementsChecker() const = 0;
diff --git a/extensions/browser/process_manager.cc b/extensions/browser/process_manager.cc index c3eaad5..c0f7253 100644 --- a/extensions/browser/process_manager.cc +++ b/extensions/browser/process_manager.cc
@@ -166,13 +166,13 @@ switch (view_type) { case VIEW_TYPE_APP_WINDOW: case VIEW_TYPE_BACKGROUND_CONTENTS: + case VIEW_TYPE_COMPONENT: case VIEW_TYPE_EXTENSION_DIALOG: case VIEW_TYPE_EXTENSION_GUEST: case VIEW_TYPE_EXTENSION_POPUP: case VIEW_TYPE_LAUNCHER_PAGE: case VIEW_TYPE_PANEL: case VIEW_TYPE_TAB_CONTENTS: - case VIEW_TYPE_VIRTUAL_KEYBOARD: return true; case VIEW_TYPE_INVALID:
diff --git a/extensions/browser/value_store/leveldb_value_store.cc b/extensions/browser/value_store/leveldb_value_store.cc index 9849842..db3e30a 100644 --- a/extensions/browser/value_store/leveldb_value_store.cc +++ b/extensions/browser/value_store/leveldb_value_store.cc
@@ -36,11 +36,20 @@ // UMA values used when recovering from a corrupted leveldb. // Do not change/delete these values as you will break reporting for older // copies of Chrome. Only add new values to the end. -enum LevelDBCorruptionRecoveryValue { - LEVELDB_RESTORE_DELETE_SUCCESS = 0, - LEVELDB_RESTORE_DELETE_FAILURE, - LEVELDB_RESTORE_REPAIR_SUCCESS, - LEVELDB_RESTORE_MAX +enum LevelDBDatabaseCorruptionRecoveryValue { + LEVELDB_DB_RESTORE_DELETE_SUCCESS = 0, + LEVELDB_DB_RESTORE_DELETE_FAILURE, + LEVELDB_DB_RESTORE_REPAIR_SUCCESS, + LEVELDB_DB_RESTORE_MAX +}; + +// UMA values used when recovering from a corrupted leveldb. +// Do not change/delete these values as you will break reporting for older +// copies of Chrome. Only add new values to the end. +enum LevelDBValueCorruptionRecoveryValue { + LEVELDB_VALUE_RESTORE_DELETE_SUCCESS, + LEVELDB_VALUE_RESTORE_DELETE_FAILURE, + LEVELDB_VALUE_RESTORE_MAX }; // Scoped leveldb snapshot which releases the snapshot on destruction. @@ -80,7 +89,8 @@ : db_path_(db_path), db_unrecoverable_(false), open_histogram_(nullptr), - restore_histogram_(nullptr) { + db_restore_histogram_(nullptr), + value_restore_histogram_(nullptr) { DCHECK_CURRENTLY_ON(BrowserThread::FILE); open_options_.max_open_files = 0; // Use minimum. @@ -96,9 +106,14 @@ "Extensions.Database.Open." + uma_client_name, 1, leveldb_env::LEVELDB_STATUS_MAX, leveldb_env::LEVELDB_STATUS_MAX + 1, base::Histogram::kUmaTargetedHistogramFlag); - restore_histogram_ = base::LinearHistogram::FactoryGet( - "Extensions.Database.Restore." + uma_client_name, 1, LEVELDB_RESTORE_MAX, - LEVELDB_RESTORE_MAX + 1, base::Histogram::kUmaTargetedHistogramFlag); + db_restore_histogram_ = base::LinearHistogram::FactoryGet( + "Extensions.Database.Database.Restore." + uma_client_name, 1, + LEVELDB_DB_RESTORE_MAX, LEVELDB_DB_RESTORE_MAX + 1, + base::Histogram::kUmaTargetedHistogramFlag); + value_restore_histogram_ = base::LinearHistogram::FactoryGet( + "Extensions.Database.Value.Restore." + uma_client_name, 1, + LEVELDB_VALUE_RESTORE_MAX, LEVELDB_VALUE_RESTORE_MAX + 1, + base::Histogram::kUmaTargetedHistogramFlag); base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "LeveldbValueStore", base::ThreadTaskRunnerHandle::Get()); } @@ -196,10 +211,10 @@ scoped_ptr<base::Value> value = json_reader.ReadToValue(it->value().ToString()); if (!value) { - return MakeReadResult(Status( - CORRUPTION, - Delete(key).ok() ? RESTORE_REPAIR_SUCCESS : RESTORE_DELETE_FAILURE, - kInvalidJson)); + return MakeReadResult( + Status(CORRUPTION, Delete(key).ok() ? VALUE_RESTORE_DELETE_SUCCESS + : VALUE_RESTORE_DELETE_FAILURE, + kInvalidJson)); } settings->SetWithoutPathExpansion(key, std::move(value)); } @@ -360,14 +375,20 @@ case RESTORE_NONE: NOTREACHED(); break; - case RESTORE_DELETE_SUCCESS: - restore_histogram_->Add(LEVELDB_RESTORE_DELETE_SUCCESS); + case DB_RESTORE_DELETE_SUCCESS: + db_restore_histogram_->Add(LEVELDB_DB_RESTORE_DELETE_SUCCESS); break; - case RESTORE_DELETE_FAILURE: - restore_histogram_->Add(LEVELDB_RESTORE_DELETE_FAILURE); + case DB_RESTORE_DELETE_FAILURE: + db_restore_histogram_->Add(LEVELDB_DB_RESTORE_DELETE_FAILURE); break; - case RESTORE_REPAIR_SUCCESS: - restore_histogram_->Add(LEVELDB_RESTORE_REPAIR_SUCCESS); + case DB_RESTORE_REPAIR_SUCCESS: + db_restore_histogram_->Add(LEVELDB_DB_RESTORE_REPAIR_SUCCESS); + break; + case VALUE_RESTORE_DELETE_SUCCESS: + value_restore_histogram_->Add(LEVELDB_VALUE_RESTORE_DELETE_SUCCESS); + break; + case VALUE_RESTORE_DELETE_FAILURE: + value_restore_histogram_->Add(LEVELDB_VALUE_RESTORE_DELETE_FAILURE); break; } return restore_status; @@ -381,9 +402,9 @@ // Deleting involves writing to the log, so it's possible to have a // perfectly OK database but still have a delete fail. if (s.ok()) - return LogRestoreStatus(RESTORE_REPAIR_SUCCESS); + return LogRestoreStatus(VALUE_RESTORE_DELETE_SUCCESS); else if (s.IsIOError()) - return LogRestoreStatus(RESTORE_DELETE_FAILURE); + return LogRestoreStatus(VALUE_RESTORE_DELETE_FAILURE); // Any other kind of failure triggers a db repair. } @@ -402,16 +423,16 @@ leveldb::DB* db = nullptr; if (s.ok()) { - restore_status = RESTORE_REPAIR_SUCCESS; + restore_status = DB_RESTORE_REPAIR_SUCCESS; s = leveldb::DB::Open(open_options_, db_path_.AsUTF8Unsafe(), &db); } if (!s.ok()) { if (DeleteDbFile()) { - restore_status = RESTORE_DELETE_SUCCESS; + restore_status = DB_RESTORE_DELETE_SUCCESS; s = leveldb::DB::Open(open_options_, db_path_.AsUTF8Unsafe(), &db); } else { - restore_status = RESTORE_DELETE_FAILURE; + restore_status = DB_RESTORE_DELETE_FAILURE; } } @@ -423,14 +444,14 @@ if (s.ok() && key) { s = Delete(*key); if (s.ok()) { - restore_status = RESTORE_REPAIR_SUCCESS; + restore_status = VALUE_RESTORE_DELETE_SUCCESS; } else if (s.IsIOError()) { - restore_status = RESTORE_DELETE_FAILURE; + restore_status = VALUE_RESTORE_DELETE_FAILURE; } else { db_.reset(db); if (!DeleteDbFile()) db_unrecoverable_ = true; - restore_status = RESTORE_DELETE_FAILURE; + restore_status = DB_RESTORE_DELETE_FAILURE; } } @@ -448,7 +469,7 @@ if (db_unrecoverable_) { return ValueStore::Status(ValueStore::CORRUPTION, - ValueStore::RESTORE_DELETE_FAILURE, + ValueStore::DB_RESTORE_DELETE_FAILURE, "Database corrupted"); } @@ -461,7 +482,7 @@ db_.reset(db); } else if (ldb_status.IsCorruption()) { status.restore_status = FixCorruption(nullptr); - if (status.restore_status != RESTORE_DELETE_FAILURE) { + if (status.restore_status != DB_RESTORE_DELETE_FAILURE) { status.code = OK; status.message = kRestoredDuringOpen; }
diff --git a/extensions/browser/value_store/leveldb_value_store.h b/extensions/browser/value_store/leveldb_value_store.h index 52ea6671..058e282 100644 --- a/extensions/browser/value_store/leveldb_value_store.h +++ b/extensions/browser/value_store/leveldb_value_store.h
@@ -115,7 +115,8 @@ // Database is corrupt - restoration failed. bool db_unrecoverable_; base::HistogramBase* open_histogram_; - base::HistogramBase* restore_histogram_; + base::HistogramBase* db_restore_histogram_; + base::HistogramBase* value_restore_histogram_; DISALLOW_COPY_AND_ASSIGN(LeveldbValueStore); };
diff --git a/extensions/browser/value_store/leveldb_value_store_unittest.cc b/extensions/browser/value_store/leveldb_value_store_unittest.cc index 6aeda43..cf53224 100644 --- a/extensions/browser/value_store/leveldb_value_store_unittest.cc +++ b/extensions/browser/value_store/leveldb_value_store_unittest.cc
@@ -134,7 +134,7 @@ ValueStore::ReadResult result = store()->Get(); ASSERT_FALSE(result->status().ok()); ASSERT_EQ(ValueStore::CORRUPTION, result->status().code); - ASSERT_EQ(ValueStore::RESTORE_REPAIR_SUCCESS, + ASSERT_EQ(ValueStore::VALUE_RESTORE_DELETE_SUCCESS, result->status().restore_status); // We should still have all valid pairs present in the database. @@ -183,7 +183,7 @@ // We couldn't recover anything, but we should be in a sane state again. ValueStore::ReadResult result = store()->Get(); - ASSERT_EQ(ValueStore::RESTORE_REPAIR_SUCCESS, + ASSERT_EQ(ValueStore::DB_RESTORE_REPAIR_SUCCESS, result->status().restore_status); EXPECT_TRUE(result->status().ok()); EXPECT_EQ(0u, result->settings().size());
diff --git a/extensions/browser/value_store/value_store.h b/extensions/browser/value_store/value_store.h index 8ca110f..b6aa0ba 100644 --- a/extensions/browser/value_store/value_store.h +++ b/extensions/browser/value_store/value_store.h
@@ -47,11 +47,15 @@ // No restore attempted. RESTORE_NONE, // Corrupted backing store successfully deleted. - RESTORE_DELETE_SUCCESS, + DB_RESTORE_DELETE_SUCCESS, // Corrupted backing store cannot be deleted. - RESTORE_DELETE_FAILURE, + DB_RESTORE_DELETE_FAILURE, // Corrupted backing store successfully repaired. - RESTORE_REPAIR_SUCCESS, + DB_RESTORE_REPAIR_SUCCESS, + // Corrupted value successfully deleted. + VALUE_RESTORE_DELETE_SUCCESS, + // Corrupted value cannot be deleted. + VALUE_RESTORE_DELETE_FAILURE, }; // The status (result) of an operation on a ValueStore.
diff --git a/extensions/common/view_type.h b/extensions/common/view_type.h index bbe498d..5fc7c273 100644 --- a/extensions/common/view_type.h +++ b/extensions/common/view_type.h
@@ -16,6 +16,7 @@ VIEW_TYPE_INVALID, VIEW_TYPE_APP_WINDOW, VIEW_TYPE_BACKGROUND_CONTENTS, + VIEW_TYPE_COMPONENT, // For custom parts of Chrome if no other type applies. VIEW_TYPE_EXTENSION_BACKGROUND_PAGE, VIEW_TYPE_EXTENSION_DIALOG, VIEW_TYPE_EXTENSION_GUEST, @@ -23,8 +24,7 @@ VIEW_TYPE_LAUNCHER_PAGE, VIEW_TYPE_PANEL, VIEW_TYPE_TAB_CONTENTS, - VIEW_TYPE_VIRTUAL_KEYBOARD, - VIEW_TYPE_LAST = VIEW_TYPE_VIRTUAL_KEYBOARD + VIEW_TYPE_LAST = VIEW_TYPE_TAB_CONTENTS }; // Constant strings corresponding to the Type enumeration values. Used
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn index f22f7e20..497c243 100644 --- a/gpu/command_buffer/service/BUILD.gn +++ b/gpu/command_buffer/service/BUILD.gn
@@ -51,6 +51,7 @@ "gl_context_virtual.h", "gl_state_restorer_impl.cc", "gl_state_restorer_impl.h", + "gl_utils.cc", "gl_utils.h", "gles2_cmd_clear_framebuffer.cc", "gles2_cmd_clear_framebuffer.h",
diff --git a/gpu/command_buffer/service/gl_utils.cc b/gpu/command_buffer/service/gl_utils.cc new file mode 100644 index 0000000..bb8ce4b --- /dev/null +++ b/gpu/command_buffer/service/gl_utils.cc
@@ -0,0 +1,26 @@ +// Copyright (c) 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 "gpu/command_buffer/service/gl_utils.h" + +#include "base/metrics/histogram.h" + +namespace gpu { +namespace gles2 { + +std::vector<int> GetAllGLErrors() { + int gl_errors[] = { + GL_NO_ERROR, + GL_INVALID_ENUM, + GL_INVALID_VALUE, + GL_INVALID_OPERATION, + GL_INVALID_FRAMEBUFFER_OPERATION, + GL_OUT_OF_MEMORY, + }; + return base::CustomHistogram::ArrayToCustomRanges(gl_errors, + arraysize(gl_errors)); +} + +} // namespace gles2 +} // namespace gpu
diff --git a/gpu/command_buffer/service/gl_utils.h b/gpu/command_buffer/service/gl_utils.h index ade4a37..9402eca 100644 --- a/gpu/command_buffer/service/gl_utils.h +++ b/gpu/command_buffer/service/gl_utils.h
@@ -8,6 +8,8 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_ #define GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_ +#include <vector> + #include "build/build_config.h" #include "ui/gl/gl_bindings.h" @@ -22,4 +24,12 @@ #define CHECK_GL_ERROR() void(0) #endif // GL_ERROR_DEBUGGING +namespace gpu { +namespace gles2 { + +std::vector<int> GetAllGLErrors(); + +} // gles2 +} // gpu + #endif // GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc index b2588b47..0ef43fb 100644 --- a/gpu/command_buffer/service/in_process_command_buffer.cc +++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -890,16 +890,9 @@ gles2::MailboxManager* mailbox_manager = decoder_->GetContextGroup()->mailbox_manager(); if (mailbox_manager->UsesSync()) { - bool make_current_success = false; - { - base::AutoLock lock(command_buffer_lock_); - make_current_success = MakeCurrent(); - } - if (make_current_success) { - SyncToken sync_token(GetNamespaceID(), GetExtraCommandBufferData(), - GetCommandBufferID(), release); - mailbox_manager->PushTextureUpdates(sync_token); - } + SyncToken sync_token(GetNamespaceID(), GetExtraCommandBufferData(), + GetCommandBufferID(), release); + mailbox_manager->PushTextureUpdates(sync_token); } sync_point_client_->ReleaseFenceSync(release);
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 1bce4948..82fab48 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc
@@ -13,6 +13,7 @@ #include "base/bits.h" #include "base/lazy_instance.h" +#include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" #include "base/thread_task_runner_handle.h" #include "base/trace_event/memory_dump_manager.h" @@ -2262,6 +2263,13 @@ } } GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, function_name); + if (args.command_type == DoTexImageArguments::kTexImage3D) { + UMA_HISTOGRAM_CUSTOM_ENUMERATION("GPU.Error.TexImage3D", error, + GetAllGLErrors()); + } else { + UMA_HISTOGRAM_CUSTOM_ENUMERATION("GPU.Error.TexImage2D", error, + GetAllGLErrors()); + } if (error == GL_NO_ERROR) { SetLevelInfo( texture_ref, args.target, args.level, args.internal_format, args.width,
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi index 7fc7de2..fc9f33f 100644 --- a/gpu/command_buffer_service.gypi +++ b/gpu/command_buffer_service.gypi
@@ -53,6 +53,7 @@ 'command_buffer/service/gl_context_virtual.h', 'command_buffer/service/gl_state_restorer_impl.cc', 'command_buffer/service/gl_state_restorer_impl.h', + 'command_buffer/service/gl_utils.cc', 'command_buffer/service/gl_utils.h', 'command_buffer/service/gles2_cmd_clear_framebuffer.cc', 'command_buffer/service/gles2_cmd_clear_framebuffer.h',
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn index d05cc79..1dddc13 100644 --- a/ipc/BUILD.gn +++ b/ipc/BUILD.gn
@@ -156,7 +156,6 @@ "attachment_broker_mac_unittest.cc", "attachment_broker_privileged_mac_unittest.cc", "attachment_broker_privileged_win_unittest.cc", - "attachment_broker_unprivileged_win_unittest.cc", "ipc_channel_posix_unittest.cc", "ipc_channel_proxy_unittest.cc", "ipc_channel_reader_unittest.cc",
diff --git a/ipc/attachment_broker_privileged_win.cc b/ipc/attachment_broker_privileged_win.cc index 38b2e652..c749a09 100644 --- a/ipc/attachment_broker_privileged_win.cc +++ b/ipc/attachment_broker_privileged_win.cc
@@ -23,12 +23,13 @@ base::ProcessId destination_process) { switch (attachment->GetBrokerableType()) { case BrokerableAttachment::WIN_HANDLE: { - const internal::HandleAttachmentWin* handle_attachment = - static_cast<const internal::HandleAttachmentWin*>(attachment.get()); + internal::HandleAttachmentWin* handle_attachment = + static_cast<internal::HandleAttachmentWin*>(attachment.get()); HandleWireFormat wire_format = handle_attachment->GetWireFormat(destination_process); HandleWireFormat new_wire_format = DuplicateWinHandle(wire_format, base::Process::Current().Pid()); + handle_attachment->reset_handle_ownership(); if (new_wire_format.handle == 0) return false; RouteDuplicatedHandle(new_wire_format); @@ -107,6 +108,10 @@ if (source_pid == wire_format.destination_process) return wire_format; + // If the handle is not valid, no additional work is required. + if (wire_format.handle == 0) + return wire_format; + base::Process source_process = base::Process::OpenWithExtraPrivileges(source_pid); base::Process dest_process =
diff --git a/ipc/attachment_broker_privileged_win.h b/ipc/attachment_broker_privileged_win.h index 70a4802b..467a977 100644 --- a/ipc/attachment_broker_privileged_win.h +++ b/ipc/attachment_broker_privileged_win.h
@@ -34,7 +34,7 @@ void OnDuplicateWinHandle(const Message& message); // Duplicates |wire_Format| from |source_process| into its destination - // process. + // process. Closes the original HANDLE. HandleWireFormat DuplicateWinHandle(const HandleWireFormat& wire_format, base::ProcessId source_process);
diff --git a/ipc/attachment_broker_privileged_win_unittest.cc b/ipc/attachment_broker_privileged_win_unittest.cc index 583050c..7a2be3b 100644 --- a/ipc/attachment_broker_privileged_win_unittest.cc +++ b/ipc/attachment_broker_privileged_win_unittest.cc
@@ -10,6 +10,9 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" +#include "base/memory/shared_memory_handle.h" +#include "base/win/scoped_handle.h" #include "ipc/attachment_broker_privileged_win.h" #include "ipc/attachment_broker_unprivileged_win.h" #include "ipc/handle_attachment_win.h" @@ -21,7 +24,10 @@ namespace { +using base::win::ScopedHandle; + const char kDataBuffer[] = "This is some test data to write to the file."; +const size_t kSharedMemorySize = 20000; // Returns the contents of the file represented by |h| as a std::string. std::string ReadFromFile(HANDLE h) { @@ -33,80 +39,107 @@ return success ? std::string(buffer, bytes_read) : std::string(); } -HANDLE GetHandleFromBrokeredAttachment( +ScopedHandle GetHandleFromBrokeredAttachment( const scoped_refptr<IPC::BrokerableAttachment>& attachment) { if (attachment->GetType() != IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) { LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT."; - return nullptr; + return ScopedHandle(nullptr); } if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::WIN_HANDLE) { LOG(INFO) << "Brokerable type not WIN_HANDLE."; - return nullptr; + return ScopedHandle(nullptr); } IPC::internal::HandleAttachmentWin* received_handle_attachment = static_cast<IPC::internal::HandleAttachmentWin*>(attachment.get()); - return received_handle_attachment->get_handle(); + ScopedHandle h(received_handle_attachment->get_handle()); + received_handle_attachment->reset_handle_ownership(); + return h; } // |message| must be deserializable as a TestHandleWinMsg. Returns the HANDLE, // or nullptr if deserialization failed. -HANDLE GetHandleFromTestHandleWinMsg(const IPC::Message& message) { +ScopedHandle GetHandleFromTestHandleWinMsg(const IPC::Message& message) { // Expect a message with a brokered attachment. if (!message.HasBrokerableAttachments()) { LOG(INFO) << "Message missing brokerable attachment."; - return nullptr; + return ScopedHandle(nullptr); } TestHandleWinMsg::Schema::Param p; bool success = TestHandleWinMsg::Read(&message, &p); if (!success) { LOG(INFO) << "Failed to deserialize message."; - return nullptr; + return ScopedHandle(nullptr); } IPC::HandleWin handle_win = base::get<1>(p); - return handle_win.get_handle(); + return ScopedHandle(handle_win.get_handle()); } -// |message| must be deserializable as a TestTwoHandleWinMsg. Returns the -// HANDLE, or nullptr if deserialization failed. -HANDLE GetHandleFromTestTwoHandleWinMsg(const IPC::Message& message, - int index) { +// Returns a mapped, shared memory region based on the handle in |message|. +scoped_ptr<base::SharedMemory> GetSharedMemoryFromSharedMemoryHandleMsg1( + const IPC::Message& message, + size_t size) { // Expect a message with a brokered attachment. if (!message.HasBrokerableAttachments()) { LOG(INFO) << "Message missing brokerable attachment."; return nullptr; } - TestTwoHandleWinMsg::Schema::Param p; - bool success = TestTwoHandleWinMsg::Read(&message, &p); + TestSharedMemoryHandleMsg1::Schema::Param p; + bool success = TestSharedMemoryHandleMsg1::Read(&message, &p); if (!success) { LOG(INFO) << "Failed to deserialize message."; return nullptr; } - IPC::HandleWin handle_win; - if (index == 0) - handle_win = base::get<0>(p); - else if (index == 1) - handle_win = base::get<1>(p); - return handle_win.get_handle(); + base::SharedMemoryHandle handle = base::get<0>(p); + scoped_ptr<base::SharedMemory> shared_memory( + new base::SharedMemory(handle, false)); + + shared_memory->Map(size); + return std::move(shared_memory); +} + +// |message| must be deserializable as a TestTwoHandleWinMsg. Returns the +// HANDLE, or nullptr if deserialization failed. +bool GetHandleFromTestTwoHandleWinMsg(const IPC::Message& message, + HANDLE* h1, + HANDLE* h2) { + // Expect a message with a brokered attachment. + if (!message.HasBrokerableAttachments()) { + LOG(INFO) << "Message missing brokerable attachment."; + return false; + } + + TestTwoHandleWinMsg::Schema::Param p; + bool success = TestTwoHandleWinMsg::Read(&message, &p); + if (!success) { + LOG(INFO) << "Failed to deserialize message."; + return false; + } + + IPC::HandleWin handle_win = base::get<0>(p); + *h1 = handle_win.get_handle(); + handle_win = base::get<1>(p); + *h2 = handle_win.get_handle(); + return true; } // |message| must be deserializable as a TestHandleWinMsg. Returns true if the // attached file HANDLE has contents |kDataBuffer|. bool CheckContentsOfTestMessage(const IPC::Message& message) { - HANDLE h = GetHandleFromTestHandleWinMsg(message); - if (h == nullptr) { + ScopedHandle h(GetHandleFromTestHandleWinMsg(message)); + if (h.Get() == nullptr) { LOG(INFO) << "Failed to get handle from TestHandleWinMsg."; return false; } - std::string contents = ReadFromFile(h); + std::string contents = ReadFromFile(h.Get()); bool success = (contents == std::string(kDataBuffer)); if (!success) { LOG(INFO) << "Expected contents: " << std::string(kDataBuffer); @@ -371,12 +404,12 @@ get_broker()->GetAttachmentWithId(*id, &received_attachment); ASSERT_NE(received_attachment.get(), nullptr); - // Check that it's the same entry in the HANDLE table. - HANDLE h2 = GetHandleFromBrokeredAttachment(received_attachment); - EXPECT_EQ(h2, h); + // Check that it's a different entry in the HANDLE table. + ScopedHandle h2(GetHandleFromBrokeredAttachment(received_attachment)); + EXPECT_NE(h2.Get(), h); - // And still points to the same file. - std::string contents = ReadFromFile(h); + // But still points to the same file. + std::string contents = ReadFromFile(h2.Get()); EXPECT_EQ(contents, std::string(kDataBuffer)); CommonTearDown(); @@ -435,6 +468,29 @@ CommonTearDown(); } +// An unprivileged process makes a shared memory region and sends it to the +// privileged process. +TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendSharedMemoryHandle) { + Init("SendSharedMemoryHandle"); + + CommonSetUp(); + ResultListener result_listener; + get_proxy_listener()->set_listener(&result_listener); + + scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory); + shared_memory->CreateAndMapAnonymous(kSharedMemorySize); + memcpy(shared_memory->memory(), kDataBuffer, strlen(kDataBuffer)); + sender()->Send(new TestSharedMemoryHandleMsg1(shared_memory->handle())); + base::MessageLoop::current()->Run(); + + // Check the result. + ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, + get_proxy_listener()->get_reason()); + ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS); + + CommonTearDown(); +} + using OnMessageReceivedCallback = void (*)(IPC::Sender* sender, const IPC::Message& message); @@ -481,14 +537,14 @@ void SendHandleWithoutPermissionsCallback(IPC::Sender* sender, const IPC::Message& message) { - HANDLE h = GetHandleFromTestHandleWinMsg(message); - if (h != nullptr) { - SetFilePointer(h, 0, nullptr, FILE_BEGIN); + ScopedHandle h(GetHandleFromTestHandleWinMsg(message)); + if (h.Get() != nullptr) { + SetFilePointer(h.Get(), 0, nullptr, FILE_BEGIN); char buffer[100]; DWORD bytes_read; BOOL success = - ::ReadFile(h, buffer, static_cast<DWORD>(strlen(kDataBuffer)), + ::ReadFile(h.Get(), buffer, static_cast<DWORD>(strlen(kDataBuffer)), &bytes_read, nullptr); if (!success && GetLastError() == ERROR_ACCESS_DENIED) { SendControlMessage(sender, true); @@ -516,8 +572,8 @@ void SendTwoHandlesCallback(IPC::Sender* sender, const IPC::Message& message) { // Check for two handles. - HANDLE h1 = GetHandleFromTestTwoHandleWinMsg(message, 0); - HANDLE h2 = GetHandleFromTestTwoHandleWinMsg(message, 1); + HANDLE h1, h2; + EXPECT_TRUE(GetHandleFromTestTwoHandleWinMsg(message, &h1, &h2)); if (h1 == nullptr || h2 == nullptr) { SendControlMessage(sender, false); return; @@ -579,4 +635,18 @@ "SendHandleTwice"); } +void SendSharedMemoryHandleCallback(IPC::Sender* sender, + const IPC::Message& message) { + scoped_ptr<base::SharedMemory> shared_memory = + GetSharedMemoryFromSharedMemoryHandleMsg1(message, kSharedMemorySize); + bool success = + memcmp(shared_memory->memory(), kDataBuffer, strlen(kDataBuffer)) == 0; + SendControlMessage(sender, success); +} + +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) { + return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback, + "SendSharedMemoryHandle"); +} + } // namespace
diff --git a/ipc/attachment_broker_unprivileged_win_unittest.cc b/ipc/attachment_broker_unprivileged_win_unittest.cc deleted file mode 100644 index e67c54a6..0000000 --- a/ipc/attachment_broker_unprivileged_win_unittest.cc +++ /dev/null
@@ -1,51 +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 "build/build_config.h" - -#include <windows.h> - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/process/process.h" -#include "ipc/attachment_broker_messages.h" -#include "ipc/attachment_broker_unprivileged_win.h" -#include "ipc/handle_attachment_win.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace IPC { - -TEST(AttachmentBrokerUnprivilegedWinTest, ReceiveValidMessage) { - HANDLE handle = LongToHandle(8); - base::ProcessId destination = base::Process::Current().Pid(); - scoped_refptr<internal::HandleAttachmentWin> attachment( - new internal::HandleAttachmentWin(handle, HandleWin::DUPLICATE)); - AttachmentBrokerMsg_WinHandleHasBeenDuplicated msg( - attachment->GetWireFormat(destination)); - AttachmentBrokerUnprivilegedWin attachment_broker; - EXPECT_TRUE(attachment_broker.OnMessageReceived(msg)); - EXPECT_EQ(1u, attachment_broker.attachments_.size()); - - scoped_refptr<BrokerableAttachment> received_attachment = - attachment_broker.attachments_.front(); - EXPECT_EQ(BrokerableAttachment::WIN_HANDLE, - received_attachment->GetBrokerableType()); - internal::HandleAttachmentWin* received_handle_attachment = - static_cast<internal::HandleAttachmentWin*>(received_attachment.get()); - EXPECT_EQ(handle, received_handle_attachment->get_handle()); -} - -TEST(AttachmentBrokerUnprivilegedWinTest, ReceiveInvalidMessage) { - HANDLE handle = LongToHandle(8); - base::ProcessId destination = base::Process::Current().Pid() + 1; - scoped_refptr<internal::HandleAttachmentWin> attachment( - new internal::HandleAttachmentWin(handle, HandleWin::DUPLICATE)); - AttachmentBrokerMsg_WinHandleHasBeenDuplicated msg( - attachment->GetWireFormat(destination)); - AttachmentBrokerUnprivilegedWin attachment_broker; - EXPECT_TRUE(attachment_broker.OnMessageReceived(msg)); - EXPECT_EQ(0u, attachment_broker.attachments_.size()); -} - -} // namespace IPC
diff --git a/ipc/handle_attachment_win.cc b/ipc/handle_attachment_win.cc index 5afd7fa..39c4ef7 100644 --- a/ipc/handle_attachment_win.cc +++ b/ipc/handle_attachment_win.cc
@@ -11,18 +11,24 @@ HandleAttachmentWin::HandleAttachmentWin(const HANDLE& handle, HandleWin::Permissions permissions) - : handle_(handle), permissions_(permissions), owns_handle_(true) {} + : handle_(INVALID_HANDLE_VALUE), + permissions_(HandleWin::INVALID), + owns_handle_(true) { + HANDLE duplicated_handle; + BOOL result = + ::DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), + &duplicated_handle, 0, FALSE, DUPLICATE_SAME_ACCESS); + if (result) { + handle_ = duplicated_handle; + permissions_ = permissions; + } +} HandleAttachmentWin::HandleAttachmentWin(const WireFormat& wire_format) : BrokerableAttachment(wire_format.attachment_id), handle_(LongToHandle(wire_format.handle)), - permissions_(wire_format.permissions), owns_handle_(false) {} - -HandleAttachmentWin::HandleAttachmentWin( - const BrokerableAttachment::AttachmentId& id) - : BrokerableAttachment(id), - handle_(INVALID_HANDLE_VALUE), - permissions_(HandleWin::INVALID), owns_handle_(false) {} + permissions_(wire_format.permissions), + owns_handle_(true) {} HandleAttachmentWin::~HandleAttachmentWin() { if (handle_ != INVALID_HANDLE_VALUE && owns_handle_)
diff --git a/ipc/handle_attachment_win.h b/ipc/handle_attachment_win.h index 35807b4..5e04bdb 100644 --- a/ipc/handle_attachment_win.h +++ b/ipc/handle_attachment_win.h
@@ -58,10 +58,9 @@ // result. Should only be called by the sender of a Chrome IPC message. HandleAttachmentWin(const HANDLE& handle, HandleWin::Permissions permissions); - // These constructors do not take ownership of the HANDLE, and should only be - // called by the receiver of a Chrome IPC message. + // This constructor takes ownership of |wire_format.handle| without making a + // copy. Should only be called by the receiver of a Chrome IPC message. explicit HandleAttachmentWin(const WireFormat& wire_format); - explicit HandleAttachmentWin(const BrokerableAttachment::AttachmentId& id); BrokerableType GetBrokerableType() const override; @@ -71,7 +70,10 @@ HANDLE get_handle() const { return handle_; } // The caller of this method has taken ownership of |handle_|. - void reset_handle_ownership() { owns_handle_ = false; } + void reset_handle_ownership() { + owns_handle_ = false; + handle_ = INVALID_HANDLE_VALUE; + } private: ~HandleAttachmentWin() override; @@ -81,9 +83,8 @@ // In the sender process, the attachment owns the HANDLE of a newly created // message. The attachment broker will eventually take ownership, and set // this member to |false|. - // In the destination process, the attachment never owns the Mach port. The - // client code that receives the Chrome IPC message is always expected to take - // ownership. + // In the destination process, the attachment owns the Mach port until a call + // to ParamTraits<HandleWin>::Read() takes ownership. bool owns_handle_; };
diff --git a/ipc/handle_win.cc b/ipc/handle_win.cc index 45fbae4..f964c832 100644 --- a/ipc/handle_win.cc +++ b/ipc/handle_win.cc
@@ -47,6 +47,7 @@ IPC::internal::HandleAttachmentWin* handle_attachment = static_cast<IPC::internal::HandleAttachmentWin*>(brokerable_attachment); r->set_handle(handle_attachment->get_handle()); + handle_attachment->reset_handle_ownership(); return true; }
diff --git a/ipc/ipc.gyp b/ipc/ipc.gyp index bc8659f..05b9989 100644 --- a/ipc/ipc.gyp +++ b/ipc/ipc.gyp
@@ -55,7 +55,6 @@ 'attachment_broker_mac_unittest.cc', 'attachment_broker_privileged_mac_unittest.cc', 'attachment_broker_privileged_win_unittest.cc', - 'attachment_broker_unprivileged_win_unittest.cc', 'ipc_channel_posix_unittest.cc', 'ipc_channel_proxy_unittest.cc', 'ipc_channel_reader_unittest.cc',
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc index 60ae58f..ea88b55 100644 --- a/ipc/ipc_message_utils.cc +++ b/ipc/ipc_message_utils.cc
@@ -660,9 +660,6 @@ #elif defined(OS_WIN) void ParamTraits<base::SharedMemoryHandle>::Write(Message* m, const param_type& p) { - // Longs on windows are 32 bits. - uint32_t pid = p.GetPID(); - m->WriteUInt32(pid); m->WriteBool(p.NeedsBrokering()); if (p.NeedsBrokering()) { @@ -676,11 +673,6 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const Message* m, base::PickleIterator* iter, param_type* r) { - uint32_t pid_int; - if (!iter->ReadUInt32(&pid_int)) - return false; - base::ProcessId pid = pid_int; - bool needs_brokering; if (!iter->ReadBool(&needs_brokering)) return false; @@ -689,7 +681,8 @@ HandleWin handle_win; if (!ParamTraits<HandleWin>::Read(m, iter, &handle_win)) return false; - *r = base::SharedMemoryHandle(handle_win.get_handle(), pid); + *r = base::SharedMemoryHandle(handle_win.get_handle(), + base::GetCurrentProcId()); return true; } @@ -697,14 +690,12 @@ if (!iter->ReadInt(&handle_int)) return false; HANDLE handle = LongToHandle(handle_int); - *r = base::SharedMemoryHandle(handle, pid); + *r = base::SharedMemoryHandle(handle, base::GetCurrentProcId()); return true; } void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p, std::string* l) { - LogParam(p.GetPID(), l); - l->append(" "); LogParam(p.GetHandle(), l); l->append(" needs brokering: "); LogParam(p.NeedsBrokering(), l);
diff --git a/ipc/ipc_test_messages.h b/ipc/ipc_test_messages.h index 62af9137..a61d1b0 100644 --- a/ipc/ipc_test_messages.h +++ b/ipc/ipc_test_messages.h
@@ -9,10 +9,12 @@ #define IPC_MESSAGE_START IPCTestMsgStart #if defined(OS_WIN) +#include "base/memory/shared_memory_handle.h" #include "ipc/handle_win.h" IPC_MESSAGE_CONTROL3(TestHandleWinMsg, int, IPC::HandleWin, int) IPC_MESSAGE_CONTROL2(TestTwoHandleWinMsg, IPC::HandleWin, IPC::HandleWin) +IPC_MESSAGE_CONTROL1(TestSharedMemoryHandleMsg1, base::SharedMemoryHandle) #endif // defined(OS_WIN) #if defined(OS_MACOSX)
diff --git a/mandoline/app/android/BUILD.gn b/mandoline/app/android/BUILD.gn index e5e50b0b..d74f42c7 100644 --- a/mandoline/app/android/BUILD.gn +++ b/mandoline/app/android/BUILD.gn
@@ -21,11 +21,11 @@ "//mandoline/ui/desktop_ui/public/interfaces", "//mojo/common", "//mojo/environment:chromium", - "//mojo/package_manager", "//mojo/runner:lib", "//mojo/runner:mojo_runner_lib", "//mojo/runner:register_local_aliases_fwd", "//mojo/shell", + "//mojo/shell/package_manager", ] sources = [
diff --git a/mandoline/app/desktop/BUILD.gn b/mandoline/app/desktop/BUILD.gn index e43c1933..0d527f9 100644 --- a/mandoline/app/desktop/BUILD.gn +++ b/mandoline/app/desktop/BUILD.gn
@@ -20,12 +20,12 @@ "//components/tracing:startup_tracing", "//mojo/common", "//mojo/environment:chromium", - "//mojo/package_manager", "//mojo/runner:lib", "//mojo/runner:register_local_aliases_fwd", "//mojo/runner/host:lib", "//mojo/runner/host:switches", "//mojo/shell", + "//mojo/shell/package_manager", ] data_deps = [
diff --git a/mandoline/app/register_local_aliases.cc b/mandoline/app/register_local_aliases.cc index b9c7375..3cc613fc 100644 --- a/mandoline/app/register_local_aliases.cc +++ b/mandoline/app/register_local_aliases.cc
@@ -4,12 +4,12 @@ #include "mojo/runner/register_local_aliases.h" -#include "mojo/package_manager/package_manager_impl.h" +#include "mojo/shell/package_manager/package_manager_impl.h" namespace mojo { namespace runner { -void RegisterLocalAliases(mojo::package_manager::PackageManagerImpl* manager) { +void RegisterLocalAliases(shell::PackageManagerImpl* manager) { // TODO(erg): We should probably handle this differently; these could be // autogenerated from package manifests. manager->RegisterApplicationPackageAlias(
diff --git a/mash/BUILD.gn b/mash/BUILD.gn index 5b29b266..8550b7cf 100644 --- a/mash/BUILD.gn +++ b/mash/BUILD.gn
@@ -14,6 +14,7 @@ "//mash/quick_launch", "//mash/shell", "//mash/task_viewer", + "//mash/wallpaper", "//mash/wm", ] }
diff --git a/mash/shell/shell_application_delegate.cc b/mash/shell/shell_application_delegate.cc index b370835..df38cba 100644 --- a/mash/shell/shell_application_delegate.cc +++ b/mash/shell/shell_application_delegate.cc
@@ -19,6 +19,7 @@ app_ = app; StartBrowserDriver(); StartWindowManager(); + StartWallpaper(); StartSystemUI(); StartQuickLaunch(); } @@ -35,6 +36,12 @@ base::Unretained(this))); } +void ShellApplicationDelegate::StartWallpaper() { + StartRestartableService("mojo:wallpaper", + base::Bind(&ShellApplicationDelegate::StartWallpaper, + base::Unretained(this))); +} + void ShellApplicationDelegate::StartSystemUI() { StartRestartableService("mojo:system_ui", base::Bind(&ShellApplicationDelegate::StartSystemUI,
diff --git a/mash/shell/shell_application_delegate.h b/mash/shell/shell_application_delegate.h index e93afd7..3b93781 100644 --- a/mash/shell/shell_application_delegate.h +++ b/mash/shell/shell_application_delegate.h
@@ -31,6 +31,7 @@ mojo::ApplicationConnection* connection) override; void StartWindowManager(); + void StartWallpaper(); void StartSystemUI(); void StartBrowserDriver(); void StartQuickLaunch();
diff --git a/mash/system_ui/system_ui.cc b/mash/system_ui/system_ui.cc index 6c4852e3e..8f589dc 100644 --- a/mash/system_ui/system_ui.cc +++ b/mash/system_ui/system_ui.cc
@@ -19,44 +19,8 @@ namespace mash { namespace system_ui { - namespace { -class DesktopBackground : public views::WidgetDelegateView { - public: - static void Create(mojo::Shell* shell) { - views::Widget* widget = new views::Widget; - views::Widget::InitParams params( - views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); - params.delegate = new DesktopBackground; - - std::map<std::string, std::vector<uint8_t>> properties; - properties[mash::wm::mojom::kWindowContainer_Property] = - mojo::TypeConverter<const std::vector<uint8_t>, int32_t>::Convert( - mash::wm::mojom::CONTAINER_USER_BACKGROUND); - mus::Window* window = - views::WindowManagerConnection::Get()->NewWindow(properties); - params.native_widget = new views::NativeWidgetMus( - widget, shell, window, mus::mojom::SURFACE_TYPE_DEFAULT); - widget->Init(params); - widget->Show(); - } - - private: - DesktopBackground() {} - ~DesktopBackground() override {} - - // Overridden from views::View: - void OnPaint(gfx::Canvas* canvas) override { - canvas->FillRect(GetLocalBounds(), SK_ColorRED); - } - - // Overridden from views::WidgetDelegate: - views::View* GetContentsView() override { return this; } - - DISALLOW_COPY_AND_ASSIGN(DesktopBackground); -}; - class Shelf : public views::WidgetDelegateView { public: static void Create(mojo::Shell* shell) { @@ -106,7 +70,6 @@ aura_init_.reset(new views::AuraInit(app, "views_mus_resources.pak")); views::WindowManagerConnection::Create(app); - DesktopBackground::Create(app->shell()); Shelf::Create(app->shell()); }
diff --git a/mash/wallpaper/BUILD.gn b/mash/wallpaper/BUILD.gn new file mode 100644 index 0000000..f070860 --- /dev/null +++ b/mash/wallpaper/BUILD.gn
@@ -0,0 +1,34 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/ui.gni") +import("//mojo/public/mojo_application.gni") +import("//mojo/public/tools/bindings/mojom.gni") + +mojo_native_application("wallpaper") { + sources = [ + "wallpaper.cc", + ] + + deps = [ + "//base", + "//components/mus/public/cpp", + "//components/mus/public/interfaces", + "//mash/wm/public/interfaces", + "//mojo/application/public/cpp", + "//mojo/application/public/cpp:sources", + "//mojo/application/public/interfaces", + "//mojo/public/cpp/bindings", + "//mojo/services/tracing/public/cpp", + "//ui/views", + "//ui/views/mus:for_mojo_application", + "//url", + ] + + resources = [ "$root_out_dir/views_mus_resources.pak" ] + + data_deps = [ + "//components/mus", + ] +}
diff --git a/mash/wallpaper/wallpaper.cc b/mash/wallpaper/wallpaper.cc new file mode 100644 index 0000000..a725ceff --- /dev/null +++ b/mash/wallpaper/wallpaper.cc
@@ -0,0 +1,84 @@ +// 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 "base/macros.h" +#include "components/mus/public/cpp/property_type_converters.h" +#include "mash/wm/public/interfaces/container.mojom.h" +#include "mojo/application/public/cpp/application_connection.h" +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "mojo/application/public/cpp/application_runner.h" +#include "mojo/public/c/system/main.h" +#include "mojo/services/tracing/public/cpp/tracing_impl.h" +#include "ui/gfx/canvas.h" +#include "ui/views/mus/aura_init.h" +#include "ui/views/mus/native_widget_mus.h" +#include "ui/views/mus/window_manager_connection.h" +#include "ui/views/widget/widget_delegate.h" + +namespace mash { +namespace wallpaper { +namespace { + +class Wallpaper : public views::WidgetDelegateView { + public: + Wallpaper() {} + ~Wallpaper() override {} + + // Overridden from views::View: + void OnPaint(gfx::Canvas* canvas) override { + canvas->FillRect(GetLocalBounds(), SK_ColorRED); + } + + // Overridden from views::WidgetDelegate: + views::View* GetContentsView() override { return this; } + + DISALLOW_COPY_AND_ASSIGN(Wallpaper); +}; + +class WallpaperApplicationDelegate : public mojo::ApplicationDelegate { + public: + WallpaperApplicationDelegate() {} + ~WallpaperApplicationDelegate() override {} + + private: + // mojo::ApplicationDelegate: + void Initialize(mojo::ApplicationImpl* app) override { + tracing_.Initialize(app); + + aura_init_.reset(new views::AuraInit(app, "views_mus_resources.pak")); + views::WindowManagerConnection::Create(app); + + views::Widget* widget = new views::Widget; + views::Widget::InitParams params( + views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.delegate = new Wallpaper; + + std::map<std::string, std::vector<uint8_t>> properties; + properties[mash::wm::mojom::kWindowContainer_Property] = + mojo::TypeConverter<const std::vector<uint8_t>, int32_t>::Convert( + mash::wm::mojom::CONTAINER_USER_BACKGROUND); + mus::Window* window = + views::WindowManagerConnection::Get()->NewWindow(properties); + params.native_widget = new views::NativeWidgetMus( + widget, app->shell(), window, mus::mojom::SURFACE_TYPE_DEFAULT); + widget->Init(params); + widget->Show(); + } + + mojo::TracingImpl tracing_; + scoped_ptr<views::AuraInit> aura_init_; + + DISALLOW_COPY_AND_ASSIGN(WallpaperApplicationDelegate); +}; + +} // namespace +} // namespace wallpaper +} // namespace mash + +MojoResult MojoMain(MojoHandle shell_handle) { + mojo::ApplicationRunner runner( + new mash::wallpaper::WallpaperApplicationDelegate); + return runner.Run(shell_handle); +}
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java index 1bd40fd..e01c26e 100644 --- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java +++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
@@ -232,7 +232,10 @@ if (isSecure && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return result; // Do not create codec for blacklisted devices. - if (!isDecoderSupportedForDevice(mime)) return result; + if (!isDecoderSupportedForDevice(mime)) { + Log.e(TAG, "Decoder for type " + mime + " is not supported on this device"); + return result; + } try { // |isSecure| only applies to video decoders. @@ -271,11 +274,24 @@ */ private static boolean isDecoderSupportedForDevice(String mime) { if (mime.equals("video/x-vnd.on2.vp8")) { - // Samsung Galaxy S4 Mini cannot render the frames decoded with VP8 - if (Build.MANUFACTURER.toLowerCase(Locale.getDefault()).equals("samsung") - && Build.MODEL.equals("GT-I9190")) { - Log.e(TAG, "VP8 video decoder is not supported on this device"); - return false; + // Some Samsung devices cannot render VP8 video directly to the surface. + if (Build.MANUFACTURER.toLowerCase(Locale.getDefault()).equals("samsung")) { + // Samsung Galaxy S4. + // Only GT-I9505G with Android 4.3 and SPH-L720 (Sprint) with Android 5.0.1 + // were tested. Only the first device has the problem. + // We blacklist popular Samsung Galaxy S4 models before Android L. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP + && (Build.MODEL.startsWith("GT-I9505") + || (Build.MODEL.startsWith("GT-I9500")))) { + return false; + } + + // Samsung Galaxy S4 Mini. + // Only GT-I9190 was tested with Android 4.4.2 + // We blacklist it and the popular GT-I9195 for all Android versions. + if (Build.MODEL.startsWith("GT-I9190") || (Build.MODEL.startsWith("GT-I9195"))) { + return false; + } } }
diff --git a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java index e662db3..a3a38ba0 100644 --- a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java +++ b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
@@ -6,6 +6,7 @@ import android.content.Context; import android.media.MediaPlayer; +import android.media.MediaPlayer.TrackInfo; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; @@ -97,6 +98,40 @@ } @CalledByNative + protected boolean hasVideo() { + TrackInfo trackInfo[] = getLocalPlayer().getTrackInfo(); + + // HLS media does not have the track info, so we treat them conservatively. + if (trackInfo.length == 0) return true; + + for (TrackInfo info : trackInfo) { + // TODO(zqzhang): may be we can have a histogram recording + // media track types in the future. + // See http://crbug.com/571411 + if (TrackInfo.MEDIA_TRACK_TYPE_VIDEO == info.getTrackType()) return true; + if (TrackInfo.MEDIA_TRACK_TYPE_UNKNOWN == info.getTrackType()) return true; + } + return false; + } + + @CalledByNative + protected boolean hasAudio() { + TrackInfo trackInfo[] = getLocalPlayer().getTrackInfo(); + + // HLS media does not have the track info, so we treat them conservatively. + if (trackInfo.length == 0) return true; + + for (TrackInfo info : trackInfo) { + // TODO(zqzhang): may be we can have a histogram recording + // media track types in the future. + // See http://crbug.com/571411 + if (TrackInfo.MEDIA_TRACK_TYPE_AUDIO == info.getTrackType()) return true; + if (TrackInfo.MEDIA_TRACK_TYPE_UNKNOWN == info.getTrackType()) return true; + } + return false; + } + + @CalledByNative protected int getVideoWidth() { return getLocalPlayer().getVideoWidth(); }
diff --git a/media/base/android/media_codec_player.cc b/media/base/android/media_codec_player.cc index 6e3e1a9..565c745 100644 --- a/media/base/android/media_codec_player.cc +++ b/media/base/android/media_codec_player.cc
@@ -366,6 +366,16 @@ audio_decoder_->SetVolume(volume); } +bool MediaCodecPlayer::HasAudio() const { + DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); + return audio_decoder_->HasStream(); +} + +bool MediaCodecPlayer::HasVideo() const { + DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); + return video_decoder_->HasStream(); +} + int MediaCodecPlayer::GetVideoWidth() { DCHECK(ui_task_runner_->BelongsToCurrentThread()); return metadata_cache_.video_size.width(); @@ -611,12 +621,12 @@ // Events from Player, called on UI thread -void MediaCodecPlayer::RequestPermissionAndPostResult( - base::TimeDelta duration) { +void MediaCodecPlayer::RequestPermissionAndPostResult(base::TimeDelta duration, + bool has_audio) { DCHECK(ui_task_runner_->BelongsToCurrentThread()); DVLOG(1) << __FUNCTION__ << " duration:" << duration; - bool granted = manager()->RequestPlay(player_id(), duration); + bool granted = manager()->RequestPlay(player_id(), duration, has_audio); GetMediaTaskRunner()->PostTask( FROM_HERE, base::Bind(&MediaCodecPlayer::OnPermissionDecided, media_weak_this_, granted)); @@ -1022,16 +1032,6 @@ return pending_seek_; } -bool MediaCodecPlayer::HasAudio() const { - DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); - return audio_decoder_->HasStream(); -} - -bool MediaCodecPlayer::HasVideo() const { - DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); - return video_decoder_->HasStream(); -} - void MediaCodecPlayer::SetDemuxerConfigs(const DemuxerConfigs& configs) { DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); DVLOG(1) << __FUNCTION__ << " " << configs; @@ -1064,7 +1064,7 @@ ui_task_runner_->PostTask( FROM_HERE, base::Bind(&MediaPlayerAndroid::RequestPermissionAndPostResult, - WeakPtrForUIThread(), duration_)); + WeakPtrForUIThread(), duration_, HasAudio())); } void MediaCodecPlayer::StartPrefetchDecoders() {
diff --git a/media/base/android/media_codec_player.h b/media/base/android/media_codec_player.h index 0898b1f..eca83e2 100644 --- a/media/base/android/media_codec_player.h +++ b/media/base/android/media_codec_player.h
@@ -205,6 +205,8 @@ void SeekTo(base::TimeDelta timestamp) override; void Release() override; void SetVolume(double volume) override; + bool HasVideo() const override; + bool HasAudio() const override; int GetVideoWidth() override; int GetVideoHeight() override; base::TimeDelta GetCurrentTime() override; @@ -267,10 +269,12 @@ // MediaPlayerAndroid implementation. - // This method requests playback permission from the manager on UI thread, - // passing total duration as an argiment. The duration must be known by the - // time of the call. The method posts the result to the media thread. - void RequestPermissionAndPostResult(base::TimeDelta duration) override; + // This method requests playback permission from the manager on UI + // thread, passing total duration and whether the media has audio + // track as arguments. The method posts the result to the media + // thread. + void RequestPermissionAndPostResult(base::TimeDelta duration, + bool has_audio) override; // This method caches the data and calls manager's OnMediaMetadataChanged(). void OnMediaMetadataChanged(base::TimeDelta duration, @@ -311,8 +315,6 @@ bool HasPendingStart() const; void SetPendingSeek(base::TimeDelta timestamp); base::TimeDelta GetPendingSeek() const; - bool HasVideo() const; - bool HasAudio() const; void SetDemuxerConfigs(const DemuxerConfigs& configs); void RequestPlayPermission(); void StartPrefetchDecoders();
diff --git a/media/base/android/media_codec_player_unittest.cc b/media/base/android/media_codec_player_unittest.cc index a3791d00..5281c42 100644 --- a/media/base/android/media_codec_player_unittest.cc +++ b/media/base/android/media_codec_player_unittest.cc
@@ -131,7 +131,9 @@ void OnWaitingForDecryptionKey(int player_id) override {} MediaPlayerAndroid* GetFullscreenPlayer() override { return nullptr; } MediaPlayerAndroid* GetPlayer(int player_id) override { return nullptr; } - bool RequestPlay(int player_id, base::TimeDelta duration) override { + bool RequestPlay(int player_id, + base::TimeDelta duration, + bool has_audio) override { return playback_allowed_; }
diff --git a/media/base/android/media_player_android.h b/media/base/android/media_player_android.h index 3ef1e7b..3f07a93 100644 --- a/media/base/android/media_player_android.h +++ b/media/base/android/media_player_android.h
@@ -66,6 +66,8 @@ virtual void SetVolume(double volume) = 0; // Get the media information from the player. + virtual bool HasVideo() const = 0; + virtual bool HasAudio() const = 0; virtual int GetVideoWidth() = 0; virtual int GetVideoHeight() = 0; virtual base::TimeDelta GetDuration() = 0; @@ -83,7 +85,8 @@ // Requests playback permission from MediaPlayerManager. // Overridden in MediaCodecPlayer to pass data between threads. - virtual void RequestPermissionAndPostResult(base::TimeDelta duration) {} + virtual void RequestPermissionAndPostResult(base::TimeDelta duration, + bool has_audio) {} // Overridden in MediaCodecPlayer to pass data between threads. virtual void OnMediaMetadataChanged(base::TimeDelta duration,
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc index 3a2a2308..deaba14 100644 --- a/media/base/android/media_player_bridge.cc +++ b/media/base/android/media_player_bridge.cc
@@ -310,6 +310,16 @@ return result; } +bool MediaPlayerBridge::HasVideo() const { + JNIEnv* env = base::android::AttachCurrentThread(); + return Java_MediaPlayerBridge_hasVideo(env, j_media_player_bridge_.obj()); +} + +bool MediaPlayerBridge::HasAudio() const { + JNIEnv* env = base::android::AttachCurrentThread(); + return Java_MediaPlayerBridge_hasAudio(env, j_media_player_bridge_.obj()); +} + int MediaPlayerBridge::GetVideoWidth() { if (!prepared_) return width_; @@ -453,7 +463,7 @@ } void MediaPlayerBridge::StartInternal() { - if (!manager()->RequestPlay(player_id(), duration_)) { + if (!manager()->RequestPlay(player_id(), duration_, HasAudio())) { Pause(true); return; }
diff --git a/media/base/android/media_player_bridge.h b/media/base/android/media_player_bridge.h index ed84dafc..b347e540 100644 --- a/media/base/android/media_player_bridge.h +++ b/media/base/android/media_player_bridge.h
@@ -65,6 +65,8 @@ void SeekTo(base::TimeDelta timestamp) override; void Release() override; void SetVolume(double volume) override; + bool HasVideo() const override; + bool HasAudio() const override; int GetVideoWidth() override; int GetVideoHeight() override; base::TimeDelta GetCurrentTime() override;
diff --git a/media/base/android/media_player_bridge_unittest.cc b/media/base/android/media_player_bridge_unittest.cc index 7d0136b..c2b2447b 100644 --- a/media/base/android/media_player_bridge_unittest.cc +++ b/media/base/android/media_player_bridge_unittest.cc
@@ -38,7 +38,8 @@ MOCK_METHOD1(OnWaitingForDecryptionKey, void(int player_id)); MOCK_METHOD0(GetFullscreenPlayer, MediaPlayerAndroid*()); MOCK_METHOD1(GetPlayer, MediaPlayerAndroid*(int player_id)); - MOCK_METHOD2(RequestPlay, bool(int player_id, base::TimeDelta duration)); + MOCK_METHOD3(RequestPlay, + bool(int player_id, base::TimeDelta duration, bool has_audio)); void OnMediaResourcesRequested(int player_id) {} };
diff --git a/media/base/android/media_player_manager.h b/media/base/android/media_player_manager.h index 802c1c9..d1db8f3 100644 --- a/media/base/android/media_player_manager.h +++ b/media/base/android/media_player_manager.h
@@ -76,7 +76,9 @@ // manager should use this opportunity to check if the current context is // appropriate for a media to play. // Returns whether the request was granted. - virtual bool RequestPlay(int player_id, base::TimeDelta duration) = 0; + virtual bool RequestPlay(int player_id, + base::TimeDelta duration, + bool has_audio) = 0; }; } // namespace media
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc index 215577b..84c0b43 100644 --- a/media/base/android/media_source_player.cc +++ b/media/base/android/media_source_player.cc
@@ -147,6 +147,14 @@ return playing_; } +bool MediaSourcePlayer::HasVideo() const { + return video_decoder_job_->HasStream(); +} + +bool MediaSourcePlayer::HasAudio() const { + return audio_decoder_job_->HasStream(); +} + int MediaSourcePlayer::GetVideoWidth() { return video_decoder_job_->output_width(); } @@ -225,7 +233,7 @@ if (pending_event_ != NO_EVENT_PENDING) return; - if (!manager()->RequestPlay(player_id(), duration_)) { + if (!manager()->RequestPlay(player_id(), duration_, HasAudio())) { Pause(true); return; } @@ -675,14 +683,6 @@ start_time_ticks_ = base::TimeTicks(); } -bool MediaSourcePlayer::HasVideo() const { - return video_decoder_job_->HasStream(); -} - -bool MediaSourcePlayer::HasAudio() const { - return audio_decoder_job_->HasStream(); -} - bool MediaSourcePlayer::AudioFinished() { return audio_decoder_job_->OutputEOSReached() || !HasAudio(); }
diff --git a/media/base/android/media_source_player.h b/media/base/android/media_source_player.h index 20017f1..f2ea9ba 100644 --- a/media/base/android/media_source_player.h +++ b/media/base/android/media_source_player.h
@@ -55,6 +55,8 @@ void SeekTo(base::TimeDelta timestamp) override; void Release() override; void SetVolume(double volume) override; + bool HasVideo() const override; + bool HasAudio() const override; int GetVideoWidth() override; int GetVideoHeight() override; base::TimeDelta GetCurrentTime() override; @@ -111,10 +113,6 @@ void DecodeMoreAudio(); void DecodeMoreVideo(); - // Functions check whether audio/video is present. - bool HasVideo() const; - bool HasAudio() const; - // Functions that check whether audio/video stream has reached end of output // or are not present in player configuration. bool AudioFinished();
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc index ce9c5c4..0ce01abf 100644 --- a/media/base/android/media_source_player_unittest.cc +++ b/media/base/android/media_source_player_unittest.cc
@@ -77,7 +77,9 @@ MediaPlayerAndroid* GetPlayer(int player_id) override { return NULL; } void OnDecorderResourcesReleased(int player_id) {} - bool RequestPlay(int player_id, base::TimeDelta duration) override { + bool RequestPlay(int player_id, + base::TimeDelta duration, + bool has_audio) override { return allow_play_; }
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc index 213cb10..17f039f 100644 --- a/media/base/audio_decoder_config.cc +++ b/media/base/audio_decoder_config.cc
@@ -114,14 +114,14 @@ return "amr_nb"; case kCodecAMR_WB: return "amr_wb"; - case kCodecGSM_MS: - return "gsm_ms"; - case kCodecPCM_ALAW: - return "pcm_alaw"; case kCodecPCM_MULAW: return "pcm_mulaw"; + case kCodecGSM_MS: + return "gsm_ms"; case kCodecOpus: return "opus"; + case kCodecPCM_ALAW: + return "pcm_alaw"; case kCodecALAC: return "alac"; }
diff --git a/media/base/mime_util.cc b/media/base/mime_util.cc index ba52704..01422b26 100644 --- a/media/base/mime_util.cc +++ b/media/base/mime_util.cc
@@ -145,13 +145,23 @@ case MimeUtil::MPEG4_AAC_LC: case MimeUtil::MPEG4_AAC_SBR_v1: case MimeUtil::MPEG4_AAC_SBR_PS_v2: + case MimeUtil::VORBIS: case MimeUtil::H264_BASELINE: case MimeUtil::H264_MAIN: case MimeUtil::H264_HIGH: case MimeUtil::VP8: - case MimeUtil::VORBIS: return true; + case MimeUtil::MPEG2_AAC_LC: + case MimeUtil::MPEG2_AAC_MAIN: + case MimeUtil::MPEG2_AAC_SSR: + // MPEG-2 variants of AAC are not supported on Android. + return false; + + case MimeUtil::OPUS: + // Opus is supported only in Lollipop+ (API Level 21). + return base::android::BuildInfo::GetInstance()->sdk_int() >= 21; + case MimeUtil::HEVC_MAIN: #if defined(ENABLE_HEVC_DEMUXING) // HEVC/H.265 is supported in Lollipop+ (API Level 21), according to @@ -161,20 +171,10 @@ return false; #endif - case MimeUtil::MPEG2_AAC_LC: - case MimeUtil::MPEG2_AAC_MAIN: - case MimeUtil::MPEG2_AAC_SSR: - // MPEG-2 variants of AAC are not supported on Android. - return false; - case MimeUtil::VP9: // VP9 is supported only in KitKat+ (API Level 19). return base::android::BuildInfo::GetInstance()->sdk_int() >= 19; - case MimeUtil::OPUS: - // Opus is supported only in Lollipop+ (API Level 21). - return base::android::BuildInfo::GetInstance()->sdk_int() >= 21; - case MimeUtil::THEORA: return false; } @@ -279,6 +279,7 @@ static const CodecIDMappings kUnambiguousCodecStringMap[] = { {"1", MimeUtil::PCM}, // We only allow this for WAV so it isn't ambiguous. // avc1/avc3.XXXXXX may be unambiguous; handled by ParseH264CodecID(). + // hev1/hvc1.XXXXXX may be unambiguous; handled by ParseHEVCCodecID(). {"mp3", MimeUtil::MP3}, {"mp4a.66", MimeUtil::MPEG2_AAC_MAIN}, {"mp4a.67", MimeUtil::MPEG2_AAC_LC},
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc index f264287b..249e561 100644 --- a/media/blink/cdm_session_adapter.cc +++ b/media/blink/cdm_session_adapter.cc
@@ -134,7 +134,8 @@ base::TimeTicks start_time, const scoped_refptr<MediaKeys>& cdm, const std::string& error_message) { - DVLOG(2) << __FUNCTION__; + DVLOG(2) << __FUNCTION__ << ": " + << (cdm ? "success" : "failure (" + error_message + ")"); DCHECK(!cdm_); TRACE_EVENT_ASYNC_END2("media", "CdmSessionAdapter::CreateCdm", trace_id_,
diff --git a/media/capture/content/feedback_signal_accumulator.cc b/media/capture/content/feedback_signal_accumulator.cc index 896c23a..ba0e08e 100644 --- a/media/capture/content/feedback_signal_accumulator.cc +++ b/media/capture/content/feedback_signal_accumulator.cc
@@ -1,6 +1,8 @@ // Copyright (c) 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 MEDIA_CAPTURE_FEEDBACK_SIGNAL_ACCUMULATOR_CC_ +#define MEDIA_CAPTURE_FEEDBACK_SIGNAL_ACCUMULATOR_CC_ #include "media/capture/content/feedback_signal_accumulator.h" @@ -9,21 +11,24 @@ namespace media { -FeedbackSignalAccumulator::FeedbackSignalAccumulator(base::TimeDelta half_life) - : half_life_(half_life) { +template <typename TimeType> +FeedbackSignalAccumulator<TimeType>::FeedbackSignalAccumulator( + base::TimeDelta half_life) + : half_life_(half_life), average_(NAN) { DCHECK(half_life_ > base::TimeDelta()); } -void FeedbackSignalAccumulator::Reset(double starting_value, - base::TimeTicks timestamp) { - DCHECK(!timestamp.is_null()); +template <typename TimeType> +void FeedbackSignalAccumulator<TimeType>::Reset(double starting_value, + TimeType timestamp) { average_ = update_value_ = prior_average_ = starting_value; reset_time_ = update_time_ = prior_update_time_ = timestamp; } -bool FeedbackSignalAccumulator::Update(double value, - base::TimeTicks timestamp) { - DCHECK(!reset_time_.is_null()); +template <typename TimeType> +bool FeedbackSignalAccumulator<TimeType>::Update(double value, + TimeType timestamp) { + DCHECK(!std::isnan(average_)) << "Reset() must be called once."; if (timestamp < update_time_) { return false; // Not in chronological order. @@ -53,4 +58,8 @@ return true; } +template class MEDIA_EXPORT FeedbackSignalAccumulator<base::TimeDelta>; +template class MEDIA_EXPORT FeedbackSignalAccumulator<base::TimeTicks>; } // namespace media + +#endif // MEDIA_CAPTURE_FEEDBACK_SIGNAL_ACCUMULATOR_CC_
diff --git a/media/capture/content/feedback_signal_accumulator.h b/media/capture/content/feedback_signal_accumulator.h index 3905d58a..08a11e90 100644 --- a/media/capture/content/feedback_signal_accumulator.h +++ b/media/capture/content/feedback_signal_accumulator.h
@@ -23,7 +23,11 @@ // // Usage note: Reset() must be called at least once before the first call to // Update(). -class MEDIA_EXPORT FeedbackSignalAccumulator { +// +// This template class supports data points that are timestamped using either +// |base::TimeDelta| or |base::TimeTicks|. +template <typename TimeType> +class FeedbackSignalAccumulator { public: // |half_life| is the amount of time that must pass between two data points to // move the accumulated average value halfway in-between. Example: If @@ -31,13 +35,11 @@ // Update(1.0, t=1s) will result in an accumulated average value of 0.5. explicit FeedbackSignalAccumulator(base::TimeDelta half_life); - // TODO(xjz): Change time type used by Reset() and Update() methods to - // TimeDelta instead of TimeTicks. https://crbug.com/573280. - // Erase all memory of historical values, re-starting with the given // |starting_value|. - void Reset(double starting_value, base::TimeTicks timestamp); - base::TimeTicks reset_time() const { return reset_time_; } + void Reset(double starting_value, TimeType timestamp); + + TimeType reset_time() const { return reset_time_; } // Apply the given |value|, which was observed at the given |timestamp|, to // the accumulated average. If the timestamp is in chronological order, the @@ -45,8 +47,9 @@ // effect and false is returned. If there are two or more updates at the same // |timestamp|, only the one with the greatest value will be accounted for // (see class comments for elaboration). - bool Update(double value, base::TimeTicks timestamp); - base::TimeTicks update_time() const { return update_time_; } + bool Update(double value, TimeType timestamp); + + TimeType update_time() const { return update_time_; } // Returns the current accumulated average value. double current() const { return average_; } @@ -57,12 +60,12 @@ // accumulated average. const base::TimeDelta half_life_; - base::TimeTicks reset_time_; // |timestamp| passed in last call to Reset(). - double average_; // Current accumulated average. - double update_value_; // Latest |value| accepted by Update(). - base::TimeTicks update_time_; // Latest |timestamp| accepted by Update(). + TimeType reset_time_; // |timestamp| passed in last call to Reset(). + double average_; // Current accumulated average. + double update_value_; // Latest |value| accepted by Update(). + TimeType update_time_; // Latest |timestamp| accepted by Update(). double prior_average_; // Accumulated average before last call to Update(). - base::TimeTicks prior_update_time_; // |timestamp| in prior call to Update(). + TimeType prior_update_time_; // |timestamp| in prior call to Update(). }; } // namespace media
diff --git a/media/capture/content/feedback_signal_accumulator_unittest.cc b/media/capture/content/feedback_signal_accumulator_unittest.cc index 9d0f925..c8ee7f7 100644 --- a/media/capture/content/feedback_signal_accumulator_unittest.cc +++ b/media/capture/content/feedback_signal_accumulator_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 "media/capture/content/feedback_signal_accumulator.h" +#include "media/capture/content/feedback_signal_accumulator.cc" #include "testing/gtest/include/gtest/gtest.h" @@ -19,7 +19,7 @@ protected: const base::TimeDelta half_life_; - FeedbackSignalAccumulator acc_; + FeedbackSignalAccumulator<base::TimeTicks> acc_; base::TimeTicks t_; };
diff --git a/media/capture/content/video_capture_oracle.cc b/media/capture/content/video_capture_oracle.cc index 461200d..920c00cc4 100644 --- a/media/capture/content/video_capture_oracle.cc +++ b/media/capture/content/video_capture_oracle.cc
@@ -85,8 +85,9 @@ // Returns true if updates have been accumulated by |accumulator| for a // sufficient amount of time and the latest update was fairly recent, relative // to |now|. -bool HasSufficientRecentFeedback(const FeedbackSignalAccumulator& accumulator, - base::TimeTicks now) { +bool HasSufficientRecentFeedback( + const FeedbackSignalAccumulator<base::TimeTicks>& accumulator, + base::TimeTicks now) { const base::TimeDelta amount_of_history = accumulator.update_time() - accumulator.reset_time(); return (amount_of_history.InMicroseconds() >= kMinSizeChangePeriodMicros) &&
diff --git a/media/capture/content/video_capture_oracle.h b/media/capture/content/video_capture_oracle.h index 6a23973..9f2f173 100644 --- a/media/capture/content/video_capture_oracle.h +++ b/media/capture/content/video_capture_oracle.h
@@ -11,7 +11,7 @@ #include "media/base/media_export.h" #include "media/capture/content/animated_content_sampler.h" #include "media/capture/content/capture_resolution_chooser.h" -#include "media/capture/content/feedback_signal_accumulator.h" +#include "media/capture/content/feedback_signal_accumulator.cc" #include "media/capture/content/smooth_event_sampler.h" #include "ui/gfx/geometry/rect.h" @@ -182,13 +182,13 @@ base::TimeTicks frame_timestamps_[kMaxFrameTimestamps]; // Recent average buffer pool utilization for capture. - FeedbackSignalAccumulator buffer_pool_utilization_; + FeedbackSignalAccumulator<base::TimeTicks> buffer_pool_utilization_; // Estimated maximum frame area that currently can be handled by the consumer, // in number of pixels per frame. This is used to adjust the capture size up // or down to a data volume the consumer can handle. Note that some consumers // do not provide feedback, and the analysis logic should account for that. - FeedbackSignalAccumulator estimated_capable_area_; + FeedbackSignalAccumulator<base::TimeTicks> estimated_capable_area_; // The time of the first analysis which concluded the end-to-end system was // under-utilized. If null, the system is not currently under-utilized. This
diff --git a/media/cast/sender/vp8_encoder.cc b/media/cast/sender/vp8_encoder.cc index a9a4547..07798ff 100644 --- a/media/cast/sender/vp8_encoder.cc +++ b/media/cast/sender/vp8_encoder.cc
@@ -50,7 +50,8 @@ const int kHighestEncodingSpeed = 12; const int kLowestEncodingSpeed = 6; -bool HasSufficientFeedback(const FeedbackSignalAccumulator& accumulator) { +bool HasSufficientFeedback( + const FeedbackSignalAccumulator<base::TimeDelta>& accumulator) { const base::TimeDelta amount_of_history = accumulator.update_time() - accumulator.reset_time(); return amount_of_history.InMicroseconds() >= 250000; // 0.25 second. @@ -331,15 +332,8 @@ if (encoded_frame->dependency == EncodedFrame::KEY) { key_frame_requested_ = false; } - - // This is not a true system clock value, but a "hack" needed in order to use - // FeedbackSignalAccumulator. - const base::TimeTicks current_time = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(10) + - video_frame->timestamp(); - if (encoded_frame->dependency == EncodedFrame::KEY) { - encoding_speed_acc_.Reset(kHighestEncodingSpeed, current_time); + encoding_speed_acc_.Reset(kHighestEncodingSpeed, video_frame->timestamp()); } else { // Equivalent encoding speed considering both cpu_used setting and // quantizer. @@ -350,7 +344,8 @@ double adjusted_encoding_speed = actual_encoding_speed * encoded_frame->deadline_utilization / kTargetDeadlineUtilization; - encoding_speed_acc_.Update(adjusted_encoding_speed, current_time); + encoding_speed_acc_.Update(adjusted_encoding_speed, + video_frame->timestamp()); } if (HasSufficientFeedback(encoding_speed_acc_)) {
diff --git a/media/cast/sender/vp8_encoder.h b/media/cast/sender/vp8_encoder.h index ef80a69..8a2a2b2b 100644 --- a/media/cast/sender/vp8_encoder.h +++ b/media/cast/sender/vp8_encoder.h
@@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/threading/thread_checker.h" -#include "media/capture/content/feedback_signal_accumulator.h" +#include "media/capture/content/feedback_signal_accumulator.cc" #include "media/cast/cast_config.h" #include "media/cast/sender/software_video_encoder.h" #include "third_party/libvpx_new/source/libvpx/vpx/vpx_encoder.h" @@ -80,7 +80,7 @@ bool has_seen_zero_length_encoded_frame_; // The accumulator (time averaging) of the encoding speed. - FeedbackSignalAccumulator encoding_speed_acc_; + FeedbackSignalAccumulator<base::TimeDelta> encoding_speed_acc_; // The higher the speed, the less CPU usage, and the lower quality. int encoding_speed_;
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn index 34e9bf2..abd063ee 100644 --- a/mojo/BUILD.gn +++ b/mojo/BUILD.gn
@@ -95,10 +95,10 @@ ] deps += [ - "//mojo/package_manager:unittests", "//mojo/services/network:apptests", "//mojo/shell:apptests", "//mojo/shell:mojo_shell_unittests", + "//mojo/shell/package_manager:unittests", ] if (is_android) {
diff --git a/mojo/fetcher/update_fetcher.cc b/mojo/fetcher/update_fetcher.cc deleted file mode 100644 index 39f3091..0000000 --- a/mojo/fetcher/update_fetcher.cc +++ /dev/null
@@ -1,105 +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 "mojo/fetcher/update_fetcher.h" - -#include <stddef.h> -#include <stdint.h> - -#include <utility> - -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/format_macros.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/stringprintf.h" -#include "mojo/common/common_type_converters.h" -#include "mojo/common/data_pipe_utils.h" -#include "mojo/common/url_type_converters.h" - -namespace mojo { -namespace fetcher { - -namespace { -void IgnoreResult(bool result) { -} - -} // namespace -UpdateFetcher::UpdateFetcher(const GURL& url, - updater::Updater* updater, - const FetchCallback& loader_callback) - : Fetcher(loader_callback), url_(url), weak_ptr_factory_(this) { - DVLOG(1) << "updating: " << url_; - updater->GetPathForApp( - url.spec(), - base::Bind(&UpdateFetcher::OnGetAppPath, weak_ptr_factory_.GetWeakPtr())); -} - -UpdateFetcher::~UpdateFetcher() { -} - -const GURL& UpdateFetcher::GetURL() const { - return url_; -} - -GURL UpdateFetcher::GetRedirectURL() const { - return GURL::EmptyGURL(); -} - -GURL UpdateFetcher::GetRedirectReferer() const { - return GURL::EmptyGURL(); -} -URLResponsePtr UpdateFetcher::AsURLResponse(base::TaskRunner* task_runner, - uint32_t skip) { - URLResponsePtr response(URLResponse::New()); - response->url = String::From(url_); - DataPipe data_pipe; - response->body = std::move(data_pipe.consumer_handle); - int64_t file_size; - if (base::GetFileSize(path_, &file_size)) { - response->headers = Array<HttpHeaderPtr>(1); - HttpHeaderPtr header = HttpHeader::New(); - header->name = "Content-Length"; - header->value = base::StringPrintf("%" PRId64, file_size); - response->headers[0] = std::move(header); - } - common::CopyFromFile(path_, std::move(data_pipe.producer_handle), skip, - task_runner, base::Bind(&IgnoreResult)); - return response; -} - -void UpdateFetcher::AsPath( - base::TaskRunner* task_runner, - base::Callback<void(const base::FilePath&, bool)> callback) { - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(callback, path_, base::PathExists(path_))); -} - -std::string UpdateFetcher::MimeType() { - return ""; -} - -bool UpdateFetcher::HasMojoMagic() { - std::string magic; - ReadFileToString(path_, &magic, strlen(kMojoMagic)); - return magic == kMojoMagic; -} - -bool UpdateFetcher::PeekFirstLine(std::string* line) { - std::string start_of_file; - ReadFileToString(path_, &start_of_file, kMaxShebangLength); - size_t return_position = start_of_file.find('\n'); - if (return_position == std::string::npos) - return false; - *line = start_of_file.substr(0, return_position + 1); - return true; -} - -void UpdateFetcher::OnGetAppPath(const mojo::String& path) { - path_ = base::FilePath::FromUTF8Unsafe(path); - loader_callback_.Run(make_scoped_ptr(this)); -} - -} // namespace fetcher -} // namespace mojo
diff --git a/mojo/fetcher/update_fetcher.h b/mojo/fetcher/update_fetcher.h deleted file mode 100644 index b75c7ec..0000000 --- a/mojo/fetcher/update_fetcher.h +++ /dev/null
@@ -1,58 +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 MOJO_FETCHER_UPDATE_FETCHER_H_ -#define MOJO_FETCHER_UPDATE_FETCHER_H_ - -#include "mojo/shell/fetcher.h" - -#include <stdint.h> - -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "mojo/services/updater/updater.mojom.h" -#include "url/gurl.h" - -namespace mojo { - -class URLLoaderFactory; - -namespace fetcher { - -class UpdateFetcher : public shell::Fetcher { - public: - UpdateFetcher(const GURL& url, - updater::Updater* updater, - const FetchCallback& loader_callback); - - ~UpdateFetcher() override; - - private: - // Fetcher implementation: - const GURL& GetURL() const override; - GURL GetRedirectURL() const override; - GURL GetRedirectReferer() const override; - URLResponsePtr AsURLResponse(base::TaskRunner* task_runner, - uint32_t skip) override; - void AsPath( - base::TaskRunner* task_runner, - base::Callback<void(const base::FilePath&, bool)> callback) override; - std::string MimeType() override; - bool HasMojoMagic() override; - bool PeekFirstLine(std::string* line) override; - - void OnGetAppPath(const mojo::String& path); - - const GURL url_; - base::FilePath path_; - base::WeakPtrFactory<UpdateFetcher> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(UpdateFetcher); -}; - -} // namespace fetcher -} // namespace mojo - -#endif // MOJO_FETCHER_UPDATE_FETCHER_H_
diff --git a/mojo/mojo_shell.gyp b/mojo/mojo_shell.gyp index 65c80301..8315a6c 100644 --- a/mojo/mojo_shell.gyp +++ b/mojo/mojo_shell.gyp
@@ -53,24 +53,22 @@ 'target_name': 'mojo_fetcher_lib', 'type': 'static_library', 'sources': [ - 'fetcher/about_fetcher.cc', - 'fetcher/about_fetcher.h', - 'fetcher/data_fetcher.cc', - 'fetcher/data_fetcher.h', - 'fetcher/local_fetcher.cc', - 'fetcher/local_fetcher.h', - 'fetcher/network_fetcher.cc', - 'fetcher/network_fetcher.h', - 'fetcher/switches.cc', - 'fetcher/switches.h', - 'fetcher/update_fetcher.cc', - 'fetcher/update_fetcher.h', - 'fetcher/url_resolver.cc', - 'fetcher/url_resolver.h', - 'package_manager/content_handler_connection.cc', - 'package_manager/content_handler_connection.h', - 'package_manager/package_manager_impl.cc', - 'package_manager/package_manager_impl.h', + 'shell/fetcher/about_fetcher.cc', + 'shell/fetcher/about_fetcher.h', + 'shell/fetcher/data_fetcher.cc', + 'shell/fetcher/data_fetcher.h', + 'shell/fetcher/local_fetcher.cc', + 'shell/fetcher/local_fetcher.h', + 'shell/fetcher/network_fetcher.cc', + 'shell/fetcher/network_fetcher.h', + 'shell/fetcher/switches.cc', + 'shell/fetcher/switches.h', + 'shell/fetcher/url_resolver.cc', + 'shell/fetcher/url_resolver.h', + 'shell/package_manager/content_handler_connection.cc', + 'shell/package_manager/content_handler_connection.h', + 'shell/package_manager/package_manager_impl.cc', + 'shell/package_manager/package_manager_impl.h', ], 'dependencies': [ '<(DEPTH)/base/base.gyp:base',
diff --git a/mojo/public/js/core_unittests.js b/mojo/public/js/core_unittests.js index 61770f29..12364dc 100644 --- a/mojo/public/js/core_unittests.js +++ b/mojo/public/js/core_unittests.js
@@ -9,10 +9,10 @@ ], function(expect, core, gc) { var HANDLE_SIGNAL_READWRITABLE = core.HANDLE_SIGNAL_WRITABLE | - core.HANDLE_SIGNAL_READABLE; + core.HANDLE_SIGNAL_READABLE; var HANDLE_SIGNAL_ALL = core.HANDLE_SIGNAL_WRITABLE | - core.HANDLE_SIGNAL_READABLE | - core.HANDLE_SIGNAL_PEER_CLOSED; + core.HANDLE_SIGNAL_READABLE | + core.HANDLE_SIGNAL_PEER_CLOSED; runWithMessagePipe(testNop); runWithMessagePipe(testReadAndWriteMessage); @@ -118,21 +118,19 @@ expect(result).toBe(core.RESULT_OK); - wait = core.waitMany( - [pipe.handle0, pipe.handle1], - [core.HANDLE_SIGNAL_WRITABLE,core.HANDLE_SIGNAL_WRITABLE], - 0); + wait = core.wait(pipe.handle0, core.HANDLE_SIGNAL_WRITABLE, 0); expect(wait.result).toBe(core.RESULT_OK); - expect(wait.index).toBe(0); - expect(wait.signalsState[0].satisfiedSignals).toBe( - core.HANDLE_SIGNAL_WRITABLE); - expect(wait.signalsState[0].satisfiableSignals).toBe(HANDLE_SIGNAL_ALL); - expect(wait.signalsState[1].satisfiedSignals).toBe( - HANDLE_SIGNAL_READWRITABLE); - expect(wait.signalsState[1].satisfiableSignals).toBe(HANDLE_SIGNAL_ALL); + expect(wait.signalsState.satisfiedSignals).toBe( + core.HANDLE_SIGNAL_WRITABLE); + expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL); - var read = core.readMessage( - pipe.handle1, core.READ_MESSAGE_FLAG_NONE); + wait = core.wait(pipe.handle1, core.HANDLE_SIGNAL_READABLE, + core.DEADLINE_INDEFINITE); + expect(wait.result).toBe(core.RESULT_OK); + expect(wait.signalsState.satisfiedSignals).toBe(HANDLE_SIGNAL_READWRITABLE); + expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL); + + var read = core.readMessage(pipe.handle1, core.READ_MESSAGE_FLAG_NONE); expect(read.result).toBe(core.RESULT_OK); expect(read.buffer.byteLength).toBe(42);
diff --git a/mojo/runner/BUILD.gn b/mojo/runner/BUILD.gn index 3a4f30e..4166e29 100644 --- a/mojo/runner/BUILD.gn +++ b/mojo/runner/BUILD.gn
@@ -130,13 +130,13 @@ "//components/tracing:startup_tracing", "//mojo/application/public/cpp", "//mojo/message_pump", - "//mojo/package_manager", "//mojo/runner/child:interfaces", "//mojo/runner/host:lib", "//mojo/services/network/public/interfaces", "//mojo/services/tracing/public/cpp", "//mojo/services/tracing/public/interfaces", "//mojo/shell", + "//mojo/shell/package_manager", "//mojo/util:filename_util", "//third_party/mojo/src/mojo/edk/system", "//ui/gl",
diff --git a/mojo/runner/context.cc b/mojo/runner/context.cc index fad89a6..3709b88 100644 --- a/mojo/runner/context.cc +++ b/mojo/runner/context.cc
@@ -31,7 +31,6 @@ #include "mojo/application/public/cpp/application_connection.h" #include "mojo/application/public/cpp/application_delegate.h" #include "mojo/application/public/cpp/application_impl.h" -#include "mojo/package_manager/package_manager_impl.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/runner/host/in_process_native_runner.h" #include "mojo/runner/host/out_of_process_native_runner.h" @@ -44,6 +43,7 @@ #include "mojo/services/tracing/public/interfaces/tracing.mojom.h" #include "mojo/shell/application_loader.h" #include "mojo/shell/connect_to_application_params.h" +#include "mojo/shell/package_manager/package_manager_impl.h" #include "mojo/shell/query_util.h" #include "mojo/shell/switches.h" #include "mojo/util/filename_util.h" @@ -68,7 +68,7 @@ DISALLOW_COPY_AND_ASSIGN(Setup); }; -void InitContentHandlers(package_manager::PackageManagerImpl* manager, +void InitContentHandlers(shell::PackageManagerImpl* manager, const base::CommandLine& command_line) { // Default content handlers. manager->RegisterContentHandler("application/javascript", @@ -217,7 +217,7 @@ task_runners_->io_runner(), embedder::ScopedPlatformHandle()); - package_manager_ = new package_manager::PackageManagerImpl( + package_manager_ = new shell::PackageManagerImpl( shell_file_root, task_runners_->blocking_pool()); InitContentHandlers(package_manager_, command_line);
diff --git a/mojo/runner/context.h b/mojo/runner/context.h index 35ced140..2db71887 100644 --- a/mojo/runner/context.h +++ b/mojo/runner/context.h
@@ -19,7 +19,7 @@ #include "url/gurl.h" namespace mojo { -namespace package_manager { +namespace shell { class PackageManagerImpl; } namespace runner { @@ -58,9 +58,7 @@ return application_manager_.get(); } - package_manager::PackageManagerImpl* package_manager() { - return package_manager_; - } + shell::PackageManagerImpl* package_manager() { return package_manager_; } private: class NativeViewportApplicationLoader; @@ -77,7 +75,7 @@ // that needs the IO thread to destruct cleanly. Tracer tracer_; // Owned by |application_manager_|. - package_manager::PackageManagerImpl* package_manager_; + shell::PackageManagerImpl* package_manager_; scoped_ptr<shell::ApplicationManager> application_manager_; base::Closure app_complete_callback_; base::Time main_entry_time_;
diff --git a/mojo/runner/register_local_aliases.cc b/mojo/runner/register_local_aliases.cc index 7411453..6323cb2 100644 --- a/mojo/runner/register_local_aliases.cc +++ b/mojo/runner/register_local_aliases.cc
@@ -7,7 +7,7 @@ namespace mojo { namespace runner { -void RegisterLocalAliases(mojo::package_manager::PackageManagerImpl* manager) {} +void RegisterLocalAliases(shell::PackageManagerImpl* manager) {} } // namespace runner } // namespace mojo
diff --git a/mojo/runner/register_local_aliases.h b/mojo/runner/register_local_aliases.h index 1969f60..4ca3688 100644 --- a/mojo/runner/register_local_aliases.h +++ b/mojo/runner/register_local_aliases.h
@@ -6,13 +6,13 @@ #define MOJO_RUNNER_REGISTER_LOCAL_ALIASES_H_ namespace mojo { -namespace package_manager { +namespace shell { class PackageManagerImpl; } namespace runner { -void RegisterLocalAliases(mojo::package_manager::PackageManagerImpl* manager); +void RegisterLocalAliases(shell::PackageManagerImpl* manager); } // namespace runner } // namespace mojo
diff --git a/mojo/shell/BUILD.gn b/mojo/shell/BUILD.gn index 09515c37..202d4dd 100644 --- a/mojo/shell/BUILD.gn +++ b/mojo/shell/BUILD.gn
@@ -80,13 +80,13 @@ test("mojo_shell_unittests") { sources = [ - "../fetcher/about_fetcher_unittest.cc", - "../fetcher/data_fetcher_unittest.cc", - "../fetcher/network_fetcher_unittest.cc", - "../fetcher/url_resolver_unittest.cc", "application_manager_unittest.cc", "capability_filter_unittest.cc", "data_pipe_peek_unittest.cc", + "fetcher/about_fetcher_unittest.cc", + "fetcher/data_fetcher_unittest.cc", + "fetcher/network_fetcher_unittest.cc", + "fetcher/url_resolver_unittest.cc", "query_util_unittest.cc", ] @@ -97,9 +97,9 @@ "//base", "//mojo/application/public/cpp", "//mojo/edk/system:test_utils", - "//mojo/fetcher", - "//mojo/package_manager", "//mojo/public/cpp/system", + "//mojo/shell/fetcher", + "//mojo/shell/package_manager", "//mojo/util:filename_util", "//testing/gtest", "//third_party/mojo/src/mojo/edk/test:run_all_unittests",
diff --git a/mojo/fetcher/BUILD.gn b/mojo/shell/fetcher/BUILD.gn similarity index 95% rename from mojo/fetcher/BUILD.gn rename to mojo/shell/fetcher/BUILD.gn index 358174c..e634cc84 100644 --- a/mojo/fetcher/BUILD.gn +++ b/mojo/shell/fetcher/BUILD.gn
@@ -16,8 +16,6 @@ "network_fetcher.h", "switches.cc", "switches.h", - "update_fetcher.cc", - "update_fetcher.h", "url_resolver.cc", "url_resolver.h", ]
diff --git a/mojo/fetcher/DEPS b/mojo/shell/fetcher/DEPS similarity index 100% rename from mojo/fetcher/DEPS rename to mojo/shell/fetcher/DEPS
diff --git a/mojo/fetcher/about_fetcher.cc b/mojo/shell/fetcher/about_fetcher.cc similarity index 93% rename from mojo/fetcher/about_fetcher.cc rename to mojo/shell/fetcher/about_fetcher.cc index 9e301db9..11181983 100644 --- a/mojo/fetcher/about_fetcher.cc +++ b/mojo/shell/fetcher/about_fetcher.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 "mojo/fetcher/about_fetcher.h" +#include "mojo/shell/fetcher/about_fetcher.h" #include <stdint.h> @@ -15,11 +15,11 @@ #include "base/message_loop/message_loop.h" namespace mojo { -namespace fetcher { +namespace shell { namespace { -void RunFetcherCallback(const shell::Fetcher::FetchCallback& callback, - scoped_ptr<shell::Fetcher> fetcher, +void RunFetcherCallback(const Fetcher::FetchCallback& callback, + scoped_ptr<Fetcher> fetcher, bool success) { callback.Run(success ? std::move(fetcher) : nullptr); } @@ -112,5 +112,5 @@ return false; } -} // namespace fetcher +} // namespace shell } // namespace mojo
diff --git a/mojo/fetcher/about_fetcher.h b/mojo/shell/fetcher/about_fetcher.h similarity index 90% rename from mojo/fetcher/about_fetcher.h rename to mojo/shell/fetcher/about_fetcher.h index bcf3c750..80ff7c9 100644 --- a/mojo/fetcher/about_fetcher.h +++ b/mojo/shell/fetcher/about_fetcher.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 MOJO_FETCHER_ABOUT_FETCHER_H_ -#define MOJO_FETCHER_ABOUT_FETCHER_H_ +#ifndef MOJO_SHELL_FETCHER_ABOUT_FETCHER_H_ +#define MOJO_SHELL_FETCHER_ABOUT_FETCHER_H_ #include "mojo/shell/fetcher.h" @@ -14,7 +14,7 @@ #include "url/gurl.h" namespace mojo { -namespace fetcher { +namespace shell { // Implements Fetcher for about: URLs. class AboutFetcher : public shell::Fetcher { @@ -54,7 +54,7 @@ DISALLOW_COPY_AND_ASSIGN(AboutFetcher); }; -} // namespace fetcher +} // namespace shell } // namespace mojo -#endif // MOJO_FETCHER_ABOUT_FETCHER_H_ +#endif // MOJO_SHELL_FETCHER_ABOUT_FETCHER_H_
diff --git a/mojo/fetcher/about_fetcher_unittest.cc b/mojo/shell/fetcher/about_fetcher_unittest.cc similarity index 90% rename from mojo/fetcher/about_fetcher_unittest.cc rename to mojo/shell/fetcher/about_fetcher_unittest.cc index e67e716..907462c 100644 --- a/mojo/fetcher/about_fetcher_unittest.cc +++ b/mojo/shell/fetcher/about_fetcher_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 "mojo/fetcher/about_fetcher.h" +#include "mojo/shell/fetcher/about_fetcher.h" #include <stddef.h> @@ -20,14 +20,14 @@ #include "mojo/application/public/cpp/interface_factory.h" #include "mojo/application/public/interfaces/content_handler.mojom.h" #include "mojo/common/weak_binding_set.h" -#include "mojo/package_manager/package_manager_impl.h" #include "mojo/shell/application_loader.h" #include "mojo/shell/application_manager.h" +#include "mojo/shell/package_manager/package_manager_impl.h" #include "mojo/util/filename_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { -namespace fetcher { +namespace shell { namespace { class TestContentHandler : public ApplicationDelegate, @@ -77,7 +77,7 @@ DISALLOW_COPY_AND_ASSIGN(TestContentHandler); }; -class TestLoader : public shell::ApplicationLoader { +class TestLoader : public ApplicationLoader { public: explicit TestLoader(ApplicationDelegate* delegate) : delegate_(delegate) {} ~TestLoader() override {} @@ -117,8 +117,8 @@ service_provider.set_connection_error_handler( [&run_loop]() { run_loop.Quit(); }); - scoped_ptr<shell::ConnectToApplicationParams> params( - new shell::ConnectToApplicationParams); + scoped_ptr<ConnectToApplicationParams> params( + new ConnectToApplicationParams); params->SetTargetURL(GURL(url)); params->set_services(std::move(service_provider_request)); application_manager_->ConnectToApplication(std::move(params)); @@ -130,12 +130,12 @@ void SetUp() override { base::FilePath shell_dir; PathService::Get(base::DIR_MODULE, &shell_dir); - scoped_ptr<package_manager::PackageManagerImpl> package_manager( - new package_manager::PackageManagerImpl(shell_dir, nullptr)); + scoped_ptr<PackageManagerImpl> package_manager( + new PackageManagerImpl(shell_dir, nullptr)); package_manager->RegisterContentHandler( "text/html", GURL("test:html_content_handler")); application_manager_.reset( - new shell::ApplicationManager(std::move(package_manager))); + new ApplicationManager(std::move(package_manager))); application_manager_->SetLoaderForURL( make_scoped_ptr(new TestLoader(&html_content_handler_)), GURL("test:html_content_handler")); @@ -147,7 +147,7 @@ base::ShadowingAtExitManager at_exit_; TestContentHandler html_content_handler_; base::MessageLoop loop_; - scoped_ptr<shell::ApplicationManager> application_manager_; + scoped_ptr<ApplicationManager> application_manager_; DISALLOW_COPY_AND_ASSIGN(AboutFetcherTest); }; @@ -177,5 +177,5 @@ } } // namespace -} // namespace fetcher +} // namespace shell } // namespace mojo
diff --git a/mojo/fetcher/data_fetcher.cc b/mojo/shell/fetcher/data_fetcher.cc similarity index 97% rename from mojo/fetcher/data_fetcher.cc rename to mojo/shell/fetcher/data_fetcher.cc index d7b96013..2c63a9b3 100644 --- a/mojo/fetcher/data_fetcher.cc +++ b/mojo/shell/fetcher/data_fetcher.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 "mojo/fetcher/data_fetcher.h" +#include "mojo/shell/fetcher/data_fetcher.h" #include <stdint.h> @@ -18,7 +18,7 @@ #include "net/base/data_url.h" namespace mojo { -namespace fetcher { +namespace shell { ScopedDataPipeConsumerHandle CreateConsumerHandleForString( const std::string& data) { @@ -115,5 +115,5 @@ return false; } -} // namespace fetcher +} // namespace shell } // namespace mojo
diff --git a/mojo/fetcher/data_fetcher.h b/mojo/shell/fetcher/data_fetcher.h similarity index 83% rename from mojo/fetcher/data_fetcher.h rename to mojo/shell/fetcher/data_fetcher.h index bbf1f427..31737ca1 100644 --- a/mojo/fetcher/data_fetcher.h +++ b/mojo/shell/fetcher/data_fetcher.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 MOJO_FETCHER_DATA_FETCHER_H_ -#define MOJO_FETCHER_DATA_FETCHER_H_ +#ifndef MOJO_SHELL_FETCHER_DATA_FETCHER_H_ +#define MOJO_SHELL_FETCHER_DATA_FETCHER_H_ #include "mojo/shell/fetcher.h" @@ -14,10 +14,10 @@ #include "url/gurl.h" namespace mojo { -namespace fetcher { +namespace shell { // Implements Fetcher for data: URLs. -class DataFetcher : public shell::Fetcher { +class DataFetcher : public Fetcher { public: static void Start(const GURL& url, const FetchCallback& loader_callback); @@ -27,7 +27,7 @@ void BuildAndDispatchResponse(); - // shell::Fetcher implementation. + // Fetcher implementation. const GURL& GetURL() const override; GURL GetRedirectURL() const override; GURL GetRedirectReferer() const override; @@ -46,7 +46,7 @@ DISALLOW_COPY_AND_ASSIGN(DataFetcher); }; -} // namespace fetcher +} // namespace shell } // namespace mojo -#endif // MOJO_FETCHER_DATA_FETCHER_H_ +#endif // MOJO_SHELL_FETCHER_DATA_FETCHER_H_
diff --git a/mojo/fetcher/data_fetcher_unittest.cc b/mojo/shell/fetcher/data_fetcher_unittest.cc similarity index 91% rename from mojo/fetcher/data_fetcher_unittest.cc rename to mojo/shell/fetcher/data_fetcher_unittest.cc index 191b4ea5..7974b02 100644 --- a/mojo/fetcher/data_fetcher_unittest.cc +++ b/mojo/shell/fetcher/data_fetcher_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 "mojo/fetcher/data_fetcher.h" +#include "mojo/shell/fetcher/data_fetcher.h" #include <stdint.h> @@ -19,7 +19,7 @@ #include "testing/gtest/include/gtest/gtest.h" namespace mojo { -namespace fetcher { +namespace shell { namespace { class FetchCallbackHelper { @@ -27,7 +27,7 @@ FetchCallbackHelper() : run_loop_(nullptr) {} ~FetchCallbackHelper() {} - shell::Fetcher::FetchCallback GetCallback() { + Fetcher::FetchCallback GetCallback() { return base::Bind(&FetchCallbackHelper::CallbackHandler, base::Unretained(this)); } @@ -38,10 +38,10 @@ run_loop.Run(); } - shell::Fetcher* fetcher() const { return fetcher_.get(); } + Fetcher* fetcher() const { return fetcher_.get(); } private: - void CallbackHandler(scoped_ptr<shell::Fetcher> fetcher) { + void CallbackHandler(scoped_ptr<Fetcher> fetcher) { fetcher_ = std::move(fetcher); if (run_loop_) run_loop_->Quit(); @@ -50,7 +50,7 @@ // If it is not null, it points to a stack-allocated base::RunLoop instance in // WaitForCallback(). base::RunLoop* run_loop_; - scoped_ptr<shell::Fetcher> fetcher_; + scoped_ptr<Fetcher> fetcher_; DISALLOW_COPY_AND_ASSIGN(FetchCallbackHelper); }; @@ -115,5 +115,5 @@ } } // namespace -} // namespace fetcher +} // namespace shell } // namespace mojo
diff --git a/mojo/fetcher/local_fetcher.cc b/mojo/shell/fetcher/local_fetcher.cc similarity index 98% rename from mojo/fetcher/local_fetcher.cc rename to mojo/shell/fetcher/local_fetcher.cc index 7d8851cc..7c1565f1 100644 --- a/mojo/fetcher/local_fetcher.cc +++ b/mojo/shell/fetcher/local_fetcher.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 "mojo/fetcher/local_fetcher.h" +#include "mojo/shell/fetcher/local_fetcher.h" #include <stddef.h> #include <stdint.h> @@ -26,7 +26,7 @@ #include "url/url_util.h" namespace mojo { -namespace fetcher { +namespace shell { namespace { void IgnoreResult(bool result) { @@ -149,5 +149,5 @@ return true; } -} // namespace fetcher +} // namespace shell } // namespace mojo
diff --git a/mojo/fetcher/local_fetcher.h b/mojo/shell/fetcher/local_fetcher.h similarity index 86% rename from mojo/fetcher/local_fetcher.h rename to mojo/shell/fetcher/local_fetcher.h index a87c8a9..4ad508f1 100644 --- a/mojo/fetcher/local_fetcher.h +++ b/mojo/shell/fetcher/local_fetcher.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 MOJO_FETCHER_LOCAL_FETCHER_H_ -#define MOJO_FETCHER_LOCAL_FETCHER_H_ +#ifndef MOJO_SHELL_FETCHER_LOCAL_FETCHER_H_ +#define MOJO_SHELL_FETCHER_LOCAL_FETCHER_H_ #include <stdint.h> @@ -18,10 +18,10 @@ class NetworkService; -namespace fetcher { +namespace shell { // Implements Fetcher for file:// URLs. -class LocalFetcher : public shell::Fetcher { +class LocalFetcher : public Fetcher { public: LocalFetcher(NetworkService* network_service, const GURL& url, @@ -59,7 +59,7 @@ DISALLOW_COPY_AND_ASSIGN(LocalFetcher); }; -} // namespace fetcher +} // namespace shell } // namespace mojo -#endif // MOJO_FETCHER_LOCAL_FETCHER_H_ +#endif // MOJO_SHELL_FETCHER_LOCAL_FETCHER_H_
diff --git a/mojo/fetcher/network_fetcher.cc b/mojo/shell/fetcher/network_fetcher.cc similarity index 95% rename from mojo/fetcher/network_fetcher.cc rename to mojo/shell/fetcher/network_fetcher.cc index 2828006..e9e20c68 100644 --- a/mojo/fetcher/network_fetcher.cc +++ b/mojo/shell/fetcher/network_fetcher.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 "mojo/fetcher/network_fetcher.h" +#include "mojo/shell/fetcher/network_fetcher.h" #include <stdint.h> @@ -31,7 +31,7 @@ #include "mojo/shell/switches.h" namespace mojo { -namespace fetcher { +namespace shell { NetworkFetcher::NetworkFetcher(bool disable_cache, mojo::URLRequestPtr request, @@ -212,14 +212,13 @@ bool NetworkFetcher::HasMojoMagic() { std::string magic; - return shell::BlockingPeekNBytes(response_->body.get(), &magic, - strlen(kMojoMagic), kPeekTimeout) && - magic == kMojoMagic; + return BlockingPeekNBytes(response_->body.get(), &magic, strlen(kMojoMagic), + kPeekTimeout) && magic == kMojoMagic; } bool NetworkFetcher::PeekFirstLine(std::string* line) { - return shell::BlockingPeekLine(response_->body.get(), line, kMaxShebangLength, - kPeekTimeout); + return BlockingPeekLine(response_->body.get(), line, kMaxShebangLength, + kPeekTimeout); } void NetworkFetcher::StartNetworkRequest(mojo::URLRequestPtr request, @@ -250,5 +249,5 @@ loader_callback_.Run(std::move(owner)); } -} // namespace fetcher +} // namespace shell } // namespace mojo
diff --git a/mojo/fetcher/network_fetcher.h b/mojo/shell/fetcher/network_fetcher.h similarity index 91% rename from mojo/fetcher/network_fetcher.h rename to mojo/shell/fetcher/network_fetcher.h index 04cd0f7..94755b3 100644 --- a/mojo/fetcher/network_fetcher.h +++ b/mojo/shell/fetcher/network_fetcher.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 MOJO_FETCHER_NETWORK_FETCHER_H_ -#define MOJO_FETCHER_NETWORK_FETCHER_H_ +#ifndef MOJO_SHELL_FETCHER_NETWORK_FETCHER_H_ +#define MOJO_SHELL_FETCHER_NETWORK_FETCHER_H_ #include "mojo/shell/fetcher.h" @@ -19,10 +19,10 @@ class URLLoaderFactory; -namespace fetcher { +namespace shell { // Implements Fetcher for http[s] files. -class NetworkFetcher : public shell::Fetcher { +class NetworkFetcher : public Fetcher { public: NetworkFetcher(bool disable_cache, mojo::URLRequestPtr request, @@ -82,7 +82,7 @@ DISALLOW_COPY_AND_ASSIGN(NetworkFetcher); }; -} // namespace fetcher +} // namespace shell } // namespace mojo -#endif // MOJO_FETCHER_NETWORK_FETCHER_H_ +#endif // MOJO_SHELL_FETCHER_NETWORK_FETCHER_H_
diff --git a/mojo/fetcher/network_fetcher_unittest.cc b/mojo/shell/fetcher/network_fetcher_unittest.cc similarity index 94% rename from mojo/fetcher/network_fetcher_unittest.cc rename to mojo/shell/fetcher/network_fetcher_unittest.cc index 9128b3a..ba58c47 100644 --- a/mojo/fetcher/network_fetcher_unittest.cc +++ b/mojo/shell/fetcher/network_fetcher_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 "mojo/fetcher/network_fetcher.h" +#include "mojo/shell/fetcher/network_fetcher.h" #include <stdint.h> @@ -22,7 +22,7 @@ #include "testing/gtest/include/gtest/gtest.h" namespace mojo { -namespace fetcher { +namespace shell { namespace { const char k200Request[] = "http://request_expect_200"; @@ -90,7 +90,7 @@ FetchCallbackHelper() : run_loop_(nullptr) {} ~FetchCallbackHelper() {} - shell::Fetcher::FetchCallback GetCallback() { + Fetcher::FetchCallback GetCallback() { return base::Bind(&FetchCallbackHelper::CallbackHandler, base::Unretained(this)); } @@ -101,10 +101,10 @@ run_loop.Run(); } - shell::Fetcher* fetcher() const { return fetcher_.get(); } + Fetcher* fetcher() const { return fetcher_.get(); } private: - void CallbackHandler(scoped_ptr<shell::Fetcher> fetcher) { + void CallbackHandler(scoped_ptr<Fetcher> fetcher) { fetcher_ = std::move(fetcher); if (run_loop_) run_loop_->Quit(); @@ -113,7 +113,7 @@ // If it is not null, it points to a stack-allocated base::RunLoop instance in // WaitForCallback(). base::RunLoop* run_loop_; - scoped_ptr<shell::Fetcher> fetcher_; + scoped_ptr<Fetcher> fetcher_; DISALLOW_COPY_AND_ASSIGN(FetchCallbackHelper); }; @@ -177,5 +177,5 @@ } } // namespace -} // namespace fetcher +} // namespace shell } // namespace mojo
diff --git a/mojo/fetcher/switches.cc b/mojo/shell/fetcher/switches.cc similarity index 89% rename from mojo/fetcher/switches.cc rename to mojo/shell/fetcher/switches.cc index 4f5e1474..cba24448 100644 --- a/mojo/fetcher/switches.cc +++ b/mojo/shell/fetcher/switches.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 "mojo/fetcher/switches.h" +#include "mojo/shell/fetcher/switches.h" namespace switches {
diff --git a/mojo/fetcher/switches.h b/mojo/shell/fetcher/switches.h similarity index 76% rename from mojo/fetcher/switches.h rename to mojo/shell/fetcher/switches.h index 207a9e74..1c57ef58 100644 --- a/mojo/fetcher/switches.h +++ b/mojo/shell/fetcher/switches.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 MOJO_FETCHER_SWITCHES_H_ -#define MOJO_FETCHER_SWITCHES_H_ +#ifndef MOJO_SHELL_FETCHER_SWITCHES_H_ +#define MOJO_SHELL_FETCHER_SWITCHES_H_ namespace switches { @@ -13,4 +13,4 @@ } // namespace switches -#endif // MOJO_FETCHER_SWITCHES_H_ +#endif // MOJO_SHELL_FETCHER_SWITCHES_H_
diff --git a/mojo/fetcher/url_resolver.cc b/mojo/shell/fetcher/url_resolver.cc similarity index 86% rename from mojo/fetcher/url_resolver.cc rename to mojo/shell/fetcher/url_resolver.cc index 4663f5e5..499d9fdb 100644 --- a/mojo/fetcher/url_resolver.cc +++ b/mojo/shell/fetcher/url_resolver.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 "mojo/fetcher/url_resolver.h" +#include "mojo/shell/fetcher/url_resolver.h" #include "base/base_paths.h" #include "base/logging.h" @@ -12,7 +12,7 @@ #include "url/url_util.h" namespace mojo { -namespace fetcher { +namespace shell { URLResolver::URLResolver(const GURL& mojo_base_url) : mojo_base_url_(util::AddTrailingSlashIfNeeded(mojo_base_url)) { @@ -29,7 +29,7 @@ if (mojo_url.SchemeIs("mojo")) { // It's still a mojo: URL, use the default mapping scheme. std::string query; - GURL base_url = shell::GetBaseURLAndQuery(mojo_url, &query); + GURL base_url = GetBaseURLAndQuery(mojo_url, &query); const std::string host = base_url.host(); return mojo_base_url_.Resolve(host + "/" + host + ".mojo" + query); } else if (mojo_url.SchemeIs("exe")) { @@ -39,7 +39,7 @@ std::string extension; #endif std::string query; - GURL base_url = shell::GetBaseURLAndQuery(mojo_url, &query); + GURL base_url = GetBaseURLAndQuery(mojo_url, &query); return mojo_base_url_.Resolve(base_url.host() + extension); } else { // The mapping has produced some sort of non-mojo: URL - file:, http:, etc. @@ -47,5 +47,5 @@ } } -} // namespace fetcher +} // namespace shell } // namespace mojo
diff --git a/mojo/fetcher/url_resolver.h b/mojo/shell/fetcher/url_resolver.h similarity index 81% rename from mojo/fetcher/url_resolver.h rename to mojo/shell/fetcher/url_resolver.h index 013ac69..2f1e0a0 100644 --- a/mojo/fetcher/url_resolver.h +++ b/mojo/shell/fetcher/url_resolver.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 MOJO_FETCHER_URL_RESOLVER_H_ -#define MOJO_FETCHER_URL_RESOLVER_H_ +#ifndef MOJO_SHELL_FETCHER_URL_RESOLVER_H_ +#define MOJO_SHELL_FETCHER_URL_RESOLVER_H_ #include <map> #include <set> @@ -14,7 +14,7 @@ #include "url/gurl.h" namespace mojo { -namespace fetcher { +namespace shell { // Supports resolving "mojo:" URLs to a file location, with ".mojo" appended. class URLResolver { @@ -32,7 +32,7 @@ DISALLOW_COPY_AND_ASSIGN(URLResolver); }; -} // namespace fetcher +} // namespace shell } // namespace mojo -#endif // MOJO_FETCHER_URL_RESOLVER_H_ +#endif // MOJO_SHELL_FETCHER_URL_RESOLVER_H_
diff --git a/mojo/fetcher/url_resolver_unittest.cc b/mojo/shell/fetcher/url_resolver_unittest.cc similarity index 91% rename from mojo/fetcher/url_resolver_unittest.cc rename to mojo/shell/fetcher/url_resolver_unittest.cc index d6cffde..6f0b3aa 100644 --- a/mojo/fetcher/url_resolver_unittest.cc +++ b/mojo/shell/fetcher/url_resolver_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 "mojo/fetcher/url_resolver.h" +#include "mojo/shell/fetcher/url_resolver.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" @@ -11,7 +11,7 @@ #include "testing/gtest/include/gtest/gtest.h" namespace mojo { -namespace fetcher { +namespace shell { namespace test { namespace { @@ -31,5 +31,5 @@ } // namespace } // namespace test -} // namespace fetcher +} // namespace shell } // namespace mojo
diff --git a/mojo/package_manager/BUILD.gn b/mojo/shell/package_manager/BUILD.gn similarity index 96% rename from mojo/package_manager/BUILD.gn rename to mojo/shell/package_manager/BUILD.gn index 21b878a..7a11e75 100644 --- a/mojo/package_manager/BUILD.gn +++ b/mojo/shell/package_manager/BUILD.gn
@@ -13,8 +13,8 @@ ] deps = [ - "//mojo/fetcher", "//mojo/shell", + "//mojo/shell/fetcher", "//mojo/util:filename_util", ] }
diff --git a/mojo/package_manager/DEPS b/mojo/shell/package_manager/DEPS similarity index 100% rename from mojo/package_manager/DEPS rename to mojo/shell/package_manager/DEPS
diff --git a/mojo/package_manager/capability_filter_content_handler_unittest.cc b/mojo/shell/package_manager/capability_filter_content_handler_unittest.cc similarity index 89% rename from mojo/package_manager/capability_filter_content_handler_unittest.cc rename to mojo/shell/package_manager/capability_filter_content_handler_unittest.cc index aaf26aca..57298ec 100644 --- a/mojo/package_manager/capability_filter_content_handler_unittest.cc +++ b/mojo/shell/package_manager/capability_filter_content_handler_unittest.cc
@@ -14,13 +14,13 @@ #include "mojo/application/public/cpp/interface_factory.h" #include "mojo/application/public/interfaces/content_handler.mojom.h" #include "mojo/common/weak_binding_set.h" -#include "mojo/package_manager/package_manager_impl.h" #include "mojo/shell/capability_filter_test.h" #include "mojo/shell/fetcher.h" +#include "mojo/shell/package_manager/package_manager_impl.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { -namespace package_manager { +namespace shell { namespace test { namespace { @@ -28,10 +28,10 @@ // A custom Fetcher used to trigger a content handler for kTestMimeType for a // specific test. -class TestFetcher : public shell::Fetcher { +class TestFetcher : public Fetcher { public: TestFetcher(const GURL& url, const FetchCallback& callback) - : shell::Fetcher(callback), + : Fetcher(callback), url_(url) { loader_callback_.Run(make_scoped_ptr(this)); } @@ -70,7 +70,7 @@ // Overridden from PackageManagerImpl: void FetchRequest( URLRequestPtr request, - const shell::Fetcher::FetchCallback& loader_callback) override { + const Fetcher::FetchCallback& loader_callback) override { new TestFetcher(GURL(request->url), loader_callback); } @@ -105,7 +105,7 @@ InterfaceRequest<Application> application, URLResponsePtr response, const Callback<void()>& destruct_callback) override { - scoped_ptr<ApplicationDelegate> delegate(new shell::test::TestApplication); + scoped_ptr<ApplicationDelegate> delegate(new test::TestApplication); embedded_apps_.push_back( new ApplicationImpl(delegate.get(), std::move(application))); embedded_app_delegates_.push_back(std::move(delegate)); @@ -122,8 +122,7 @@ } // namespace -class CapabilityFilterContentHandlerTest - : public shell::test::CapabilityFilterTest { +class CapabilityFilterContentHandlerTest : public test::CapabilityFilterTest { public: CapabilityFilterContentHandlerTest() : package_manager_(nullptr) { @@ -135,11 +134,11 @@ private: // Overridden from CapabilityFilterTest: - shell::PackageManager* CreatePackageManager() override { + PackageManager* CreatePackageManager() override { return package_manager_; } void SetUp() override { - shell::test::CapabilityFilterTest::SetUp(); + test::CapabilityFilterTest::SetUp(); GURL content_handler_url("test:content_handler"); package_manager_->RegisterContentHandler(kTestMimeType, @@ -162,5 +161,5 @@ } } // namespace test -} // namespace package_manager +} // namespace shell } // namespace mojo
diff --git a/mojo/package_manager/content_handler_connection.cc b/mojo/shell/package_manager/content_handler_connection.cc similarity index 85% rename from mojo/package_manager/content_handler_connection.cc rename to mojo/shell/package_manager/content_handler_connection.cc index cd2e23cb..433245a6 100644 --- a/mojo/package_manager/content_handler_connection.cc +++ b/mojo/shell/package_manager/content_handler_connection.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 "mojo/package_manager/content_handler_connection.h" +#include "mojo/shell/package_manager/content_handler_connection.h" #include <stdint.h> @@ -15,12 +15,12 @@ #include "mojo/shell/identity.h" namespace mojo { -namespace package_manager { +namespace shell { ContentHandlerConnection::ContentHandlerConnection( - shell::ApplicationManager* manager, - const shell::Identity& source, - const shell::Identity& content_handler, + ApplicationManager* manager, + const Identity& source, + const Identity& content_handler, uint32_t id, const ClosedCallback& connection_closed_callback) : connection_closed_callback_(connection_closed_callback), @@ -30,8 +30,7 @@ ref_count_(0) { ServiceProviderPtr services; - scoped_ptr<shell::ConnectToApplicationParams> params( - new shell::ConnectToApplicationParams); + scoped_ptr<ConnectToApplicationParams> params(new ConnectToApplicationParams); params->set_source(source); params->SetTarget(identity_); params->set_services(GetProxy(&services)); @@ -74,5 +73,5 @@ CloseConnection(); } -} // namespace package_manager +} // namespace shell } // namespace mojo
diff --git a/mojo/package_manager/content_handler_connection.h b/mojo/shell/package_manager/content_handler_connection.h similarity index 76% rename from mojo/package_manager/content_handler_connection.h rename to mojo/shell/package_manager/content_handler_connection.h index 9ca029e..92b5929 100644 --- a/mojo/package_manager/content_handler_connection.h +++ b/mojo/shell/package_manager/content_handler_connection.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 MOJO_PACKAGE_MANAGER_CONTENT_HANDLER_CONNECTION_H_ -#define MOJO_PACKAGE_MANAGER_CONTENT_HANDLER_CONNECTION_H_ +#ifndef MOJO_SHELL_PACKAGE_MANAGER_CONTENT_HANDLER_CONNECTION_H_ +#define MOJO_SHELL_PACKAGE_MANAGER_CONTENT_HANDLER_CONNECTION_H_ #include <stdint.h> @@ -18,8 +18,6 @@ namespace mojo { namespace shell { class ApplicationManager; -} -namespace package_manager { // A ContentHandlerConnection is responsible for creating and maintaining a // connection to an app which provides the ContentHandler service. @@ -31,9 +29,9 @@ public: using ClosedCallback = base::Callback<void(ContentHandlerConnection*)>; // |id| is a unique identifier for this content handler. - ContentHandlerConnection(shell::ApplicationManager* manager, - const shell::Identity& source, - const shell::Identity& content_handler, + ContentHandlerConnection(ApplicationManager* manager, + const Identity& source, + const Identity& content_handler, uint32_t id, const ClosedCallback& connection_closed_callback); @@ -43,7 +41,7 @@ // Closes the connection and destroys |this| object. void CloseConnection(); - const shell::Identity& identity() const { return identity_; } + const Identity& identity() const { return identity_; } uint32_t id() const { return id_; } private: @@ -52,7 +50,7 @@ void ApplicationDestructed(); ClosedCallback connection_closed_callback_; - shell::Identity identity_; + Identity identity_; ContentHandlerPtr content_handler_; bool connection_closed_; @@ -63,7 +61,7 @@ DISALLOW_COPY_AND_ASSIGN(ContentHandlerConnection); }; -} // namespace package_manager +} // namespace shell } // namespace mojo -#endif // MOJO_PACKAGE_MANAGER_CONTENT_HANDLER_CONNECTION_H_ +#endif // MOJO_SHELL_PACKAGE_MANAGER_CONTENT_HANDLER_CONNECTION_H_
diff --git a/mojo/package_manager/content_handler_unittest.cc b/mojo/shell/package_manager/content_handler_unittest.cc similarity index 82% rename from mojo/package_manager/content_handler_unittest.cc rename to mojo/shell/package_manager/content_handler_unittest.cc index 7cef4bb..fce2d31 100644 --- a/mojo/package_manager/content_handler_unittest.cc +++ b/mojo/shell/package_manager/content_handler_unittest.cc
@@ -19,23 +19,23 @@ #include "mojo/application/public/cpp/interface_factory.h" #include "mojo/application/public/interfaces/content_handler.mojom.h" #include "mojo/application/public/interfaces/service_provider.mojom.h" -#include "mojo/package_manager/package_manager_impl.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/shell/application_loader.h" #include "mojo/shell/application_manager.h" #include "mojo/shell/connect_util.h" #include "mojo/shell/fetcher.h" +#include "mojo/shell/package_manager/package_manager_impl.h" #include "mojo/shell/test_package_manager.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { -namespace package_manager { +namespace shell { namespace test { namespace { const char kTestMimeType[] = "test/mime-type"; -class TestFetcher : public shell::Fetcher { +class TestFetcher : public Fetcher { public: TestFetcher(const FetchCallback& fetch_callback, const GURL& url, @@ -94,7 +94,7 @@ DISALLOW_COPY_AND_ASSIGN(TestContentHandler); }; -class TestApplicationLoader : public shell::ApplicationLoader, +class TestApplicationLoader : public ApplicationLoader, public ApplicationDelegate, public InterfaceFactory<ContentHandler> { public: @@ -131,12 +131,12 @@ DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader); }; -class TestPackageManager : public PackageManagerImpl { +class TestPackageManagerImpl : public PackageManagerImpl { public: - explicit TestPackageManager(const base::FilePath& package_path) + explicit TestPackageManagerImpl(const base::FilePath& package_path) : PackageManagerImpl(package_path, nullptr), mime_type_(kTestMimeType) {} - ~TestPackageManager() override {} + ~TestPackageManagerImpl() override {} void set_mime_type(const std::string& mime_type) { mime_type_ = mime_type; @@ -145,14 +145,14 @@ // PackageManagerImpl: void FetchRequest( URLRequestPtr request, - const shell::Fetcher::FetchCallback& loader_callback) override { + const Fetcher::FetchCallback& loader_callback) override { new TestFetcher(loader_callback, GURL(request->url), mime_type_); } private: std::string mime_type_; - DISALLOW_COPY_AND_ASSIGN(TestPackageManager); + DISALLOW_COPY_AND_ASSIGN(TestPackageManagerImpl); }; } // namespace @@ -167,10 +167,10 @@ void SetUp() override { base::FilePath shell_dir; PathService::Get(base::DIR_MODULE, &shell_dir); - test_package_manager_ = new TestPackageManager(shell_dir); + test_package_manager_ = new TestPackageManagerImpl(shell_dir); test_package_manager_->RegisterContentHandler(kTestMimeType, content_handler_url_); - application_manager_.reset(new shell::ApplicationManager( + application_manager_.reset(new ApplicationManager( make_scoped_ptr(test_package_manager_))); } @@ -184,9 +184,9 @@ const GURL requestor_url_; base::MessageLoop loop_; - scoped_ptr<shell::ApplicationManager> application_manager_; + scoped_ptr<ApplicationManager> application_manager_; // Owned by ApplicationManager. - TestPackageManager* test_package_manager_; + TestPackageManagerImpl* test_package_manager_; DISALLOW_COPY_AND_ASSIGN(ContentHandlerTest); }; @@ -194,13 +194,12 @@ TEST_F(ContentHandlerTest, ContentHandlerConnectionGetsRequestorURL) { TestApplicationLoader* loader = new TestApplicationLoader; application_manager_->SetLoaderForURL( - scoped_ptr<shell::ApplicationLoader>(loader), + scoped_ptr<ApplicationLoader>(loader), content_handler_url_); bool called = false; - scoped_ptr<shell::ConnectToApplicationParams> params( - new shell::ConnectToApplicationParams); - params->set_source(shell::Identity(requestor_url_)); + scoped_ptr<ConnectToApplicationParams> params(new ConnectToApplicationParams); + params->set_source(Identity(requestor_url_)); params->SetTargetURL(GURL("test:test")); params->set_on_application_end( base::Bind(&QuitClosure, base::Unretained(&called))); @@ -216,15 +215,15 @@ MultipleConnectionsToContentHandlerGetSameContentHandlerId) { TestApplicationLoader* content_handler_loader = new TestApplicationLoader; application_manager_->SetLoaderForURL( - scoped_ptr<shell::ApplicationLoader>(content_handler_loader), + scoped_ptr<ApplicationLoader>(content_handler_loader), content_handler_url_); uint32_t content_handler_id; { base::RunLoop run_loop; - scoped_ptr<shell::ConnectToApplicationParams> params( - new shell::ConnectToApplicationParams); - params->set_source(shell::Identity(requestor_url_)); + scoped_ptr<ConnectToApplicationParams> params( + new ConnectToApplicationParams); + params->set_source(Identity(requestor_url_)); params->SetTargetURL(GURL("test:test")); params->set_connect_callback([&content_handler_id, &run_loop](uint32_t t) { content_handler_id = t; @@ -238,9 +237,9 @@ uint32_t content_handler_id2; { base::RunLoop run_loop; - scoped_ptr<shell::ConnectToApplicationParams> params( - new shell::ConnectToApplicationParams); - params->set_source(shell::Identity(requestor_url_)); + scoped_ptr<ConnectToApplicationParams> params( + new ConnectToApplicationParams); + params->set_source(Identity(requestor_url_)); params->SetTargetURL(GURL("test:test")); params->set_connect_callback([&content_handler_id2, &run_loop](uint32_t t) { content_handler_id2 = t; @@ -256,15 +255,15 @@ TEST_F(ContentHandlerTest, DifferedContentHandlersGetDifferentIDs) { TestApplicationLoader* content_handler_loader = new TestApplicationLoader; application_manager_->SetLoaderForURL( - scoped_ptr<shell::ApplicationLoader>(content_handler_loader), + scoped_ptr<ApplicationLoader>(content_handler_loader), content_handler_url_); uint32_t content_handler_id; { base::RunLoop run_loop; - scoped_ptr<shell::ConnectToApplicationParams> params( - new shell::ConnectToApplicationParams); - params->set_source(shell::Identity(requestor_url_)); + scoped_ptr<ConnectToApplicationParams> params( + new ConnectToApplicationParams); + params->set_source(Identity(requestor_url_)); params->SetTargetURL(GURL("test:test")); params->set_connect_callback([&content_handler_id, &run_loop](uint32_t t) { content_handler_id = t; @@ -283,15 +282,15 @@ TestApplicationLoader* content_handler_loader2 = new TestApplicationLoader; application_manager_->SetLoaderForURL( - scoped_ptr<shell::ApplicationLoader>(content_handler_loader2), + scoped_ptr<ApplicationLoader>(content_handler_loader2), content_handler_url2); uint32_t content_handler_id2; { base::RunLoop run_loop; - scoped_ptr<shell::ConnectToApplicationParams> params( - new shell::ConnectToApplicationParams); - params->set_source(shell::Identity(requestor_url_)); + scoped_ptr<ConnectToApplicationParams> params( + new ConnectToApplicationParams); + params->set_source(Identity(requestor_url_)); params->SetTargetURL(GURL("test2:test2")); params->set_connect_callback([&content_handler_id2, &run_loop](uint32_t t) { content_handler_id2 = t; @@ -307,12 +306,12 @@ TEST_F(ContentHandlerTest, ConnectWithNoContentHandlerGetsInvalidContentHandlerId) { application_manager_->SetLoaderForURL( - scoped_ptr<shell::ApplicationLoader>(new TestApplicationLoader), + scoped_ptr<ApplicationLoader>(new TestApplicationLoader), GURL("test:test")); uint32_t content_handler_id = 1u; - scoped_ptr<shell::ConnectToApplicationParams> params( - new shell::ConnectToApplicationParams); + scoped_ptr<ConnectToApplicationParams> params( + new ConnectToApplicationParams); params->SetTargetURL(GURL("test:test")); params->set_connect_callback( [&content_handler_id](uint32_t t) { content_handler_id = t; });
diff --git a/mojo/package_manager/package_manager_impl.cc b/mojo/shell/package_manager/package_manager_impl.cc similarity index 72% rename from mojo/package_manager/package_manager_impl.cc rename to mojo/shell/package_manager/package_manager_impl.cc index 205a68f9..9b95c3e 100644 --- a/mojo/package_manager/package_manager_impl.cc +++ b/mojo/shell/package_manager/package_manager_impl.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 "mojo/package_manager/package_manager_impl.h" +#include "mojo/shell/package_manager/package_manager_impl.h" #include <stdint.h> @@ -10,22 +10,21 @@ #include "base/bind.h" #include "mojo/application/public/interfaces/content_handler.mojom.h" -#include "mojo/fetcher/about_fetcher.h" -#include "mojo/fetcher/data_fetcher.h" -#include "mojo/fetcher/local_fetcher.h" -#include "mojo/fetcher/network_fetcher.h" -#include "mojo/fetcher/switches.h" -#include "mojo/fetcher/update_fetcher.h" -#include "mojo/package_manager/content_handler_connection.h" #include "mojo/shell/application_manager.h" #include "mojo/shell/connect_util.h" +#include "mojo/shell/fetcher/about_fetcher.h" +#include "mojo/shell/fetcher/data_fetcher.h" +#include "mojo/shell/fetcher/local_fetcher.h" +#include "mojo/shell/fetcher/network_fetcher.h" +#include "mojo/shell/fetcher/switches.h" +#include "mojo/shell/package_manager/content_handler_connection.h" #include "mojo/shell/query_util.h" #include "mojo/shell/switches.h" #include "mojo/util/filename_util.h" #include "url/gurl.h" namespace mojo { -namespace package_manager { +namespace shell { PackageManagerImpl::PackageManagerImpl( const base::FilePath& shell_file_root, @@ -39,7 +38,7 @@ if (!shell_file_root.empty()) { GURL mojo_root_file_url = util::FilePathToFileURL(shell_file_root).Resolve(std::string()); - url_resolver_.reset(new fetcher::URLResolver(mojo_root_file_url)); + url_resolver_.reset(new URLResolver(mojo_root_file_url)); } } @@ -66,22 +65,21 @@ std::make_pair(content_handler_package, qualifier); } -void PackageManagerImpl::SetApplicationManager( - shell::ApplicationManager* manager) { +void PackageManagerImpl::SetApplicationManager(ApplicationManager* manager) { application_manager_ = manager; } void PackageManagerImpl::FetchRequest( URLRequestPtr request, - const shell::Fetcher::FetchCallback& loader_callback) { + const Fetcher::FetchCallback& loader_callback) { GURL url(request->url); - if (url.SchemeIs(fetcher::AboutFetcher::kAboutScheme)) { - fetcher::AboutFetcher::Start(url, loader_callback); + if (url.SchemeIs(AboutFetcher::kAboutScheme)) { + AboutFetcher::Start(url, loader_callback); return; } if (url.SchemeIs(url::kDataScheme)) { - fetcher::DataFetcher::Start(url, loader_callback); + DataFetcher::Start(url, loader_callback); return; } @@ -90,53 +88,35 @@ // LocalFetcher uses the network service to infer MIME types from URLs. // Skip this for mojo URLs to avoid recursively loading the network service. if (!network_service_ && !url.SchemeIs("mojo") && !url.SchemeIs("exe")) { - shell::ConnectToService(application_manager_, - GURL("mojo:network_service"), &network_service_); + ConnectToService(application_manager_, GURL("mojo:network_service"), + &network_service_); } // Ownership of this object is transferred to |loader_callback|. // TODO(beng): this is eff'n weird. - new fetcher::LocalFetcher( - network_service_.get(), resolved_url, - shell::GetBaseURLAndQuery(resolved_url, nullptr), - shell_file_root_, loader_callback); + new LocalFetcher(network_service_.get(), resolved_url, + GetBaseURLAndQuery(resolved_url, nullptr), + shell_file_root_, loader_callback); return; } -#if 0 - // TODO(beng): figure out how this should be integrated now that mapped_url - // is toast. - // TODO(scottmg): to quote someone I know, if you liked this you shouldda put - // a test on it. - if (url.SchemeIs("mojo") && - base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kUseUpdater)) { - shell::ConnectToService(application_manager_, GURL("mojo:updater"), - &updater_); - // Ownership of this object is transferred to |loader_callback|. - // TODO(beng): this is eff'n weird. - new fetcher::UpdateFetcher(url, updater_.get(), loader_callback); - return; - } -#endif - if (!url_loader_factory_) { - shell::ConnectToService(application_manager_, GURL("mojo:network_service"), - &url_loader_factory_); + ConnectToService(application_manager_, GURL("mojo:network_service"), + &url_loader_factory_); } // Ownership of this object is transferred to |loader_callback|. // TODO(beng): this is eff'n weird. - new fetcher::NetworkFetcher(disable_cache_, std::move(request), - url_loader_factory_.get(), loader_callback); + new NetworkFetcher(disable_cache_, std::move(request), + url_loader_factory_.get(), loader_callback); } uint32_t PackageManagerImpl::HandleWithContentHandler( - shell::Fetcher* fetcher, - const shell::Identity& source, + Fetcher* fetcher, + const Identity& source, const GURL& target_url, - const shell::CapabilityFilter& target_filter, + const CapabilityFilter& target_filter, InterfaceRequest<Application>* application_request) { - shell::Identity content_handler_identity; + Identity content_handler_identity; URLResponsePtr response; if (ShouldHandleWithContentHandler(fetcher, target_url, @@ -157,10 +137,10 @@ } bool PackageManagerImpl::ShouldHandleWithContentHandler( - shell::Fetcher* fetcher, + Fetcher* fetcher, const GURL& target_url, - const shell::CapabilityFilter& target_filter, - shell::Identity* content_handler_identity, + const CapabilityFilter& target_filter, + Identity* content_handler_identity, URLResponsePtr* response) const { // TODO(beng): it seems like some delegate should/would want to have a say in // configuring the qualifier also. @@ -182,7 +162,7 @@ if (fetcher->PeekContentHandler(&shebang, &content_handler_url)) { *response = fetcher->AsURLResponse(task_runner_, static_cast<int>(shebang.size())); - *content_handler_identity = shell::Identity( + *content_handler_identity = Identity( content_handler_url, use_real_qualifier ? (*response)->site.To<std::string>() : std::string(), @@ -194,7 +174,7 @@ auto iter = mime_type_to_url_.find(fetcher->MimeType()); if (iter != mime_type_to_url_.end()) { *response = fetcher->AsURLResponse(task_runner_, 0); - *content_handler_identity = shell::Identity( + *content_handler_identity = Identity( iter->second, use_real_qualifier ? (*response)->site.To<std::string>() : std::string(), @@ -208,7 +188,7 @@ // We replace the qualifier with the one our package alias requested. *response = URLResponse::New(); (*response)->url = target_url.spec(); - *content_handler_identity = shell::Identity( + *content_handler_identity = Identity( alias_iter->second.first, use_real_qualifier ? alias_iter->second.second : std::string(), target_filter); @@ -219,8 +199,8 @@ } ContentHandlerConnection* PackageManagerImpl::GetContentHandler( - const shell::Identity& content_handler_identity, - const shell::Identity& source_identity) { + const Identity& content_handler_identity, + const Identity& source_identity) { auto it = identity_to_content_handler_.find(content_handler_identity); if (it != identity_to_content_handler_.end()) return it->second; @@ -243,5 +223,5 @@ identity_to_content_handler_.erase(it); } -} // namespace package_manager +} // namespace shell } // namespace mojo
diff --git a/mojo/package_manager/package_manager_impl.h b/mojo/shell/package_manager/package_manager_impl.h similarity index 72% rename from mojo/package_manager/package_manager_impl.h rename to mojo/shell/package_manager/package_manager_impl.h index 3001fe33..e550fdd 100644 --- a/mojo/package_manager/package_manager_impl.h +++ b/mojo/shell/package_manager/package_manager_impl.h
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MOJO_PACKAGE_MANAGER_PACKAGE_MANAGER_IMPL_H_ -#define MOJO_PACKAGE_MANAGER_PACKAGE_MANAGER_IMPL_H_ +#ifndef MOJO_SHELL_PACKAGE_MANAGER_PACKAGE_MANAGER_IMPL_H_ +#define MOJO_SHELL_PACKAGE_MANAGER_PACKAGE_MANAGER_IMPL_H_ #include <stdint.h> #include "base/files/file_path.h" #include "base/macros.h" -#include "mojo/fetcher/url_resolver.h" #include "mojo/services/network/public/interfaces/network_service.mojom.h" #include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h" +#include "mojo/shell/fetcher/url_resolver.h" #include "mojo/shell/package_manager.h" namespace base { @@ -21,16 +21,14 @@ namespace mojo { class ContentHandler; namespace shell { +class ContentHandlerConnection; class Fetcher; class Identity; -} -namespace package_manager { -class ContentHandlerConnection; -// This is the default implementation of shell::PackageManager. It loads -// http/s urls off the network as well as providing special handling for mojo: -// and about: urls. -class PackageManagerImpl : public shell::PackageManager { +// This is the default implementation of PackageManager. It loads http/s urls +// off the network as well as providing special handling for mojo: and about: +// urls. +class PackageManagerImpl : public PackageManager { public: // mojo: urls are only supported if |shell_file_root| is non-empty. // |task_runner| is used by Fetchers created by the PackageManager to complete @@ -60,39 +58,39 @@ using ApplicationPackagedAlias = std::map<GURL, std::pair<GURL, std::string>>; using MimeTypeToURLMap = std::map<std::string, GURL>; using IdentityToContentHandlerMap = - std::map<shell::Identity, ContentHandlerConnection*>; + std::map<Identity, ContentHandlerConnection*>; - // Overridden from shell::PackageManager: - void SetApplicationManager(shell::ApplicationManager* manager) override; + // Overridden from PackageManager: + void SetApplicationManager(ApplicationManager* manager) override; void FetchRequest( URLRequestPtr request, - const shell::Fetcher::FetchCallback& loader_callback) override; + const Fetcher::FetchCallback& loader_callback) override; uint32_t HandleWithContentHandler( - shell::Fetcher* fetcher, - const shell::Identity& source, + Fetcher* fetcher, + const Identity& source, const GURL& target_url, - const shell::CapabilityFilter& target_filter, + const CapabilityFilter& target_filter, InterfaceRequest<Application>* application_request) override; GURL ResolveURL(const GURL& url); bool ShouldHandleWithContentHandler( - shell::Fetcher* fetcher, + Fetcher* fetcher, const GURL& target_url, - const shell::CapabilityFilter& target_filter, - shell::Identity* content_handler_identity, + const CapabilityFilter& target_filter, + Identity* content_handler_identity, URLResponsePtr* response) const; // Returns a running ContentHandler for |content_handler_identity|, if there // is not one running one is started for |source_identity|. ContentHandlerConnection* GetContentHandler( - const shell::Identity& content_handler_identity, - const shell::Identity& source_identity); + const Identity& content_handler_identity, + const Identity& source_identity); void OnContentHandlerConnectionClosed( ContentHandlerConnection* content_handler); - shell::ApplicationManager* application_manager_; - scoped_ptr<fetcher::URLResolver> url_resolver_; + ApplicationManager* application_manager_; + scoped_ptr<URLResolver> url_resolver_; const bool disable_cache_; NetworkServicePtr network_service_; URLLoaderFactoryPtr url_loader_factory_; @@ -107,7 +105,7 @@ DISALLOW_COPY_AND_ASSIGN(PackageManagerImpl); }; -} // namespace package_manager +} // namespace shell } // namespace mojo -#endif // MOJO_PACKAGE_MANAGER_PACKAGE_MANAGER_IMPL_H_ +#endif // MOJO_SHELL_PACKAGE_MANAGER_PACKAGE_MANAGER_IMPL_H_
diff --git a/native_client_sdk/src/build_tools/build_projects.py b/native_client_sdk/src/build_tools/build_projects.py index f1a76c2..1646d6be 100755 --- a/native_client_sdk/src/build_tools/build_projects.py +++ b/native_client_sdk/src/build_tools/build_projects.py
@@ -148,7 +148,7 @@ if clobber: buildbot_common.RemoveDir(dirpath) buildbot_common.MakeDir(dirpath) - targets = [desc['NAME'] for desc in projects] + targets = [desc['NAME'] for desc in projects if 'TARGETS' in desc] deps = GetDeps(projects) # Generate master make for this branch of projects
diff --git a/native_client_sdk/src/build_tools/parse_dsc.py b/native_client_sdk/src/build_tools/parse_dsc.py index 3d862deeb..8d4e9f2 100755 --- a/native_client_sdk/src/build_tools/parse_dsc.py +++ b/native_client_sdk/src/build_tools/parse_dsc.py
@@ -42,6 +42,7 @@ 'linker-script'], True), 'SOURCES': (list, '', True), + 'EXTRA_SOURCES': (list, '', False), 'CFLAGS': (list, '', False), 'CFLAGS_GCC': (list, '', False), 'CXXFLAGS': (list, '', False),
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list index a7676e5..7a39a238 100644 --- a/native_client_sdk/src/build_tools/sdk_files.list +++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -61,11 +61,6 @@ include/glibc/bits/* include/glibc/rpc/netdb.h include/glibc/sys/mount.h -include/gmock/* -include/gmock/internal/* -include/gtest/* -include/gtest/internal/* -include/gtest/internal/src/* include/json/* include/KHR/* include/mac/sys/mount.h @@ -98,8 +93,6 @@ [win]include/win/* include/win/poll.h include/win/sys/poll.h -[linux,mac]lib/${PLATFORM}_host/Debug/libgmock.a -[linux,mac]lib/${PLATFORM}_host/Debug/libgtest.a [linux,mac]lib/${PLATFORM}_host/Debug/libjsoncpp.a [linux,mac]lib/${PLATFORM}_host/Debug/libnacl_io.a [linux,mac]lib/${PLATFORM}_host/Debug/libppapi.a @@ -113,8 +106,6 @@ [linux,mac]lib/${PLATFORM}_host/Debug/libppapi_simple_cpp_real.a [linux,mac]lib/${PLATFORM}_host/Debug/libppapi_simple_real.a [linux,mac]lib/${PLATFORM}_host/Debug/libsdk_util.a -[linux,mac]lib/${PLATFORM}_host/Release/libgmock.a -[linux,mac]lib/${PLATFORM}_host/Release/libgtest.a [linux,mac]lib/${PLATFORM}_host/Release/libjsoncpp.a [linux,mac]lib/${PLATFORM}_host/Release/libnacl_io.a [linux,mac]lib/${PLATFORM}_host/Release/libppapi.a @@ -128,8 +119,6 @@ [linux,mac]lib/${PLATFORM}_host/Release/libppapi_simple_cpp_real.a [linux,mac]lib/${PLATFORM}_host/Release/libppapi_simple_real.a [linux,mac]lib/${PLATFORM}_host/Release/libsdk_util.a -[win]lib/${PLATFORM}_x86_32_host/Debug/gmock.lib -[win]lib/${PLATFORM}_x86_32_host/Debug/gtest.lib [win]lib/${PLATFORM}_x86_32_host/Debug/jsoncpp.lib [win]lib/${PLATFORM}_x86_32_host/Debug/ppapi.lib [win]lib/${PLATFORM}_x86_32_host/Debug/ppapi_cpp.lib @@ -137,8 +126,6 @@ [win]lib/${PLATFORM}_x86_32_host/Debug/ppapi_gles2.lib [win]lib/${PLATFORM}_x86_32_host/Debug/pthread.lib [win]lib/${PLATFORM}_x86_32_host/Debug/sdk_util.lib -[win]lib/${PLATFORM}_x86_32_host/Release/gmock.lib -[win]lib/${PLATFORM}_x86_32_host/Release/gtest.lib [win]lib/${PLATFORM}_x86_32_host/Release/jsoncpp.lib [win]lib/${PLATFORM}_x86_32_host/Release/ppapi.lib [win]lib/${PLATFORM}_x86_32_host/Release/ppapi_cpp.lib @@ -147,8 +134,6 @@ [win]lib/${PLATFORM}_x86_32_host/Release/pthread.lib [win]lib/${PLATFORM}_x86_32_host/Release/sdk_util.lib lib/clang-newlib_arm/Debug/liberror_handling.a -lib/clang-newlib_arm/Debug/libgmock.a -lib/clang-newlib_arm/Debug/libgtest.a lib/clang-newlib_arm/Debug/libjsoncpp.a lib/clang-newlib_arm/Debug/libnacl_io.a lib/clang-newlib_arm/Debug/libppapi_cpp.a @@ -160,8 +145,6 @@ lib/clang-newlib_arm/Debug/libppapi_simple_real.a lib/clang-newlib_arm/Debug/libsdk_util.a lib/clang-newlib_arm/Release/liberror_handling.a -lib/clang-newlib_arm/Release/libgmock.a -lib/clang-newlib_arm/Release/libgtest.a lib/clang-newlib_arm/Release/libjsoncpp.a lib/clang-newlib_arm/Release/libnacl_io.a lib/clang-newlib_arm/Release/libppapi_cpp.a @@ -173,8 +156,6 @@ lib/clang-newlib_arm/Release/libppapi_simple_real.a lib/clang-newlib_arm/Release/libsdk_util.a lib/clang-newlib_x86_32/Debug/liberror_handling.a -lib/clang-newlib_x86_32/Debug/libgmock.a -lib/clang-newlib_x86_32/Debug/libgtest.a lib/clang-newlib_x86_32/Debug/libjsoncpp.a lib/clang-newlib_x86_32/Debug/libnacl_io.a lib/clang-newlib_x86_32/Debug/libppapi_cpp.a @@ -186,8 +167,6 @@ lib/clang-newlib_x86_32/Debug/libppapi_simple_real.a lib/clang-newlib_x86_32/Debug/libsdk_util.a lib/clang-newlib_x86_32/Release/liberror_handling.a -lib/clang-newlib_x86_32/Release/libgmock.a -lib/clang-newlib_x86_32/Release/libgtest.a lib/clang-newlib_x86_32/Release/libjsoncpp.a lib/clang-newlib_x86_32/Release/libnacl_io.a lib/clang-newlib_x86_32/Release/libppapi_cpp.a @@ -199,8 +178,6 @@ lib/clang-newlib_x86_32/Release/libppapi_simple_real.a lib/clang-newlib_x86_32/Release/libsdk_util.a lib/clang-newlib_x86_64/Debug/liberror_handling.a -lib/clang-newlib_x86_64/Debug/libgmock.a -lib/clang-newlib_x86_64/Debug/libgtest.a lib/clang-newlib_x86_64/Debug/libjsoncpp.a lib/clang-newlib_x86_64/Debug/libnacl_io.a lib/clang-newlib_x86_64/Debug/libppapi_cpp.a @@ -212,8 +189,6 @@ lib/clang-newlib_x86_64/Debug/libppapi_simple_real.a lib/clang-newlib_x86_64/Debug/libsdk_util.a lib/clang-newlib_x86_64/Release/liberror_handling.a -lib/clang-newlib_x86_64/Release/libgmock.a -lib/clang-newlib_x86_64/Release/libgtest.a lib/clang-newlib_x86_64/Release/libjsoncpp.a lib/clang-newlib_x86_64/Release/libnacl_io.a lib/clang-newlib_x86_64/Release/libppapi_cpp.a @@ -224,10 +199,6 @@ lib/clang-newlib_x86_64/Release/libppapi_simple_cpp_real.a lib/clang-newlib_x86_64/Release/libppapi_simple_real.a lib/clang-newlib_x86_64/Release/libsdk_util.a -lib/glibc_arm/Debug/libgmock.a -lib/glibc_arm/Debug/libgmock.so -lib/glibc_arm/Debug/libgtest.a -lib/glibc_arm/Debug/libgtest.so lib/glibc_arm/Debug/libjsoncpp.a lib/glibc_arm/Debug/libjsoncpp.so lib/glibc_arm/Debug/libnacl_io.a @@ -248,10 +219,6 @@ lib/glibc_arm/Debug/libppapi_simple_real.so lib/glibc_arm/Debug/libsdk_util.a lib/glibc_arm/Debug/libsdk_util.so -lib/glibc_arm/Release/libgmock.a -lib/glibc_arm/Release/libgmock.so -lib/glibc_arm/Release/libgtest.a -lib/glibc_arm/Release/libgtest.so lib/glibc_arm/Release/libjsoncpp.a lib/glibc_arm/Release/libjsoncpp.so lib/glibc_arm/Release/libnacl_io.a @@ -272,10 +239,6 @@ lib/glibc_arm/Release/libppapi_simple_real.so lib/glibc_arm/Release/libsdk_util.a lib/glibc_arm/Release/libsdk_util.so -lib/glibc_x86_32/Debug/libgmock.a -lib/glibc_x86_32/Debug/libgmock.so -lib/glibc_x86_32/Debug/libgtest.a -lib/glibc_x86_32/Debug/libgtest.so lib/glibc_x86_32/Debug/libjsoncpp.a lib/glibc_x86_32/Debug/libjsoncpp.so lib/glibc_x86_32/Debug/libnacl_io.a @@ -296,10 +259,6 @@ lib/glibc_x86_32/Debug/libppapi_simple_real.so lib/glibc_x86_32/Debug/libsdk_util.a lib/glibc_x86_32/Debug/libsdk_util.so -lib/glibc_x86_32/Release/libgmock.a -lib/glibc_x86_32/Release/libgmock.so -lib/glibc_x86_32/Release/libgtest.a -lib/glibc_x86_32/Release/libgtest.so lib/glibc_x86_32/Release/libjsoncpp.a lib/glibc_x86_32/Release/libjsoncpp.so lib/glibc_x86_32/Release/libnacl_io.a @@ -320,10 +279,6 @@ lib/glibc_x86_32/Release/libppapi_simple_real.so lib/glibc_x86_32/Release/libsdk_util.a lib/glibc_x86_32/Release/libsdk_util.so -lib/glibc_x86_64/Debug/libgmock.a -lib/glibc_x86_64/Debug/libgmock.so -lib/glibc_x86_64/Debug/libgtest.a -lib/glibc_x86_64/Debug/libgtest.so lib/glibc_x86_64/Debug/libjsoncpp.a lib/glibc_x86_64/Debug/libjsoncpp.so lib/glibc_x86_64/Debug/libnacl_io.a @@ -344,10 +299,6 @@ lib/glibc_x86_64/Debug/libppapi_simple_real.so lib/glibc_x86_64/Debug/libsdk_util.a lib/glibc_x86_64/Debug/libsdk_util.so -lib/glibc_x86_64/Release/libgmock.a -lib/glibc_x86_64/Release/libgmock.so -lib/glibc_x86_64/Release/libgtest.a -lib/glibc_x86_64/Release/libgtest.so lib/glibc_x86_64/Release/libjsoncpp.a lib/glibc_x86_64/Release/libjsoncpp.so lib/glibc_x86_64/Release/libnacl_io.a @@ -368,8 +319,6 @@ lib/glibc_x86_64/Release/libppapi_simple_real.so lib/glibc_x86_64/Release/libsdk_util.a lib/glibc_x86_64/Release/libsdk_util.so -lib/pnacl/Debug/libgmock.a -lib/pnacl/Debug/libgtest.a lib/pnacl/Debug/libjsoncpp.a lib/pnacl/Debug/libnacl_io.a lib/pnacl/Debug/libppapi_cpp.a @@ -380,8 +329,6 @@ lib/pnacl/Debug/libppapi_simple_cpp_real.a lib/pnacl/Debug/libppapi_simple_real.a lib/pnacl/Debug/libsdk_util.a -lib/pnacl/Release/libgmock.a -lib/pnacl/Release/libgtest.a lib/pnacl/Release/libjsoncpp.a lib/pnacl/Release/libnacl_io.a lib/pnacl/Release/libppapi_cpp.a
diff --git a/native_client_sdk/src/doc/sdk/release-notes.rst b/native_client_sdk/src/doc/sdk/release-notes.rst index a68fa7e..460d7237 100644 --- a/native_client_sdk/src/doc/sdk/release-notes.rst +++ b/native_client_sdk/src/doc/sdk/release-notes.rst
@@ -7,6 +7,12 @@ The dates in the following release notes denote when Chrome and the NaCl SDK reached canary status. The stable release is typically 6 weeks later. +Chrome/Pepper 49 +================ + +* gtest/gmock no longer shipped as prebuilt libraries. This is in-line with + normal gtest/gmock usage guidelines. Projects wishing to use gtest/gmock must + now add explict include paths and compile gtest-all.cc locally. Chrome/Pepper 45 (10 July 2015) ================================
diff --git a/native_client_sdk/src/examples/tutorial/testing/example.dsc b/native_client_sdk/src/examples/tutorial/testing/example.dsc index 284ec46a..07f1fbc 100644 --- a/native_client_sdk/src/examples/tutorial/testing/example.dsc +++ b/native_client_sdk/src/examples/tutorial/testing/example.dsc
@@ -6,7 +6,9 @@ 'NAME' : 'testing', 'TYPE' : 'main', 'SOURCES' : ['testing.cc'], - 'LIBS' : ['ppapi_simple_cpp', 'ppapi_cpp', 'ppapi', 'gtest', 'nacl_io', 'pthread'], + 'LIBS' : ['ppapi_simple_cpp', 'ppapi_cpp', 'ppapi', 'nacl_io', 'pthread'], + 'INCLUDES': ['../../../src/gtest/include', '../../../src/gtest'], + 'EXTRA_SOURCES' : ['../../../src/gtest/src/gtest-all.cc'], 'CXXFLAGS': ['-Wno-sign-compare'] } ],
diff --git a/native_client_sdk/src/libraries/gmock/library.dsc b/native_client_sdk/src/libraries/gmock/library.dsc index 0a268a2..71c5c47 100644 --- a/native_client_sdk/src/libraries/gmock/library.dsc +++ b/native_client_sdk/src/libraries/gmock/library.dsc
@@ -1,64 +1,38 @@ { - 'SEARCH': [ - '../../../../testing/gmock/include/gmock', - '../../../../testing/gmock/include/gmock/internal', - '../../../../testing/gmock/src', - ], - 'TARGETS': [ - { - 'NAME' : 'gmock', - 'TYPE' : 'lib', - 'SOURCES' : [ - 'gmock.cc', - 'gmock-matchers.cc', - 'gmock-cardinalities.cc', - 'gmock-internal-utils.cc', - 'gmock-spec-builders.cc', - ], # gmock-spec-builders.cc:248: error: enumeration value ‘FAIL’ not handled in switch - 'CXXFLAGS': ['-Wno-switch-enum'], - 'DEPS': ['gtest'], - } + #'CXXFLAGS': ['-Wno-switch-enum'], + 'SEARCH': [ + '../../../../testing/gmock', ], - 'HEADERS': [ - { - 'FILES': [ - 'gmock-actions.h', - 'gmock-cardinalities.h', - 'gmock-generated-actions.h', - 'gmock-generated-actions.h.pump', - 'gmock-generated-function-mockers.h', - 'gmock-generated-function-mockers.h.pump', - 'gmock-generated-matchers.h', - 'gmock-generated-matchers.h.pump', - 'gmock-generated-nice-strict.h', - 'gmock-generated-nice-strict.h.pump', - 'gmock.h', - 'gmock-matchers.h', - 'gmock-more-actions.h', - 'gmock-more-matchers.h', - 'gmock-spec-builders.h', - ], - 'DEST': 'include/gmock', - }, - { - 'FILES': [ - 'gmock-generated-internal-utils.h', - 'gmock-generated-internal-utils.h.pump', - 'gmock-internal-utils.h', - 'gmock-port.h', - ], - 'DEST': 'include/gmock/internal', - }, - { - 'FILES': [ - 'gmock.h', - 'gmock-generated-actions.h', - 'gmock-matchers.h', - 'gmock-port.h', - ], - 'DEST': 'include/gmock/internal/custom', - }, + 'DATA': [ + 'src/gmock.cc', + 'src/gmock-all.cc', + 'src/gmock-matchers.cc', + 'src/gmock-cardinalities.cc', + 'src/gmock-internal-utils.cc', + 'src/gmock-spec-builders.cc', + 'include/gmock/gmock-actions.h', + 'include/gmock/gmock-cardinalities.h', + 'include/gmock/gmock-generated-actions.h', + 'include/gmock/gmock-generated-actions.h.pump', + 'include/gmock/gmock-generated-function-mockers.h', + 'include/gmock/gmock-generated-function-mockers.h.pump', + 'include/gmock/gmock-generated-matchers.h', + 'include/gmock/gmock-generated-matchers.h.pump', + 'include/gmock/gmock-generated-nice-strict.h', + 'include/gmock/gmock-generated-nice-strict.h.pump', + 'include/gmock/gmock.h', + 'include/gmock/gmock-matchers.h', + 'include/gmock/gmock-more-actions.h', + 'include/gmock/gmock-more-matchers.h', + 'include/gmock/gmock-spec-builders.h', + 'include/gmock/internal/gmock-generated-internal-utils.h', + 'include/gmock/internal/gmock-generated-internal-utils.h.pump', + 'include/gmock/internal/gmock-internal-utils.h', + 'include/gmock/internal/gmock-port.h', + 'include/gmock/internal/custom/gmock-generated-actions.h', + 'include/gmock/internal/custom/gmock-matchers.h', + 'include/gmock/internal/custom/gmock-port.h', ], 'DEST': 'src', 'NAME': 'gmock',
diff --git a/native_client_sdk/src/libraries/gtest/library.dsc b/native_client_sdk/src/libraries/gtest/library.dsc index a22b7f4..41667f2 100644 --- a/native_client_sdk/src/libraries/gtest/library.dsc +++ b/native_client_sdk/src/libraries/gtest/library.dsc
@@ -1,80 +1,43 @@ { 'SEARCH': [ - '.', - '../../../../testing/gtest/include/gtest', - '../../../../testing/gtest/include/gtest/internal', - '../../../../testing/gtest/src', + '../../../../testing/gtest', ], - 'TARGETS': [ - { - 'NAME' : 'gtest', - 'TYPE' : 'lib', - 'SOURCES' : [ - 'gtest.cc', - 'gtest-death-test.cc', - 'gtest-filepath.cc', - 'gtest-port.cc', - 'gtest-printers.cc', - 'gtest-test-part.cc', - 'gtest-typed-test.cc', - ], - 'INCLUDES': [ - # See comment below about gtest-internal-inl.h - '$(NACL_SDK_ROOT)/include/gtest/internal', - ], - } - ], - 'HEADERS': [ - { - 'FILES': [ - 'gtest-death-test.h', - 'gtest.h', - 'gtest-message.h', - 'gtest-param-test.h', - 'gtest_pred_impl.h', - 'gtest-printers.h', - 'gtest_prod.h', - 'gtest-spi.h', - 'gtest-test-part.h', - 'gtest-typed-test.h', - ], - 'DEST': 'include/gtest', - }, - { - 'FILES': [ - 'gtest-death-test-internal.h', - 'gtest-filepath.h', - 'gtest-internal.h', - 'gtest-linked_ptr.h', - 'gtest-param-util-generated.h', - 'gtest-param-util.h', - 'gtest-port-arch.h', - 'gtest-port.h', - 'gtest-string.h', - 'gtest-tuple.h', - 'gtest-type-util.h', - ], - 'DEST': 'include/gtest/internal', - }, - { - 'FILES': [ - 'gtest.h', - 'gtest-port.h', - 'gtest-printers.h', - ], - 'DEST': 'include/gtest/internal/custom', - }, - { - # This is cheesy, but gtest.cc includes "src/gtest-internal-inl.h". Since - # gtest is not installed in the SDK, I don't really care about the - # directory layout. - # TODO(binji): If we decide to include gtest, put this file in a better - # spot. - 'FILES': [ - 'gtest-internal-inl.h', - ], - 'DEST': 'include/gtest/internal/src', - }, + 'DATA': [ + 'src/gtest.cc', + 'src/gtest_main.cc', + 'src/gtest-death-test.cc', + 'src/gtest-all.cc', + 'src/gtest-filepath.cc', + 'src/gtest-port.cc', + 'src/gtest-printers.cc', + 'src/gtest-test-part.cc', + 'src/gtest-typed-test.cc', + 'src/gtest-internal-inl.h', + 'include/gtest/gtest.h', + 'include/gtest/gtest-death-test.h', + 'include/gtest/gtest.h', + 'include/gtest/gtest-message.h', + 'include/gtest/gtest-param-test.h', + 'include/gtest/gtest_pred_impl.h', + 'include/gtest/gtest-printers.h', + 'include/gtest/gtest_prod.h', + 'include/gtest/gtest-spi.h', + 'include/gtest/gtest-test-part.h', + 'include/gtest/gtest-typed-test.h', + 'include/gtest/internal/gtest-death-test-internal.h', + 'include/gtest/internal/gtest-filepath.h', + 'include/gtest/internal/gtest-internal.h', + 'include/gtest/internal/gtest-linked_ptr.h', + 'include/gtest/internal/gtest-param-util-generated.h', + 'include/gtest/internal/gtest-param-util.h', + 'include/gtest/internal/gtest-port-arch.h', + 'include/gtest/internal/gtest-port.h', + 'include/gtest/internal/gtest-string.h', + 'include/gtest/internal/gtest-tuple.h', + 'include/gtest/internal/gtest-type-util.h', + 'include/gtest/internal/custom/gtest.h', + 'include/gtest/internal/custom/gtest-port.h', + 'include/gtest/internal/custom/gtest-printers.h', ], 'DEST': 'src', 'NAME': 'gtest',
diff --git a/native_client_sdk/src/resources/Makefile.example.template b/native_client_sdk/src/resources/Makefile.example.template index aef08ef..750af9d 100644 --- a/native_client_sdk/src/resources/Makefile.example.template +++ b/native_client_sdk/src/resources/Makefile.example.template
@@ -52,7 +52,8 @@ [[ExpandDict('LIBS', targets[0].get('LIBS', []))]] [[for target in targets:]] -[[ source_list = (s for s in sorted(target['SOURCES']) if not s.endswith('.h'))]] +[[ source_list = sorted(target['SOURCES'] + target.get('EXTRA_SOURCES', []))]] +[[ source_list = (s for s in source_list if not s.endswith('.h'))]] [[ source_list = ' \\\n '.join(source_list)]] [[ sources = target['NAME'] + '_SOURCES']] [[ cflags = target['NAME'] + '_CFLAGS']]
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc b/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc index ec4379b..3c2bb3a 100644 --- a/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc +++ b/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc
@@ -11,7 +11,12 @@ 'echo_server.h', ], 'DEPS': ['ppapi_simple_cpp', 'nacl_io'], - 'LIBS': ['ppapi_simple_cpp', 'ppapi_cpp', 'gmock', 'ppapi', 'gtest', 'nacl_io', 'pthread'], + 'LIBS': ['ppapi_simple_cpp', 'ppapi_cpp', 'ppapi', 'nacl_io', 'pthread'], + 'EXTRA_SOURCES' : ['../../src/gtest/src/gtest-all.cc'], + 'INCLUDES': [ + '../../src/gtest/include', + '../../src/gtest' + ], 'CXXFLAGS': ['-Wno-sign-compare'] } ],
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc index c7ce99a..c13ae0f 100644 --- a/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc +++ b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc
@@ -15,7 +15,6 @@ #include <string> #include "echo_server.h" -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "nacl_io/kernel_intercept.h" #include "nacl_io/kernel_proxy.h"
diff --git a/native_client_sdk/src/tests/nacl_io_test/example.dsc b/native_client_sdk/src/tests/nacl_io_test/example.dsc index 0a1055d..ee48428 100644 --- a/native_client_sdk/src/tests/nacl_io_test/example.dsc +++ b/native_client_sdk/src/tests/nacl_io_test/example.dsc
@@ -62,14 +62,25 @@ 'tty_test.cc', ], 'DEPS': ['ppapi_simple_cpp', 'nacl_io'], - 'LIBS': ['ppapi_simple_cpp', 'ppapi_cpp', 'gmock', 'nacl_io', 'ppapi', 'gtest', 'pthread'], - 'INCLUDES': ["."], + 'LIBS': ['ppapi_simple_cpp', 'ppapi_cpp', 'nacl_io', 'ppapi', 'pthread'], + 'INCLUDES': [ + '.', + '../../src/gtest/include', + '../../src/gtest', + '../../src/gmock/include', + '../../src/gmock' + ], + 'EXTRA_SOURCES' : [ + '../../src/gtest/src/gtest-all.cc', + '../../src/gmock/src/gmock-all.cc' + ], 'CXXFLAGS': ['-Wno-sign-compare'], } ], 'DATA': [ 'example.js' ], + 'DEST': 'tests', 'NAME': 'nacl_io_test', 'TITLE': 'NaCl IO test',
diff --git a/native_client_sdk/src/tests/sdk_util_test/example.dsc b/native_client_sdk/src/tests/sdk_util_test/example.dsc index 334d1da..46cf7d1 100644 --- a/native_client_sdk/src/tests/sdk_util_test/example.dsc +++ b/native_client_sdk/src/tests/sdk_util_test/example.dsc
@@ -11,7 +11,17 @@ 'string_util_test.cc', ], 'DEPS': ['ppapi_simple_cpp', 'sdk_util', 'nacl_io'], - 'LIBS': ['ppapi_simple_cpp', 'ppapi_cpp', 'gmock', 'nacl_io', 'ppapi', 'gtest', 'pthread'], + 'LIBS': ['ppapi_simple_cpp', 'ppapi_cpp', 'nacl_io', 'ppapi', 'pthread'], + 'INCLUDES': [ + '../../src/gtest/include', + '../../src/gtest', + '../../src/gmock/include', + '../../src/gmock' + ], + 'EXTRA_SOURCES' : [ + '../../src/gtest/src/gtest-all.cc', + '../../src/gmock/src/gmock-all.cc' + ], 'CXXFLAGS': ['-Wno-sign-compare'] } ],
diff --git a/native_client_sdk/src/tools/common.mk b/native_client_sdk/src/tools/common.mk index c3227985..f43ed63 100644 --- a/native_client_sdk/src/tools/common.mk +++ b/native_client_sdk/src/tools/common.mk
@@ -379,12 +379,16 @@ # # Convert a source path to a object file path. +# If source path is absolute then just use the basename of for the object +# file name (absolute sources paths with the same basename are not allowed). +# For relative paths use the full path to the source in the object file path +# name. # # $1 = Source Name # $2 = Arch suffix # define SRC_TO_OBJ -$(OUTDIR)/$(basename $(subst ..,__,$(1)))$(2).o +$(if $(filter /%,$(1)), $(OUTDIR)/$(basename $(notdir $(1)))$(2).o, $(OUTDIR)/$(basename $(subst ..,__,$(1)))$(2).o) endef
diff --git a/native_client_sdk/src/tools/host_vc.mk b/native_client_sdk/src/tools/host_vc.mk index 0890bc4..9755c554 100644 --- a/native_client_sdk/src/tools/host_vc.mk +++ b/native_client_sdk/src/tools/host_vc.mk
@@ -77,7 +77,7 @@ @echo "TOUCHED $$@" > $(STAMPDIR)/$(1).stamp all:$(LIBDIR)/$(OSNAME)_x86_32_host/$(CONFIG)/$(1).lib -$(LIBDIR)/$(OSNAME)_x86_32_host/$(CONFIG)/$(1).lib: $(foreach src,$(2),$(OUTDIR)/$(basename $(src)).o) +$(LIBDIR)/$(OSNAME)_x86_32_host/$(CONFIG)/$(1).lib: $(foreach src,$(2),$(call SRC_TO_OBJ,$(src))) $(MKDIR) -p $$(dir $$@) $(call LOG,LIB,$$@,$(HOST_LIB) /OUT:$$@ $$^ $(WIN_LDFLAGS)) endef @@ -111,7 +111,7 @@ # $6 = VC Linker Switches # define LINK_RULE -$(call LINKER_RULE,$(OUTDIR)/$(1)$(HOST_EXT),$(foreach src,$(2),$(OUTDIR)/$(basename $(src)).o),$(3),$(4),$(LIB_PATHS),$(6)) +$(call LINKER_RULE,$(OUTDIR)/$(1)$(HOST_EXT),$(foreach src,$(2),$(call SRC_TO_OBJ,$(src))),$(3),$(4),$(LIB_PATHS),$(6)) endef
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc index e7d1ac34..8f93dc47 100644 --- a/net/http/http_stream_factory_impl.cc +++ b/net/http/http_stream_factory_impl.cc
@@ -120,23 +120,30 @@ Request* request = new Request(request_info.url, this, delegate, websocket_handshake_stream_create_helper, net_log, Request::HTTP_STREAM); + HostPortPair server = HostPortPair::FromURL(request_info.url); + GURL origin_url = ApplyHostMappingRules(request_info.url, &server); + Job* job = new Job(this, session_, request_info, priority, server_ssl_config, - proxy_ssl_config, net_log.net_log()); + proxy_ssl_config, server, origin_url, net_log.net_log()); request->AttachJob(job); - const AlternativeServiceVector alternative_service_vector = - GetAlternativeServicesFor(request_info.url, delegate); + const AlternativeService alternative_service = + GetAlternativeServiceFor(request_info, delegate); - if (!alternative_service_vector.empty()) { - // TODO(bnc): Pass on multiple alternative services to Job. - const AlternativeService& alternative_service = - alternative_service_vector[0]; + if (alternative_service.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL) { // Never share connection with other jobs for FTP requests. + DVLOG(1) << "Selected alternative service (host: " + << alternative_service.host_port_pair().host() + << " port: " << alternative_service.host_port_pair().port() << ")"; + DCHECK(!request_info.url.SchemeIs("ftp")); + HostPortPair server = alternative_service.host_port_pair(); + GURL origin_url = ApplyHostMappingRules(request_info.url, &server); Job* alternative_job = new Job(this, session_, request_info, priority, server_ssl_config, - proxy_ssl_config, alternative_service, net_log.net_log()); + proxy_ssl_config, server, origin_url, alternative_service, + net_log.net_log()); request->AttachJob(alternative_job); job->WaitFor(alternative_job); @@ -159,27 +166,28 @@ const SSLConfig& server_ssl_config, const SSLConfig& proxy_ssl_config) { DCHECK(!for_websockets_); - AlternativeService alternative_service; - AlternativeServiceVector alternative_service_vector = - GetAlternativeServicesFor(request_info.url, nullptr); - if (!alternative_service_vector.empty()) { - // TODO(bnc): Pass on multiple alternative services to Job. - alternative_service = alternative_service_vector[0]; + AlternativeService alternative_service = + GetAlternativeServiceFor(request_info, nullptr); + HostPortPair server; + if (alternative_service.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL) { + server = alternative_service.host_port_pair(); if (session_->params().quic_disable_preconnect_if_0rtt && alternative_service.protocol == QUIC && session_->quic_stream_factory()->ZeroRTTEnabledFor(QuicServerId( alternative_service.host_port_pair(), request_info.privacy_mode))) { return; } + } else { + server = HostPortPair::FromURL(request_info.url); } - + GURL origin_url = ApplyHostMappingRules(request_info.url, &server); // Due to how the socket pools handle priorities and idle sockets, only IDLE // priority currently makes sense for preconnects. The priority for // preconnects is currently ignored (see RequestSocketsForPool()), but could // be used at some point for proxy resolution or something. - Job* job = - new Job(this, session_, request_info, IDLE, server_ssl_config, - proxy_ssl_config, alternative_service, session_->net_log()); + Job* job = new Job(this, session_, request_info, IDLE, server_ssl_config, + proxy_ssl_config, server, origin_url, alternative_service, + session_->net_log()); preconnect_job_set_.insert(job); job->Preconnect(num_streams); } @@ -188,11 +196,13 @@ return session_->params().host_mapping_rules; } -AlternativeServiceVector HttpStreamFactoryImpl::GetAlternativeServicesFor( - const GURL& original_url, +AlternativeService HttpStreamFactoryImpl::GetAlternativeServiceFor( + const HttpRequestInfo& request_info, HttpStreamRequest::Delegate* delegate) { + GURL original_url = request_info.url; + if (original_url.SchemeIs("ftp")) - return AlternativeServiceVector(); + return AlternativeService(); HostPortPair origin = HostPortPair::FromURL(original_url); HttpServerProperties& http_server_properties = @@ -200,7 +210,7 @@ const AlternativeServiceVector alternative_service_vector = http_server_properties.GetAlternativeServices(origin); if (alternative_service_vector.empty()) - return AlternativeServiceVector(); + return AlternativeService(); bool quic_advertised = false; bool quic_all_broken = true; @@ -208,7 +218,9 @@ const bool enable_different_host = session_->params().use_alternative_services; - AlternativeServiceVector enabled_alternative_service_vector; + // First Alt-Svc that is not marked as broken. + AlternativeService first_alternative_service; + for (const AlternativeService& alternative_service : alternative_service_vector) { DCHECK(IsAlternateProtocolValid(alternative_service.protocol)); @@ -244,7 +256,10 @@ if (session_->HasSpdyExclusion(origin)) continue; - enabled_alternative_service_vector.push_back(alternative_service); + // Cache this entry if we don't have a non-broken Alt-Svc yet. + if (first_alternative_service.protocol == + UNINITIALIZED_ALTERNATE_PROTOCOL) + first_alternative_service = alternative_service; continue; } @@ -259,11 +274,25 @@ if (!original_url.SchemeIs("https")) continue; - enabled_alternative_service_vector.push_back(alternative_service); + // Check whether there's an existing session to use for this QUIC Alt-Svc. + HostPortPair destination = alternative_service.host_port_pair(); + std::string origin_host = + ApplyHostMappingRules(request_info.url, &destination).host(); + QuicServerId server_id(destination, request_info.privacy_mode); + if (session_->quic_stream_factory()->CanUseExistingSession( + server_id, request_info.privacy_mode, origin_host)) + return alternative_service; + + // Cache this entry if we don't have a non-broken Alt-Svc yet. + if (first_alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL) + first_alternative_service = alternative_service; } + + // Ask delegate to mark QUIC as broken for the origin. if (quic_advertised && quic_all_broken && delegate != nullptr) delegate->OnQuicBroken(); - return enabled_alternative_service_vector; + + return first_alternative_service; } void HttpStreamFactoryImpl::OrphanJob(Job* job, const Request* request) {
diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h index 30ab442..5d8a206 100644 --- a/net/http/http_stream_factory_impl.h +++ b/net/http/http_stream_factory_impl.h
@@ -85,8 +85,8 @@ WebSocketHandshakeStreamBase::CreateHelper* create_helper, const BoundNetLog& net_log); - AlternativeServiceVector GetAlternativeServicesFor( - const GURL& original_url, + AlternativeService GetAlternativeServiceFor( + const HttpRequestInfo& request_info, HttpStreamRequest::Delegate* delegate); // Detaches |job| from |request|.
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index d5bcc51b..f66b053 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc
@@ -96,6 +96,8 @@ RequestPriority priority, const SSLConfig& server_ssl_config, const SSLConfig& proxy_ssl_config, + HostPortPair server, + GURL origin_url, NetLog* net_log) : Job(stream_factory, session, @@ -103,9 +105,10 @@ priority, server_ssl_config, proxy_ssl_config, + server, + origin_url, AlternativeService(), - net_log) { -} + net_log) {} HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory, HttpNetworkSession* session, @@ -113,6 +116,8 @@ RequestPriority priority, const SSLConfig& server_ssl_config, const SSLConfig& proxy_ssl_config, + HostPortPair server, + GURL origin_url, AlternativeService alternative_service, NetLog* net_log) : request_(NULL), @@ -127,6 +132,8 @@ stream_factory_(stream_factory), next_state_(STATE_NONE), pac_request_(NULL), + server_(server), + origin_url_(origin_url), alternative_service_(alternative_service), blocking_job_(NULL), waiting_job_(NULL), @@ -722,13 +729,6 @@ } int HttpStreamFactoryImpl::Job::DoStart() { - if (IsSpdyAlternative() || IsQuicAlternative()) { - server_ = alternative_service_.host_port_pair(); - } else { - server_ = HostPortPair::FromURL(request_info_.url); - } - origin_url_ = - stream_factory_->ApplyHostMappingRules(request_info_.url, &server_); valid_spdy_session_pool_.reset(new ValidSpdySessionPool( session_->spdy_session_pool(), origin_url_, IsSpdyAlternative()));
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h index 68ea52a..eb67353 100644 --- a/net/http/http_stream_factory_impl_job.h +++ b/net/http/http_stream_factory_impl_job.h
@@ -46,6 +46,8 @@ RequestPriority priority, const SSLConfig& server_ssl_config, const SSLConfig& proxy_ssl_config, + HostPortPair server, + GURL origin_url, NetLog* net_log); // Constructor for alternative Job. Job(HttpStreamFactoryImpl* stream_factory, @@ -54,6 +56,8 @@ RequestPriority priority, const SSLConfig& server_ssl_config, const SSLConfig& proxy_ssl_config, + HostPortPair server, + GURL origin_url, AlternativeService alternative_service, NetLog* net_log); ~Job();
diff --git a/net/http/http_stream_factory_impl_request_unittest.cc b/net/http/http_stream_factory_impl_request_unittest.cc index 0704ebf..9e9c5d1 100644 --- a/net/http/http_stream_factory_impl_request_unittest.cc +++ b/net/http/http_stream_factory_impl_request_unittest.cc
@@ -80,14 +80,14 @@ GURL(), factory, &request_delegate, NULL, BoundNetLog(), HttpStreamFactoryImpl::Request::HTTP_STREAM); - HttpStreamFactoryImpl::Job* job = - new HttpStreamFactoryImpl::Job(factory, - session.get(), - HttpRequestInfo(), - DEFAULT_PRIORITY, - SSLConfig(), - SSLConfig(), - NULL); + HttpRequestInfo request_info; + + HostPortPair server = HostPortPair::FromURL(request_info.url); + GURL original_url = factory->ApplyHostMappingRules(request_info.url, &server); + + HttpStreamFactoryImpl::Job* job = new HttpStreamFactoryImpl::Job( + factory, session.get(), request_info, DEFAULT_PRIORITY, SSLConfig(), + SSLConfig(), server, original_url, NULL); request.AttachJob(job); EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index 4beb01d..b67d646 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc
@@ -195,7 +195,6 @@ auth_handler_factory_( HttpAuthHandlerFactory::CreateDefault(&host_resolver_)), random_generator_(0), - hanging_data_(nullptr, 0, nullptr, 0), ssl_data_(ASYNC, OK) { request_.method = "GET"; std::string url("https://"); @@ -233,7 +232,25 @@ scoped_ptr<QuicEncryptedPacket> ConstructAckPacket( QuicPacketNumber largest_received, QuicPacketNumber least_unacked) { - return maker_.MakeAckPacket(2, largest_received, least_unacked, true); + return maker_.MakeAckPacket(2, largest_received, least_unacked, + least_unacked, true); + } + + scoped_ptr<QuicEncryptedPacket> ConstructAckPacket( + QuicPacketNumber largest_received, + QuicPacketNumber least_unacked, + QuicTestPacketMaker* maker) { + return maker->MakeAckPacket(2, largest_received, least_unacked, + least_unacked, true); + } + + scoped_ptr<QuicEncryptedPacket> ConstructAckAndConnectionClosePacket( + QuicPacketNumber packet_number, + QuicPacketNumber largest_received, + QuicPacketNumber ack_least_unacked, + QuicPacketNumber stop_least_unacked) { + return maker_.MakeAckPacket(packet_number, largest_received, + ack_least_unacked, stop_least_unacked, true); } scoped_ptr<QuicEncryptedPacket> ConstructAckAndConnectionClosePacket( @@ -256,16 +273,31 @@ return maker_.MakeRstPacket(num, include_version, stream_id, error_code); } + // Uses default QuicTestPacketMaker. SpdyHeaderBlock GetRequestHeaders(const std::string& method, const std::string& scheme, const std::string& path) { - return maker_.GetRequestHeaders(method, scheme, path); + return GetRequestHeaders(method, scheme, path, maker_); + } + + // Uses customized QuicTestPacketMaker. + SpdyHeaderBlock GetRequestHeaders(const std::string& method, + const std::string& scheme, + const std::string& path, + QuicTestPacketMaker& maker) { + return maker.GetRequestHeaders(method, scheme, path); } SpdyHeaderBlock GetResponseHeaders(const std::string& status) { return maker_.GetResponseHeaders(status); } + // Appends alt_svc headers in the response headers. + SpdyHeaderBlock GetResponseHeaders(const std::string& status, + const std::string& alt_svc) { + return maker_.GetResponseHeaders(status, alt_svc); + } + scoped_ptr<QuicEncryptedPacket> ConstructDataPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, @@ -282,12 +314,50 @@ QuicStreamId stream_id, bool should_include_version, bool fin, - const SpdyHeaderBlock& headers) { + const SpdyHeaderBlock& headers, + QuicStreamOffset* offset) { SpdyPriority priority = ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY); - return maker_.MakeRequestHeadersPacket(packet_number, stream_id, - should_include_version, fin, - priority, headers); + return maker_.MakeRequestHeadersPacketWithOffsetTracking( + packet_number, stream_id, should_include_version, fin, priority, + headers, offset); + } + + scoped_ptr<QuicEncryptedPacket> ConstructRequestHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + const SpdyHeaderBlock& headers, + QuicStreamOffset* offset, + QuicTestPacketMaker* maker) { + SpdyPriority priority = + ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY); + return maker->MakeRequestHeadersPacketWithOffsetTracking( + packet_number, stream_id, should_include_version, fin, priority, + headers, offset); + } + + scoped_ptr<QuicEncryptedPacket> ConstructRequestHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + const SpdyHeaderBlock& headers) { + return ConstructRequestHeadersPacket(packet_number, stream_id, + should_include_version, fin, headers, + nullptr, &maker_); + } + scoped_ptr<QuicEncryptedPacket> ConstructRequestHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + const SpdyHeaderBlock& headers, + QuicTestPacketMaker* maker) { + return ConstructRequestHeadersPacket(packet_number, stream_id, + should_include_version, fin, headers, + nullptr, maker); } scoped_ptr<QuicEncryptedPacket> ConstructResponseHeadersPacket( @@ -296,8 +366,44 @@ bool should_include_version, bool fin, const SpdyHeaderBlock& headers) { - return maker_.MakeResponseHeadersPacket( - packet_number, stream_id, should_include_version, fin, headers); + return ConstructResponseHeadersPacket(packet_number, stream_id, + should_include_version, fin, headers, + nullptr, &maker_); + } + + scoped_ptr<QuicEncryptedPacket> ConstructResponseHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + const SpdyHeaderBlock& headers, + QuicTestPacketMaker* maker) { + return ConstructResponseHeadersPacket(packet_number, stream_id, + should_include_version, fin, headers, + nullptr, maker); + } + + scoped_ptr<QuicEncryptedPacket> ConstructResponseHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + const SpdyHeaderBlock& headers, + QuicStreamOffset* offset) { + return maker_.MakeResponseHeadersPacketWithOffsetTracking( + packet_number, stream_id, should_include_version, fin, headers, offset); + } + + scoped_ptr<QuicEncryptedPacket> ConstructResponseHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + const SpdyHeaderBlock& headers, + QuicStreamOffset* offset, + QuicTestPacketMaker* maker) { + return maker->MakeResponseHeadersPacketWithOffsetTracking( + packet_number, stream_id, should_include_version, fin, headers, offset); } void CreateSession() { CreateSessionWithFactory(&socket_factory_, false); } @@ -433,9 +539,12 @@ } void AddHangingNonAlternateProtocolSocketData() { + scoped_ptr<StaticSocketDataProvider> hanging_data; + hanging_data.reset(new StaticSocketDataProvider()); MockConnect hanging_connect(SYNCHRONOUS, ERR_IO_PENDING); - hanging_data_.set_connect_data(hanging_connect); - socket_factory_.AddSocketDataProvider(&hanging_data_); + hanging_data->set_connect_data(hanging_connect); + hanging_data_.push_back(std::move(hanging_data)); + socket_factory_.AddSocketDataProvider(hanging_data_.back().get()); socket_factory_.AddSSLSocketDataProvider(&ssl_data_); } @@ -459,7 +568,7 @@ HttpNetworkSession::Params params_; HttpRequestInfo request_; BoundTestNetLog net_log_; - StaticSocketDataProvider hanging_data_; + std::vector<scoped_ptr<StaticSocketDataProvider>> hanging_data_; SSLSocketDataProvider ssl_data_; private: @@ -635,6 +744,7 @@ mock_quic_data1.AddRead(ASYNC, ERR_SOCKET_NOT_CONNECTED); MockQuicData mock_quic_data2; + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_); mock_quic_data2.AddRead(ASYNC, ERR_SOCKET_NOT_CONNECTED); crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_); @@ -768,14 +878,13 @@ } // When multiple alternative services are advertised, -// HttpStreamFactoryImpl::RequestStreamInternal() only passes the first one to -// Job. This is what the following test verifies. -// TODO(bnc): Update this test when multiple alternative services are handled -// properly. -TEST_P(QuicNetworkTransactionTest, UseFirstAlternativeServiceForQuic) { +// HttpStreamFactoryImpl::RequestStreamInternal() should select the alternative +// service which uses existing QUIC session if available. If no existing QUIC +// session can be used, use the first alternative service from the list. +TEST_P(QuicNetworkTransactionTest, UseExistingAlternativeServiceForQuic) { MockRead http_reads[] = { MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Alt-Svc: quic=\":443\", quic=\":1234\"\r\n\r\n"), + MockRead("Alt-Svc: quic=\"foo.example.com:443\", quic=\":444\"\r\n\r\n"), MockRead("hello world"), MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), MockRead(ASYNC, OK)}; @@ -785,15 +894,38 @@ socket_factory_.AddSocketDataProvider(&http_data); socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + QuicStreamOffset request_header_offset = 0; + QuicStreamOffset response_header_offset = 0; + // First QUIC request data. + // Open a session to foo.example.com:443 using the first entry of the + // alternative service list. MockQuicData mock_quic_data; - mock_quic_data.AddWrite( - ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true, - GetRequestHeaders("GET", "https", "/"))); + mock_quic_data.AddWrite(ConstructRequestHeadersPacket( + 1, kClientDataStreamId1, true, true, + GetRequestHeaders("GET", "https", "/"), &request_header_offset)); + + std::string alt_svc_list = + "quic=\"mail.example.com:444\", quic=\"foo.example.com:443\", " + "quic=\"bar.example.com:445\""; mock_quic_data.AddRead(ConstructResponseHeadersPacket( - 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"))); + 1, kClientDataStreamId1, false, false, + GetResponseHeaders("200 OK", alt_svc_list), &response_header_offset)); mock_quic_data.AddRead( ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!")); mock_quic_data.AddWrite(ConstructAckPacket(2, 1)); + + // Second QUIC request data. + // Connection pooling, using existing session, no need to include version + // as version negotiation has been completed. + mock_quic_data.AddWrite(ConstructRequestHeadersPacket( + 3, kClientDataStreamId2, false, true, + GetRequestHeaders("GET", "https", "/"), &request_header_offset)); + mock_quic_data.AddRead(ConstructResponseHeadersPacket( + 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"), + &response_header_offset)); + mock_quic_data.AddRead( + ConstructDataPacket(4, kClientDataStreamId2, false, true, 0, "hello!")); + mock_quic_data.AddWrite(ConstructAckAndConnectionClosePacket(4, 4, 3, 1)); mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read mock_quic_data.AddRead(ASYNC, 0); // EOF @@ -803,7 +935,283 @@ CreateSessionWithNextProtos(); SendRequestAndExpectHttpResponse("hello world"); + SendRequestAndExpectQuicResponseOnPort("hello!", 443); + SendRequestAndExpectQuicResponseOnPort("hello!", 443); +} + +// When multiple alternative services that has existing QUIC session. +// HttpStreamFactoryImpl::RequestStreamInternal() should select the first +// alternative service which uses existing QUIC session. +TEST_P(QuicNetworkTransactionTest, UseFirstExistingAlternativeServiceForQuic) { + MockRead http_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Alt-Svc: quic=\"foo.example.com:443\", quic=\":446\"\r\n\r\n"), + MockRead("hello world"), + MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead(ASYNC, OK)}; + + StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr, + 0); + socket_factory_.AddSocketDataProvider(&http_data); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + + QuicStreamOffset request_header_offset = 0; + QuicStreamOffset response_header_offset = 0; + + QuicTestPacketMaker maker(GetParam(), 0, clock_, kDefaultServerHostName); + + MockQuicData mock_quic_data; + MockQuicData mock_quic_data2; + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_); + // First QUIC request data. + // Open a QUIC session to foo.example.com:443. + mock_quic_data.AddWrite(ConstructRequestHeadersPacket( + 1, kClientDataStreamId1, true, true, + GetRequestHeaders("GET", "https", "/"), &request_header_offset)); + + std::string alt_svc_list = + "quic=\"bar.example.com:444\", quic=\"frog.example.com:445\", " + "quic=\"mail.example.com:446\""; + // Response header from the server resets the alt_svc list for the origin. + mock_quic_data.AddRead(ConstructResponseHeadersPacket( + 1, kClientDataStreamId1, false, false, + GetResponseHeaders("200 OK", alt_svc_list), &response_header_offset)); + mock_quic_data.AddRead(ConstructDataPacket(2, kClientDataStreamId1, false, + true, 0, "hello from foo!")); + mock_quic_data.AddWrite(ConstructAckPacket(2, 1)); + + // Second QUIC request data. + // Existing QUIC session to foo.example.com is not viable from the updated + // alt_svc. Unable to pool the existing QUIC session. + // Open a new QUIC session to bar.example.com:443. + mock_quic_data2.AddWrite(ConstructRequestHeadersPacket( + 1, kClientDataStreamId1, true, true, + GetRequestHeaders("GET", "https", "/"), &maker)); + alt_svc_list = + "quic=\"foo.example.com:443\", quic=\"mail.example.com:446\", " + "quic=\"bar.example.com:444\""; + // Response header from the server resets the alt_svc list for the origin. + mock_quic_data2.AddRead(ConstructResponseHeadersPacket( + 1, kClientDataStreamId1, false, false, + GetResponseHeaders("200 OK", alt_svc_list), &maker)); + mock_quic_data2.AddRead(ConstructDataPacket(2, kClientDataStreamId1, false, + true, 0, "hello from bar!")); + mock_quic_data2.AddWrite(ConstructAckPacket(2, 1, &maker)); + mock_quic_data2.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read + mock_quic_data2.AddRead(ASYNC, 0); // EOF + + // Third QUIC request data. + // Connection pooling, using the first existing session to foo.example.com + mock_quic_data.AddWrite(ConstructRequestHeadersPacket( + 3, kClientDataStreamId2, false, true, + GetRequestHeaders("GET", "https", "/"), &request_header_offset)); + mock_quic_data.AddRead(ConstructResponseHeadersPacket( + 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"), + &response_header_offset)); + mock_quic_data.AddRead(ConstructDataPacket(4, kClientDataStreamId2, false, + true, 0, "hello from foo!")); + mock_quic_data.AddWrite(ConstructAckAndConnectionClosePacket(4, 4, 3, 1)); + mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read + mock_quic_data.AddRead(ASYNC, 0); // EOF + + mock_quic_data.AddSocketDataToFactory(&socket_factory_); + AddHangingNonAlternateProtocolSocketData(); + + mock_quic_data2.AddSocketDataToFactory(&socket_factory_); + + AddHangingNonAlternateProtocolSocketData(); + + CreateSessionWithNextProtos(); + + SendRequestAndExpectHttpResponse("hello world"); + SendRequestAndExpectQuicResponseOnPort("hello from foo!", 443); + SendRequestAndExpectQuicResponseOnPort("hello from bar!", 444); + SendRequestAndExpectQuicResponseOnPort("hello from foo!", 443); +} + +// Multiple origins have listed the same alternative services. When there's a +// existing QUIC session opened by a request to other origin, +// if the cert is valid, should select this QUIC session to make the request +// if this is also the first existing QUIC session. +TEST_P(QuicNetworkTransactionTest, + UseSharedExistingAlternativeServiceForQuicWithValidCert) { + // Default cert is valid for the following origins: + // mail.example.com, mail.example.org, and www.example.org. + + // HTTP data for request to mail.example.com. + MockRead http_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Alt-Svc: quic=\":443\"\r\n\r\n"), + MockRead("hello world from mail.example.com"), + MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead(ASYNC, OK)}; + + StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr, + 0); + socket_factory_.AddSocketDataProvider(&http_data); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + + // HTTP data for request to mail.example.org. + MockRead http_reads2[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Alt-Svc: quic=\":444\", quic=\"mail.example.com:443\"\r\n\r\n"), + MockRead("hello world from mail.example.org"), + MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead(ASYNC, OK)}; + + StaticSocketDataProvider http_data2(http_reads2, arraysize(http_reads2), + nullptr, 0); + socket_factory_.AddSocketDataProvider(&http_data2); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + + QuicStreamOffset request_header_offset = 0; + QuicStreamOffset response_header_offset = 0; + + QuicTestPacketMaker maker(GetParam(), 0, clock_, kDefaultServerHostName); + maker.set_hostname("mail.example.org"); + MockQuicData mock_quic_data; + + // First QUIC request data. + mock_quic_data.AddWrite(ConstructRequestHeadersPacket( + 1, kClientDataStreamId1, true, true, + GetRequestHeaders("GET", "https", "/"), &request_header_offset)); + + mock_quic_data.AddRead(ConstructResponseHeadersPacket( + 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"), + &response_header_offset)); + mock_quic_data.AddRead(ConstructDataPacket(2, kClientDataStreamId1, false, + true, 0, "hello from mail QUIC!")); + mock_quic_data.AddWrite(ConstructAckPacket(2, 1)); + + // Second QUIC request data. + mock_quic_data.AddWrite(ConstructRequestHeadersPacket( + 3, kClientDataStreamId2, false, true, + GetRequestHeaders("GET", "https", "/", maker), &request_header_offset, + &maker)); + mock_quic_data.AddRead(ConstructResponseHeadersPacket( + 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"), + &response_header_offset)); + mock_quic_data.AddRead(ConstructDataPacket(4, kClientDataStreamId2, false, + true, 0, "hello from mail QUIC!")); + mock_quic_data.AddWrite(ConstructAckAndConnectionClosePacket(4, 4, 3, 1)); + mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read + mock_quic_data.AddRead(ASYNC, 0); // EOF + + mock_quic_data.AddSocketDataToFactory(&socket_factory_); + AddHangingNonAlternateProtocolSocketData(); + + CreateSessionWithNextProtos(); + + // Send two HTTP requests, responses set up alt-svc lists for the origins. + SendRequestAndExpectHttpResponse("hello world from mail.example.com"); + request_.url = GURL("https://mail.example.org/"); + SendRequestAndExpectHttpResponse("hello world from mail.example.org"); + + // Open a QUIC session to mail.example.com:443 when making request + // to mail.example.com. + request_.url = GURL("https://mail.example.com/"); + SendRequestAndExpectQuicResponseOnPort("hello from mail QUIC!", 443); + + // Uses the existing QUIC session when making request to mail.example.org. + request_.url = GURL("https://mail.example.org/"); + SendRequestAndExpectQuicResponseOnPort("hello from mail QUIC!", 443); +} + +// Multiple origins have listed the same alternative services. When there's a +// existing QUIC session opened by a request to other origin, +// if the cert is NOT valid, should ignore this QUIC session. +TEST_P(QuicNetworkTransactionTest, + DoNotUseSharedExistingAlternativeServiceForQuicWithInvalidCert) { + // Default cert is only valid for the following origins: + // mail.example.com, mail.example.org, and www.example.org. + // NOT valid for docs.example.org. + + // HTTP data for request to mail.example.com. + MockRead http_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Alt-Svc: quic=\":443\"\r\n\r\n"), + MockRead("hello world from mail.example.com"), + MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead(ASYNC, OK)}; + + StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr, + 0); + socket_factory_.AddSocketDataProvider(&http_data); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + + // HTTP data for request to docs.example.org. + MockRead http_reads2[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Alt-Svc: quic=\":444\", quic=\"mail.example.com:443\"\r\n\r\n"), + MockRead("hello world from docs.example.org"), + MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead(ASYNC, OK)}; + + StaticSocketDataProvider http_data2(http_reads2, arraysize(http_reads2), + nullptr, 0); + socket_factory_.AddSocketDataProvider(&http_data2); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + + QuicTestPacketMaker maker(GetParam(), 0, clock_, kDefaultServerHostName); + maker.set_hostname("docs.example.org"); + MockQuicData mock_quic_data; + MockQuicData mock_quic_data2; + + // Adding a valid cert for *.example.org but not mail.example.com. + ProofVerifyDetailsChromium verify_details; + scoped_refptr<X509Certificate> cert( + ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); + verify_details.cert_verify_result.verified_cert = cert; + verify_details.cert_verify_result.is_issued_by_known_root = true; + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + // First QUIC request data. + mock_quic_data.AddWrite( + ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true, + GetRequestHeaders("GET", "https", "/"))); + mock_quic_data.AddRead(ConstructResponseHeadersPacket( + 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"))); + mock_quic_data.AddRead(ConstructDataPacket(2, kClientDataStreamId1, false, + true, 0, "hello from mail QUIC!")); + mock_quic_data.AddWrite(ConstructAckPacket(2, 1)); + mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read + mock_quic_data.AddRead(ASYNC, 0); // EOF + + // First QUIC request data. + mock_quic_data2.AddWrite(ConstructRequestHeadersPacket( + 1, kClientDataStreamId1, true, true, + GetRequestHeaders("GET", "https", "/", maker), &maker)); + mock_quic_data2.AddRead( + ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false, + GetResponseHeaders("200 OK"), &maker)); + mock_quic_data2.AddRead(ConstructDataPacket( + 2, kClientDataStreamId1, false, true, 0, "hello from docs QUIC!")); + mock_quic_data2.AddWrite(ConstructAckPacket(2, 1, &maker)); + mock_quic_data2.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read + mock_quic_data2.AddRead(ASYNC, 0); // EOF + + mock_quic_data.AddSocketDataToFactory(&socket_factory_); + AddHangingNonAlternateProtocolSocketData(); + + mock_quic_data2.AddSocketDataToFactory(&socket_factory_); + AddHangingNonAlternateProtocolSocketData(); + + CreateSessionWithNextProtos(); + + // Send HTTP requests, responses set up the alt-svc lists for the origins. + SendRequestAndExpectHttpResponse("hello world from mail.example.com"); + request_.url = GURL("https://docs.example.org/"); + SendRequestAndExpectHttpResponse("hello world from docs.example.org"); + + // Open a QUIC session to mail.example.com:443 when making request + // to mail.example.com. + request_.url = GURL("https://mail.example.com/"); + SendRequestAndExpectQuicResponseOnPort("hello from mail QUIC!", 443); + + // Open another new QUIC session to docs.example.org:444. + request_.url = GURL("https://docs.example.org/"); + SendRequestAndExpectQuicResponseOnPort("hello from docs QUIC!", 444); } TEST_P(QuicNetworkTransactionTest, AlternativeServiceDifferentPort) {
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index dbfd508..2986c59 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -27,7 +27,6 @@ #include "net/cert/ct_verifier.h" #include "net/dns/host_resolver.h" #include "net/dns/single_request_host_resolver.h" -#include "net/http/http_server_properties.h" #include "net/quic/crypto/channel_id_chromium.h" #include "net/quic/crypto/proof_verifier_chromium.h" #include "net/quic/crypto/properties_based_quic_server_info.h" @@ -713,6 +712,20 @@ quic_server_info_factory_.reset(quic_server_info_factory); } +bool QuicStreamFactory::CanUseExistingSession(QuicServerId server_id, + PrivacyMode privacy_mode, + StringPiece origin_host) { + // TODO(zhongyi): delete active_sessions_.empty() checks once the + // android crash issue(crbug.com/498823) is resolved. + if (active_sessions_.empty()) + return false; + SessionMap::iterator it = active_sessions_.find(server_id); + if (it == active_sessions_.end()) + return false; + QuicChromiumClientSession* session = it->second; + return session->CanPool(origin_host.as_string(), privacy_mode); +} + int QuicStreamFactory::Create(const HostPortPair& host_port_pair, PrivacyMode privacy_mode, int cert_verify_flags,
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h index fd317d66..8ce70a9 100644 --- a/net/quic/quic_stream_factory.h +++ b/net/quic/quic_stream_factory.h
@@ -23,6 +23,7 @@ #include "net/base/host_port_pair.h" #include "net/base/network_change_notifier.h" #include "net/cert/cert_database.h" +#include "net/http/http_server_properties.h" #include "net/log/net_log.h" #include "net/proxy/proxy_server.h" #include "net/quic/network_connection.h" @@ -151,6 +152,12 @@ const QuicTagVector& connection_options); ~QuicStreamFactory() override; + // Returns true if there is an existing session to |server_id| which can be + // used for request to |origin_host|. + bool CanUseExistingSession(QuicServerId server_id, + PrivacyMode privacy_mode, + StringPiece origin_host); + // Creates a new QuicHttpStream to |host_port_pair| which will be // owned by |request|. // If a matching session already exists, this method will return OK. If no
diff --git a/net/quic/test_tools/quic_test_packet_maker.cc b/net/quic/test_tools/quic_test_packet_maker.cc index 91d1a605..2b9993b 100644 --- a/net/quic/test_tools/quic_test_packet_maker.cc +++ b/net/quic/test_tools/quic_test_packet_maker.cc
@@ -167,11 +167,23 @@ return scoped_ptr<QuicEncryptedPacket>(MakePacket(header, QuicFrame(&close))); } +// Sets both least_unacked fields in stop waiting frame and ack frame +// to be |least_unacked|. scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket( QuicPacketNumber packet_number, QuicPacketNumber largest_received, QuicPacketNumber least_unacked, bool send_feedback) { + return MakeAckPacket(packet_number, largest_received, least_unacked, + least_unacked, send_feedback); +} + +scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket( + QuicPacketNumber packet_number, + QuicPacketNumber largest_received, + QuicPacketNumber ack_least_unacked, + QuicPacketNumber stop_least_unacked, + bool send_feedback) { QuicPacketHeader header; header.public_header.connection_id = connection_id_; header.public_header.reset_flag = false; @@ -184,7 +196,7 @@ QuicAckFrame ack(MakeAckFrame(largest_received)); ack.delta_time_largest_observed = QuicTime::Delta::Zero(); - for (QuicPacketNumber i = least_unacked; i <= largest_received; ++i) { + for (QuicPacketNumber i = ack_least_unacked; i <= largest_received; ++i) { ack.received_packet_times.push_back(make_pair(i, clock_->Now())); } @@ -194,7 +206,7 @@ frames.push_back(QuicFrame(&ack)); QuicStopWaitingFrame stop_waiting; - stop_waiting.least_unacked = least_unacked; + stop_waiting.least_unacked = stop_least_unacked; frames.push_back(QuicFrame(&stop_waiting)); scoped_ptr<QuicPacket> packet( @@ -228,6 +240,22 @@ SpdyPriority priority, const SpdyHeaderBlock& headers, size_t* spdy_headers_frame_length) { + return MakeRequestHeadersPacket(packet_number, stream_id, + should_include_version, fin, priority, + headers, spdy_headers_frame_length, nullptr); +} + +// If |offset| is provided, will use the value when creating the packet. +// Will also update the value after packet creation. +scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + SpdyPriority priority, + const SpdyHeaderBlock& headers, + size_t* spdy_headers_frame_length, + QuicStreamOffset* offset) { InitializeHeader(packet_number, should_include_version); scoped_ptr<SpdySerializedFrame> spdy_frame; if (spdy_request_framer_.protocol_version() == SPDY3) { @@ -247,22 +275,75 @@ if (spdy_headers_frame_length) { *spdy_headers_frame_length = spdy_frame->size(); } - QuicStreamFrame frame( - kHeadersStreamId, false, 0, - base::StringPiece(spdy_frame->data(), spdy_frame->size())); - return MakePacket(header_, QuicFrame(&frame)); + if (offset != nullptr) { + QuicStreamFrame frame( + kHeadersStreamId, false, *offset, + base::StringPiece(spdy_frame->data(), spdy_frame->size())); + *offset += spdy_frame->size(); + return MakePacket(header_, QuicFrame(&frame)); + } else { + QuicStreamFrame frame( + kHeadersStreamId, false, 0, + base::StringPiece(spdy_frame->data(), spdy_frame->size())); + + return MakePacket(header_, QuicFrame(&frame)); + } } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( +// Convenience method for calling MakeRequestHeadersPacket with nullptr for +// |spdy_headers_frame_length|. +scoped_ptr<QuicEncryptedPacket> +QuicTestPacketMaker::MakeRequestHeadersPacketWithOffsetTracking( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, bool fin, SpdyPriority priority, - const SpdyHeaderBlock& headers) { + const SpdyHeaderBlock& headers, + QuicStreamOffset* offset) { return MakeRequestHeadersPacket(packet_number, stream_id, should_include_version, fin, priority, - headers, nullptr); + headers, nullptr, offset); +} + +// If |offset| is provided, will use the value when creating the packet. +// Will also update the value after packet creation. +scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + const SpdyHeaderBlock& headers, + size_t* spdy_headers_frame_length, + QuicStreamOffset* offset) { + InitializeHeader(packet_number, should_include_version); + scoped_ptr<SpdySerializedFrame> spdy_frame; + if (spdy_response_framer_.protocol_version() == SPDY3) { + SpdySynReplyIR syn_reply(stream_id); + syn_reply.set_header_block(headers); + syn_reply.set_fin(fin); + spdy_frame.reset(spdy_response_framer_.SerializeSynReply(syn_reply)); + } else { + SpdyHeadersIR headers_frame(stream_id); + headers_frame.set_header_block(headers); + headers_frame.set_fin(fin); + spdy_frame.reset(spdy_response_framer_.SerializeFrame(headers_frame)); + } + if (spdy_headers_frame_length) { + *spdy_headers_frame_length = spdy_frame->size(); + } + if (offset != nullptr) { + QuicStreamFrame frame( + kHeadersStreamId, false, *offset, + base::StringPiece(spdy_frame->data(), spdy_frame->size())); + *offset += spdy_frame->size(); + return MakePacket(header_, QuicFrame(&frame)); + } else { + QuicStreamFrame frame( + kHeadersStreamId, false, 0, + base::StringPiece(spdy_frame->data(), spdy_frame->size())); + return MakePacket(header_, QuicFrame(&frame)); + } } scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( @@ -272,36 +353,24 @@ bool fin, const SpdyHeaderBlock& headers, size_t* spdy_headers_frame_length) { - InitializeHeader(packet_number, should_include_version); - scoped_ptr<SpdySerializedFrame> spdy_frame; - if (spdy_request_framer_.protocol_version() == SPDY3) { - SpdySynReplyIR syn_reply(stream_id); - syn_reply.set_header_block(headers); - syn_reply.set_fin(fin); - spdy_frame.reset(spdy_response_framer_.SerializeSynReply(syn_reply)); - } else { - SpdyHeadersIR headers_frame(stream_id); - headers_frame.set_header_block(headers); - headers_frame.set_fin(fin); - spdy_frame.reset(spdy_request_framer_.SerializeFrame(headers_frame)); - } - if (spdy_headers_frame_length) { - *spdy_headers_frame_length = spdy_frame->size(); - } - QuicStreamFrame frame( - kHeadersStreamId, false, 0, - base::StringPiece(spdy_frame->data(), spdy_frame->size())); - return MakePacket(header_, QuicFrame(&frame)); + return MakeResponseHeadersPacket(packet_number, stream_id, + should_include_version, fin, headers, + spdy_headers_frame_length, nullptr); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( +// Convenience method for calling MakeResponseHeadersPacket with nullptr for +// |spdy_headers_frame_length|. +scoped_ptr<QuicEncryptedPacket> +QuicTestPacketMaker::MakeResponseHeadersPacketWithOffsetTracking( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, bool fin, - const SpdyHeaderBlock& headers) { - return MakeResponseHeadersPacket( - packet_number, stream_id, should_include_version, fin, headers, nullptr); + const SpdyHeaderBlock& headers, + QuicStreamOffset* offset) { + return MakeResponseHeadersPacket(packet_number, stream_id, + should_include_version, fin, headers, + nullptr, offset); } SpdyHeaderBlock QuicTestPacketMaker::GetRequestHeaders( @@ -324,6 +393,16 @@ return headers; } +SpdyHeaderBlock QuicTestPacketMaker::GetResponseHeaders( + const std::string& status, + const std::string& alt_svc) { + SpdyHeaderBlock headers; + headers[":status"] = status; + headers["Alt-Svc"] = alt_svc; + headers["content-type"] = "text/plain"; + return headers; +} + scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakePacket( const QuicPacketHeader& header, const QuicFrame& frame) {
diff --git a/net/quic/test_tools/quic_test_packet_maker.h b/net/quic/test_tools/quic_test_packet_maker.h index a63bbfa..97697701 100644 --- a/net/quic/test_tools/quic_test_packet_maker.h +++ b/net/quic/test_tools/quic_test_packet_maker.h
@@ -58,6 +58,12 @@ QuicPacketNumber largest_received, QuicPacketNumber least_unacked, bool send_feedback); + scoped_ptr<QuicEncryptedPacket> MakeAckPacket( + QuicPacketNumber packet_number, + QuicPacketNumber largest_received, + QuicPacketNumber ack_least_unacked, + QuicPacketNumber stop_least_unacked, + bool send_feedback); scoped_ptr<QuicEncryptedPacket> MakeDataPacket(QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -76,15 +82,26 @@ const SpdyHeaderBlock& headers, size_t* spdy_headers_frame_length); - // Convenience method for calling MakeRequestHeadersPacket with nullptr for - // |spdy_headers_frame_length|. scoped_ptr<QuicEncryptedPacket> MakeRequestHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, bool fin, SpdyPriority priority, - const SpdyHeaderBlock& headers); + const SpdyHeaderBlock& headers, + size_t* spdy_headers_frame_length, + QuicStreamOffset* offset); + + // Convenience method for calling MakeRequestHeadersPacket with nullptr for + // |spdy_headers_frame_length|. + scoped_ptr<QuicEncryptedPacket> MakeRequestHeadersPacketWithOffsetTracking( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + SpdyPriority priority, + const SpdyHeaderBlock& headers, + QuicStreamOffset* offset); // If |spdy_headers_frame_length| is non-null, it will be set to the size of // the SPDY headers frame created for this packet. @@ -94,22 +111,35 @@ bool should_include_version, bool fin, const SpdyHeaderBlock& headers, + size_t* spdy_headers_frame_length, + QuicStreamOffset* offset); + + scoped_ptr<QuicEncryptedPacket> MakeResponseHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + const SpdyHeaderBlock& headers, size_t* spdy_headers_frame_length); // Convenience method for calling MakeResponseHeadersPacket with nullptr for // |spdy_headers_frame_length|. - scoped_ptr<QuicEncryptedPacket> MakeResponseHeadersPacket( + scoped_ptr<QuicEncryptedPacket> MakeResponseHeadersPacketWithOffsetTracking( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, bool fin, - const SpdyHeaderBlock& headers); + const SpdyHeaderBlock& headers, + QuicStreamOffset* offset); SpdyHeaderBlock GetRequestHeaders(const std::string& method, const std::string& scheme, const std::string& path); SpdyHeaderBlock GetResponseHeaders(const std::string& status); + SpdyHeaderBlock GetResponseHeaders(const std::string& status, + const std::string& alt_svc); + private: scoped_ptr<QuicEncryptedPacket> MakePacket(const QuicPacketHeader& header, const QuicFrame& frame);
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 88941f8..9941436 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc
@@ -1974,7 +1974,7 @@ // SelectNextProtoCallback is called by OpenSSL during the handshake. If the // server supports NPN, selects a protocol from the list that the server -// provides. According to third_party/openssl/openssl/ssl/ssl_lib.c, the +// provides. According to third_party/boringssl/src/ssl/ssl_lib.c, the // callback can assume that |in| is syntactically valid. int SSLClientSocketOpenSSL::SelectNextProtoCallback(unsigned char** out, unsigned char* outlen,
diff --git a/storage/browser/quota/quota_database.cc b/storage/browser/quota/quota_database.cc index 546073f..fee6621 100644 --- a/storage/browser/quota/quota_database.cc +++ b/storage/browser/quota/quota_database.cc
@@ -60,6 +60,15 @@ UMA_HISTOGRAM_ENUMERATION("Quota.LRUOriginTypes", entry, MAX_ORIGIN_TYPE); } +void LogDaysSinceLastAccess(base::Time this_time, + const QuotaDatabase::OriginInfoTableEntry& entry) { + base::TimeDelta time_since = this_time - std::max(entry.last_access_time, + entry.last_modified_time); + if (time_since.InDays() < 1) + return; + UMA_HISTOGRAM_COUNTS_1000("Quota.DaysSinceLastAccess", time_since.InDays()); +} + } // anonymous namespace // static @@ -203,22 +212,24 @@ sql::Statement statement; - int used_count = 1; - if (FindOriginUsedCount(origin, type, &used_count)) { - ++used_count; + OriginInfoTableEntry entry; + if (GetOriginInfo(origin, type, &entry)) { + LogDaysSinceLastAccess(last_access_time, entry); + ++entry.used_count; const char* kSql = "UPDATE OriginInfoTable" " SET used_count = ?, last_access_time = ?" " WHERE origin = ? AND type = ?"; statement.Assign(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); } else { + entry.used_count = 1; const char* kSql = "INSERT INTO OriginInfoTable" " (used_count, last_access_time, origin, type)" " VALUES (?, ?, ?, ?)"; statement.Assign(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); } - statement.BindInt(0, used_count); + statement.BindInt(0, entry.used_count); statement.BindInt64(1, last_access_time.ToInternalValue()); statement.BindString(2, origin.spec()); statement.BindInt(3, static_cast<int>(type)); @@ -237,8 +248,9 @@ sql::Statement statement; - int dummy; - if (FindOriginUsedCount(origin, type, &dummy)) { + OriginInfoTableEntry entry; + if (GetOriginInfo(origin, type, &entry)) { + LogDaysSinceLastAccess(last_modified_time, entry); const char* kSql = "UPDATE OriginInfoTable" " SET last_modified_time = ?" @@ -528,27 +540,6 @@ this, &QuotaDatabase::Commit); } -bool QuotaDatabase::FindOriginUsedCount( - const GURL& origin, StorageType type, int* used_count) { - DCHECK(used_count); - if (!LazyOpen(false)) - return false; - - const char* kSql = - "SELECT used_count FROM OriginInfoTable" - " WHERE origin = ? AND type = ?"; - - sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); - statement.BindString(0, origin.spec()); - statement.BindInt(1, static_cast<int>(type)); - - if (!statement.Step()) - return false; - - *used_count = statement.ColumnInt(0); - return true; -} - bool QuotaDatabase::LazyOpen(bool create_if_needed) { if (db_) return true;
diff --git a/storage/browser/quota/quota_database.h b/storage/browser/quota/quota_database.h index 49d5e13..bcda36922 100644 --- a/storage/browser/quota/quota_database.h +++ b/storage/browser/quota/quota_database.h
@@ -167,10 +167,6 @@ void Commit(); void ScheduleCommit(); - bool FindOriginUsedCount(const GURL& origin, - StorageType type, - int* used_count); - bool LazyOpen(bool create_if_needed); bool EnsureDatabaseVersion(); bool ResetSchema();
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index 7f6cec3..b6ba9ad 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc
@@ -1695,7 +1695,7 @@ db_initialization_callbacks_.Run(); GetTemporaryGlobalQuota( base::Bind(&QuotaManager::DidGetInitialTemporaryGlobalQuota, - weak_factory_.GetWeakPtr())); + weak_factory_.GetWeakPtr(), base::TimeTicks::Now())); } void QuotaManager::DidGetLRUOrigin(const GURL* origin, @@ -1706,8 +1706,14 @@ lru_origin_callback_.Reset(); } -void QuotaManager::DidGetInitialTemporaryGlobalQuota(QuotaStatusCode status, - int64_t quota_unused) { +void QuotaManager::DidGetInitialTemporaryGlobalQuota( + base::TimeTicks start_ticks, + QuotaStatusCode status, + int64_t quota_unused) { + UMA_HISTOGRAM_LONG_TIMES( + "Quota.TimeToInitializeGlobalQuota", + base::TimeTicks::Now() - start_ticks); + if (eviction_disabled_) return;
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h index 27c7dee..16e3527 100644 --- a/storage/browser/quota/quota_manager.h +++ b/storage/browser/quota/quota_manager.h
@@ -428,7 +428,8 @@ bool success); void DidGetLRUOrigin(const GURL* origin, bool success); - void DidGetInitialTemporaryGlobalQuota(QuotaStatusCode status, + void DidGetInitialTemporaryGlobalQuota(base::TimeTicks start_ticks, + QuotaStatusCode status, int64_t quota_unused); void DidInitializeTemporaryOriginsInfo(bool success); void DidGetAvailableSpace(int64_t space);
diff --git a/styleguide/c++/c++11.html b/styleguide/c++/c++11.html index 1e14b42d..2776be9 100644 --- a/styleguide/c++/c++11.html +++ b/styleguide/c++/c++11.html
@@ -395,6 +395,17 @@ </tr> <tr> +<td>Forwarding references</td> +<td><code>std::forward()</code></td> +<td>Perfectly forwards arguments (including rvalues)</td> +<td><a href="http://en.cppreference.com/w/cpp/utility/forward"><code>std::forward</code></a></td> +<td> + Allowed, though usage should be rare (primarily for forwarding constructor arguments, or in carefully reviewed library code). + <a href="https://groups.google.com/a/chromium.org/d/topic/cxx/-O7euklhSxs/discussion">Discussion thread</a> +</td> +</tr> + +<tr> <td>Type Traits</td> <td>Class templates within <code><type_traits></code></td> <td>Allows compile-time inspection of the properties of types</td> @@ -548,6 +559,18 @@ <td>Does not yet work in MSVS2013. Reevaluate once it does. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/gcoUbcjfsII">Discussion thread</a></td> </tr> +<tr> +<td>Ref-qualified Member Functions</td> +<td><code>class T {<br/> void f() & {}<br/> void f() && {}<br/>};<br/>t.f(); // first<br/>T().f(); // second<br/>std::move(t).f(); // second</code></td> +<td>Allows class member functions to only bind to |this| as an rvalue or lvalue.</td> +<td><a href="http://en.cppreference.com/w/cpp/language/member_functions"> +Member functions</a></td> +<td> + Banned in the google3 C++11 library style guide. Banned in Chromium except by explicit approval from <code>styleguide/c++/OWNERS</code>. + <a href="https://groups.google.com/a/chromium.org/d/topic/cxx/gowclr2LPQA/discussion">Discussion Thread</a> +</td> +</tr> + </tbody> </table> @@ -591,6 +614,37 @@ <td>C++11 has all kinds of classes for threads, mutexes, etc. Since we already have good code for this in <code>base/</code>, we should keep using the base classes, at least at first. <code>base::Thread</code> is tightly coupled to <code>MessageLoop</code> which would make it hard to replace. We should investigate using standard mutexes, or unique_lock, etc. to replace our locking/synchronization classes.</td> </tr> +<tr> +<td>Atomics</td> +<td><code>std::atomic</code> and others in <code><atomic></code></td> +<td>Fine-grained atomic types and operations</td> +<td><a href="http://en.cppreference.com/w/cpp/atomic"><atomic></a></td> +<td>Use in tcmalloc has caused <a href="http://crbug.com/572525">performance regressions</a>. Banned until we understand this better. <a href="https://groups.google.com/a/chromium.org/d/topic/cxx/Ej3RAiaI44s/discussion">Discussion Thread</a></td> +</tr> + +<tr> +<td>Shared Pointers</td> +<td><code>std::shared_ptr</code></td> +<td>Allows shared ownership of a pointer through reference counts</td> +<td><a href="http://en.cppreference.com/w/cpp/memory/shared_ptr">std::shared_ptr</a></td> +<td> + Needs a lot more evaluation for Chromium, and there isn't enough of a push for this feature. + <a href="https://groups.google.com/a/chromium.org/d/topic/cxx/aT2wsBLKvzI/discussion">Discussion Thread</a>, + <a href="https://google.github.io/styleguide/cppguide.html#Ownership_and_Smart_Pointers">Google Style Guide</a> +</td> +</tr> + +<tr> +<td>Initializer Lists</td> +<td><code>std::initializer_list<T></code></td> +<td>Allows containers to be initialized with aggregate elements</td> +<td><a href="http://en.cppreference.com/w/cpp/utility/initializer_list"><code>std::initializer_list</code></a></td> +<td> + Banned for now; will be re-evaluated once we switch to MSVC 2015. + <a href="https://groups.google.com/a/chromium.org/d/topic/cxx/TQQ-L51_naM/discussion">Discussion Thread</a> +</td> +</tr> + </tbody> </table> @@ -644,15 +698,6 @@ </tr> <tr> -<td>Ref-qualified Member Functions</td> -<td><code>class T {<br/> void f() & {}<br/> void f() && {}<br/>};<br/>t.f(); // first<br/>T().f(); // second<br/>std::move(t).f(); // second</code></td> -<td>Allows class member functions to only bind to |this| as an rvalue or lvalue.</td> -<td><a href="http://en.cppreference.com/w/cpp/language/member_functions"> -Member functions</a></td> -<td>Banned in the google3 C++11 library style guide, but being considered for use in bind/callback in google3 and the standard library.</td> -</tr> - -<tr> <td>Union Class Members</td> <td><code>union <i>name</i> { <i>class</i> <i>var</i>}</code></td> <td>Allows class type members</td> @@ -724,14 +769,6 @@ </tr> <tr> -<td>Atomics</td> -<td><code>std::atomic</code> and others in <code><atomic></code></td> -<td>Fine-grained atomic types and operations</td> -<td><a href="http://en.cppreference.com/w/cpp/atomic"><atomic></a></td> -<td></td> -</tr> - -<tr> <td>Bind Operations</td> <td><code>std::bind(<i>function</i>, <i>args</i>, ...)</code></td> <td>Declares a function object bound to certain arguments</td> @@ -874,14 +911,6 @@ </tr> <tr> -<td>Initializer Lists</td> -<td><code>std::initializer_list<T></code></td> -<td>Allows containers to be initialized with aggregate elements</td> -<td>TODO: documentation link</td> -<td></td> -</tr> - -<tr> <td>Pointer Traits Class Template</td> <td><code>std::pointer_traits</code></td> <td>Provides a standard way to access properties @@ -923,15 +952,6 @@ </tr> <tr> -<td>Shared Pointers</td> -<td><code>std::shared_ptr</code></td> -<td>Allows shared ownership of a pointer through reference counts</td> -<td><a href="http://en.cppreference.com/w/cpp/memory/shared_ptr">std::shared_ptr</a></td> -<td><a href="https://google.github.io/styleguide/cppguide.html#Ownership_and_Smart_Pointers"> -Ownership and Smart Pointers</a></td> -</tr> - -<tr> <td>Soft Program Exits</td> <td><code>std::at_quick_exit()</code> and <code>std::quick_exit()</code></td>
diff --git a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java index fc579d7f..7e8e205 100644 --- a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java +++ b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
@@ -279,9 +279,7 @@ } /** - * This method is deprecated; please use the asynchronous version below instead. - * - * See http://crbug.com/517697 for details. + * @return Whether or not there is an account authenticator for Google accounts. */ public boolean hasGoogleAccountAuthenticator() { AuthenticatorDescription[] descs = mAccountManager.getAuthenticatorTypes();
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 266f152..e6896b9e 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1328,4 +1328,4 @@ crbug.com/575037 [ Android ] webaudio/codec-tests/aac/vbr-128kbps-44khz.html [ Skip ] crbug.com/575037 [ Android ] webaudio/codec-tests/mp3/128kbps-44khz.html [ Skip ] -crbug.com/575037 [ Android ] webaudio/codec-tests/wav/24bit-22khz-resample.html [ Skip ] +crbug.com/575037 [ Android ] webaudio/codec-tests/wav/24bit-22khz-resample.html [ Skip ] \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/webgl/tex-input-validation-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/webgl/tex-input-validation-expected.txt index 988a943..0b35e3f9 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/webgl/tex-input-validation-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/canvas/webgl/tex-input-validation-expected.txt
@@ -8,7 +8,7 @@ Checking TexImage2D: a set of inputs that are valid in GL but invalid in GLES2 PASS getError was expected value: INVALID_ENUM : internalFormat: RGBA target: 0x8064 format: RGBA type: UNSIGNED_BYTE border: 0 -PASS getError was expected value: INVALID_ENUM : internalFormat: 0x1903 target: TEXTURE_2D format: 0x1903 type: UNSIGNED_BYTE border: 0 +PASS getError was one of: INVALID_ENUM or INVALID_VALUE : internalFormat: 0x1903 target: TEXTURE_2D format: 0x1903 type: UNSIGNED_BYTE border: 0 PASS getError was expected value: INVALID_VALUE : internalFormat: RGBA target: TEXTURE_2D format: RGBA type: UNSIGNED_BYTE border: 1 PASS getError was expected value: INVALID_OPERATION : internalFormat: RGBA target: TEXTURE_2D format: RGB type: UNSIGNED_BYTE border: 0 PASS getError was expected value: INVALID_ENUM : internalFormat: RGBA target: TEXTURE_2D format: RGBA type: BYTE border: 0
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/webgl/tex-input-validation.html b/third_party/WebKit/LayoutTests/fast/canvas/webgl/tex-input-validation.html index 57b77eff..b28da68 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/webgl/tex-input-validation.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/webgl/tex-input-validation.html
@@ -180,7 +180,7 @@ border: 0, format: 0x1903, // GL_RED type: gl.UNSIGNED_BYTE, - expectedError: gl.INVALID_ENUM}, + expectedError: [gl.INVALID_ENUM, gl.INVALID_VALUE] }, {target: gl.TEXTURE_2D, internalFormat: gl.RGBA, border: 1,
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/webgl/webgl-depth-texture-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/webgl/webgl-depth-texture-expected.txt index bcb294f..b3f5851 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/webgl/webgl-depth-texture-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/canvas/webgl/webgl-depth-texture-expected.txt
@@ -5,8 +5,8 @@ PASS WebGL context exists Testing binding enum with extension disabled -PASS gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null) generated expected GL error: INVALID_ENUM. -PASS gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null) generated expected GL error: INVALID_ENUM. +PASS gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null) generated one of expected GL errors: INVALID_ENUM or INVALID_VALUE. +PASS gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null) generated one of expected GL errors: INVALID_ENUM or INVALID_VALUE. PASS Successfully enabled WEBGL_depth_texture extension PASS WEBGL_depth_texture listed as supported and getExtension succeeded Testing WEBGL_depth_texture
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/webgl/webgl-depth-texture.html b/third_party/WebKit/LayoutTests/fast/canvas/webgl/webgl-depth-texture.html index b129f11b..b98b314 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/webgl/webgl-depth-texture.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/webgl/webgl-depth-texture.html
@@ -94,8 +94,8 @@ var tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); - shouldGenerateGLError(gl, gl.INVALID_ENUM, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null)'); - shouldGenerateGLError(gl, gl.INVALID_ENUM, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null)'); + shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE], 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null)'); + shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE], 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null)'); }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js index d0db2418a..561cd78 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -442,12 +442,10 @@ InspectorTest.dumpNavigatorViewInMode = function(view, mode) { InspectorTest.addResult(view instanceof WebInspector.SourcesNavigatorView ? "Sources:" : "Content Scripts:"); - if (WebInspector.moduleSetting("navigatorGroupByFrame").get() !== mode.includes("frame")) - WebInspector.moduleSetting("navigatorGroupByFrame").set(mode.includes("frame")); - if (WebInspector.moduleSetting("navigatorGroupByDomain") !== mode.includes("domain")) - WebInspector.moduleSetting("navigatorGroupByDomain").set(mode.includes("domain")); - if (WebInspector.moduleSetting("navigatorGroupByFolder") !== mode.includes("folder")) - WebInspector.moduleSetting("navigatorGroupByFolder").set(mode.includes("folder")); + view._groupByFrame = mode.includes("frame"); + view._groupByDomain = mode.includes("domain"); + view._groupByFolder = mode.includes("folder"); + view._resetForTest(); InspectorTest.addResult("-------- Setting mode: [" + mode + "]"); InspectorTest.dumpNavigatorView(view); }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-document-url.html b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-document-url.html index 749cea5..838df871 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-document-url.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-document-url.html
@@ -5,12 +5,25 @@ <script src="resource-tree-test.js"></script> <script> +function loadIframe() +{ + var iframe = document.createElement("iframe"); + iframe.src = "resources/dummy-iframe.html"; + document.body.appendChild(iframe); +} function test() { - InspectorTest.runAfterResourcesAreFinished(["dummy-iframe.html", "inspector-test.js", "resources-test.js", "resource-tree-test.js"], step1); + InspectorTest.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, waitForResources); + InspectorTest.evaluateInPage("loadIframe()"); - function step1() + function waitForResources() + { + InspectorTest.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, waitForResources); + InspectorTest.runAfterResourcesAreFinished(["dummy-iframe.html", "inspector-test.js", "resources-test.js", "resource-tree-test.js"], dump); + } + + function dump() { function formatter(resource) { @@ -26,12 +39,10 @@ </head> -<body> +<body onload="runTest()"> <p> Tests that resources have proper documentURL set in the tree model. </p> -<iframe src="resources/dummy-iframe.html" onload="runTest()"> - </body> </html>
diff --git a/third_party/WebKit/LayoutTests/paint/background/rounded-clip-fractional-offset-expected.png b/third_party/WebKit/LayoutTests/paint/background/rounded-clip-fractional-offset-expected.png new file mode 100644 index 0000000..bc9f1c2f --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/background/rounded-clip-fractional-offset-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/background/rounded-clip-fractional-offset-expected.txt b/third_party/WebKit/LayoutTests/paint/background/rounded-clip-fractional-offset-expected.txt new file mode 100644 index 0000000..b4d3ddc --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/background/rounded-clip-fractional-offset-expected.txt
@@ -0,0 +1,10 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x116 + LayoutBlockFlow {HTML} at (0,0) size 800x116 + LayoutBlockFlow {BODY} at (8,8) size 394x100 [bgcolor=#808080] + LayoutBlockFlow {DIV} at (0,0) size 305.78x100 + LayoutBlockFlow {DIV} at (10.39,0) size 295.39x100 +layer at (18,8) size 295x100 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 295.39x100 [bgcolor=#FF0000] + LayoutBlockFlow {DIV} at (95.30,0) size 200x100 [color=#FFFFFF] [bgcolor=#000000]
diff --git a/third_party/WebKit/LayoutTests/paint/background/rounded-clip-fractional-offset.html b/third_party/WebKit/LayoutTests/paint/background/rounded-clip-fractional-offset.html new file mode 100644 index 0000000..2f99628 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/background/rounded-clip-fractional-offset.html
@@ -0,0 +1,35 @@ +<!doctype HTML> +<style> +body { + background: grey; + width: 394px; +} +.column { + width: 295.4px; + padding-left: 10.4px; +} + +.red-background { + background: red; + position: relative; + overflow: hidden; + border-radius: 1px; + height: 100px; +} + +.black-background { + height: 100px; + background: black; + color: white; + width: 200px; + margin-left: 95.3px; +} +</style> +<!-- There should not be any red visible to the right of the black square. --> +<div class="column"> + <div> + <div class="red-background"> + <div class="black-background"></div> + </div> + </div> +</div> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/platform/mac/plugins/plugin-clip-subframe-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/plugins/plugin-clip-subframe-expected.txt index e48932c0..73b286f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/plugins/plugin-clip-subframe-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/plugins/plugin-clip-subframe-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE MESSAGE: line 5: NPP_SetWindow: NULL window, Rect {0, 0, 300, 150}, Clip Rect {65528, 65528, 65528, 65528}, Type 2 +CONSOLE MESSAGE: line 5: NPP_SetWindow: NULL window, Rect {0, 0, 300, 150}, Clip Rect {65518, 65318, 65518, 65318}, Type 2
diff --git a/third_party/WebKit/LayoutTests/svg/dom/svgpath-negative-pathLength-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/svgpath-negative-pathLength-expected.txt index 60a8c47e..09caefe 100644 --- a/third_party/WebKit/LayoutTests/svg/dom/svgpath-negative-pathLength-expected.txt +++ b/third_party/WebKit/LayoutTests/svg/dom/svgpath-negative-pathLength-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 4: Error: A negative value for path attribute <pathLength> is not allowed +CONSOLE ERROR: line 4: Error: Invalid negative value for <path> attribute pathLength="-1"
diff --git a/third_party/WebKit/LayoutTests/svg/repaint/transform-foreign-object-expected.txt b/third_party/WebKit/LayoutTests/svg/repaint/transform-foreign-object-expected.txt new file mode 100644 index 0000000..7308065 --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/repaint/transform-foreign-object-expected.txt
@@ -0,0 +1,24 @@ +{ + "bounds": [800, 600], + "children": [ + { + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "repaintRects": [ + [108, 8, 100, 100], + [108, 8, 100, 100], + [108, 8, 100, 100], + [8, 8, 100, 100], + [8, 8, 100, 100], + [8, 8, 100, 100] + ], + "paintInvalidationClients": [ + "LayoutSVGRoot svg", + "LayoutSVGForeignObject foreignObject", + "LayoutBlockFlow DIV" + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/svg/repaint/transform-foreign-object.html b/third_party/WebKit/LayoutTests/svg/repaint/transform-foreign-object.html new file mode 100644 index 0000000..5163eb3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/repaint/transform-foreign-object.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<script src="../../fast/repaint/resources/text-based-repaint.js"></script> +<script> + window.onload = runRepaintTest; + + function repaintTest() { + var foreign = document.getElementsByTagName("foreignObject")[0]; + foreign.style.transform = 'translate(100px, 0px)'; + } +</script> +<body> +<svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <foreignObject width="100" height="100"> + <div xmlns="http://www.w3.org/1999/xhtml" style="width: 100px; height: 100px; background-color: green;"></div> + </foreignObject> +</svg> +</body>
diff --git a/third_party/WebKit/LayoutTests/svg/repaint/transform-text-element-expected.txt b/third_party/WebKit/LayoutTests/svg/repaint/transform-text-element-expected.txt new file mode 100644 index 0000000..d8c0a6f --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/repaint/transform-text-element-expected.txt
@@ -0,0 +1,28 @@ +{ + "bounds": [800, 600], + "children": [ + { + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "repaintRects": [ + [8, 58, 400, 100], + [8, 58, 400, 100], + [8, 58, 400, 100], + [8, 8, 400, 100], + [8, 8, 400, 100], + [8, 8, 400, 100] + ], + "paintInvalidationClients": [ + "RootInlineBox", + "InlineTextBox 'Test'", + "LayoutSVGRoot svg", + "LayoutSVGText text", + "RootInlineBox", + "LayoutSVGInlineText #text", + "InlineTextBox 'Test'" + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/svg/repaint/transform-text-element.html b/third_party/WebKit/LayoutTests/svg/repaint/transform-text-element.html new file mode 100644 index 0000000..e9701431 --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/repaint/transform-text-element.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<script src="../../fast/repaint/resources/text-based-repaint.js"></script> +<script src=../../resources/ahem.js></script> +<script> + window.onload = runRepaintTest; + + function repaintTest() { + var text = document.getElementsByTagName("text")[0]; + text.style.transform = 'translate(0px, 50px)'; + } +</script> +<body> +<svg width="400" height="400" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <text y="80" fill="green" font-size="100" font-family="Ahem">Test</text> +</svg> +</body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop-expected.txt new file mode 100644 index 0000000..1a92f989 --- /dev/null +++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop-expected.txt
@@ -0,0 +1,12 @@ +Test if AudioBufferSourceNode stops prematurely after the loop attribute change. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS Region #1 contains only the constant 1. +PASS Region #2 (looped) contains only the constant 2. +PASS Region #3 contains only the constant 3. +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop.html b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop.html new file mode 100644 index 0000000..a0d7e127 --- /dev/null +++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop.html
@@ -0,0 +1,91 @@ +<!DOCTYPE html> +<html> + +<head> + <title>Test AudioBufferSourceNode premature loop stop</title> + <script src="../resources/js-test.js"></script> + <script src="resources/compatibility.js"></script> + <script src="resources/audio-testing.js"></script> +</head> + +<body> + <script> + description("Test if AudioBufferSourceNode stops prematurely after the loop attribute change."); + window.jsTestIsAsync = true; + + // Reasonably low sample rate for the optimum test speed. + var sampleRate = 4096; + + var audit = Audit.createTaskRunner(); + + // Task: Create a buffer with 3 regions filled with constant value of [1, 2, + // 3]. Then set a loop range over the second region. Start the loop and + // disable it in the middle of looping. Verify the rendered buffer has the + // entire content including the looped region. + audit.defineTask('premature-loop-stop', function (done) { + var regionValues = [1, 2, 3]; + + // The region length is 2 * render quantum size to be able to suspend the + // rendering at the half of the region. + var regionLength = 256; + + // The test will repeat the second region 3 times, thus the rendered audio + // have the length of 5 * regionLength. + var context = new OfflineAudioContext(1, 5 * regionLength, sampleRate); + + // Create 3 constant buffers of [1, 2, 3] and concatenate them together: + // | 1 | 2 | 3 | + var testBuffer = context.createBuffer(1, 3 * regionLength, sampleRate); + var testChannel = testBuffer.getChannelData(0); + for (var i = 0; i < regionValues.length; i++) { + var region = createConstantBuffer(context, regionLength, regionValues[i]); + testChannel.set(region.getChannelData(0), regionLength * i);; + } + + var source = context.createBufferSource(); + source.connect(context.destination); + + source.buffer = testBuffer; + source.loop = true; + + // Set loop points over the region 2. + source.loopStart = regionLength/sampleRate; + source.loopEnd = 2 * regionLength/sampleRate; + + source.start(); + + // Disengage the loop at |3.5 * regionLength / sampleRate| which is the + // end of 7th rendering quantum and also the half of the third iteration + // of region #2. + context.suspend(3.5 * regionLength/sampleRate).then(function () { + source.loop = false; + context.resume(); + }); + + context.startRendering().then(function (renderedBuffer) { + var channel = renderedBuffer.getChannelData(0); + + // Verify if the rendered buffer has the following structure: + // | 1 | 2 | 2 | 2 | 3 | + var region1 = channel.subarray(0, regionLength - 1); + var region2 = channel.subarray(regionLength, 4 * regionLength - 1); + var region3 = channel.subarray(4 * regionLength, 5 * regionLength - 1); + + Should('Region #1', region1).beConstantValueOf(1); + Should('Region #2 (looped)', region2).beConstantValueOf(2); + Should('Region #3', region3).beConstantValueOf(3); + }).then(done); + }); + + audit.defineTask('finish', function (done) { + finishJSTest(); + done(); + }); + + audit.runTasks(); + + successfullyParsed = true; + </script> +</body> + +</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute-expected.txt new file mode 100644 index 0000000..d5ef99a --- /dev/null +++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute-expected.txt
@@ -0,0 +1,41 @@ +Test linearRampToValue Updates the Param Value + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS gain.gain.value at frame 127 is equal to 0.06201171875. +PASS gain.gain.value at frame 255 is equal to 0.12451171875. +PASS gain.gain.value at frame 383 is equal to 0.18701171875. +PASS gain.gain.value at frame 511 is equal to 0.24951171875. +PASS gain.gain.value at frame 639 is equal to 0.31201171875. +PASS gain.gain.value at frame 767 is equal to 0.37451171875. +PASS gain.gain.value at frame 895 is equal to 0.43701171875. +PASS gain.gain.value at frame 1023 is equal to 0.49951171875. +PASS gain.gain.value at frame 1151 is equal to 0.56201171875. +PASS gain.gain.value at frame 1279 is equal to 0.62451171875. +PASS gain.gain.value at frame 1407 is equal to 0.68701171875. +PASS gain.gain.value at frame 1535 is equal to 0.74951171875. +PASS gain.gain.value at frame 1663 is equal to 0.81201171875. +PASS gain.gain.value at frame 1791 is equal to 0.87451171875. +PASS gain.gain.value at frame 1919 is equal to 0.93701171875. +PASS gain.gain.value at frame 2047 is equal to 0.99951171875. +PASS gain.gain.value at frame 2175 is equal to 1. +PASS gain.gain.value at frame 2303 is equal to 1. +PASS gain.gain.value at frame 2431 is equal to 1. +PASS gain.gain.value at frame 2559 is equal to 1. +PASS gain.gain.value at frame 2687 is equal to 1. +PASS gain.gain.value at frame 2815 is equal to 1. +PASS gain.gain.value at frame 2943 is equal to 1. +PASS gain.gain.value at frame 3071 is equal to 1. +PASS gain.gain.value at frame 3199 is equal to 1. +PASS gain.gain.value at frame 3327 is equal to 1. +PASS gain.gain.value at frame 3455 is equal to 1. +PASS gain.gain.value at frame 3583 is equal to 1. +PASS gain.gain.value at frame 3711 is equal to 1. +PASS gain.gain.value at frame 3839 is equal to 1. +PASS gain.gain.value at frame 3967 is equal to 1. +PASS linearRampToValue properly set the AudioParam value. +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute.html new file mode 100644 index 0000000..7497fe80 --- /dev/null +++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute.html
@@ -0,0 +1,88 @@ +<!doctype html> +<html> + <head> + <title>Test linearRampToValue Updates the Param Value</title> + <script src="../resources/js-test.js"></script> + <script src="resources/compatibility.js"></script> + <script src="resources/audio-testing.js"></script> + </head> + + <body> + <script> + description("Test linearRampToValue Updates the Param Value"); + window.jsTestIsAsync = true; + + var renderQuantumSize = 128; + // Should be a power of two to get rid of rounding errors when converting between time and + // frame. + var sampleRate = 4096; + var renderDuration = 1; + // End time of the linear ramp automation + var rampEndTime = renderDuration / 2; + + var audit = Audit.createTaskRunner(); + + // Test that linearRampToValue properly sets the AudioParam .value attribute when the + // linearRamp automation is running. + audit.defineTask("propagate", function (done) { + var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate); + + // Create a constant source. + var source = context.createBufferSource(); + source.buffer = createConstantBuffer(context, 1, 1); + source.loop = true; + + // The gain node to be automated for testing. + var gain = context.createGain(); + + gain.gain.setValueAtTime(0, 0); + gain.gain.linearRampToValueAtTime(1, rampEndTime); + + // Connect up the graph + source.connect(gain); + gain.connect(context.destination); + + var success = true; + + // The number of rendering quanta that will be processed in the context. At the beginning + // of each rendering quantum (except the first), we will check that gain.gain.value has the + // expected value. + var renderLoops = Math.floor(renderDuration * sampleRate / renderQuantumSize); + + for (var k = 1; k < renderLoops; ++k) { + var time = k * renderQuantumSize / sampleRate; + context.suspend(time).then(function () { + var expected = 1; + + if (context.currentTime <= rampEndTime) { + // The expected value of the gain is the last computed value from the previous + // rendering quantum because suspend() stops at the beginning of a rendering quantum, + // so we haven't computed the new value yet. + expected = (context.currentTime - 1 / sampleRate) / rampEndTime; + } + + var frame = context.currentTime * sampleRate - 1; + success = Should("gain.gain.value at frame " + frame, gain.gain.value) + .beEqualTo(expected) && success; + }).then(context.resume.bind(context)); + } + + // Rock and roll! + source.start(); + context.startRendering().then(function (result) { + if (success) + testPassed("linearRampToValue properly set the AudioParam value."); + else + testFailed("linearRampToValue did not properly set the AudioParam value."); + }).then(done); + }); + + audit.defineTask("finish", function (done) { + finishJSTest(); + done(); + }); + + audit.runTasks(); + </script> + </body> +</html>
diff --git a/third_party/WebKit/ManualTests/webaudio/audiobuffersource-looping.html b/third_party/WebKit/ManualTests/webaudio/audiobuffersource-looping.html deleted file mode 100644 index 0f2908a..0000000 --- a/third_party/WebKit/ManualTests/webaudio/audiobuffersource-looping.html +++ /dev/null
@@ -1,81 +0,0 @@ -<!doctype html> -<html> - <head> - <title>AudioBufferSource with Looping Enabled then Disabled</title> - <script> - var context = new AudioContext(); - // Launch countdown example - var url = "http://www.nasa.gov/mp3/590318main_ringtone_135_launch.mp3"; - - function enableButtons() - { - document.getElementById("Original").disabled = false; - document.getElementById("Test").disabled = false; - } - - function disableButtons() - { - document.getElementById("Original").disabled = true; - document.getElementById("Test").disabled = true; - } - - function playClip(loopEndTime) { - disableButtons(); - - var request = new XMLHttpRequest(); - request.open("GET", url, true); - request.responseType = "arraybuffer"; - request.onload = function () { - context.decodeAudioData( - request.response, - function (buffer) { - var source = context.createBufferSource(); - source.buffer = buffer; - source.connect(context.destination); - source.onended = enableButtons; - source.start(); - // If a loopEndTime is given, enable looping and stop looping after loopEndTime ms. - if (loopEndTime) { - // These limits were selected to cause the word "eight" to be repeated in the given - // URL. If the URL is updated these values probably need to be changed. - source.loopStart = 2.2; - source.loopEnd = 3; - source.loop = true; - - setTimeout(function () { - source.loop = false; - }, - loopEndTime); - } - }, - function () { - alert("Could not get audio clip"); - }); - }; - request.send(); - } - </script> - </head> - - <body> - <h1>AudioBufferSource with looping enabled then disabled</h1> - <p> - This tests an AudioBufferSource node is not prematurely stopped if looping is enabled for the - buffer and then disabled. This can't be tested in an offline context until suspend/resume - support is added for an offline context. - </p> - - <p>Press "Original" to play the clip in its entirety (15 sec).</p> - - <p> - Press "Test" to run the test. A part of the clip will be looped for a while and then looping - will be turned off. (You should hear "eight" repeated about four times.) The rest of the - clip should be heard in its entirety. The onended event should also be fired, enabling the - buttons again. If the buttons are not enabled, the test has failed. File a new bug at <a - href="http://crbug.com/new">crbug.com/new</a>. - </p> - - <button id="Original" onclick="playClip()">Original</button> - <button id="Test" onclick="playClip(5000)">Test</button> - </body> -</html>
diff --git a/third_party/WebKit/Source/bindings/templates/interface.cpp b/third_party/WebKit/Source/bindings/templates/interface.cpp index ba01c29..367bce74 100644 --- a/third_party/WebKit/Source/bindings/templates/interface.cpp +++ b/third_party/WebKit/Source/bindings/templates/interface.cpp
@@ -535,7 +535,8 @@ {# Report full list of valid arities if gaps and above minimum #} {% if constructor_overloads.valid_arities %} if (info.Length() >= {{constructor_overloads.length}}) { - throwArityTypeError(exceptionState, "{{constructor_overloads.valid_arities}}", info.Length()); + setArityTypeError(exceptionState, "{{constructor_overloads.valid_arities}}", info.Length()); + exceptionState.throwIfNeeded(); return; } {% endif %}
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor.cpp index 6240bcb5..7338a6b 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor.cpp
@@ -252,7 +252,8 @@ break; default: if (info.Length() >= 0) { - throwArityTypeError(exceptionState, "[0, 1, 2, 3, 7, 8, 9]", info.Length()); + setArityTypeError(exceptionState, "[0, 1, 2, 3, 7, 8, 9]", info.Length()); + exceptionState.throwIfNeeded(); return; } exceptionState.throwTypeError(ExceptionMessages::notEnoughArguments(0, info.Length()));
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp index 67f0f27..caeb6475 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp
@@ -68,8 +68,11 @@ void LayoutSVGBlock::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) { - if (diff.needsFullLayout()) + if (diff.needsFullLayout()) { setNeedsBoundariesUpdate(); + if (style()->hasTransform()) + setNeedsTransformUpdate(); + } if (isBlendingAllowed()) { bool hasBlendModeChanged = (oldStyle && oldStyle->hasBlendMode()) == !style()->hasBlendMode();
diff --git a/third_party/WebKit/Source/core/paint/LayerClipRecorder.cpp b/third_party/WebKit/Source/core/paint/LayerClipRecorder.cpp index 02d21e0..5bd6b53b 100644 --- a/third_party/WebKit/Source/core/paint/LayerClipRecorder.cpp +++ b/third_party/WebKit/Source/core/paint/LayerClipRecorder.cpp
@@ -61,7 +61,11 @@ if (layer->layoutObject()->hasOverflowClip() && layer->layoutObject()->style()->hasBorderRadius() && inContainingBlockChain(&paintLayer, layer)) { LayoutPoint delta(fragmentOffset); layer->convertToLayerCoords(localPaintingInfo.rootLayer, delta); - roundedRectClips.append(layer->layoutObject()->style()->getRoundedInnerBorderFor(LayoutRect(delta, LayoutSize(layer->size())))); + + // The PaintLayer's size is pixel-snapped if it is a LayoutBox. We can't use a pre-snapped border rect for clipping, since getRoundedInnerBorderFor assumes + // it has not been snapped yet. + LayoutSize size(layer->layoutBox() ? toLayoutBox(layer->layoutObject())->size() : LayoutSize(layer->size())); + roundedRectClips.append(layer->layoutObject()->style()->getRoundedInnerBorderFor(LayoutRect(delta, size))); } if (layer == localPaintingInfo.rootLayer)
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp index 4d63ab9d..dcf2d0b2 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -97,6 +97,13 @@ if (LayoutView* layoutView = frameView.layoutView()) walk(*layoutView, localContext); + + for (Frame* child = frameView.frame().tree().firstChild(); child; child = child->tree().nextSibling()) { + if (!child->isLocalFrame()) + continue; + if (FrameView* childView = toLocalFrame(child)->view()) + walk(*childView, localContext); + } } static void deriveBorderBoxFromContainerContext(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) @@ -328,8 +335,6 @@ object.clearObjectPaintProperties(); } - // TODO(trchen): Walk subframes for LayoutFrame. - for (LayoutObject* child = object.slowFirstChild(); child; child = child->nextSibling()) { if (child->isBoxModelObject() || child->isSVG()) walk(*child, localContext);
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp index 2fce3a6..b50cd69 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -20,7 +20,8 @@ class PaintPropertyTreeBuilderTest : public RenderingTest { public: PaintPropertyTreeBuilderTest() - : m_originalSlimmingPaintV2Enabled(RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { } + : RenderingTest(SingleChildFrameLoaderClient::create()) + , m_originalSlimmingPaintV2Enabled(RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { } void loadTestData(const char* fileName) { @@ -556,4 +557,23 @@ EXPECT_EQ(frameView->contentClip(), borderRadiusClip->parent()); } +TEST_F(PaintPropertyTreeBuilderTest, TransformNodesAcrossSubframes) +{ + setBodyInnerHTML( + "<style>body { margin: 0; }</style>" + "<div id='divWithTransform' style='transform: translate3d(1px, 2px, 3px);'>" + " <iframe id='frame' width='500' height='500'></iframe>" + "</div>"); + Document& frameDocument = setupChildIframe("frame", "<div id='transform' style='transform: translate3d(4px, 5px, 6px);'></div>"); + document().view()->updateAllLifecyclePhases(); + + LayoutObject& divWithTransform = *document().getElementById("divWithTransform")->layoutObject(); + ObjectPaintProperties* divWithTransformProperties = divWithTransform.objectPaintProperties(); + EXPECT_EQ(TransformationMatrix().translate3d(1, 2, 3), divWithTransformProperties->transform()->matrix()); + + LayoutObject* innerDivWithTransform = frameDocument.getElementById("transform")->layoutObject(); + ObjectPaintProperties* innerDivWithTransformProperties = innerDivWithTransform->objectPaintProperties(); + EXPECT_EQ(TransformationMatrix().translate3d(4, 5, 6), innerDivWithTransformProperties->transform()->matrix()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp index 98d539a5..0d890675 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp
@@ -42,6 +42,12 @@ Traits::addFrameViewProperties(frameView, *this); if (LayoutView* layoutView = frameView.layoutView()) collectPropertyNodes(*layoutView); + for (Frame* child = frameView.frame().tree().firstChild(); child; child = child->tree().nextSibling()) { + if (!child->isLocalFrame()) + continue; + if (FrameView* childView = toLocalFrame(child)->view()) + collectPropertyNodes(*childView); + } } void collectPropertyNodes(const LayoutObject& object) @@ -60,6 +66,7 @@ stringBuilder.append(' '); if (m_nodeToDebugString.contains(node)) stringBuilder.append(m_nodeToDebugString.get(node)); + stringBuilder.append(String::format(" %p", node)); Traits::printNodeAsString(node, stringBuilder); fprintf(stderr, "%s\n", stringBuilder.toString().ascii().data()); } @@ -100,8 +107,7 @@ static void printNodeAsString(const TransformPaintPropertyNode* node, StringBuilder& stringBuilder) { - stringBuilder.append(String::format(" %p ", node)); - stringBuilder.append("transform="); + stringBuilder.append(" transform="); TransformationMatrix::DecomposedType decomposition; if (!node->matrix().decompose(decomposition)) { @@ -137,14 +143,33 @@ static void printNodeAsString(const ClipPaintPropertyNode* node, StringBuilder& stringBuilder) { - stringBuilder.append(String::format(" %p ", node)); - stringBuilder.append(String::format("localTransformSpace=%p ", node->localTransformSpace())); + stringBuilder.append(String::format(" localTransformSpace=%p ", node->localTransformSpace())); stringBuilder.append(String::format("rect=%f,%f,%f,%f", node->clipRect().rect().x(), node->clipRect().rect().y(), node->clipRect().rect().width(), node->clipRect().rect().height())); } }; +template <> +class PropertyTreePrinterTraits<EffectPaintPropertyNode> { +public: + static void addFrameViewProperties(const FrameView& frameView, PropertyTreePrinter<EffectPaintPropertyNode>& printer) + { + // FrameView does not create any effect nodes. + } + + static void addObjectPaintProperties(const ObjectPaintProperties& paintProperties, PropertyTreePrinter<EffectPaintPropertyNode>& printer) + { + if (const EffectPaintPropertyNode* effect = paintProperties.effect()) + printer.addPropertyNode(effect, "Effect"); + } + + static void printNodeAsString(const EffectPaintPropertyNode* node, StringBuilder& stringBuilder) + { + stringBuilder.append(String::format(" opacity=%f", node->opacity())); + } +}; + } // anonymous namespace void showTransformPropertyTree(const FrameView& rootFrame) @@ -159,6 +184,12 @@ PropertyTreePrinter<ClipPaintPropertyNode>(rootFrame).show(); } +void showEffectPropertyTree(const FrameView& rootFrame) +{ + ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); + PropertyTreePrinter<EffectPaintPropertyNode>(rootFrame).show(); +} + } // namespace blink #endif
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h index 12504c03..148a928 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h
@@ -12,6 +12,7 @@ void showTransformPropertyTree(const FrameView& rootFrame); void showClipPropertyTree(const FrameView& rootFrame); +void showEffectPropertyTree(const FrameView& rootFrame); } // namespace blink #endif
diff --git a/third_party/WebKit/Source/core/svg/SVGPathElement.cpp b/third_party/WebKit/Source/core/svg/SVGPathElement.cpp index b21d54b..cd50481 100644 --- a/third_party/WebKit/Source/core/svg/SVGPathElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGPathElement.cpp
@@ -21,7 +21,6 @@ #include "core/svg/SVGPathElement.h" #include "core/layout/svg/LayoutSVGPath.h" -#include "core/svg/SVGDocumentExtensions.h" #include "core/svg/SVGMPathElement.h" #include "core/svg/SVGPathQuery.h" #include "core/svg/SVGPathUtilities.h" @@ -39,10 +38,8 @@ SVGParsingError setBaseValueAsString(const String& value) override { SVGParsingError parseStatus = SVGAnimatedNumber::setBaseValueAsString(value); - - ASSERT(contextElement()); if (parseStatus == NoError && baseValue()->value() < 0) - contextElement()->document().accessSVGExtensions().reportError("A negative value for path attribute <pathLength> is not allowed"); + parseStatus = NegativeValueForbiddenError; return parseStatus; }
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes index c32546c..65d4d715 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
@@ -2,7 +2,7 @@ "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28", "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45", "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485", - "toolbarButtonGlyphs.svg": "f1b787b943d8b2d46d8e7f74b0a86cd5", + "toolbarButtonGlyphs.svg": "ce97bd7f6480b622c021170cb91ea06c", "breakpoint.svg": "69cd92d807259c022791112809b97799", "responsiveDesign.svg": "1d6e963f88e5e448a7cff85f75a0e6b0" } \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes index c32546c..65d4d715 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
@@ -2,7 +2,7 @@ "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28", "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45", "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485", - "toolbarButtonGlyphs.svg": "f1b787b943d8b2d46d8e7f74b0a86cd5", + "toolbarButtonGlyphs.svg": "ce97bd7f6480b622c021170cb91ea06c", "breakpoint.svg": "69cd92d807259c022791112809b97799", "responsiveDesign.svg": "1d6e963f88e5e448a7cff85f75a0e6b0" } \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg index 36c48f90..8be902a 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
@@ -21,13 +21,13 @@ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><sodipodi:namedview showgrid="true" id="namedview3397" - inkscape:zoom="6.7102273" - inkscape:cx="176" - inkscape:cy="84.292174" - inkscape:window-width="2495" - inkscape:window-height="1576" - inkscape:window-x="65" - inkscape:window-y="24" + inkscape:zoom="18.979389" + inkscape:cx="179.57284" + inkscape:cy="146.96411" + inkscape:window-width="1920" + inkscape:window-height="1122" + inkscape:window-x="0" + inkscape:window-y="25" inkscape:window-maximized="1" inkscape:current-layer="svg3395" inkscape:snap-global="false" @@ -1017,40 +1017,6 @@ inkscape:connector-curvature="0" d="m 267,110 h -2 v 5 h 5 v -2 h -3 v -3 z m -2,-4 h 2 v -3 h 3 v -2 h -5 v 5 z m 12,7 h -3 v 2 h 5 v -5 h -2 v 3 z m -3,-12 v 2 h 3 v 3 h 2 v -5 h -5 z" id="path6-6" /><path - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.99999994;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - d="m 295,100 0,0.5 0,4.5 c 0,2.66667 4.44151,-1.67145 4.44151,0.99522 1.29167,0 -0.73318,7.00478 0.55849,7.00478 l 9,0 c 1.33333,0 -0.58161,-5.21491 0.75173,-5.21491 0,-2.16667 3.24827,1.38158 3.24827,-0.78509 l 0,-6.5 0,-0.5 -0.5,0 -17,0 z m 1,1 16,0 0,6 -2.76214,0.27122 L 309,112 l -9,0 -0.15511,-6.8501 L 296,105 z" - id="rect3641-2" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccccccccccccccccccccc" /><path - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - d="m 293,105 0,0.5 0,10 0,0.5 0.5,0 6,0 0.5,0 0,-0.5 0,-10 0,-0.5 -0.5,0 -6,0 z m 1,1 5,0 0,8 -5,0 z" - id="rect3641-2-5" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccccccccccccccccc" /><path - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.99999994;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - d="m 309,107 0,0.5 0,8 0,0.5 0.5,0 5,0 0.5,0 0,-0.5 0,-8 0,-0.5 -0.5,0 -5,0 z m 1,1 4,0 0,6 -4,0 z" - id="rect3641-2-2" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccccccccccccccccc" /><path - d="m 305,116 -2,0 0,-3 2,0 0,3 z" - id="path3517-0" - inkscape:connector-curvature="0" - style="opacity:0.2" /><rect - height="6" - width="1" - x="-116" - y="301" - id="rect3645-1" - transform="matrix(0,-1,1,0,0,0)" /><path - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - d="m 299,149 0,0.46875 0,13.0625 0,0.46875 0.4375,0 8.125,0 0.4375,0 0,-0.46875 0,-13.0625 0,-0.46875 -0.4375,0 -8.125,0 z m 1,2 7,0 0,9 -7,0 z m 2,10 3,0 0,1 -3,0 z" - id="rect3641-2-5-2" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccccccccccccccccccccc" /><path - style="opacity:0.2" - inkscape:connector-curvature="0" - id="path4070" - d="m 307.37415,162.12363 -7.84375,0 0,-11.625 7.84375,0 0,11.625 z" /><path style="fill:none" inkscape:connector-curvature="0" d="m 166,147 h 18 v 18 h -18 z" @@ -1097,4 +1063,22 @@ style="fill:none" inkscape:connector-curvature="0" d="m 231,75 h 18 v 18 h -18 z" - id="path4367" /></svg> \ No newline at end of file + id="path4367" /><path + style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" + d="m 300,100.99977 0,4.00012 0,1.00007 3.34345,0.53115 -0.0156,8.04683 L 302,114.99977 c 0.006,0.59278 0.43931,1.01145 1,1 l 8,0 c 0.57896,0.002 0.98177,-0.42708 1,-1 l 0,-14 c -0.0102,-0.53477 -0.48177,-0.99739 -1,-1 l -10,0 c -0.53297,0.008 -0.99716,0.45677 -1,1 z m 1,0 10,0 0,13.9995 -8,0 0.71845,-0.42179 0.0937,-8.4218 -2.8122,-0.1561 0,-0.99993 z" + id="rect3641-2-5-28" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccccccccccccccccc" /><path + style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" + d="m 297,105.99954 0,9 c 0.006,0.59278 0.43931,1.01145 1,1 l 5,0 c 0.57896,0.002 0.98177,-0.42708 1,-1 l 0,-9 c -0.0102,-0.53477 -0.48177,-0.99739 -1,-1 l -5,0 c -0.53297,0.008 -0.99716,0.45677 -1,1 z m 1,1.00023 5,0 0,7 -5,0 z" + id="rect3641-2-5-28-7" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccccccccc" /><path + style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" + d="m 299,150 0,12 c 0.006,0.62742 0.46004,1 1,1 l 7,0 c 0.51693,-5.4e-4 1,-0.46004 1,-1 l 0,-12 c 0,-0.54731 -0.43242,-1 -1,-1 l -7,0 c -0.54731,0 -1,0.42137 -1,1 z m 1,1 7,0 0,9 -7,0 z m 2,10 3,0 0,1 -3,0 z" + id="rect3641-2-5-2" + inkscape:connector-curvature="0" + sodipodi:nodetypes="sccccsssscccccccccc" /><path + inkscape:connector-curvature="0" + d="M 169,16.08946 V 19 h 2.91054 L 180.1944,10.71614 177.28385,7.8055997 169,16.08946 z m 13.76911,-7.9387003 c 0.30785,-0.30785 0.30785,-0.79294 0,-1.1007901 l -1.81908,-1.81909 c -0.30785,-0.3078399 -0.79295,-0.3078399 -1.10078,0 l -1.52058,1.52991 2.91054,2.9105401 1.5299,-1.52057 z" + id="path4" /></svg> \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png index 6802f4f..50cb528b 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png +++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png index 86604ad..6fc7237 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png +++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js index b53976d..a4855aa 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
@@ -67,6 +67,17 @@ WebInspector.CompilerScriptMapping.StubProjectID = "compiler-script-project"; +WebInspector.CompilerScriptMapping._originSymbol = Symbol("origin"); + +/** + * @param {!WebInspector.UISourceCode} uiSourceCode + * @return {?string} + */ +WebInspector.CompilerScriptMapping.uiSourceCodeOrigin = function(uiSourceCode) +{ + return uiSourceCode[WebInspector.CompilerScriptMapping._originSymbol] || null; +} + WebInspector.CompilerScriptMapping.prototype = { /** * @param {!WebInspector.DebuggerModel.Location} rawLocation @@ -200,11 +211,12 @@ if (this._sourceMapForURL.get(sourceURL)) continue; this._sourceMapForURL.set(sourceURL, sourceMap); - if (!this._networkMapping.hasMappingForURL(sourceURL) && !this._networkMapping.uiSourceCodeForScriptURL(sourceURL, script)) { - var contentProvider = sourceMap.sourceContentProvider(sourceURL, WebInspector.resourceTypes.SourceMapScript); - this._networkProject.addFileForURL(sourceURL, contentProvider, WebInspector.ResourceTreeFrame.fromScript(script), script.isContentScript()); - } var uiSourceCode = this._networkMapping.uiSourceCodeForScriptURL(sourceURL, script); + if (!uiSourceCode && !this._networkMapping.hasMappingForURL(sourceURL)) { + var contentProvider = sourceMap.sourceContentProvider(sourceURL, WebInspector.resourceTypes.SourceMapScript); + uiSourceCode = this._networkProject.addFileForURL(sourceURL, contentProvider, WebInspector.ResourceTreeFrame.fromScript(script), script.isContentScript()); + uiSourceCode[WebInspector.CompilerScriptMapping._originSymbol] = script.sourceURL; + } if (uiSourceCode) { this._bindUISourceCode(uiSourceCode); } else {
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js index b8262b2..709b6f7 100644 --- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js +++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
@@ -5,9 +5,8 @@ /** * @constructor * @extends {WebInspector.VBox} - * @param {function()} pageResizeCallback */ -WebInspector.DeviceModeView = function(pageResizeCallback) +WebInspector.DeviceModeView = function() { WebInspector.VBox.call(this, true); this.setMinimumSize(150, 150); @@ -20,8 +19,13 @@ // TODO(dgozman): remove CountUpdated event. this._showMediaInspectorSetting = WebInspector.settings.createSetting("showMediaQueryInspector", false); this._showMediaInspectorSetting.addChangeListener(this._updateUI, this); + this._showRulersSetting = WebInspector.settings.createSetting("emulation.showRulers", false); + this._showRulersSetting.addChangeListener(this._updateUI, this); - this._pageResizeCallback = pageResizeCallback; + this._topRuler = new WebInspector.DeviceModeView.Ruler(true, this._model.widthSetting().set.bind(this._model.widthSetting())); + this._topRuler.element.classList.add("device-mode-ruler-top"); + this._leftRuler = new WebInspector.DeviceModeView.Ruler(false, this._model.heightSetting().set.bind(this._model.heightSetting())); + this._leftRuler.element.classList.add("device-mode-ruler-left"); this._createUI(); WebInspector.zoomManager.addEventListener(WebInspector.ZoomManager.Events.ZoomChanged, this._updateUI, this); }; @@ -29,13 +33,12 @@ WebInspector.DeviceModeView.prototype = { _createUI: function() { - this._toolbar = new WebInspector.DeviceModeView.Toolbar(this._model, this._showMediaInspectorSetting); + this._toolbar = new WebInspector.DeviceModeView.Toolbar(this._model, this._showMediaInspectorSetting, this._showRulersSetting); this.contentElement.appendChild(this._toolbar.element()); - var contentClip = this.contentElement.createChild("div", "device-mode-content-clip vbox"); - this._mediaInspectorContainer = contentClip.createChild("div", "device-mode-media-container"); - this._contentArea = contentClip.createChild("div", "device-mode-content-area"); - + this._contentClip = this.contentElement.createChild("div", "device-mode-content-clip vbox"); + this._mediaInspectorContainer = this._contentClip.createChild("div", "device-mode-media-container"); + this._contentArea = this._contentClip.createChild("div", "device-mode-content-area"); this._deviceBlueprints = this._contentArea.createChild("div", "fill"); WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevicesList.Events.StandardDevicesUpdated, this._updateBlueprints, this); @@ -153,8 +156,10 @@ return; var zoomFactor = WebInspector.zoomManager.zoomFactor(); - var resizePagePlaceholder = false; - var resizeSelf = false; + var callDoResize = false; + var showRulers = this._showRulersSetting.get() && this._model.type() !== WebInspector.DeviceModeModel.Type.None; + var contentAreaResized = false; + var updateRulers = false; if (this._cachedModelType !== this._model.type() || this._cachedModelScale !== this._model.scale()) { this._updateBlueprints(); @@ -168,7 +173,9 @@ this._screenArea.style.top = cssScreenRect.top + "px"; this._screenArea.style.width = cssScreenRect.width + "px"; this._screenArea.style.height = cssScreenRect.height + "px"; - resizePagePlaceholder = true; + this._leftRuler.element.style.left = cssScreenRect.left + "px"; + updateRulers = true; + callDoResize = true; this._cachedCssScreenRect = cssScreenRect; } @@ -178,7 +185,7 @@ this._pageArea.style.top = cssVisiblePageRect.top + "px"; this._pageArea.style.width = cssVisiblePageRect.width + "px"; this._pageArea.style.height = cssVisiblePageRect.height + "px"; - resizePagePlaceholder = true; + callDoResize = true; this._cachedCssVisiblePageRect = cssVisiblePageRect; } @@ -196,18 +203,40 @@ this._mediaInspector.show(this._mediaInspectorContainer); else this._mediaInspector.detach(); - resizePagePlaceholder = true; - resizeSelf = true; + contentAreaResized = true; + callDoResize = true; this._cachedMediaInspectorVisible = mediaInspectorVisible; } + if (showRulers !== this._cachedShowRulers) { + this._contentArea.classList.toggle("device-mode-rulers-visible", showRulers); + if (showRulers) { + this._topRuler.show(this._contentClip, this._contentArea); + this._leftRuler.show(this._contentArea); + } else { + this._topRuler.detach(); + this._leftRuler.detach(); + } + callDoResize = true; + this._cachedShowRulers = showRulers; + } + + if (this._model.scale() !== this._cachedScale) { + updateRulers = true; + this._cachedScale = this._model.scale(); + } + this._toolbar.update(); this._loadScreenImage(this._model.screenImage()); - if (resizePagePlaceholder) - this._pageResizeCallback.call(null); this._mediaInspector.setAxisTransform(-cssScreenRect.left * zoomFactor / this._model.scale(), this._model.scale()); - if (resizeSelf) - this.onResize(); + if (callDoResize) + this.doResize(); + if (updateRulers) { + this._topRuler.render(this._cachedCssScreenRect ? this._cachedCssScreenRect.left : 0, this._model.scale()); + this._leftRuler.render(0, this._model.scale()); + } + if (contentAreaResized) + this._contentAreaResized(); }, _updateBlueprints: function() @@ -225,8 +254,10 @@ var blueprint = blueprintContainer.createChild("div", "device-mode-blueprint"); blueprint.style.width = device.vertical.width * scale + "px"; blueprint.style.height = device.vertical.height * scale + "px"; - blueprint.createChild("span").textContent = device.title; - blueprint.addEventListener("dblclick", this._resizeTo.bind(this, device.vertical.width, device.vertical.height), false); + var clickable = blueprint.createChild("div", "device-mode-blueprint-border"); + clickable.createChild("span").textContent = device.title; + clickable.addEventListener("dblclick", this._resizeTo.bind(this, device.vertical.width, device.vertical.height), false); + blueprint.createChild("div", "device-mode-blueprint-inside"); } }, @@ -250,17 +281,20 @@ this._screenImage.classList.toggle("hidden", !success); }, + _contentAreaResized: function() + { + var zoomFactor = WebInspector.zoomManager.zoomFactor(); + var rect = this._contentArea.getBoundingClientRect(); + this._model.setAvailableSize(new Size(Math.max(rect.width * zoomFactor, 1), Math.max(rect.height * zoomFactor, 1))); + }, + /** * @override */ onResize: function() { - if (!this.isShowing()) - return; - - var zoomFactor = WebInspector.zoomManager.zoomFactor(); - var rect = this._contentArea.getBoundingClientRect(); - this._model.setAvailableSize(new Size(Math.max(rect.width * zoomFactor, 1), Math.max(rect.height * zoomFactor, 1))); + if (this.isShowing()) + this._contentAreaResized(); }, /** @@ -286,17 +320,19 @@ /** * @param {!WebInspector.DeviceModeModel} model * @param {!WebInspector.Setting} showMediaInspectorSetting + * @param {!WebInspector.Setting} showRulersSetting * @constructor */ -WebInspector.DeviceModeView.Toolbar = function(model, showMediaInspectorSetting) +WebInspector.DeviceModeView.Toolbar = function(model, showMediaInspectorSetting, showRulersSetting) { this._model = model; this._showMediaInspectorSetting = showMediaInspectorSetting; + this._showRulersSetting = showRulersSetting; /** @type {!Map<!WebInspector.EmulatedDevice, !WebInspector.EmulatedDevice.Mode>} */ this._lastMode = new Map(); /** @type {?WebInspector.EmulatedDevice} */ this._lastDevice = null; - /** @type {!Array<!WebInspector.ToolbarTextGlyphItem>} */ + /** @type {!Array<!WebInspector.ToolbarLabel>} */ this._appliedSizeItems = []; /** @type {?Element} */ this._visibleToolbar = null; @@ -417,7 +453,7 @@ */ _appendAppliedSizeItems: function(toolbar) { - var item = new WebInspector.ToolbarTextGlyphItem(); + var item = new WebInspector.ToolbarLabel(); this._appliedSizeItems.push(item); toolbar.appendToolbarItem(item); }, @@ -489,6 +525,7 @@ contextMenu.appendSeparator(); contextMenu.appendCheckboxItem(WebInspector.UIString("Show media queries"), this._toggleMediaInspector.bind(this), this._showMediaInspectorSetting.get(), this._model.type() === WebInspector.DeviceModeModel.Type.None); + contextMenu.appendCheckboxItem(WebInspector.UIString("Show rulers"), this._toggleRulers.bind(this), this._showRulersSetting.get(), this._model.type() === WebInspector.DeviceModeModel.Type.None); contextMenu.appendItem(WebInspector.UIString("Configure network\u2026"), this._openNetworkConfig.bind(this), false); }, @@ -497,6 +534,11 @@ this._showMediaInspectorSetting.set(!this._showMediaInspectorSetting.get()); }, + _toggleRulers: function() + { + this._showRulersSetting.set(!this._showRulersSetting.get()); + }, + _openNetworkConfig: function() { InspectorFrontendHost.bringToFront(); @@ -832,6 +874,115 @@ /** * @constructor + * @extends {WebInspector.VBox} + * @param {boolean} horizontal + * @param {function(number)} applyCallback + */ +WebInspector.DeviceModeView.Ruler = function(horizontal, applyCallback) +{ + WebInspector.VBox.call(this); + this._contentElement = this.element.createChild("div", "device-mode-ruler flex-auto"); + this._horizontal = horizontal; + this._scale = 1; + this._offset = 0; + this._count = 0; + this._throttler = new WebInspector.Throttler(0); + this._applyCallback = applyCallback; +} + +WebInspector.DeviceModeView.Ruler.prototype = { + /** + * @param {number} offset + * @param {number} scale + */ + render: function(offset, scale) + { + this._scale = scale; + this._offset = offset; + if (this._horizontal) + this.element.style.paddingLeft = this._offset + "px"; + else + this.element.style.paddingTop = this._offset + "px"; + this._throttler.schedule(this._update.bind(this)); + }, + + /** + * @override + */ + onResize: function() + { + this._throttler.schedule(this._update.bind(this)); + }, + + /** + * @return {!Promise.<?>} + */ + _update: function() + { + var zoomFactor = WebInspector.zoomManager.zoomFactor(); + var size = this._horizontal ? this._contentElement.offsetWidth : this._contentElement.offsetHeight; + + if (this._scale !== this._renderedScale || zoomFactor !== this._renderedZoomFactor) { + this._contentElement.removeChildren(); + this._count = 0; + this._renderedScale = this._scale; + this._renderedZoomFactor = zoomFactor; + } + + var dipSize = size * zoomFactor / this._scale; + var count = Math.ceil(dipSize / 5); + var step = 1; + if (this._scale < 0.8) + step = 2; + if (this._scale < 0.6) + step = 5; + if (this._scale < 0.5) + step = 20; + + for (var i = count; i < this._count; i++) { + if (!(i % step)) + this._contentElement.lastChild.remove(); + } + + for (var i = this._count; i < count; i++) { + if (i % step) + continue; + var marker = this._contentElement.createChild("div", "device-mode-ruler-marker"); + if (i) { + if (this._horizontal) + marker.style.left = (5 * i) * this._scale / zoomFactor + "px"; + else + marker.style.top = (5 * i) * this._scale / zoomFactor + "px"; + if (!(i % 20)) { + var text = marker.createChild("div", "device-mode-ruler-text"); + text.textContent = i * 5; + text.addEventListener("click", this._onMarkerClick.bind(this, i * 5), false); + } + } + if (!(i % 10)) + marker.classList.add("device-mode-ruler-marker-large"); + else if (!(i % 5)) + marker.classList.add("device-mode-ruler-marker-medium"); + } + + this._count = count; + return Promise.resolve(); + }, + + /** + * @param {number} size + */ + _onMarkerClick: function(size) + { + this._applyCallback.call(null, size); + }, + + __proto__: WebInspector.VBox.prototype +} + + +/** + * @constructor * @implements {WebInspector.ActionDelegate} */ WebInspector.DeviceModeView.ActionDelegate = function() @@ -870,7 +1021,7 @@ WebInspector.VBox.call(this); WebInspector.DeviceModeView._wrapperInstance = this; this._inspectedPagePlaceholder = inspectedPagePlaceholder; - this._deviceModeView = new WebInspector.DeviceModeView(this._resizePlaceholder.bind(this)); + this._deviceModeView = new WebInspector.DeviceModeView(); this._showDeviceToolbarSetting = WebInspector.settings.createSetting("emulation.showDeviceToolbar", true); this._showDeviceToolbarSetting.addChangeListener(this._update, this); this._update(); @@ -905,11 +1056,5 @@ } }, - _resizePlaceholder: function() - { - if (this._showDeviceToolbarSetting.get()) - this._inspectedPagePlaceholder.onResize(); - }, - __proto__: WebInspector.VBox.prototype }
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js b/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js index 50786b4..e103e2d 100644 --- a/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js +++ b/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js
@@ -262,7 +262,6 @@ return; var oldChildrenCount = this.contentElement.children.length; - var scrollTop = this.contentElement.scrollTop; this.contentElement.removeChildren(); var container = null; @@ -276,7 +275,6 @@ bar.classList.toggle("media-inspector-marker-inactive", !marker.active); container.appendChild(bar); } - this.contentElement.scrollTop = scrollTop; }, /**
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css index ed853301..57bb35c 100644 --- a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css +++ b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
@@ -161,29 +161,121 @@ } .device-mode-blueprint { - display: flex; - border-left: 1px dashed #dcdcdc; - border-right: 1px dashed #dcdcdc; - border-bottom: 1px dashed #dcdcdc; flex-direction: column; justify-content: flex-end; - text-align: end; - color: #aaa; - pointer-events: initial; flex: none; + position: relative; + pointer-events: auto; } -.device-mode-blueprint:hover { +.device-mode-blueprint-border { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + display: flex; + align-items: flex-end; + justify-content: flex-end; + color: #aaa; + border: 1px solid #dcdcdc; + margin-top: -1px; +} + +.device-mode-blueprint-border:hover { border-color: #aaa; } -.device-mode-blueprint > span { +.device-mode-blueprint-border > span { transition: opacity 150ms; opacity: 0; padding: 3px; } -.device-mode-blueprint:hover > span { +.device-mode-blueprint-border:hover > span { opacity: 1; - display: initial; +} + +.device-mode-blueprint-inside { + position: absolute; + left: 20px; + right: 20px; + top: 20px; + bottom: 20px; +} + +.device-mode-ruler { + pointer-events: none; + position: relative; +} + +.device-mode-ruler-top { + flex: 0 0 20px; +} + +.device-mode-ruler-left { + position: absolute; + left: 0; + width: 20px; + top: 0; + bottom: 0; + transform: translateX(-20px); +} + +.device-mode-ruler-marker { + position: absolute; +} + +.device-mode-ruler-top .device-mode-ruler-marker { + width: 0; + height: 5px; + bottom: 0; + border-right: 1px solid hsl(0, 0%, 50%); + margin-right: -1px; +} + +.device-mode-ruler-top .device-mode-ruler-marker.device-mode-ruler-marker-medium { + height: 10px; +} + +.device-mode-ruler-top .device-mode-ruler-marker.device-mode-ruler-marker-large { + height: 15px; +} + +.device-mode-ruler-left .device-mode-ruler-marker { + height: 0; + width: 5px; + right: 0; + border-bottom: 1px solid hsl(0, 0%, 50%); + margin-bottom: -1px; +} + +.device-mode-ruler-left .device-mode-ruler-marker.device-mode-ruler-marker-medium { + width: 10px; +} + +.device-mode-ruler-left .device-mode-ruler-marker.device-mode-ruler-marker-large { + width: 15px; +} + +.device-mode-ruler-text { + font-size: 11px; + color: hsl(0, 0%, 50%); + position: relative; + pointer-events: auto; +} + +.device-mode-ruler-text:hover { + color: hsl(0, 0%, 10%); +} + +.device-mode-ruler-top .device-mode-ruler-text { + left: 2px; + top: -2px; +} + +.device-mode-ruler-left .device-mode-ruler-text { + left: -4px; + top: -15px; + transform: rotate(270deg); }
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js index 6a044a4..f7154c51 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js +++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js
@@ -81,7 +81,7 @@ _customUserAgentChanged: function() { - if (!this._customUserAgent.checked) + if (!this._customUserAgentRadio.checked) return; WebInspector.multitargetNetworkManager.setCustomUserAgentOverride(this._customUserAgentSetting.get()); },
diff --git a/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js b/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js index 47395a1b..cb3e8be 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js +++ b/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js
@@ -55,9 +55,15 @@ delete this._emptyWidget; } - if (!this._previewView) + if (!this._previewView) { this._previewView = this._createPreviewView(); - this._previewView.show(this.element); + this._previewView.show(this.element); + if (this._previewView instanceof WebInspector.VBoxWithToolbarItems) { + var toolbar = new WebInspector.Toolbar("network-item-preview-toolbar", this.element); + for (var item of /** @type {!WebInspector.VBoxWithToolbarItems} */ (this._previewView).toolbarItems()) + toolbar.appendToolbarItem(item); + } + } this.innerView = this._previewView; } },
diff --git a/third_party/WebKit/Source/devtools/front_end/network/networkLogView.css b/third_party/WebKit/Source/devtools/front_end/network/networkLogView.css index a56ca7b..38b3deb 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/networkLogView.css +++ b/third_party/WebKit/Source/devtools/front_end/network/networkLogView.css
@@ -34,20 +34,25 @@ } .network-summary-bar { - flex: 0 0 19px; + flex: 0 0 27px; padding-left: 5px; - line-height: 18px; background-color: #eee; border-top: 1px solid #ccc; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; + display: flex; + align-items: center; } .network-summary-bar label[is=dt-icon-label] { margin-right: 6px; } +.network-summary-bar > * { + flex: none; +} + .network-log-grid.data-grid table.data { background: transparent; }
diff --git a/third_party/WebKit/Source/devtools/front_end/network/networkPanel.css b/third_party/WebKit/Source/devtools/front_end/network/networkPanel.css index 82cdd865..6d73e6b6 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/networkPanel.css +++ b/third_party/WebKit/Source/devtools/front_end/network/networkPanel.css
@@ -49,6 +49,11 @@ background: white; } +.network-item-preview-toolbar { + border-top: 1px solid #ccc; + background-color: #eee; +} + .resource-timing-view { display: block; margin: 6px;
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js index bf898c3c..7b562574 100644 --- a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js +++ b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
@@ -149,7 +149,7 @@ this._constructorsDataGrid.setNameFilter(this._classNameFilter); this._diffDataGrid.setNameFilter(this._classNameFilter); - this._selectedSizeText = new WebInspector.ToolbarTextGlyphItem(); + this._selectedSizeText = new WebInspector.ToolbarLabel(); this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.element, this._getHoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), undefined, true);
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js b/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js index 18eb2dec..07d34fe 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js
@@ -28,18 +28,19 @@ /** * @constructor - * @extends {WebInspector.VBox} + * @extends {WebInspector.VBoxWithToolbarItems} * @param {string} mimeType * @param {!WebInspector.ContentProvider} contentProvider */ WebInspector.FontView = function(mimeType, contentProvider) { - WebInspector.VBox.call(this); + WebInspector.VBoxWithToolbarItems.call(this); this.registerRequiredCSS("source_frame/fontView.css"); this.element.classList.add("font-view"); this._url = contentProvider.contentURL(); this._mimeType = mimeType; this._contentProvider = contentProvider; + this._mimeTypeLabel = new WebInspector.ToolbarLabel(mimeType); } WebInspector.FontView._fontPreviewLines = [ "ABCDEFGHIJKLM", "NOPQRSTUVWXYZ", "abcdefghijklm", "nopqrstuvwxyz", "1234567890" ]; @@ -50,6 +51,15 @@ WebInspector.FontView.prototype = { /** + * @override + * @return {!Array<!WebInspector.ToolbarItem>} + */ + toolbarItems: function() + { + return [this._mimeTypeLabel]; + }, + + /** * @param {string} uniqueFontName * @param {?string} content */ @@ -147,5 +157,5 @@ this.fontPreviewElement.style.setProperty("font-size", finalFontSize + "px", null); }, - __proto__: WebInspector.VBox.prototype + __proto__: WebInspector.VBoxWithToolbarItems.prototype }
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js b/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js index 9687d88d..04542bc1 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js
@@ -27,23 +27,35 @@ */ /** - * @extends {WebInspector.VBox} + * @extends {WebInspector.VBoxWithToolbarItems} * @constructor * @param {string} mimeType * @param {!WebInspector.ContentProvider} contentProvider */ WebInspector.ImageView = function(mimeType, contentProvider) { - WebInspector.VBox.call(this); + WebInspector.VBoxWithToolbarItems.call(this); this.registerRequiredCSS("source_frame/imageView.css"); this.element.classList.add("image-view"); this._url = contentProvider.contentURL(); this._parsedURL = new WebInspector.ParsedURL(this._url); this._mimeType = mimeType; this._contentProvider = contentProvider; + this._sizeLabel = new WebInspector.ToolbarLabel(); + this._dimensionsLabel = new WebInspector.ToolbarLabel(); + this._mimeTypeLabel = new WebInspector.ToolbarLabel(mimeType); } WebInspector.ImageView.prototype = { + /** + * @override + * @return {!Array<!WebInspector.ToolbarItem>} + */ + toolbarItems: function() + { + return [this._sizeLabel, new WebInspector.ToolbarSeparator(), this._dimensionsLabel, new WebInspector.ToolbarSeparator(), this._mimeTypeLabel]; + }, + wasShown: function() { this._createContentIfNeeded(); @@ -54,16 +66,11 @@ if (this._container) return; - var imageContainer = this.element.createChild("div", "image"); - var imagePreviewElement = imageContainer.createChild("img", "resource-image-view"); + this._container = this.element.createChild("div", "image"); + var imagePreviewElement = this._container.createChild("img", "resource-image-view"); imagePreviewElement.addEventListener("contextmenu", this._contextMenu.bind(this), true); - - this._container = this.element.createChild("div", "info"); - this._container.createChild("h1", "title").textContent = this._parsedURL.displayName; - - var infoListElement = createElementWithClass("dl", "infoList"); - WebInspector.Resource.populateImageSource(this._url, this._mimeType, this._contentProvider, imagePreviewElement); + this._contentProvider.requestContent(onContentAvailable.bind(this)); /** @@ -72,22 +79,8 @@ */ function onContentAvailable(content) { - var resourceSize = this._base64ToSize(content); - - var imageProperties = [ - { name: WebInspector.UIString("Dimensions"), value: WebInspector.UIString("%d × %d", imagePreviewElement.naturalWidth, imagePreviewElement.naturalHeight) }, - { name: WebInspector.UIString("File size"), value: Number.bytesToString(resourceSize) }, - { name: WebInspector.UIString("MIME type"), value: this._mimeType } - ]; - - infoListElement.removeChildren(); - for (var i = 0; i < imageProperties.length; ++i) { - infoListElement.createChild("dt").textContent = imageProperties[i].name; - infoListElement.createChild("dd").textContent = imageProperties[i].value; - } - infoListElement.createChild("dt").textContent = WebInspector.UIString("URL"); - infoListElement.createChild("dd").appendChild(WebInspector.linkifyURLAsNode(this._url, undefined, undefined, true)); - this._container.appendChild(infoListElement); + this._sizeLabel.setText(Number.bytesToString(this._base64ToSize(content))); + this._dimensionsLabel.setText(WebInspector.UIString("%d × %d", imagePreviewElement.naturalWidth, imagePreviewElement.naturalHeight)); } this._imagePreviewElement = imagePreviewElement; }, @@ -133,5 +126,5 @@ InspectorFrontendHost.openInNewTab(this._url); }, - __proto__: WebInspector.VBox.prototype + __proto__: WebInspector.VBoxWithToolbarItems.prototype }
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js b/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js index d2237101..23dde482 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js
@@ -29,14 +29,14 @@ */ /** - * @extends {WebInspector.VBox} + * @extends {WebInspector.VBoxWithToolbarItems} * @constructor * @implements {WebInspector.Replaceable} * @param {!WebInspector.ContentProvider} contentProvider */ WebInspector.SourceFrame = function(contentProvider) { - WebInspector.VBox.call(this); + WebInspector.VBoxWithToolbarItems.call(this); this._url = contentProvider.contentURL(); this._contentProvider = contentProvider; @@ -53,7 +53,7 @@ this._shortcuts = {}; this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false); - this._sourcePosition = new WebInspector.ToolbarTextGlyphItem(); + this._sourcePosition = new WebInspector.ToolbarLabel(); } WebInspector.SourceFrame.Events = { @@ -96,11 +96,12 @@ }, /** - * @return {!WebInspector.ToolbarItem} + * @override + * @return {!Array<!WebInspector.ToolbarItem>} */ - toolbarText: function() + toolbarItems: function() { - return this._sourcePosition; + return [this._sourcePosition]; }, /** @@ -602,7 +603,7 @@ e.consume(true); }, - __proto__: WebInspector.VBox.prototype + __proto__: WebInspector.VBoxWithToolbarItems.prototype } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/imageView.css b/third_party/WebKit/Source/devtools/front_end/source_frame/imageView.css index ab7f386..e2be192 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/imageView.css +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/imageView.css
@@ -4,25 +4,11 @@ * found in the LICENSE file. */ -.image-view { - overflow: auto; -} - -.image-view > * { - flex: none; -} - .image-view > .image { padding: 20px 20px 10px 20px; text-align: center; } -.image-view > .info { - padding-bottom: 10px; - font-size: 11px; - -webkit-user-select: text; -} - .image-view img.resource-image-view { max-width: 100%; max-height: 1000px; @@ -31,33 +17,3 @@ -webkit-user-select: text; -webkit-user-drag: auto; } - -.image-view .title { - text-align: center; - font-size: 13px; -} - -.image-view .infoList { - margin: 0; -} - -.image-view .infoList dt { - font-weight: bold; - display: inline-block; - width: 50%; - text-align: right; - color: rgb(76, 76, 76); -} - -.image-view .infoList dd { - display: inline-block; - padding-left: 8px; - width: 50%; - text-align: left; - margin: 0; -} - -.image-view .infoList dd::after { - white-space: pre; - content: "\A"; -}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js index c53cd03..959448a3 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -38,7 +38,6 @@ { this._scriptsPanel = scriptsPanel; this._breakpointManager = WebInspector.breakpointManager; - this._uiSourceCode = uiSourceCode; WebInspector.UISourceCodeFrame.call(this, uiSourceCode); if (uiSourceCode.project().type() === WebInspector.projectTypes.Debugger) @@ -55,10 +54,10 @@ this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointAdded, this._breakpointAdded, this); this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointRemoved, this._breakpointRemoved, this); - this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._onSourceMappingChanged, this); - this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this); - this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this); - this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._showBlackboxInfobarIfNeeded, this); + this.uiSourceCode().addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._onSourceMappingChanged, this); + this.uiSourceCode().addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this); + this.uiSourceCode().addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this); + this.uiSourceCode().addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._showBlackboxInfobarIfNeeded, this); /** @type {!Map.<!WebInspector.Target, !WebInspector.ResourceScriptFile>}*/ this._scriptFileForTarget = new Map(); @@ -81,6 +80,22 @@ } WebInspector.JavaScriptSourceFrame.prototype = { + /** + * @override + * @return {!Array<!WebInspector.ToolbarItem>} + */ + toolbarItems: function() + { + var result = WebInspector.UISourceCodeFrame.prototype.toolbarItems.call(this); + var originURL = WebInspector.CompilerScriptMapping.uiSourceCodeOrigin(this.uiSourceCode()); + if (originURL) { + var parsedURL = originURL.asParsedURL(); + if (parsedURL) + result.push(new WebInspector.ToolbarLabel(WebInspector.UIString("(source mapped from %s)", parsedURL.displayName))); + } + return result; + }, + _updateInfobars: function() { this.attachInfobars([this._blackboxInfobar, this._divergedInfobar]); @@ -88,7 +103,7 @@ _showDivergedInfobar: function() { - if (!this._uiSourceCode.contentType().isScript()) + if (!this.uiSourceCode().contentType().isScript()) return; if (this._divergedInfobar) @@ -97,11 +112,11 @@ var infobar = new WebInspector.UISourceCodeFrame.Infobar(WebInspector.Infobar.Type.Warning, WebInspector.UIString("Workspace mapping mismatch")); this._divergedInfobar = infobar; - var fileURL = this._uiSourceCode.originURL(); + var fileURL = this.uiSourceCode().originURL(); infobar.createDetailsRowMessage(WebInspector.UIString("The content of this file on the file system:\u00a0")).appendChild( WebInspector.linkifyURLAsNode(fileURL, fileURL, "source-frame-infobar-details-url", true)); - var scriptURL = WebInspector.networkMapping.networkURL(this._uiSourceCode); + var scriptURL = WebInspector.networkMapping.networkURL(this.uiSourceCode()); infobar.createDetailsRowMessage(WebInspector.UIString("does not match the loaded script:\u00a0")).appendChild( WebInspector.linkifyURLAsNode(scriptURL, scriptURL, "source-frame-infobar-details-url", true)); @@ -127,13 +142,13 @@ _showBlackboxInfobarIfNeeded: function() { - if (!this._uiSourceCode.contentType().hasScripts()) + if (!this.uiSourceCode().contentType().hasScripts()) return; - var projectType = this._uiSourceCode.project().type(); + var projectType = this.uiSourceCode().project().type(); if (projectType === WebInspector.projectTypes.Snippets) return; - var networkURL = WebInspector.networkMapping.networkURL(this._uiSourceCode); - var url = projectType === WebInspector.projectTypes.Formatter ? this._uiSourceCode.originURL() : networkURL; + var networkURL = WebInspector.networkMapping.networkURL(this.uiSourceCode()); + var url = projectType === WebInspector.projectTypes.Formatter ? this.uiSourceCode().originURL() : networkURL; var isContentScript = projectType === WebInspector.projectTypes.ContentScripts; if (!WebInspector.BlackboxSupport.isBlackboxed(url, isContentScript)) { this._hideBlackboxInfobar(); @@ -269,9 +284,9 @@ */ function populate(resolve, reject) { - var uiLocation = new WebInspector.UILocation(this._uiSourceCode, lineNumber, 0); + var uiLocation = new WebInspector.UILocation(this.uiSourceCode(), lineNumber, 0); this._scriptsPanel.appendUILocationItems(contextMenu, uiLocation); - var breakpoint = this._breakpointManager.findBreakpointOnLine(this._uiSourceCode, lineNumber); + var breakpoint = this._breakpointManager.findBreakpointOnLine(this.uiSourceCode(), lineNumber); if (!breakpoint) { // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint. contextMenu.appendItem(WebInspector.UIString.capitalize("Add ^breakpoint"), this._createNewBreakpoint.bind(this, lineNumber, 0, "", true)); @@ -330,7 +345,7 @@ */ function populateSourceMapMembers() { - if (this._uiSourceCode.project().type() === WebInspector.projectTypes.Network && WebInspector.moduleSetting("jsSourceMapsEnabled").get()) { + if (this.uiSourceCode().project().type() === WebInspector.projectTypes.Network && WebInspector.moduleSetting("jsSourceMapsEnabled").get()) { if (this._scriptFileForTarget.size) { var scriptFile = this._scriptFileForTarget.valuesArray()[0]; var addSourceMapURLLabel = WebInspector.UIString.capitalize("Add ^source ^map\u2026"); @@ -348,7 +363,7 @@ if (this._supportsEnabledBreakpointsWhileEditing() || this._scriptFileForTarget.size) return; - if (this._uiSourceCode.isDirty()) + if (this.uiSourceCode().isDirty()) this._muteBreakpointsWhileEditing(); else this._restoreBreakpointsAfterEditing(); @@ -401,7 +416,7 @@ _updateDivergedInfobar: function() { - if (this._uiSourceCode.project().type() !== WebInspector.projectTypes.FileSystem) { + if (this.uiSourceCode().project().type() !== WebInspector.projectTypes.FileSystem) { this._hideDivergedInfobar(); return; } @@ -415,14 +430,14 @@ if (!hasDivergedScript) this._hideDivergedInfobar(); } else { - if (hasDivergedScript && !this._uiSourceCode.isDirty()) + if (hasDivergedScript && !this.uiSourceCode().isDirty()) this._showDivergedInfobar(); } }, _supportsEnabledBreakpointsWhileEditing: function() { - return this._uiSourceCode.project().type() === WebInspector.projectTypes.Snippets; + return this.uiSourceCode().project().type() === WebInspector.projectTypes.Snippets; }, _restoreBreakpointsIfConsistentScripts: function() @@ -463,7 +478,7 @@ _removeAllBreakpoints: function() { - var breakpoints = this._breakpointManager.breakpointsForUISourceCode(this._uiSourceCode); + var breakpoints = this._breakpointManager.breakpointsForUISourceCode(this.uiSourceCode()); for (var i = 0; i < breakpoints.length; ++i) breakpoints[i].remove(); }, @@ -724,7 +739,7 @@ var functionUILocation = WebInspector.debuggerWorkspaceBinding.rawLocationToUILocation(/**@type {!WebInspector.DebuggerModel.Location} */ (callFrame.functionLocation())); var executionUILocation = WebInspector.debuggerWorkspaceBinding.rawLocationToUILocation(callFrame.location()); - if (functionUILocation.uiSourceCode !== this._uiSourceCode || executionUILocation.uiSourceCode !== this._uiSourceCode) { + if (functionUILocation.uiSourceCode !== this.uiSourceCode() || executionUILocation.uiSourceCode !== this.uiSourceCode()) { this._clearValueWidgets(); return; } @@ -886,7 +901,7 @@ _breakpointAdded: function(event) { var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiLocation); - if (uiLocation.uiSourceCode !== this._uiSourceCode) + if (uiLocation.uiSourceCode !== this.uiSourceCode()) return; if (this._shouldIgnoreExternalBreakpointEvents()) return; @@ -899,12 +914,12 @@ _breakpointRemoved: function(event) { var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiLocation); - if (uiLocation.uiSourceCode !== this._uiSourceCode) + if (uiLocation.uiSourceCode !== this.uiSourceCode()) return; if (this._shouldIgnoreExternalBreakpointEvents()) return; - var remainingBreakpoint = this._breakpointManager.findBreakpointOnLine(this._uiSourceCode, uiLocation.lineNumber); + var remainingBreakpoint = this._breakpointManager.findBreakpointOnLine(this.uiSourceCode(), uiLocation.lineNumber); if (!remainingBreakpoint && this.loaded) this._removeBreakpointDecoration(uiLocation.lineNumber); }, @@ -923,7 +938,7 @@ { var linesCount = this.textEditor.linesCount; for (var i = 0; i < linesCount; ++i) { - var lineHasMapping = WebInspector.debuggerWorkspaceBinding.uiLineHasMapping(this._uiSourceCode, i); + var lineHasMapping = WebInspector.debuggerWorkspaceBinding.uiLineHasMapping(this.uiSourceCode(), i); if (!lineHasMapping) this._hasLineWithoutMapping = true; if (this._hasLineWithoutMapping) @@ -937,12 +952,12 @@ _updateScriptFile: function(target) { var oldScriptFile = this._scriptFileForTarget.get(target); - var newScriptFile = WebInspector.debuggerWorkspaceBinding.scriptFile(this._uiSourceCode, target); + var newScriptFile = WebInspector.debuggerWorkspaceBinding.scriptFile(this.uiSourceCode(), target); this._scriptFileForTarget.remove(target); if (oldScriptFile) { oldScriptFile.removeEventListener(WebInspector.ResourceScriptFile.Events.DidMergeToVM, this._didMergeToVM, this); oldScriptFile.removeEventListener(WebInspector.ResourceScriptFile.Events.DidDivergeFromVM, this._didDivergeFromVM, this); - if (this._muted && !this._uiSourceCode.isDirty()) + if (this._muted && !this.uiSourceCode().isDirty()) this._restoreBreakpointsIfConsistentScripts(); } if (newScriptFile) @@ -967,7 +982,7 @@ if (this._executionLocation) this.setExecutionLocation(this._executionLocation); - var breakpointLocations = this._breakpointManager.breakpointLocationsForUISourceCode(this._uiSourceCode); + var breakpointLocations = this._breakpointManager.breakpointLocationsForUISourceCode(this.uiSourceCode()); for (var i = 0; i < breakpointLocations.length; ++i) this._breakpointAdded({data:breakpointLocations[i]}); @@ -1003,7 +1018,7 @@ */ _toggleBreakpoint: function(lineNumber, onlyDisable) { - var breakpoint = this._breakpointManager.findBreakpointOnLine(this._uiSourceCode, lineNumber); + var breakpoint = this._breakpointManager.findBreakpointOnLine(this.uiSourceCode(), lineNumber); if (breakpoint) { if (onlyDisable) breakpoint.setEnabled(!breakpoint.enabled()); @@ -1044,17 +1059,17 @@ */ _setBreakpoint: function(lineNumber, columnNumber, condition, enabled) { - this._breakpointManager.setBreakpoint(this._uiSourceCode, lineNumber, columnNumber, condition, enabled); + this._breakpointManager.setBreakpoint(this.uiSourceCode(), lineNumber, columnNumber, condition, enabled); }, dispose: function() { this._breakpointManager.removeEventListener(WebInspector.BreakpointManager.Events.BreakpointAdded, this._breakpointAdded, this); this._breakpointManager.removeEventListener(WebInspector.BreakpointManager.Events.BreakpointRemoved, this._breakpointRemoved, this); - this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._onSourceMappingChanged, this); - this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this); - this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this); - this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._showBlackboxInfobarIfNeeded, this); + this.uiSourceCode().removeEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._onSourceMappingChanged, this); + this.uiSourceCode().removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this); + this.uiSourceCode().removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this); + this.uiSourceCode().removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._showBlackboxInfobarIfNeeded, this); WebInspector.moduleSetting("skipStackFramesPattern").removeChangeListener(this._showBlackboxInfobarIfNeeded, this); WebInspector.moduleSetting("skipContentScripts").removeChangeListener(this._showBlackboxInfobarIfNeeded, this); WebInspector.UISourceCodeFrame.prototype.dispose.call(this);
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js index eedc0ef8..88febb4 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -54,12 +54,8 @@ this.element.addEventListener("contextmenu", this.handleContextMenu.bind(this), false); - this._navigatorGroupingByFrameSetting = WebInspector.moduleSetting("navigatorGroupByFrame"); - this._navigatorGroupingByFrameSetting.addChangeListener(this._groupingChanged.bind(this)); - this._navigatorGroupingByDomainSetting = WebInspector.moduleSetting("navigatorGroupByDomain"); - this._navigatorGroupingByDomainSetting.addChangeListener(this._groupingChanged.bind(this)); - this._navigatorGroupingByFolderSetting = WebInspector.moduleSetting("navigatorGroupByFolder"); - this._navigatorGroupingByFolderSetting.addChangeListener(this._groupingChanged.bind(this)); + this._navigatorGroupByFolderSetting = WebInspector.moduleSetting("navigatorGroupByFolder"); + this._navigatorGroupByFolderSetting.addChangeListener(this._groupingChanged.bind(this)); this._initGrouping(); WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this); @@ -674,9 +670,15 @@ _initGrouping: function() { - this._groupByFrame = this._navigatorGroupingByFrameSetting.get(); - this._groupByDomain = this._navigatorGroupingByDomainSetting.get(); - this._groupByFolder = this._groupByDomain && this._navigatorGroupingByFolderSetting.get(); + this._groupByFrame = true; + this._groupByDomain = this._navigatorGroupByFolderSetting.get(); + this._groupByFolder = this._groupByDomain; + }, + + _resetForTest: function() + { + this.reset(); + this._workspace.uiSourceCodes().forEach(this._addUISourceCode.bind(this)); }, /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js index ed1ed886..85d2040e 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js
@@ -126,14 +126,10 @@ */ _populateMenu: function(contextMenu) { - var groupByFrameSetting = WebInspector.moduleSetting("navigatorGroupByFrame"); - var groupByDomainSetting = WebInspector.moduleSetting("navigatorGroupByDomain"); var groupByFolderSetting = WebInspector.moduleSetting("navigatorGroupByFolder"); contextMenu.appendItemsAtLocation("navigatorMenu"); contextMenu.appendSeparator(); - contextMenu.appendCheckboxItem(WebInspector.UIString("Group by frame"), () => groupByFrameSetting.set(!groupByFrameSetting.get()), groupByFrameSetting.get()); - contextMenu.appendCheckboxItem(WebInspector.UIString("Group by domain"), () => groupByDomainSetting.set(!groupByDomainSetting.get()), groupByDomainSetting.get()); - contextMenu.appendCheckboxItem(WebInspector.UIString("Group by folder"), () => groupByFolderSetting.set(!groupByFolderSetting.get()), groupByFolderSetting.get(), !groupByDomainSetting.get()); + contextMenu.appendCheckboxItem(WebInspector.UIString("Group by folder"), () => groupByFolderSetting.set(!groupByFolderSetting.get()), groupByFolderSetting.get()); }, __proto__: WebInspector.Object.prototype
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js index 5840ed5c..c8df776 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
@@ -26,7 +26,7 @@ this._searchableView.setMinimalSearchQuerySize(0); this._searchableView.show(this.element); - /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.Widget>} */ + /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.VBoxWithToolbarItems>} */ this._sourceViewByUISourceCode = new Map(); var tabbedEditorPlaceholderText = WebInspector.isMac() ? WebInspector.UIString("Hit Cmd+P to open a file") : WebInspector.UIString("Hit Ctrl+P to open a file"); @@ -50,7 +50,7 @@ for (var i = 0; i < actions.length; ++i) this._toolbarEditorActions.appendToolbarItem(actions[i].button(this)); } - this._scriptViewToolbarText = new WebInspector.Toolbar("", this._toolbarContainerElement); + this._scriptViewToolbar = new WebInspector.Toolbar("", this._toolbarContainerElement); WebInspector.startBatchUpdate(); this._workspace.uiSourceCodes().forEach(this._addUISourceCode.bind(this)); @@ -281,13 +281,12 @@ _updateScriptViewToolbarItems: function() { - this._scriptViewToolbarText.removeToolbarItems(); - var sourceFrame = this.currentSourceFrame(); - if (!sourceFrame) - return; - - var toolbarText = sourceFrame.toolbarText(); - this._scriptViewToolbarText.appendToolbarItem(toolbarText); + this._scriptViewToolbar.removeToolbarItems(); + var view = /** @type {?WebInspector.VBoxWithToolbarItems} */(this.visibleView()); + if (view) { + for (var item of view.toolbarItems()) + this._scriptViewToolbar.appendToolbarItem(item); + } }, /** @@ -334,7 +333,6 @@ var sourceView; var contentType = uiSourceCode.contentType(); - if (contentType.hasScripts()) sourceFrame = new WebInspector.JavaScriptSourceFrame(this._sourcesPanel, uiSourceCode); else if (contentType.isStyleSheet()) @@ -350,7 +348,7 @@ sourceFrame.setHighlighterType(WebInspector.NetworkProject.uiSourceCodeMimeType(uiSourceCode)); this._historyManager.trackSourceFrameCursorJumps(sourceFrame); } - this._sourceViewByUISourceCode.set(uiSourceCode, /** @type {!WebInspector.Widget} */(sourceFrame || sourceView)); + this._sourceViewByUISourceCode.set(uiSourceCode, /** @type {!WebInspector.VBoxWithToolbarItems} */(sourceFrame || sourceView)); return /** @type {!WebInspector.Widget} */(sourceFrame || sourceView); },
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/module.json b/third_party/WebKit/Source/devtools/front_end/sources/module.json index 878b5fc..c67ea5a7 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/module.json +++ b/third_party/WebKit/Source/devtools/front_end/sources/module.json
@@ -222,11 +222,11 @@ "bindings": [ { "platform": "mac", - "shortcut": "Meta+O Meta+P" + "shortcut": "Meta+P Meta+O" }, { "platform": "windows,linux", - "shortcut": "Ctrl+O Ctrl+P" + "shortcut": "Ctrl+P Ctrl+O" } ] }, @@ -243,18 +243,6 @@ }, { "type": "setting", - "settingName": "navigatorGroupByFrame", - "settingType": "boolean", - "defaultValue": "true" - }, - { - "type": "setting", - "settingName": "navigatorGroupByDomain", - "settingType": "boolean", - "defaultValue": "true" - }, - { - "type": "setting", "settingName": "navigatorGroupByFolder", "settingType": "boolean", "defaultValue": "true"
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 c68fa0c..d7105d0 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -106,9 +106,7 @@ */ appendText: function(text) { - var item = new WebInspector.ToolbarTextGlyphItem(); - item.setText(text); - this.appendToolbarItem(item); + this.appendToolbarItem(new WebInspector.ToolbarLabel(text)); }, removeToolbarItems: function() @@ -237,19 +235,22 @@ /** * @constructor * @extends {WebInspector.ToolbarItem} + * @param {string=} text + * @param {string=} glyph */ -WebInspector.ToolbarTextGlyphItem = function() +WebInspector.ToolbarLabel = function(text, glyph) { WebInspector.ToolbarItem.call(this, createElementWithClass("button", "toolbar-text-glyph")); this._glyphElement = this.element.createChild("div", "toolbar-glyph hidden"); this._textElement = this.element.createChild("div", "toolbar-text hidden"); - this._text = ""; - this._glyph = ""; + this.setText(text || ""); + if (glyph) + this.setGlyph(glyph); this._state = ""; this._title = ""; } -WebInspector.ToolbarTextGlyphItem.prototype = { +WebInspector.ToolbarLabel.prototype = { /** * @param {string} text */ @@ -338,13 +339,13 @@ /** * @constructor - * @extends {WebInspector.ToolbarTextGlyphItem} + * @extends {WebInspector.ToolbarLabel} * @param {string} title * @param {string} glyph */ WebInspector.ToolbarButton = function(title, glyph) { - WebInspector.ToolbarTextGlyphItem.call(this); + WebInspector.ToolbarLabel.call(this); this.element.classList.add("toolbar-button"); this.element.addEventListener("click", this._clicked.bind(this), false); this.element.addEventListener("mousedown", this._mouseDown.bind(this), false); @@ -380,7 +381,7 @@ this.dispatchEventToListeners("mouseup", event); }, - __proto__: WebInspector.ToolbarTextGlyphItem.prototype + __proto__: WebInspector.ToolbarLabel.prototype } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Widget.js b/third_party/WebKit/Source/devtools/front_end/ui/Widget.js index 9c044ac..3b53ce0 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/Widget.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/Widget.js
@@ -633,6 +633,27 @@ } /** + * @constructor + * @extends {WebInspector.VBox} + */ +WebInspector.VBoxWithToolbarItems = function() +{ + WebInspector.VBox.call(this); +} + +WebInspector.VBoxWithToolbarItems.prototype = { + /** + * @return {!Array<!WebInspector.ToolbarItem>} + */ + toolbarItems: function() + { + return []; + }, + + __proto__: WebInspector.VBox.prototype +} + +/** * @override * @param {?Node} child * @return {?Node}
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css b/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css index 633a9a4..1dd4e3e2 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css
@@ -90,7 +90,7 @@ } .edit-button { - background-position: -224px -72px; + background-position: -160px 0px; } .editor-container {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js index 8001938e..a9a01054 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js +++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js
@@ -23,6 +23,7 @@ this._promptElement = this.contentElement.createChild("div", "monospace filtered-list-widget-input"); this._promptElement.setAttribute("spellcheck", "false"); + this._promptElement.setAttribute("contenteditable", "true"); this._prompt = new WebInspector.TextPrompt(this._autocomplete.bind(this)); this._prompt.renderAsBlock(); this._prompt.addEventListener(WebInspector.TextPrompt.Events.ItemAccepted, this._onAutocompleted, this);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/filteredListWidget.css b/third_party/WebKit/Source/devtools/front_end/ui_lazy/filteredListWidget.css index 8dcf450e..dc8f7e4 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/filteredListWidget.css +++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/filteredListWidget.css
@@ -15,16 +15,16 @@ border: 0; box-shadow: rgba(140, 140, 140, 0.5) 0 4px 16px; margin: 0; - padding-left: 6px; + padding: 0 6px; z-index: 1; font-size: inherit; } .filtered-list-widget-input { white-space: pre; - -webkit-user-modify: read-write-plaintext-only; height: 18px; margin-top: 10px; + overflow: hidden; } .filtered-list-widget > div.container {
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp index 2fad5535..6e4b87e 100644 --- a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp +++ b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
@@ -460,6 +460,11 @@ _mm_storeu_ps(values + writeIndex, vValue); vValue = _mm_add_ps(vValue, vInc); } + // Update |value| with the last value computed so that the .value attribute of the + // AudioParam gets the correct linear ramp value, in case the following loop doesn't + // execute. + if (writeIndex >= 1) + value = values[writeIndex - 1]; #endif // Serially process remaining values. for (; writeIndex < fillToFrame; ++writeIndex) { @@ -753,6 +758,7 @@ for (; writeIndex < numberOfValues; ++writeIndex) values[writeIndex] = value; + // This value is used to set the .value attribute of the AudioParam. return value; }
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp index a128374..9478f11 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -858,7 +858,7 @@ void WebGL2RenderingContextBase::texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, DOMArrayBufferView* pixels) { if (isContextLost() || !validateTexFunc3DTarget("texImage3D", target) - || !validateTexFunc("texImage3D", NotTexSubImage, SourceArrayBufferView, target, level, internalformat, width, height, depth, border, format, type, 0, 0, 0) + || !validateTexFunc("texImage3D", TexImage, SourceArrayBufferView, target, level, internalformat, width, height, depth, border, format, type, 0, 0, 0) || !validateTexFuncData("texImage3D", level, width, height, depth, format, type, pixels, NullAllowed)) return; @@ -1044,7 +1044,7 @@ synthesizeGLError(GL_INVALID_VALUE, "compressedTexImage3D", "border not 0"); return; } - if (!validateCompressedTexDimensions("compressedTexImage3D", NotTexSubImage, target, level, width, height, depth, internalformat)) + if (!validateCompressedTexDimensions("compressedTexImage3D", CompressedTexImage, target, level, width, height, depth, internalformat)) return; if (!validateCompressedTexFuncData("compressedTexImage3D", width, height, depth, internalformat, data)) return; @@ -1298,112 +1298,64 @@ { if (isContextLost()) return; + webContext()->vertexAttribI4i(index, x, y, z, w); + setVertexAttribType(index, Int32ArrayType); +} - if (index >= m_maxVertexAttribs) { - synthesizeGLError(GL_INVALID_VALUE, "vertexAttribI4i", "index out of range"); +void WebGL2RenderingContextBase::vertexAttribI4iv(GLuint index, const DOMInt32Array* v) +{ + if (isContextLost()) + return; + if (!v || v->length() < 4) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttribI4iv", "invalid array"); return; } - - webContext()->vertexAttribI4i(index, x, y, z, w); - VertexAttribValue& attribValue = m_vertexAttribValue[index]; - attribValue.type = Int32ArrayType; - attribValue.value.intValue[0] = x; - attribValue.value.intValue[1] = y; - attribValue.value.intValue[2] = z; - attribValue.value.intValue[3] = w; + webContext()->vertexAttribI4iv(index, v->data()); + setVertexAttribType(index, Int32ArrayType); } -void WebGL2RenderingContextBase::vertexAttribI4iv(GLuint index, const DOMInt32Array* value) +void WebGL2RenderingContextBase::vertexAttribI4iv(GLuint index, const Vector<GLint>& v) { - vertexAttribIivImpl("vertexAttribI4iv", index, value->data(), value->length()); -} - -void WebGL2RenderingContextBase::vertexAttribI4iv(GLuint index, const Vector<GLint>& value) -{ - vertexAttribIivImpl("vertexAttribI4iv", index, value.data(), value.size()); + if (isContextLost()) + return; + if (v.size() < 4) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttribI4iv", "invalid array"); + return; + } + webContext()->vertexAttribI4iv(index, v.data()); + setVertexAttribType(index, Int32ArrayType); } void WebGL2RenderingContextBase::vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) { if (isContextLost()) return; - - if (index >= m_maxVertexAttribs) { - synthesizeGLError(GL_INVALID_VALUE, "vertexAttribI4ui", "index out of range"); - return; - } - webContext()->vertexAttribI4ui(index, x, y, z, w); - VertexAttribValue& attribValue = m_vertexAttribValue[index]; - attribValue.type = Uint32ArrayType; - attribValue.value.uintValue[0] = x; - attribValue.value.uintValue[1] = y; - attribValue.value.uintValue[2] = z; - attribValue.value.uintValue[3] = w; + setVertexAttribType(index, Uint32ArrayType); } -void WebGL2RenderingContextBase::vertexAttribI4uiv(GLuint index, const DOMUint32Array* value) -{ - vertexAttribIuivImpl("vertexAttribI4uiv", index, value->data(), value->length()); -} - -void WebGL2RenderingContextBase::vertexAttribI4uiv(GLuint index, const Vector<GLuint>& value) -{ - vertexAttribIuivImpl("vertexAttribI4uiv", index, value.data(), value.size()); -} - -void WebGL2RenderingContextBase::vertexAttribIivImpl(const char* functionName, GLuint index, const GLint* value, GLsizei size) +void WebGL2RenderingContextBase::vertexAttribI4uiv(GLuint index, const DOMUint32Array* v) { if (isContextLost()) return; - - if (!value) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); + if (!v || v->length() < 4) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttribI4uiv", "invalid array"); return; } - if (size < 4) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid size"); - return; - } - if (index >= m_maxVertexAttribs) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range"); - return; - } - - webContext()->vertexAttribI4iv(index, value); - VertexAttribValue& attribValue = m_vertexAttribValue[index]; - attribValue.type = Int32ArrayType; - attribValue.value.intValue[0] = value[0]; - attribValue.value.intValue[1] = value[1]; - attribValue.value.intValue[2] = value[2]; - attribValue.value.intValue[3] = value[3]; + webContext()->vertexAttribI4uiv(index, v->data()); + setVertexAttribType(index, Uint32ArrayType); } -void WebGL2RenderingContextBase::vertexAttribIuivImpl(const char* functionName, GLuint index, const GLuint* value, GLsizei size) +void WebGL2RenderingContextBase::vertexAttribI4uiv(GLuint index, const Vector<GLuint>& v) { if (isContextLost()) return; - - if (!value) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); + if (v.size() < 4) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttribI4uiv", "invalid array"); return; } - if (size < 4) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid size"); - return; - } - if (index >= m_maxVertexAttribs) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range"); - return; - } - - webContext()->vertexAttribI4uiv(index, value); - VertexAttribValue& attribValue = m_vertexAttribValue[index]; - attribValue.type = Uint32ArrayType; - attribValue.value.uintValue[0] = value[0]; - attribValue.value.uintValue[1] = value[1]; - attribValue.value.uintValue[2] = value[2]; - attribValue.value.uintValue[3] = value[3]; + webContext()->vertexAttribI4uiv(index, v.data()); + setVertexAttribType(index, Uint32ArrayType); } void WebGL2RenderingContextBase::vertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, long long offset) @@ -1444,9 +1396,6 @@ if (!validateDrawArrays("drawArraysInstanced", mode, first, count)) return; - if (!validateDrawInstanced("drawArraysInstanced", instanceCount)) - return; - clearIfComposited(); handleTextureCompleteness("drawArraysInstanced", true); @@ -1460,9 +1409,6 @@ if (!validateDrawElements("drawElementsInstanced", mode, count, type, offset)) return; - if (!validateDrawInstanced("drawElementsInstanced", instanceCount)) - return; - if (transformFeedbackActive() && !transformFeedbackPaused()) { synthesizeGLError(GL_INVALID_OPERATION, "drawElementsInstanced", "transform feedback is active and not paused"); return;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h index 9370f58..f71f068 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
@@ -212,9 +212,6 @@ bool validateBufferBaseTarget(const char* functionName, GLenum target); bool validateAndUpdateBufferBindBaseTarget(const char* functionName, GLenum, GLuint, WebGLBuffer*); - void vertexAttribIivImpl(const char*, GLuint, const GLint*, GLsizei); - void vertexAttribIuivImpl(const char*, GLuint, const GLuint*, GLsizei); - bool checkAndTranslateAttachments(const char* functionName, GLenum, const Vector<GLenum>&, Vector<GLenum>&); /* WebGLRenderingContextBase overrides */
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp index 6eb6c9f..71ac672 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -1062,11 +1062,7 @@ m_readBufferOfDefaultFramebuffer = GL_BACK; - if (isWebGL2OrHigher()) { - m_defaultVertexArrayObject = WebGLVertexArrayObject::create(this, WebGLVertexArrayObjectBase::VaoTypeDefault); - } else { - m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectBase::VaoTypeDefault); - } + m_defaultVertexArrayObject = WebGLVertexArrayObject::create(this, WebGLVertexArrayObjectBase::VaoTypeDefault); addContextObject(m_defaultVertexArrayObject.get()); // It's not convenient or necessary to pass a ScriptState this far down; while one is available // during WebGLRenderingContext construction, the wrapper for the context itself hasn't been @@ -1076,7 +1072,7 @@ m_preservedDefaultVAOObjectWrapper = false; m_boundVertexArrayObject = m_defaultVertexArrayObject; - m_vertexAttribValue.resize(m_maxVertexAttribs); + m_vertexAttribType.resize(m_maxVertexAttribs); createFallbackBlackTextures1x1(); @@ -1155,7 +1151,6 @@ m_boundArrayBuffer = nullptr; m_defaultVertexArrayObject = nullptr; m_boundVertexArrayObject = nullptr; - m_vertexAttrib0Buffer = nullptr; m_currentProgram = nullptr; m_framebufferBinding = nullptr; m_renderbufferBinding = nullptr; @@ -1446,16 +1441,10 @@ return; if (!validateLocationLength("bindAttribLocation", name)) return; - if (!validateString("bindAttribLocation", name)) - return; if (isPrefixReserved(name)) { synthesizeGLError(GL_INVALID_OPERATION, "bindAttribLocation", "reserved prefix"); return; } - if (index >= m_maxVertexAttribs) { - synthesizeGLError(GL_INVALID_VALUE, "bindAttribLocation", "index out of range"); - return; - } webContext()->bindAttribLocation(objectOrZero(program), index, name.utf8().data()); } @@ -1860,7 +1849,7 @@ synthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D", "border not 0"); return; } - if (!validateCompressedTexDimensions("compressedTexImage2D", NotTexSubImage, target, level, width, height, 1, internalformat)) + if (!validateCompressedTexDimensions("compressedTexImage2D", CompressedTexImage, target, level, width, height, 1, internalformat)) return; if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, 1, internalformat, data)) return; @@ -1919,7 +1908,7 @@ return; if (!validateTexFuncLevel("copyTexImage2D", target, level)) return; - if (!validateTexFuncParameters("copyTexImage2D", NotTexSubImage, target, level, internalformat, width, height, 1, border, internalformat, GL_UNSIGNED_BYTE)) + if (!validateTexFuncParameters("copyTexImage2D", CopyTexImage, target, level, internalformat, width, height, 1, border, internalformat, GL_UNSIGNED_BYTE)) return; if (!validateSettableTexFormat("copyTexImage2D", internalformat)) return; @@ -2074,15 +2063,6 @@ { if (isContextLost()) return; - switch (mode) { - case GL_FRONT_AND_BACK: - case GL_FRONT: - case GL_BACK: - break; - default: - synthesizeGLError(GL_INVALID_ENUM, "cullFace", "invalid mode"); - return; - } webContext()->cullFace(mode); } @@ -2188,8 +2168,6 @@ { if (isContextLost()) return; - if (!validateStencilOrDepthFunc("depthFunc", func)) - return; webContext()->depthFunc(func); } @@ -2205,6 +2183,7 @@ { if (isContextLost()) return; + // Check required by WebGL spec section 6.12 if (zNear > zFar) { synthesizeGLError(GL_INVALID_OPERATION, "depthRange", "zNear > zFar"); return; @@ -2255,6 +2234,7 @@ bool WebGLRenderingContextBase::validateRenderingState(const char* functionName) { + // Command buffer will not error if no program is bound. if (!m_currentProgram) { synthesizeGLError(GL_INVALID_OPERATION, functionName, "no valid shader program in use"); return false; @@ -2312,9 +2292,6 @@ if (!validateDrawArrays("drawArraysInstancedANGLE", mode, first, count)) return; - if (!validateDrawInstanced("drawArraysInstancedANGLE", primcount)) - return; - clearIfComposited(); handleTextureCompleteness("drawArraysInstancedANGLE", true); @@ -2328,9 +2305,6 @@ if (!validateDrawElements("drawElementsInstancedANGLE", mode, count, type, offset)) return; - if (!validateDrawInstanced("drawElementsInstancedANGLE", primcount)) - return; - clearIfComposited(); handleTextureCompleteness("drawElementsInstancedANGLE", true); @@ -2481,14 +2455,6 @@ { if (isContextLost()) return; - switch (mode) { - case GL_CW: - case GL_CCW: - break; - default: - synthesizeGLError(GL_INVALID_ENUM, "frontFace", "invalid mode"); - return; - } webContext()->frontFace(mode); } @@ -3503,14 +3469,22 @@ } case GL_CURRENT_VERTEX_ATTRIB: { - VertexAttribValue& attribValue = m_vertexAttribValue[index]; - switch (attribValue.type) { - case Float32ArrayType: - return WebGLAny(scriptState, DOMFloat32Array::create(attribValue.value.floatValue, 4)); - case Int32ArrayType: - return WebGLAny(scriptState, DOMInt32Array::create(attribValue.value.intValue, 4)); - case Uint32ArrayType: - return WebGLAny(scriptState, DOMUint32Array::create(attribValue.value.uintValue, 4)); + switch (m_vertexAttribType[index]) { + case Float32ArrayType: { + GLfloat floatValue[4]; + webContext()->getVertexAttribfv(index, pname, floatValue); + return WebGLAny(scriptState, DOMFloat32Array::create(floatValue, 4)); + } + case Int32ArrayType: { + GLint intValue[4]; + webContext()->getVertexAttribIiv(index, pname, intValue); + return WebGLAny(scriptState, DOMInt32Array::create(intValue, 4)); + } + case Uint32ArrayType: { + GLuint uintValue[4]; + webContext()->getVertexAttribIuiv(index, pname, uintValue); + return WebGLAny(scriptState, DOMUint32Array::create(uintValue, 4)); + } default: ASSERT_NOT_REACHED(); break; @@ -3534,10 +3508,6 @@ { if (isContextLost()) return 0; - if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) { - synthesizeGLError(GL_INVALID_ENUM, "getVertexAttribOffset", "invalid parameter name"); - return 0; - } GLintptr result = webContext()->getVertexAttribOffset(index, pname); return static_cast<long long>(result); } @@ -3978,8 +3948,6 @@ { if (isContextLost()) return; - if (!validateSize("scissor", width, height)) - return; webContext()->scissor(x, y, width, height); } @@ -4152,7 +4120,7 @@ return internalformat; } -void WebGLRenderingContextBase::texImage2DBase(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels) +void WebGLRenderingContextBase::texImage2DBase(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels) { // All calling functions check isContextLost, so a duplicate check is not needed here. WebGLTexture* tex = validateTextureBinding("texImage2D", target, true); @@ -4161,7 +4129,7 @@ tex->setLevelInfo(target, level, internalformat, width, height, 1, type); } -void WebGLRenderingContextBase::texImage2DImpl(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, Image* image, WebGLImageConversion::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha) +void WebGLRenderingContextBase::texImage2DImpl(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, Image* image, WebGLImageConversion::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha) { // All calling functions check isContextLost, so a duplicate check is not needed here. if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) { @@ -4213,24 +4181,7 @@ if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, depth, border, format, type)) return false; - if (functionType == NotTexSubImage) { - if (texture->isImmutable()) { - synthesizeGLError(GL_INVALID_OPERATION, functionName, "attempted to modify immutable texture"); - return false; - } - - // Depth is for WebGL 2.0 only where iSNPOTStrict() is always false. - if (isNPOTStrict() && level && WebGLTexture::isNPOT(width, height)) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "level > 0 not power of 2"); - return false; - } - // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat - // by checking if the ArrayBufferView is null or not. - if (sourceType != SourceArrayBufferView) { - if (!validateSettableTexFormat(functionName, format)) - return false; - } - } else { + if (functionType == TexSubImage) { if (!validateSettableTexFormat(functionName, format)) return false; if (!validateSize(functionName, xoffset, yoffset, zoffset)) @@ -4251,6 +4202,23 @@ synthesizeGLError(GL_INVALID_OPERATION, functionName, "type of incoming data does not match that used to define the texture"); return false; } + } else { + if (texture->isImmutable()) { + synthesizeGLError(GL_INVALID_OPERATION, functionName, "attempted to modify immutable texture"); + return false; + } + + // Depth is for WebGL 2.0 only where iSNPOTStrict() is always false. + if (isNPOTStrict() && level && WebGLTexture::isNPOT(width, height)) { + synthesizeGLError(GL_INVALID_VALUE, functionName, "level > 0 not power of 2"); + return false; + } + // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat + // by checking if the ArrayBufferView is null or not. + if (sourceType != SourceArrayBufferView) { + if (!validateSettableTexFormat(functionName, format)) + return false; + } } return true; @@ -4296,11 +4264,11 @@ return buf->newImageSnapshot(); } -void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, +void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, DOMArrayBufferView* pixels) { - if (isContextLost() || !validateTexFunc("texImage2D", NotTexSubImage, SourceArrayBufferView, target, level, internalformat, width, height, 1, border, format, type, 0, 0, 0) + if (isContextLost() || !validateTexFunc("texImage2D", TexImage, SourceArrayBufferView, target, level, internalformat, width, height, 1, border, format, type, 0, 0, 0) || !validateTexFuncData("texImage2D", level, width, height, 1, format, type, pixels, NullAllowed)) return; void* data = pixels ? pixels->baseAddress() : 0; @@ -4319,7 +4287,7 @@ restoreUnpackParameters(); } -void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, +void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, ImageData* pixels) { if (!pixels) { @@ -4330,7 +4298,7 @@ synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "The source data has been neutered."); return; } - if (isContextLost() || !validateTexFunc("texImage2D", NotTexSubImage, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 1, 0, format, type, 0, 0, 0)) + if (isContextLost() || !validateTexFunc("texImage2D", TexImage, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 1, 0, format, type, 0, 0, 0)) return; if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) { // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented. @@ -4353,7 +4321,7 @@ restoreUnpackParameters(); } -void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, +void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLImageElement* image, ExceptionState& exceptionState) { if (isContextLost() || !validateHTMLImageElement("texImage2D", image, exceptionState)) @@ -4367,13 +4335,13 @@ if (imageForRender && imageForRender->isSVGImage()) imageForRender = drawImageIntoBuffer(imageForRender.release(), image->width(), image->height(), "texImage2D"); - if (!imageForRender || !validateTexFunc("texImage2D", NotTexSubImage, SourceHTMLImageElement, target, level, internalformat, imageForRender->width(), imageForRender->height(), 1, 0, format, type, 0, 0, 0)) + if (!imageForRender || !validateTexFunc("texImage2D", TexImage, SourceHTMLImageElement, target, level, internalformat, imageForRender->width(), imageForRender->height(), 1, 0, format, type, 0, 0, 0)) return; texImage2DImpl(target, level, internalformat, format, type, imageForRender.get(), WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha); } -bool WebGLRenderingContextBase::canUseTexImageCanvasByGPU(GLenum internalformat, GLenum type) +bool WebGLRenderingContextBase::canUseTexImageCanvasByGPU(GLint internalformat, GLenum type) { if (isFloatType(type) || isIntegerFormat(internalformat) || isSRGBFormat(internalformat)) return false; @@ -4381,7 +4349,7 @@ } void WebGLRenderingContextBase::texImageCanvasByGPU(TexImageByGPUType functionType, WebGLTexture* texture, GLenum target, - GLint level, GLenum internalformat, GLenum type, GLint xoffset, GLint yoffset, GLint zoffset, HTMLCanvasElement* canvas) + GLint level, GLint internalformat, GLenum type, GLint xoffset, GLint yoffset, GLint zoffset, HTMLCanvasElement* canvas) { ScopedTexture2DRestorer restorer(this); @@ -4443,10 +4411,10 @@ } } -void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, +void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLCanvasElement* canvas, ExceptionState& exceptionState) { - if (isContextLost() || !validateHTMLCanvasElement("texImage2D", canvas, exceptionState) || !validateTexFunc("texImage2D", NotTexSubImage, SourceHTMLCanvasElement, target, level, internalformat, canvas->width(), canvas->height(), 1, 0, format, type, 0, 0, 0)) + if (isContextLost() || !validateHTMLCanvasElement("texImage2D", canvas, exceptionState) || !validateTexFunc("texImage2D", TexImage, SourceHTMLCanvasElement, target, level, internalformat, canvas->width(), canvas->height(), 1, 0, format, type, 0, 0, 0)) return; WebGLTexture* texture = validateTextureBinding("texImage2D", target, true); @@ -4479,11 +4447,11 @@ return buf->newImageSnapshot(); } -void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, +void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLVideoElement* video, ExceptionState& exceptionState) { if (isContextLost() || !validateHTMLVideoElement("texImage2D", video, exceptionState) - || !validateTexFunc("texImage2D", NotTexSubImage, SourceHTMLVideoElement, target, level, internalformat, video->videoWidth(), video->videoHeight(), 1, 0, format, type, 0, 0, 0)) + || !validateTexFunc("texImage2D", TexImage, SourceHTMLVideoElement, target, level, internalformat, video->videoWidth(), video->videoHeight(), 1, 0, format, type, 0, 0, 0)) return; // Go through the fast path doing a GPU-GPU textures copy without a readback to system memory if possible. @@ -4524,7 +4492,7 @@ texImage2DImpl(target, level, internalformat, format, type, image.get(), WebGLImageConversion::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha); } -void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, +void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, PassRefPtrWillBeRawPtr<ImageBitmap> bitmap) { ASSERT(bitmap->bitmapImage()); @@ -4532,7 +4500,7 @@ synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "The source data has been neutered."); return; } - if (isContextLost() || !validateTexFunc("texImage2D", NotTexSubImage, SourceImageBitmap, target, level, 0, bitmap->width(), bitmap->height(), 1, 0, format, type, 0, 0, 0)) + if (isContextLost() || !validateTexFunc("texImage2D", TexImage, SourceImageBitmap, target, level, 0, bitmap->width(), bitmap->height(), 1, 0, format, type, 0, 0, 0)) return; StaticBitmapImage* imageForRender = bitmap->bitmapImage(); texImage2DImpl(target, level, internalformat, format, type, imageForRender, WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha); @@ -4724,7 +4692,7 @@ WebGLTexture* texture = validateTextureBinding("texSubImage2D", target, true); ASSERT(texture); - GLenum internalformat = texture->getInternalFormat(target, level); + GLint internalformat = texture->getInternalFormat(target, level); // texImageCanvasByGPU relies on copyTextureCHROMIUM which doesn't support float/integer/sRGB internal format. // FIXME: relax the constrains if copyTextureCHROMIUM is upgraded to handle more formats. if (!canvas->renderingContext() || !canvas->renderingContext()->isAccelerated() || !canUseTexImageCanvasByGPU(internalformat, type)) { @@ -5073,64 +5041,138 @@ webContext()->validateProgram(objectOrZero(program)); } +void WebGLRenderingContextBase::setVertexAttribType(GLuint index, VertexAttribValueType type) +{ + if (index < m_maxVertexAttribs) + m_vertexAttribType[index] = type; +} + void WebGLRenderingContextBase::vertexAttrib1f(GLuint index, GLfloat v0) { - vertexAttribfImpl("vertexAttrib1f", index, 1, v0, 0.0f, 0.0f, 1.0f); + if (isContextLost()) + return; + webContext()->vertexAttrib1f(index, v0); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index, const DOMFloat32Array* v) { - vertexAttribfvImpl("vertexAttrib1fv", index, v, 1); + if (isContextLost()) + return; + if (!v || v->length() < 1) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttrib1fv", "invalid array"); + return; + } + webContext()->vertexAttrib1fv(index, v->data()); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index, const Vector<GLfloat>& v) { - vertexAttribfvImpl("vertexAttrib1fv", index, v.data(), v.size(), 1); + if (isContextLost()) + return; + if (v.size() < 1) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttrib1fv", "invalid array"); + return; + } + webContext()->vertexAttrib1fv(index, v.data()); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1) { - vertexAttribfImpl("vertexAttrib2f", index, 2, v0, v1, 0.0f, 1.0f); + if (isContextLost()) + return; + webContext()->vertexAttrib2f(index, v0, v1); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index, const DOMFloat32Array* v) { - vertexAttribfvImpl("vertexAttrib2fv", index, v, 2); + if (isContextLost()) + return; + if (!v || v->length() < 2) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttrib2fv", "invalid array"); + return; + } + webContext()->vertexAttrib2fv(index, v->data()); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index, const Vector<GLfloat>& v) { - vertexAttribfvImpl("vertexAttrib2fv", index, v.data(), v.size(), 2); + if (isContextLost()) + return; + if (v.size() < 2) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttrib2fv", "invalid array"); + return; + } + webContext()->vertexAttrib2fv(index, v.data()); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2) { - vertexAttribfImpl("vertexAttrib3f", index, 3, v0, v1, v2, 1.0f); + if (isContextLost()) + return; + webContext()->vertexAttrib3f(index, v0, v1, v2); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index, const DOMFloat32Array* v) { - vertexAttribfvImpl("vertexAttrib3fv", index, v, 3); + if (isContextLost()) + return; + if (!v || v->length() < 3) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttrib3fv", "invalid array"); + return; + } + webContext()->vertexAttrib3fv(index, v->data()); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index, const Vector<GLfloat>& v) { - vertexAttribfvImpl("vertexAttrib3fv", index, v.data(), v.size(), 3); + if (isContextLost()) + return; + if (v.size() < 3) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttrib3fv", "invalid array"); + return; + } + webContext()->vertexAttrib3fv(index, v.data()); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { - vertexAttribfImpl("vertexAttrib4f", index, 4, v0, v1, v2, v3); + if (isContextLost()) + return; + webContext()->vertexAttrib4f(index, v0, v1, v2, v3); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index, const DOMFloat32Array* v) { - vertexAttribfvImpl("vertexAttrib4fv", index, v, 4); + if (isContextLost()) + return; + if (!v || v->length() < 4) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttrib4fv", "invalid array"); + return; + } + webContext()->vertexAttrib4fv(index, v->data()); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index, const Vector<GLfloat>& v) { - vertexAttribfvImpl("vertexAttrib4fv", index, v.data(), v.size(), 4); + if (isContextLost()) + return; + if (v.size() < 4) { + synthesizeGLError(GL_INVALID_VALUE, "vertexAttrib4fv", "invalid array"); + return; + } + webContext()->vertexAttrib4fv(index, v.data()); + setVertexAttribType(index, Float32ArrayType); } void WebGLRenderingContextBase::vertexAttribPointer(ScriptState* scriptState, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, long long offset) @@ -5171,8 +5213,6 @@ { if (isContextLost()) return; - if (!validateSize("viewport", width, height)) - return; webContext()->viewport(x, y, width, height); } @@ -5571,7 +5611,7 @@ return true; } -bool WebGLRenderingContextBase::validateTexFuncFormatAndType(const char* functionName, GLenum internalformat, GLenum format, GLenum type, GLint level) +bool WebGLRenderingContextBase::validateTexFuncFormatAndType(const char* functionName, TexImageFunctionType functionType, GLenum internalformat, GLenum format, GLenum type, GLint level) { if (!m_isWebGL2FormatsTypesAdded && isWebGL2OrHigher()) { ADD_VALUES_TO_SET(m_supportedInternalFormats, kSupportedInternalFormatsES3); @@ -5611,7 +5651,11 @@ } if (m_supportedInternalFormats.find(internalformat) == m_supportedInternalFormats.end()) { - synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid internalformat"); + if (functionType == TexImage) { + synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid internalformat"); + } else { + synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid internalformat"); + } return false; } if (m_supportedFormats.find(format) == m_supportedFormats.end()) { @@ -5727,7 +5771,7 @@ // We absolutely have to validate the format and type combination. // The texImage2D entry points taking HTMLImage, etc. will produce // temporary data based on this combination, so it must be legal. - if (!validateTexFuncFormatAndType(functionName, internalformat, format, type, level)) + if (!validateTexFuncFormatAndType(functionName, functionType, internalformat, format, type, level)) return false; if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height, depth)) @@ -6190,23 +6234,6 @@ } } -bool WebGLRenderingContextBase::validateDrawMode(const char* functionName, GLenum mode) -{ - switch (mode) { - case GL_POINTS: - case GL_LINE_STRIP: - case GL_LINE_LOOP: - case GL_LINES: - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_TRIANGLES: - return true; - default: - synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid draw mode"); - return false; - } -} - bool WebGLRenderingContextBase::validateStencilSettings(const char* functionName) { if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) { @@ -6473,22 +6500,12 @@ bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GLenum mode, GLint first, GLsizei count) { - if (isContextLost() || !validateDrawMode(functionName, mode)) + if (isContextLost()) return false; if (!validateStencilSettings(functionName)) return false; - if (first < 0 || count < 0) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "first or count < 0"); - return false; - } - - if (!count) { - markContextChanged(CanvasChanged); - return false; - } - if (!validateRenderingState(functionName)) { return false; } @@ -6504,43 +6521,20 @@ bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GLenum mode, GLsizei count, GLenum type, long long offset) { - if (isContextLost() || !validateDrawMode(functionName, mode)) + if (isContextLost()) return false; if (!validateStencilSettings(functionName)) return false; - switch (type) { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT: - break; - case GL_UNSIGNED_INT: - if (extensionEnabled(OESElementIndexUintName) || isWebGL2OrHigher()) - break; - synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid type"); - return false; - default: + if (type == GL_UNSIGNED_INT && !isWebGL2OrHigher() && !extensionEnabled(OESElementIndexUintName)) { synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid type"); return false; } - if (count < 0) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "count < 0"); - return false; - } if (!validateValueFitNonNegInt32(functionName, "offset", offset)) return false; - if (!count) { - markContextChanged(CanvasChanged); - return false; - } - - if (!m_boundVertexArrayObject->boundElementArrayBuffer()) { - synthesizeGLError(GL_INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound"); - return false; - } - if (!validateRenderingState(functionName)) { return false; } @@ -6554,97 +6548,6 @@ return true; } -// Helper function to validate draw*Instanced calls -bool WebGLRenderingContextBase::validateDrawInstanced(const char* functionName, GLsizei primcount) -{ - if (primcount < 0) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "primcount < 0"); - return false; - } - - return true; -} - -void WebGLRenderingContextBase::vertexAttribfImpl(const char* functionName, GLuint index, GLsizei expectedSize, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) -{ - if (isContextLost()) - return; - if (index >= m_maxVertexAttribs) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range"); - return; - } - // In GL, we skip setting vertexAttrib0 values. - switch (expectedSize) { - case 1: - webContext()->vertexAttrib1f(index, v0); - break; - case 2: - webContext()->vertexAttrib2f(index, v0, v1); - break; - case 3: - webContext()->vertexAttrib3f(index, v0, v1, v2); - break; - case 4: - webContext()->vertexAttrib4f(index, v0, v1, v2, v3); - break; - } - VertexAttribValue& attribValue = m_vertexAttribValue[index]; - attribValue.type = Float32ArrayType; - attribValue.value.floatValue[0] = v0; - attribValue.value.floatValue[1] = v1; - attribValue.value.floatValue[2] = v2; - attribValue.value.floatValue[3] = v3; -} - -void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GLuint index, const DOMFloat32Array* v, GLsizei expectedSize) -{ - if (isContextLost()) - return; - if (!v) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); - return; - } - vertexAttribfvImpl(functionName, index, v->data(), v->length(), expectedSize); -} - -void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GLuint index, const GLfloat* v, GLsizei size, GLsizei expectedSize) -{ - if (isContextLost()) - return; - if (!v) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); - return; - } - if (size < expectedSize) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid size"); - return; - } - if (index >= m_maxVertexAttribs) { - synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range"); - return; - } - // In GL, we skip setting vertexAttrib0 values. - switch (expectedSize) { - case 1: - webContext()->vertexAttrib1fv(index, v); - break; - case 2: - webContext()->vertexAttrib2fv(index, v); - break; - case 3: - webContext()->vertexAttrib3fv(index, v); - break; - case 4: - webContext()->vertexAttrib4fv(index, v); - break; - } - VertexAttribValue& attribValue = m_vertexAttribValue[index]; - attribValue.initValue(); - attribValue.type = Float32ArrayType; - for (int ii = 0; ii < expectedSize; ++ii) - attribValue.value.floatValue[ii] = v[ii]; -} - void WebGLRenderingContextBase::dispatchContextLostEvent(Timer<WebGLRenderingContextBase>*) { RefPtrWillBeRawPtr<WebGLContextEvent> event = WebGLContextEvent::create(EventTypeNames::webglcontextlost, false, true, ""); @@ -6980,7 +6883,6 @@ visitor->trace(m_boundArrayBuffer); visitor->trace(m_defaultVertexArrayObject); visitor->trace(m_boundVertexArrayObject); - visitor->trace(m_vertexAttrib0Buffer); visitor->trace(m_currentProgram); visitor->trace(m_framebufferBinding); visitor->trace(m_renderbufferBinding);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h index 26b1f063..4ce5acc 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -291,18 +291,18 @@ void stencilOp(GLenum fail, GLenum zfail, GLenum zpass); void stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); - void texImage2D(GLenum target, GLint level, GLenum internalformat, + void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, DOMArrayBufferView*); - void texImage2D(GLenum target, GLint level, GLenum internalformat, + void texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, ImageData*); - void texImage2D(GLenum target, GLint level, GLenum internalformat, + void texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLImageElement*, ExceptionState&); - void texImage2D(GLenum target, GLint level, GLenum internalformat, + void texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLCanvasElement*, ExceptionState&); - void texImage2D(GLenum target, GLint level, GLenum internalformat, + void texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLVideoElement*, ExceptionState&); - void texImage2D(GLenum target, GLint level, GLenum internalformat, + void texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, PassRefPtrWillBeRawPtr<ImageBitmap>); void texParameterf(GLenum target, GLenum pname, GLfloat param); @@ -552,36 +552,9 @@ Uint32ArrayType, }; - class VertexAttribValue { - public: - VertexAttribValue() - : type(Float32ArrayType) - { - initValue(); - } - - void initValue() - { - value.floatValue[0] = 0.0f; - value.floatValue[1] = 0.0f; - value.floatValue[2] = 0.0f; - value.floatValue[3] = 1.0f; - } - - VertexAttribValueType type; - union { - GLfloat floatValue[4]; - GLint intValue[4]; - GLuint uintValue[4]; - } value; - }; - Vector<VertexAttribValue> m_vertexAttribValue; + Vector<VertexAttribValueType> m_vertexAttribType; unsigned m_maxVertexAttribs; - PersistentWillBeMember<WebGLBuffer> m_vertexAttrib0Buffer; - long m_vertexAttrib0BufferSize; - GLfloat m_vertexAttrib0BufferValue[4]; - bool m_forceAttrib0BufferRefill; - bool m_vertexAttrib0UsedBefore; + void setVertexAttribType(GLuint index, VertexAttribValueType); PersistentWillBeMember<WebGLProgram> m_currentProgram; PersistentWillBeMember<WebGLFramebuffer> m_framebufferBinding; @@ -835,14 +808,16 @@ // Convert texture internal format. GLenum convertTexInternalFormat(GLenum internalformat, GLenum type); - void texImage2DBase(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels); - void texImage2DImpl(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, Image*, WebGLImageConversion::ImageHtmlDomSource, bool flipY, bool premultiplyAlpha); + void texImage2DBase(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels); + void texImage2DImpl(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, Image*, WebGLImageConversion::ImageHtmlDomSource, bool flipY, bool premultiplyAlpha); void texSubImage2DBase(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); void texSubImage2DImpl(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, Image*, WebGLImageConversion::ImageHtmlDomSource, bool flipY, bool premultiplyAlpha); enum TexImageFunctionType { - NotTexSubImage, - TexSubImage + TexImage, + TexSubImage, + CopyTexImage, + CompressedTexImage }; enum TexImageByGPUType { TexImage2DByGPU, @@ -851,8 +826,8 @@ }; // Copy from the canvas element directly to the texture via the GPU, without a read-back to system memory. void texImageCanvasByGPU(TexImageByGPUType, WebGLTexture*, GLenum target, GLint level, - GLenum internalformat, GLenum type, GLint xoffset, GLint yoffset, GLint zoffset, HTMLCanvasElement*); - bool canUseTexImageCanvasByGPU(GLenum internalformat, GLenum type); + GLint internalformat, GLenum type, GLint xoffset, GLint yoffset, GLint zoffset, HTMLCanvasElement*); + bool canUseTexImageCanvasByGPU(GLint internalformat, GLenum type); void handleTextureCompleteness(const char*, bool); void createFallbackBlackTextures1x1(); @@ -884,7 +859,7 @@ // Helper function to check input internalformat/format/type for functions {copy}Tex{Sub}Image. // Generates GL error and returns false if parameters are invalid. - bool validateTexFuncFormatAndType(const char* functionName, GLenum internalformat, GLenum format, GLenum type, GLint level); + bool validateTexFuncFormatAndType(const char* functionName, TexImageFunctionType, GLenum internalformat, GLenum format, GLenum type, GLint level); // Helper function to check readbuffer validity for readPixels and copyTex{Sub}Image. // If yes, obtains the readbuffer's format, type, the bound read framebuffer, returns true. @@ -973,9 +948,6 @@ // the given format. bool validateCompressedTexSubDimensions(const char* functionName, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, WebGLTexture*); - // Helper function to validate mode for draw{Arrays/Elements}. - bool validateDrawMode(const char* functionName, GLenum); - // Helper function to validate if front/back stencilMask and stencilFunc settings are the same. bool validateStencilSettings(const char* functionName); @@ -1056,14 +1028,6 @@ // Helper function to validate drawElements(Instanced) calls bool validateDrawElements(const char* functionName, GLenum mode, GLsizei count, GLenum type, long long offset); - // Helper function to validate draw*Instanced calls - bool validateDrawInstanced(const char* functionName, GLsizei primcount); - - // Helper functions for vertexAttribNf{v}. - void vertexAttribfImpl(const char* functionName, GLuint index, GLsizei expectedSize, GLfloat, GLfloat, GLfloat, GLfloat); - void vertexAttribfvImpl(const char* functionName, GLuint index, const DOMFloat32Array*, GLsizei expectedSize); - void vertexAttribfvImpl(const char* functionName, GLuint index, const GLfloat*, GLsizei, GLsizei expectedSize); - // Helper functions to bufferData() and bufferSubData(). void bufferDataImpl(GLenum target, long long size, const void* data, GLenum usage); void bufferSubDataImpl(GLenum target, long long offset, GLsizeiptr, const void* data);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.idl b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.idl index cec3428f..16f62a8c 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.idl +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.idl
@@ -616,23 +616,23 @@ // FIXME: should be union type // https://www.khronos.org/bugzilla/show_bug.cgi?id=1172 void texImage2D( - GLenum target, GLint level, GLenum internalformat, + GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels); void texImage2D( - GLenum target, GLint level, GLenum internalformat, + GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, ImageData? pixels); [RaisesException] void texImage2D( - GLenum target, GLint level, GLenum internalformat, + GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLImageElement image); [RaisesException] void texImage2D( - GLenum target, GLint level, GLenum internalformat, + GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLCanvasElement canvas); [RaisesException] void texImage2D( - GLenum target, GLint level, GLenum internalformat, + GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLVideoElement video); [RuntimeEnabled=ExperimentalCanvasFeatures] void texImage2D( - GLenum target, GLint level, GLenum internalformat, + GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, ImageBitmap bitmap); void texSubImage2D(
diff --git a/third_party/WebKit/Source/platform/DEPS b/third_party/WebKit/Source/platform/DEPS index 24bc427..7c9df97 100644 --- a/third_party/WebKit/Source/platform/DEPS +++ b/third_party/WebKit/Source/platform/DEPS
@@ -2,6 +2,7 @@ "+base/json", "+base/location.h", "+base/memory", + "+base/sys_info.h", "+base/trace_event", "+base/values.h", "+mozilla",
diff --git a/third_party/WebKit/Source/platform/MemoryPurgeController.cpp b/third_party/WebKit/Source/platform/MemoryPurgeController.cpp index b75255b5..cecd16d8 100644 --- a/third_party/WebKit/Source/platform/MemoryPurgeController.cpp +++ b/third_party/WebKit/Source/platform/MemoryPurgeController.cpp
@@ -4,6 +4,7 @@ #include "platform/MemoryPurgeController.h" +#include "base/sys_info.h" #include "platform/TraceEvent.h" #include "public/platform/Platform.h" #include "wtf/Partitions.h" @@ -15,7 +16,7 @@ } MemoryPurgeController::MemoryPurgeController() - : m_deviceKind(Platform::current()->isLowEndDeviceMode() ? DeviceKind::LowEnd : DeviceKind::NotSpecified) + : m_deviceKind(base::SysInfo::IsLowEndDevice() ? DeviceKind::LowEnd : DeviceKind::NotSpecified) { }
diff --git a/third_party/WebKit/Source/platform/heap/Handle.h b/third_party/WebKit/Source/platform/heap/Handle.h index a585ac83..d340213 100644 --- a/third_party/WebKit/Source/platform/heap/Handle.h +++ b/third_party/WebKit/Source/platform/heap/Handle.h
@@ -223,7 +223,7 @@ TraceCallback traceCallback = TraceMethodDelegate<PersistentBase<T, weaknessConfiguration, crossThreadnessConfiguration>, &PersistentBase<T, weaknessConfiguration, crossThreadnessConfiguration>::trace>::trampoline; if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) { - m_persistentNode = ThreadState::crossThreadPersistentRegion().allocatePersistentNode(this, traceCallback); + m_persistentNode = Heap::crossThreadPersistentRegion().allocatePersistentNode(this, traceCallback); } else { ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); ASSERT(state->checkThread()); @@ -240,7 +240,7 @@ return; if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) { - ThreadState::crossThreadPersistentRegion().freePersistentNode(m_persistentNode); + Heap::crossThreadPersistentRegion().freePersistentNode(m_persistentNode); } else { ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); ASSERT(state->checkThread());
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp index 9c41a5a..4972af8 100644 --- a/third_party/WebKit/Source/platform/heap/Heap.cpp +++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -215,6 +215,12 @@ ASSERT(Heap::allocatedSpace() == 0); } +CrossThreadPersistentRegion& Heap::crossThreadPersistentRegion() +{ + DEFINE_THREAD_SAFE_STATIC_LOCAL(CrossThreadPersistentRegion, persistentRegion, new CrossThreadPersistentRegion()); + return persistentRegion; +} + #if ENABLE(ASSERT) BasePage* Heap::findPageFromAddress(Address address) {
diff --git a/third_party/WebKit/Source/platform/heap/Heap.h b/third_party/WebKit/Source/platform/heap/Heap.h index 4eee272..84753b2 100644 --- a/third_party/WebKit/Source/platform/heap/Heap.h +++ b/third_party/WebKit/Source/platform/heap/Heap.h
@@ -44,6 +44,7 @@ namespace blink { +class CrossThreadPersistentRegion; template<typename T> class Member; template<typename T> class WeakMember; template<typename T> class UntracedMember; @@ -76,6 +77,8 @@ static void shutdown(); static void doShutdown(); + static CrossThreadPersistentRegion& crossThreadPersistentRegion(); + #if ENABLE(ASSERT) static BasePage* findPageFromAddress(Address); static BasePage* findPageFromAddress(const void* pointer) { return findPageFromAddress(reinterpret_cast<Address>(const_cast<void*>(pointer))); }
diff --git a/third_party/WebKit/Source/platform/heap/PersistentNode.h b/third_party/WebKit/Source/platform/heap/PersistentNode.h index 338adf2b..f6ebddbfe 100644 --- a/third_party/WebKit/Source/platform/heap/PersistentNode.h +++ b/third_party/WebKit/Source/platform/heap/PersistentNode.h
@@ -13,6 +13,8 @@ namespace blink { +class CrossThreadPersistentRegion; + class PersistentNode final { public: PersistentNode()
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp index 4b07285..05b9138f 100644 --- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp +++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -275,7 +275,7 @@ // thread local GC. prepareForThreadStateTermination(); - ThreadState::crossThreadPersistentRegion().prepareForThreadStateTermination(this); + Heap::crossThreadPersistentRegion().prepareForThreadStateTermination(this); // Do thread local GC's as long as the count of thread local Persistents // changes and is above zero. @@ -315,7 +315,7 @@ void ThreadState::visitPersistentRoots(Visitor* visitor) { TRACE_EVENT0("blink_gc", "ThreadState::visitPersistentRoots"); - crossThreadPersistentRegion().tracePersistentNodes(visitor); + Heap::crossThreadPersistentRegion().tracePersistentNodes(visitor); for (ThreadState* state : attachedThreads()) state->visitPersistents(visitor); @@ -491,12 +491,6 @@ } } -CrossThreadPersistentRegion& ThreadState::crossThreadPersistentRegion() -{ - DEFINE_THREAD_SAFE_STATIC_LOCAL(CrossThreadPersistentRegion, persistentRegion, new CrossThreadPersistentRegion()); - return persistentRegion; -} - size_t ThreadState::totalMemorySize() { return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partitions::totalSizeOfCommittedPages();
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h index 2e8e081..b43767d 100644 --- a/third_party/WebKit/Source/platform/heap/ThreadState.h +++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -52,7 +52,6 @@ class BasePage; class CallbackStack; -class CrossThreadPersistentRegion; struct GCInfo; class GarbageCollectedMixinConstructorMarker; class HeapObjectHeader; @@ -368,7 +367,6 @@ // A region of PersistentNodes allocated on the given thread. PersistentRegion* persistentRegion() const { return m_persistentRegion.get(); } // A region of PersistentNodes not owned by any particular thread. - static CrossThreadPersistentRegion& crossThreadPersistentRegion(); // Visit local thread stack and trace all pointers conservatively. void visitStack(Visitor*);
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp index 4b35fb5..c119dbf 100644 --- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp +++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -927,7 +927,7 @@ LayoutBox* box = toLayoutBox(ownerElement->layoutObject()); - // Plugin frameRects are in absolute screen space. + // Plugin frameRects are in absolute space within their frame. IntRect frameRectInOwnerElementSpace = box->absoluteToLocalQuad(FloatRect(frameRect()), UseTransforms).enclosingBoundingBox(); LayoutRect unclippedAbsoluteRect(frameRectInOwnerElementSpace); @@ -945,8 +945,8 @@ clippedLocalRect.intersect(rootView->frameView()->visibleContentRect()); // TODO(chrishtr): intentionally ignore transform, because the positioning of frameRect() does also. This is probably wrong. - unclippedIntLocalRect = box->absoluteToLocalQuad(FloatRect(unclippedIntLocalRect)).enclosingBoundingBox(); - clippedLocalRect = box->absoluteToLocalQuad(FloatRect(clippedLocalRect)).enclosingBoundingBox(); + unclippedIntLocalRect = box->absoluteToLocalQuad(FloatRect(unclippedIntLocalRect), TraverseDocumentBoundaries).enclosingBoundingBox(); + clippedLocalRect = box->absoluteToLocalQuad(FloatRect(clippedLocalRect), TraverseDocumentBoundaries).enclosingBoundingBox(); } void WebPluginContainerImpl::calculateGeometry(IntRect& windowRect, IntRect& clipRect, IntRect& unobscuredRect, Vector<IntRect>& cutOutRects) @@ -965,4 +965,4 @@ cutOutRects[i].move(-frameRect().x(), -frameRect().y()); } -} // namespace blinkf +} // namespace blink
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.h b/third_party/WebKit/Source/web/WebPluginContainerImpl.h index 5d2dbb4e..c765b3a 100644 --- a/third_party/WebKit/Source/web/WebPluginContainerImpl.h +++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
@@ -191,6 +191,8 @@ const IntRect& frameRect, Vector<IntRect>& cutOutRects); + friend class WebPluginContainerTest; + RawPtrWillBeMember<HTMLPlugInElement> m_element; WebPlugin* m_webPlugin;
diff --git a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp index 29aff42..4a8440f 100644 --- a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
@@ -72,6 +72,11 @@ Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); } + void calculateGeometry(WebPluginContainerImpl* pluginContainerImpl, IntRect& windowRect, IntRect& clipRect, IntRect& unobscuredRect, Vector<IntRect>& cutOutRects) + { + pluginContainerImpl->calculateGeometry(windowRect, clipRect, unobscuredRect, cutOutRects); + } + protected: std::string m_baseURL; }; @@ -402,6 +407,46 @@ EXPECT_FALSE(pluginContainerImpl->isRectTopmost(rect)); } +#define EXPECT_RECT_EQ(expected, actual) \ + do { \ + const IntRect& actualRect = actual; \ + EXPECT_EQ(expected.x(), actualRect.x()); \ + EXPECT_EQ(expected.y(), actualRect.y()); \ + EXPECT_EQ(expected.width(), actualRect.width()); \ + EXPECT_EQ(expected.height(), actualRect.height()); \ + } while (false) + +TEST_F(WebPluginContainerTest, ClippedRectsForIframedElement) +{ + URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("plugin_container.html")); + URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("plugin_containing_page.html")); + + TestPluginWebFrameClient pluginWebFrameClient; // Must outlive webViewHelper. + FrameTestHelpers::WebViewHelper webViewHelper; + WebView* webView = webViewHelper.initializeAndLoad(m_baseURL + "plugin_containing_page.html", true, &pluginWebFrameClient); + ASSERT(webView); + webView->settings()->setPluginsEnabled(true); + webView->resize(WebSize(300, 300)); + webView->updateAllLifecyclePhases(); + runPendingTasks(); + + WebElement pluginElement = webView->mainFrame()->firstChild()->document().getElementById("translated-plugin"); + RefPtrWillBeRawPtr<WebPluginContainerImpl> pluginContainerImpl = toWebPluginContainerImpl(pluginElement.pluginContainer()); + + ASSERT(pluginContainerImpl.get()); + pluginContainerImpl->setFrameRect(IntRect(0, 0, 300, 300)); + + IntRect windowRect, clipRect, unobscuredRect; + Vector<IntRect> cutOutRects; + calculateGeometry(pluginContainerImpl.get(), windowRect, clipRect, unobscuredRect, cutOutRects); + EXPECT_RECT_EQ(IntRect(10, 210, 300, 300), windowRect); + EXPECT_RECT_EQ(IntRect(0, 0, 240, 90), clipRect); + EXPECT_RECT_EQ(IntRect(0, 0, 240, 160), unobscuredRect); + + // Cause the plugin's frame to be detached. + webViewHelper.reset(); +} + TEST_F(WebPluginContainerTest, TopmostAfterDetachTest) { static WebRect topmostRect(10, 10, 40, 40);
diff --git a/third_party/WebKit/Source/web/tests/data/plugin_containing_page.html b/third_party/WebKit/Source/web/tests/data/plugin_containing_page.html new file mode 100644 index 0000000..a8765ad --- /dev/null +++ b/third_party/WebKit/Source/web/tests/data/plugin_containing_page.html
@@ -0,0 +1,3 @@ +<!doctype HTML> +<div style="width: 200px; height: 200px"></div> +<iframe src="plugin_container.html" height="160" width="240"></iframe>
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h index b92cc9f1..ecf0d22 100644 --- a/third_party/WebKit/public/platform/Platform.h +++ b/third_party/WebKit/public/platform/Platform.h
@@ -272,9 +272,6 @@ // zero, if there is no limit. virtual size_t virtualMemoryLimitMB() { return 0; } - // True when Blink runs on low end devices. - virtual bool isLowEndDeviceMode() { return false; } - // Return the number of of processors of the current machine. virtual size_t numberOfProcessors() { return 0; }
diff --git a/third_party/kasko/BUILD.gn b/third_party/kasko/BUILD.gn index bedcb1d..2d06fe09 100644 --- a/third_party/kasko/BUILD.gn +++ b/third_party/kasko/BUILD.gn
@@ -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("//build/config/features.gni") +import("//build/buildflag_header.gni") import("//build/config/sanitizers/sanitizers.gni") declare_args() { @@ -13,6 +13,15 @@ enable_kasko_hang_reports = false } +# GYP version: target 'kasko_features' in third_party/kasko/kasko.gyp +buildflag_header("kasko_features") { + header = "kasko_features.h" + flags = [ + "ENABLE_KASKO=$enable_kasko", + "ENABLE_KASKO_HANG_REPORTS=$enable_kasko_hang_reports", + ] +} + if (enable_kasko) { assert(is_win, "Kasko only support Windows.") assert(target_cpu == "x86", "Kasko only support 32 bits.") @@ -21,15 +30,12 @@ config("kasko_config") { visibility = [ ":*" ] - defines = [ "KASKO" ] - if (enable_kasko_hang_reports) { - defines += [ "KASKO_HANG_REPORTS" ] - } include_dirs = [ "//third_party/kasko/binaries/include" ] lib_dirs = [ "//third_party/kasko/binaries" ] libs = [ "kasko.dll.lib" ] } + # GYP version: target 'copy_kasko_dll' in third_party/kasko/kasko.gyp copy("copy_kasko_dll") { visibility = [ ":*" ] sources = [ @@ -41,15 +47,18 @@ ] } + # GYP version: target 'kasko' in third_party/kasko/kasko.gyp group("kasko") { - if (enable_kasko) { - deps = [ - ":copy_kasko_dll", - ] - public_configs = [ ":kasko_config" ] - } + public_deps = [ + ":copy_kasko_dll", + ":kasko_features", + ] + public_configs = [ ":kasko_config" ] } } else { group("kasko") { + public_deps = [ + ":kasko_features", + ] } }
diff --git a/third_party/kasko/kasko.gyp b/third_party/kasko/kasko.gyp new file mode 100644 index 0000000..1d1162d43 --- /dev/null +++ b/third_party/kasko/kasko.gyp
@@ -0,0 +1,79 @@ +{ + 'targets': [ + { + # GN: //third_party/kasko:kasko_features + 'target_name': 'kasko_features', + 'type': 'none', + 'includes': [ '../../build/buildflag_header.gypi' ], + 'variables': { + 'buildflag_header_path': 'third_party/kasko/kasko_features.h', + 'buildflag_flags': [ + 'ENABLE_KASKO=<(kasko)', + 'ENABLE_KASKO_HANG_REPORTS=<(kasko_hang_reports)', + ], + }, + }, + ], + 'conditions': [ + ['kasko==1', { + 'targets': [ + { + # GN: //third_party/kasko:copy_kasko_dll + 'target_name': 'copy_kasko_dll', + 'type': 'none', + 'variables': { + 'kasko_exe_dir': '<(DEPTH)/third_party/kasko/binaries', + }, + 'outputs': [ + '<(PRODUCT_DIR)/kasko.dll', + '<(PRODUCT_DIR)/kasko.dll.pdb', + ], + 'copies': [ + { + 'destination': '<(PRODUCT_DIR)', + 'files': [ + '<(kasko_exe_dir)/kasko.dll', + '<(kasko_exe_dir)/kasko.dll.pdb', + ], + }, + ], + }, + { + # GN: //third_party/kasko + 'target_name': 'kasko', + 'type': 'none', + 'dependencies': [ + 'copy_kasko_dll', + 'kasko_features', + ], + 'direct_dependent_settings': { + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalDependencies': [ + 'kasko.dll.lib', + ], + 'AdditionalLibraryDirectories': [ + '../third_party/kasko/binaries' + ], + }, + }, + 'include_dirs': [ + '../../third_party/kasko/binaries/include', + ], + }, + }, + ], + }, { # 'kasko==0' + 'targets': [ + { + # GN: //third_party/kasko + 'target_name': 'kasko', + 'type': 'none', + 'dependencies': [ + 'kasko_features', + ], + }, + ], + }], + ], # 'conditions' +}
diff --git a/tools/OWNERS b/tools/OWNERS index c5c14ce..d67c47a 100644 --- a/tools/OWNERS +++ b/tools/OWNERS
@@ -42,7 +42,9 @@ per-file remove_stale_pyc_files.py=dtu@chromium.org +per-file roll_angle.py=kbr@chromium.org per-file roll_angle.py=kjellander@chromium.org +per-file roll_angle.py=geofflang@chromium.org per-file roll_webrtc.py=kjellander@chromium.org per-file safely-roll-deps.py=borenet@chromium.org
diff --git a/tools/auto_bisect/fetch_build.py b/tools/auto_bisect/fetch_build.py index 7a2d8b24..565c2e7 100644 --- a/tools/auto_bisect/fetch_build.py +++ b/tools/auto_bisect/fetch_build.py
@@ -22,7 +22,10 @@ import sys import zipfile -# Telemetry (src/tools/telemetry) is expected to be in the PYTHONPATH. +_CATAPULT_BASE_PATH = os.path.abspath(os.path.join( + __file__, '..', '..', 'third_party', 'catapult', 'catapult_base')) +if _CATAPULT_BASE_PATH not in sys.path: + sys.path.insert(1, _CATAPULT_BASE_PATH) from catapult_base import cloud_storage import bisect_utils
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py index 54482a39..4346629 100755 --- a/tools/checklicenses/checklicenses.py +++ b/tools/checklicenses/checklicenses.py
@@ -119,7 +119,7 @@ ], 'buildtools/third_party/libc++/trunk/test': [ - # http://llvm.org/bugs/show_bug.cgi?id=18291 + # http://llvm.org/bugs/show_bug.cgi?id=25980 'UNKNOWN', ], # http://llvm.org/bugs/show_bug.cgi?id=25976 @@ -194,11 +194,6 @@ ], # http://crbug.com/333508 - 'third_party/clang_format/script': [ - 'UNKNOWN', - ], - - # http://crbug.com/333508 'buildtools/clang_format/script': [ 'UNKNOWN', ], @@ -220,27 +215,18 @@ 'third_party/catapult/third_party/apiclient': [ 'UNKNOWN', ], - 'third_party/catapult/dashboard/third_party/apiclient': [ - 'UNKNOWN', - ], # https://bugs.launchpad.net/beautifulsoup/+bug/1481316 # MIT license. 'third_party/catapult/third_party/beautifulsoup': [ 'UNKNOWN' ], - 'third_party/catapult/dashboard/third_party/beautifulsoup': [ - 'UNKNOWN' - ], # https://code.google.com/p/graphy/issues/detail?id=6 # Apache (v2.0) 'third_party/catapult/third_party/graphy': [ 'UNKNOWN', ], - 'third_party/catapult/dashboard/third_party/graphy': [ - 'UNKNOWN', - ], # https://github.com/GoogleCloudPlatform/gsutil/issues/305 ('third_party/catapult/third_party/gsutil/gslib/third_party/' @@ -297,6 +283,7 @@ ], # https://bitbucket.org/gutworth/six/issues/137/please-add-per-file-licenses + # Already fixed upstream. https://crbug.com/573341 'third_party/catapult/third_party/gsutil/third_party/six': [ 'UNKNOWN', ], @@ -307,77 +294,41 @@ 'UNKNOWN', ], - # https://github.com/jcgregorio/httplib2/issues/307 - # MIT license. - 'third_party/catapult/third_party/httplib2': [ - 'UNKNOWN', - ], - 'third_party/catapult/dashboard/third_party/httplib2': [ - 'UNKNOWN', - ], - # https://github.com/GoogleCloudPlatform/appengine-mapreduce/issues/71 # Apache (v2.0) 'third_party/catapult/third_party/mapreduce': [ 'UNKNOWN', ], - 'third_party/catapult/dashboard/third_party/mapreduce': [ - 'UNKNOWN', - ], # https://code.google.com/p/webapp-improved/issues/detail?id=103 # Apache (v2.0). 'third_party/catapult/third_party/webapp2': [ 'UNKNOWN', ], - 'third_party/catapult/dashboard/third_party/webapp2': [ - 'UNKNOWN', - ], # https://github.com/Pylons/webob/issues/211 # MIT license. 'third_party/catapult/third_party/WebOb': [ 'UNKNOWN', ], - 'third_party/catapult/dashboard/third_party/WebOb': [ - 'UNKNOWN', - ], # https://github.com/Pylons/webtest/issues/141 # MIT license. 'third_party/catapult/third_party/webtest': [ 'UNKNOWN', ], - 'third_party/catapult/dashboard/third_party/webtest': [ - 'UNKNOWN', - ], # https://bitbucket.org/ianb/paste/issues/12/add-license-headers-to-source-files # MIT license. 'third_party/catapult/third_party/Paste': [ 'UNKNOWN', ], - 'third_party/catapult/dashboard/third_party/Paste': [ - 'UNKNOWN', - ], - - # https://github.com/google/oauth2client/issues/231 - # Apache v2.0. - 'third_party/catapult/third_party/oauth2client': [ - 'UNKNOWN', - ], - 'third_party/catapult/dashboard/third_party/oauth2client': [ - 'UNKNOWN', - ], # https://bitbucket.org/gutworth/six/issues/129/add-license-headers-to-source-files # MIT license. 'third_party/catapult/third_party/six': [ 'UNKNOWN', ], - 'third_party/catapult/dashboard/third_party/six': [ - 'UNKNOWN', - ], 'third_party/expat/files/lib': [ # http://crbug.com/98121 'UNKNOWN', @@ -413,6 +364,9 @@ 'UNKNOWN', ], 'third_party/junit/src': [ + # Pulled in via DEPS for Android only. + # Eclipse Public License / not shipped. + # Bug filed but upstream prefers not to fix. # https://github.com/junit-team/junit/issues/1132 'UNKNOWN', ], @@ -438,10 +392,6 @@ 'UNKNOWN', ], - 'third_party/libpng': [ # http://crbug.com/98318 - 'UNKNOWN', - ], - # The following files lack license headers, but are trivial. 'third_party/libusb/src/libusb/os/poll_posix.h': [ 'UNKNOWN', @@ -475,18 +425,12 @@ 'third_party/openmax_dl/dl' : [ 'Khronos Group', ], - 'third_party/openssl': [ # http://crbug.com/98451 - 'UNKNOWN', - ], 'third_party/boringssl': [ # There are some files in BoringSSL which came from OpenSSL and have no # license in them. We don't wish to add the license header ourselves # thus we don't expect to pass license checks. 'UNKNOWN', ], - 'third_party/ots/tools/ttf-checksum.py': [ # http://code.google.com/p/ots/issues/detail?id=2 - 'UNKNOWN', - ], 'third_party/molokocacao': [ # http://crbug.com/98453 'UNKNOWN', ], @@ -560,6 +504,17 @@ 'UNKNOWN', ], + # BSD License. http://bugzilla.maptools.org/show_bug.cgi?id=2532 + 'third_party/pdfium/third_party/libtiff/tif_ojpeg.c': [ + 'UNKNOWN', + ], + 'third_party/pdfium/third_party/libtiff/tiffvers.h': [ + 'UNKNOWN', + ], + 'third_party/pdfium/third_party/libtiff/uvcode.h': [ + 'UNKNOWN', + ], + 'third_party/talloc': [ 'GPL (v3 or later)', 'UNKNOWN', # http://crbug.com/98588 @@ -627,12 +582,6 @@ # https://sourceforge.net/p/pyserial/feature-requests/35/ 'UNKNOWN', ], - 'v8/test/cctest': [ # http://crbug.com/98597 - 'UNKNOWN', - ], - 'v8/src/third_party/kernel/tools/perf/util/jitdump.h': [ # http://crbug.com/391716 - 'UNKNOWN', - ], } EXCLUDED_PATHS = [
diff --git a/tools/checkperms/checkperms.py b/tools/checkperms/checkperms.py index d264ddaf..81b0f4f0 100755 --- a/tools/checkperms/checkperms.py +++ b/tools/checkperms/checkperms.py
@@ -302,9 +302,8 @@ try: bit = has_executable_bit(full_path) except OSError: - # It's faster to catch exception than call os.path.islink(). Chromium - # tree happens to have invalid symlinks under - # third_party/openssl/openssl/test/. + # It's faster to catch exception than call os.path.islink(). The Chromium + # tree may have invalid symlinks. return None if must_be_executable(rel_path):
diff --git a/tools/chrome_proxy/chrome_proxy_config.py b/tools/chrome_proxy/chrome_proxy_config.py index 35846e8c..0b58413 100644 --- a/tools/chrome_proxy/chrome_proxy_config.py +++ b/tools/chrome_proxy/chrome_proxy_config.py
@@ -11,6 +11,8 @@ _top_level_dir = os.path.dirname(os.path.realpath(__file__)) -CONFIG = chromium_config.ChromiumConfig( - top_level_dir=_top_level_dir, - benchmark_dirs=[os.path.join(_top_level_dir, 'integration_tests')]) +def Config(benchmark_subdirs): + return chromium_config.ChromiumConfig( + top_level_dir=_top_level_dir, + benchmark_dirs=[os.path.join(_top_level_dir, subdir) + for subdir in benchmark_subdirs])
diff --git a/tools/chrome_proxy/run_benchmark b/tools/chrome_proxy/run_benchmark index e6bcbde..1fac51589 100755 --- a/tools/chrome_proxy/run_benchmark +++ b/tools/chrome_proxy/run_benchmark
@@ -14,4 +14,5 @@ if __name__ == '__main__': - sys.exit(benchmark_runner.main(chrome_proxy_config.CONFIG)) + sys.exit(benchmark_runner.main(chrome_proxy_config.Config( + ['integration_tests'])))
diff --git a/tools/chrome_proxy/run_livetests b/tools/chrome_proxy/run_livetests index 6c177719..2d98fe0 100755 --- a/tools/chrome_proxy/run_livetests +++ b/tools/chrome_proxy/run_livetests
@@ -7,14 +7,11 @@ import sys sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'telemetry')) -sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'perf')) from telemetry import benchmark_runner +import chrome_proxy_config if __name__ == '__main__': - top_level_dir = os.path.dirname(os.path.realpath(__file__)) - config = benchmark_runner.ProjectConfig( - top_level_dir=top_level_dir, - benchmark_dirs=[os.path.join(top_level_dir, 'live_tests')]) - sys.exit(benchmark_runner.main(config)) + sys.exit(benchmark_runner.main(chrome_proxy_config.Config( + ['live_tests'])))
diff --git a/tools/chrome_proxy/run_tests b/tools/chrome_proxy/run_tests index 027a323..6abd3fa 100755 --- a/tools/chrome_proxy/run_tests +++ b/tools/chrome_proxy/run_tests
@@ -19,4 +19,5 @@ if __name__ == '__main__': - sys.exit(unittest_runner.Run(chrome_proxy_config.CONFIG)) + sys.exit(unittest_runner.Run(chrome_proxy_config.Config(['integration_tests', + 'live_tests'])))
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 888c1ff..5303c257 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -1900,7 +1900,7 @@ <description>A renderer process died abnormally.</description> </action> -<action name="BrowserPlugin.Guest.Attached"> +<action name="BrowserPlugin.Guest.Attached" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -1910,12 +1910,12 @@ <description>A renderer process died because it crashed.</description> </action> -<action name="BrowserPlugin.Guest.Create"> +<action name="BrowserPlugin.Guest.Create" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> -<action name="BrowserPlugin.Guest.DidNavigate"> +<action name="BrowserPlugin.Guest.DidNavigate" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -1940,7 +1940,7 @@ <description>A renderer process failed to launch.</description> </action> -<action name="BrowserPlugin.Guest.Navigate"> +<action name="BrowserPlugin.Guest.Navigate" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -13488,7 +13488,7 @@ <description>Please enter the description of this user action.</description> </action> -<action name="WebView.WebRequest.AddListener"> +<action name="WebView.WebRequest.AddListener" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 621ef5a0..d5efe4f 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -4857,6 +4857,24 @@ </summary> </histogram> +<histogram + name="Compositing.Browser.RenderPass.AppendQuadData.NumMissingTilesNoImageContent"> + <owner>vollick@chromium.org</owner> + <summary> + Tracks the number of missing tiles that had some image content in the + browser process. + </summary> +</histogram> + +<histogram + name="Compositing.Browser.RenderPass.AppendQuadData.NumMissingTilesSomeImageContent"> + <owner>vollick@chromium.org</owner> + <summary> + Tracks the number of missing tiles that did not have any image content in + the browser process. + </summary> +</histogram> + <histogram name="Compositing.CopyFromSurfaceTime" units="ms"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary> @@ -5051,6 +5069,24 @@ </histogram> <histogram + name="Compositing.Renderer.RenderPass.AppendQuadData.NumMissingTilesNoImageContent"> + <owner>vollick@chromium.org</owner> + <summary> + Tracks the number of missing tiles that had some image content in the + renderer process. + </summary> +</histogram> + +<histogram + name="Compositing.Renderer.RenderPass.AppendQuadData.NumMissingTilesSomeImageContent"> + <owner>vollick@chromium.org</owner> + <summary> + Tracks the number of missing tiles that did not have any image content in + the renderer process. + </summary> +</histogram> + +<histogram name="Compositing.RenderPass.AppendQuadData.CheckerboardedNeedRasterContentArea" units="pixels/frame"> <owner>weiliangc@chromium.org</owner> @@ -11879,20 +11915,41 @@ </summary> </histogram> +<histogram name="Extensions.Database.Database.Restore" + enum="LevelDBDatabaseCorruptionRestoreValue"> + <owner>cmumford@chromium.org</owner> + <summary> + The result of an attempt to recover from an attempt to open a database that + failed as a result of corruption. + </summary> +</histogram> + <histogram name="Extensions.Database.Open" enum="LevelDBStatus"> <owner>cmumford@chromium.org</owner> <summary>The result of an open attempt to an Extensions database.</summary> </histogram> <histogram name="Extensions.Database.Restore" - enum="LevelDBCorruptionRestoreValue"> + enum="LevelDBDatabaseCorruptionRestoreValue"> <owner>cmumford@chromium.org</owner> + <obsolete> + Shipped only in M48. Superceded by Extensions.Database.Database.Restore and + Extensions.Database.Value.Restore. + </obsolete> <summary> The result of an attempt to recover from an attempt to open a database that failed as a result of corruption. </summary> </histogram> +<histogram name="Extensions.Database.Value.Restore" + enum="LevelDBValueCorruptionDeleteValue"> + <owner>cmumford@chromium.org</owner> + <summary> + The result of an attempt to delete a corrupted value from a database. + </summary> +</histogram> + <histogram name="Extensions.DeclarativeRulesStorageInitialization" units="milliseconds"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> @@ -15035,6 +15092,12 @@ <summary>The display type used to ask for an EGLDisplay.</summary> </histogram> +<histogram name="GPU.Error" enum="GLError"> + <owner>junov@chromium.org</owner> + <owner>piman@chromium.org</owner> + <summary>The error states generated by OpenGL calls.</summary> +</histogram> + <histogram name="GPU.FenceSupport" enum="BooleanAvailable"> <owner>reveman@chromium.org</owner> <summary> @@ -18453,6 +18516,14 @@ </summary> </histogram> +<histogram name="Media.AvdaCodecImage.WaitTimeForFrame" units="milliseconds"> + <owner>liberato@chromium.org</owner> + <summary> + Time spent waiting for a frame to become available in a SurfaceTexture after + requesting that MediaCodec renders it. + </summary> +</histogram> + <histogram name="Media.CacheUseful" enum="BooleanSuccess"> <owner>scherkus@chromium.org</owner> <summary> @@ -38353,6 +38424,14 @@ </summary> </histogram> +<histogram name="Quota.DaysSinceLastAccess" units="days"> + <owner>michaeln@chromium.org</owner> + <summary> + The number of days since an origin's data was last accessed. Logged upon + access when the time since last access is at least 24 hours. + </summary> +</histogram> + <histogram name="Quota.DiskspaceShortage" units="MB"> <owner>tzik@chromium.org</owner> <summary> @@ -38506,6 +38585,14 @@ <summary>Time spent to an eviction round.</summary> </histogram> +<histogram name="Quota.TimeToInitializeGlobalQuota" units="milliseconds"> + <owner>michaeln@chromium.org</owner> + <summary> + Time spent initializing the global quota. Logged when the storage + partition's quota manager is initialized. + </summary> +</histogram> + <histogram name="Quota.TotalDiskSpace" units="MB"> <owner>micaheln@chromium.org</owner> <summary> @@ -59419,7 +59506,7 @@ <int value="8" label="Arrived at settings menu by another path: entered on, exited on"/> <int value="9" label="Enabled directly from the First Run Experience"/> - <int value="10" label="Diabled directly from the First Run Experience"/> + <int value="10" label="Disabled directly from the First Run Experience"/> </enum> <enum name="DataUsageReportSubmissionResult" type="int"> @@ -66386,6 +66473,15 @@ <int value="6" label="UNSET"/> </enum> +<enum name="GLError" type="int"> + <int value="0" label="0x0000 - GL_NO_ERROR"/> + <int value="1280" label="0x0500 - GL_INVALID_ENUM"/> + <int value="1281" label="0x0501 - GL_INVALID_VALUE"/> + <int value="1282" label="0x0502 - GL_INVALID_OPERATION"/> + <int value="1285" label="0x0505 - GL_OUT_OF_MEMORY"/> + <int value="1286" label="0x0506 - GL_INVALID_FRAMEBUFFER_OPERATION"/> +</enum> + <enum name="GoogleCaptchaEvent" type="int"> <int value="0" label="Google CAPTCHA shown"/> <int value="1" label="Google CAPTCHA solved"/> @@ -67605,6 +67701,7 @@ <int value="319509360" label="xkb:be::ger">Belgian keyboard</int> <int value="382485416" label="xkb:lv:apostrophe:lav">Latvian keyboard</int> <int value="398887705" label="ti-t-i0-und">Tigrinya transliteration</int> + <int value="400837283" label="yue-hant-t-i0-und">Cantonese input method</int> <int value="414827905" label="vkd_ta_typewriter"> Tamil keyboard (Typewriter) </int> @@ -68576,9 +68673,9 @@ </enum> <enum name="LevelDBCorruptionRestoreValue" type="int"> - <int value="0" label="Delete Success"/> - <int value="1" label="Delete Failure"/> - <int value="2" label="Repair Success"/> + <int value="0" label="Database Delete Success"/> + <int value="1" label="Database Delete Failure"/> + <int value="2" label="Database Repair Success"/> </enum> <enum name="LevelDBCorruptionTypes" type="int"> @@ -68616,6 +68713,12 @@ <int value="31" label="file is too short"/> </enum> +<enum name="LevelDBDatabaseCorruptionRestoreValue" type="int"> + <int value="0" label="Delete Success"/> + <int value="1" label="Delete Failure"/> + <int value="2" label="Repair Success"/> +</enum> + <enum name="LevelDBErrorCount" type="int"> <int value="1" label="Failure"/> </enum> @@ -68661,6 +68764,11 @@ <int value="5" label="IO Error"/> </enum> +<enum name="LevelDBValueCorruptionDeleteValue" type="int"> + <int value="0" label="Delete Success"/> + <int value="1" label="Delete Failure"/> +</enum> + <enum name="LibraryLoadFromApkStatus" type="int"> <int value="0" label="Unknown"/> <int value="1" label="Not supported">obsolete</int> @@ -81749,6 +81857,12 @@ <affected-histogram name="PLT.PT_StartToFinish"/> </histogram_suffixes> +<histogram_suffixes name="GLApisWithErrorReporting"> + <suffix name="TexImage2D" label="All GL APIs that allocate a 2D texture."/> + <suffix name="TexImage3D" label="All GL APIs that allocate a 3D texture."/> + <affected-histogram name="GPU.Error"/> +</histogram_suffixes> + <histogram_suffixes name="GlobalSdch"> <suffix name="global_disable_sdch" label="with SDCH completely disabled"/> <suffix name="global_enable_sdch"
diff --git a/tools/perf/docs/perf_bot_sheriffing.md b/tools/perf/docs/perf_bot_sheriffing.md index 89290d9..99cee30 100644 --- a/tools/perf/docs/perf_bot_sheriffing.md +++ b/tools/perf/docs/perf_bot_sheriffing.md
@@ -21,16 +21,17 @@ Everyone can view the chromium.perf waterfall at https://build.chromium.org/p/chromium.perf/, but for Googlers it is recommended that you use the url -**https://uberchromegw.corp.google.com/i/chromium.perf/** instead. The reason for -this is that in order to make the performance tests as realistic as possible, -the chromium.perf waterfall runs release official builds of Chrome. But the -logs from release official builds may leak info from our partners that we do -not have permission to share outside of Google. So the logs are available to -Googlers only. +**https://uberchromegw.corp.google.com/i/chromium.perf/** instead. The reason +for this is that in order to make the performance tests as realistic as +possible, the chromium.perf waterfall runs release official builds of Chrome. +But the logs from release official builds may leak info from our partners that +we do not have permission to share outside of Google. So the logs are available +to Googlers only. Note that there are four different views: - 1. [Console view](https://uberchromegw.corp.google.com/i/chromium.perf/) makes - it easier to see a summary. + + 1. [Console view](https://uberchromegw.corp.google.com/i/chromium.perf/) + makes it easier to see a summary. 2. [Waterfall view](https://uberchromegw.corp.google.com/i/chromium.perf/waterfall) shows more details, including recent changes. 3. [Firefighter](https://chromiumperfstats.appspot.com/) shows traces of @@ -40,7 +41,8 @@ "Android Nexus5 Perf (2)" * **start_time** is seconds since the epoch. -You can see a list of all previously filed bugs using the **[Performance-Waterfall](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-Waterfall)** +You can see a list of all previously filed bugs using the +**[Performance-BotHealth](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth)** label in crbug. Please also check the recent @@ -52,13 +54,16 @@ You want to keep the waterfall green! So any bot that is red or purple needs to be investigated. When a test fails: -1. File a bug using [this template](https://code.google.com/p/chromium/issues/entry?labels=Performance-Waterfall,Performance-Sheriff,Pri-1,Type-Bug-Regression,OS-?&comment=Revision+range+first+seen:%0ALink+to+failing+step+log:%0A%0A%0AIf%20the%20test%20is%20disabled,%20please%20downgrade%20to%20Pri-2.&summary=%3Ctest%3E+failure+on+chromium.perf+at+%3Crevisionrange%3E). +1. File a bug using + [this template](https://code.google.com/p/chromium/issues/entry?labels=Performance-BotHealth,Pri-1,Type-Bug-Regression,OS-?&comment=Revision+range+first+seen:%0ALink+to+failing+step+log:%0A%0A%0AIf%20the%20test%20is%20disabled,%20please%20downgrade%20to%20Pri-2.&summary=%3Ctest%3E+failure+on+chromium.perf+at+%3Crevisionrange%3E). You'll want to be sure to include: * Link to buildbot status page of failing build. * Copy and paste of relevant failure snippet from the stdio. - * CC the test owner from [go/perf-owners](https://docs.google.com/spreadsheets/d/1R_1BAOd3xeVtR0jn6wB5HHJ2K25mIbKp3iIRQKkX38o/edit#gid=0). + * CC the test owner from + [go/perf-owners](https://docs.google.com/spreadsheets/d/1R_1BAOd3xeVtR0jn6wB5HHJ2K25mIbKp3iIRQKkX38o/edit#gid=0). * The revision range the test occurred on. * A list of all platforms the test fails on. + 2. Disable the failing test if it is failing more than one out of five runs. (see below for instructions on telemetry and other types of tests). Make sure your disable cl includes a BUG= line with the bug from step 1 and the test @@ -78,6 +83,11 @@ 3. Type the **Bug ID** from step 1, the **Good Revision** the last commit pos data was received from, the **Bad Revision** the last commit pos and set **Bisect mode** to `return_code`. + * On Android and Mac, you can view platform-level screenshots of the device + screen for failing tests, links to which are printed in the logs. Often + this will immediately reveal failure causes that are opaque from the logs + alone. On other platforms, Devtools will produce tab screenshots as long as + the tab did not crash. #####<a name="telemetryfailures"></a> Disabling Telemetry Tests @@ -134,7 +144,7 @@ If the bot goes purple and you believe it's an infrastructure issue, file a bug with -[this template](https://code.google.com/p/chromium/issues/entry?labels=Pri-1,Performance-Waterfall,Performance-Sheriff,Infra-Troopers,OS-?&comment=Link+to+buildbot+status+page:&summary=Purple+Bot+on+chromium.perf), +[this template](https://code.google.com/p/chromium/issues/entry?labels=Pri-1,Performance-BotHealth,Infra-Troopers,OS-?&comment=Link+to+buildbot+status+page:&summary=Purple+Bot+on+chromium.perf), which will automatically add the bug to the trooper queue. Be sure to note which step is failing, and paste any relevant info from the logs into the bug. @@ -152,26 +162,26 @@ with the same device affinity number are failing, it's probably a device failure. -For both types of failures, please file a bug with [this template](https://code.google.com/p/chromium/issues/entry?labels=Pri-1,Performance-Waterfall,Performance-Sheriff,Infra-Labs,OS-Android&comment=Link+to+buildbot+status+page:&summary=Device+offline+on+chromium.perf) +For both types of failures, please file a bug with [this template](https://code.google.com/p/chromium/issues/entry?labels=Pri-1,Performance-BotHealth,Infra-Labs,OS-Android&comment=Link+to+buildbot+status+page:&summary=Device+offline+on+chromium.perf) which will add an issue to the infra labs queue. ####<a name="followup"></a> Follow up on failures -**[Pri-0 bugs](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-Waterfall+label%3APri-0)** +**[Pri-0 bugs](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth+label%3APri-0)** should have an owner or contact on speed infra team and be worked on as top priority. Pri-0 generally implies an entire waterfall is down. -**[Pri-1 bugs](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-Waterfall+label%3APri-1)** +**[Pri-1 bugs](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth+label%3APri-1)** should be pinged daily, and checked to make sure someone is following up. Pri-1 bugs are for a red test (not yet disabled), purple bot, or failing device. -**[Pri-2 bugs](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-Waterfall+label%3APri-2)** +**[Pri-2 bugs](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth+label%3APri-2)** are for disabled tests. These should be pinged weekly, and work towards fixing should be ongoing when the sheriff is not working on a Pri-1 issue. Here is the -[list of Pri-2 bugs that have not been pinged in a week](https://code.google.com/p/chromium/issues/list?can=2&q=label:Performance-Waterfall%20label:Pri-2%20modified-before:today-7&sort=modified) +[list of Pri-2 bugs that have not been pinged in a week](https://code.google.com/p/chromium/issues/list?can=2&q=label:Performance-BotHealth%20label:Pri-2%20modified-before:today-7&sort=modified) If you need help triaging, here are the common labels you should use: - * **Performance-Waterfall** should go on all bugs you file about the bots, + * **Performance-BotHealth** should go on all bugs you file about the bots; it's the label we use to track all the issues. * **Infra-Troopers** adds the bug to the trooper queue. This is for high priority issues, like a build breakage. Please add a comment explaining @@ -232,4 +242,4 @@ 3. Do we use sheriff-o-matic? 4. Should we add some list of bugs that bot sheriffs could help fix, to improve their workflow? ---> \ No newline at end of file +-->
diff --git a/tools/roll_angle.py b/tools/roll_angle.py index 734cfc88..751d4ac 100755 --- a/tools/roll_angle.py +++ b/tools/roll_angle.py
@@ -13,7 +13,10 @@ import time extra_trybots = [ - 'win_clang_dbg', + { + "mastername": "tryserver.chromium.win", + "buildername": "win_clang_dbg", + } ] SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) @@ -266,7 +269,8 @@ # Run additional tryjobs extra_try_args = [] for extra_trybot in extra_trybots: - extra_try_args += ['-b', extra_trybot] + extra_try_args += ['-m', extra_trybot["mastername"], + '-b', extra_trybot["buildername"]] self._RunCommand(base_try_cmd + extra_try_args) cl_info = self._GetCLInfo()
diff --git a/tools/telemetry/telemetry/core/local_server_unittest.py b/tools/telemetry/telemetry/core/local_server_unittest.py index 47ed6f7..46ff85c 100644 --- a/tools/telemetry/telemetry/core/local_server_unittest.py +++ b/tools/telemetry/telemetry/core/local_server_unittest.py
@@ -1,11 +1,10 @@ # 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. -import unittest - import BaseHTTPServer import SimpleHTTPServer +from telemetry import decorators from telemetry.core import local_server from telemetry.testing import tab_test_case @@ -69,7 +68,7 @@ cls._server = SimpleLocalServer() cls._platform.StartLocalServer(cls._server) - @unittest.skip("flakily times out: https://crbug.com/570955") + @decorators.Disabled('all') # https://crbug.com/570955 def testLocalServer(self): self.assertTrue(self._server in self._platform.local_servers) self._tab.Navigate(self._server.url) @@ -78,7 +77,7 @@ body_text = body_text.strip() self.assertEquals('hello world', body_text) - @unittest.skip("flakily times out: https://crbug.com/570955") + @decorators.Disabled('all') # https://crbug.com/570955 def testStartingAndRestarting(self): server2 = SimpleLocalServer() self.assertRaises(Exception,
diff --git a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder_unittest.py b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder_unittest.py index 4ad584a..78f9fa5 100644 --- a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder_unittest.py +++ b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder_unittest.py
@@ -41,6 +41,8 @@ self.assertEqual([], possible_browsers) def testCanLaunchAlwaysTrueReturnsAllExceptExact(self): + if not self.finder_options.chrome_root: + self.skipTest('--chrome-root is not specified, skip the test') fake_platform = FakeAndroidPlatform(can_launch=True) all_types = set( android_browser_finder.FindAllBrowserTypes(self.finder_options)) @@ -52,6 +54,8 @@ set([b.browser_type for b in possible_browsers])) def testCanLaunchAlwaysTrueWithExactApkReturnsAll(self): + if not self.finder_options.chrome_root: + self.skipTest('--chrome-root is not specified, skip the test') self._android_browser_finder_stub.os.path.files.append( '/foo/ContentShell.apk') self.finder_options.browser_executable = '/foo/ContentShell.apk' @@ -87,6 +91,8 @@ self.finder_options, fake_platform) def testNoErrorWithUnrecognizedApkName(self): + if not self.finder_options.chrome_root: + self.skipTest('--chrome-root is not specified, skip the test') self._android_browser_finder_stub.os.path.files.append( '/foo/unknown.apk') self.finder_options.browser_executable = '/foo/unknown.apk'
diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/devtools_client_backend_unittest.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/devtools_client_backend_unittest.py index c8aaa7a..3cef05fbc 100644 --- a/tools/telemetry/telemetry/internal/backends/chrome_inspector/devtools_client_backend_unittest.py +++ b/tools/telemetry/telemetry/internal/backends/chrome_inspector/devtools_client_backend_unittest.py
@@ -6,7 +6,7 @@ from telemetry.testing import browser_test_case from telemetry.timeline import model from telemetry.timeline import trace_data -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config class DevToolsClientBackendTest(browser_test_case.BrowserTestCase): @@ -82,9 +82,9 @@ self.skipTest('Browser does not support tracing, skipping test.') # Start Chrome tracing. - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - devtools_client.StartChromeTracing(options) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + devtools_client.StartChromeTracing(config.tracing_options) # Stop Chrome tracing and check that the resulting data is valid. builder = trace_data.TraceDataBuilder()
diff --git a/tools/telemetry/telemetry/internal/platform/profiler/android_systrace_profiler.py b/tools/telemetry/telemetry/internal/platform/profiler/android_systrace_profiler.py index 1301d7c..b1738c3 100644 --- a/tools/telemetry/telemetry/internal/platform/profiler/android_systrace_profiler.py +++ b/tools/telemetry/telemetry/internal/platform/profiler/android_systrace_profiler.py
@@ -11,7 +11,7 @@ from telemetry.internal.backends.chrome import android_browser_finder from telemetry.internal.platform import profiler from telemetry.timeline import trace_data as trace_data_module -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config _SYSTRACE_CATEGORIES = [ 'gfx', @@ -35,9 +35,9 @@ # Use telemetry's own tracing backend instead the combined mode in # adb_profile_chrome because some benchmarks also do tracing of their own # and the two methods conflict. - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - self._browser_backend.StartTracing(options, timeout=10) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + self._browser_backend.StartTracing(config.tracing_options, timeout=10) command = ['python', os.path.join(util.GetChromiumSrcDir(), 'tools', 'profile_chrome.py'), '--categories', '', '--continuous', '--output',
diff --git a/tools/telemetry/telemetry/internal/platform/profiler/trace_profiler.py b/tools/telemetry/telemetry/internal/platform/profiler/trace_profiler.py index 6d45a16..2672346 100644 --- a/tools/telemetry/telemetry/internal/platform/profiler/trace_profiler.py +++ b/tools/telemetry/telemetry/internal/platform/profiler/trace_profiler.py
@@ -8,7 +8,7 @@ from telemetry.internal.platform import profiler from telemetry.timeline import trace_data as trace_data_module -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config class TraceProfiler(profiler.Profiler): @@ -22,10 +22,10 @@ categories_with_flow = 'disabled-by-default-toplevel.flow' if categories: categories_with_flow += ',%s' % categories - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True self._browser_backend.StartTracing( - options, categories_with_flow, timeout=10) + config.tracing_options, categories_with_flow, timeout=10) @classmethod def name(cls):
diff --git a/tools/telemetry/telemetry/timeline/tracing_config.py b/tools/telemetry/telemetry/timeline/tracing_config.py index 6122ce4..b69992d 100644 --- a/tools/telemetry/telemetry/timeline/tracing_config.py +++ b/tools/telemetry/telemetry/timeline/tracing_config.py
@@ -5,7 +5,96 @@ import json from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options + + +RECORD_UNTIL_FULL = 'record-until-full' +RECORD_CONTINUOUSLY = 'record-continuously' +RECORD_AS_MUCH_AS_POSSIBLE = 'record-as-much-as-possible' +ECHO_TO_CONSOLE = 'trace-to-console' + +RECORD_MODES = [ + RECORD_UNTIL_FULL, + RECORD_CONTINUOUSLY, + RECORD_AS_MUCH_AS_POSSIBLE, + ECHO_TO_CONSOLE +] + +ENABLE_SYSTRACE = 'enable-systrace' + +class TracingOptions(object): + """Tracing options control which core tracing systems should be enabled. + + This simply turns on those systems. If those systems have additional options, + e.g. what to trace, then they are typically configured by adding + categories to the TracingCategoryFilter. + + Options: + enable_chrome_trace: a boolean that specifies whether to enable + chrome tracing. + enable_platform_display_trace: a boolean that specifies whether to + platform display tracing. + enable_android_graphics_memtrack: a boolean that specifies whether + to enable the memtrack_helper daemon to track graphics memory on + Android (see goo.gl/4Y30p9). Doesn't have any effects on other OSs. + + The following ones are specific to chrome tracing. See + base/trace_event/trace_config.h for more information. + record_mode: can be any mode in RECORD_MODES. This corresponds to + record modes in chrome. + enable_systrace: a boolean that specifies whether to enable systrace. + """ + # Map telemetry's tracing record_mode to the DevTools API string. + # (The keys happen to be the same as the values.) + _RECORD_MODE_MAP = { + RECORD_UNTIL_FULL: 'record-until-full', + RECORD_CONTINUOUSLY: 'record-continuously', + RECORD_AS_MUCH_AS_POSSIBLE: 'record-as-much-as-possible', + ECHO_TO_CONSOLE: 'trace-to-console' + } + + def __init__(self): + self.enable_chrome_trace = False + self.enable_platform_display_trace = False + self.enable_android_graphics_memtrack = False + + self._record_mode = RECORD_AS_MUCH_AS_POSSIBLE + self._enable_systrace = False + + @property + def record_mode(self): + return self._record_mode + + @record_mode.setter + def record_mode(self, value): + assert value in RECORD_MODES + self._record_mode = value + + @property + def enable_systrace(self): + return self._enable_systrace + + @enable_systrace.setter + def enable_systrace(self, value): + self._enable_systrace = value + + def GetTraceOptionsStringForChromeDevtool(self): + """Map Chrome tracing options in Telemetry to the DevTools API string.""" + result = [TracingOptions._RECORD_MODE_MAP[self._record_mode]] + if self._enable_systrace: + result.append(ENABLE_SYSTRACE) + return ','.join(result) + + def GetDictForChromeTracing(self): + RECORD_MODE_PARAM = 'record_mode' + ENABLE_SYSTRACE_PARAM = 'enable_systrace' + + result = {} + result[RECORD_MODE_PARAM] = ( + TracingOptions._RECORD_MODE_MAP[self._record_mode]) + if self._enable_systrace: + result[ENABLE_SYSTRACE_PARAM] = True + return result + class TracingConfig(object): """Tracing config is the configuration for Chrome tracing. @@ -14,7 +103,7 @@ about the JSON string format, see base/trace_event/trace_config.h. """ def __init__(self): - self._tracing_options = tracing_options.TracingOptions() + self._tracing_options = TracingOptions() self._tracing_category_filter = ( tracing_category_filter.TracingCategoryFilter())
diff --git a/tools/telemetry/telemetry/timeline/tracing_config_unittest.py b/tools/telemetry/telemetry/timeline/tracing_config_unittest.py index daf00a4..be9f0373 100644 --- a/tools/telemetry/telemetry/timeline/tracing_config_unittest.py +++ b/tools/telemetry/telemetry/timeline/tracing_config_unittest.py
@@ -6,7 +6,6 @@ from telemetry.timeline import tracing_category_filter from telemetry.timeline import tracing_config -from telemetry.timeline import tracing_options class TracingConfigTests(unittest.TestCase): @@ -25,7 +24,7 @@ config = tracing_config.TracingConfig() config.SetTracingCategoryFilter(category_filter) config.tracing_options.enable_systrace = True - config.tracing_options.record_mode = tracing_options.RECORD_UNTIL_FULL + config.tracing_options.record_mode = tracing_config.RECORD_UNTIL_FULL config_string = config.GetChromeTraceConfigJsonString() self.assertEquals( '{'
diff --git a/tools/telemetry/telemetry/timeline/tracing_options.py b/tools/telemetry/telemetry/timeline/tracing_options.py deleted file mode 100644 index 5f99b7c..0000000 --- a/tools/telemetry/telemetry/timeline/tracing_options.py +++ /dev/null
@@ -1,91 +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. - -RECORD_UNTIL_FULL = 'record-until-full' -RECORD_CONTINUOUSLY = 'record-continuously' -RECORD_AS_MUCH_AS_POSSIBLE = 'record-as-much-as-possible' -ECHO_TO_CONSOLE = 'trace-to-console' - -RECORD_MODES = [ - RECORD_UNTIL_FULL, - RECORD_CONTINUOUSLY, - RECORD_AS_MUCH_AS_POSSIBLE, - ECHO_TO_CONSOLE -] - -ENABLE_SYSTRACE = 'enable-systrace' - -class TracingOptions(object): - """Tracing options control which core tracing systems should be enabled. - - This simply turns on those systems. If those systems have additional options, - e.g. what to trace, then they are typically configured by adding - categories to the TracingCategoryFilter. - - Options: - enable_chrome_trace: a boolean that specifies whether to enable - chrome tracing. - enable_platform_display_trace: a boolean that specifies whether to - platform display tracing. - enable_android_graphics_memtrack: a boolean that specifies whether - to enable the memtrack_helper daemon to track graphics memory on - Android (see goo.gl/4Y30p9). Doesn't have any effects on other OSs. - - The following ones are specific to chrome tracing. See - base/trace_event/trace_config.h for more information. - record_mode: can be any mode in RECORD_MODES. This corresponds to - record modes in chrome. - enable_systrace: a boolean that specifies whether to enable systrace. - """ - # Map telemetry's tracing record_mode to the DevTools API string. - # (The keys happen to be the same as the values.) - _RECORD_MODE_MAP = { - RECORD_UNTIL_FULL: 'record-until-full', - RECORD_CONTINUOUSLY: 'record-continuously', - RECORD_AS_MUCH_AS_POSSIBLE: 'record-as-much-as-possible', - ECHO_TO_CONSOLE: 'trace-to-console' - } - - def __init__(self): - self.enable_chrome_trace = False - self.enable_platform_display_trace = False - self.enable_android_graphics_memtrack = False - - self._record_mode = RECORD_AS_MUCH_AS_POSSIBLE - self._enable_systrace = False - - @property - def record_mode(self): - return self._record_mode - - @record_mode.setter - def record_mode(self, value): - assert value in RECORD_MODES - self._record_mode = value - - @property - def enable_systrace(self): - return self._enable_systrace - - @enable_systrace.setter - def enable_systrace(self, value): - self._enable_systrace = value - - def GetTraceOptionsStringForChromeDevtool(self): - """Map Chrome tracing options in Telemetry to the DevTools API string.""" - result = [TracingOptions._RECORD_MODE_MAP[self._record_mode]] - if self._enable_systrace: - result.append(ENABLE_SYSTRACE) - return ','.join(result) - - def GetDictForChromeTracing(self): - RECORD_MODE_PARAM = 'record_mode' - ENABLE_SYSTRACE_PARAM = 'enable_systrace' - - result = {} - result[RECORD_MODE_PARAM] = ( - TracingOptions._RECORD_MODE_MAP[self._record_mode]) - if self._enable_systrace: - result[ENABLE_SYSTRACE_PARAM] = True - return result
diff --git a/ui/base/cocoa/controls/hyperlink_text_view.h b/ui/base/cocoa/controls/hyperlink_text_view.h index affe648..0a0cb440 100644 --- a/ui/base/cocoa/controls/hyperlink_text_view.h +++ b/ui/base/cocoa/controls/hyperlink_text_view.h
@@ -16,6 +16,7 @@ @private BOOL refusesFirstResponder_; BOOL drawsBackgroundUsingSuperview_; + BOOL isValidLink_; } @property(nonatomic, assign) BOOL drawsBackgroundUsingSuperview; @@ -26,7 +27,8 @@ withFont:(NSFont*)font messageColor:(NSColor*)messageColor; -// Marks a |range| within the given message as link. +// Marks a |range| within the given message as a link. Pass nil as the url to +// create a link that can neither be copied nor dragged. - (void)addLinkRange:(NSRange)range withURL:(NSString*)url linkColor:(NSColor*)linkColor;
diff --git a/ui/base/cocoa/controls/hyperlink_text_view.mm b/ui/base/cocoa/controls/hyperlink_text_view.mm index c4936e2..2a50e0f 100644 --- a/ui/base/cocoa/controls/hyperlink_text_view.mm +++ b/ui/base/cocoa/controls/hyperlink_text_view.mm
@@ -95,6 +95,7 @@ refusesFirstResponder_ = NO; drawsBackgroundUsingSuperview_ = NO; + isValidLink_ = NO; } - (void)fixupCursor { @@ -102,6 +103,28 @@ [[NSCursor arrowCursor] set]; } +// Only allow contextual menus (which allow copying of the link URL) if the link +// is a valid one. +- (NSMenu*)menuForEvent:(NSEvent*)e { + if (isValidLink_) + return [super menuForEvent:e]; + + return nil; +} + +// Only allow dragging of valid links. +- (BOOL)dragSelectionWithEvent:(NSEvent*)event + offset:(NSSize)mouseOffset + slideBack:(BOOL)slideBack { + if (isValidLink_) { + return [super dragSelectionWithEvent:event + offset:mouseOffset + slideBack:slideBack]; + } + + return NO; +} + - (void)setMessage:(NSString*)message withFont:(NSFont*)font messageColor:(NSColor*)messageColor { @@ -125,12 +148,15 @@ - (void)addLinkRange:(NSRange)range withURL:(NSString*)url linkColor:(NSColor*)linkColor { - // When the NSLinkAttributeName attribute is used, AppKit makes the link - // draggable. If no URL is provided, dropping it on the tab strip will crash - // <http://crbug.com/528228>. Require that a URL is used, and that only a URL - // is used. - DCHECK_GT([url length], 0u); - DCHECK([NSURL URLWithString:url]); + // If a URL is provided, make sure it is a valid one. + if (url) { + DCHECK_GT([url length], 0u); + DCHECK([NSURL URLWithString:url]); + isValidLink_ = YES; + } else { + url = @""; + isValidLink_ = NO; + } NSDictionary* attributes = @{ NSForegroundColorAttributeName : linkColor, NSUnderlineStyleAttributeName : @(YES),
diff --git a/ui/base/cocoa/menu_controller.h b/ui/base/cocoa/menu_controller.h index 1da66749..7e8e4ac 100644 --- a/ui/base/cocoa/menu_controller.h +++ b/ui/base/cocoa/menu_controller.h
@@ -15,6 +15,9 @@ class MenuModel; } +UI_BASE_EXPORT extern NSString* const kMenuControllerMenuWillOpenNotification; +UI_BASE_EXPORT extern NSString* const kMenuControllerMenuDidCloseNotification; + // A controller for the cross-platform menu model. The menu that's created // has the tag and represented object set for each menu item. The object is a // NSValue holding a pointer to the model for that level of the menu (to
diff --git a/ui/base/cocoa/menu_controller.mm b/ui/base/cocoa/menu_controller.mm index 9faa607..8c92b28 100644 --- a/ui/base/cocoa/menu_controller.mm +++ b/ui/base/cocoa/menu_controller.mm
@@ -15,6 +15,11 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/text_elider.h" +NSString* const kMenuControllerMenuWillOpenNotification = + @"MenuControllerMenuWillOpen"; +NSString* const kMenuControllerMenuDidCloseNotification = + @"MenuControllerMenuDidClose"; + @interface MenuController (Private) - (void)addSeparatorToMenu:(NSMenu*)menu atIndex:(int)index; @@ -233,6 +238,9 @@ - (void)menuWillOpen:(NSMenu*)menu { isMenuOpen_ = YES; model_->MenuWillShow(); + [[NSNotificationCenter defaultCenter] + postNotificationName:kMenuControllerMenuWillOpenNotification + object:self]; } - (void)menuDidClose:(NSMenu*)menu { @@ -240,6 +248,9 @@ model_->MenuClosed(); isMenuOpen_ = NO; } + [[NSNotificationCenter defaultCenter] + postNotificationName:kMenuControllerMenuDidCloseNotification + object:self]; } @end
diff --git a/ui/events/ozone/device/device_manager.cc b/ui/events/ozone/device/device_manager.cc index a52123f..9811fc58 100644 --- a/ui/events/ozone/device/device_manager.cc +++ b/ui/events/ozone/device/device_manager.cc
@@ -4,6 +4,8 @@ #include "ui/events/ozone/device/device_manager.h" +#include "base/trace_event/trace_event.h" + #if defined(USE_UDEV) #include "ui/events/ozone/device/udev/device_manager_udev.h" #else @@ -13,6 +15,7 @@ namespace ui { scoped_ptr<DeviceManager> CreateDeviceManager() { +TRACE_EVENT0("ozone", "CreateDeviceManager"); #if defined(USE_UDEV) return make_scoped_ptr(new DeviceManagerUdev()); #else
diff --git a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc index 4484041..53f2f89 100644 --- a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc +++ b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
@@ -133,7 +133,6 @@ {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_PLUS}, {DomCode::SEMICOLON, 0, 0, kAny, kAny, VKEY_OEM_PLUS}, {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_2}, - {DomCode::MINUS, 1, 1, 0x003F, 0x005C, VKEY_OEM_MINUS}, // ?, backslash {DomCode::MINUS, 1, 0, 0x003F, kAny, VKEY_OEM_PLUS}}; // ? // U+002C comma
diff --git a/ui/file_manager/gallery/css/gallery.css b/ui/file_manager/gallery/css/gallery.css index 523142b..921924a8 100644 --- a/ui/file_manager/gallery/css/gallery.css +++ b/ui/file_manager/gallery/css/gallery.css
@@ -231,11 +231,19 @@ pointer-events: auto; } +.gallery:not([tools]) > files-tooltip { + opacity: 0; +} + /* Hide immediately when entering the slideshow. */ .gallery[tools][slideshow] > .toolbar { transition-duration: 0ms; } +.gallery[tools][slideshow] > files-tooltip { + transition-duration: 0ms; +} + .gallery[tools][locked] > .toolbar { pointer-events: none; }
diff --git a/ui/file_manager/gallery/js/slide_mode.js b/ui/file_manager/gallery/js/slide_mode.js index e1253c9..f2ed020 100644 --- a/ui/file_manager/gallery/js/slide_mode.js +++ b/ui/file_manager/gallery/js/slide_mode.js
@@ -873,6 +873,8 @@ this.printButton_.disabled = true; this.editButton_.disabled = true; this.errorBanner_.show('GALLERY_NO_IMAGES'); + if (this.isEditing()) + this.toggleEditor(); }.bind(this)); return; } @@ -886,6 +888,9 @@ // To force to dispatch a selection change event, unselect all before. this.selectionModel_.unselectAll(); this.select(nextIndex); + // If the removed image was edit, leave the editing mode. + if (this.isEditing()) + this.toggleEditor(); } }.bind(this), 0); };
diff --git a/ui/gfx/platform_font.h b/ui/gfx/platform_font.h index 44907799..58b0083 100644 --- a/ui/gfx/platform_font.h +++ b/ui/gfx/platform_font.h
@@ -41,18 +41,18 @@ // greater than just ascent + descent. Specifically, the Windows and Mac // implementations include leading and the Linux one does not. This may // need to be revisited in the future. - virtual int GetHeight() const = 0; + virtual int GetHeight() = 0; // Returns the baseline, or ascent, of the font. - virtual int GetBaseline() const = 0; + virtual int GetBaseline() = 0; // Returns the cap height of the font. - virtual int GetCapHeight() const = 0; + virtual int GetCapHeight() = 0; // Returns the expected number of horizontal pixels needed to display the // specified length of characters. Call GetStringWidth() to retrieve the // actual number. - virtual int GetExpectedTextWidth(int length) const = 0; + virtual int GetExpectedTextWidth(int length) = 0; // Returns the style of the font. virtual int GetStyle() const = 0;
diff --git a/ui/gfx/platform_font_ios.h b/ui/gfx/platform_font_ios.h index fea67ac..5cc1224 100644 --- a/ui/gfx/platform_font_ios.h +++ b/ui/gfx/platform_font_ios.h
@@ -19,10 +19,10 @@ // Overridden from PlatformFont: Font DeriveFont(int size_delta, int style) const override; - int GetHeight() const override; - int GetBaseline() const override; - int GetCapHeight() const override; - int GetExpectedTextWidth(int length) const override; + int GetHeight() override; + int GetBaseline() override; + int GetCapHeight() override; + int GetExpectedTextWidth(int length) override; int GetStyle() const override; const std::string& GetFontName() const override; std::string GetActualFontNameForTesting() const override;
diff --git a/ui/gfx/platform_font_ios.mm b/ui/gfx/platform_font_ios.mm index c6ca541..c51b8cb7 100644 --- a/ui/gfx/platform_font_ios.mm +++ b/ui/gfx/platform_font_ios.mm
@@ -46,19 +46,19 @@ return Font(new PlatformFontIOS(font_name_, font_size_ + size_delta, style)); } -int PlatformFontIOS::GetHeight() const { +int PlatformFontIOS::GetHeight() { return height_; } -int PlatformFontIOS::GetBaseline() const { +int PlatformFontIOS::GetBaseline() { return ascent_; } -int PlatformFontIOS::GetCapHeight() const { +int PlatformFontIOS::GetCapHeight() { return cap_height_; } -int PlatformFontIOS::GetExpectedTextWidth(int length) const { +int PlatformFontIOS::GetExpectedTextWidth(int length) { return length * average_width_; }
diff --git a/ui/gfx/platform_font_linux.cc b/ui/gfx/platform_font_linux.cc index d2652a2..3c58ccb 100644 --- a/ui/gfx/platform_font_linux.cc +++ b/ui/gfx/platform_font_linux.cc
@@ -157,19 +157,23 @@ gfx::GetFontRenderParams(query, NULL))); } -int PlatformFontLinux::GetHeight() const { +int PlatformFontLinux::GetHeight() { + ComputeMetricsIfNecessary(); return height_pixels_; } -int PlatformFontLinux::GetBaseline() const { +int PlatformFontLinux::GetBaseline() { + ComputeMetricsIfNecessary(); return ascent_pixels_; } -int PlatformFontLinux::GetCapHeight() const { +int PlatformFontLinux::GetCapHeight() { + ComputeMetricsIfNecessary(); return cap_height_pixels_; } -int PlatformFontLinux::GetExpectedTextWidth(int length) const { +int PlatformFontLinux::GetExpectedTextWidth(int length) { + ComputeMetricsIfNecessary(); return round(static_cast<float>(length) * average_width_pixels_); } @@ -238,20 +242,6 @@ #endif font_render_params_ = render_params; - SkPaint paint; - paint.setAntiAlias(false); - paint.setSubpixelText(false); - paint.setTextSize(font_size_pixels_); - paint.setTypeface(typeface_.get()); - paint.setFakeBoldText((Font::BOLD & style_) && !typeface_->isBold()); - paint.setTextSkewX((Font::ITALIC & style_) && !typeface_->isItalic() ? - -SK_Scalar1/4 : 0); - SkPaint::FontMetrics metrics; - paint.getFontMetrics(&metrics); - ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent); - height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent); - cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight); - average_width_pixels_ = SkScalarToDouble(metrics.fAvgCharWidth); } void PlatformFontLinux::InitFromPlatformFont(const PlatformFontLinux* other) { @@ -263,10 +253,35 @@ device_scale_factor_ = other->device_scale_factor_; #endif font_render_params_ = other->font_render_params_; - ascent_pixels_ = other->ascent_pixels_; - height_pixels_ = other->height_pixels_; - cap_height_pixels_ = other->cap_height_pixels_; - average_width_pixels_ = other->average_width_pixels_; + + if (!other->metrics_need_computation_) { + metrics_need_computation_ = false; + ascent_pixels_ = other->ascent_pixels_; + height_pixels_ = other->height_pixels_; + cap_height_pixels_ = other->cap_height_pixels_; + average_width_pixels_ = other->average_width_pixels_; + } +} + +void PlatformFontLinux::ComputeMetricsIfNecessary() { + if (metrics_need_computation_) { + metrics_need_computation_ = false; + + SkPaint paint; + paint.setAntiAlias(false); + paint.setSubpixelText(false); + paint.setTextSize(font_size_pixels_); + paint.setTypeface(typeface_.get()); + paint.setFakeBoldText((Font::BOLD & style_) && !typeface_->isBold()); + paint.setTextSkewX((Font::ITALIC & style_) && !typeface_->isItalic() ? + -SK_Scalar1/4 : 0); + SkPaint::FontMetrics metrics; + paint.getFontMetrics(&metrics); + ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent); + height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent); + cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight); + average_width_pixels_ = SkScalarToDouble(metrics.fAvgCharWidth); + } } ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/gfx/platform_font_linux.h b/ui/gfx/platform_font_linux.h index 0d8f2af3..52c4bce 100644 --- a/ui/gfx/platform_font_linux.h +++ b/ui/gfx/platform_font_linux.h
@@ -42,10 +42,10 @@ // Overridden from PlatformFont: Font DeriveFont(int size_delta, int style) const override; - int GetHeight() const override; - int GetBaseline() const override; - int GetCapHeight() const override; - int GetExpectedTextWidth(int length) const override; + int GetHeight() override; + int GetBaseline() override; + int GetCapHeight() override; + int GetExpectedTextWidth(int length) override; int GetStyle() const override; const std::string& GetFontName() const override; std::string GetActualFontNameForTesting() const override; @@ -74,6 +74,9 @@ // Initializes this object as a copy of another PlatformFontLinux. void InitFromPlatformFont(const PlatformFontLinux* other); + // Computes the metrics if they have not yet been computed. + void ComputeMetricsIfNecessary(); + skia::RefPtr<SkTypeface> typeface_; // Additional information about the face. @@ -88,7 +91,8 @@ // Information describing how the font should be rendered. FontRenderParams font_render_params_; - // Cached metrics, generated at construction. + // Cached metrics, generated on demand. + bool metrics_need_computation_ = true; int ascent_pixels_; int height_pixels_; int cap_height_pixels_;
diff --git a/ui/gfx/platform_font_mac.h b/ui/gfx/platform_font_mac.h index 12734ac8..66ffc40 100644 --- a/ui/gfx/platform_font_mac.h +++ b/ui/gfx/platform_font_mac.h
@@ -22,10 +22,10 @@ // Overridden from PlatformFont: Font DeriveFont(int size_delta, int style) const override; - int GetHeight() const override; - int GetBaseline() const override; - int GetCapHeight() const override; - int GetExpectedTextWidth(int length) const override; + int GetHeight() override; + int GetBaseline() override; + int GetCapHeight() override; + int GetExpectedTextWidth(int length) override; int GetStyle() const override; const std::string& GetFontName() const override; std::string GetActualFontNameForTesting() const override;
diff --git a/ui/gfx/platform_font_mac.mm b/ui/gfx/platform_font_mac.mm index dfe83fc7..3129489 100644 --- a/ui/gfx/platform_font_mac.mm +++ b/ui/gfx/platform_font_mac.mm
@@ -99,19 +99,19 @@ return Font(new PlatformFontMac(font_name_, font_size_ + size_delta, style)); } -int PlatformFontMac::GetHeight() const { +int PlatformFontMac::GetHeight() { return height_; } -int PlatformFontMac::GetBaseline() const { +int PlatformFontMac::GetBaseline() { return ascent_; } -int PlatformFontMac::GetCapHeight() const { +int PlatformFontMac::GetCapHeight() { return cap_height_; } -int PlatformFontMac::GetExpectedTextWidth(int length) const { +int PlatformFontMac::GetExpectedTextWidth(int length) { return length * average_width_; }
diff --git a/ui/gfx/platform_font_win.cc b/ui/gfx/platform_font_win.cc index 8646beb0..e48bca2 100644 --- a/ui/gfx/platform_font_win.cc +++ b/ui/gfx/platform_font_win.cc
@@ -368,19 +368,19 @@ return Font(new PlatformFontWin(CreateHFontRef(hfont))); } -int PlatformFontWin::GetHeight() const { +int PlatformFontWin::GetHeight() { return font_ref_->height(); } -int PlatformFontWin::GetBaseline() const { +int PlatformFontWin::GetBaseline() { return font_ref_->baseline(); } -int PlatformFontWin::GetCapHeight() const { +int PlatformFontWin::GetCapHeight() { return font_ref_->cap_height(); } -int PlatformFontWin::GetExpectedTextWidth(int length) const { +int PlatformFontWin::GetExpectedTextWidth(int length) { return length * std::min(font_ref_->GetDluBaseX(), font_ref_->ave_char_width()); }
diff --git a/ui/gfx/platform_font_win.h b/ui/gfx/platform_font_win.h index f696453..b03ed81 100644 --- a/ui/gfx/platform_font_win.h +++ b/ui/gfx/platform_font_win.h
@@ -58,10 +58,10 @@ // Overridden from PlatformFont: Font DeriveFont(int size_delta, int style) const override; - int GetHeight() const override; - int GetBaseline() const override; - int GetCapHeight() const override; - int GetExpectedTextWidth(int length) const override; + int GetHeight() override; + int GetBaseline() override; + int GetCapHeight() override; + int GetExpectedTextWidth(int length) override; int GetStyle() const override; const std::string& GetFontName() const override; std::string GetActualFontNameForTesting() const override;
diff --git a/ui/gl/android/surface_texture.cc b/ui/gl/android/surface_texture.cc index 232705d6..1c5b788 100644 --- a/ui/gl/android/surface_texture.cc +++ b/ui/gl/android/surface_texture.cc
@@ -35,9 +35,16 @@ const base::Closure& callback) { JNIEnv* env = base::android::AttachCurrentThread(); Java_SurfaceTexturePlatformWrapper_setFrameAvailableCallback( - env, - j_surface_texture_.obj(), - reinterpret_cast<intptr_t>(new SurfaceTextureListener(callback))); + env, j_surface_texture_.obj(), + reinterpret_cast<intptr_t>(new SurfaceTextureListener(callback, false))); +} + +void SurfaceTexture::SetFrameAvailableCallbackOnAnyThread( + const base::Closure& callback) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_SurfaceTexturePlatformWrapper_setFrameAvailableCallback( + env, j_surface_texture_.obj(), + reinterpret_cast<intptr_t>(new SurfaceTextureListener(callback, true))); } void SurfaceTexture::UpdateTexImage() {
diff --git a/ui/gl/android/surface_texture.h b/ui/gl/android/surface_texture.h index 56282ff..b0ffc90 100644 --- a/ui/gl/android/surface_texture.h +++ b/ui/gl/android/surface_texture.h
@@ -31,6 +31,12 @@ // the callback from a weak pointer to your object. void SetFrameAvailableCallback(const base::Closure& callback); + // Set the listener callback, but allow it to be invoked on any thread. The + // same caveats apply as SetFrameAvailableCallback, plus whatever other issues + // show up due to multithreading (e.g., don't bind the Closure to a method + // via a weak ref). + void SetFrameAvailableCallbackOnAnyThread(const base::Closure& callback); + // Update the texture image to the most recent frame from the image stream. void UpdateTexImage();
diff --git a/ui/gl/android/surface_texture_listener.cc b/ui/gl/android/surface_texture_listener.cc index 7d999f6..6b5c0117 100644 --- a/ui/gl/android/surface_texture_listener.cc +++ b/ui/gl/android/surface_texture_listener.cc
@@ -11,10 +11,11 @@ namespace gfx { -SurfaceTextureListener::SurfaceTextureListener(const base::Closure& callback) +SurfaceTextureListener::SurfaceTextureListener(const base::Closure& callback, + bool use_any_thread) : callback_(callback), - browser_loop_(base::ThreadTaskRunnerHandle::Get()) { -} + browser_loop_(base::ThreadTaskRunnerHandle::Get()), + use_any_thread_(use_any_thread) {} SurfaceTextureListener::~SurfaceTextureListener() { } @@ -28,7 +29,7 @@ void SurfaceTextureListener::FrameAvailable(JNIEnv* env, const JavaParamRef<jobject>& obj) { - if (!browser_loop_->BelongsToCurrentThread()) { + if (!use_any_thread_ && !browser_loop_->BelongsToCurrentThread()) { browser_loop_->PostTask(FROM_HERE, callback_); } else { callback_.Run();
diff --git a/ui/gl/android/surface_texture_listener.h b/ui/gl/android/surface_texture_listener.h index c9d8ff5..0043c1c 100644 --- a/ui/gl/android/surface_texture_listener.h +++ b/ui/gl/android/surface_texture_listener.h
@@ -37,7 +37,10 @@ // Native code should not hold any reference to this object, and instead pass // it up to Java for being referenced by a SurfaceTexture instance. - SurfaceTextureListener(const base::Closure& callback); + // If use_any_thread is true, then the FrameAvailable callback will happen + // on whatever thread calls us. Otherwise, we will call it back on the same + // thread that was used to construct us. + SurfaceTextureListener(const base::Closure& callback, bool use_any_thread); ~SurfaceTextureListener(); friend class SurfaceTexture; @@ -46,6 +49,8 @@ scoped_refptr<base::SingleThreadTaskRunner> browser_loop_; + bool use_any_thread_; + DISALLOW_IMPLICIT_CONSTRUCTORS(SurfaceTextureListener); };
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc index b965552..67c1483c 100644 --- a/ui/gl/gl_surface_ozone.cc +++ b/ui/gl/gl_surface_ozone.cc
@@ -262,13 +262,14 @@ EGLDisplay display = GetDisplay(); WaitForFence(display, fence); eglDestroySyncKHR(display, fence); - } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) { - glFinish(); } unsubmitted_frames_.back()->ScheduleOverlayPlanes(widget_); unsubmitted_frames_.back()->overlays.clear(); + if (ozone_surface_->IsUniversalDisplayLinkDevice()) + glFinish(); + return ozone_surface_->OnSwapBuffers() ? gfx::SwapResult::SWAP_ACK : gfx::SwapResult::SWAP_FAILED; } @@ -347,9 +348,6 @@ return; // Defer frame submission until fence signals. } - if (ozone_surface_->IsUniversalDisplayLinkDevice()) - glFinish(); - frame->ready = true; SubmitFrame(); } @@ -383,6 +381,9 @@ return; } + if (ozone_surface_->IsUniversalDisplayLinkDevice()) + glFinish(); + ozone_surface_->OnSwapBuffersAsync(frame->callback); } }
diff --git a/ui/ozone/common/gpu/ozone_gpu_message_params.h b/ui/ozone/common/gpu/ozone_gpu_message_params.h index b8d3018..d6c6523 100644 --- a/ui/ozone/common/gpu/ozone_gpu_message_params.h +++ b/ui/ozone/common/gpu/ozone_gpu_message_params.h
@@ -64,6 +64,8 @@ // Higher the value, the more important it is to ensure that this // overlay candidate finds a compatible free hardware plane to use. uint32_t weight; + // By default we mark this configuration valid for promoting it to an overlay. + bool is_overlay_candidate = true; // Will be set in GPU process. These are unique plane ids of primary display // supporting this configuration. std::vector<uint32_t> plane_ids;
diff --git a/ui/ozone/common/gpu/ozone_gpu_messages.h b/ui/ozone/common/gpu/ozone_gpu_messages.h index cc95fe01e..0edd20a 100644 --- a/ui/ozone/common/gpu/ozone_gpu_messages.h +++ b/ui/ozone/common/gpu/ozone_gpu_messages.h
@@ -72,6 +72,7 @@ IPC_STRUCT_TRAITS_MEMBER(crop_rect) IPC_STRUCT_TRAITS_MEMBER(plane_z_order) IPC_STRUCT_TRAITS_MEMBER(weight) + IPC_STRUCT_TRAITS_MEMBER(is_overlay_candidate) IPC_STRUCT_TRAITS_MEMBER(plane_ids) IPC_STRUCT_TRAITS_END()
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn index 26dfa60..a3bbbd22 100644 --- a/ui/ozone/platform/drm/BUILD.gn +++ b/ui/ozone/platform/drm/BUILD.gn
@@ -14,6 +14,12 @@ packages = [ "libdrm" ] } +config("drm_atomic") { + if (use_drm_atomic) { + defines = [ "USE_DRM_ATOMIC" ] + } +} + source_set("gbm") { sources = [ "client_native_pixmap_factory_gbm.cc", @@ -40,6 +46,8 @@ "gpu/drm_gpu_display_manager.h", "gpu/drm_gpu_platform_support.cc", "gpu/drm_gpu_platform_support.h", + "gpu/drm_overlay_validator.cc", + "gpu/drm_overlay_validator.h", "gpu/drm_thread.cc", "gpu/drm_thread.h", "gpu/drm_thread_message_proxy.cc", @@ -132,7 +140,7 @@ defines = [ "OZONE_IMPLEMENTATION" ] if (use_drm_atomic) { - defines += [ "USE_DRM_ATOMIC" ] + configs += [ ":drm_atomic" ] sources += [ "gpu/hardware_display_plane_atomic.cc", "gpu/hardware_display_plane_atomic.h", @@ -153,7 +161,9 @@ source_set("gbm_unittests") { testonly = true + configs += [ ":drm_atomic" ] sources = [ + "gpu/drm_overlay_validator_unittest.cc", "gpu/drm_window_unittest.cc", "gpu/fake_plane_info.cc", "gpu/fake_plane_info.h", @@ -167,6 +177,8 @@ "gpu/mock_hardware_display_plane_manager.h", "gpu/mock_scanout_buffer.cc", "gpu/mock_scanout_buffer.h", + "gpu/mock_scanout_buffer_generator.cc", + "gpu/mock_scanout_buffer_generator.h", "gpu/screen_manager_unittest.cc", ]
diff --git a/ui/ozone/platform/drm/gbm.gypi b/ui/ozone/platform/drm/gbm.gypi index a73909c..3a73d9e 100644 --- a/ui/ozone/platform/drm/gbm.gypi +++ b/ui/ozone/platform/drm/gbm.gypi
@@ -14,11 +14,23 @@ 'gbm', ], 'use_mesa_platform_null%': 0, - 'use_drm_atomic%': 0, }, 'targets': [ { + 'target_name': 'drm_atomic', + 'type': 'none', + 'conditions': [ + ['use_drm_atomic==1', { + 'direct_dependent_settings': { + 'defines': [ + 'USE_DRM_ATOMIC', + ], + }, + }], + ], + }, + { 'target_name': 'ozone_platform_gbm', 'type': 'static_library', 'dependencies': [ @@ -38,6 +50,7 @@ '../events/platform/events_platform.gyp:events_platform', '../gfx/gfx.gyp:gfx', '../gfx/gfx.gyp:gfx_geometry', + 'drm_atomic', ], 'defines': [ 'OZONE_IMPLEMENTATION', @@ -68,6 +81,8 @@ 'gpu/drm_gpu_display_manager.h', 'gpu/drm_gpu_platform_support.cc', 'gpu/drm_gpu_platform_support.h', + 'gpu/drm_overlay_validator.cc', + 'gpu/drm_overlay_validator.h', 'gpu/drm_thread.cc', 'gpu/drm_thread.h', 'gpu/drm_thread_message_proxy.cc', @@ -149,9 +164,6 @@ 'gpu/hardware_display_plane_manager_atomic.cc', 'gpu/hardware_display_plane_manager_atomic.h', ], - 'defines': [ - 'USE_DRM_ATOMIC=1', - ], }], ], }, @@ -164,14 +176,17 @@ '../gfx/gfx.gyp:gfx', '../gfx/gfx.gyp:gfx_geometry', 'ozone.gyp:ozone', + 'drm_atomic', ], 'export_dependent_settings': [ '../../build/linux/system.gyp:libdrm', '../../skia/skia.gyp:skia', '../gfx/gfx.gyp:gfx_geometry', + 'drm_atomic', ], 'direct_dependent_settings': { 'sources': [ + 'gpu/drm_overlay_validator_unittest.cc', 'gpu/drm_window_unittest.cc', 'gpu/fake_plane_info.cc', 'gpu/fake_plane_info.h', @@ -185,6 +200,8 @@ 'gpu/mock_hardware_display_plane_manager.h', 'gpu/mock_scanout_buffer.cc', 'gpu/mock_scanout_buffer.h', + 'gpu/mock_scanout_buffer_generator.cc', + 'gpu/mock_scanout_buffer_generator.h', 'gpu/screen_manager_unittest.cc', ], },
diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.cc b/ui/ozone/platform/drm/gpu/crtc_controller.cc index 7e4233f..6efa243 100644 --- a/ui/ozone/platform/drm/gpu/crtc_controller.cc +++ b/ui/ozone/platform/drm/gpu/crtc_controller.cc
@@ -119,6 +119,12 @@ return drm_->plane_manager()->GetCompatibleHardwarePlaneIds(plane, crtc_); } +bool CrtcController::IsFormatSupported(uint32_t fourcc_format, + uint32_t z_order) const { + return drm_->plane_manager()->IsFormatSupported(fourcc_format, z_order, + crtc_); +} + void CrtcController::OnPageFlipEvent(unsigned int frame, unsigned int seconds, unsigned int useconds) {
diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.h b/ui/ozone/platform/drm/gpu/crtc_controller.h index 01d9a1d..ca541a7 100644 --- a/ui/ozone/platform/drm/gpu/crtc_controller.h +++ b/ui/ozone/platform/drm/gpu/crtc_controller.h
@@ -60,6 +60,10 @@ std::vector<uint32_t> GetCompatibleHardwarePlaneIds( const OverlayPlane& plane) const; + // Returns true if hardware plane with z_order equal to |z_order| can support + // |fourcc_format| format. + bool IsFormatSupported(uint32_t fourcc_format, uint32_t z_order) const; + // Called if the page flip event wasn't scheduled (ie: page flip fails). This // will then signal the request such that the caller doesn't wait for the // event forever.
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc b/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc new file mode 100644 index 0000000..6604e83 --- /dev/null +++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
@@ -0,0 +1,257 @@ +// 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 "ui/ozone/platform/drm/gpu/drm_overlay_validator.h" + +#include <drm_fourcc.h> + +#include "ui/gfx/geometry/size_conversions.h" +#include "ui/ozone/platform/drm/common/drm_util.h" +#include "ui/ozone/platform/drm/gpu/drm_device.h" +#include "ui/ozone/platform/drm/gpu/drm_window.h" +#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" +#include "ui/ozone/platform/drm/gpu/scanout_buffer.h" + +namespace ui { + +namespace { + +const size_t kMaxCacheSize = 200; + +bool NeedsAlphaComposition(uint32_t format) { + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_UYVY: + return false; + default: + return true; + } +} + +scoped_refptr<ScanoutBuffer> GetBufferForPageFlipTest( + const scoped_refptr<DrmDevice>& drm_device, + const gfx::Size& size, + uint32_t format, + ScanoutBufferGenerator* buffer_generator, + std::vector<scoped_refptr<ScanoutBuffer>>* reusable_buffers) { + // Check if we can re-use existing buffers. + for (const auto& buffer : *reusable_buffers) { + if (buffer->GetFramebufferPixelFormat() == format && + buffer->GetSize() == size) { + return buffer; + } + } + + gfx::BufferFormat buffer_format = GetBufferFormatFromFourCCFormat(format); + scoped_refptr<ScanoutBuffer> scanout_buffer = + buffer_generator->Create(drm_device, buffer_format, size); + reusable_buffers->push_back(scanout_buffer); + + return scanout_buffer; +} + +gfx::Size GetScaledSize(const gfx::Size original_size, + const gfx::Rect display_rect, + const gfx::RectF crop_rect) { + if (!crop_rect.IsEmpty()) { + return gfx::ToCeiledSize( + gfx::SizeF(display_rect.width() / crop_rect.width(), + display_rect.height() / crop_rect.height())); + } + + return original_size; +} + +uint32_t FindOptimalBufferFormat(uint32_t original_format, + uint32_t plane_z_order, + const gfx::Rect& plane_bounds, + const gfx::Rect& window_bounds, + HardwareDisplayController* controller) { + bool force_primary_format = false; + uint32_t optimal_format = original_format; + uint32_t z_order = plane_z_order; + // If Overlay completely covers primary and isn't transparent, try to find + // optimal format w.r.t primary plane. This guarantees that optimal format + // would not fail page flip when plane manager/CC collapses planes. + if (plane_bounds == window_bounds && + !NeedsAlphaComposition(original_format)) { + z_order = 0; +#if !defined(USE_DRM_ATOMIC) + // Page flip can fail when trying to flip a buffer of format other than + // what was used during Modeset on non atomic kernels. There is no + // definitive way to query this. + force_primary_format = true; +#endif + } + + if (force_primary_format) { + optimal_format = DRM_FORMAT_XRGB8888; + } else { + if (controller->IsFormatSupported(DRM_FORMAT_UYVY, z_order)) { + optimal_format = DRM_FORMAT_UYVY; + } else if (controller->IsFormatSupported(DRM_FORMAT_XRGB8888, z_order)) { + optimal_format = DRM_FORMAT_XRGB8888; + } + } + + return optimal_format; +} + +} // namespace + +DrmOverlayValidator::OverlayHints::OverlayHints(uint32_t format, + bool scale_buffer) + : optimal_format(format), handle_scaling(scale_buffer) {} + +DrmOverlayValidator::OverlayHints::~OverlayHints() {} + +DrmOverlayValidator::DrmOverlayValidator(DrmWindow* window) + : window_(window), overlay_hints_cache_(kMaxCacheSize) {} + +DrmOverlayValidator::~DrmOverlayValidator() {} + +std::vector<OverlayCheck_Params> DrmOverlayValidator::TestPageFlip( + const std::vector<OverlayCheck_Params>& params, + const OverlayPlaneList& last_used_planes, + ScanoutBufferGenerator* buffer_generator) { + std::vector<OverlayCheck_Params> validated_params = params; + HardwareDisplayController* controller = window_->GetController(); + if (!controller) { + // Nothing much we can do here. + for (auto& overlay : validated_params) + overlay.is_overlay_candidate = false; + + return validated_params; + } + + OverlayPlaneList test_list; + std::vector<scoped_refptr<ScanoutBuffer>> reusable_buffers; + scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice(); + + for (const auto& plane : last_used_planes) + reusable_buffers.push_back(plane.buffer); + + for (auto& overlay : validated_params) { + if (!overlay.is_overlay_candidate) + continue; + + gfx::Size scaled_buffer_size = GetScaledSize( + overlay.buffer_size, overlay.display_rect, overlay.crop_rect); + + scoped_refptr<ScanoutBuffer> buffer = GetBufferForPageFlipTest( + drm, scaled_buffer_size, GetFourCCFormatForFramebuffer(overlay.format), + buffer_generator, &reusable_buffers); + DCHECK(buffer); + + OverlayPlane plane(buffer, overlay.plane_z_order, overlay.transform, + overlay.display_rect, overlay.crop_rect); + test_list.push_back(plane); + + if (controller->TestPageFlip(test_list)) { + overlay.is_overlay_candidate = true; + } else { + // If test failed here, platform cannot support this configuration + // with current combination of layers. This is usually the case when this + // plane has requested post processing capability which needs additional + // hardware resources and they might be already in use by other planes. + // For example this plane has requested scaling capabilities and all + // available scalars are already in use by other planes. + DCHECK(test_list.size() > 1); + overlay.is_overlay_candidate = false; + test_list.pop_back(); + } + } + + UpdateOverlayHintsCache(drm, test_list, buffer_generator, &reusable_buffers); + + return validated_params; +} + +uint32_t DrmOverlayValidator::GetOptimalBufferFormat( + const OverlayPlane& plane, + const OverlayPlaneList& plane_list) const { + const auto& iter = overlay_hints_cache_.Peek(plane_list); + // We dont have any information in cache about this combination of layers, + // return standard BGRX format. + if (iter == overlay_hints_cache_.end()) + return DRM_FORMAT_XRGB8888; + + DCHECK(plane_list.size() == iter->second.size()); + + size_t size = plane_list.size(); + uint32_t index; + for (index = 0; index < size; index++) { + const OverlayPlane& test_plane = plane_list.at(index); + if (test_plane.z_order == plane.z_order && + test_plane.plane_transform == plane.plane_transform && + test_plane.display_bounds == plane.display_bounds && + test_plane.crop_rect == plane.crop_rect) { + break; + } + } + + return iter->second.at(index).optimal_format; +} + +void DrmOverlayValidator::ClearCache() { + overlay_hints_cache_.Clear(); +} + +void DrmOverlayValidator::UpdateOverlayHintsCache( + const scoped_refptr<DrmDevice>& drm, + const OverlayPlaneList& plane_list, + ScanoutBufferGenerator* buffer_generator, + std::vector<scoped_refptr<ScanoutBuffer>>* reusable_buffers) { + const auto& iter = overlay_hints_cache_.Get(plane_list); + if (iter != overlay_hints_cache_.end()) + return; + + OverlayPlaneList preferred_format_test_list = plane_list; + HardwareDisplayController* controller = window_->GetController(); + OverlayHintsList overlay_hints; + for (auto& plane : preferred_format_test_list) { + uint32_t original_format = plane.buffer->GetFramebufferPixelFormat(); + + if (plane.z_order == 0) { + overlay_hints.push_back( + OverlayHints(original_format, true /* scaling */)); + continue; + } + + uint32_t optimal_format = FindOptimalBufferFormat( + original_format, plane.z_order, plane.display_bounds, window_->bounds(), + controller); + + if (optimal_format != original_format) { + scoped_refptr<ScanoutBuffer> original_buffer = plane.buffer; + plane.buffer = + GetBufferForPageFlipTest(drm, plane.buffer->GetSize(), optimal_format, + buffer_generator, reusable_buffers); + + if (!controller->TestPageFlip(preferred_format_test_list)) { + // If test failed here, it means even though optimal_format is + // supported, platform cannot support it with current combination of + // layers. This is usually the case when optimal_format needs certain + // capabilites (i.e. conversion, scaling etc) and needed hardware + // resources might be already in use. Fall back to original format. + optimal_format = original_format; + plane.buffer = original_buffer; + } + } + + // TODO(kalyank): We always request scaling to be done by 3D engine, VPP + // etc. We should use them only if downscaling is needed and let display + // controller handle up-scaling on platforms which support it. + overlay_hints.push_back(OverlayHints(optimal_format, true /* scaling */)); + } + + // Make sure we dont hold reference to buffer when caching this plane list. + for (auto& plane : preferred_format_test_list) + plane.buffer = nullptr; + + DCHECK(preferred_format_test_list.size() == overlay_hints.size()); + overlay_hints_cache_.Put(preferred_format_test_list, overlay_hints); +} + +} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator.h b/ui/ozone/platform/drm/gpu/drm_overlay_validator.h new file mode 100644 index 0000000..c09639fc --- /dev/null +++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator.h
@@ -0,0 +1,84 @@ +// 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 UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_VALIDATOR_H_ +#define UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_VALIDATOR_H_ + +#include "base/containers/mru_cache.h" +#include "ui/ozone/platform/drm/gpu/overlay_plane.h" + +namespace ui { + +class DrmDevice; +class DrmWindow; +class HardwareDisplayController; +class ScanoutBufferGenerator; +struct OverlayCheck_Params; + +class DrmOverlayValidator { + public: + explicit DrmOverlayValidator(DrmWindow* window); + ~DrmOverlayValidator(); + + // Tests if configurations |params| are compatible with |window_| and finds + // which of these configurations can be promoted to Overlay composition + // without failing the page flip. It expects |params| to be sorted by z_order. + std::vector<OverlayCheck_Params> TestPageFlip( + const std::vector<OverlayCheck_Params>& params, + const OverlayPlaneList& last_used_planes, + ScanoutBufferGenerator* buffer_generator); + + // Tries to predict preferred format supported by hardware planes for |plane| + // for the given combination of |plane_list|. Using this format can help + // reduce read memory bandwidth during scanout for this plane. + uint32_t GetOptimalBufferFormat(const OverlayPlane& plane, + const OverlayPlaneList& plane_list) const; + + // Clears internal cache of validated overlay configurations. This should be + // usually called when |window_| size has changed or moved controller. + void ClearCache(); + + private: + // Contains hints which can be used to reduce display read memory bandwidth, + // for a given OverlayPlane. These are useful in case of video to determine + // if converting the buffer storage format before composition could lead to + // any potential bandwidth savings. Other useful hint is to determine if + // scaling needs to be done before page flip or can be handled by plane. + struct OverlayHints { + OverlayHints(uint32_t optimal_format, bool handle_scaling); + ~OverlayHints(); + // Optimal buffer storage format supported by hardware for a given + // OverlayPlane. This hint can be ignored and still compositing an + // OverlayPlane should not fail page flip or cause any visual artifacts. + uint32_t optimal_format; + // Hints if buffer scaling needs to be done before page flip as plane cannot + // support it. Ignoring this hint may result in displaying buffer with wrong + // resolution. + bool handle_scaling; + }; + + using OverlayHintsList = std::vector<OverlayHints>; + + // Check if we can optimize format for reducing Display controller read + // bandwidth for |plane_list| and cache the value. + void UpdateOverlayHintsCache( + const scoped_refptr<DrmDevice>& drm, + const OverlayPlaneList& plane_list, + ScanoutBufferGenerator* buffer_generator, + std::vector<scoped_refptr<ScanoutBuffer>>* reusable_buffers); + + DrmWindow* window_; // Not owned. + + // List of all configurations which have been validated. + base::MRUCacheBase<OverlayPlaneList, + OverlayHintsList, + base::MRUCacheNullDeletor<OverlayHintsList>> + overlay_hints_cache_; + + DISALLOW_COPY_AND_ASSIGN(DrmOverlayValidator); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_VALIDATOR_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc new file mode 100644 index 0000000..59cd6a0 --- /dev/null +++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
@@ -0,0 +1,481 @@ +// 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 <drm_fourcc.h> + +#include <utility> + +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/ozone/common/gpu/ozone_gpu_message_params.h" +#include "ui/ozone/platform/drm/common/drm_util.h" +#include "ui/ozone/platform/drm/gpu/crtc_controller.h" +#include "ui/ozone/platform/drm/gpu/drm_device_generator.h" +#include "ui/ozone/platform/drm/gpu/drm_device_manager.h" +#include "ui/ozone/platform/drm/gpu/drm_overlay_validator.h" +#include "ui/ozone/platform/drm/gpu/drm_window.h" +#include "ui/ozone/platform/drm/gpu/fake_plane_info.h" +#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" +#include "ui/ozone/platform/drm/gpu/mock_drm_device.h" +#include "ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.h" +#include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h" +#include "ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h" +#include "ui/ozone/platform/drm/gpu/screen_manager.h" + +namespace { + +// Mode of size 6x4. +const drmModeModeInfo kDefaultMode = + {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}}; + +const gfx::AcceleratedWidget kDefaultWidgetHandle = 1; +const uint32_t kDefaultCrtc = 1; +const uint32_t kDefaultConnector = 2; +const uint32_t kSecondaryCrtc = 3; +const uint32_t kSecondaryConnector = 4; +const size_t kPlanesPerCrtc = 1; + +} // namespace + +class DrmOverlayValidatorTest : public testing::Test { + public: + DrmOverlayValidatorTest() {} + + void SetUp() override; + void TearDown() override; + + void OnSwapBuffers(gfx::SwapResult result) { + on_swap_buffers_count_++; + last_swap_buffers_result_ = result; + } + + protected: + scoped_ptr<base::MessageLoop> message_loop_; + scoped_refptr<ui::MockDrmDevice> drm_; + scoped_ptr<ui::MockScanoutBufferGenerator> buffer_generator_; + scoped_ptr<ui::ScreenManager> screen_manager_; + scoped_ptr<ui::DrmDeviceManager> drm_device_manager_; + ui::MockHardwareDisplayPlaneManager* plane_manager_; + ui::DrmWindow* window_; + scoped_ptr<ui::DrmOverlayValidator> overlay_validator_; + std::vector<ui::OverlayCheck_Params> overlay_params_; + ui::OverlayPlaneList plane_list_; + + int on_swap_buffers_count_; + gfx::SwapResult last_swap_buffers_result_; + gfx::Rect overlay_rect_; + gfx::Rect primary_rect_; + + private: + DISALLOW_COPY_AND_ASSIGN(DrmOverlayValidatorTest); +}; + +void DrmOverlayValidatorTest::SetUp() { + on_swap_buffers_count_ = 0; + last_swap_buffers_result_ = gfx::SwapResult::SWAP_FAILED; + + message_loop_.reset(new base::MessageLoopForUI); + std::vector<uint32_t> crtcs; + crtcs.push_back(kDefaultCrtc); + drm_ = new ui::MockDrmDevice(false, crtcs, kPlanesPerCrtc); + buffer_generator_.reset(new ui::MockScanoutBufferGenerator()); + screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get())); + screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector); + screen_manager_->ConfigureDisplayController( + drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode); + + drm_device_manager_.reset(new ui::DrmDeviceManager(nullptr)); + + scoped_ptr<ui::DrmWindow> window(new ui::DrmWindow( + kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get())); + window->Initialize(); + window->SetBounds( + gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay))); + screen_manager_->AddWindow(kDefaultWidgetHandle, std::move(window)); + plane_manager_ = + static_cast<ui::MockHardwareDisplayPlaneManager*>(drm_->plane_manager()); + window_ = screen_manager_->GetWindow(kDefaultWidgetHandle); + overlay_validator_.reset(new ui::DrmOverlayValidator(window_)); + + overlay_rect_ = + gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2); + + primary_rect_ = gfx::Rect(0, 0, kDefaultMode.hdisplay, kDefaultMode.vdisplay); + + ui::OverlayCheck_Params primary_candidate; + primary_candidate.buffer_size = primary_rect_.size(); + primary_candidate.display_rect = primary_rect_; + overlay_params_.push_back(primary_candidate); + + ui::OverlayCheck_Params overlay_candidate; + overlay_candidate.buffer_size = overlay_rect_.size(); + overlay_candidate.display_rect = overlay_rect_; + overlay_candidate.plane_z_order = 1; + overlay_params_.push_back(overlay_candidate); + + for (const auto& param : overlay_params_) { + ui::OverlayPlane plane(nullptr, param.plane_z_order, param.transform, + param.display_rect, param.crop_rect); + plane_list_.push_back(plane); + } +} + +void DrmOverlayValidatorTest::TearDown() { + scoped_ptr<ui::DrmWindow> window = + screen_manager_->RemoveWindow(kDefaultWidgetHandle); + window->Shutdown(); + message_loop_.reset(); +} + +TEST_F(DrmOverlayValidatorTest, WindowWithNoController) { + // We should never promote layers to overlay when controller is not + // present. + ui::HardwareDisplayController* controller = window_->GetController(); + window_->SetController(nullptr); + std::vector<ui::OverlayCheck_Params> validated_params = + overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList(), + buffer_generator_.get()); + EXPECT_EQ(false, validated_params.front().is_overlay_candidate); + EXPECT_EQ(false, validated_params.back().is_overlay_candidate); + window_->SetController(controller); +} + +TEST_F(DrmOverlayValidatorTest, DontPromoteMoreLayersThanAvailablePlanes) { + std::vector<ui::OverlayCheck_Params> validated_params = + overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList(), + buffer_generator_.get()); + EXPECT_EQ(true, validated_params.front().is_overlay_candidate); + EXPECT_EQ(false, validated_params.back().is_overlay_candidate); +} + +TEST_F(DrmOverlayValidatorTest, DontCollapseOverlayToPrimaryInFullScreen) { + // Overlay Validator should not collapse planes during validation. + overlay_params_.back().buffer_size = primary_rect_.size(); + overlay_params_.back().display_rect = primary_rect_; + plane_list_.back().display_bounds = primary_rect_; + + std::vector<ui::OverlayCheck_Params> validated_params = + overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList(), + buffer_generator_.get()); + // Second candidate should be marked as Invalid as we have only one plane + // per CRTC. + EXPECT_EQ(true, validated_params.front().is_overlay_candidate); + EXPECT_EQ(false, validated_params.back().is_overlay_candidate); +} + +TEST_F(DrmOverlayValidatorTest, ClearCacheOnReset) { + // This test checks if we invalidate cache when Reset is called. + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = overlay_rect_; + plane_list_.back().display_bounds = overlay_rect_; + std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888, + DRM_FORMAT_UYVY}; + + ui::FakePlaneInfo primary_plane_info( + 100, 1 << 0, std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888)); + ui::FakePlaneInfo overlay_info(101, 1 << 0, xrgb_yuv_packed_formats); + std::vector<ui::FakePlaneInfo> planes_info{primary_plane_info, overlay_info}; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList(), + buffer_generator_.get()); + + uint32_t optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); + EXPECT_EQ(DRM_FORMAT_UYVY, optimal_format); + // Check if ClearCache actually clears the cache. + overlay_validator_->ClearCache(); + optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); + // There should be no entry in cache for this configuration and should return + // default value of DRM_FORMAT_XRGB8888. + EXPECT_EQ(DRM_FORMAT_XRGB8888, optimal_format); +} + +TEST_F(DrmOverlayValidatorTest, OptimalFormatForOverlayInFullScreen_XRGB) { + // Optimal format for Overlay configuration should be XRGB, when primary plane + // supports only XRGB and overlay obscures primary. + overlay_params_.back().buffer_size = primary_rect_.size(); + overlay_params_.back().display_rect = primary_rect_; + plane_list_.back().display_bounds = primary_rect_; + + // Check optimal format for Overlay. + ui::FakePlaneInfo primary_plane_info( + 100, 1 << 0, std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888)); + std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888, + DRM_FORMAT_UYVY}; + ui::FakePlaneInfo plane_info(101, 1 << 0, xrgb_yuv_packed_formats); + + std::vector<ui::FakePlaneInfo> planes{primary_plane_info, plane_info}; + plane_manager_->SetPlaneProperties(planes); + overlay_validator_->ClearCache(); + + overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList(), + buffer_generator_.get()); + uint32_t optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); + EXPECT_EQ(DRM_FORMAT_XRGB8888, optimal_format); +} + +TEST_F(DrmOverlayValidatorTest, OptimalFormatForOverlayInFullScreen_YUV) { + overlay_params_.back().buffer_size = primary_rect_.size(); + overlay_params_.back().display_rect = primary_rect_; + plane_list_.back().display_bounds = primary_rect_; + std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888, + DRM_FORMAT_UYVY}; + + // We should prefer YUV when primary can support it. + ui::FakePlaneInfo primary_plane_info(100, 1 << 0, xrgb_yuv_packed_formats); + ui::FakePlaneInfo plane_info(101, 1 << 0, xrgb_yuv_packed_formats); + + std::vector<ui::FakePlaneInfo> planes{primary_plane_info, plane_info}; + plane_manager_->SetPlaneProperties(planes); + overlay_validator_->ClearCache(); + + overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList(), + buffer_generator_.get()); + uint32_t optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); +#if defined(USE_DRM_ATOMIC) + EXPECT_EQ(DRM_FORMAT_UYVY, optimal_format); +#else + // If Atomic support is disabled, ensure we choose DRM_FORMAT_XRGB8888 as the + // optimal format even if other packed formats are supported by Primary. + EXPECT_EQ(DRM_FORMAT_XRGB8888, optimal_format); +#endif +} + +TEST_F(DrmOverlayValidatorTest, OverlayPreferredFormat_YUV) { + plane_manager_->ResetPlaneCount(); + // This test checks for optimal format in case of non full screen video case. + // Prefer YUV as optimal format when Overlay supports it. + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = overlay_rect_; + plane_list_.back().display_bounds = overlay_rect_; + + std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888, + DRM_FORMAT_UYVY}; + ui::FakePlaneInfo primary_plane_info( + 100, 1 << 0, std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888)); + ui::FakePlaneInfo overlay_info(101, 1 << 0, xrgb_yuv_packed_formats); + std::vector<ui::FakePlaneInfo> planes_info{primary_plane_info, overlay_info}; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + std::vector<ui::OverlayCheck_Params> validated_params = + overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList(), + buffer_generator_.get()); + + for (const auto& param : validated_params) + EXPECT_EQ(true, param.is_overlay_candidate); + + EXPECT_EQ(5, plane_manager_->plane_count()); + + uint32_t optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); + EXPECT_EQ(DRM_FORMAT_UYVY, optimal_format); +} + +TEST_F(DrmOverlayValidatorTest, OverlayPreferredFormat_XRGB) { + plane_manager_->ResetPlaneCount(); + // This test checks for optimal format in case of non full screen video case. + // This should be XRGB when overlay doesn't support YUV. + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = overlay_rect_; + plane_list_.back().display_bounds = overlay_rect_; + + std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888, + DRM_FORMAT_UYVY}; + ui::FakePlaneInfo primary_plane_info(100, 1 << 0, xrgb_yuv_packed_formats); + ui::FakePlaneInfo overlay_info(101, 1 << 0, + std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888)); + std::vector<ui::FakePlaneInfo> planes_info{primary_plane_info, overlay_info}; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + std::vector<ui::OverlayCheck_Params> validated_params = + overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList(), + buffer_generator_.get()); + uint32_t optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); + + EXPECT_EQ(DRM_FORMAT_XRGB8888, optimal_format); + EXPECT_EQ(3, plane_manager_->plane_count()); + for (const auto& param : validated_params) + EXPECT_EQ(true, param.is_overlay_candidate); +} + +TEST_F(DrmOverlayValidatorTest, RejectYUVBuffersIfNotSupported) { + plane_manager_->ResetPlaneCount(); + // Check case where buffer storage format is already UYVY but planes dont + // support it. + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = overlay_rect_; + plane_list_.back().display_bounds = overlay_rect_; + + std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888, + DRM_FORMAT_UYVY}; + ui::FakePlaneInfo primary_plane_info(100, 1 << 0, xrgb_yuv_packed_formats); + ui::FakePlaneInfo overlay_info(101, 1 << 0, + std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888)); + std::vector<ui::FakePlaneInfo> planes_info{primary_plane_info, overlay_info}; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + std::vector<ui::OverlayCheck_Params> validated_params = overlay_params_; + validated_params.back().format = gfx::BufferFormat::UYVY_422; + plane_manager_->ResetPlaneCount(); + validated_params = overlay_validator_->TestPageFlip( + validated_params, ui::OverlayPlaneList(), buffer_generator_.get()); + + EXPECT_EQ(false, validated_params.back().is_overlay_candidate); +} + +TEST_F(DrmOverlayValidatorTest, + RejectYUVBuffersIfNotSupported_MirroredControllers) { + std::vector<uint32_t> crtcs{kDefaultCrtc, kSecondaryCrtc}; + plane_manager_->SetCrtcInfo(crtcs); + + std::vector<uint32_t> only_rgb_format{DRM_FORMAT_XRGB8888}; + std::vector<uint32_t> xrgb_yuv_packed_formats{DRM_FORMAT_XRGB8888, + DRM_FORMAT_UYVY}; + ui::HardwareDisplayController* controller = window_->GetController(); + controller->AddCrtc(scoped_ptr<ui::CrtcController>( + new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector))); + ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>( + new ui::MockScanoutBuffer(primary_rect_.size()))); + EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode)); + + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = overlay_rect_; + plane_list_.back().display_bounds = overlay_rect_; + + ui::FakePlaneInfo primary_crtc_primary_plane(100, 1 << 0, only_rgb_format); + ui::FakePlaneInfo primary_crtc_overlay(101, 1 << 0, xrgb_yuv_packed_formats); + ui::FakePlaneInfo secondary_crtc_primary_plane(102, 1 << 1, only_rgb_format); + ui::FakePlaneInfo secondary_crtc_overlay(103, 1 << 1, + xrgb_yuv_packed_formats); + + std::vector<ui::FakePlaneInfo> planes_info{ + primary_crtc_primary_plane, primary_crtc_overlay, + secondary_crtc_primary_plane, secondary_crtc_overlay}; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + std::vector<ui::OverlayCheck_Params> validated_params = overlay_params_; + validated_params.back().format = gfx::BufferFormat::UYVY_422; + plane_manager_->ResetPlaneCount(); + validated_params = overlay_validator_->TestPageFlip( + validated_params, ui::OverlayPlaneList(), buffer_generator_.get()); + + EXPECT_EQ(true, validated_params.back().is_overlay_candidate); + + // Both controllers have Overlay which support DRM_FORMAT_UYVY, hence this + // should be picked as the optimal format. + uint32_t optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); + EXPECT_EQ(DRM_FORMAT_UYVY, optimal_format); + + // This configuration should not be promoted to Overlay when either of the + // controllers dont support UYVY format. + + // Check case where we dont have support for packed formats in Mirrored CRTC. + planes_info.back().allowed_formats = only_rgb_format; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + validated_params = overlay_validator_->TestPageFlip( + validated_params, ui::OverlayPlaneList(), buffer_generator_.get()); + EXPECT_EQ(false, validated_params.back().is_overlay_candidate); + + // Check case where we dont have support for packed formats in primary + // display. + planes_info.back().allowed_formats = xrgb_yuv_packed_formats; + planes_info[1].allowed_formats = only_rgb_format; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + validated_params = overlay_validator_->TestPageFlip( + validated_params, ui::OverlayPlaneList(), buffer_generator_.get()); + EXPECT_EQ(false, validated_params.back().is_overlay_candidate); + controller->RemoveCrtc(drm_, kSecondaryCrtc); +} + +TEST_F(DrmOverlayValidatorTest, OptimalFormatYUV_MirroredControllers) { + std::vector<uint32_t> crtcs{kDefaultCrtc, kSecondaryCrtc}; + plane_manager_->SetCrtcInfo(crtcs); + overlay_validator_->ClearCache(); + + ui::HardwareDisplayController* controller = window_->GetController(); + controller->AddCrtc(scoped_ptr<ui::CrtcController>( + new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector))); + ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>( + new ui::MockScanoutBuffer(primary_rect_.size()))); + EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode)); + + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = overlay_rect_; + plane_list_.back().display_bounds = overlay_rect_; + std::vector<uint32_t> only_rgb_format = {DRM_FORMAT_XRGB8888}; + std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888, + DRM_FORMAT_UYVY}; + + ui::FakePlaneInfo primary_crtc_primary_plane(100, 1 << 0, only_rgb_format); + ui::FakePlaneInfo primary_crtc_overlay(101, 1 << 0, xrgb_yuv_packed_formats); + ui::FakePlaneInfo secondary_crtc_primary_plane(102, 1 << 1, only_rgb_format); + ui::FakePlaneInfo secondary_crtc_overlay(103, 1 << 1, + xrgb_yuv_packed_formats); + + std::vector<ui::FakePlaneInfo> planes_info{ + primary_crtc_primary_plane, primary_crtc_overlay, + secondary_crtc_primary_plane, secondary_crtc_overlay}; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + plane_manager_->ResetPlaneCount(); + std::vector<ui::OverlayCheck_Params> validated_params = + overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList(), + buffer_generator_.get()); + + EXPECT_EQ(true, validated_params.back().is_overlay_candidate); + // Both controllers have Overlay which support DRM_FORMAT_UYVY, hence this + // should be picked as the optimal format. + uint32_t optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); + EXPECT_EQ(DRM_FORMAT_UYVY, optimal_format); + + // DRM_FORMAT_XRGB8888 should be the preferred format when either of the + // controllers dont support UYVY format. + + // Check case where we dont have support for packed formats in Mirrored CRTC. + planes_info.back().allowed_formats = only_rgb_format; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + validated_params = overlay_validator_->TestPageFlip( + overlay_params_, ui::OverlayPlaneList(), buffer_generator_.get()); + EXPECT_EQ(true, validated_params.back().is_overlay_candidate); + + optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); + EXPECT_EQ(DRM_FORMAT_XRGB8888, optimal_format); + + // Check case where we dont have support for packed formats in primary + // display. + planes_info.back().allowed_formats = xrgb_yuv_packed_formats; + planes_info[1].allowed_formats = only_rgb_format; + plane_manager_->SetPlaneProperties(planes_info); + overlay_validator_->ClearCache(); + + validated_params = overlay_validator_->TestPageFlip( + overlay_params_, ui::OverlayPlaneList(), buffer_generator_.get()); + EXPECT_EQ(true, validated_params.back().is_overlay_candidate); + + optimal_format = overlay_validator_->GetOptimalBufferFormat( + plane_list_.back(), plane_list_); + EXPECT_EQ(DRM_FORMAT_XRGB8888, optimal_format); + controller->RemoveCrtc(drm_, kSecondaryCrtc); +}
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc index 32236c1..9fba31b8 100644 --- a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc +++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -153,6 +153,17 @@ return plane_ids; } +bool HardwareDisplayController::IsFormatSupported(uint32_t fourcc_format, + uint32_t z_order) const { + for (size_t i = 0; i < crtc_controllers_.size(); ++i) { + // Make sure all displays have overlay to support this format. + if (!crtc_controllers_[i]->IsFormatSupported(fourcc_format, z_order)) + return false; + } + + return true; +} + bool HardwareDisplayController::SetCursor( const scoped_refptr<ScanoutBuffer>& buffer) { bool status = true;
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/ui/ozone/platform/drm/gpu/hardware_display_controller.h index 5c6855e1..a09da0e0 100644 --- a/ui/ozone/platform/drm/gpu/hardware_display_controller.h +++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.h
@@ -128,6 +128,8 @@ std::vector<uint32_t> GetCompatibleHardwarePlaneIds( const OverlayPlane& plane) const; + bool IsFormatSupported(uint32_t fourcc_format, uint32_t z_order) const; + // Set the hardware cursor to show the contents of |surface|. bool SetCursor(const scoped_refptr<ScanoutBuffer>& buffer);
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc index 6a8ed5dd..5e734c8 100644 --- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc +++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
@@ -299,4 +299,37 @@ return plane_ids; } +bool HardwareDisplayPlaneManager::IsFormatSupported(uint32_t fourcc_format, + uint32_t z_order, + uint32_t crtc_id) const { + bool format_supported = false; + int crtc_index = LookupCrtcIndex(crtc_id); + if (crtc_index < 0) { + LOG(ERROR) << "Cannot find crtc " << crtc_id; + return format_supported; + } + + // We dont have a way to query z_order of a plane. This is a temporary + // solution till driver exposes z_order property. + uint32_t plane_z_order = 0; + for (const auto& hardware_plane : planes_) { + if (plane_z_order > z_order) + break; + + if (!hardware_plane->CanUseForCrtc(crtc_index)) + continue; + + if (plane_z_order == z_order) { + if (hardware_plane->IsSupportedFormat(fourcc_format)) + format_supported = true; + + break; + } else { + plane_z_order++; + } + } + + return format_supported; +} + } // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h index 4a93183..d91a34b 100644 --- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h +++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -99,6 +99,10 @@ std::vector<uint32_t> GetCompatibleHardwarePlaneIds(const OverlayPlane& plane, uint32_t crtc_id) const; + bool IsFormatSupported(uint32_t fourcc_format, + uint32_t z_order, + uint32_t crtc_id) const; + protected: virtual bool SetPlaneData(HardwareDisplayPlaneList* plane_list, HardwareDisplayPlane* hw_plane,
diff --git a/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.cc b/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.cc index 8868372..a01818d 100644 --- a/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.cc +++ b/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.cc
@@ -43,6 +43,8 @@ drm_ = drm; } +MockHardwareDisplayPlaneManager::~MockHardwareDisplayPlaneManager() {} + void MockHardwareDisplayPlaneManager::InitForTest( const FakePlaneInfo* planes, size_t count, @@ -63,6 +65,34 @@ }); } +void MockHardwareDisplayPlaneManager::SetPlaneProperties( + const std::vector<FakePlaneInfo>& planes) { + planes_.clear(); + uint32_t count = planes.size(); + for (size_t i = 0; i < count; i++) { + scoped_ptr<HardwareDisplayPlane> plane( + new HardwareDisplayPlane(planes[i].id, planes[i].allowed_crtc_mask)); + plane->Initialize(drm_, planes[i].allowed_formats, false, true); + planes_.push_back(std::move(plane)); + } + + // The real HDPM uses sorted planes, so sort them for consistency. + std::sort(planes_.begin(), planes_.end(), + [](const scoped_ptr<HardwareDisplayPlane>& l, + const scoped_ptr<HardwareDisplayPlane>& r) { + return l->plane_id() < r->plane_id(); + }); + + ResetPlaneCount(); +} + +void MockHardwareDisplayPlaneManager::SetCrtcInfo( + const std::vector<uint32_t>& crtcs) { + crtcs_ = crtcs; + planes_.clear(); + ResetPlaneCount(); +} + bool MockHardwareDisplayPlaneManager::SetPlaneData( HardwareDisplayPlaneList* plane_list, HardwareDisplayPlane* hw_plane, @@ -83,4 +113,8 @@ return plane_count_; } +void MockHardwareDisplayPlaneManager::ResetPlaneCount() { + plane_count_ = 0; +} + } // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.h b/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.h index c9057d3..60f159e5 100644 --- a/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.h +++ b/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.h
@@ -22,12 +22,17 @@ explicit MockHardwareDisplayPlaneManager(DrmDevice* drm); + ~MockHardwareDisplayPlaneManager() override; + // Normally we'd use DRM to figure out the controller configuration. But we // can't use DRM in unit tests, so we just create a fake configuration. void InitForTest(const FakePlaneInfo* planes, size_t count, const std::vector<uint32_t>& crtcs); + void SetPlaneProperties(const std::vector<FakePlaneInfo>& planes); + void SetCrtcInfo(const std::vector<uint32_t>& crtcs); + bool SetPlaneData(HardwareDisplayPlaneList* plane_list, HardwareDisplayPlane* hw_plane, const OverlayPlane& overlay, @@ -36,6 +41,7 @@ CrtcController* crtc) override; int plane_count() const; + void ResetPlaneCount(); private: int plane_count_ = 0;
diff --git a/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.cc b/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.cc new file mode 100644 index 0000000..c370202 --- /dev/null +++ b/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.cc
@@ -0,0 +1,26 @@ +// 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 "ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h" + +#include "ui/ozone/platform/drm/common/drm_util.h" +#include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h" + +namespace ui { + +MockScanoutBufferGenerator::MockScanoutBufferGenerator() {} + +MockScanoutBufferGenerator::~MockScanoutBufferGenerator() {} + +scoped_refptr<ScanoutBuffer> MockScanoutBufferGenerator::Create( + const scoped_refptr<DrmDevice>& drm, + gfx::BufferFormat format, + const gfx::Size& size) { + scoped_refptr<MockScanoutBuffer> buffer( + new MockScanoutBuffer(size, GetFourCCFormatForFramebuffer(format))); + + return buffer; +} + +} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h b/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h new file mode 100644 index 0000000..87535ad --- /dev/null +++ b/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h
@@ -0,0 +1,30 @@ +// 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 UI_OZONE_PLATFORM_DRM_GPU_MOCK_SCANOUT_BUFFER_GENERATOR_H_ +#define UI_OZONE_PLATFORM_DRM_GPU_MOCK_SCANOUT_BUFFER_GENERATOR_H_ + +#include "base/macros.h" + +#include "ui/ozone/platform/drm/gpu/scanout_buffer.h" + +namespace ui { + +class MockScanoutBufferGenerator : public ScanoutBufferGenerator { + public: + MockScanoutBufferGenerator(); + ~MockScanoutBufferGenerator() override; + + // ScanoutBufferGenerator: + scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DrmDevice>& drm, + gfx::BufferFormat format, + const gfx::Size& size) override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockScanoutBufferGenerator); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRM_GPU_MOCK_SCANOUT_BUFFER_GENERATOR_H_
diff --git a/ui/ozone/platform/drm/gpu/overlay_plane.cc b/ui/ozone/platform/drm/gpu/overlay_plane.cc index 77dce16b4..6f5917f2 100644 --- a/ui/ozone/platform/drm/gpu/overlay_plane.cc +++ b/ui/ozone/platform/drm/gpu/overlay_plane.cc
@@ -30,6 +30,12 @@ OverlayPlane::~OverlayPlane() { } +bool OverlayPlane::operator<(const OverlayPlane& plane) const { + return std::tie(z_order, display_bounds, crop_rect, plane_transform) < + std::tie(plane.z_order, plane.display_bounds, plane.crop_rect, + plane.plane_transform); +} + // static const OverlayPlane* OverlayPlane::GetPrimaryPlane( const OverlayPlaneList& overlays) {
diff --git a/ui/ozone/platform/drm/gpu/overlay_plane.h b/ui/ozone/platform/drm/gpu/overlay_plane.h index d1d32a6..5f23f574 100644 --- a/ui/ozone/platform/drm/gpu/overlay_plane.h +++ b/ui/ozone/platform/drm/gpu/overlay_plane.h
@@ -30,6 +30,8 @@ const gfx::Rect& display_bounds, const gfx::RectF& crop_rect); + bool operator<(const OverlayPlane& plane) const; + ~OverlayPlane(); // Returns the primary plane in |overlays|.
diff --git a/ui/views/mus/native_widget_mus.cc b/ui/views/mus/native_widget_mus.cc index 4df9aeb..abe4462 100644 --- a/ui/views/mus/native_widget_mus.cc +++ b/ui/views/mus/native_widget_mus.cc
@@ -309,6 +309,14 @@ native_widget_delegate_->OnNativeWidgetCreated(false); } +void NativeWidgetMus::OnWidgetInitDone() { + // The client area is calculated from the NonClientView. During + // InitNativeWidget() the NonClientView has not been created. When this + // function is called the NonClientView has been created, so that we can + // correctly calculate the client area and push it to the mus::Window. + UpdateClientArea(); +} + bool NativeWidgetMus::ShouldUseNativeFrame() const { // NOTIMPLEMENTED(); return false;
diff --git a/ui/views/mus/native_widget_mus.h b/ui/views/mus/native_widget_mus.h index e3e42be..a940baf9 100644 --- a/ui/views/mus/native_widget_mus.h +++ b/ui/views/mus/native_widget_mus.h
@@ -84,6 +84,7 @@ // internal::NativeWidgetPrivate: NonClientFrameView* CreateNonClientFrameView() override; void InitNativeWidget(const Widget::InitParams& params) override; + void OnWidgetInitDone() override; bool ShouldUseNativeFrame() const override; bool ShouldWindowContentsBeTransparent() const override; void FrameTypeChanged() override;
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc index bd16be59..997c0542 100644 --- a/ui/views/mus/window_manager_connection.cc +++ b/ui/views/mus/window_manager_connection.cc
@@ -110,9 +110,6 @@ mus::Window* WindowManagerConnection::NewWindow( const std::map<std::string, std::vector<uint8_t>>& properties) { - if (window_tree_connection_) - return window_tree_connection_->NewTopLevelWindow(&properties); - mus::mojom::WindowTreeClientPtr window_tree_client; mojo::InterfaceRequest<mus::mojom::WindowTreeClient> window_tree_client_request = GetProxy(&window_tree_client); @@ -121,16 +118,16 @@ mojo::Map<mojo::String, mojo::Array<uint8_t>>::From(properties)); base::ThreadRestrictions::ScopedAllowWait allow_wait; - window_tree_connection_.reset(mus::WindowTreeConnection::Create( - this, std::move(window_tree_client_request), - mus::WindowTreeConnection::CreateType::WAIT_FOR_EMBED)); - window_tree_connection_->SetDeleteOnNoRoots(false); - DCHECK_EQ(1u, window_tree_connection_->GetRoots().size()); - return *window_tree_connection_->GetRoots().begin(); + mus::WindowTreeConnection* window_tree_connection = + mus::WindowTreeConnection::Create( + this, std::move(window_tree_client_request), + mus::WindowTreeConnection::CreateType::WAIT_FOR_EMBED); + DCHECK_EQ(1u, window_tree_connection->GetRoots().size()); + return *window_tree_connection->GetRoots().begin(); } WindowManagerConnection::WindowManagerConnection(mojo::ApplicationImpl* app) - : app_(app), window_tree_connection_(nullptr) { + : app_(app) { app->ConnectToService("mojo:mus", &window_manager_); ui_init_.reset(new ui::mojo::UIInit( @@ -141,9 +138,6 @@ } WindowManagerConnection::~WindowManagerConnection() { - // ~WindowTreeConnection calls back to us (we're the WindowTreeDelegate), - // destroy it while we are still valid. - window_tree_connection_.reset(); } void WindowManagerConnection::OnEmbed(mus::Window* root) {}
diff --git a/ui/views/mus/window_manager_connection.h b/ui/views/mus/window_manager_connection.h index ab12a03b..c9bf4ccc 100644 --- a/ui/views/mus/window_manager_connection.h +++ b/ui/views/mus/window_manager_connection.h
@@ -61,7 +61,6 @@ mojo::ApplicationImpl* app_; mus::mojom::WindowManagerPtr window_manager_; scoped_ptr<ui::mojo::UIInit> ui_init_; - scoped_ptr<mus::WindowTreeConnection> window_tree_connection_; DISALLOW_COPY_AND_ASSIGN(WindowManagerConnection); };
diff --git a/ui/views/widget/android/native_widget_android.cc b/ui/views/widget/android/native_widget_android.cc index f7b85f1..2aed158 100644 --- a/ui/views/widget/android/native_widget_android.cc +++ b/ui/views/widget/android/native_widget_android.cc
@@ -182,6 +182,8 @@ // the necessary parts that exists in desktop_native_widget_aura. } +void NativeWidgetAndroid::OnWidgetInitDone() {} + NonClientFrameView* NativeWidgetAndroid::CreateNonClientFrameView() { NOTIMPLEMENTED(); return nullptr;
diff --git a/ui/views/widget/android/native_widget_android.h b/ui/views/widget/android/native_widget_android.h index 4941559b..8aaa3c4 100644 --- a/ui/views/widget/android/native_widget_android.h +++ b/ui/views/widget/android/native_widget_android.h
@@ -59,6 +59,7 @@ // Overridden from internal::NativeWidgetPrivate: void InitNativeWidget(const Widget::InitParams& params) override; + void OnWidgetInitDone() override; NonClientFrameView* CreateNonClientFrameView() override; bool ShouldUseNativeFrame() const override; bool ShouldWindowContentsBeTransparent() const override;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index 3cda119..618d774 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -546,6 +546,8 @@ GetWidget()->GetRootView())); } +void DesktopNativeWidgetAura::OnWidgetInitDone() {} + NonClientFrameView* DesktopNativeWidgetAura::CreateNonClientFrameView() { return ShouldUseNativeFrame() ? new NativeFrameView(GetWidget()) : NULL; }
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index 6004090..2a756d9 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -91,6 +91,7 @@ protected: // Overridden from internal::NativeWidgetPrivate: void InitNativeWidget(const Widget::InitParams& params) override; + void OnWidgetInitDone() override; NonClientFrameView* CreateNonClientFrameView() override; bool ShouldUseNativeFrame() const override; bool ShouldWindowContentsBeTransparent() const override;
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index 7c579d1..5072bd5 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc
@@ -181,6 +181,8 @@ GetWidget()->GetRootView())); } +void NativeWidgetAura::OnWidgetInitDone() {} + NonClientFrameView* NativeWidgetAura::CreateNonClientFrameView() { return NULL; }
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h index 247b3e1..30bf169 100644 --- a/ui/views/widget/native_widget_aura.h +++ b/ui/views/widget/native_widget_aura.h
@@ -50,6 +50,7 @@ // Overridden from internal::NativeWidgetPrivate: void InitNativeWidget(const Widget::InitParams& params) override; + void OnWidgetInitDone() override; NonClientFrameView* CreateNonClientFrameView() override; bool ShouldUseNativeFrame() const override; bool ShouldWindowContentsBeTransparent() const override;
diff --git a/ui/views/widget/native_widget_mac.h b/ui/views/widget/native_widget_mac.h index cac04a04..f2f7918 100644 --- a/ui/views/widget/native_widget_mac.h +++ b/ui/views/widget/native_widget_mac.h
@@ -49,6 +49,7 @@ // internal::NativeWidgetPrivate: void InitNativeWidget(const Widget::InitParams& params) override; + void OnWidgetInitDone() override; NonClientFrameView* CreateNonClientFrameView() override; bool ShouldUseNativeFrame() const override; bool ShouldWindowContentsBeTransparent() const override;
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm index 812f730..e34f61d 100644 --- a/ui/views/widget/native_widget_mac.mm +++ b/ui/views/widget/native_widget_mac.mm
@@ -139,6 +139,8 @@ bridge_->CreateLayer(params.layer_type, translucent); } +void NativeWidgetMac::OnWidgetInitDone() {} + NonClientFrameView* NativeWidgetMac::CreateNonClientFrameView() { return new NativeFrameView(GetWidget()); }
diff --git a/ui/views/widget/native_widget_private.h b/ui/views/widget/native_widget_private.h index 2adf5894..6e52bf6 100644 --- a/ui/views/widget/native_widget_private.h +++ b/ui/views/widget/native_widget_private.h
@@ -74,6 +74,10 @@ // Initializes the NativeWidget. virtual void InitNativeWidget(const Widget::InitParams& params) = 0; + // Called at the end of Widget::Init(), after Widget has completed + // initialization. + virtual void OnWidgetInitDone() = 0; + // Returns a NonClientFrameView for the widget's NonClientView, or NULL if // the NativeWidget wants no special NonClientFrameView. virtual NonClientFrameView* CreateNonClientFrameView() = 0;
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index 04c9011..18aa4c6 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -397,6 +397,7 @@ // the correct NativeTheme (on Linux). See http://crbug.com/384492 observer_manager_.Add(GetNativeTheme()); native_widget_initialized_ = true; + native_widget_->OnWidgetInitDone(); } // Unconverted methods (see header) --------------------------------------------
diff --git a/url/origin.h b/url/origin.h index 3b9f50bd..73e6248 100644 --- a/url/origin.h +++ b/url/origin.h
@@ -67,7 +67,7 @@ // origin.scheme(); // "https" // origin.host(); // "example.com" // origin.port(); // 443 -// origin.IsUnique(); // false +// origin.unique(); // false // // * To answer the question "Are |this| and |that| "same-origin" with each // other?", use |Origin::IsSameOriginWith|: