diff --git a/DEPS b/DEPS index b951f26..e1a20ba 100644 --- a/DEPS +++ b/DEPS
@@ -40,7 +40,7 @@ # 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': 'e8f28818a2c0fe967f9fc4cec4bb9dc78af78212', + 'skia_revision': 'f90aa014d8639a0881b4cfb831b72eb0c8dfbbd7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other.
diff --git a/android_webview/browser/deferred_gpu_command_service.cc b/android_webview/browser/deferred_gpu_command_service.cc index 9cfd2ded7..2873d8c 100644 --- a/android_webview/browser/deferred_gpu_command_service.cc +++ b/android_webview/browser/deferred_gpu_command_service.cc
@@ -13,10 +13,8 @@ #include "base/trace_event/trace_event.h" #include "content/public/browser/gpu_utils.h" #include "content/public/common/content_switches.h" -#include "gpu/command_buffer/service/framebuffer_completeness_cache.h" #include "gpu/command_buffer/service/gpu_preferences.h" #include "gpu/command_buffer/service/gpu_switches.h" -#include "gpu/command_buffer/service/shader_translator_cache.h" #include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/config/gpu_switches.h" #include "ui/gl/gl_switches.h" @@ -156,24 +154,6 @@ bool DeferredGpuCommandService::UseVirtualizedGLContexts() { return true; } -scoped_refptr<gpu::gles2::ShaderTranslatorCache> -DeferredGpuCommandService::shader_translator_cache() { - if (!shader_translator_cache_.get()) { - shader_translator_cache_ = - new gpu::gles2::ShaderTranslatorCache(gpu_preferences()); - } - return shader_translator_cache_; -} - -scoped_refptr<gpu::gles2::FramebufferCompletenessCache> -DeferredGpuCommandService::framebuffer_completeness_cache() { - if (!framebuffer_completeness_cache_.get()) { - framebuffer_completeness_cache_ = - new gpu::gles2::FramebufferCompletenessCache; - } - return framebuffer_completeness_cache_; -} - gpu::SyncPointManager* DeferredGpuCommandService::sync_point_manager() { return sync_point_manager_.get(); }
diff --git a/android_webview/browser/deferred_gpu_command_service.h b/android_webview/browser/deferred_gpu_command_service.h index ed27efc4..20417222 100644 --- a/android_webview/browser/deferred_gpu_command_service.h +++ b/android_webview/browser/deferred_gpu_command_service.h
@@ -48,10 +48,6 @@ void ScheduleTask(const base::Closure& task) override; void ScheduleDelayedWork(const base::Closure& task) override; bool UseVirtualizedGLContexts() override; - scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache() - override; - scoped_refptr<gpu::gles2::FramebufferCompletenessCache> - framebuffer_completeness_cache() override; gpu::SyncPointManager* sync_point_manager() override; void RunTasks(); @@ -82,9 +78,6 @@ std::queue<std::pair<base::Time, base::Closure> > idle_tasks_; std::unique_ptr<gpu::SyncPointManager> sync_point_manager_; - scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache_; - scoped_refptr<gpu::gles2::FramebufferCompletenessCache> - framebuffer_completeness_cache_; DISALLOW_COPY_AND_ASSIGN(DeferredGpuCommandService); };
diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc index 422297e..a77ff4af 100644 --- a/ash/wm/system_gesture_event_filter_unittest.cc +++ b/ash/wm/system_gesture_event_filter_unittest.cc
@@ -344,11 +344,11 @@ bounds = toplevel->GetNativeWindow()->bounds(); // Swipe right and down starting with one finger. // Add another finger after 120ms and continue dragging. - // The window should move and the drag should be determined by the center - // point between the fingers. + // The window should not move (see crbug.com/363625) and drag should be + // determined by the delta of center point between the fingers. generator.GestureMultiFingerScrollWithDelays(kTouchPoints, points, delays, 15, kSteps, 150, 150); - bounds += gfx::Vector2d(150 + (points[1].x() - points[0].x()) / 2, 150); + bounds += gfx::Vector2d(150, 150); EXPECT_EQ(bounds.ToString(), toplevel->GetNativeWindow()->bounds().ToString()); }
diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc index 4739631..c040e73 100644 --- a/ash/wm/toplevel_window_event_handler_unittest.cc +++ b/ash/wm/toplevel_window_event_handler_unittest.cc
@@ -540,6 +540,146 @@ EXPECT_FALSE(wm::GetWindowState(target.get())->IsMinimized()); } +TEST_F(ToplevelWindowEventHandlerTest, TwoFingerDragDifferentDelta) { + std::unique_ptr<aura::Window> target(CreateWindow(HTCAPTION)); + ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), + target.get()); + + const int kSteps = 10; + const int kTouchPoints = 2; + gfx::Point points[kTouchPoints] = { + gfx::Point(5, 5), // Within caption. + gfx::Point(55, 5), // Within caption. + }; + gfx::Vector2d delta[kTouchPoints] = { + gfx::Vector2d(80, 80), gfx::Vector2d(20, 20), + }; + int delay_adding_finger_ms[kTouchPoints] = {0, 0}; + int delay_releasing_finger_ms[kTouchPoints] = {150, 150}; + + gfx::Rect bounds = target->bounds(); + // Swipe right and down starting with two fingers. Two fingers have different + // moving deltas. The window position should move along the average vector of + // these two fingers. + generator.GestureMultiFingerScrollWithDelays( + kTouchPoints, points, delta, delay_adding_finger_ms, + delay_releasing_finger_ms, 15, kSteps); + bounds += gfx::Vector2d(50, 50); + EXPECT_EQ(bounds.ToString(), target->bounds().ToString()); +} + +TEST_F(ToplevelWindowEventHandlerTest, TwoFingerDragDelayAddFinger) { + std::unique_ptr<aura::Window> target(CreateWindow(HTCAPTION)); + ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), + target.get()); + + const int kSteps = 10; + const int kTouchPoints = 2; + gfx::Point points[kTouchPoints] = { + gfx::Point(5, 5), // Within caption. + gfx::Point(55, 5), // Within caption. + }; + gfx::Vector2d delta[kTouchPoints] = { + gfx::Vector2d(50, 50), gfx::Vector2d(50, 50), + }; + int delay_adding_finger_ms[kTouchPoints] = {0, 90}; + int delay_releasing_finger_ms[kTouchPoints] = {150, 150}; + + gfx::Rect bounds = target->bounds(); + // Swipe right and down starting with one fingers. Add another finger at 90ms + // and continue dragging. The drag should continue without interrupt. + generator.GestureMultiFingerScrollWithDelays( + kTouchPoints, points, delta, delay_adding_finger_ms, + delay_releasing_finger_ms, 15, kSteps); + bounds += gfx::Vector2d(50, 50); + EXPECT_EQ(bounds.ToString(), target->bounds().ToString()); +} + +TEST_F(ToplevelWindowEventHandlerTest, TwoFingerDragDelayReleaseFinger) { + std::unique_ptr<aura::Window> target(CreateWindow(HTCAPTION)); + ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), + target.get()); + + const int kSteps = 10; + const int kTouchPoints = 2; + gfx::Point points[kTouchPoints] = { + gfx::Point(5, 5), // Within caption. + gfx::Point(55, 5), // Within caption. + }; + gfx::Vector2d delta[kTouchPoints] = { + gfx::Vector2d(50, 50), gfx::Vector2d(50, 50), + }; + int delay_adding_finger_ms[kTouchPoints] = {0, 0}; + int delay_releasing_finger_ms[kTouchPoints] = {150, 90}; + + gfx::Rect bounds = target->bounds(); + // Swipe right and down starting with two fingers. Remove one finger at 90ms + // and continue dragging. The drag should continue without interrupt. + generator.GestureMultiFingerScrollWithDelays( + kTouchPoints, points, delta, delay_adding_finger_ms, + delay_releasing_finger_ms, 15, kSteps); + bounds += gfx::Vector2d(50, 50); + EXPECT_EQ(bounds.ToString(), target->bounds().ToString()); +} + +TEST_F(ToplevelWindowEventHandlerTest, + TwoFingerDragDelayAdd2ndAndRelease2ndFinger) { + std::unique_ptr<aura::Window> target(CreateWindow(HTCAPTION)); + ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), + target.get()); + + const int kSteps = 10; + const int kTouchPoints = 2; + gfx::Point points[kTouchPoints] = { + gfx::Point(5, 5), // Within caption. + gfx::Point(55, 5), // Within caption. + }; + gfx::Vector2d delta[kTouchPoints] = { + gfx::Vector2d(50, 50), gfx::Vector2d(50, 50), + }; + int delay_adding_finger_ms[kTouchPoints] = {0, 30}; + int delay_releasing_finger_ms[kTouchPoints] = {150, 120}; + + gfx::Rect bounds = target->bounds(); + // Swipe right and down starting with one fingers. Add second finger at 30ms, + // continue dragging, release second finger at 120ms and continue dragging. + // The drag should continue without interrupt. + generator.GestureMultiFingerScrollWithDelays( + kTouchPoints, points, delta, delay_adding_finger_ms, + delay_releasing_finger_ms, 15, kSteps); + bounds += gfx::Vector2d(50, 50); + EXPECT_EQ(bounds.ToString(), target->bounds().ToString()); +} + +TEST_F(ToplevelWindowEventHandlerTest, + TwoFingerDragDelayAdd2ndAndRelease1stFinger) { + std::unique_ptr<aura::Window> target(CreateWindow(HTCAPTION)); + ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), + target.get()); + + const int kSteps = 10; + const int kTouchPoints = 2; + gfx::Point points[kTouchPoints] = { + gfx::Point(5, 5), // Within caption. + gfx::Point(55, 5), // Within caption. + }; + gfx::Vector2d delta[kTouchPoints] = { + gfx::Vector2d(50, 50), gfx::Vector2d(50, 50), + }; + int delay_adding_finger_ms[kTouchPoints] = {0, 30}; + int delay_releasing_finger_ms[kTouchPoints] = {120, 150}; + + gfx::Rect bounds = target->bounds(); + // Swipe right and down starting with one fingers. Add second finger at 30ms, + // continue dragging, release first finger at 120ms and continue dragging. + // The drag should continue without interrupt. + generator.GestureMultiFingerScrollWithDelays( + kTouchPoints, points, delta, delay_adding_finger_ms, + delay_releasing_finger_ms, 15, kSteps); + bounds += gfx::Vector2d(50, 50); + EXPECT_EQ(bounds.ToString(), target->bounds().ToString()); +} + TEST_F(ToplevelWindowEventHandlerTest, GestureDragToRestore) { std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate( new TestWindowDelegate(HTCAPTION), 0, gfx::Rect(10, 20, 30, 40)));
diff --git a/ash/wm/wm_toplevel_window_event_handler.cc b/ash/wm/wm_toplevel_window_event_handler.cc index e400861..7e67f4cd 100644 --- a/ash/wm/wm_toplevel_window_event_handler.cc +++ b/ash/wm/wm_toplevel_window_event_handler.cc
@@ -258,6 +258,9 @@ } case ui::ET_GESTURE_BEGIN: { if (event->details().touch_points() == 1) { + first_finger_touch_point_ = event->location(); + aura::Window::ConvertPointToTarget(target, target->parent(), + &first_finger_touch_point_); first_finger_hittest_ = GetNonClientComponent(target, event->location()); } else if (window_resizer_.get()) { @@ -275,9 +278,7 @@ GetNonClientComponent(target, event->location()); if (CanStartTwoFingerMove(target, first_finger_hittest_, second_finger_hittest)) { - gfx::Point location_in_parent = - event->details().bounding_box().CenterPoint(); - AttemptToStartDrag(target, location_in_parent, HTCAPTION, + AttemptToStartDrag(target, first_finger_touch_point_, HTCAPTION, ::wm::WINDOW_MOVE_SOURCE_TOUCH, EndClosure()); event->StopPropagation(); }
diff --git a/ash/wm/wm_toplevel_window_event_handler.h b/ash/wm/wm_toplevel_window_event_handler.h index 7394283f..58dc1f55 100644 --- a/ash/wm/wm_toplevel_window_event_handler.h +++ b/ash/wm/wm_toplevel_window_event_handler.h
@@ -105,6 +105,10 @@ // touched the screen. |first_finger_hittest_| is one of ui/base/hit_test.h int first_finger_hittest_; + // The point for the first finger at the time that it initially touched the + // screen. + gfx::Point first_finger_touch_point_; + // The window bounds when the drag was started. When a window is minimized, // maximized or snapped via a swipe/fling gesture, the restore bounds should // be set to the bounds of the window when the drag was started.
diff --git a/build/android/pylib/utils/logging_utils.py b/build/android/pylib/utils/logging_utils.py index 2c2eabf..41c61338 100644 --- a/build/android/pylib/utils/logging_utils.py +++ b/build/android/pylib/utils/logging_utils.py
@@ -11,9 +11,37 @@ _COLORAMA_PATH = os.path.join( host_paths.DIR_SOURCE_ROOT, 'third_party', 'colorama', 'src') -with host_paths.SysPath(_COLORAMA_PATH): +with host_paths.SysPath(_COLORAMA_PATH, position=0): import colorama + +class _ColorFormatter(logging.Formatter): + # pylint does not see members added dynamically in the constructor. + # pylint: disable=no-member + color_map = { + logging.DEBUG: colorama.Fore.CYAN, + logging.WARNING: colorama.Fore.YELLOW, + logging.ERROR: colorama.Fore.RED, + logging.CRITICAL: colorama.Back.RED + colorama.Style.BRIGHT, + } + + def __init__(self, wrapped_formatter=None): + """Wraps a |logging.Formatter| and adds color.""" + super(_ColorFormatter, self).__init__(self) + self._wrapped_formatter = wrapped_formatter or logging.Formatter() + + #override + def format(self, record): + message = self._wrapped_formatter.format(record) + return self.Colorize(message, record.levelno) + + def Colorize(self, message, log_level): + try: + return self.color_map[log_level] + message + colorama.Style.RESET_ALL + except KeyError: + return message + + class ColorStreamHandler(logging.StreamHandler): """Handler that can be used to colorize logging output. @@ -29,18 +57,10 @@ logging.info('message') """ - # pylint does not see members added dynamically in the constructor. - # pylint: disable=no-member - color_map = { - logging.DEBUG: colorama.Fore.CYAN, - logging.WARNING: colorama.Fore.YELLOW, - logging.ERROR: colorama.Fore.RED, - logging.CRITICAL: colorama.Back.RED + colorama.Style.BRIGHT, - } - def __init__(self, force_color=False): super(ColorStreamHandler, self).__init__() self.force_color = force_color + self.setFormatter(logging.Formatter()) @property def is_tty(self): @@ -48,17 +68,10 @@ return isatty and isatty() #override - def format(self, record): - message = logging.StreamHandler.format(self, record) + def setFormatter(self, formatter): if self.force_color or self.is_tty: - return self.Colorize(message, record.levelno) - return message - - def Colorize(self, message, log_level): - try: - return self.color_map[log_level] + message + colorama.Style.RESET_ALL - except KeyError: - return message + formatter = _ColorFormatter(formatter) + super(ColorStreamHandler, self).setFormatter(formatter) @staticmethod def MakeDefault(force_color=False):
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index 0b053e2d..3753483 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -41,6 +41,7 @@ from pylib.results import json_results from pylib.results import report_results from pylib.utils import logdog_helper +from pylib.utils import logging_utils from py_utils import contextlib_ext @@ -187,7 +188,11 @@ def ProcessCommonOptions(args): """Processes and handles all common options.""" - run_tests_helper.SetLogLevel(args.verbose_count) + run_tests_helper.SetLogLevel(args.verbose_count, add_handler=False) + handler = logging_utils.ColorStreamHandler() + handler.setFormatter(run_tests_helper.CustomFormatter()) + logging.getLogger().addHandler(handler) + constants.SetBuildType(args.build_type) if args.output_directory: constants.SetOutputDirectory(args.output_directory)
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps index db43088..63326874 100644 --- a/build/android/test_runner.pydeps +++ b/build/android/test_runner.pydeps
@@ -115,6 +115,12 @@ ../../third_party/catapult/tracing/tracing_build/__init__.py ../../third_party/catapult/tracing/tracing_build/trace2html.py ../../third_party/catapult/tracing/tracing_project.py +../../third_party/colorama/src/colorama/__init__.py +../../third_party/colorama/src/colorama/ansi.py +../../third_party/colorama/src/colorama/ansitowin32.py +../../third_party/colorama/src/colorama/initialise.py +../../third_party/colorama/src/colorama/win32.py +../../third_party/colorama/src/colorama/winterm.py ../../third_party/jinja2/__init__.py ../../third_party/jinja2/_compat.py ../../third_party/jinja2/bccache.py @@ -200,6 +206,7 @@ pylib/utils/dexdump.py pylib/utils/google_storage_helper.py pylib/utils/logdog_helper.py +pylib/utils/logging_utils.py pylib/utils/proguard.py pylib/utils/repo_utils.py pylib/valgrind_tools.py
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index 076206a..f59770a 100644 --- a/build/config/sanitizers/sanitizers.gni +++ b/build/config/sanitizers/sanitizers.gni
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/config/chrome_build.gni") +import("//build/config/chromecast_build.gni") import("//build/toolchain/toolchain.gni") declare_args() { @@ -142,8 +143,9 @@ # buildtools/third_party/libc++abi) instead of stdlibc++ as standard library. # This is intended to be used for instrumented builds. use_custom_libcxx = - (is_asan && is_linux && !is_chromeos) || is_tsan || is_msan || is_ubsan || - is_ubsan_security || (use_libfuzzer && !is_mac) || use_afl + (is_asan && is_linux && !is_chromeos && + (!is_chromecast || is_cast_desktop_build)) || is_tsan || is_msan || + is_ubsan || is_ubsan_security || (use_libfuzzer && !is_mac) || use_afl # Enable -fsanitize-coverage. use_sanitizer_coverage =
diff --git a/chrome/VERSION b/chrome/VERSION index 7eea030..8383d27 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=61 MINOR=0 -BUILD=3130 +BUILD=3131 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 3fc38b8..ae511f7b 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -177,6 +177,7 @@ "//components/crash/android:java", "//components/dom_distiller/content/browser/android:dom_distiller_content_java", "//components/dom_distiller/core/android:dom_distiller_core_java", + "//components/download/public:public_java", "//components/feature_engagement_tracker:feature_engagement_tracker_java", "//components/gcm_driver/android:gcm_driver_java", "//components/gcm_driver/instance_id/android:instance_id_driver_java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java new file mode 100644 index 0000000..6ff490f --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java
@@ -0,0 +1,124 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.download.service; + +import android.content.Context; + +import org.chromium.base.Callback; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.components.background_task_scheduler.TaskParameters; +import org.chromium.components.download.DownloadTaskType; + +import java.util.HashMap; +import java.util.Map; + +/** + * Entry point for the download service to perform desired action when the task is fired by the + * scheduler. The scheduled task is executed for the regular profile and also for incognito profile + * if an incognito profile exists. + */ +@JNINamespace("download::android") +public class DownloadBackgroundTask extends NativeBackgroundTask { + // Helper class to track the number of pending {@link TaskFinishedCallback}s. + private static class PendingTaskCounter { + // Number of tasks in progress. + public int numPendingCallbacks; + + // Whether at least one of the tasks needs reschedule. + public boolean needsReschedule; + } + + // Keeps track of in progress tasks which haven't invoked their {@link TaskFinishedCallback}s. + private Map<Integer, PendingTaskCounter> mPendingTaskCounters = new HashMap<>(); + + @Override + protected int onStartTaskBeforeNativeLoaded( + Context context, TaskParameters taskParameters, TaskFinishedCallback callback) { + return NativeBackgroundTask.LOAD_NATIVE; + } + + @Override + protected void onStartTaskWithNative( + Context context, TaskParameters taskParameters, final TaskFinishedCallback callback) { + // In case of future upgrades, we would need to build an intent for the old version and + // validate that this code still works. This would require decoupling this immediate class + // from native as well. + @DownloadTaskType + final int taskType = + taskParameters.getExtras().getInt(DownloadTaskScheduler.EXTRA_TASK_TYPE); + + Callback<Boolean> wrappedCallback = new Callback<Boolean>() { + @Override + public void onResult(Boolean needsReschedule) { + boolean noPendingCallbacks = + decrementPendingCallbackCount(taskType, needsReschedule); + if (noPendingCallbacks) { + callback.taskFinished(mPendingTaskCounters.get(taskType).needsReschedule); + mPendingTaskCounters.remove(taskType); + } + } + }; + + Profile profile = Profile.getLastUsedProfile().getOriginalProfile(); + incrementPendingCallbackCount(taskType); + nativeStartBackgroundTask(profile, taskType, wrappedCallback); + + if (profile.hasOffTheRecordProfile()) { + incrementPendingCallbackCount(taskType); + nativeStartBackgroundTask(profile.getOffTheRecordProfile(), taskType, wrappedCallback); + } + } + + private void incrementPendingCallbackCount(@DownloadTaskType int taskType) { + PendingTaskCounter taskCounter = mPendingTaskCounters.containsKey(taskType) + ? mPendingTaskCounters.get(taskType) + : new PendingTaskCounter(); + taskCounter.numPendingCallbacks++; + mPendingTaskCounters.put(taskType, taskCounter); + } + + /** @return Whether or not there are no more pending callbacks and we can notify the system. */ + private boolean decrementPendingCallbackCount( + @DownloadTaskType int taskType, boolean needsRescuedule) { + PendingTaskCounter taskCounter = mPendingTaskCounters.get(taskType); + assert taskCounter != null && taskCounter.numPendingCallbacks > 0; + + taskCounter.numPendingCallbacks = Math.max(0, taskCounter.numPendingCallbacks - 1); + taskCounter.needsReschedule |= needsRescuedule; + return taskCounter.numPendingCallbacks == 0; + } + + @Override + protected boolean onStopTaskBeforeNativeLoaded(Context context, TaskParameters taskParameters) { + return true; + } + + @Override + protected boolean onStopTaskWithNative(Context context, TaskParameters taskParameters) { + @DownloadTaskType + int taskType = taskParameters.getExtras().getInt(DownloadTaskScheduler.EXTRA_TASK_TYPE); + mPendingTaskCounters.remove(taskType); + + Profile profile = Profile.getLastUsedProfile().getOriginalProfile(); + boolean needsReschedule = nativeStopBackgroundTask(profile, taskType); + + if (profile.hasOffTheRecordProfile()) { + needsReschedule |= nativeStopBackgroundTask(profile.getOffTheRecordProfile(), taskType); + } + + return needsReschedule; + } + + @Override + public void reschedule(Context context) { + // TODO(shaktisahu): Called when system asks us to schedule the task again. (crbug/730786) + } + + private native void nativeStartBackgroundTask( + Profile profile, int taskType, Callback<Boolean> callback); + private native boolean nativeStopBackgroundTask(Profile profile, int taskType); +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java new file mode 100644 index 0000000..4b5b642 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java
@@ -0,0 +1,74 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.download.service; + +import android.os.Bundle; + +import org.chromium.base.ContextUtils; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler; +import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory; +import org.chromium.components.background_task_scheduler.TaskIds; +import org.chromium.components.background_task_scheduler.TaskInfo; +import org.chromium.components.download.DownloadTaskType; + +import java.util.concurrent.TimeUnit; + +/** + * A background task scheduler that schedules various types of jobs with the system with certain + * conditions as requested by the download service. + */ +@JNINamespace("download::android") +public class DownloadTaskScheduler { + public static final String EXTRA_TASK_TYPE = "extra_task_type"; + + @CalledByNative + private static void scheduleTask(@DownloadTaskType int taskType, boolean requiresCharging, + boolean requiresUnmeteredNetwork, long windowStartTimeSeconds, + long windowEndTimeSeconds) { + Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_TASK_TYPE, taskType); + BackgroundTaskScheduler scheduler = BackgroundTaskSchedulerFactory.getScheduler(); + TaskInfo taskInfo = + TaskInfo.createOneOffTask(getTaskId(taskType), DownloadBackgroundTask.class, + TimeUnit.SECONDS.toMillis(windowStartTimeSeconds), + TimeUnit.SECONDS.toMillis(windowEndTimeSeconds)) + .setRequiredNetworkType( + getRequiredNetworkType(taskType, requiresUnmeteredNetwork)) + .setRequiresCharging(requiresCharging) + .setUpdateCurrent(true) + .setIsPersisted(true) + .setExtras(bundle) + .build(); + scheduler.schedule(ContextUtils.getApplicationContext(), taskInfo); + } + + @CalledByNative + private static void cancelTask(@DownloadTaskType int taskType) { + BackgroundTaskScheduler scheduler = BackgroundTaskSchedulerFactory.getScheduler(); + scheduler.cancel(ContextUtils.getApplicationContext(), getTaskId(taskType)); + } + + private static int getTaskId(@DownloadTaskType int taskType) { + switch (taskType) { + case DownloadTaskType.DOWNLOAD_TASK: + return TaskIds.DOWNLOAD_SERVICE_JOB_ID; + case DownloadTaskType.CLEANUP_TASK: + return TaskIds.DOWNLOAD_CLEANUP_JOB_ID; + default: + assert false; + return -1; + } + } + + private static int getRequiredNetworkType( + @DownloadTaskType int taskType, boolean requiresUnmeteredNetwork) { + if (taskType != DownloadTaskType.DOWNLOAD_TASK) return TaskInfo.NETWORK_TYPE_NONE; + + return requiresUnmeteredNetwork ? TaskInfo.NETWORK_TYPE_UNMETERED + : TaskInfo.NETWORK_TYPE_ANY; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java index bd25589..fd6f120 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
@@ -4,8 +4,13 @@ package org.chromium.chrome.browser.payments; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; + import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.SuppressFBWarnings; +import org.chromium.chrome.browser.ChromeActivity; import org.chromium.content_public.browser.WebContents; import org.chromium.payments.mojom.PaymentDetailsModifier; import org.chromium.payments.mojom.PaymentItem; @@ -62,13 +67,19 @@ @CalledByNative private static void addInstrument(List<PaymentInstrument> instruments, WebContents webContents, - long swRegistrationId, String instrumentId, String label, String[] methodNameArray) { + long swRegistrationId, String instrumentId, String label, String[] methodNameArray, + Bitmap icon) { + Context context = ChromeActivity.fromWebContents(webContents); + if (context == null) return; + Set<String> methodNames = new HashSet<String>(); for (int i = 0; i < methodNameArray.length; i++) { methodNames.add(methodNameArray[i]); } - instruments.add(new ServiceWorkerPaymentInstrument( - webContents, swRegistrationId, instrumentId, label, methodNames)); + + instruments.add( + new ServiceWorkerPaymentInstrument(webContents, swRegistrationId, instrumentId, + label, methodNames, new BitmapDrawable(context.getResources(), icon))); } @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentInstrument.java index c3d56c05..4579a9c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentInstrument.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentInstrument.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.payments; +import android.graphics.drawable.Drawable; + import org.chromium.content_public.browser.WebContents; import org.chromium.payments.mojom.PaymentDetailsModifier; import org.chromium.payments.mojom.PaymentItem; @@ -39,11 +41,12 @@ * @param instrumentId The unique id of the payment instrument. * @param label The label of the payment instrument. * @param methodNames A set of payment method names supported by the payment instrument. + * @param icon The drawable icon of the payment instrument. */ public ServiceWorkerPaymentInstrument(WebContents webContents, long swRegistrationId, - String instrumentId, String label, Set<String> methodNames) { + String instrumentId, String label, Set<String> methodNames, Drawable icon) { super(Long.toString(swRegistrationId) + "#" + instrumentId, label, null /* sublabel */, - null /* icon */); + icon); mWebContents = webContents; mSWRegistrationId = swRegistrationId; mInstrumentId = instrumentId;
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 074ad45..66e2a78c 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -345,6 +345,8 @@ "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java", "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java", "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiFactory.java", + "java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java", + "java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java", "java/src/org/chromium/chrome/browser/download/ui/BackendItems.java", "java/src/org/chromium/chrome/browser/download/ui/BackendProvider.java", "java/src/org/chromium/chrome/browser/download/ui/DeletedFileTracker.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java index dbba560a..458c1d6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
@@ -65,16 +65,18 @@ instruments.add(new ServiceWorkerPaymentInstrument(webContents, 0 /* swRegistrationId */, "new" /* instrumentId */, "Create BobPay account" /* label */, - new HashSet<String>(Arrays.asList("https://bobpay.com", - "basic-card")) /* methodNames */)); + new HashSet<String>(Arrays.asList( + "https://bobpay.com", "basic-card")) /* methodNames */, + null /* icon*/)); } if (instrumentPresence == TWO_OPTIONS) { instruments.add(new ServiceWorkerPaymentInstrument(webContents, 0 /* swRegistrationId */, "existing" /* instrumentId */, "Existing BobPay account" /* label */, - new HashSet<String>(Arrays.asList("https://bobpay.com", - "basic-card")) /* methodNames */)); + new HashSet<String>(Arrays.asList( + "https://bobpay.com", "basic-card")) /* methodNames */, + null /* icon */)); } callback.onPaymentAppCreated(
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 6fefe12a..7023bef 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -379,6 +379,8 @@ "download/download_target_determiner_delegate.h", "download/download_target_info.cc", "download/download_target_info.h", + "download/download_task_scheduler_impl.cc", + "download/download_task_scheduler_impl.h", "download/download_ui_controller.cc", "download/download_ui_controller.h", "download/drag_download_item.h", @@ -2925,6 +2927,10 @@ "android/download/intercept_download_resource_throttle.h", "android/download/items/offline_content_aggregator_factory_android.cc", "android/download/items/offline_content_aggregator_factory_android.h", + "android/download/service/download_background_task.cc", + "android/download/service/download_background_task.h", + "android/download/service/download_task_scheduler.cc", + "android/download/service/download_task_scheduler.h", "android/download/ui/thumbnail_provider.cc", "android/download/ui/thumbnail_provider.h", "android/favicon_helper.cc", @@ -4211,6 +4217,8 @@ "../android/java/src/org/chromium/chrome/browser/download/DownloadItem.java", "../android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java", "../android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java", + "../android/java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java", + "../android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java", "../android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProviderImpl.java", "../android/java/src/org/chromium/chrome/browser/engagement/SiteEngagementService.java", "../android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java",
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index 8b2178a..ceb6e72 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -48,6 +48,7 @@ #include "chrome/browser/android/download/download_controller.h" #include "chrome/browser/android/download/download_manager_service.h" #include "chrome/browser/android/download/items/offline_content_aggregator_factory_android.h" +#include "chrome/browser/android/download/service/download_background_task.h" #include "chrome/browser/android/download/ui/thumbnail_provider.h" #include "chrome/browser/android/favicon_helper.h" #include "chrome/browser/android/feature_engagement_tracker/feature_engagement_tracker_factory_android.h" @@ -308,6 +309,8 @@ {"DomDistillerServiceFactory", dom_distiller::android::DomDistillerServiceFactoryAndroid::Register}, {"DomDistillerTabUtils", RegisterDomDistillerTabUtils}, + {"DownloadBackgroundTask", + download::android::RegisterDownloadBackgroundTask}, {"DownloadController", DownloadController::RegisterDownloadController}, {"DownloadManagerService", DownloadManagerService::RegisterDownloadManagerService},
diff --git a/chrome/browser/android/download/service/download_background_task.cc b/chrome/browser/android/download/service/download_background_task.cc new file mode 100644 index 0000000..9ad0bccf --- /dev/null +++ b/chrome/browser/android/download/service/download_background_task.cc
@@ -0,0 +1,67 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/download/service/download_background_task.h" + +#include "base/android/callback_android.h" +#include "base/callback_forward.h" +#include "chrome/browser/download/download_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_android.h" +#include "components/download/public/download_service.h" +#include "content/public/browser/browser_context.h" +#include "jni/DownloadBackgroundTask_jni.h" + +using base::android::JavaParamRef; + +namespace download { +namespace android { + +// static +bool RegisterDownloadBackgroundTask(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +void CallTaskFinishedCallback(const base::android::JavaRef<jobject>& j_callback, + bool needs_reschedule) { + RunCallbackAndroid(j_callback, needs_reschedule); +} + +// static +void StartBackgroundTask( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + const base::android::JavaParamRef<jobject>& jprofile, + jint task_type, + const base::android::JavaParamRef<jobject>& jcallback) { + Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); + DCHECK(profile); + + TaskFinishedCallback finish_callback = + base::Bind(&CallTaskFinishedCallback, + base::android::ScopedJavaGlobalRef<jobject>(jcallback)); + + DownloadService* download_service = + DownloadServiceFactory::GetForBrowserContext(profile); + download_service->OnStartScheduledTask( + static_cast<DownloadTaskType>(task_type), finish_callback); +} + +// static +jboolean StopBackgroundTask( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + const base::android::JavaParamRef<jobject>& jprofile, + jint task_type) { + Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); + DCHECK(profile); + + DownloadService* download_service = + DownloadServiceFactory::GetForBrowserContext(profile); + return download_service->OnStopScheduledTask( + static_cast<DownloadTaskType>(task_type)); +} + +} // namespace android +} // namespace download
diff --git a/chrome/browser/android/download/service/download_background_task.h b/chrome/browser/android/download/service/download_background_task.h new file mode 100644 index 0000000..730abf5 --- /dev/null +++ b/chrome/browser/android/download/service/download_background_task.h
@@ -0,0 +1,22 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_SERVICE_DOWNLOAD_BACKGROUND_TASK_H_ +#define CHROME_BROWSER_ANDROID_DOWNLOAD_SERVICE_DOWNLOAD_BACKGROUND_TASK_H_ + +#include <jni.h> +#include <memory> + +#include "base/android/jni_android.h" +#include "base/macros.h" + +namespace download { +namespace android { + +bool RegisterDownloadBackgroundTask(JNIEnv* env); + +} // namespace android +} // namespace download + +#endif // CHROME_BROWSER_ANDROID_DOWNLOAD_SERVICE_DOWNLOAD_BACKGROUND_TASK_H_
diff --git a/chrome/browser/android/download/service/download_task_scheduler.cc b/chrome/browser/android/download/service/download_task_scheduler.cc new file mode 100644 index 0000000..6a5a078 --- /dev/null +++ b/chrome/browser/android/download/service/download_task_scheduler.cc
@@ -0,0 +1,34 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/download/service/download_task_scheduler.h" + +#include "base/android/jni_android.h" +#include "jni/DownloadTaskScheduler_jni.h" + +namespace download { +namespace android { + +DownloadTaskScheduler::DownloadTaskScheduler() = default; + +DownloadTaskScheduler::~DownloadTaskScheduler() = default; + +void DownloadTaskScheduler::ScheduleTask(DownloadTaskType task_type, + bool require_unmetered_network, + bool require_charging, + long window_start_time_seconds, + long window_end_time_seconds) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_DownloadTaskScheduler_scheduleTask( + env, static_cast<jint>(task_type), require_unmetered_network, + require_charging, window_start_time_seconds, window_end_time_seconds); +} + +void DownloadTaskScheduler::CancelTask(DownloadTaskType task_type) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_DownloadTaskScheduler_cancelTask(env, static_cast<jint>(task_type)); +} + +} // namespace android +} // namespace download
diff --git a/chrome/browser/android/download/service/download_task_scheduler.h b/chrome/browser/android/download/service/download_task_scheduler.h new file mode 100644 index 0000000..7e0e73b --- /dev/null +++ b/chrome/browser/android/download/service/download_task_scheduler.h
@@ -0,0 +1,40 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_SERVICE_DOWNLOAD_TASK_SCHEDULER_H_ +#define CHROME_BROWSER_ANDROID_DOWNLOAD_SERVICE_DOWNLOAD_TASK_SCHEDULER_H_ + +#include <jni.h> +#include <memory> + +#include "base/macros.h" +#include "components/download/public/download_task_types.h" +#include "components/download/public/task_scheduler.h" + +namespace download { +namespace android { + +// DownloadTaskScheduler is the utility class to schedule various types of +// background tasks with the OS as of when required by the download service. +class DownloadTaskScheduler : public TaskScheduler { + public: + DownloadTaskScheduler(); + ~DownloadTaskScheduler(); + + // TaskScheduler implementation. + void ScheduleTask(DownloadTaskType task_type, + bool require_unmetered_network, + bool require_charging, + long window_start_time_seconds, + long window_end_time_seconds) override; + void CancelTask(DownloadTaskType task_type) override; + + private: + DISALLOW_COPY_AND_ASSIGN(DownloadTaskScheduler); +}; + +} // namespace android +} // namespace download + +#endif // CHROME_BROWSER_ANDROID_DOWNLOAD_SERVICE_DOWNLOAD_TASK_SCHEDULER_H_
diff --git a/chrome/browser/android/payments/service_worker_payment_app_bridge.cc b/chrome/browser/android/payments/service_worker_payment_app_bridge.cc index 6fd1d02f..98a4f22 100644 --- a/chrome/browser/android/payments/service_worker_payment_app_bridge.cc +++ b/chrome/browser/android/payments/service_worker_payment_app_bridge.cc
@@ -16,6 +16,7 @@ #include "content/public/browser/stored_payment_instrument.h" #include "content/public/browser/web_contents.h" #include "jni/ServiceWorkerPaymentAppBridge_jni.h" +#include "ui/gfx/android/java_bitmap.h" namespace { @@ -49,7 +50,8 @@ env, java_instruments, jweb_contents, instrument->registration_id, ConvertUTF8ToJavaString(env, instrument->instrument_key), ConvertUTF8ToJavaString(env, instrument->name), - ToJavaArrayOfStrings(env, instrument->enabled_methods)); + ToJavaArrayOfStrings(env, instrument->enabled_methods), + gfx::ConvertToJavaBitmap(instrument->icon.get())); } Java_ServiceWorkerPaymentAppBridge_onPaymentAppCreated( env, java_instruments, jweb_contents, jcallback);
diff --git a/chrome/browser/chromeos/printing/specifics_translation_unittest.cc b/chrome/browser/chromeos/printing/specifics_translation_unittest.cc index 36765a1..5c6fb48 100644 --- a/chrome/browser/chromeos/printing/specifics_translation_unittest.cc +++ b/chrome/browser/chromeos/printing/specifics_translation_unittest.cc
@@ -13,17 +13,17 @@ namespace { -const char id[] = "UNIQUE_ID"; -const char display_name[] = "Best Printer Ever"; -const char description[] = "The green one"; -const char manufacturer[] = "Manufacturer"; -const char model[] = "MODEL"; -const char uri[] = "ipps://notaprinter.chromium.org/ipp/print"; -const char uuid[] = "UUIDUUIDUUID"; +constexpr char kId[] = "UNIQUE_ID"; +constexpr char kDisplayName[] = "Best Printer Ever"; +constexpr char kDescription[] = "The green one"; +constexpr char kManufacturer[] = "Manufacturer"; +constexpr char kModel[] = "MODEL"; +constexpr char kUri[] = "ipps://notaprinter.chromium.org/ipp/print"; +constexpr char kUuid[] = "UUIDUUIDUUID"; const base::Time kUpdateTime = base::Time::FromInternalValue(22114455660000); -const char kUserSuppliedPPD[] = "file://foo/bar/baz/eeaaaffccdd00"; -const char effective_make_and_model[] = "Manufacturer Model T1000"; +constexpr char kUserSuppliedPPD[] = "file://foo/bar/baz/eeaaaffccdd00"; +constexpr char kEffectiveMakeAndModel[] = "Manufacturer Model T1000"; } // namespace @@ -32,71 +32,71 @@ TEST(SpecificsTranslationTest, SpecificsToPrinter) { sync_pb::PrinterSpecifics specifics; - specifics.set_id(id); - specifics.set_display_name(display_name); - specifics.set_description(description); - specifics.set_manufacturer(manufacturer); - specifics.set_model(model); - specifics.set_uri(uri); - specifics.set_uuid(uuid); + specifics.set_id(kId); + specifics.set_display_name(kDisplayName); + specifics.set_description(kDescription); + specifics.set_manufacturer(kManufacturer); + specifics.set_model(kModel); + specifics.set_uri(kUri); + specifics.set_uuid(kUuid); specifics.set_updated_timestamp(kUpdateTime.ToJavaTime()); sync_pb::PrinterPPDReference ppd; - ppd.set_effective_make_and_model(effective_make_and_model); + ppd.set_effective_make_and_model(kEffectiveMakeAndModel); *specifics.mutable_ppd_reference() = ppd; std::unique_ptr<Printer> result = SpecificsToPrinter(specifics); - EXPECT_EQ(id, result->id()); - EXPECT_EQ(display_name, result->display_name()); - EXPECT_EQ(description, result->description()); - EXPECT_EQ(manufacturer, result->manufacturer()); - EXPECT_EQ(model, result->model()); - EXPECT_EQ(uri, result->uri()); - EXPECT_EQ(uuid, result->uuid()); + EXPECT_EQ(kId, result->id()); + EXPECT_EQ(kDisplayName, result->display_name()); + EXPECT_EQ(kDescription, result->description()); + EXPECT_EQ(kManufacturer, result->manufacturer()); + EXPECT_EQ(kModel, result->model()); + EXPECT_EQ(kUri, result->uri()); + EXPECT_EQ(kUuid, result->uuid()); EXPECT_EQ(kUpdateTime, result->last_updated()); - EXPECT_EQ(effective_make_and_model, + EXPECT_EQ(kEffectiveMakeAndModel, result->ppd_reference().effective_make_and_model); EXPECT_FALSE(result->IsIppEverywhere()); } TEST(SpecificsTranslationTest, PrinterToSpecifics) { Printer printer; - printer.set_id(id); - printer.set_display_name(display_name); - printer.set_description(description); - printer.set_manufacturer(manufacturer); - printer.set_model(model); - printer.set_uri(uri); - printer.set_uuid(uuid); + printer.set_id(kId); + printer.set_display_name(kDisplayName); + printer.set_description(kDescription); + printer.set_manufacturer(kManufacturer); + printer.set_model(kModel); + printer.set_uri(kUri); + printer.set_uuid(kUuid); Printer::PpdReference ppd; - ppd.effective_make_and_model = effective_make_and_model; + ppd.effective_make_and_model = kEffectiveMakeAndModel; *printer.mutable_ppd_reference() = ppd; std::unique_ptr<sync_pb::PrinterSpecifics> result = PrinterToSpecifics(printer); - EXPECT_EQ(id, result->id()); - EXPECT_EQ(display_name, result->display_name()); - EXPECT_EQ(description, result->description()); - EXPECT_EQ(manufacturer, result->manufacturer()); - EXPECT_EQ(model, result->model()); - EXPECT_EQ(uri, result->uri()); - EXPECT_EQ(uuid, result->uuid()); + EXPECT_EQ(kId, result->id()); + EXPECT_EQ(kDisplayName, result->display_name()); + EXPECT_EQ(kDescription, result->description()); + EXPECT_EQ(kManufacturer, result->manufacturer()); + EXPECT_EQ(kModel, result->model()); + EXPECT_EQ(kUri, result->uri()); + EXPECT_EQ(kUuid, result->uuid()); - EXPECT_EQ(effective_make_and_model, + EXPECT_EQ(kEffectiveMakeAndModel, result->ppd_reference().effective_make_and_model()); } TEST(SpecificsTranslationTest, SpecificsToPrinterRoundTrip) { Printer printer; - printer.set_id(id); - printer.set_display_name(display_name); - printer.set_description(description); - printer.set_manufacturer(manufacturer); - printer.set_model(model); - printer.set_uri(uri); - printer.set_uuid(uuid); + printer.set_id(kId); + printer.set_display_name(kDisplayName); + printer.set_description(kDescription); + printer.set_manufacturer(kManufacturer); + printer.set_model(kModel); + printer.set_uri(kUri); + printer.set_uuid(kUuid); Printer::PpdReference ppd; ppd.autoconf = true; @@ -105,13 +105,13 @@ std::unique_ptr<sync_pb::PrinterSpecifics> temp = PrinterToSpecifics(printer); std::unique_ptr<Printer> result = SpecificsToPrinter(*temp); - EXPECT_EQ(id, result->id()); - EXPECT_EQ(display_name, result->display_name()); - EXPECT_EQ(description, result->description()); - EXPECT_EQ(manufacturer, result->manufacturer()); - EXPECT_EQ(model, result->model()); - EXPECT_EQ(uri, result->uri()); - EXPECT_EQ(uuid, result->uuid()); + EXPECT_EQ(kId, result->id()); + EXPECT_EQ(kDisplayName, result->display_name()); + EXPECT_EQ(kDescription, result->description()); + EXPECT_EQ(kManufacturer, result->manufacturer()); + EXPECT_EQ(kModel, result->model()); + EXPECT_EQ(kUri, result->uri()); + EXPECT_EQ(kUuid, result->uuid()); EXPECT_TRUE(result->ppd_reference().effective_make_and_model.empty()); EXPECT_TRUE(result->ppd_reference().autoconf); @@ -119,17 +119,17 @@ TEST(SpecificsTranslationTest, MergePrinterToSpecifics) { sync_pb::PrinterSpecifics original; - original.set_id(id); + original.set_id(kId); original.mutable_ppd_reference()->set_autoconf(true); - Printer printer(id); + Printer printer(kId); printer.mutable_ppd_reference()->effective_make_and_model = - effective_make_and_model; + kEffectiveMakeAndModel; MergePrinterToSpecifics(printer, &original); - EXPECT_EQ(id, original.id()); - EXPECT_EQ(effective_make_and_model, + EXPECT_EQ(kId, original.id()); + EXPECT_EQ(kEffectiveMakeAndModel, original.ppd_reference().effective_make_and_model()); // Verify that autoconf is cleared. @@ -139,7 +139,7 @@ // Tests that the autoconf value overrides other PpdReference fields. TEST(SpecificsTranslationTest, AutoconfOverrides) { sync_pb::PrinterSpecifics original; - original.set_id(id); + original.set_id(kId); auto* ppd_reference = original.mutable_ppd_reference(); ppd_reference->set_autoconf(true); ppd_reference->set_user_supplied_ppd_url(kUserSuppliedPPD); @@ -155,10 +155,10 @@ // autoconf is false. TEST(SpecificsTranslationTest, UserSuppliedOverrides) { sync_pb::PrinterSpecifics original; - original.set_id(id); + original.set_id(kId); auto* ppd_reference = original.mutable_ppd_reference(); ppd_reference->set_user_supplied_ppd_url(kUserSuppliedPPD); - ppd_reference->set_effective_make_and_model(effective_make_and_model); + ppd_reference->set_effective_make_and_model(kEffectiveMakeAndModel); auto printer = SpecificsToPrinter(original);
diff --git a/chrome/browser/download/download_service_factory.cc b/chrome/browser/download/download_service_factory.cc index 41a2f7a..05a415bc 100644 --- a/chrome/browser/download/download_service_factory.cc +++ b/chrome/browser/download/download_service_factory.cc
@@ -10,15 +10,21 @@ #include "base/sequenced_task_runner.h" #include "base/task_scheduler/post_task.h" #include "base/task_scheduler/task_traits.h" +#include "chrome/browser/download/download_task_scheduler_impl.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_constants.h" #include "components/download/content/factory/download_service_factory.h" #include "components/download/public/clients.h" #include "components/download/public/download_service.h" +#include "components/download/public/task_scheduler.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "content/public/browser/browser_context.h" +#if defined(OS_ANDROID) +#include "chrome/browser/android/download/service/download_task_scheduler.h" +#endif + // static DownloadServiceFactory* DownloadServiceFactory::GetInstance() { return base::Singleton<DownloadServiceFactory>::get(); @@ -56,8 +62,17 @@ base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), base::TaskPriority::BACKGROUND}); + std::unique_ptr<download::TaskScheduler> task_scheduler; + +#if defined(OS_ANDROID) + task_scheduler = base::MakeUnique<download::android::DownloadTaskScheduler>(); +#else + task_scheduler = base::MakeUnique<DownloadTaskSchedulerImpl>(context); +#endif + return download::CreateDownloadService(std::move(clients), download_manager, - storage_dir, background_task_runner); + storage_dir, background_task_runner, + std::move(task_scheduler)); } content::BrowserContext* DownloadServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/download/download_task_scheduler_impl.cc b/chrome/browser/download/download_task_scheduler_impl.cc new file mode 100644 index 0000000..32a9386 --- /dev/null +++ b/chrome/browser/download/download_task_scheduler_impl.cc
@@ -0,0 +1,61 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/download/download_task_scheduler_impl.h" + +#include "base/bind.h" +#include "base/cancelable_callback.h" +#include "base/sequenced_task_runner.h" +#include "base/task_scheduler/post_task.h" +#include "base/task_scheduler/task_traits.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" +#include "chrome/browser/download/download_service_factory.h" +#include "components/download/public/download_service.h" +#include "content/public/browser/browser_context.h" + +DownloadTaskSchedulerImpl::DownloadTaskSchedulerImpl( + content::BrowserContext* context) + : context_(context), weak_factory_(this) {} + +DownloadTaskSchedulerImpl::~DownloadTaskSchedulerImpl() = default; + +void DownloadTaskSchedulerImpl::ScheduleTask( + download::DownloadTaskType task_type, + bool require_unmetered_network, + bool require_charging, + long window_start_time_seconds, + long window_end_time_seconds) { + // We only rely on this for cleanup tasks. Since this doesn't restart Chrome, + // for download tasks it doesn't do much and we handle them outside of task + // scheduler. + if (task_type != download::DownloadTaskType::CLEANUP_TASK) + return; + + scheduled_tasks_[task_type].Reset( + base::Bind(&DownloadTaskSchedulerImpl::RunScheduledTask, + weak_factory_.GetWeakPtr(), task_type)); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, scheduled_tasks_[task_type].callback(), + base::TimeDelta::FromSeconds(window_start_time_seconds)); +} + +void DownloadTaskSchedulerImpl::CancelTask( + download::DownloadTaskType task_type) { + scheduled_tasks_[task_type].Cancel(); +} + +void DownloadTaskSchedulerImpl::RunScheduledTask( + download::DownloadTaskType task_type) { + download::DownloadService* download_service = + DownloadServiceFactory::GetForBrowserContext(context_); + download_service->OnStartScheduledTask( + task_type, base::Bind(&DownloadTaskSchedulerImpl::OnTaskFinished, + weak_factory_.GetWeakPtr())); +} + +void DownloadTaskSchedulerImpl::OnTaskFinished(bool reschedule) { + // TODO(shaktisahu): Cache the original scheduling params and re-post task in + // case it needs reschedule. +}
diff --git a/chrome/browser/download/download_task_scheduler_impl.h b/chrome/browser/download/download_task_scheduler_impl.h new file mode 100644 index 0000000..6fa5d969 --- /dev/null +++ b/chrome/browser/download/download_task_scheduler_impl.h
@@ -0,0 +1,50 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TASK_SCHEDULER_IMPL_H_ +#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TASK_SCHEDULER_IMPL_H_ + +#include <map> + +#include "base/cancelable_callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/download/public/task_scheduler.h" + +namespace content { +class BrowserContext; +} // namespace content + +// A TaskScheduler implementation that doesn't do anything but posts the task +// after the specified delay. +// If Chrome is shut down, the implementation will not automatically restart it. +class DownloadTaskSchedulerImpl : public download::TaskScheduler { + public: + explicit DownloadTaskSchedulerImpl(content::BrowserContext* context); + ~DownloadTaskSchedulerImpl(); + + // TaskScheduler implementation. + void ScheduleTask(download::DownloadTaskType task_type, + bool require_unmetered_network, + bool require_charging, + long window_start_time_seconds, + long window_end_time_seconds) override; + void CancelTask(download::DownloadTaskType task_type) override; + + private: + void RunScheduledTask(download::DownloadTaskType task_type); + void OnTaskFinished(bool reschedule); + + content::BrowserContext* context_; + + // Keeps track of scheduled tasks so that they can be cancelled. + std::map<download::DownloadTaskType, base::CancelableClosure> + scheduled_tasks_; + + base::WeakPtrFactory<DownloadTaskSchedulerImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(DownloadTaskSchedulerImpl); +}; + +#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TASK_SCHEDULER_IMPL_H_
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html index 968ca1b7..9fd16e3 100644 --- a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html +++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
@@ -205,7 +205,7 @@ <div class="start"> <div class="label">$i18n{printerQueue}</div> <div class="secondary"> - <paper-input no-label-float label="ipp/print" + <paper-input no-label-float label="ipp/print" value="{{newPrinter.printerQueue}}"> </paper-input> </div> @@ -228,7 +228,7 @@ <paper-button class="secondary-button" on-tap="switchToDiscoveryDialog_"> $i18n{discoverPrintersButtonText} - </paper-button> + </paper-button> </div> <div> <!-- Right group --> <paper-button class="cancel-button secondary-button" @@ -236,7 +236,7 @@ $i18n{cancelButtonText} </paper-button> <paper-button class="action-button" - on-tap="switchToManufacturerDialog_" + on-tap="addPressed_" disabled="[[!newPrinter.printerName]]"> $i18n{addPrinterButtonText} </paper-button>
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js index 8e1d7de44..52099fa 100644 --- a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js +++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js
@@ -40,6 +40,7 @@ function getEmptyPrinter_() { return { printerAddress: '', + printerAutoconf: false, printerDescription: '', printerId: '', printerManufacturer: '', @@ -169,13 +170,13 @@ }, /** @private */ - switchToManufacturerDialog_: function() { + addPressed_: function() { // Set the default printer queue to be "ipp/print". - if (!this.newPrinter.printerQueue) + if (!this.newPrinter.printerQueue) { this.set('newPrinter.printerQueue', 'ipp/print'); - + } this.$$('add-printer-dialog').close(); - this.fire('open-manufacturer-model-dialog'); + this.fire('open-configuring-printer-dialog'); }, /** @private */ @@ -416,6 +417,46 @@ }, /** @private */ + addPrinter_: function() { + settings.CupsPrintersBrowserProxyImpl.getInstance(). + addCupsPrinter(this.newPrinter); + }, + + /** @private */ + switchToManufacturerDialog_: function() { + this.$$('add-printer-configuring-dialog').close(); + this.fire('open-manufacturer-model-dialog'); + }, + + /** + * Handler for getPrinterInfo success. + * @param {!PrinterMakeModel} info + * @private + * */ + onPrinterFound_: function(info) { + this.newPrinter.printerAutoconf = info.autoconf; + this.newPrinter.printerManufacturer = info.manufacturer; + this.newPrinter.printerModel = info.model; + + // Add the printer if it's configurable. Otherwise, forward to the + // manufacturer dialog. + if (this.newPrinter.printerAutoconf) { + this.addPrinter_(); + } else { + this.switchToManufacturerDialog_(); + } + }, + + /** + * Handler for getPrinterInfo failure. + * @param {*} rejected + * @private + */ + infoFailed_: function(rejected) { + this.switchToManufacturerDialog_(); + }, + + /** @private */ openConfiguringPrinterDialog_: function() { this.switchDialog_( this.currentDialog_, AddPrinterDialogs.CONFIGURING, @@ -423,13 +464,25 @@ if (this.previousDialog_ == AddPrinterDialogs.DISCOVERY) { this.configuringDialogTitle = loadTimeData.getString('addPrintersNearbyTitle'); - settings.CupsPrintersBrowserProxyImpl.getInstance().addCupsPrinter( - this.newPrinter); - } else if (this.previousDialog_ == AddPrinterDialogs.MANUFACTURER) { + this.addPrinter_(); + } else if ( + this.previousDialog_ == AddPrinterDialogs.MANUFACTURER) { this.configuringDialogTitle = loadTimeData.getString('addPrintersManuallyTitle'); - settings.CupsPrintersBrowserProxyImpl.getInstance().addCupsPrinter( - this.newPrinter); + this.addPrinter_(); + } else if (this.previousDialog_ == AddPrinterDialogs.MANUALLY) { + this.configuringDialogTitle = + loadTimeData.getString('addPrintersManuallyTitle'); + if (this.newPrinter.printerProtocol == 'ipp' || + this.newPrinter.printerProtocol == 'ipps') { + settings.CupsPrintersBrowserProxyImpl.getInstance(). + getPrinterInfo(this.newPrinter). + then( + this.onPrinterFound_.bind(this), this.infoFailed_.bind(this)); + } else { + // Defer the switch until all the elements are drawn. + this.async(this.switchToManufacturerDialog_.bind(this)); + } } },
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js b/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js index c02a562..3af40d9 100644 --- a/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js +++ b/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js
@@ -10,6 +10,7 @@ /** * @typedef {{ * printerAddress: string, + * printerAutoconf: boolean, * printerDescription: string, * printerId: string, * printerManufacturer: string, @@ -46,6 +47,22 @@ */ var ModelsInfo; +/** + * @typedef {{ + * manufacturer: string, + * model: string, + * autoconf: boolean + * }} + */ +var PrinterMakeModel; + +/** + * @typedef {{ + * message: string + * }} + */ +var QueryFailure; + cr.define('settings', function() { /** @interface */ function CupsPrintersBrowserProxy() {} @@ -93,6 +110,12 @@ * @return {!Promise<!ModelsInfo>} */ getCupsPrinterModelsList: function(manufacturer) {}, + + /** + * @param {!CupsPrinterInfo} newPrinter + * @return {!Promise<!PrinterMakeModel>} + */ + getPrinterInfo: function(newPrinter) {}, }; /** @@ -147,6 +170,11 @@ getCupsPrinterModelsList: function(manufacturer) { return cr.sendWithPromise('getCupsPrinterModelsList', manufacturer); }, + + /** @override */ + getPrinterInfo: function(newPrinter) { + return cr.sendWithPromise('getPrinterInfo', newPrinter); + }, }; return {
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc index 866d8fd..fdb621c 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -55,15 +55,8 @@ if (content_settings()) { CleanUpExpiredVerdicts(); UMA_HISTOGRAM_COUNTS_1000( - "PasswordProtection.NumberOfCachedVerdictBeforeShutdown." - "PasswordOnFocus", - GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); - UMA_HISTOGRAM_COUNTS_1000( - "PasswordProtection.NumberOfCachedVerdictBeforeShutdown." - "ProtectedPasswordEntry", - GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); + "PasswordProtection.NumberOfCachedVerdictBeforeShutdown", + GetStoredVerdictCount()); } }
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc index f496f390..a30d126 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -75,7 +75,6 @@ } void CacheVerdict(const GURL& url, - LoginReputationClientRequest::TriggerType trigger_type, LoginReputationClientResponse* verdict, const base::Time& receive_time) override {}
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc index 7aadf49d..ad257ad 100644 --- a/chrome/browser/translate/chrome_translate_client.cc +++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -90,9 +90,12 @@ // If entry is null, we don't record the page. // The navigation entry can be null in situations like download or initial // blank page. - if (entry != nullptr) { + DCHECK(web_contents); + if (entry != nullptr && + TranslateService::IsTranslatableURL(entry->GetVirtualURL())) { user_event_service->RecordUserEvent( - translate::ConstructLanguageDetectionEvent(details)); + translate::ConstructLanguageDetectionEvent( + entry->GetTimestamp().ToInternalValue(), details)); } }
diff --git a/chrome/browser/translate/chrome_translate_client.h b/chrome/browser/translate/chrome_translate_client.h index da171a3..141350f 100644 --- a/chrome/browser/translate/chrome_translate_client.h +++ b/chrome/browser/translate/chrome_translate_client.h
@@ -113,6 +113,10 @@ private: explicit ChromeTranslateClient(content::WebContents* web_contents); friend class content::WebContentsUserData<ChromeTranslateClient>; + FRIEND_TEST_ALL_PREFIXES(ChromeTranslateClientTest, + LanguageEventShouldRecord); + FRIEND_TEST_ALL_PREFIXES(ChromeTranslateClientTest, + LanguageEventShouldNotRecord); // content::WebContentsObserver implementation. void WebContentsDestroyed() override;
diff --git a/chrome/browser/translate/chrome_translate_client_unittest.cc b/chrome/browser/translate/chrome_translate_client_unittest.cc new file mode 100644 index 0000000..1793d84 --- /dev/null +++ b/chrome/browser/translate/chrome_translate_client_unittest.cc
@@ -0,0 +1,69 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/translate/chrome_translate_client.h" + +#include <memory> + +#include "base/command_line.h" +#include "base/memory/ref_counted.h" +#include "base/run_loop.h" +#include "chrome/browser/sync/profile_sync_service_factory.h" +#include "chrome/browser/sync/user_event_service_factory.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "components/sync/user_events/fake_user_event_service.h" +#include "components/translate/core/common/language_detection_details.h" +#include "content/public/browser/web_contents.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +std::unique_ptr<KeyedService> BuildFakeUserEventService( + content::BrowserContext* context) { + return base::MakeUnique<syncer::FakeUserEventService>(); +} + +class ChromeTranslateClientTest : public ChromeRenderViewHostTestHarness { + public: + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + fake_user_event_service_ = static_cast<syncer::FakeUserEventService*>( + browser_sync::UserEventServiceFactory::GetInstance() + ->SetTestingFactoryAndUse(browser_context(), + &BuildFakeUserEventService)); + } + + void TearDown() override { ChromeRenderViewHostTestHarness::TearDown(); } + + protected: + syncer::FakeUserEventService* GetUserEventService() { + return fake_user_event_service_; + } + + private: + syncer::FakeUserEventService* fake_user_event_service_; +}; + +TEST_F(ChromeTranslateClientTest, LanguageEventShouldRecord) { + GURL url("http://yahoo.com"); + NavigateAndCommit(url); + ChromeTranslateClient client(web_contents()); + translate::LanguageDetectionDetails details; + details.cld_language = "en"; + details.is_cld_reliable = true; + details.adopted_language = "en"; + client.OnLanguageDetermined(details); + EXPECT_EQ(1ul, GetUserEventService()->GetRecordedUserEvents().size()); +} + +TEST_F(ChromeTranslateClientTest, LanguageEventShouldNotRecord) { + GURL url("about://blank"); + NavigateAndCommit(url); + ChromeTranslateClient client(web_contents()); + translate::LanguageDetectionDetails details; + details.cld_language = "en"; + details.is_cld_reliable = true; + details.adopted_language = "en"; + client.OnLanguageDetermined(details); + EXPECT_EQ(0u, GetUserEventService()->GetRecordedUserEvents().size()); +}
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc index 6c0ece3..ed2397d 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
@@ -337,9 +337,11 @@ l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_BUBBLE_FOLDER_LABEL)); layout->AddView(parent_combobox_); - layout->AddPaddingRow( - kFixed, - provider->GetInsetsMetric(views::INSETS_DIALOG_CONTENTS).bottom()); + if (provider->UseExtraDialogPadding()) { + layout->AddPaddingRow( + kFixed, + provider->GetInsetsMetric(views::INSETS_DIALOG_CONTENTS).bottom()); + } AddChildView(bookmark_contents_view_); }
diff --git a/chrome/browser/ui/views/harmony/chrome_layout_provider.cc b/chrome/browser/ui/views/harmony/chrome_layout_provider.cc index a66a6b4aa..1fd3548a 100644 --- a/chrome/browser/ui/views/harmony/chrome_layout_provider.cc +++ b/chrome/browser/ui/views/harmony/chrome_layout_provider.cc
@@ -30,8 +30,6 @@ return views::kMinimumButtonWidth; case DISTANCE_CONTROL_LIST_VERTICAL: return GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL); - case DISTANCE_DIALOG_BUTTON_TOP: - return 0; case DISTANCE_RELATED_CONTROL_HORIZONTAL_SMALL: return views::kRelatedControlSmallHorizontalSpacing; case DISTANCE_RELATED_CONTROL_VERTICAL_SMALL:
diff --git a/chrome/browser/ui/views/harmony/chrome_layout_provider.h b/chrome/browser/ui/views/harmony/chrome_layout_provider.h index 318cab5..5541639 100644 --- a/chrome/browser/ui/views/harmony/chrome_layout_provider.h +++ b/chrome/browser/ui/views/harmony/chrome_layout_provider.h
@@ -17,8 +17,6 @@ DISTANCE_BUTTON_MINIMUM_WIDTH = views::VIEWS_DISTANCE_END, // Vertical spacing between a list of multiple controls in one column. DISTANCE_CONTROL_LIST_VERTICAL, - // Spacing between a dialog button and the content above it. - DISTANCE_DIALOG_BUTTON_TOP, // Smaller horizontal spacing between other controls that are logically // related. DISTANCE_RELATED_CONTROL_HORIZONTAL_SMALL,
diff --git a/chrome/browser/ui/views/harmony/harmony_layout_provider.cc b/chrome/browser/ui/views/harmony/harmony_layout_provider.cc index 365023c..2e108b4 100644 --- a/chrome/browser/ui/views/harmony/harmony_layout_provider.cc +++ b/chrome/browser/ui/views/harmony/harmony_layout_provider.cc
@@ -17,6 +17,7 @@ int HarmonyLayoutProvider::GetDistanceMetric(int metric) const { DCHECK_GE(metric, views::VIEWS_INSETS_MAX); switch (metric) { + case views::DISTANCE_BUBBLE_BUTTON_TOP_MARGIN: case views::DISTANCE_BUBBLE_CONTENTS_HORIZONTAL_MARGIN: case views::DISTANCE_BUBBLE_CONTENTS_VERTICAL_MARGIN: case views::DISTANCE_DIALOG_CONTENTS_HORIZONTAL_MARGIN: @@ -42,8 +43,6 @@ return kHarmonyLayoutUnit / 2; case views::DISTANCE_DIALOG_BUTTON_BOTTOM_MARGIN: return kHarmonyLayoutUnit; - case DISTANCE_DIALOG_BUTTON_TOP: - return kHarmonyLayoutUnit; case views::DISTANCE_DIALOG_BUTTON_MINIMUM_WIDTH: case DISTANCE_BUTTON_MINIMUM_WIDTH: // Minimum label size plus padding.
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc index e5d02eb..f8d13d1 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/chromeos/printing/ppd_provider_factory.h" #include "chrome/browser/chromeos/printing/printer_configurer.h" #include "chrome/browser/chromeos/printing/printer_discoverer.h" +#include "chrome/browser/chromeos/printing/printer_info.h" #include "chrome/browser/chromeos/printing/printers_manager_factory.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/profiles/profile.h" @@ -45,6 +46,12 @@ namespace { +const char kIppScheme[] = "ipp"; +const char kIppsScheme[] = "ipps"; + +const int kIppPort = 631; +const int kIppsPort = 443; + // These values are written to logs. New enum values can be added, but existing // enums must never be renumbered or deleted and reused. enum PpdSourceForHistogram { kUser = 0, kScs = 1, kPpdSourceMax }; @@ -58,6 +65,7 @@ Printer::PrinterProtocol::kProtocolMax); } +// Returns a JSON representation of |printer| as a CupsPrinterInfo. std::unique_ptr<base::DictionaryValue> GetPrinterInfo(const Printer& printer) { std::unique_ptr<base::DictionaryValue> printer_info = base::MakeUnique<base::DictionaryValue>(); @@ -98,6 +106,23 @@ return printer_info; } +// Extracts a sanitized value of printerQueeu from |printer_dict|. Returns an +// empty string if the value was not present in the dictionary. +std::string GetPrinterQueue(const base::DictionaryValue& printer_dict) { + std::string queue; + if (!printer_dict.GetString("printerQueue", &queue)) { + return queue; + } + + if (!queue.empty() && queue[0] == '/') { + // Strip the leading backslash. It is expected that this results in an + // empty string if the input is just a backslash. + queue = queue.substr(1); + } + + return queue; +} + } // namespace CupsPrintersHandler::CupsPrintersHandler(content::WebUI* webui) @@ -127,6 +152,9 @@ "addCupsPrinter", base::Bind(&CupsPrintersHandler::HandleAddCupsPrinter, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "getPrinterInfo", base::Bind(&CupsPrintersHandler::HandleGetPrinterInfo, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "getCupsPrinterManufacturersList", base::Bind(&CupsPrintersHandler::HandleGetCupsPrinterManufacturers, base::Unretained(this))); @@ -203,6 +231,90 @@ base::Bind(&base::DoNothing)); } +void CupsPrintersHandler::HandleGetPrinterInfo(const base::ListValue* args) { + DCHECK(args); + std::string callback_id; + if (!args->GetString(0, &callback_id)) { + NOTREACHED() << "Expected request for a promise"; + return; + } + + const base::DictionaryValue* printer_dict = nullptr; + if (!args->GetDictionary(1, &printer_dict)) { + NOTREACHED() << "Dictionary missing"; + return; + } + + AllowJavascript(); + + std::string printer_address; + if (!printer_dict->GetString("printerAddress", &printer_address)) { + NOTREACHED() << "Address missing"; + return; + } + + if (printer_address.empty()) { + // Run the failure callback. + OnPrinterInfo(callback_id, false, "", "", false); + return; + } + + std::string printer_queue = GetPrinterQueue(*printer_dict); + + std::string printer_protocol; + if (!printer_dict->GetString("printerProtocol", &printer_protocol)) { + NOTREACHED() << "Protocol missing"; + return; + } + + // Parse url to separate address and port. ParseStandardURL expects a scheme, + // so add the printer_protocol. + std::string printer_uri = + printer_protocol + url::kStandardSchemeSeparator + printer_address; + const char* uri_ptr = printer_uri.c_str(); + url::Parsed parsed; + url::ParseStandardURL(uri_ptr, printer_uri.length(), &parsed); + base::StringPiece host(&printer_uri[parsed.host.begin], parsed.host.len); + + int port = ParsePort(uri_ptr, parsed.port); + if (port == url::SpecialPort::PORT_UNSPECIFIED || + port == url::SpecialPort::PORT_INVALID) { + // imply port from protocol + if (printer_protocol == kIppScheme) { + port = kIppPort; + } else if (printer_protocol == kIppsScheme) { + // ipps is ipp over https so it uses the https port. + port = kIppsPort; + } else { + NOTREACHED() << "Unrecognized protocol. Port was not set."; + } + } + + ::chromeos::QueryIppPrinter( + host.as_string(), port, printer_queue, + base::Bind(&CupsPrintersHandler::OnPrinterInfo, + weak_factory_.GetWeakPtr(), callback_id)); +} + +void CupsPrintersHandler::OnPrinterInfo(const std::string& callback_id, + bool success, + const std::string& make, + const std::string& model, + bool ipp_everywhere) { + if (!success) { + base::DictionaryValue reject; + reject.SetString("message", "Querying printer failed"); + RejectJavascriptCallback(base::Value(callback_id), reject); + return; + } + + base::DictionaryValue info; + info.SetString("manufacturer", make); + info.SetString("model", model); + info.SetBoolean("autoconf", ipp_everywhere); + ResolveJavascriptCallback(base::Value(callback_id), info); +} + void CupsPrintersHandler::HandleAddCupsPrinter(const base::ListValue* args) { AllowJavascript(); @@ -216,7 +328,6 @@ std::string printer_model; std::string printer_address; std::string printer_protocol; - std::string printer_queue; std::string printer_ppd_path; CHECK(printer_dict->GetString("printerId", &printer_id)); CHECK(printer_dict->GetString("printerName", &printer_name)); @@ -225,16 +336,18 @@ CHECK(printer_dict->GetString("printerModel", &printer_model)); CHECK(printer_dict->GetString("printerAddress", &printer_address)); CHECK(printer_dict->GetString("printerProtocol", &printer_protocol)); - // printerQueue might be null for a printer whose protocol is not 'LPD'. - printer_dict->GetString("printerQueue", &printer_queue); - // printerPPDPath might be null for an auto-discovered printer. - printer_dict->GetString("printerPPDPath", &printer_ppd_path); - std::string printer_uri = printer_protocol + "://" + printer_address; + std::string printer_queue = GetPrinterQueue(*printer_dict); + + std::string printer_uri = + printer_protocol + url::kStandardSchemeSeparator + printer_address; if (!printer_queue.empty()) { printer_uri += "/" + printer_queue; } + // printerPPDPath might be null for an auto-discovered printer. + printer_dict->GetString("printerPPDPath", &printer_ppd_path); + std::unique_ptr<Printer> printer = base::MakeUnique<Printer>(printer_id); printer->set_display_name(printer_name); printer->set_description(printer_description); @@ -242,8 +355,13 @@ printer->set_model(printer_model); printer->set_uri(printer_uri); - // Verify a valid ppd path is present. - if (!printer_ppd_path.empty()) { + bool autoconf = false; + printer_dict->GetBoolean("printerAutoconf", &autoconf); + + // Verify that the printer is autoconf or a valid ppd path is present. + if (autoconf) { + printer->mutable_ppd_reference()->autoconf = true; + } else if (!printer_ppd_path.empty()) { RecordPpdSource(kUser); GURL tmp = net::FilePathToFileURL(base::FilePath(printer_ppd_path)); if (!tmp.is_valid()) {
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h index 343daea..ee93a93 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h
@@ -49,6 +49,23 @@ void HandleUpdateCupsPrinter(const base::ListValue* args); void HandleRemoveCupsPrinter(const base::ListValue* args); + // For a CupsPrinterInfo in |args|, retrieves the relevant PrinterInfo object + // using an IPP call to the printer. + void HandleGetPrinterInfo(const base::ListValue* args); + + // Handles the callback for HandleGetPrinterInfo. |callback_id| is the + // identifier to resolve the correct Promise. |success| indicates if the + // query was successful. |make| is the detected printer manufacturer. + // |model| is the detected model. |ipp_everywhere| indicates if configuration + // using the CUPS IPP Everywhere driver should be attempted. If |success| is + // false, the values of |make|, |model| and |ipp_everywhere| are not + // specified. + void OnPrinterInfo(const std::string& callback_id, + bool success, + const std::string& make, + const std::string& model, + bool ipp_everywhere); + void HandleAddCupsPrinter(const base::ListValue* args); void OnAddedPrinter(std::unique_ptr<Printer> printer, chromeos::PrinterSetupResult result);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 4622529..fe3d75d 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3270,6 +3270,7 @@ "../browser/thumbnails/content_based_thumbnailing_algorithm_unittest.cc", "../browser/thumbnails/simple_thumbnail_crop_unittest.cc", "../browser/thumbnails/thumbnail_service_unittest.cc", + "../browser/translate/chrome_translate_client_unittest.cc", "../browser/translate/language_model_factory_unittest.cc", "../browser/translate/translate_service_unittest.cc", "../browser/ui/android/tab_model/tab_model_list_unittest.cc",
diff --git a/chrome/test/data/webui/media_router/OWNERS b/chrome/test/data/webui/media_router/OWNERS new file mode 100644 index 0000000..fda51ea --- /dev/null +++ b/chrome/test/data/webui/media_router/OWNERS
@@ -0,0 +1,3 @@ +file://chrome/browser/media/router/OWNERS + +# COMPONENT: Internals>Cast>UI
diff --git a/chrome/test/data/webui/settings/cups_printer_page_tests.js b/chrome/test/data/webui/settings/cups_printer_page_tests.js index 715fd44..aa5d175 100644 --- a/chrome/test/data/webui/settings/cups_printer_page_tests.js +++ b/chrome/test/data/webui/settings/cups_printer_page_tests.js
@@ -12,6 +12,7 @@ 'getCupsPrintersList', 'getCupsPrinterManufacturersList', 'getCupsPrinterModelsList', + 'getPrinterInfo', 'startDiscoveringPrinters', 'stopDiscoveringPrinters', ]); @@ -23,6 +24,7 @@ printerList: [], manufacturers: [], models: [], + printerInfo: {}, /** @override */ getCupsPrintersList: function() { @@ -43,6 +45,13 @@ }, /** @override */ + getPrinterInfo: function(newPrinter) { + this.methodCalled('getPrinterInfo', newPrinter); + // Reject all calls for now. + return Promise.reject(); + }, + + /** @override */ startDiscoveringPrinters: function() { this.methodCalled('startDiscoveringPrinters'); }, @@ -117,15 +126,20 @@ // Now we should be in the manually add dialog. var addDialog = dialog.$$('add-printer-manually-dialog'); assertTrue(!!addDialog); - fillAddManuallyDialog(addDialog); MockInteractions.tap(addDialog.$$('.action-button')); Polymer.dom.flush(); + // Configure is shown until getPrinterInfo is rejected. + assertTrue(!!dialog.$$('add-printer-configuring-dialog')); - // showing model selection - assertFalse(!!dialog.$$('add-printer-configuring-dialog')); - assertTrue(!!dialog.$$('add-printer-manufacturer-model-dialog')); + // Upon rejection, show model. + return cupsPrintersBrowserProxy. + whenCalled('getCupsPrinterManufacturersList'). + then(function() { + // TODO(skau): Verify other dialogs are hidden. + assertTrue(!!dialog.$$('add-printer-manufacturer-model-dialog')); + }); }); /** @@ -149,10 +163,11 @@ MockInteractions.tap(addDialog.$$('.action-button')); Polymer.dom.flush(); - var modelDialog = dialog.$$('add-printer-manufacturer-model-dialog'); - assertTrue(!!modelDialog); - - return cupsPrintersBrowserProxy.whenCalled( - 'getCupsPrinterManufacturersList'); + return cupsPrintersBrowserProxy. + whenCalled('getCupsPrinterManufacturersList'). + then(function() { + var modelDialog = dialog.$$('add-printer-manufacturer-model-dialog'); + assertTrue(!!modelDialog); + }); }); });
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java index 77252d7c..287f06e7 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
@@ -25,8 +25,10 @@ static final int BACKGROUND_TASK_CHROME_MINIDUMP = 5; static final int BACKGROUND_TASK_OFFLINE_PAGES = 6; static final int BACKGROUND_TASK_OFFLINE_PREFETCH = 7; + static final int BACKGROUND_TASK_DOWNLOAD_SERVICE = 8; + static final int BACKGROUND_TASK_DOWNLOAD_CLEANUP = 9; // Keep this one at the end and increment appropriately when adding new tasks. - static final int BACKGROUND_TASK_COUNT = 8; + static final int BACKGROUND_TASK_COUNT = 10; static final String KEY_CACHED_UMA = "bts_cached_uma"; @@ -222,6 +224,10 @@ return BACKGROUND_TASK_OFFLINE_PAGES; case TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID: return BACKGROUND_TASK_OFFLINE_PREFETCH; + case TaskIds.DOWNLOAD_SERVICE_JOB_ID: + return BACKGROUND_TASK_DOWNLOAD_SERVICE; + case TaskIds.DOWNLOAD_CLEANUP_JOB_ID: + return BACKGROUND_TASK_DOWNLOAD_CLEANUP; default: assert false; }
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java index e4a39529..b9c4fe57 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java
@@ -20,6 +20,8 @@ public static final int CHROME_MINIDUMP_UPLOADING_JOB_ID = 43; public static final int OFFLINE_PAGES_BACKGROUND_JOB_ID = 77; public static final int OFFLINE_PAGES_PREFETCH_JOB_ID = 78; + public static final int DOWNLOAD_SERVICE_JOB_ID = 53; + public static final int DOWNLOAD_CLEANUP_JOB_ID = 54; private TaskIds() {} }
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java index 405ef75..94e3a1c6 100644 --- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
@@ -67,7 +67,13 @@ assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_OFFLINE_PREFETCH, BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId( TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID)); - assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_COUNT, 8); + assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_DOWNLOAD_SERVICE, + BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId( + TaskIds.DOWNLOAD_SERVICE_JOB_ID)); + assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_DOWNLOAD_CLEANUP, + BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId( + TaskIds.DOWNLOAD_CLEANUP_JOB_ID)); + assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_COUNT, 10); } @Test
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc index 4bee639..2333fe25 100644 --- a/components/content_settings/core/common/content_settings.cc +++ b/components/content_settings/core/common/content_settings.cc
@@ -57,7 +57,6 @@ {CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA, 31}, {CONTENT_SETTINGS_TYPE_ADS, 32}, {CONTENT_SETTINGS_TYPE_ADS_DATA, 33}, - {CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, 34}, }; int ContentSettingTypeToHistogramValue(ContentSettingsType content_setting,
diff --git a/components/download/components_unittests.filter b/components/download/components_unittests.filter index dd85efe6..7c53bdc 100644 --- a/components/download/components_unittests.filter +++ b/components/download/components_unittests.filter
@@ -1,8 +1,10 @@ +BatteryListenerTest.* DownloadDriverImplTest.* DownloadServiceClientSetTest.* DownloadServiceControllerImplTest.* DownloadServiceImplTest.* DownloadServiceEntryUtilsTest.* DownloadServiceModelImplTest.* -BatteryListenerTest.* -NetworkListenerTest.* \ No newline at end of file +DownloadStoreTest.* +NetworkListenerTest.* +ProtoConversionsTest.* \ No newline at end of file
diff --git a/components/download/content/factory/download_service_factory.cc b/components/download/content/factory/download_service_factory.cc index c768b245..bb2d7b97 100644 --- a/components/download/content/factory/download_service_factory.cc +++ b/components/download/content/factory/download_service_factory.cc
@@ -25,7 +25,8 @@ std::unique_ptr<DownloadClientMap> clients, content::DownloadManager* download_manager, const base::FilePath& storage_dir, - const scoped_refptr<base::SequencedTaskRunner>& background_task_runner) { + const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, + std::unique_ptr<TaskScheduler> task_scheduler) { auto client_set = base::MakeUnique<ClientSet>(std::move(clients)); auto config = Configuration::CreateFromFinch(); @@ -44,7 +45,8 @@ auto controller = base::MakeUnique<ControllerImpl>( std::move(client_set), std::move(config), std::move(driver), - std::move(model), std::move(device_status_listener)); + std::move(model), std::move(device_status_listener), + std::move(task_scheduler)); return new DownloadServiceImpl(std::move(controller)); }
diff --git a/components/download/content/factory/download_service_factory.h b/components/download/content/factory/download_service_factory.h index 8f5120b..8df6dfe7 100644 --- a/components/download/content/factory/download_service_factory.h +++ b/components/download/content/factory/download_service_factory.h
@@ -19,6 +19,7 @@ namespace download { class DownloadService; +class TaskScheduler; // |clients| is a map of DownloadClient -> std::unique_ptr<Client>. This // represents all of the clients that are allowed to have requests made on @@ -34,7 +35,8 @@ std::unique_ptr<DownloadClientMap> clients, content::DownloadManager* download_manager, const base::FilePath& storage_dir, - const scoped_refptr<base::SequencedTaskRunner>& background_task_runner); + const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, + std::unique_ptr<TaskScheduler> task_scheduler); } // namespace download
diff --git a/components/download/internal/controller.h b/components/download/internal/controller.h index 0ea3f736..26011a0b 100644 --- a/components/download/internal/controller.h +++ b/components/download/internal/controller.h
@@ -9,6 +9,8 @@ #include "base/macros.h" #include "components/download/public/clients.h" +#include "components/download/public/download_service.h" +#include "components/download/public/download_task_types.h" namespace download { @@ -54,6 +56,13 @@ // Otherwise returns DownloadClient::INVALID for an unowned entry. virtual DownloadClient GetOwnerOfDownload(const std::string& guid) = 0; + // See DownloadService::OnStartScheduledTask. + virtual void OnStartScheduledTask(DownloadTaskType task_type, + const TaskFinishedCallback& callback) = 0; + + // See DownloadService::OnStopScheduledTask. + virtual bool OnStopScheduledTask(DownloadTaskType task_type) = 0; + private: DISALLOW_COPY_AND_ASSIGN(Controller); };
diff --git a/components/download/internal/controller_impl.cc b/components/download/internal/controller_impl.cc index 38f73731..c5e6782 100644 --- a/components/download/internal/controller_impl.cc +++ b/components/download/internal/controller_impl.cc
@@ -8,13 +8,13 @@ #include <vector> #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/threading/thread_task_runner_handle.h" #include "components/download/internal/client_set.h" #include "components/download/internal/config.h" #include "components/download/internal/entry.h" #include "components/download/internal/entry_utils.h" #include "components/download/internal/model.h" -#include "components/download/internal/stats.h" namespace download { @@ -23,12 +23,14 @@ std::unique_ptr<Configuration> config, std::unique_ptr<DownloadDriver> driver, std::unique_ptr<Model> model, - std::unique_ptr<DeviceStatusListener> device_status_listener) + std::unique_ptr<DeviceStatusListener> device_status_listener, + std::unique_ptr<TaskScheduler> task_scheduler) : clients_(std::move(clients)), config_(std::move(config)), driver_(std::move(driver)), model_(std::move(model)), - device_status_listener_(std::move(device_status_listener)) {} + device_status_listener_(std::move(device_status_listener)), + task_scheduler_(std::move(task_scheduler)) {} ControllerImpl::~ControllerImpl() { device_status_listener_->Stop(); @@ -135,6 +137,57 @@ return entry ? entry->client : DownloadClient::INVALID; } +void ControllerImpl::OnStartScheduledTask( + DownloadTaskType task_type, + const TaskFinishedCallback& callback) { + task_finished_callbacks_[task_type] = callback; + if (!startup_status_.Complete()) { + return; + } else if (!startup_status_.Ok()) { + HandleTaskFinished(task_type, false, + stats::ScheduledTaskStatus::ABORTED_ON_FAILED_INIT); + return; + } + + ProcessScheduledTasks(); +} + +bool ControllerImpl::OnStopScheduledTask(DownloadTaskType task_type) { + HandleTaskFinished(task_type, false, + stats::ScheduledTaskStatus::CANCELLED_ON_STOP); + return true; +} + +void ControllerImpl::ProcessScheduledTasks() { + if (!startup_status_.Ok()) { + while (!task_finished_callbacks_.empty()) { + auto it = task_finished_callbacks_.begin(); + HandleTaskFinished(it->first, false, + stats::ScheduledTaskStatus::ABORTED_ON_FAILED_INIT); + } + return; + } + + while (!task_finished_callbacks_.empty()) { + auto it = task_finished_callbacks_.begin(); + // TODO(shaktisahu): Execute the scheduled task. + + HandleTaskFinished(it->first, false, + stats::ScheduledTaskStatus::COMPLETED_NORMALLY); + } +} + +void ControllerImpl::HandleTaskFinished(DownloadTaskType task_type, + bool needs_reschedule, + stats::ScheduledTaskStatus status) { + if (status != stats::ScheduledTaskStatus::CANCELLED_ON_STOP) { + base::ResetAndReturn(&task_finished_callbacks_[task_type]) + .Run(needs_reschedule); + } + stats::LogScheduledTaskStatus(task_type, status); + task_finished_callbacks_.erase(task_type); +} + void ControllerImpl::OnDriverReady(bool success) { DCHECK(!startup_status_.driver_ok.has_value()); startup_status_.driver_ok = success; @@ -205,6 +258,7 @@ if (!startup_status_.Ok()) { // TODO(dtrainor): Recover here. Try to clean up any disk state and, if // possible, any DownloadDriver data and continue with initialization? + ProcessScheduledTasks(); return; } @@ -216,6 +270,7 @@ // TODO(dtrainor): Post this so that the initialization step is finalized // before Clients can take action. NotifyClientsOfStartup(); + ProcessScheduledTasks(); } void ControllerImpl::CancelOrphanedRequests() {
diff --git a/components/download/internal/controller_impl.h b/components/download/internal/controller_impl.h index 3a1e2db..3e7a852 100644 --- a/components/download/internal/controller_impl.h +++ b/components/download/internal/controller_impl.h
@@ -15,7 +15,9 @@ #include "components/download/internal/model.h" #include "components/download/internal/scheduler/device_status_listener.h" #include "components/download/internal/startup_status.h" +#include "components/download/internal/stats.h" #include "components/download/public/download_params.h" +#include "components/download/public/task_scheduler.h" namespace download { @@ -38,7 +40,8 @@ std::unique_ptr<Configuration> config, std::unique_ptr<DownloadDriver> driver, std::unique_ptr<Model> model, - std::unique_ptr<DeviceStatusListener> device_status_listener); + std::unique_ptr<DeviceStatusListener> device_status_listener, + std::unique_ptr<TaskScheduler> task_scheduler); ~ControllerImpl() override; // Controller implementation. @@ -51,6 +54,9 @@ void ChangeDownloadCriteria(const std::string& guid, const SchedulingParams& params) override; DownloadClient GetOwnerOfDownload(const std::string& guid) override; + void OnStartScheduledTask(DownloadTaskType task_type, + const TaskFinishedCallback& callback) override; + bool OnStopScheduledTask(DownloadTaskType task_type) override; private: // DownloadDriver::Client implementation. @@ -106,6 +112,14 @@ DownloadParams::StartResult result, const DownloadParams::StartCallback& callback); + // Entry point for a scheduled task after the task is fired. + void ProcessScheduledTasks(); + + // Handles and clears any pending task finished callbacks. + void HandleTaskFinished(DownloadTaskType task_type, + bool needs_reschedule, + stats::ScheduledTaskStatus status); + std::unique_ptr<ClientSet> clients_; std::unique_ptr<Configuration> config_; @@ -113,10 +127,12 @@ std::unique_ptr<DownloadDriver> driver_; std::unique_ptr<Model> model_; std::unique_ptr<DeviceStatusListener> device_status_listener_; + std::unique_ptr<TaskScheduler> task_scheduler_; // Internal state. StartupStatus startup_status_; std::map<std::string, DownloadParams::StartCallback> start_callbacks_; + std::map<DownloadTaskType, TaskFinishedCallback> task_finished_callbacks_; DISALLOW_COPY_AND_ASSIGN(ControllerImpl); };
diff --git a/components/download/internal/controller_impl_unittest.cc b/components/download/internal/controller_impl_unittest.cc index f47aa27..6cecf73 100644 --- a/components/download/internal/controller_impl_unittest.cc +++ b/components/download/internal/controller_impl_unittest.cc
@@ -31,6 +31,16 @@ namespace { +class MockTaskScheduler : public TaskScheduler { + public: + MockTaskScheduler() = default; + ~MockTaskScheduler() = default; + + // TaskScheduler implementation. + MOCK_METHOD5(ScheduleTask, void(DownloadTaskType, bool, bool, long, long)); + MOCK_METHOD1(CancelTask, void(DownloadTaskType)); +}; + class DownloadServiceControllerImplTest : public testing::Test { public: DownloadServiceControllerImplTest() @@ -43,6 +53,7 @@ base::Bind(&DownloadServiceControllerImplTest::StartCallback, base::Unretained(this)); } + ~DownloadServiceControllerImplTest() override = default; void SetUp() override { @@ -61,10 +72,12 @@ auto client_set = base::MakeUnique<ClientSet>(std::move(clients)); auto model = base::MakeUnique<ModelImpl>(std::move(store)); auto device_status_listener = base::MakeUnique<TestDeviceStatusListener>(); + auto task_scheduler = base::MakeUnique<MockTaskScheduler>(); controller_ = base::MakeUnique<ControllerImpl>( std::move(client_set), std::move(config), std::move(driver), - std::move(model), std::move(device_status_listener)); + std::move(model), std::move(device_status_listener), + std::move(task_scheduler)); } protected:
diff --git a/components/download/internal/download_service_impl.cc b/components/download/internal/download_service_impl.cc index 27519ebc..c88c550 100644 --- a/components/download/internal/download_service_impl.cc +++ b/components/download/internal/download_service_impl.cc
@@ -17,6 +17,16 @@ DownloadServiceImpl::~DownloadServiceImpl() = default; +void DownloadServiceImpl::OnStartScheduledTask( + DownloadTaskType task_type, + const TaskFinishedCallback& callback) { + controller_->OnStartScheduledTask(task_type, callback); +} + +bool DownloadServiceImpl::OnStopScheduledTask(DownloadTaskType task_type) { + return controller_->OnStopScheduledTask(task_type); +} + DownloadService::ServiceStatus DownloadServiceImpl::GetStatus() { if (!controller_->GetStartupStatus()->Complete()) return DownloadService::ServiceStatus::STARTING_UP;
diff --git a/components/download/internal/download_service_impl.h b/components/download/internal/download_service_impl.h index e9f8e89..ab755c37 100644 --- a/components/download/internal/download_service_impl.h +++ b/components/download/internal/download_service_impl.h
@@ -25,6 +25,9 @@ ~DownloadServiceImpl() override; // DownloadService implementation. + void OnStartScheduledTask(DownloadTaskType task_type, + const TaskFinishedCallback& callback) override; + bool OnStopScheduledTask(DownloadTaskType task_type) override; ServiceStatus GetStatus() override; void StartDownload(const DownloadParams& download_params) override; void PauseDownload(const std::string& guid) override;
diff --git a/components/download/internal/stats.cc b/components/download/internal/stats.cc index ac019b7..762204d 100644 --- a/components/download/internal/stats.cc +++ b/components/download/internal/stats.cc
@@ -29,5 +29,10 @@ // TODO(dtrainor): Log |action|. } +void LogScheduledTaskStatus(DownloadTaskType task_type, + ScheduledTaskStatus status) { + // TODO(shaktisahu): Log |task_type| and |status|. +} + } // namespace stats } // namespace download
diff --git a/components/download/internal/stats.h b/components/download/internal/stats.h index 5142760..4ccae0c 100644 --- a/components/download/internal/stats.h +++ b/components/download/internal/stats.h
@@ -7,6 +7,7 @@ #include "components/download/public/clients.h" #include "components/download/public/download_params.h" +#include "components/download/public/download_task_types.h" namespace download { @@ -60,6 +61,18 @@ COUNT = 4, }; +// Enum used by UMA metrics to log the status of scheduled tasks. +enum class ScheduledTaskStatus { + // Startup failed and the task was not run. + ABORTED_ON_FAILED_INIT = 0, + + // OnStopScheduledTask() was received before the task could be fired. + CANCELLED_ON_STOP = 1, + + // Callback was run successfully after completion of the task. + COMPLETED_NORMALLY = 2, +}; + // Logs the results of starting up the Controller. Will log each failure reason // if |status| contains more than one initialization failure. void LogControllerStartupStatus(const StartupStatus& status); @@ -75,6 +88,10 @@ // cases. void LogModelOperationResult(ModelAction action, bool success); +// Log statistics about the status of a TaskFinishedCallback. +void LogScheduledTaskStatus(DownloadTaskType task_type, + ScheduledTaskStatus status); + } // namespace stats } // namespace download
diff --git a/components/download/internal/test/mock_controller.h b/components/download/internal/test/mock_controller.h index d4ac200..5c5ff76 100644 --- a/components/download/internal/test/mock_controller.h +++ b/components/download/internal/test/mock_controller.h
@@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_TEST_MOCK_CONTROLLER_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_TEST_MOCK_CONTROLLER_H_ + #include "base/macros.h" #include "components/download/internal/controller.h" #include "components/download/internal/startup_status.h" @@ -26,6 +29,9 @@ MOCK_METHOD2(ChangeDownloadCriteria, void(const std::string&, const SchedulingParams&)); MOCK_METHOD1(GetOwnerOfDownload, DownloadClient(const std::string&)); + MOCK_METHOD2(OnStartScheduledTask, + void(DownloadTaskType, const TaskFinishedCallback&)); + MOCK_METHOD1(OnStopScheduledTask, bool(DownloadTaskType task_type)); private: DISALLOW_COPY_AND_ASSIGN(MockController); @@ -33,3 +39,5 @@ } // namespace test } // namespace download + +#endif // COMPONENTS_DOWNLOAD_INTERNAL_TEST_MOCK_CONTROLLER_H_
diff --git a/components/download/public/BUILD.gn b/components/download/public/BUILD.gn index 5f013fd..016afe2 100644 --- a/components/download/public/BUILD.gn +++ b/components/download/public/BUILD.gn
@@ -14,8 +14,10 @@ "download_params.cc", "download_params.h", "download_service.h", + "download_task_types.h", "features.cc", "features.h", + "task_scheduler.h", ] deps = [ @@ -28,3 +30,22 @@ "//url", ] } + +if (is_android) { + android_library("public_java") { + srcjar_deps = [ ":jni_enums" ] + + deps = [ + "//base:base_java", + "//third_party/android_tools:android_support_annotations_java", + ] + } + + java_cpp_enum("jni_enums") { + visibility = [ "*" ] + + sources = [ + "download_task_types.h", + ] + } +}
diff --git a/components/download/public/download_service.h b/components/download/public/download_service.h index 37165c2..38c01a95 100644 --- a/components/download/public/download_service.h +++ b/components/download/public/download_service.h
@@ -14,6 +14,7 @@ #include "base/memory/ref_counted.h" #include "base/sequenced_task_runner.h" #include "components/download/public/clients.h" +#include "components/download/public/download_task_types.h" #include "components/keyed_service/core/keyed_service.h" namespace download { @@ -22,6 +23,8 @@ struct DownloadParams; struct SchedulingParams; +using TaskFinishedCallback = base::Callback<void(bool)>; + // A service responsible for helping facilitate the scheduling and downloading // of file content from the web. See |DownloadParams| for more details on the // types of scheduling that can be achieved and the required input parameters @@ -48,6 +51,20 @@ UNAVAILABLE = 2, }; + // Callback method to run by the service when a pre-scheduled task starts. + // This method is invoked on main thread and while it is running, the system + // holds a wakelock which is not released until either the |callback| is run + // or OnStopScheduledTask is invoked by the system. Do not call this method + // directly. + virtual void OnStartScheduledTask(DownloadTaskType task_type, + const TaskFinishedCallback& callback) = 0; + + // Callback method to run by the service if the system decides to stop the + // task. Returns true if the task needs to be rescheduled. Any pending + // TaskFinishedCallback should be reset after this call. Do not call this + // method directly. + virtual bool OnStopScheduledTask(DownloadTaskType task_type) = 0; + // Whether or not the DownloadService is currently available, initialized // successfully, and ready to be used. virtual ServiceStatus GetStatus() = 0;
diff --git a/components/download/public/download_task_types.h b/components/download/public/download_task_types.h new file mode 100644 index 0000000..a26bc013 --- /dev/null +++ b/components/download/public/download_task_types.h
@@ -0,0 +1,22 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_PUBLIC_DOWNLOAD_TASK_TYPES_H_ +#define COMPONENTS_DOWNLOAD_PUBLIC_DOWNLOAD_TASK_TYPES_H_ + +namespace download { + +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.download +enum class DownloadTaskType { + // Task to invoke download service to take various download actions. + DOWNLOAD_TASK = 0, + + // Task to remove unnecessary files from the system. + CLEANUP_TASK = 1, +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_PUBLIC_DOWNLOAD_TASK_TYPES_H_
diff --git a/components/download/public/task_scheduler.h b/components/download/public/task_scheduler.h new file mode 100644 index 0000000..0d5df15 --- /dev/null +++ b/components/download/public/task_scheduler.h
@@ -0,0 +1,34 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_PUBLIC_TASK_SCHEDULER_H_ +#define COMPONENTS_DOWNLOAD_PUBLIC_TASK_SCHEDULER_H_ + +#include "components/download/public/download_task_types.h" + +namespace download { + +// A helper class backed by system APIs to schedule jobs in the background. The +// tasks can run independently of each other as long as they have different +// |task_type|. Scheduling another task of same |task_type| before the task is +// fired will cancel the previous task. +class TaskScheduler { + public: + // Schedules a task with the operating system. The system has the liberty of + // firing the task any time between |window_start_time_seconds| and + // |window_end_time_seconds|. If the trigger conditions are not met, the + // behavior is unknown. + virtual void ScheduleTask(DownloadTaskType task_type, + bool require_unmetered_network, + bool require_charging, + long window_start_time_seconds, + long window_end_time_seconds) = 0; + + // Cancels a pre-scheduled task of type |task_type|. + virtual void CancelTask(DownloadTaskType task_type) = 0; +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_PUBLIC_TASK_SCHEDULER_H_
diff --git a/components/payments/mojom/payment_app.mojom b/components/payments/mojom/payment_app.mojom index f0bd4dd..6cb1980 100644 --- a/components/payments/mojom/payment_app.mojom +++ b/components/payments/mojom/payment_app.mojom
@@ -14,14 +14,26 @@ NOT_FOUND, NO_ACTIVE_WORKER, STORAGE_OPERATION_FAILED, + FETCH_INSTRUMENT_ICON_FAILED, }; +// This struct is provided to hold an image object from render side +// (ImageObject.idl). +struct ImageObject { + url.mojom.Url src; +}; + +// This struct is provided to hold a payment instrument from render +// side (PaymentInstrument.idl). struct PaymentInstrument { string name; + array<ImageObject> icons; array<string> enabled_methods; string stringified_capabilities; }; +// This interface provides implementation of PaymentInstruments.idl +// in render side. interface PaymentManager { Init(string service_worker_scope); DeletePaymentInstrument(string instrument_key) @@ -38,6 +50,8 @@ => (PaymentHandlerStatus status); }; +// This struct is provided to send payment request data to render side +// (PaymentRequestEvent.idl). struct PaymentRequestEventData { url.mojom.Url top_level_origin; url.mojom.Url payment_request_origin; @@ -48,6 +62,8 @@ string instrument_key; }; +// This struct is provided to receive payment app response from render +// side (PaymentAppResponse.idl). struct PaymentAppResponse { string method_name; string stringified_details;
diff --git a/components/safe_browsing/password_protection/password_protection_request.cc b/components/safe_browsing/password_protection/password_protection_request.cc index f23e47e..909c848 100644 --- a/components/safe_browsing/password_protection/password_protection_request.cc +++ b/components/safe_browsing/password_protection/password_protection_request.cc
@@ -36,14 +36,12 @@ password_form_action_(password_form_action), password_form_frame_url_(password_form_frame_url), saved_domain_(saved_domain), - trigger_type_(type), + request_type_(type), password_field_exists_(password_field_exists), password_protection_service_(pps), request_timeout_in_ms_(request_timeout_in_ms), weakptr_factory_(this) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(trigger_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || - trigger_type_ == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); } PasswordProtectionRequest::~PasswordProtectionRequest() { @@ -87,7 +85,7 @@ std::unique_ptr<LoginReputationClientResponse> cached_response = base::MakeUnique<LoginReputationClientResponse>(); auto verdict = password_protection_service_->GetCachedVerdict( - main_frame_url_, trigger_type_, cached_response.get()); + main_frame_url_, cached_response.get()); if (verdict != LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED) Finish(PasswordProtectionService::RESPONSE_ALREADY_CACHED, std::move(cached_response)); @@ -98,11 +96,11 @@ void PasswordProtectionRequest::FillRequestProto() { request_proto_ = base::MakeUnique<LoginReputationClientRequest>(); request_proto_->set_page_url(main_frame_url_.spec()); - request_proto_->set_trigger_type(trigger_type_); - password_protection_service_->FillUserPopulation(trigger_type_, + request_proto_->set_trigger_type(request_type_); + password_protection_service_->FillUserPopulation(request_type_, request_proto_.get()); request_proto_->set_stored_verdict_cnt( - password_protection_service_->GetStoredVerdictCount(trigger_type_)); + password_protection_service_->GetStoredVerdictCount()); LoginReputationClientRequest::Frame* main_frame = request_proto_->add_frames(); main_frame->set_url(main_frame_url_.spec()); @@ -110,7 +108,7 @@ password_protection_service_->FillReferrerChain( main_frame_url_, -1 /* tab id not available */, main_frame); - switch (trigger_type_) { + switch (request_type_) { case LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE: { LoginReputationClientRequest::Frame::Form* password_form; if (password_form_frame_url_ == main_frame_url_) { @@ -249,7 +247,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); tracker_.TryCancelAll(); - if (trigger_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) { + if (request_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) { UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogramName, outcome, PasswordProtectionService::MAX_OUTCOME); } else { @@ -258,7 +256,7 @@ } if (outcome == PasswordProtectionService::SUCCEEDED && response) { - switch (trigger_type_) { + switch (request_type_) { case LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE: UMA_HISTOGRAM_ENUMERATION( "PasswordProtection.Verdict.PasswordFieldOnFocus",
diff --git a/components/safe_browsing/password_protection/password_protection_request.h b/components/safe_browsing/password_protection/password_protection_request.h index 756a65d..721739b 100644 --- a/components/safe_browsing/password_protection/password_protection_request.h +++ b/components/safe_browsing/password_protection/password_protection_request.h
@@ -74,8 +74,8 @@ content::WebContents* web_contents() const { return web_contents_; } - LoginReputationClientRequest::TriggerType trigger_type() const { - return trigger_type_; + LoginReputationClientRequest::TriggerType request_type() const { + return request_type_; } private: @@ -129,7 +129,7 @@ const std::string saved_domain_; // If this request is for unfamiliar login page or for a password reuse event. - const LoginReputationClientRequest::TriggerType trigger_type_; + const LoginReputationClientRequest::TriggerType request_type_; // If there is a password field on the page. const bool password_field_exists_;
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc index b24e456..c7ec2a9d 100644 --- a/components/safe_browsing/password_protection/password_protection_service.cc +++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -4,9 +4,6 @@ #include "components/safe_browsing/password_protection/password_protection_service.h" -#include <stddef.h> -#include <string> - #include "base/base64.h" #include "base/bind.h" #include "base/callback.h" @@ -41,7 +38,6 @@ const int kRequestTimeoutMs = 10000; const char kPasswordProtectionRequestUrl[] = "https://sb-ssl.google.com/safebrowsing/clientreport/login"; -const char kPasswordOnFocusCacheKey[] = "password_on_focus_cache_key"; // Helper function to determine if the given origin matches content settings // map's patterns. @@ -91,8 +87,7 @@ scoped_refptr<net::URLRequestContextGetter> request_context_getter, HistoryService* history_service, HostContentSettingsMap* host_content_settings_map) - : stored_verdict_count_password_on_focus_(-1), - stored_verdict_count_password_entry_(-1), + : stored_verdict_count_(-1), database_manager_(database_manager), request_context_getter_(request_context_getter), history_service_observer_(this), @@ -127,50 +122,24 @@ hostname.find('.') != std::string::npos; } -// We cache both types of pings under the same content settings type ( -// CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION). Since UNFAMILIAR_LOGING_PAGE -// verdicts are only enabled on extended reporting users, we cache them one -// layer lower in the content setting DictionaryValue than PASSWORD_REUSE_EVENT -// verdicts. -// In other words, to cache a UNFAMILIAR_LOGIN_PAGE verdict we needs two levels -// of keys: (1) origin, (2) cache expression returned in verdict. -// To cache a PASSWORD_REUSE_EVENT, three levels of keys are used: -// (1) origin, (2) 2nd level key is always |kPasswordOnFocusCacheKey|, -// (3) cache expression. LoginReputationClientResponse::VerdictType PasswordProtectionService::GetCachedVerdict( const GURL& url, - TriggerType trigger_type, LoginReputationClientResponse* out_response) { - DCHECK(trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || - trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); - if (!url.is_valid()) return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; + DCHECK(content_settings_); + GURL hostname = GetHostNameWithHTTPScheme(url); - std::unique_ptr<base::DictionaryValue> cache_dictionary = + std::unique_ptr<base::DictionaryValue> verdict_dictionary = base::DictionaryValue::From(content_settings_->GetWebsiteSetting( hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), nullptr)); - - if (!cache_dictionary.get() || cache_dictionary->empty()) + // Return early if there is no verdict cached for this origin. + if (!verdict_dictionary.get() || verdict_dictionary->empty()) return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; - base::DictionaryValue* verdict_dictionary = nullptr; - if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) { - // All UNFAMILIAR_LOGIN_PAGE verdicts (a.k.a password on focus ping) - // are cached under |kPasswordOnFocusCacheKey|. - if (!cache_dictionary->HasKey( - base::StringPiece(kPasswordOnFocusCacheKey))) { - return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED; - } - DCHECK(cache_dictionary->GetDictionaryWithoutPathExpansion( - base::StringPiece(kPasswordOnFocusCacheKey), &verdict_dictionary)); - } else { - verdict_dictionary = cache_dictionary.get(); - } - std::vector<std::string> paths; GeneratePathVariantsWithoutQuery(url, &paths); int max_path_depth = -1; @@ -179,12 +148,8 @@ // For all the verdicts of the same origin, we key them by |cache_expression|. // Its corresponding value is a DictionaryValue contains its creation time and // the serialized verdict proto. - for (base::DictionaryValue::Iterator it(*verdict_dictionary); !it.IsAtEnd(); - it.Advance()) { - if (trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT && - it.key() == base::StringPiece(kPasswordOnFocusCacheKey)) { - continue; - } + for (base::DictionaryValue::Iterator it(*verdict_dictionary.get()); + !it.IsAtEnd(); it.Advance()) { base::DictionaryValue* verdict_entry = nullptr; CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion( it.key() /* cache_expression */, &verdict_entry)); @@ -215,66 +180,39 @@ void PasswordProtectionService::CacheVerdict( const GURL& url, - TriggerType trigger_type, LoginReputationClientResponse* verdict, const base::Time& receive_time) { DCHECK(verdict); DCHECK(content_settings_); - DCHECK(trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || - trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); GURL hostname = GetHostNameWithHTTPScheme(url); - int* stored_verdict_count = - trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE - ? &stored_verdict_count_password_on_focus_ - : &stored_verdict_count_password_entry_; - std::unique_ptr<base::DictionaryValue> cache_dictionary = + std::unique_ptr<base::DictionaryValue> verdict_dictionary = base::DictionaryValue::From(content_settings_->GetWebsiteSetting( hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), nullptr)); - if (!cache_dictionary.get()) - cache_dictionary = base::MakeUnique<base::DictionaryValue>(); + if (!verdict_dictionary.get()) + verdict_dictionary = base::MakeUnique<base::DictionaryValue>(); std::unique_ptr<base::DictionaryValue> verdict_entry = CreateDictionaryFromVerdict(verdict, receive_time); - base::DictionaryValue* verdict_dictionary = nullptr; - if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) { - // All UNFAMILIAR_LOGIN_PAGE verdicts (a.k.a password on focus ping) - // are cached under |kPasswordOnFocusCacheKey|. - if (!cache_dictionary->HasKey( - base::StringPiece(kPasswordOnFocusCacheKey))) { - cache_dictionary->SetDictionaryWithoutPathExpansion( - base::StringPiece(kPasswordOnFocusCacheKey), - base::MakeUnique<base::DictionaryValue>()); - } - DCHECK(cache_dictionary->GetDictionaryWithoutPathExpansion( - base::StringPiece(kPasswordOnFocusCacheKey), &verdict_dictionary)); - } else { - verdict_dictionary = cache_dictionary.get(); - } - // Increases stored verdict count if we haven't seen this cache expression // before. if (!verdict_dictionary->HasKey(verdict->cache_expression())) - *stored_verdict_count = GetStoredVerdictCount(trigger_type) + 1; + stored_verdict_count_ = GetStoredVerdictCount() + 1; // If same cache_expression is already in this verdict_dictionary, we simply // override it. verdict_dictionary->SetWithoutPathExpansion(verdict->cache_expression(), std::move(verdict_entry)); content_settings_->SetWebsiteSettingDefaultScope( hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, - std::string(), std::move(cache_dictionary)); + std::string(), std::move(verdict_dictionary)); } void PasswordProtectionService::CleanUpExpiredVerdicts() { DCHECK(content_settings_); - - if (GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) <= 0 && - GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT) <= 0) + if (GetStoredVerdictCount() <= 0) return; ContentSettingsForOneType password_protection_settings; @@ -286,29 +224,44 @@ password_protection_settings) { GURL primary_pattern_url = GURL(source.primary_pattern.ToString()); // Find all verdicts associated with this origin. - std::unique_ptr<base::DictionaryValue> cache_dictionary = + std::unique_ptr<base::DictionaryValue> verdict_dictionary = base::DictionaryValue::From(content_settings_->GetWebsiteSetting( primary_pattern_url, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), nullptr)); - bool has_expired_password_on_focus_entry = RemoveExpiredVerdicts( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - cache_dictionary.get()); - bool has_expired_password_reuse_entry = RemoveExpiredVerdicts( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, - cache_dictionary.get()); + std::vector<std::string> expired_keys; + for (base::DictionaryValue::Iterator it(*verdict_dictionary.get()); + !it.IsAtEnd(); it.Advance()) { + base::DictionaryValue* verdict_entry = nullptr; + CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion( + it.key(), &verdict_entry)); + int verdict_received_time; + LoginReputationClientResponse verdict; + CHECK(ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict)); - if (cache_dictionary->size() == 0u) { + if (IsCacheExpired(verdict_received_time, verdict.cache_duration_sec())) { + // Since DictionaryValue::Iterator cannot be used to modify the + // dictionary, we record the keys of expired verdicts in |expired_keys| + // and remove them in the next for-loop. + expired_keys.push_back(it.key()); + } + } + + for (const std::string& key : expired_keys) { + verdict_dictionary->RemoveWithoutPathExpansion(key, nullptr); + stored_verdict_count_--; + } + + if (verdict_dictionary->size() == 0u) { content_settings_->ClearSettingsForOneTypeWithPredicate( CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, base::Time(), base::Bind(&OriginMatchPrimaryPattern, primary_pattern_url)); - } else if (has_expired_password_on_focus_entry || - has_expired_password_reuse_entry) { + } else if (expired_keys.size() > 0u) { // Set the website setting of this origin with the updated // |verdict_diectionary|. content_settings_->SetWebsiteSettingDefaultScope( primary_pattern_url, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), - std::move(cache_dictionary)); + std::move(verdict_dictionary)); } } } @@ -319,15 +272,14 @@ const GURL& password_form_action, const GURL& password_form_frame_url, const std::string& saved_domain, - TriggerType trigger_type, + LoginReputationClientRequest::TriggerType type, bool password_field_exists) { DCHECK_CURRENTLY_ON(BrowserThread::UI); scoped_refptr<PasswordProtectionRequest> request( new PasswordProtectionRequest( web_contents, main_frame_url, password_form_action, - password_form_frame_url, saved_domain, trigger_type, - password_field_exists, this, GetRequestTimeoutInMS())); - + password_form_frame_url, saved_domain, type, password_field_exists, + this, GetRequestTimeoutInMS())); DCHECK(request); request->Start(); requests_.insert(std::move(request)); @@ -380,11 +332,11 @@ if (response) { if (!already_cached) { - CacheVerdict(request->main_frame_url(), request->trigger_type(), - response.get(), base::Time::Now()); + CacheVerdict(request->main_frame_url(), response.get(), + base::Time::Now()); } - if (request->trigger_type() == + if (request->request_type() == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE && response->verdict_type() == LoginReputationClientResponse::PHISHING && base::FeatureList::IsEnabled(kPasswordProtectionInterstitial)) { @@ -427,51 +379,30 @@ return url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true)); } -int PasswordProtectionService::GetStoredVerdictCount(TriggerType trigger_type) { +int PasswordProtectionService::GetStoredVerdictCount() { DCHECK(content_settings_); - DCHECK(trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || - trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); - int* stored_verdict_count = - trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE - ? &stored_verdict_count_password_on_focus_ - : &stored_verdict_count_password_entry_; // If we have already computed this, return its value. - if (*stored_verdict_count >= 0) - return *stored_verdict_count; + if (stored_verdict_count_ >= 0) + return stored_verdict_count_; ContentSettingsForOneType password_protection_settings; content_settings_->GetSettingsForOneType( CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), &password_protection_settings); - stored_verdict_count_password_on_focus_ = 0; - stored_verdict_count_password_entry_ = 0; + stored_verdict_count_ = 0; if (password_protection_settings.empty()) return 0; for (const ContentSettingPatternSource& source : password_protection_settings) { - std::unique_ptr<base::DictionaryValue> cache_dictionary = + std::unique_ptr<base::DictionaryValue> verdict_dictionary = base::DictionaryValue::From(content_settings_->GetWebsiteSetting( GURL(source.primary_pattern.ToString()), GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), nullptr)); - if (cache_dictionary.get() && !cache_dictionary->empty()) { - stored_verdict_count_password_entry_ += - static_cast<int>(cache_dictionary->size()); - if (cache_dictionary->HasKey( - base::StringPiece(kPasswordOnFocusCacheKey))) { - // Substracts 1 from password_entry count if |kPasswordOnFocusCacheKey| - // presents. - stored_verdict_count_password_entry_ -= 1; - base::DictionaryValue* password_on_focus_dict = nullptr; - cache_dictionary->GetDictionaryWithoutPathExpansion( - base::StringPiece(kPasswordOnFocusCacheKey), - &password_on_focus_dict); - stored_verdict_count_password_on_focus_ += - static_cast<int>(password_on_focus_dict->size()); - } - } + if (verdict_dictionary.get() && !verdict_dictionary->empty()) + stored_verdict_count_ += static_cast<int>(verdict_dictionary->size()); } - return *stored_verdict_count; + return stored_verdict_count_; } int PasswordProtectionService::GetRequestTimeoutInMS() { @@ -479,7 +410,7 @@ } void PasswordProtectionService::FillUserPopulation( - TriggerType trigger_type, + const LoginReputationClientRequest::TriggerType& request_type, LoginReputationClientRequest* request_proto) { ChromeUserPopulation* user_population = request_proto->mutable_population(); user_population->set_user_population( @@ -509,10 +440,8 @@ bool expired, const history::URLRows& deleted_rows, const std::set<GURL>& favicon_urls) { - if (stored_verdict_count_password_on_focus_ <= 0 && - stored_verdict_count_password_entry_ <= 0) { + if (stored_verdict_count_ <= 0) return; - } BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, @@ -534,8 +463,7 @@ if (all_history) { content_settings_->ClearSettingsForOneType( CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION); - stored_verdict_count_password_on_focus_ = 0; - stored_verdict_count_password_entry_ = 0; + stored_verdict_count_ = 0; return; } @@ -546,104 +474,24 @@ for (const history::URLRow& row : deleted_rows) { if (!row.url().SchemeIsHTTPOrHTTPS()) continue; - GURL url_key = GetHostNameWithHTTPScheme(row.url()); - stored_verdict_count_password_on_focus_ = - GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) - - GetVerdictCountForURL( - url_key, LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE); - stored_verdict_count_password_entry_ = - GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT) - - GetVerdictCountForURL( - url_key, LoginReputationClientRequest::PASSWORD_REUSE_EVENT); + std::unique_ptr<base::DictionaryValue> verdict_dictionary = + base::DictionaryValue::From(content_settings_->GetWebsiteSetting( + url_key, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, + std::string(), nullptr)); + + // Move on if we have no cached verdict for this deleted history row. + if (!verdict_dictionary.get() || verdict_dictionary->empty()) + continue; + + int verdict_count = static_cast<int>(verdict_dictionary->size()); + stored_verdict_count_ = GetStoredVerdictCount() - verdict_count; content_settings_->ClearSettingsForOneTypeWithPredicate( CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, base::Time(), base::Bind(&OriginMatchPrimaryPattern, url_key)); } } -int PasswordProtectionService::GetVerdictCountForURL(const GURL& url, - TriggerType trigger_type) { - DCHECK(trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || - trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); - std::unique_ptr<base::DictionaryValue> cache_dictionary = - base::DictionaryValue::From(content_settings_->GetWebsiteSetting( - url, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), - nullptr)); - if (!cache_dictionary.get() || cache_dictionary->empty()) - return 0; - - if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) { - base::DictionaryValue* password_on_focus_dict = nullptr; - cache_dictionary->GetDictionaryWithoutPathExpansion( - base::StringPiece(kPasswordOnFocusCacheKey), &password_on_focus_dict); - return password_on_focus_dict ? password_on_focus_dict->size() : 0; - } else { - return cache_dictionary->HasKey(base::StringPiece(kPasswordOnFocusCacheKey)) - ? cache_dictionary->size() - 1 - : cache_dictionary->size(); - } -} - -bool PasswordProtectionService::RemoveExpiredVerdicts( - TriggerType trigger_type, - base::DictionaryValue* cache_dictionary) { - DCHECK(trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE || - trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT); - base::DictionaryValue* verdict_dictionary = nullptr; - if (trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT) { - verdict_dictionary = cache_dictionary; - } else { - if (!cache_dictionary->GetDictionaryWithoutPathExpansion( - base::StringPiece(kPasswordOnFocusCacheKey), &verdict_dictionary)) { - return false; - } - } - - if (!verdict_dictionary || verdict_dictionary->empty()) - return false; - - std::vector<std::string> expired_keys; - for (base::DictionaryValue::Iterator it(*verdict_dictionary); !it.IsAtEnd(); - it.Advance()) { - if (trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT && - it.key() == std::string(kPasswordOnFocusCacheKey)) - continue; - - base::DictionaryValue* verdict_entry = nullptr; - CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion( - it.key(), &verdict_entry)); - int verdict_received_time; - LoginReputationClientResponse verdict; - CHECK(ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict)); - - if (IsCacheExpired(verdict_received_time, verdict.cache_duration_sec())) { - // Since DictionaryValue::Iterator cannot be used to modify the - // dictionary, we record the keys of expired verdicts in |expired_keys| - // and remove them in the next for-loop. - expired_keys.push_back(it.key()); - } - } - - for (const std::string& key : expired_keys) { - verdict_dictionary->RemoveWithoutPathExpansion(key, nullptr); - if (trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT) - stored_verdict_count_password_entry_--; - else - stored_verdict_count_password_on_focus_--; - } - - if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE && - verdict_dictionary->size() == 0U) { - cache_dictionary->RemoveWithoutPathExpansion( - base::StringPiece(kPasswordOnFocusCacheKey), nullptr); - } - - return expired_keys.size() > 0U; -} - // static bool PasswordProtectionService::ParseVerdictEntry( base::DictionaryValue* verdict_entry,
diff --git a/components/safe_browsing/password_protection/password_protection_service.h b/components/safe_browsing/password_protection/password_protection_service.h index 10036f4..89870aa 100644 --- a/components/safe_browsing/password_protection/password_protection_service.h +++ b/components/safe_browsing/password_protection/password_protection_service.h
@@ -49,7 +49,6 @@ // HostContentSettingsMap instance. class PasswordProtectionService : public history::HistoryServiceObserver { public: - using TriggerType = LoginReputationClientRequest::TriggerType; // The outcome of the request. These values are used for UMA. // DO NOT CHANGE THE ORDERING OF THESE VALUES. enum RequestOutcome { @@ -88,13 +87,11 @@ // any thread. LoginReputationClientResponse::VerdictType GetCachedVerdict( const GURL& url, - TriggerType trigger_type, LoginReputationClientResponse* out_response); - // Stores |verdict| in |settings| based on its |trigger_type|, |url|, - // |verdict| and |receive_time|. + // Stores |verdict| in |settings| based on |url|, |verdict| and + // |receive_time|. virtual void CacheVerdict(const GURL& url, - TriggerType trigger_type, LoginReputationClientResponse* verdict, const base::Time& receive_time); @@ -109,7 +106,7 @@ const GURL& password_form_action, const GURL& password_form_frame_url, const std::string& saved_domain, - TriggerType trigger_type, + LoginReputationClientRequest::TriggerType type, bool password_field_exists); virtual void MaybeStartPasswordFieldOnFocusRequest( @@ -155,9 +152,9 @@ // the requests. void CancelPendingRequests(); - // Gets the total number of verdicts of the specified |trigger_type| we cached - // for this profile. This counts both expired and active verdicts. - virtual int GetStoredVerdictCount(TriggerType trigger_type); + // Gets the total number of verdict (no matter expired or not) we cached for + // current active profile. + virtual int GetStoredVerdictCount(); scoped_refptr<net::URLRequestContextGetter> request_context_getter() { return request_context_getter_; @@ -176,8 +173,9 @@ int event_tab_id, // -1 if tab id is not available. LoginReputationClientRequest::Frame* frame) = 0; - void FillUserPopulation(TriggerType trigger_type, - LoginReputationClientRequest* request_proto); + void FillUserPopulation( + const LoginReputationClientRequest::TriggerType& request_type, + LoginReputationClientRequest* request_proto); virtual bool IsExtendedReporting() = 0; @@ -225,15 +223,6 @@ void RemoveContentSettingsOnURLsDeleted(bool all_history, const history::URLRows& deleted_rows); - // Helper function called by RemoveContentSettingsOnURLsDeleted(..). It - // calculate the number of verdicts of |type| that associate with |url|. - int GetVerdictCountForURL(const GURL& url, TriggerType type); - - // Remove verdict of |type| from |cache_dictionary|. Return false if no - // verdict removed, true otherwise. - bool RemoveExpiredVerdicts(TriggerType type, - base::DictionaryValue* cache_dictionary); - static bool ParseVerdictEntry(base::DictionaryValue* verdict_entry, int* out_verdict_received_time, LoginReputationClientResponse* out_verdict); @@ -256,12 +245,8 @@ static void RecordNoPingingReason(const base::Feature& feature, RequestOutcome reason); - // Number of verdict stored for this profile for password on focus pings. - int stored_verdict_count_password_on_focus_; - - // Number of verdict stored for this profile for protected password entry - // pings. - int stored_verdict_count_password_entry_; + // Number of verdict stored for this profile. + int stored_verdict_count_; scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc index 1baee7c..d297ef1 100644 --- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc +++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -201,19 +201,18 @@ } void CacheVerdict(const GURL& url, - LoginReputationClientRequest::TriggerType trigger, LoginReputationClientResponse::VerdictType verdict, int cache_duration_sec, const std::string& cache_expression, const base::Time& verdict_received_time) { LoginReputationClientResponse response( CreateVerdictProto(verdict, cache_duration_sec, cache_expression)); - password_protection_service_->CacheVerdict(url, trigger, &response, + password_protection_service_->CacheVerdict(url, &response, verdict_received_time); } - size_t GetStoredVerdictCount(LoginReputationClientRequest::TriggerType type) { - return password_protection_service_->GetStoredVerdictCount(type); + size_t GetStoredVerdictCount() { + return password_protection_service_->GetStoredVerdictCount(); } protected: @@ -305,173 +304,80 @@ GURL("http://evil.com/worse/index.html"), cache_expression_with_slash)); } -TEST_F(PasswordProtectionServiceTest, TestCachePasswordReuseVerdicts) { - ASSERT_EQ(0U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - +TEST_F(PasswordProtectionServiceTest, TestCachedVerdicts) { + ASSERT_EQ(0U, GetStoredVerdictCount()); // Assume each verdict has a TTL of 10 minutes. // Cache a verdict for http://www.test.com/foo/index.html CacheVerdict(GURL("http://www.test.com/foo/index.html"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foo", base::Time::Now()); - EXPECT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); + EXPECT_EQ(1U, GetStoredVerdictCount()); // Cache another verdict with the some origin and cache_expression should // override the cache. CacheVerdict(GURL("http://www.test.com/foo/index2.html"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::PHISHING, 10 * 60, "test.com/foo", base::Time::Now()); - EXPECT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); + EXPECT_EQ(1U, GetStoredVerdictCount()); LoginReputationClientResponse out_verdict; - EXPECT_EQ( - LoginReputationClientResponse::PHISHING, - password_protection_service_->GetCachedVerdict( - GURL("http://www.test.com/foo/index2.html"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &out_verdict)); + EXPECT_EQ(LoginReputationClientResponse::PHISHING, + password_protection_service_->GetCachedVerdict( + GURL("http://www.test.com/foo/index2.html"), &out_verdict)); // Cache another verdict with the same origin but different cache_expression // will not increase setting count, but will increase the number of verdicts // in the given origin. CacheVerdict(GURL("http://www.test.com/bar/index2.html"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::SAFE, 10 * 60, "test.com/bar", base::Time::Now()); - EXPECT_EQ(2U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - - // Now cache a UNFAMILIAR_LOGIN_PAGE verdict, stored verdict count for - // PASSWORD_REUSE_EVENT should be the same. - CacheVerdict(GURL("http://www.test.com/foobar/index3.html"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foobar", - base::Time::Now()); - EXPECT_EQ(2U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - EXPECT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); -} - -TEST_F(PasswordProtectionServiceTest, TestCacheUnfamiliarLoginVerdicts) { - ASSERT_EQ(0U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); - - // Assume each verdict has a TTL of 10 minutes. - // Cache a verdict for http://www.test.com/foo/index.html - CacheVerdict(GURL("http://www.test.com/foo/index.html"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foo", - base::Time::Now()); - - EXPECT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); - - // Cache another verdict with the same origin but different cache_expression - // will not increase setting count, but will increase the number of verdicts - // in the given origin. - CacheVerdict(GURL("http://www.test.com/bar/index2.html"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - LoginReputationClientResponse::SAFE, 10 * 60, "test.com/bar", - base::Time::Now()); - EXPECT_EQ(2U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); - - // Now cache a PASSWORD_REUSE_EVENT verdict, stored verdict count for - // UNFAMILIAR_LOGIN_PAGE should be the same. - CacheVerdict(GURL("http://www.test.com/foobar/index3.html"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, - LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foobar", - base::Time::Now()); - EXPECT_EQ(2U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); - EXPECT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); + EXPECT_EQ(2U, GetStoredVerdictCount()); } TEST_F(PasswordProtectionServiceTest, TestGetCachedVerdicts) { - ASSERT_EQ(0U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - ASSERT_EQ(0U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); - // Prepare 3 verdicts of the same origin with different cache expressions, - // one is expired, one is not, the other is of a different type. + ASSERT_EQ(0U, GetStoredVerdictCount()); + // Prepare 2 verdicts of the same origin with different cache expressions, + // one is expired, the other is not. base::Time now = base::Time::Now(); CacheVerdict(GURL("http://test.com/login.html"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::SAFE, 10 * 60, "test.com", now); CacheVerdict( GURL("http://test.com/def/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::PHISHING, 10 * 60, "test.com/def", base::Time::FromDoubleT(now.ToDoubleT() - 24.0 * 60.0 * 60.0)); // Yesterday, expired. - CacheVerdict(GURL("http://test.com/bar/login.html"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - LoginReputationClientResponse::PHISHING, 10 * 60, "test.com/bar", - now); - - ASSERT_EQ(2U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - ASSERT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); + ASSERT_EQ(2U, GetStoredVerdictCount()); // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL with unknown origin. LoginReputationClientResponse actual_verdict; - EXPECT_EQ( - LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, - password_protection_service_->GetCachedVerdict( - GURL("http://www.unknown.com/"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &actual_verdict)); + EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, + password_protection_service_->GetCachedVerdict( + GURL("http://www.unknown.com/"), &actual_verdict)); // Return SAFE if look up for a URL that matches "test.com" cache expression. - EXPECT_EQ( - LoginReputationClientResponse::SAFE, - password_protection_service_->GetCachedVerdict( - GURL("http://test.com/xyz/foo.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &actual_verdict)); + EXPECT_EQ(LoginReputationClientResponse::SAFE, + password_protection_service_->GetCachedVerdict( + GURL("http://test.com/xyz/foo.jsp"), &actual_verdict)); // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL whose variants match // test.com/def, but the corresponding verdict is expired. - EXPECT_EQ( - LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, - password_protection_service_->GetCachedVerdict( - GURL("http://test.com/def/ghi/index.html"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &actual_verdict)); + EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, + password_protection_service_->GetCachedVerdict( + GURL("http://test.com/def/ghi/index.html"), &actual_verdict)); } TEST_F(PasswordProtectionServiceTest, TestRemoveCachedVerdictOnURLsDeleted) { - ASSERT_EQ(0U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - ASSERT_EQ(0U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); + ASSERT_EQ(0U, GetStoredVerdictCount()); // Prepare 2 verdicts. One is for origin "http://foo.com", and the other is // for "http://bar.com". base::Time now = base::Time::Now(); CacheVerdict(GURL("http://foo.com/abc/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::LOW_REPUTATION, 10 * 60, "foo.com/abc", now); CacheVerdict(GURL("http://bar.com/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::PHISHING, 10 * 60, "bar.com", now); - ASSERT_EQ(2U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - - CacheVerdict(GURL("http://foo.com/abc/index.jsp"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - LoginReputationClientResponse::LOW_REPUTATION, 10 * 60, - "foo.com/abc", now); - CacheVerdict(GURL("http://bar.com/index.jsp"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - LoginReputationClientResponse::PHISHING, 10 * 60, "bar.com", - now); - ASSERT_EQ(2U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); + ASSERT_EQ(2U, GetStoredVerdictCount()); // Delete a bar.com URL. Corresponding content setting keyed on // origin "http://bar.com" should be removed, @@ -484,31 +390,17 @@ password_protection_service_->RemoveContentSettingsOnURLsDeleted( false /* all_history */, deleted_urls); - EXPECT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - EXPECT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); - + EXPECT_EQ(1U, GetStoredVerdictCount()); LoginReputationClientResponse actual_verdict; - EXPECT_EQ( - LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, - password_protection_service_->GetCachedVerdict( - GURL("http://bar.com"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &actual_verdict)); EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, password_protection_service_->GetCachedVerdict( - GURL("http://bar.com"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - &actual_verdict)); + GURL("http://bar.com"), &actual_verdict)); // If delete all history. All password protection content settings should be // gone. password_protection_service_->RemoveContentSettingsOnURLsDeleted( true /* all_history */, history::URLRows()); - EXPECT_EQ(0U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - EXPECT_EQ(0U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); + EXPECT_EQ(0U, GetStoredVerdictCount()); } TEST_F(PasswordProtectionServiceTest, VerifyCanGetReputationOfURL) { @@ -562,10 +454,8 @@ TEST_F(PasswordProtectionServiceTest, TestNoRequestSentIfVerdictAlreadyCached) { histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogramName, 0); - CacheVerdict(GURL(kTargetUrl), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - LoginReputationClientResponse::LOW_REPUTATION, 600, - GURL(kTargetUrl).host(), base::Time::Now()); + CacheVerdict(GURL(kTargetUrl), LoginReputationClientResponse::LOW_REPUTATION, + 600, GURL(kTargetUrl).host(), base::Time::Now()); InitializeAndStartPasswordOnFocusRequest(false /* match whitelist */, 10000 /* timeout in ms*/); base::RunLoop().RunUntilIdle(); @@ -672,87 +562,42 @@ } TEST_F(PasswordProtectionServiceTest, TestCleanUpExpiredVerdict) { - // Prepare 4 verdicts for PASSWORD_REUSE_EVENT: + ASSERT_EQ(0U, GetStoredVerdictCount()); + // Prepare 4 verdicts: // (1) "foo.com/abc" valid // (2) "foo.com/def" expired // (3) "bar.com/abc" expired // (4) "bar.com/def" expired base::Time now = base::Time::Now(); CacheVerdict(GURL("https://foo.com/abc/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::LOW_REPUTATION, 10 * 60, "foo.com/abc", now); CacheVerdict(GURL("https://foo.com/def/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::LOW_REPUTATION, 0, "foo.com/def", now); CacheVerdict(GURL("https://bar.com/abc/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::PHISHING, 0, "bar.com/abc", now); CacheVerdict(GURL("https://bar.com/def/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, LoginReputationClientResponse::PHISHING, 0, "bar.com/def", now); - ASSERT_EQ(4U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - - // Prepare 2 verdicts for UNFAMILIAR_LOGIN_PAGE: - // (1) "bar.com/def" valid - // (2) "bar.com/xyz" expired - CacheVerdict(GURL("https://bar.com/def/index.jsp"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - LoginReputationClientResponse::SAFE, 10 * 60, "bar.com/def", - now); - CacheVerdict(GURL("https://bar.com/xyz/index.jsp"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - LoginReputationClientResponse::PHISHING, 0, "bar.com/xyz", now); - ASSERT_EQ(2U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); + ASSERT_EQ(4U, GetStoredVerdictCount()); password_protection_service_->CleanUpExpiredVerdicts(); - ASSERT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::PASSWORD_REUSE_EVENT)); - ASSERT_EQ(1U, GetStoredVerdictCount( - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE)); + ASSERT_EQ(1U, GetStoredVerdictCount()); LoginReputationClientResponse actual_verdict; - // Has cached PASSWORD_REUSE_EVENT verdict for foo.com/abc. - EXPECT_EQ( - LoginReputationClientResponse::LOW_REPUTATION, - password_protection_service_->GetCachedVerdict( - GURL("https://foo.com/abc/test.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &actual_verdict)); - // No cached PASSWORD_REUSE_EVENT verdict for foo.com/def. - EXPECT_EQ( - LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, - password_protection_service_->GetCachedVerdict( - GURL("https://foo.com/def/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &actual_verdict)); - // No cached PASSWORD_REUSE_EVENT verdict for bar.com/abc. - EXPECT_EQ( - LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, - password_protection_service_->GetCachedVerdict( - GURL("https://bar.com/abc/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &actual_verdict)); - // No cached PASSWORD_REUSE_EVENT verdict for bar.com/def. - EXPECT_EQ( - LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, - password_protection_service_->GetCachedVerdict( - GURL("https://bar.com/def/index.jsp"), - LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &actual_verdict)); - - // Has cached UNFAMILIAR_LOGIN_PAGE verdict for bar.com/def. - EXPECT_EQ(LoginReputationClientResponse::SAFE, + // Has cached verdict for foo.com/abc. + EXPECT_EQ(LoginReputationClientResponse::LOW_REPUTATION, password_protection_service_->GetCachedVerdict( - GURL("https://bar.com/def/index.jsp"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - &actual_verdict)); - - // No cached UNFAMILIAR_LOGIN_PAGE verdict for bar.com/xyz. + GURL("https://foo.com/abc/test.jsp"), &actual_verdict)); + // No cached verdict for foo.com/def. EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, password_protection_service_->GetCachedVerdict( - GURL("https://bar.com/xyz/index.jsp"), - LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, - &actual_verdict)); + GURL("https://foo.com/def/index.jsp"), &actual_verdict)); + // Nothing in content setting for bar.com. + EXPECT_EQ(nullptr, content_setting_map_->GetWebsiteSetting( + GURL("https://bar.com"), GURL(), + CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, + std::string(), nullptr)); } TEST_F(PasswordProtectionServiceTest, VerifyPasswordOnFocusRequestProto) {
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc index bb9f136c..1b346e2 100644 --- a/components/sync/driver/sync_driver_switches.cc +++ b/components/sync/driver/sync_driver_switches.cc
@@ -40,6 +40,14 @@ const base::Feature kSyncUserEvents{"SyncUserEvents", base::FEATURE_DISABLED_BY_DEFAULT}; +// Gates registration for user language detection events. +const base::Feature kSyncUserLanguageDetectionEvents{ + "SyncUserLanguageDetectionEvents", base::FEATURE_DISABLED_BY_DEFAULT}; + +// Gates registration for user translation events. +const base::Feature kSyncUserTranslationEvents{ + "SyncUserTranslationEvents", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables USS implementation of Autocomplete datatype. const base::Feature kSyncUSSAutocomplete{"SyncUSSAutocomplete", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/sync/driver/sync_driver_switches.h b/components/sync/driver/sync_driver_switches.h index e4597fd5..bce16be 100644 --- a/components/sync/driver/sync_driver_switches.h +++ b/components/sync/driver/sync_driver_switches.h
@@ -21,6 +21,8 @@ extern const base::Feature kSyncClearDataOnPassphraseEncryption; extern const base::Feature kSyncUserEvents; +extern const base::Feature kSyncUserLanguageDetectionEvents; +extern const base::Feature kSyncUserTranslationEvents; extern const base::Feature kSyncUSSAutocomplete; extern const base::Feature kSyncUSSTypedURL; extern const base::Feature kSyncUSSDeviceInfo;
diff --git a/components/translate/core/common/language_detection_logging_helper.cc b/components/translate/core/common/language_detection_logging_helper.cc index e632bdfb..b98ae85 100644 --- a/components/translate/core/common/language_detection_logging_helper.cc +++ b/components/translate/core/common/language_detection_logging_helper.cc
@@ -14,13 +14,14 @@ namespace translate { std::unique_ptr<sync_pb::UserEventSpecifics> ConstructLanguageDetectionEvent( + const int64_t navigation_id, const LanguageDetectionDetails& details) { auto specifics = base::MakeUnique<sync_pb::UserEventSpecifics>(); specifics->set_event_time_usec(base::Time::Now().ToInternalValue()); // TODO(renjieliu): Revisit this field when the best way to identify // navigations is determined. - specifics->set_navigation_id(base::Time::Now().ToInternalValue()); + specifics->set_navigation_id(navigation_id); sync_pb::LanguageDetection lang_detection; auto* const lang = lang_detection.add_detected_languages(); @@ -33,4 +34,5 @@ *specifics->mutable_language_detection() = lang_detection; return specifics; } + } // namespace translate \ No newline at end of file
diff --git a/components/translate/core/common/language_detection_logging_helper.h b/components/translate/core/common/language_detection_logging_helper.h index d8f67bb..15ecaee5 100644 --- a/components/translate/core/common/language_detection_logging_helper.h +++ b/components/translate/core/common/language_detection_logging_helper.h
@@ -15,7 +15,10 @@ struct LanguageDetectionDetails; +// Construct language detection based on navigation_id and language detection +// details. std::unique_ptr<sync_pb::UserEventSpecifics> ConstructLanguageDetectionEvent( + int64_t navigation_id, const LanguageDetectionDetails& details); } // namespace translate
diff --git a/components/translate/core/common/language_detection_logging_helper_unittest.cc b/components/translate/core/common/language_detection_logging_helper_unittest.cc index 6dc27c0..c22a0ee0 100644 --- a/components/translate/core/common/language_detection_logging_helper_unittest.cc +++ b/components/translate/core/common/language_detection_logging_helper_unittest.cc
@@ -24,8 +24,11 @@ lang->set_language_code(details.cld_language); lang->set_is_reliable(details.is_cld_reliable); lang_detection.set_adopted_language_code(details.adopted_language); + const int64_t navigation_id = 1000000000000000LL; const std::unique_ptr<sync_pb::UserEventSpecifics> user_event = - ConstructLanguageDetectionEvent(details); + ConstructLanguageDetectionEvent(navigation_id, details); + // Expect the navigation id is correctly set. + EXPECT_EQ(user_event->navigation_id(), navigation_id); EXPECT_EQ(user_event->language_detection().SerializeAsString(), lang_detection.SerializeAsString()); } @@ -43,7 +46,9 @@ lang->set_language_code(details.cld_language); lang->set_is_reliable(details.is_cld_reliable); const std::unique_ptr<sync_pb::UserEventSpecifics> user_event = - ConstructLanguageDetectionEvent(details); + ConstructLanguageDetectionEvent(100, details); + // Expect the navigation id is correctly set. + EXPECT_EQ(user_event->navigation_id(), 100); EXPECT_EQ(user_event->language_detection().SerializeAsString(), lang_detection.SerializeAsString()); }
diff --git a/components/ukm/public/interfaces/ukm_interface.mojom b/components/ukm/public/interfaces/ukm_interface.mojom index 0625916..4daeb839 100644 --- a/components/ukm/public/interfaces/ukm_interface.mojom +++ b/components/ukm/public/interfaces/ukm_interface.mojom
@@ -19,4 +19,5 @@ interface UkmRecorderInterface { AddEntry(UkmEntry entry); + UpdateSourceURL(int64 source_id, string url); };
diff --git a/components/ukm/public/mojo_ukm_recorder.cc b/components/ukm/public/mojo_ukm_recorder.cc index 8d5af8f9..d62b1464 100644 --- a/components/ukm/public/mojo_ukm_recorder.cc +++ b/components/ukm/public/mojo_ukm_recorder.cc
@@ -13,8 +13,7 @@ MojoUkmRecorder::~MojoUkmRecorder() = default; void MojoUkmRecorder::UpdateSourceURL(SourceId source_id, const GURL& url) { - DCHECK(false); - // Not implemented yet, currently a no-op. + interface_->UpdateSourceURL(source_id, url.spec()); } void MojoUkmRecorder::AddEntry(mojom::UkmEntryPtr entry) {
diff --git a/components/ukm/ukm_interface.cc b/components/ukm/ukm_interface.cc index d89f613..99decf0 100644 --- a/components/ukm/ukm_interface.cc +++ b/components/ukm/ukm_interface.cc
@@ -4,14 +4,30 @@ #include "components/ukm/ukm_interface.h" +#include "base/atomic_sequence_num.h" #include "base/memory/ptr_util.h" #include "components/ukm/public/ukm_recorder.h" #include "mojo/public/cpp/bindings/strong_binding.h" +#include "url/gurl.h" namespace ukm { -UkmInterface::UkmInterface(UkmRecorder* ukm_recorder) - : ukm_recorder_(ukm_recorder) {} +namespace { + +// Map source ids from different instances into unique namespaces, so that +// clients can create thier own IDs without having them collide. +// This won't be necessary once we switch to using CoordinationUnitIDs. +int64_t ConvertSourceId(int64_t source_id, int64_t instance_id) { + const int64_t low_bits = (INT64_C(1) << 32) - 1; + // Neither ID should get large enough to cause an issue, but explicitly + // discard down to 32 bits anyway. + return ((instance_id & low_bits) << 32) | (source_id & low_bits); +} + +} // namespace + +UkmInterface::UkmInterface(UkmRecorder* ukm_recorder, int64_t instance_id) + : ukm_recorder_(ukm_recorder), instance_id_(instance_id) {} UkmInterface::~UkmInterface() = default; @@ -19,12 +35,21 @@ void UkmInterface::Create(UkmRecorder* ukm_recorder, const service_manager::BindSourceInfo& source_info, mojom::UkmRecorderInterfaceRequest request) { - mojo::MakeStrongBinding(base::MakeUnique<UkmInterface>(ukm_recorder), - std::move(request)); + static base::StaticAtomicSequenceNumber seq; + mojo::MakeStrongBinding( + base::MakeUnique<UkmInterface>(ukm_recorder, + static_cast<int64_t>(seq.GetNext()) + 1), + std::move(request)); } void UkmInterface::AddEntry(mojom::UkmEntryPtr ukm_entry) { + ukm_entry->source_id = ConvertSourceId(instance_id_, ukm_entry->source_id); ukm_recorder_->AddEntry(std::move(ukm_entry)); } +void UkmInterface::UpdateSourceURL(int64_t source_id, const std::string& url) { + ukm_recorder_->UpdateSourceURL(ConvertSourceId(instance_id_, source_id), + GURL(url)); +} + } // namespace ukm
diff --git a/components/ukm/ukm_interface.h b/components/ukm/ukm_interface.h index 2f536fc..a3047738 100644 --- a/components/ukm/ukm_interface.h +++ b/components/ukm/ukm_interface.h
@@ -17,7 +17,7 @@ class UkmInterface : public mojom::UkmRecorderInterface { public: - explicit UkmInterface(UkmRecorder* ukm_recorder); + UkmInterface(UkmRecorder* ukm_recorder, int64_t instance_id); ~UkmInterface() override; static void Create(UkmRecorder* ukm_recorder, @@ -27,8 +27,10 @@ private: // ukm::mojom::UkmRecorderInterface: void AddEntry(mojom::UkmEntryPtr entry) override; + void UpdateSourceURL(int64_t source_id, const std::string& url) override; UkmRecorder* ukm_recorder_; + int64_t instance_id_; DISALLOW_COPY_AND_ASSIGN(UkmInterface); };
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 0c0fcbbb..0bc69e1 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -110,6 +110,7 @@ "//services/catalog:constants", "//services/catalog/public/cpp", "//services/catalog/public/interfaces:constants", + "//services/data_decoder/public/cpp", "//services/data_decoder/public/interfaces", "//services/device:lib", "//services/device/public/interfaces", @@ -1071,6 +1072,8 @@ "payments/payment_app_database.h", "payments/payment_app_provider_impl.cc", "payments/payment_app_provider_impl.h", + "payments/payment_instrument_icon_fetcher.cc", + "payments/payment_instrument_icon_fetcher.h", "payments/payment_manager.cc", "payments/payment_manager.h", "permissions/permission_service_context.cc",
diff --git a/content/browser/DEPS b/content/browser/DEPS index 530f0c0..437c816 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS
@@ -22,6 +22,7 @@ "+content/app/strings/grit", # For generated headers "+content/public/browser", + "+device/base/synchronization", "+device/gamepad", # For gamepad API "+device/generic_sensor", # For sensors service. "+device/geolocation",
diff --git a/content/browser/generic_sensor_browsertest.cc b/content/browser/generic_sensor_browsertest.cc index 66375fe..8b3b9ee 100644 --- a/content/browser/generic_sensor_browsertest.cc +++ b/content/browser/generic_sensor_browsertest.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/bind.h" #include "base/command_line.h" #include "base/macros.h" -#include "base/memory/singleton.h" #include "base/synchronization/waitable_event.h" #include "base/threading/platform_thread.h" #include "build/build_config.h" @@ -17,75 +17,150 @@ #include "content/public/test/test_utils.h" #include "content/shell/browser/shell.h" #include "content/shell/browser/shell_javascript_dialog_manager.h" -#include "device/generic_sensor/platform_sensor.h" -#include "device/generic_sensor/platform_sensor_provider.h" -#include "device/generic_sensor/sensor_provider_impl.h" +#include "device/base/synchronization/one_writer_seqlock.h" +#include "device/generic_sensor/public/cpp/platform_sensor_configuration.h" +#include "device/generic_sensor/public/cpp/sensor_reading.h" +#include "device/generic_sensor/public/interfaces/sensor.mojom.h" +#include "device/generic_sensor/public/interfaces/sensor_provider.mojom.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/system/buffer.h" +#include "services/device/public/interfaces/constants.mojom.h" +#include "services/service_manager/public/cpp/service_context.h" namespace content { namespace { -class FakeAmbientLightSensor : public device::PlatformSensor { +class FakeAmbientLightSensor : public device::mojom::Sensor { public: - FakeAmbientLightSensor(mojo::ScopedSharedBufferMapping mapping, - device::PlatformSensorProvider* provider) - : PlatformSensor(device::mojom::SensorType::AMBIENT_LIGHT, - std::move(mapping), - provider) {} + FakeAmbientLightSensor() { + shared_buffer_handle_ = mojo::SharedBufferHandle::Create( + sizeof(device::SensorReadingSharedBuffer) * + static_cast<uint64_t>(device::mojom::SensorType::LAST)); + } - device::mojom::ReportingMode GetReportingMode() override { + ~FakeAmbientLightSensor() override = default; + + // device::mojom::Sensor implemenation: + void AddConfiguration( + const device::PlatformSensorConfiguration& configuration, + AddConfigurationCallback callback) override { + std::move(callback).Run(true); + SensorReadingChanged(); + } + + void GetDefaultConfiguration( + GetDefaultConfigurationCallback callback) override { + std::move(callback).Run(GetDefaultConfiguration()); + } + + void RemoveConfiguration( + const device::PlatformSensorConfiguration& configuration, + RemoveConfigurationCallback callback) override { + std::move(callback).Run(true); + } + + void Suspend() override {} + void Resume() override {} + + device::PlatformSensorConfiguration GetDefaultConfiguration() { + return device::PlatformSensorConfiguration(60 /* frequency */); + } + + device::mojom::ReportingMode GetReportingMode() { return device::mojom::ReportingMode::ON_CHANGE; } - bool StartSensor( - const device::PlatformSensorConfiguration& configuration) override { + double GetMaximumSupportedFrequency() { return 60.0; } + double GetMinimumSupportedFrequency() { return 1.0; } + + device::mojom::SensorClientRequest GetClient() { + return mojo::MakeRequest(&client_); + } + + mojo::ScopedSharedBufferHandle GetSharedBufferHandle() { + return shared_buffer_handle_->Clone( + mojo::SharedBufferHandle::AccessMode::READ_ONLY); + } + + uint64_t GetBufferOffset() { + return device::SensorReadingSharedBuffer::GetOffset( + device::mojom::SensorType::AMBIENT_LIGHT); + } + + void SensorReadingChanged() { + if (!shared_buffer_handle_.is_valid()) + return; + + mojo::ScopedSharedBufferMapping shared_buffer = + shared_buffer_handle_->MapAtOffset( + device::mojom::SensorInitParams::kReadBufferSizeForTests, + GetBufferOffset()); + device::SensorReading reading; reading.timestamp = (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(); reading.values[0] = 50; - UpdateSensorReading(reading, true); - return true; + + device::SensorReadingSharedBuffer* buffer = + static_cast<device::SensorReadingSharedBuffer*>(shared_buffer.get()); + auto& seqlock = buffer->seqlock.value(); + seqlock.WriteBegin(); + buffer->reading = reading; + seqlock.WriteEnd(); + + if (client_) + client_->SensorReadingChanged(); } - void StopSensor() override {} + private: + mojo::ScopedSharedBufferHandle shared_buffer_handle_; + device::mojom::SensorClientPtr client_; - protected: - ~FakeAmbientLightSensor() override = default; - bool CheckSensorConfiguration( - const device::PlatformSensorConfiguration& configuration) override { - return true; - } - device::PlatformSensorConfiguration GetDefaultConfiguration() override { - return device::PlatformSensorConfiguration(60 /* frequency */); - } + DISALLOW_COPY_AND_ASSIGN(FakeAmbientLightSensor); }; -class FakeSensorProvider : public device::PlatformSensorProvider { +class FakeSensorProvider : public device::mojom::SensorProvider { public: - static FakeSensorProvider* GetInstance() { - return base::Singleton<FakeSensorProvider, base::LeakySingletonTraits< - FakeSensorProvider>>::get(); - } - FakeSensorProvider() = default; + FakeSensorProvider() : binding_(this) {} ~FakeSensorProvider() override = default; - protected: - void CreateSensorInternal(device::mojom::SensorType type, - mojo::ScopedSharedBufferMapping mapping, - const CreateSensorCallback& callback) override { - // Create Sensors here. + void Bind(const service_manager::BindSourceInfo& source_info, + const std::string& interface_name, + mojo::ScopedMessagePipeHandle handle) { + DCHECK(!binding_.is_bound()); + binding_.Bind(device::mojom::SensorProviderRequest(std::move(handle))); + } + + // device::mojom::sensorProvider implementation. + void GetSensor(device::mojom::SensorType type, + device::mojom::SensorRequest sensor_request, + GetSensorCallback callback) override { switch (type) { case device::mojom::SensorType::AMBIENT_LIGHT: { - scoped_refptr<device::PlatformSensor> sensor = - new FakeAmbientLightSensor(std::move(mapping), this); - callback.Run(std::move(sensor)); + auto sensor = base::MakeUnique<FakeAmbientLightSensor>(); + + auto init_params = device::mojom::SensorInitParams::New(); + init_params->memory = sensor->GetSharedBufferHandle(); + init_params->buffer_offset = sensor->GetBufferOffset(); + init_params->default_configuration = sensor->GetDefaultConfiguration(); + init_params->maximum_frequency = sensor->GetMaximumSupportedFrequency(); + init_params->minimum_frequency = sensor->GetMinimumSupportedFrequency(); + + std::move(callback).Run(std::move(init_params), sensor->GetClient()); + mojo::MakeStrongBinding(std::move(sensor), std::move(sensor_request)); break; } default: NOTIMPLEMENTED(); - callback.Run(nullptr); } } + + private: + mojo::Binding<device::mojom::SensorProvider> binding_; + + DISALLOW_COPY_AND_ASSIGN(FakeSensorProvider); }; class GenericSensorBrowserTest : public ContentBrowserTest { @@ -94,31 +169,37 @@ : io_loop_finished_event_( base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED) { - // TODO(darktears): remove when the GenericSensor feature goes stable. base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); cmd_line->AppendSwitchASCII(switches::kEnableFeatures, "GenericSensor"); } void SetUpOnMainThread() override { + fake_sensor_provider_ = base::MakeUnique<FakeSensorProvider>(); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&GenericSensorBrowserTest::SetUpOnIOThread, + base::Bind(&GenericSensorBrowserTest::SetBinderOnIOThread, base::Unretained(this))); + io_loop_finished_event_.Wait(); } - void SetUpOnIOThread() { - device::PlatformSensorProvider::SetProviderForTesting( - FakeSensorProvider::GetInstance()); + void SetBinderOnIOThread() { + // Because Device Service also runs in this process(browser process), here + // we can directly set our binder to intercept interface requests against + // it. + service_manager::ServiceContext::SetGlobalBinderForTesting( + device::mojom::kServiceName, device::mojom::SensorProvider::Name_, + base::Bind(&FakeSensorProvider::Bind, + base::Unretained(fake_sensor_provider_.get()))); + io_loop_finished_event_.Signal(); } - void TearDown() override { - device::PlatformSensorProvider::SetProviderForTesting(nullptr); - } - - public: + private: base::WaitableEvent io_loop_finished_event_; + std::unique_ptr<FakeSensorProvider> fake_sensor_provider_; + + DISALLOW_COPY_AND_ASSIGN(GenericSensorBrowserTest); }; IN_PROC_BROWSER_TEST_F(GenericSensorBrowserTest, AmbientLightSensorTest) {
diff --git a/content/browser/payments/payment_app.proto b/content/browser/payments/payment_app.proto index c2eadb6..78a0a23 100644 --- a/content/browser/payments/payment_app.proto +++ b/content/browser/payments/payment_app.proto
@@ -13,6 +13,10 @@ optional string key = 2; } +message StoredPaymentInstrumentImageObject { + optional string src = 1; +} + message StoredPaymentInstrumentProto { optional int64 registration_id = 1; optional string instrument_key = 2; @@ -20,4 +24,6 @@ optional string name = 4; repeated string enabled_methods = 5; optional string stringified_capabilities = 6; + repeated StoredPaymentInstrumentImageObject icons = 7; + optional string decoded_instrument_icon = 8; }
diff --git a/content/browser/payments/payment_app_database.cc b/content/browser/payments/payment_app_database.cc index 5c58b9b..c1c1bf8 100644 --- a/content/browser/payments/payment_app_database.cc +++ b/content/browser/payments/payment_app_database.cc
@@ -7,6 +7,7 @@ #include <map> #include <utility> +#include "base/base64.h" #include "base/bind.h" #include "base/memory/ptr_util.h" #include "base/optional.h" @@ -16,6 +17,8 @@ #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/public/browser/browser_thread.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/image/image.h" namespace content { namespace { @@ -58,6 +61,10 @@ PaymentInstrumentPtr instrument = PaymentInstrument::New(); instrument->name = instrument_proto.name(); + for (const auto& icon : instrument_proto.icons()) { + instrument->icons.emplace_back( + payments::mojom::ImageObject::New(GURL(icon.src()))); + } for (const auto& method : instrument_proto.enabled_methods()) instrument->enabled_methods.push_back(method); instrument->stringified_capabilities = @@ -78,6 +85,18 @@ instrument->instrument_key = instrument_proto.instrument_key(); instrument->origin = GURL(instrument_proto.origin()); instrument->name = instrument_proto.name(); + + if (!instrument_proto.decoded_instrument_icon().empty()) { + std::string icon_raw_data; + base::Base64Decode(instrument_proto.decoded_instrument_icon(), + &icon_raw_data); + // Note that the icon has been decoded to PNG raw data regardless of the + // original icon format that was downloaded. + gfx::Image icon_image = gfx::Image::CreateFrom1xPNGBytes( + reinterpret_cast<const unsigned char*>(icon_raw_data.data()), + icon_raw_data.size()); + instrument->icon = base::MakeUnique<SkBitmap>(icon_image.AsBitmap()); + } for (const auto& method : instrument_proto.enabled_methods()) instrument->enabled_methods.push_back(method); @@ -166,12 +185,46 @@ WritePaymentInstrumentCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (instrument->icons.size() > 0) { + instrument_icon_fetcher_ = + base::MakeRefCounted<PaymentInstrumentIconFetcher>(); + instrument_icon_fetcher_->Start( + instrument->icons, service_worker_context_, + base::Bind(&PaymentAppDatabase::DidFetchedPaymentInstrumentIcon, + weak_ptr_factory_.GetWeakPtr(), scope, instrument_key, + base::Passed(std::move(instrument)), + base::Passed(std::move(callback)))); + } else { + service_worker_context_->FindReadyRegistrationForPattern( + scope, + base::Bind( + &PaymentAppDatabase::DidFindRegistrationToWritePaymentInstrument, + weak_ptr_factory_.GetWeakPtr(), instrument_key, + base::Passed(std::move(instrument)), std::string(), + base::Passed(std::move(callback)))); + } +} + +void PaymentAppDatabase::DidFetchedPaymentInstrumentIcon( + const GURL& scope, + const std::string& instrument_key, + payments::mojom::PaymentInstrumentPtr instrument, + WritePaymentInstrumentCallback callback, + const std::string& icon) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + instrument_icon_fetcher_ = nullptr; + if (icon.empty()) { + std::move(callback).Run(PaymentHandlerStatus::FETCH_INSTRUMENT_ICON_FAILED); + return; + } + service_worker_context_->FindReadyRegistrationForPattern( scope, base::Bind( &PaymentAppDatabase::DidFindRegistrationToWritePaymentInstrument, weak_ptr_factory_.GetWeakPtr(), instrument_key, - base::Passed(std::move(instrument)), + base::Passed(std::move(instrument)), icon, base::Passed(std::move(callback)))); } @@ -371,6 +424,7 @@ void PaymentAppDatabase::DidFindRegistrationToWritePaymentInstrument( const std::string& instrument_key, PaymentInstrumentPtr instrument, + const std::string& decoded_instrument_icon, WritePaymentInstrumentCallback callback, ServiceWorkerStatusCode status, scoped_refptr<ServiceWorkerRegistration> registration) { @@ -381,6 +435,7 @@ } StoredPaymentInstrumentProto instrument_proto; + instrument_proto.set_decoded_instrument_icon(decoded_instrument_icon); instrument_proto.set_registration_id(registration->id()); instrument_proto.set_instrument_key(instrument_key); instrument_proto.set_origin(registration->pattern().GetOrigin().spec()); @@ -388,6 +443,11 @@ for (const auto& method : instrument->enabled_methods) { instrument_proto.add_enabled_methods(method); } + for (const auto& image_object : instrument->icons) { + StoredPaymentInstrumentImageObject* image_object_proto = + instrument_proto.add_icons(); + image_object_proto->set_src(image_object->src.spec()); + } instrument_proto.set_stringified_capabilities( instrument->stringified_capabilities);
diff --git a/content/browser/payments/payment_app_database.h b/content/browser/payments/payment_app_database.h index 0016850..230db47a 100644 --- a/content/browser/payments/payment_app_database.h +++ b/content/browser/payments/payment_app_database.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "components/payments/mojom/payment_app.mojom.h" +#include "content/browser/payments/payment_instrument_icon_fetcher.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/common/content_export.h" @@ -122,12 +123,21 @@ void DidFindRegistrationToWritePaymentInstrument( const std::string& instrument_key, payments::mojom::PaymentInstrumentPtr instrument, + const std::string& decoded_instrument_icon, WritePaymentInstrumentCallback callback, ServiceWorkerStatusCode status, scoped_refptr<ServiceWorkerRegistration> registration); void DidWritePaymentInstrument(WritePaymentInstrumentCallback callback, ServiceWorkerStatusCode status); + // PaymentInstrumentIconFetcherCallback. + void DidFetchedPaymentInstrumentIcon( + const GURL& scope, + const std::string& instrument_key, + payments::mojom::PaymentInstrumentPtr instrument, + WritePaymentInstrumentCallback callback, + const std::string& icon); + // ClearPaymentInstruments callbacks void DidFindRegistrationToClearPaymentInstruments( const GURL& scope, @@ -142,6 +152,7 @@ void DidClearPaymentInstruments(ClearPaymentInstrumentsCallback callback, ServiceWorkerStatusCode status); + scoped_refptr<PaymentInstrumentIconFetcher> instrument_icon_fetcher_; scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_; base::WeakPtrFactory<PaymentAppDatabase> weak_ptr_factory_;
diff --git a/content/browser/payments/payment_instrument_icon_fetcher.cc b/content/browser/payments/payment_instrument_icon_fetcher.cc new file mode 100644 index 0000000..a4ccdd97 --- /dev/null +++ b/content/browser/payments/payment_instrument_icon_fetcher.cc
@@ -0,0 +1,163 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/payments/payment_instrument_icon_fetcher.h" + +#include "base/base64.h" +#include "base/bind_helpers.h" +#include "content/browser/storage_partition_impl.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/common/service_manager_connection.h" +#include "net/base/load_flags.h" +#include "net/http/http_status_code.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/data_decoder/public/cpp/decode_image.h" +#include "services/service_manager/public/cpp/connector.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/image/image.h" + +namespace content { + +namespace { + +net::NetworkTrafficAnnotationTag g_traffic_annotation = + net::DefineNetworkTrafficAnnotation("payment_instrument_icon_fetcher", R"( + semantics { + sender: "Web Payments" + description: + "Chromium downloads payment instrument icons when registering + payment instruments." + trigger: + "When user navigates to a website to register web payment apps." + data: + "URL of the required icon to fetch. No user information is sent." + destination: WEBSITE + } + policy { + cookies_allowed: false + setting: + "This feature cannot be disabled in settings. Users can refuse + to install web payment apps." + policy_exception_justification: "Not implemented." + })"); + +} // namespace + +PaymentInstrumentIconFetcher::PaymentInstrumentIconFetcher() + : checking_image_object_index_(0) {} +PaymentInstrumentIconFetcher::~PaymentInstrumentIconFetcher() {} + +void PaymentInstrumentIconFetcher::Start( + const std::vector<payments::mojom::ImageObjectPtr>& image_objects, + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, + PaymentInstrumentIconFetcherCallback callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + for (const auto& obj : image_objects) { + image_objects_.emplace_back(payments::mojom::ImageObject::New(obj->src)); + } + DCHECK_GT(image_objects_.size(), 0U); + + callback_ = std::move(callback); + + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::BindOnce(&PaymentInstrumentIconFetcher::StartFromUIThread, this, + std::move(service_worker_context))); +} + +void PaymentInstrumentIconFetcher::StartFromUIThread( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + url_request_context_getter_ = + service_worker_context->storage_partition()->GetURLRequestContext(); + if (!url_request_context_getter_) { + PostCallbackToIOThread(std::string()); + return; + } + + FetchIcon(); +} + +void PaymentInstrumentIconFetcher::FetchIcon() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (checking_image_object_index_ >= image_objects_.size()) { + PostCallbackToIOThread(std::string()); + return; + } + + GURL* icon_src_url = &(image_objects_[checking_image_object_index_]->src); + if (!icon_src_url->is_valid()) { + checking_image_object_index_++; + FetchIcon(); + return; + } + + fetcher_ = net::URLFetcher::Create(*icon_src_url, net::URLFetcher::GET, this, + g_traffic_annotation); + fetcher_->SetRequestContext(url_request_context_getter_.get()); + fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | + net::LOAD_DO_NOT_SAVE_COOKIES); + fetcher_->SetStopOnRedirect(true); + fetcher_->Start(); +} + +void PaymentInstrumentIconFetcher::OnURLFetchComplete( + const net::URLFetcher* source) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + DCHECK_EQ(fetcher_.get(), source); + std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_); + + std::string data; + if (!(source->GetStatus().is_success() && + source->GetResponseCode() == net::HTTP_OK && + source->GetResponseAsString(&data))) { + checking_image_object_index_++; + FetchIcon(); + return; + } + + service_manager::mojom::ConnectorRequest connector_request; + std::unique_ptr<service_manager::Connector> connector = + service_manager::Connector::Create(&connector_request); + content::ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->BindConnectorRequest(std::move(connector_request)); + + std::vector<uint8_t> image_data(data.begin(), data.end()); + data_decoder::DecodeImage( + connector.get(), image_data, data_decoder::mojom::ImageCodec::DEFAULT, + false, data_decoder::kDefaultMaxSizeInBytes, gfx::Size(), + base::Bind(&PaymentInstrumentIconFetcher::DecodeImageCallback, this)); +} + +void PaymentInstrumentIconFetcher::DecodeImageCallback(const SkBitmap& bitmap) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (bitmap.drawsNothing()) { + checking_image_object_index_++; + FetchIcon(); + return; + } + + gfx::Image decoded_image = gfx::Image::CreateFrom1xBitmap(bitmap); + scoped_refptr<base::RefCountedMemory> raw_data = decoded_image.As1xPNGBytes(); + std::string base_64; + base::Base64Encode( + base::StringPiece(raw_data->front_as<char>(), raw_data->size()), + &base_64); + + PostCallbackToIOThread(base_64); +} + +void PaymentInstrumentIconFetcher::PostCallbackToIOThread( + const std::string& decoded_data) { + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::BindOnce(std::move(callback_), decoded_data)); +} + +} // namespace content
diff --git a/content/browser/payments/payment_instrument_icon_fetcher.h b/content/browser/payments/payment_instrument_icon_fetcher.h new file mode 100644 index 0000000..a4fc3958 --- /dev/null +++ b/content/browser/payments/payment_instrument_icon_fetcher.h
@@ -0,0 +1,76 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_PAYMENTS_PAYMENT_INSTRUMENT_ICON_FETCHER_H_ +#define CONTENT_BROWSER_PAYMENTS_PAYMENT_INSTRUMENT_ICON_FETCHER_H_ + +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "components/payments/mojom/payment_app.mojom.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "net/url_request/url_fetcher.h" +#include "net/url_request/url_fetcher_delegate.h" +#include "net/url_request/url_request_context_getter.h" +#include "third_party/skia/include/core/SkBitmap.h" + +namespace content { + +class PaymentInstrumentIconFetcher + : public base::RefCountedThreadSafe<PaymentInstrumentIconFetcher>, + private net::URLFetcherDelegate { + public: + using PaymentInstrumentIconFetcherCallback = + base::OnceCallback<void(const std::string&)>; + + PaymentInstrumentIconFetcher(); + + // Starts fetching and decoding payment instrument icon from online. The + // result will be send back through |callback|. + // TODO(gogerald): Right now, we return the first fetchable and decodable icon + // with smallest available size. We may add more logic to choose appropriate + // icon according to icon size and our usage. + void Start(const std::vector<payments::mojom::ImageObjectPtr>& image_objects, + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, + PaymentInstrumentIconFetcherCallback callback); + + private: + friend class base::RefCountedThreadSafe<PaymentInstrumentIconFetcher>; + ~PaymentInstrumentIconFetcher() override; + + void StartFromUIThread( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context); + void PostCallbackToIOThread(const std::string& decoded_data); + + // data_decoder::mojom::ImageDecoder::DecodeImageCallback. + void DecodeImageCallback(const SkBitmap& bitmap); + + // Override net::URLFetcherDelegate. + void OnURLFetchComplete(const net::URLFetcher* source) override; + + void FetchIcon(); + + // Declared set of image objects of the payment instrument. + std::vector<payments::mojom::ImageObjectPtr> image_objects_; + + // The index of the currently checking image object in image_objects_. + size_t checking_image_object_index_; + + // The callback to notify after complete. + PaymentInstrumentIconFetcherCallback callback_; + + // The url request context getter for fetching icon from online. + scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; + + // The url fetcher to fetch raw icon from online. + std::unique_ptr<net::URLFetcher> fetcher_; + + DISALLOW_COPY_AND_ASSIGN(PaymentInstrumentIconFetcher); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_PAYMENTS_PAYMENT_INSTRUMENT_ICON_FETCHER_H_ \ No newline at end of file
diff --git a/content/public/browser/stored_payment_instrument.h b/content/public/browser/stored_payment_instrument.h index 858e2c5..5c0f64d 100644 --- a/content/public/browser/stored_payment_instrument.h +++ b/content/public/browser/stored_payment_instrument.h
@@ -10,6 +10,7 @@ #include <vector> #include "content/common/content_export.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "url/gurl.h" namespace content { @@ -32,6 +33,9 @@ // Label for this payment instrument. std::string name; + // Decoded icon for this payment instrument. + std::unique_ptr<SkBitmap> icon; + // A list of one or more payment method identifiers of the payment methods // supported by this payment instrument. std::vector<std::string> enabled_methods;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 9837f8b0..063ca757 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -4064,11 +4064,8 @@ if (request.GetPreviewsState() != WebURLRequest::kPreviewsUnspecified) return request.GetPreviewsState() & WebURLRequest::kClientLoFiOn; - if (!(previews_state_ & CLIENT_LOFI_ON)) + if (!IsClientLoFiActiveForFrame()) return false; - if (previews_state_ & (PREVIEWS_OFF | PREVIEWS_NO_TRANSFORM)) { - return false; - } // Even if this frame is using Server Lo-Fi, https:// images won't be handled // by Server Lo-Fi since their requests won't be sent to the Data Saver proxy, @@ -4078,6 +4075,15 @@ return true; } +bool RenderFrameImpl::IsClientLoFiActiveForFrame() { + if (!(previews_state_ & CLIENT_LOFI_ON)) + return false; + if (previews_state_ & (PREVIEWS_OFF | PREVIEWS_NO_TRANSFORM)) { + return false; + } + return true; +} + void RenderFrameImpl::AbortClientNavigation() { Send(new FrameHostMsg_AbortNavigation(routing_id_)); }
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index f9efacf6..d64f3ce 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -584,6 +584,7 @@ void DidChangeThemeColor() override; void DispatchLoad() override; blink::WebEffectiveConnectionType GetEffectiveConnectionType() override; + bool IsClientLoFiActiveForFrame() override; bool ShouldUseClientLoFiForRequest(const blink::WebURLRequest&) override; void AbortClientNavigation() override; void DidChangeSelection(bool is_empty_selection) override;
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc index deff2df1..b7d0598 100644 --- a/content/renderer/render_frame_impl_browsertest.cc +++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -488,6 +488,38 @@ } } +TEST_F(RenderFrameImplTest, IsClientLoFiActiveForFrame) { + const struct { + PreviewsState frame_previews_state; + bool expected_is_client_lo_fi_active_for_frame; + } tests[] = { + // With no previews enabled for the frame, no previews should be + // activated. + {PREVIEWS_UNSPECIFIED, false}, + + // Server Lo-Fi should not make Client Lo-Fi active. + {SERVER_LOFI_ON, false}, + + // PREVIEWS_NO_TRANSFORM and PREVIEWS_OFF should + // take precedence over Client Lo-Fi. + {CLIENT_LOFI_ON | PREVIEWS_NO_TRANSFORM, false}, + {CLIENT_LOFI_ON | PREVIEWS_OFF, false}, + + // Otherwise, if Client Lo-Fi is enabled on its own or with + // SERVER_LOFI_ON, then it is active for the frame. + {CLIENT_LOFI_ON, true}, + {CLIENT_LOFI_ON | SERVER_LOFI_ON, true}, + }; + + for (const auto& test : tests) { + SetPreviewsState(frame(), test.frame_previews_state); + + EXPECT_EQ(test.expected_is_client_lo_fi_active_for_frame, + frame()->IsClientLoFiActiveForFrame()) + << (&test - tests); + } +} + TEST_F(RenderFrameImplTest, ShouldUseClientLoFiForRequest) { const struct { PreviewsState frame_previews_state;
diff --git a/extensions/common/api/bluetooth_low_energy.idl b/extensions/common/api/bluetooth_low_energy.idl index b35cd98..f0641f57 100644 --- a/extensions/common/api/bluetooth_low_energy.idl +++ b/extensions/common/api/bluetooth_low_energy.idl
@@ -254,6 +254,12 @@ // Get all the GATT services that were discovered on the remote device with // the given device address. + // + // <em>Note:</em> If service discovery is not yet complete on the device, + // this API will return a subset (possibly empty) of services. A work around + // is to add a time based delay and/or call repeatedly until the expected + // number of services is returned. + // // |deviceAddress|: The Bluetooth address of the remote device whose GATT // services should be returned. // |callback|: Called with the list of requested Service objects.
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc index beba5c0..abbf784 100644 --- a/gpu/command_buffer/service/context_group.cc +++ b/gpu/command_buffer/service/context_group.cc
@@ -16,7 +16,6 @@ #include "gpu/command_buffer/service/framebuffer_manager.h" #include "gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h" #include "gpu/command_buffer/service/gpu_preferences.h" -#include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/path_manager.h" #include "gpu/command_buffer/service/program_manager.h" #include "gpu/command_buffer/service/progress_reporter.h" @@ -62,11 +61,10 @@ ContextGroup::ContextGroup( const GpuPreferences& gpu_preferences, - const scoped_refptr<MailboxManager>& mailbox_manager, + MailboxManager* mailbox_manager, const scoped_refptr<MemoryTracker>& memory_tracker, - const scoped_refptr<ShaderTranslatorCache>& shader_translator_cache, - const scoped_refptr<FramebufferCompletenessCache>& - framebuffer_completeness_cache, + ShaderTranslatorCache* shader_translator_cache, + FramebufferCompletenessCache* framebuffer_completeness_cache, const scoped_refptr<FeatureInfo>& feature_info, bool bind_generates_resource, ImageManager* image_manager, @@ -118,8 +116,7 @@ discardable_manager_(discardable_manager) { DCHECK(discardable_manager); DCHECK(feature_info_); - if (!mailbox_manager_.get()) - mailbox_manager_ = new MailboxManagerImpl; + DCHECK(mailbox_manager_); transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(memory_tracker_.get()); }
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h index 3f9073e..98d864d5 100644 --- a/gpu/command_buffer/service/context_group.h +++ b/gpu/command_buffer/service/context_group.h
@@ -57,20 +57,18 @@ // resources. class GPU_EXPORT ContextGroup : public base::RefCounted<ContextGroup> { public: - ContextGroup( - const GpuPreferences& gpu_preferences, - const scoped_refptr<MailboxManager>& mailbox_manager, - const scoped_refptr<MemoryTracker>& memory_tracker, - const scoped_refptr<ShaderTranslatorCache>& shader_translator_cache, - const scoped_refptr<FramebufferCompletenessCache>& - framebuffer_completeness_cache, - const scoped_refptr<FeatureInfo>& feature_info, - bool bind_generates_resource, - ImageManager* image_manager, - gpu::ImageFactory* image_factory, - ProgressReporter* progress_reporter, - const GpuFeatureInfo& gpu_feature_info, - ServiceDiscardableManager* discardable_manager); + ContextGroup(const GpuPreferences& gpu_preferences, + MailboxManager* mailbox_manager, + const scoped_refptr<MemoryTracker>& memory_tracker, + ShaderTranslatorCache* shader_translator_cache, + FramebufferCompletenessCache* framebuffer_completeness_cache, + const scoped_refptr<FeatureInfo>& feature_info, + bool bind_generates_resource, + ImageManager* image_manager, + gpu::ImageFactory* image_factory, + ProgressReporter* progress_reporter, + const GpuFeatureInfo& gpu_feature_info, + ServiceDiscardableManager* discardable_manager); // This should only be called by GLES2Decoder. This must be paired with a // call to destroy if it succeeds. @@ -83,20 +81,16 @@ // It should only be called by GLES2Decoder. void Destroy(GLES2Decoder* decoder, bool have_context); - MailboxManager* mailbox_manager() const { - return mailbox_manager_.get(); - } + MailboxManager* mailbox_manager() const { return mailbox_manager_; } - MemoryTracker* memory_tracker() const { - return memory_tracker_.get(); - } + MemoryTracker* memory_tracker() const { return memory_tracker_.get(); } ShaderTranslatorCache* shader_translator_cache() const { - return shader_translator_cache_.get(); + return shader_translator_cache_; } FramebufferCompletenessCache* framebuffer_completeness_cache() const { - return framebuffer_completeness_cache_.get(); + return framebuffer_completeness_cache_; } bool bind_generates_resource() { @@ -252,10 +246,10 @@ void ReportProgress(); const GpuPreferences& gpu_preferences_; - scoped_refptr<MailboxManager> mailbox_manager_; + MailboxManager* mailbox_manager_; scoped_refptr<MemoryTracker> memory_tracker_; - scoped_refptr<ShaderTranslatorCache> shader_translator_cache_; - scoped_refptr<FramebufferCompletenessCache> framebuffer_completeness_cache_; + ShaderTranslatorCache* shader_translator_cache_; + FramebufferCompletenessCache* framebuffer_completeness_cache_; std::unique_ptr<TransferBufferManager> transfer_buffer_manager_; bool enforce_gl_minimums_;
diff --git a/gpu/command_buffer/service/context_group_unittest.cc b/gpu/command_buffer/service/context_group_unittest.cc index 3ef61f90..dada3dc9 100644 --- a/gpu/command_buffer/service/context_group_unittest.cc +++ b/gpu/command_buffer/service/context_group_unittest.cc
@@ -12,7 +12,7 @@ #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h" #include "gpu/command_buffer/service/gpu_service_test.h" #include "gpu/command_buffer/service/image_manager.h" -#include "gpu/command_buffer/service/mailbox_manager.h" +#include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/service_discardable_manager.h" #include "gpu/command_buffer/service/test_helper.h" #include "gpu/command_buffer/service/texture_manager.h" @@ -46,8 +46,8 @@ decoder_.reset(new MockGLES2Decoder(&command_buffer_service_)); scoped_refptr<FeatureInfo> feature_info = new FeatureInfo; group_ = scoped_refptr<ContextGroup>(new ContextGroup( - gpu_preferences_, nullptr /* mailbox_manager */, - nullptr /* memory_tracker */, nullptr /* shader_translator_cache */, + gpu_preferences_, &mailbox_manager_, nullptr /* memory_tracker */, + nullptr /* shader_translator_cache */, nullptr /* framebuffer_completeness_cache */, feature_info, kBindGeneratesResource, &image_manager_, nullptr /* image_factory */, nullptr /* progress_reporter */, GpuFeatureInfo(), @@ -58,6 +58,7 @@ ImageManager image_manager_; ServiceDiscardableManager discardable_manager_; FakeCommandBufferServiceBase command_buffer_service_; + MailboxManagerImpl mailbox_manager_; std::unique_ptr<MockGLES2Decoder> decoder_; scoped_refptr<ContextGroup> group_; };
diff --git a/gpu/command_buffer/service/framebuffer_completeness_cache.h b/gpu/command_buffer/service/framebuffer_completeness_cache.h index 932aa62..dd26bf69 100644 --- a/gpu/command_buffer/service/framebuffer_completeness_cache.h +++ b/gpu/command_buffer/service/framebuffer_completeness_cache.h
@@ -9,7 +9,6 @@ #include "base/containers/hash_tables.h" #include "base/macros.h" -#include "base/memory/ref_counted.h" #include "gpu/gpu_export.h" namespace gpu { @@ -18,20 +17,15 @@ // Refcounted wrapper for a hash_set of framebuffer format signatures // representing framebuffer configurations that are reported by the GL // driver as complete according to glCheckFramebufferStatusEXT. -class GPU_EXPORT FramebufferCompletenessCache - : public base::RefCounted<FramebufferCompletenessCache> { +class GPU_EXPORT FramebufferCompletenessCache { public: FramebufferCompletenessCache(); + ~FramebufferCompletenessCache(); bool IsComplete(const std::string& signature) const; void SetComplete(const std::string& signature); - protected: - virtual ~FramebufferCompletenessCache(); - private: - friend class base::RefCounted<FramebufferCompletenessCache>; - typedef base::hash_set<std::string> Map; Map cache_;
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc index e803262..e2333d1 100644 --- a/gpu/command_buffer/service/framebuffer_manager.cc +++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -318,8 +318,7 @@ FramebufferManager::FramebufferManager( uint32_t max_draw_buffers, uint32_t max_color_attachments, - const scoped_refptr<FramebufferCompletenessCache>& - framebuffer_combo_complete_cache) + FramebufferCompletenessCache* framebuffer_combo_complete_cache) : framebuffer_state_change_count_(1), framebuffer_count_(0), have_context_(true),
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h index 182032b9..09ab0923 100644 --- a/gpu/command_buffer/service/framebuffer_manager.h +++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -317,10 +317,10 @@ // so we can correctly clear them. class GPU_EXPORT FramebufferManager { public: - FramebufferManager(uint32_t max_draw_buffers, - uint32_t max_color_attachments, - const scoped_refptr<FramebufferCompletenessCache>& - framebuffer_combo_complete_cache); + FramebufferManager( + uint32_t max_draw_buffers, + uint32_t max_color_attachments, + FramebufferCompletenessCache* framebuffer_combo_complete_cache); ~FramebufferManager(); // Must call before destruction. @@ -360,7 +360,7 @@ void StopTracking(Framebuffer* framebuffer); FramebufferCompletenessCache* GetFramebufferComboCompleteCache() { - return framebuffer_combo_complete_cache_.get(); + return framebuffer_combo_complete_cache_; } // Info for each framebuffer in the system. @@ -381,7 +381,7 @@ uint32_t max_draw_buffers_; uint32_t max_color_attachments_; - scoped_refptr<FramebufferCompletenessCache> framebuffer_combo_complete_cache_; + FramebufferCompletenessCache* framebuffer_combo_complete_cache_; DISALLOW_COPY_AND_ASSIGN(FramebufferManager); };
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc index 1ebaeda..ebe5fc8 100644 --- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc +++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -119,7 +119,7 @@ : context_type_(context_type), manager_(kMaxDrawBuffers, kMaxColorAttachments, - new FramebufferCompletenessCache), + &framebuffer_completeness_cache_), feature_info_(new FeatureInfo()) { texture_manager_.reset(new TextureManager( nullptr, feature_info_.get(), kMaxTextureSize, kMaxCubemapSize, @@ -158,6 +158,7 @@ } ContextType context_type_; + FramebufferCompletenessCache framebuffer_completeness_cache_; FramebufferManager manager_; Framebuffer* framebuffer_; scoped_refptr<FeatureInfo> feature_info_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h index 24723e6..420dd28 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
@@ -357,7 +357,7 @@ ClientServiceMap<GLuint, GLuint> vertex_array_id_map_; // Mailboxes - scoped_refptr<MailboxManager> mailbox_manager_; + MailboxManager* mailbox_manager_; // State tracking of currently bound 2D textures (client IDs) size_t active_texture_unit_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 4dfe0539f..bda9206 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -126,7 +126,8 @@ cached_depth_mask_(true), cached_stencil_front_mask_(static_cast<GLuint>(-1)), cached_stencil_back_mask_(static_cast<GLuint>(-1)), - shader_language_version_(100) { + shader_language_version_(100), + shader_translator_cache_(gpu_preferences_) { memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_)); } @@ -208,9 +209,8 @@ } group_ = scoped_refptr<ContextGroup>(new ContextGroup( - gpu_preferences_, nullptr /* mailbox_manager */, memory_tracker_, - new ShaderTranslatorCache(gpu_preferences_), - new FramebufferCompletenessCache, feature_info, + gpu_preferences_, &mailbox_manager_, memory_tracker_, + &shader_translator_cache_, &framebuffer_completeness_cache_, feature_info, normalized_init.bind_generates_resource, &image_manager_, nullptr /* image_factory */, nullptr /* progress_reporter */, GpuFeatureInfo(), &discardable_manager_));
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index d268fc1..8d717f8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -22,6 +22,7 @@ #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h" #include "gpu/command_buffer/service/gpu_preferences.h" #include "gpu/command_buffer/service/image_manager.h" +#include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/program_manager.h" #include "gpu/command_buffer/service/query_manager.h" #include "gpu/command_buffer/service/renderbuffer_manager.h" @@ -767,7 +768,10 @@ void SetupInitStateManualExpectationsForDoLineWidth(GLfloat width); GpuPreferences gpu_preferences_; - gles2::ImageManager image_manager_; + MailboxManagerImpl mailbox_manager_; + ShaderTranslatorCache shader_translator_cache_; + FramebufferCompletenessCache framebuffer_completeness_cache_; + ImageManager image_manager_; ServiceDiscardableManager discardable_manager_; scoped_refptr<ContextGroup> group_; MockGLStates gl_states_;
diff --git a/gpu/command_buffer/service/mailbox_manager.cc b/gpu/command_buffer/service/mailbox_manager.cc index 629b269..be559781 100644 --- a/gpu/command_buffer/service/mailbox_manager.cc +++ b/gpu/command_buffer/service/mailbox_manager.cc
@@ -5,6 +5,7 @@ #include "gpu/command_buffer/service/mailbox_manager.h" #include "base/command_line.h" +#include "base/memory/ptr_util.h" #include "gpu/command_buffer/service/gpu_preferences.h" #include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/mailbox_manager_sync.h" @@ -13,11 +14,11 @@ namespace gles2 { // static -scoped_refptr<MailboxManager> MailboxManager::Create( +std::unique_ptr<MailboxManager> MailboxManager::Create( const GpuPreferences& gpu_preferences) { if (gpu_preferences.enable_threaded_texture_mailboxes) - return scoped_refptr<MailboxManager>(new MailboxManagerSync); - return scoped_refptr<MailboxManager>(new MailboxManagerImpl); + return base::MakeUnique<MailboxManagerSync>(); + return base::MakeUnique<MailboxManagerImpl>(); } } // namespage gles2
diff --git a/gpu/command_buffer/service/mailbox_manager.h b/gpu/command_buffer/service/mailbox_manager.h index 1d9ce635..3c7234c 100644 --- a/gpu/command_buffer/service/mailbox_manager.h +++ b/gpu/command_buffer/service/mailbox_manager.h
@@ -5,8 +5,9 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_MAILBOX_MANAGER_H_ #define GPU_COMMAND_BUFFER_SERVICE_MAILBOX_MANAGER_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/ref_counted.h" #include "gpu/command_buffer/common/mailbox.h" #include "gpu/gpu_export.h" @@ -20,10 +21,9 @@ class TextureBase; // Manages resources scoped beyond the context or context group level. -class GPU_EXPORT MailboxManager : public base::RefCounted<MailboxManager> { +class GPU_EXPORT MailboxManager { public: - static scoped_refptr<MailboxManager> Create( - const GpuPreferences& gpu_preferences); + virtual ~MailboxManager() {} // Look up the texture definition from the named mailbox. virtual TextureBase* ConsumeTexture(const Mailbox& mailbox) = 0; @@ -41,14 +41,8 @@ // Destroy any mailbox that reference the given texture. virtual void TextureDeleted(TextureBase* texture) = 0; - protected: - MailboxManager() {} - virtual ~MailboxManager() {} - - private: - friend class base::RefCounted<MailboxManager>; - - DISALLOW_COPY_AND_ASSIGN(MailboxManager); + static std::unique_ptr<MailboxManager> Create( + const GpuPreferences& gpu_preferences); }; } // namespage gles2
diff --git a/gpu/command_buffer/service/mailbox_manager_impl.h b/gpu/command_buffer/service/mailbox_manager_impl.h index ff3d4a80..7cde11d9 100644 --- a/gpu/command_buffer/service/mailbox_manager_impl.h +++ b/gpu/command_buffer/service/mailbox_manager_impl.h
@@ -24,6 +24,7 @@ class GPU_EXPORT MailboxManagerImpl : public MailboxManager { public: MailboxManagerImpl(); + ~MailboxManagerImpl() override; // MailboxManager implementation: TextureBase* ConsumeTexture(const Mailbox& mailbox) override; @@ -33,12 +34,7 @@ void PullTextureUpdates(const SyncToken& token) override {} void TextureDeleted(TextureBase* texture) override; - protected: - ~MailboxManagerImpl() override; - private: - friend class base::RefCounted<MailboxManager>; - void InsertTexture(const Mailbox& mailbox, TextureBase* texture); // This is a bidirectional map between mailbox and textures. We can have
diff --git a/gpu/command_buffer/service/mailbox_manager_sync.h b/gpu/command_buffer/service/mailbox_manager_sync.h index a1a64aaa..33f4e36 100644 --- a/gpu/command_buffer/service/mailbox_manager_sync.h +++ b/gpu/command_buffer/service/mailbox_manager_sync.h
@@ -27,6 +27,7 @@ class GPU_EXPORT MailboxManagerSync : public MailboxManager { public: MailboxManagerSync(); + ~MailboxManagerSync() override; // MailboxManager implementation: Texture* ConsumeTexture(const Mailbox& mailbox) override; @@ -37,12 +38,8 @@ void TextureDeleted(TextureBase* texture) override; private: - friend class base::RefCounted<MailboxManager>; - static bool SkipTextureWorkarounds(const Texture* texture); - ~MailboxManagerSync() override; - class TextureGroup : public base::RefCounted<TextureGroup> { public: explicit TextureGroup(const TextureDefinition& definition);
diff --git a/gpu/command_buffer/service/mailbox_manager_unittest.cc b/gpu/command_buffer/service/mailbox_manager_unittest.cc index a1935883..711b890 100644 --- a/gpu/command_buffer/service/mailbox_manager_unittest.cc +++ b/gpu/command_buffer/service/mailbox_manager_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "gpu/command_buffer/common/sync_token.h" #include "gpu/command_buffer/service/feature_info.h" #include "gpu/command_buffer/service/gpu_service_test.h" @@ -33,14 +34,14 @@ void SetUp() override { GpuServiceTest::SetUp(); feature_info_ = new FeatureInfo; - manager_ = new MailboxManagerImpl; + manager_ = base::MakeUnique<MailboxManagerImpl>(); DCHECK(!manager_->UsesSync()); } virtual void SetUpWithSynchronizer() { GpuServiceTest::SetUp(); feature_info_ = new FeatureInfo; - manager_ = new MailboxManagerSync(); + manager_ = base::MakeUnique<MailboxManagerSync>(); DCHECK(manager_->UsesSync()); } @@ -82,7 +83,7 @@ void DestroyTexture(TextureBase* texture) { delete texture; } - scoped_refptr<MailboxManager> manager_; + std::unique_ptr<MailboxManager> manager_; private: scoped_refptr<FeatureInfo> feature_info_; @@ -195,7 +196,7 @@ protected: void SetUp() override { MailboxManagerTest::SetUpWithSynchronizer(); - manager2_ = new MailboxManagerSync(); + manager2_ = base::MakeUnique<MailboxManagerSync>(); context_ = new gl::GLContextStub(); surface_ = new gl::GLSurfaceStub(); context_->MakeCurrent(surface_.get()); @@ -250,7 +251,7 @@ MailboxManagerTest::TearDown(); } - scoped_refptr<MailboxManager> manager2_; + std::unique_ptr<MailboxManager> manager2_; scoped_refptr<gl::GLContext> context_; scoped_refptr<gl::GLSurface> surface_;
diff --git a/gpu/command_buffer/service/service_discardable_manager_unittest.cc b/gpu/command_buffer/service/service_discardable_manager_unittest.cc index 6cdffaf..9ddcb12 100644 --- a/gpu/command_buffer/service/service_discardable_manager_unittest.cc +++ b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
@@ -8,7 +8,7 @@ #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h" #include "gpu/command_buffer/service/gpu_service_test.h" #include "gpu/command_buffer/service/image_manager.h" -#include "gpu/command_buffer/service/mailbox_manager.h" +#include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/command_buffer/service/mocks.h" #include "gpu/command_buffer/service/test_helper.h" @@ -69,10 +69,10 @@ GpuServiceTest::SetUp(); decoder_.reset(new MockGLES2Decoder(&command_buffer_service_)); feature_info_ = new FeatureInfo(); - context_group_ = scoped_refptr<ContextGroup>( - new ContextGroup(gpu_preferences_, nullptr, nullptr, nullptr, nullptr, - feature_info_, false, &image_manager_, nullptr, - nullptr, GpuFeatureInfo(), &discardable_manager_)); + context_group_ = scoped_refptr<ContextGroup>(new ContextGroup( + gpu_preferences_, &mailbox_manager_, nullptr, nullptr, nullptr, + feature_info_, false, &image_manager_, nullptr, nullptr, + GpuFeatureInfo(), &discardable_manager_)); TestHelper::SetupContextGroupInitExpectations( gl_.get(), DisallowedFeatures(), "", "", CONTEXT_TYPE_OPENGLES2, false); context_group_->Initialize(decoder_.get(), CONTEXT_TYPE_OPENGLES2, @@ -113,7 +113,8 @@ .RetiresOnSaturation(); } - gles2::ImageManager image_manager_; + MailboxManagerImpl mailbox_manager_; + ImageManager image_manager_; ServiceDiscardableManager discardable_manager_; GpuPreferences gpu_preferences_; scoped_refptr<FeatureInfo> feature_info_;
diff --git a/gpu/command_buffer/service/shader_translator_cache.h b/gpu/command_buffer/service/shader_translator_cache.h index 67b9158d..b764b75 100644 --- a/gpu/command_buffer/service/shader_translator_cache.h +++ b/gpu/command_buffer/service/shader_translator_cache.h
@@ -27,10 +27,10 @@ // TODO(backer): Investigate using glReleaseShaderCompiler as an alternative to // to this cache. class GPU_EXPORT ShaderTranslatorCache - : public base::RefCounted<ShaderTranslatorCache>, - public NON_EXPORTED_BASE(ShaderTranslator::DestructionObserver) { + : public NON_EXPORTED_BASE(ShaderTranslator::DestructionObserver) { public: explicit ShaderTranslatorCache(const GpuPreferences& gpu_preferences); + ~ShaderTranslatorCache() override; // ShaderTranslator::DestructionObserver implementation void OnDestruct(ShaderTranslator* translator) override; @@ -43,9 +43,7 @@ ShCompileOptions driver_bug_workarounds); private: - friend class base::RefCounted<ShaderTranslatorCache>; friend class ShaderTranslatorCacheTest_InitParamComparable_Test; - ~ShaderTranslatorCache() override; // Parameters passed into ShaderTranslator::Init struct ShaderTranslatorInitParams {
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc index 551364d0..f7d8f48 100644 --- a/gpu/command_buffer/tests/fuzzer_main.cc +++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -90,12 +90,21 @@ "GL_OES_texture_half_float_linear"; #endif +GpuPreferences GetGpuPreferences() { + GpuPreferences preferences; +#if defined(GPU_FUZZER_USE_PASSTHROUGH_CMD_DECODER) + preferences.use_passthrough_cmd_decoder = true; +#endif + return preferences; +} + class CommandBufferSetup { public: CommandBufferSetup() : atexit_manager_(), - mailbox_manager_(new gles2::MailboxManagerImpl), - share_group_(new gl::GLShareGroup) { + gpu_preferences_(GetGpuPreferences()), + share_group_(new gl::GLShareGroup), + translator_cache_(gpu_preferences_) { logging::SetMinLogLevel(logging::LOG_FATAL); base::CommandLine::Init(0, NULL); @@ -104,7 +113,6 @@ #if defined(GPU_FUZZER_USE_PASSTHROUGH_CMD_DECODER) command_line->AppendSwitch(switches::kUsePassthroughCmdDecoder); - gpu_preferences_.use_passthrough_cmd_decoder = true; recreate_context_ = true; #endif @@ -133,9 +141,6 @@ InitContext(); gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings(); #endif // defined(GPU_FUZZER_USE_STUB) - - translator_cache_ = new gles2::ShaderTranslatorCache(gpu_preferences_); - completeness_cache_ = new gles2::FramebufferCompletenessCache; } void InitDecoder() { @@ -147,8 +152,8 @@ scoped_refptr<gles2::FeatureInfo> feature_info = new gles2::FeatureInfo(); scoped_refptr<gles2::ContextGroup> context_group = new gles2::ContextGroup( - gpu_preferences_, mailbox_manager_.get(), nullptr /* memory_tracker */, - translator_cache_, completeness_cache_, feature_info, + gpu_preferences_, &mailbox_manager_, nullptr /* memory_tracker */, + &translator_cache_, &completeness_cache_, feature_info, true /* bind_generates_resource */, &image_manager_, nullptr /* image_factory */, nullptr /* progress_reporter */, GpuFeatureInfo(), &discardable_manager_); @@ -264,7 +269,7 @@ GpuPreferences gpu_preferences_; - scoped_refptr<gles2::MailboxManager> mailbox_manager_; + gles2::MailboxManagerImpl mailbox_manager_; scoped_refptr<gl::GLShareGroup> share_group_; SyncPointManager sync_point_manager_; gles2::ImageManager image_manager_; @@ -274,8 +279,8 @@ scoped_refptr<gl::GLSurface> surface_; scoped_refptr<gl::GLContext> context_; - scoped_refptr<gles2::ShaderTranslatorCache> translator_cache_; - scoped_refptr<gles2::FramebufferCompletenessCache> completeness_cache_; + gles2::ShaderTranslatorCache translator_cache_; + gles2::FramebufferCompletenessCache completeness_cache_; std::unique_ptr<CommandBufferDirect> command_buffer_;
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc index 5fa84d47..795052a3 100644 --- a/gpu/command_buffer/tests/gl_manager.cc +++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -31,7 +31,6 @@ #include "gpu/command_buffer/service/gl_context_virtual.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/gpu_switches.h" -#include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/command_buffer/service/service_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -257,11 +256,12 @@ InitializeGpuPreferencesForTestingFromCommandLine(command_line, &gpu_preferences_); - gles2::MailboxManager* mailbox_manager = NULL; if (options.share_mailbox_manager) { - mailbox_manager = options.share_mailbox_manager->mailbox_manager(); + mailbox_manager_ = options.share_mailbox_manager->mailbox_manager(); } else if (options.share_group_manager) { - mailbox_manager = options.share_group_manager->mailbox_manager(); + mailbox_manager_ = options.share_group_manager->mailbox_manager(); + } else { + mailbox_manager_ = &owned_mailbox_manager_; } gl::GLShareGroup* share_group = NULL; @@ -285,8 +285,6 @@ real_gl_context = options.virtual_manager->context(); } - mailbox_manager_ = - mailbox_manager ? mailbox_manager : new gles2::MailboxManagerImpl; share_group_ = share_group ? share_group : new gl::GLShareGroup; gles2::ContextCreationAttribHelper attribs; @@ -305,15 +303,16 @@ attribs.offscreen_framebuffer_size = options.size; attribs.buffer_preserved = options.preserve_backbuffer; attribs.bind_generates_resource = options.bind_generates_resource; + translator_cache_ = + base::MakeUnique<gles2::ShaderTranslatorCache>(gpu_preferences_); if (!context_group) { GpuDriverBugWorkarounds gpu_driver_bug_workaround(&command_line); scoped_refptr<gles2::FeatureInfo> feature_info = new gles2::FeatureInfo(command_line, gpu_driver_bug_workaround); context_group = new gles2::ContextGroup( - gpu_preferences_, mailbox_manager_.get(), nullptr /* memory_tracker */, - new gpu::gles2::ShaderTranslatorCache(gpu_preferences_), - new gpu::gles2::FramebufferCompletenessCache, feature_info, + gpu_preferences_, mailbox_manager_, nullptr /* memory_tracker */, + translator_cache_.get(), &completeness_cache_, feature_info, options.bind_generates_resource, &image_manager_, options.image_factory, nullptr /* progress_reporter */, GpuFeatureInfo(), &discardable_manager_);
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h index 2cc2dea..01f8c80 100644 --- a/gpu/command_buffer/tests/gl_manager.h +++ b/gpu/command_buffer/tests/gl_manager.h
@@ -16,6 +16,7 @@ #include "gpu/command_buffer/service/feature_info.h" #include "gpu/command_buffer/service/gpu_preferences.h" #include "gpu/command_buffer/service/image_manager.h" +#include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/service_discardable_manager.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -109,9 +110,7 @@ return decoder_.get(); } - gles2::MailboxManager* mailbox_manager() const { - return mailbox_manager_.get(); - } + gles2::MailboxManager* mailbox_manager() const { return mailbox_manager_; } gl::GLShareGroup* share_group() const { return share_group_.get(); } @@ -155,7 +154,12 @@ gpu::GpuPreferences gpu_preferences_; - scoped_refptr<gles2::MailboxManager> mailbox_manager_; + gles2::MailboxManagerImpl owned_mailbox_manager_; + gles2::ImageManager image_manager_; + ServiceDiscardableManager discardable_manager_; + std::unique_ptr<gles2::ShaderTranslatorCache> translator_cache_; + gles2::FramebufferCompletenessCache completeness_cache_; + gles2::MailboxManager* mailbox_manager_ = nullptr; scoped_refptr<gl::GLShareGroup> share_group_; std::unique_ptr<CommandBufferDirect> command_buffer_; std::unique_ptr<gles2::GLES2Decoder> decoder_; @@ -165,9 +169,6 @@ std::unique_ptr<TransferBuffer> transfer_buffer_; std::unique_ptr<gles2::GLES2Implementation> gles2_implementation_; - gles2::ImageManager image_manager_; - ServiceDiscardableManager discardable_manager_; - uint64_t next_fence_sync_release_ = 1; bool use_iosurface_memory_buffers_ = false;
diff --git a/gpu/gles2_conform_support/egl/context.cc b/gpu/gles2_conform_support/egl/context.cc index 39613b68..d61fabb 100644 --- a/gpu/gles2_conform_support/egl/context.cc +++ b/gpu/gles2_conform_support/egl/context.cc
@@ -14,7 +14,6 @@ #include "gpu/command_buffer/client/transfer_buffer.h" #include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/image_manager.h" -#include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/command_buffer/service/service_discardable_manager.h" #include "gpu/command_buffer/service/transfer_buffer_manager.h" @@ -54,7 +53,8 @@ config_(config), is_current_in_some_thread_(false), is_destroyed_(false), - gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()) {} + gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()), + translator_cache_(gpu::GpuPreferences()) {} Context::~Context() { // We might not have a surface, so we must lose the context. Cleanup will @@ -258,10 +258,8 @@ scoped_refptr<gpu::gles2::FeatureInfo> feature_info( new gpu::gles2::FeatureInfo(gpu_driver_bug_workarounds_)); scoped_refptr<gpu::gles2::ContextGroup> group(new gpu::gles2::ContextGroup( - gpu_preferences_, nullptr /* mailbox_manager */, - nullptr /* memory_tracker */, - new gpu::gles2::ShaderTranslatorCache(gpu_preferences_), - new gpu::gles2::FramebufferCompletenessCache, feature_info, true, + gpu::GpuPreferences(), &mailbox_manager_, nullptr /* memory_tracker */, + &translator_cache_, &completeness_cache_, feature_info, true, &image_manager_, nullptr /* image_factory */, nullptr /* progress_reporter */, gpu::GpuFeatureInfo(), &discardable_manager_));
diff --git a/gpu/gles2_conform_support/egl/context.h b/gpu/gles2_conform_support/egl/context.h index f90ad445..f0bb5d53 100644 --- a/gpu/gles2_conform_support/egl/context.h +++ b/gpu/gles2_conform_support/egl/context.h
@@ -16,6 +16,7 @@ #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/gpu_preferences.h" #include "gpu/command_buffer/service/image_manager.h" +#include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/service_discardable_manager.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "ui/gfx/native_widget_types.h" @@ -104,11 +105,16 @@ const Config* config_; bool is_current_in_some_thread_; bool is_destroyed_; - gpu::GpuPreferences gpu_preferences_; const gpu::GpuDriverBugWorkarounds gpu_driver_bug_workarounds_; std::unique_ptr<gpu::TransferBufferManager> transfer_buffer_manager_; std::unique_ptr<gpu::CommandBufferDirect> command_buffer_; std::unique_ptr<gpu::gles2::GLES2CmdHelper> gles2_cmd_helper_; + + gpu::gles2::MailboxManagerImpl mailbox_manager_; + gpu::gles2::ImageManager image_manager_; + gpu::ServiceDiscardableManager discardable_manager_; + gpu::gles2::ShaderTranslatorCache translator_cache_; + gpu::gles2::FramebufferCompletenessCache completeness_cache_; std::unique_ptr<gpu::gles2::GLES2Decoder> decoder_; std::unique_ptr<gpu::TransferBuffer> transfer_buffer_; @@ -116,9 +122,6 @@ std::unique_ptr<gpu::gles2::GLES2Interface> client_gl_context_; - gpu::gles2::ImageManager image_manager_; - gpu::ServiceDiscardableManager discardable_manager_; - DISALLOW_COPY_AND_ASSIGN(Context); };
diff --git a/gpu/ipc/gpu_in_process_thread_service.cc b/gpu/ipc/gpu_in_process_thread_service.cc index b21b864..d1aedd6 100644 --- a/gpu/ipc/gpu_in_process_thread_service.cc +++ b/gpu/ipc/gpu_in_process_thread_service.cc
@@ -30,24 +30,6 @@ return true; } -scoped_refptr<gpu::gles2::ShaderTranslatorCache> -GpuInProcessThreadService::shader_translator_cache() { - if (!shader_translator_cache_) { - shader_translator_cache_ = make_scoped_refptr( - new gpu::gles2::ShaderTranslatorCache(gpu_preferences())); - } - return shader_translator_cache_; -} - -scoped_refptr<gpu::gles2::FramebufferCompletenessCache> -GpuInProcessThreadService::framebuffer_completeness_cache() { - if (!framebuffer_completeness_cache_.get()) { - framebuffer_completeness_cache_ = - make_scoped_refptr(new gpu::gles2::FramebufferCompletenessCache); - } - return framebuffer_completeness_cache_; -} - gpu::SyncPointManager* GpuInProcessThreadService::sync_point_manager() { return sync_point_manager_; }
diff --git a/gpu/ipc/gpu_in_process_thread_service.h b/gpu/ipc/gpu_in_process_thread_service.h index eb77ee27..fdf2703 100644 --- a/gpu/ipc/gpu_in_process_thread_service.h +++ b/gpu/ipc/gpu_in_process_thread_service.h
@@ -30,10 +30,6 @@ void ScheduleTask(const base::Closure& task) override; void ScheduleDelayedWork(const base::Closure& task) override; bool UseVirtualizedGLContexts() override; - scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache() - override; - scoped_refptr<gpu::gles2::FramebufferCompletenessCache> - framebuffer_completeness_cache() override; gpu::SyncPointManager* sync_point_manager() override; void AddRef() const override; void Release() const override; @@ -47,9 +43,6 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner_; gpu::SyncPointManager* sync_point_manager_; // Non-owning. - scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache_; - scoped_refptr<gpu::gles2::FramebufferCompletenessCache> - framebuffer_completeness_cache_; DISALLOW_COPY_AND_ASSIGN(GpuInProcessThreadService); };
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc index 4f70fead..3b28b89a 100644 --- a/gpu/ipc/in_process_command_buffer.cc +++ b/gpu/ipc/in_process_command_buffer.cc
@@ -32,12 +32,10 @@ #include "gpu/command_buffer/service/gl_context_virtual.h" #include "gpu/command_buffer/service/gpu_preferences.h" #include "gpu/command_buffer/service/image_factory.h" -#include "gpu/command_buffer/service/image_manager.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/memory_program_cache.h" #include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/command_buffer/service/query_manager.h" -#include "gpu/command_buffer/service/service_discardable_manager.h" #include "gpu/command_buffer/service/service_utils.h" #include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/command_buffer/service/transfer_buffer_manager.h" @@ -126,15 +124,28 @@ } // anonyous namespace InProcessCommandBuffer::Service::Service(const GpuPreferences& gpu_preferences) - : gpu_preferences_(gpu_preferences), - gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()) {} + : Service(gpu_preferences, nullptr, nullptr) {} InProcessCommandBuffer::Service::Service( gpu::gles2::MailboxManager* mailbox_manager, scoped_refptr<gl::GLShareGroup> share_group) - : gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()), + : Service(GpuPreferences(), mailbox_manager, share_group) {} + +InProcessCommandBuffer::Service::Service( + const GpuPreferences& gpu_preferences, + gpu::gles2::MailboxManager* mailbox_manager, + scoped_refptr<gl::GLShareGroup> share_group) + : gpu_preferences_(gpu_preferences), + gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()), mailbox_manager_(mailbox_manager), - share_group_(share_group) {} + share_group_(share_group), + shader_translator_cache_(gpu_preferences_) { + if (!mailbox_manager_) { + // TODO(piman): have embedders own the mailbox manager. + owned_mailbox_manager_ = gles2::MailboxManager::Create(gpu_preferences_); + mailbox_manager_ = owned_mailbox_manager_.get(); + } +} InProcessCommandBuffer::Service::~Service() {} @@ -153,14 +164,6 @@ return share_group_; } -scoped_refptr<gles2::MailboxManager> -InProcessCommandBuffer::Service::mailbox_manager() { - if (!mailbox_manager_.get()) { - mailbox_manager_ = gles2::MailboxManager::Create(gpu_preferences()); - } - return mailbox_manager_; -} - gpu::gles2::ProgramCache* InProcessCommandBuffer::Service::program_cache() { if (!program_cache_.get() && (gl::g_current_gl_driver->ext.b_GL_ARB_get_program_binary || @@ -178,20 +181,6 @@ return program_cache_.get(); } -gles2::ImageManager* InProcessCommandBuffer::Service::image_manager() { - if (!image_manager_) - image_manager_.reset(new gles2::ImageManager()); - return image_manager_.get(); -} - -ServiceDiscardableManager* -InProcessCommandBuffer::Service::discardable_manager() { - if (!discardable_manager_) { - discardable_manager_.reset(new ServiceDiscardableManager()); - } - return discardable_manager_.get(); -} - InProcessCommandBuffer::InProcessCommandBuffer( const scoped_refptr<Service>& service) : command_buffer_id_(CommandBufferId::FromUnsafeValue(
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h index a058e16..d36f0c71 100644 --- a/gpu/ipc/in_process_command_buffer.h +++ b/gpu/ipc/in_process_command_buffer.h
@@ -29,6 +29,8 @@ #include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/gpu_preferences.h" +#include "gpu/command_buffer/service/image_manager.h" +#include "gpu/command_buffer/service/service_discardable_manager.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/gpu_export.h" #include "gpu/ipc/service/image_transport_surface_delegate.h" @@ -187,7 +189,7 @@ // The serializer interface to the GPU service (i.e. thread). class Service { public: - Service(const gpu::GpuPreferences& gpu_preferences); + explicit Service(const gpu::GpuPreferences& gpu_preferences); Service(gles2::MailboxManager* mailbox_manager, scoped_refptr<gl::GLShareGroup> share_group); @@ -204,30 +206,42 @@ virtual void ScheduleDelayedWork(const base::Closure& task) = 0; virtual bool UseVirtualizedGLContexts() = 0; - virtual scoped_refptr<gles2::ShaderTranslatorCache> - shader_translator_cache() = 0; - virtual scoped_refptr<gles2::FramebufferCompletenessCache> - framebuffer_completeness_cache() = 0; virtual SyncPointManager* sync_point_manager() = 0; + virtual bool BlockThreadOnWaitSyncToken() const = 0; + const GpuPreferences& gpu_preferences(); const GpuDriverBugWorkarounds& gpu_driver_bug_workarounds(); scoped_refptr<gl::GLShareGroup> share_group(); - scoped_refptr<gles2::MailboxManager> mailbox_manager(); + gles2::MailboxManager* mailbox_manager() { return mailbox_manager_; } gles2::ProgramCache* program_cache(); - gles2::ImageManager* image_manager(); - ServiceDiscardableManager* discardable_manager(); - virtual bool BlockThreadOnWaitSyncToken() const = 0; + gles2::ImageManager* image_manager() { return &image_manager_; } + ServiceDiscardableManager* discardable_manager() { + return &discardable_manager_; + } + gles2::ShaderTranslatorCache* shader_translator_cache() { + return &shader_translator_cache_; + } + gles2::FramebufferCompletenessCache* framebuffer_completeness_cache() { + return &framebuffer_completeness_cache_; + } protected: + Service(const gpu::GpuPreferences& gpu_preferences, + gles2::MailboxManager* mailbox_manager, + scoped_refptr<gl::GLShareGroup> share_group); + const GpuPreferences gpu_preferences_; const GpuDriverBugWorkarounds gpu_driver_bug_workarounds_; - scoped_refptr<gles2::MailboxManager> mailbox_manager_; + std::unique_ptr<gles2::MailboxManager> owned_mailbox_manager_; + gles2::MailboxManager* mailbox_manager_ = nullptr; scoped_refptr<gl::GLShareGroup> share_group_; std::unique_ptr<gles2::ProgramCache> program_cache_; // No-op default initialization is used in in-process mode. GpuProcessActivityFlags activity_flags_; - std::unique_ptr<gles2::ImageManager> image_manager_; - std::unique_ptr<ServiceDiscardableManager> discardable_manager_; + gles2::ImageManager image_manager_; + ServiceDiscardableManager discardable_manager_; + gles2::ShaderTranslatorCache shader_translator_cache_; + gles2::FramebufferCompletenessCache framebuffer_completeness_cache_; }; private:
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc index bcae75e..c6a1efb 100644 --- a/gpu/ipc/service/gpu_channel.cc +++ b/gpu/ipc/service/gpu_channel.cc
@@ -797,10 +797,7 @@ GpuChannelManager* gpu_channel_manager, Scheduler* scheduler, SyncPointManager* sync_point_manager, - GpuWatchdogThread* watchdog, scoped_refptr<gl::GLShareGroup> share_group, - scoped_refptr<gles2::MailboxManager> mailbox_manager, - ServiceDiscardableManager* discardable_manager, scoped_refptr<PreemptionFlag> preempting_flag, scoped_refptr<PreemptionFlag> preempted_flag, scoped_refptr<base::SingleThreadTaskRunner> task_runner, @@ -818,15 +815,11 @@ task_runner_(task_runner), io_task_runner_(io_task_runner), share_group_(share_group), - mailbox_manager_(mailbox_manager), image_manager_(new gles2::ImageManager()), - watchdog_(watchdog), - discardable_manager_(discardable_manager), is_gpu_host_(is_gpu_host), weak_factory_(this) { DCHECK(gpu_channel_manager_); DCHECK(client_id_); - DCHECK(discardable_manager_); if (!scheduler_) { message_queue_ = new GpuChannelMessageQueue(
diff --git a/gpu/ipc/service/gpu_channel.h b/gpu/ipc/service/gpu_channel.h index a6953e23..74d474e 100644 --- a/gpu/ipc/service/gpu_channel.h +++ b/gpu/ipc/service/gpu_channel.h
@@ -46,7 +46,6 @@ class GpuChannelManager; class GpuChannelMessageFilter; class GpuChannelMessageQueue; -class GpuWatchdogThread; class GPU_EXPORT FilteredSender : public IPC::Sender { public: @@ -84,10 +83,7 @@ GpuChannel(GpuChannelManager* gpu_channel_manager, Scheduler* scheduler, SyncPointManager* sync_point_manager, - GpuWatchdogThread* watchdog, scoped_refptr<gl::GLShareGroup> share_group, - scoped_refptr<gles2::MailboxManager> mailbox_manager, - ServiceDiscardableManager* discardable_manager_, scoped_refptr<PreemptionFlag> preempting_flag, scoped_refptr<PreemptionFlag> preempted_flag, scoped_refptr<base::SingleThreadTaskRunner> task_runner, @@ -114,14 +110,8 @@ SyncPointManager* sync_point_manager() const { return sync_point_manager_; } - GpuWatchdogThread* watchdog() const { return watchdog_; } - gles2::ImageManager* image_manager() const { return image_manager_.get(); } - const scoped_refptr<gles2::MailboxManager>& mailbox_manager() const { - return mailbox_manager_; - } - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner() const { return task_runner_; } @@ -157,10 +147,6 @@ gl::GLShareGroup* share_group() const { return share_group_.get(); } - ServiceDiscardableManager* discardable_manager() const { - return discardable_manager_; - } - GpuCommandBufferStub* LookupCommandBuffer(int32_t route_id); void LoseAllContexts(); @@ -275,14 +261,8 @@ // process use. scoped_refptr<gl::GLShareGroup> share_group_; - scoped_refptr<gles2::MailboxManager> mailbox_manager_; - std::unique_ptr<gles2::ImageManager> image_manager_; - GpuWatchdogThread* const watchdog_; - - ServiceDiscardableManager* discardable_manager_; - const bool is_gpu_host_; // Member variables should appear before the WeakPtrFactory, to ensure that
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc index a0bde422..7a9a4c9c 100644 --- a/gpu/ipc/service/gpu_channel_manager.cc +++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -21,7 +21,6 @@ #include "gpu/command_buffer/service/memory_program_cache.h" #include "gpu/command_buffer/service/preemption_flag.h" #include "gpu/command_buffer/service/scheduler.h" -#include "gpu/command_buffer/service/shader_translator_cache.h" #include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/ipc/common/gpu_messages.h" #include "gpu/ipc/service/gpu_channel.h" @@ -67,6 +66,7 @@ gpu_memory_manager_(this), scheduler_(scheduler), sync_point_manager_(sync_point_manager), + shader_translator_cache_(gpu_preferences_), gpu_memory_buffer_factory_(gpu_memory_buffer_factory), gpu_feature_info_(gpu_feature_info), exiting_for_lost_context_(false), @@ -102,21 +102,6 @@ return program_cache_.get(); } -gles2::ShaderTranslatorCache* GpuChannelManager::shader_translator_cache() { - if (!shader_translator_cache_.get()) { - shader_translator_cache_ = - new gles2::ShaderTranslatorCache(gpu_preferences_); - } - return shader_translator_cache_.get(); -} - -gles2::FramebufferCompletenessCache* -GpuChannelManager::framebuffer_completeness_cache() { - if (!framebuffer_completeness_cache_.get()) - framebuffer_completeness_cache_ = new gles2::FramebufferCompletenessCache; - return framebuffer_completeness_cache_.get(); -} - void GpuChannelManager::RemoveChannel(int client_id) { delegate_->DidDestroyChannel(client_id); gpu_channels_.erase(client_id); @@ -131,8 +116,7 @@ uint64_t client_tracing_id, bool is_gpu_host) { std::unique_ptr<GpuChannel> gpu_channel = base::MakeUnique<GpuChannel>( - this, scheduler_, sync_point_manager_, watchdog_, share_group_, - mailbox_manager_, &discardable_manager_, + this, scheduler_, sync_point_manager_, share_group_, is_gpu_host ? preemption_flag_ : nullptr, is_gpu_host ? nullptr : preemption_flag_, task_runner_, io_task_runner_, client_id, client_tracing_id, is_gpu_host);
diff --git a/gpu/ipc/service/gpu_channel_manager.h b/gpu/ipc/service/gpu_channel_manager.h index 1aebaed2..b5a0463 100644 --- a/gpu/ipc/service/gpu_channel_manager.h +++ b/gpu/ipc/service/gpu_channel_manager.h
@@ -22,6 +22,7 @@ #include "gpu/command_buffer/common/constants.h" #include "gpu/command_buffer/service/gpu_preferences.h" #include "gpu/command_buffer/service/service_discardable_manager.h" +#include "gpu/command_buffer/service/shader_translator_cache.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/config/gpu_feature_info.h" #include "gpu/gpu_export.h" @@ -43,10 +44,8 @@ class SyncPointManager; struct SyncToken; namespace gles2 { -class FramebufferCompletenessCache; class MailboxManager; class ProgramCache; -class ShaderTranslatorCache; } } @@ -75,6 +74,7 @@ ~GpuChannelManager(); GpuChannelManagerDelegate* delegate() const { return delegate_; } + GpuWatchdogThread* watchdog() const { return watchdog_; } GpuChannel* EstablishChannel(int client_id, uint64_t client_tracing_id, @@ -100,9 +100,16 @@ return gpu_driver_bug_workarounds_; } const GpuFeatureInfo& gpu_feature_info() const { return gpu_feature_info_; } + ServiceDiscardableManager* discardable_manager() { + return &discardable_manager_; + } gles2::ProgramCache* program_cache(); - gles2::ShaderTranslatorCache* shader_translator_cache(); - gles2::FramebufferCompletenessCache* framebuffer_completeness_cache(); + gles2::ShaderTranslatorCache* shader_translator_cache() { + return &shader_translator_cache_; + } + gles2::FramebufferCompletenessCache* framebuffer_completeness_cache() { + return &framebuffer_completeness_cache_; + } GpuMemoryManager* gpu_memory_manager() { return &gpu_memory_manager_; } @@ -120,9 +127,7 @@ bool is_exiting_for_lost_context() { return exiting_for_lost_context_; } - gles2::MailboxManager* mailbox_manager() const { - return mailbox_manager_.get(); - } + gles2::MailboxManager* mailbox_manager() { return mailbox_manager_.get(); } gl::GLShareGroup* share_group() const { return share_group_.get(); } @@ -156,15 +161,14 @@ scoped_refptr<PreemptionFlag> preemption_flag_; - scoped_refptr<gles2::MailboxManager> mailbox_manager_; + std::unique_ptr<gles2::MailboxManager> mailbox_manager_; GpuMemoryManager gpu_memory_manager_; Scheduler* scheduler_; // SyncPointManager guaranteed to outlive running MessageLoop. SyncPointManager* sync_point_manager_; std::unique_ptr<gles2::ProgramCache> program_cache_; - scoped_refptr<gles2::ShaderTranslatorCache> shader_translator_cache_; - scoped_refptr<gles2::FramebufferCompletenessCache> - framebuffer_completeness_cache_; + gles2::ShaderTranslatorCache shader_translator_cache_; + gles2::FramebufferCompletenessCache framebuffer_completeness_cache_; scoped_refptr<gl::GLSurface> default_offscreen_surface_; GpuMemoryBufferFactory* const gpu_memory_buffer_factory_; GpuFeatureInfo gpu_feature_info_;
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc index c5f6a811..8c5705e8 100644 --- a/gpu/ipc/service/gpu_command_buffer_stub.cc +++ b/gpu/ipc/service/gpu_command_buffer_stub.cc
@@ -570,7 +570,7 @@ gpu::GpuMemoryBufferFactory* gmb_factory = channel_->gpu_channel_manager()->gpu_memory_buffer_factory(); context_group_ = new gles2::ContextGroup( - manager->gpu_preferences(), channel_->mailbox_manager(), + manager->gpu_preferences(), manager->mailbox_manager(), new GpuCommandBufferMemoryTracker( channel_, command_buffer_id_.GetUnsafeValue(), init_params.attribs.context_type, channel_->task_runner()), @@ -578,8 +578,8 @@ manager->framebuffer_completeness_cache(), feature_info, init_params.attribs.bind_generates_resource, channel_->image_manager(), gmb_factory ? gmb_factory->AsImageFactory() : nullptr, - channel_->watchdog() /* progress_reporter */, - manager->gpu_feature_info(), channel_->discardable_manager()); + manager->watchdog() /* progress_reporter */, + manager->gpu_feature_info(), manager->discardable_manager()); } #if defined(OS_MACOSX) @@ -595,7 +595,7 @@ // MailboxManagerSync synchronization correctness currently depends on having // only a single context. See crbug.com/510243 for details. - use_virtualized_gl_context_ |= channel_->mailbox_manager()->UsesSync(); + use_virtualized_gl_context_ |= manager->mailbox_manager()->UsesSync(); bool offscreen = (surface_handle_ == kNullSurfaceHandle); gl::GLSurface* default_surface = manager->GetDefaultOffscreenSurface(); @@ -838,8 +838,9 @@ CommandBufferServiceClient::CommandBatchProcessedResult GpuCommandBufferStub::OnCommandBatchProcessed() { - if (channel_->watchdog()) - channel_->watchdog()->CheckArmed(); + GpuWatchdogThread* watchdog = channel_->gpu_channel_manager()->watchdog(); + if (watchdog) + watchdog->CheckArmed(); bool pause = false; if (channel_->scheduler()) { pause = channel_->scheduler()->ShouldYield(sequence_id_);
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist index 21910c4..bd63303 100644 --- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist +++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -39,7 +39,7 @@ <string>Disable Request Mobile Site</string> <key>Key</key> <string>RequestMobileSiteDisabled</string> - <key>Default</key> + <key>DefaultValue</key> <false/> </dict> <dict>
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm index 616defce..5954eb0 100644 --- a/ios/web_view/internal/cwv_web_view.mm +++ b/ios/web_view/internal/cwv_web_view.mm
@@ -87,6 +87,8 @@ - (void)updateNavigationAvailability; // Updates the URLs exposed through |lastCommittedURL| and |visibleURL|. - (void)updateCurrentURLs; +// Updates |title| property. +- (void)updateTitle; @end @@ -239,7 +241,7 @@ } - (void)webStateDidChangeTitle:(web::WebState*)webState { - self.title = base::SysUTF16ToNSString(_webState->GetTitle()); + [self updateTitle]; } - (void)renderProcessGoneForWebState:(web::WebState*)webState { @@ -373,6 +375,12 @@ _translationController.webState = _webState.get(); [self addInternalWebViewAsSubview]; + + [self updateNavigationAvailability]; + [self updateCurrentURLs]; + [self updateTitle]; + self.loading = NO; + self.estimatedProgress = 0.0; } // Adds the web view provided by |_webState| as a subview unless it has already. @@ -398,4 +406,8 @@ self.visibleURL = net::NSURLWithGURL(_webState->GetVisibleURL()); } +- (void)updateTitle { + self.title = base::SysUTF16ToNSString(_webState->GetTitle()); +} + @end
diff --git a/ios/web_view/test/BUILD.gn b/ios/web_view/test/BUILD.gn index 1b25eda..70620cb 100644 --- a/ios/web_view/test/BUILD.gn +++ b/ios/web_view/test/BUILD.gn
@@ -17,6 +17,7 @@ testonly = true sources = [ "chrome_web_view_kvo_inttest.mm", + "chrome_web_view_restorable_state_inttest.mm", "chrome_web_view_test.h", "chrome_web_view_test.mm", "observer.h",
diff --git a/ios/web_view/test/chrome_web_view_restorable_state_inttest.mm b/ios/web_view/test/chrome_web_view_restorable_state_inttest.mm new file mode 100644 index 0000000..7c17e25b --- /dev/null +++ b/ios/web_view/test/chrome_web_view_restorable_state_inttest.mm
@@ -0,0 +1,73 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <ChromeWebView/ChromeWebView.h> + +#import "ios/web_view/test/chrome_web_view_test.h" +#include "testing/gtest_mac.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +// Creates web view for testing. +CWVWebView* CreateWebView() { + return [[CWVWebView alloc] + initWithFrame:CGRectMake(0, 0, 50, 50) + configuration:[CWVWebViewConfiguration defaultConfiguration]]; +} + +// Creates a new web view and restores its state from |source_web_view|. +CWVWebView* CreateWebViewWithState(CWVWebView* source_web_view) { + NSMutableData* data = [[NSMutableData alloc] init]; + NSKeyedArchiver* archiver = + [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; + [source_web_view encodeRestorableStateWithCoder:archiver]; + [archiver finishEncoding]; + NSKeyedUnarchiver* unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; + CWVWebView* result = CreateWebView(); + [result decodeRestorableStateWithCoder:unarchiver]; + return result; +} + +} // namespace + +namespace ios_web_view { + +// Tests encodeRestorableStateWithCoder: and decodeRestorableStateWithCoder: +// methods. +typedef ios_web_view::ChromeWebViewTest ChromeWebViewRestorableStateTest; +TEST_F(ChromeWebViewRestorableStateTest, EncodeDecode) { + // Create web view that will be used as a source for state restoration. + CWVWebView* web_view = CreateWebView(); + + // Load 2 URLs to create non-default state. + ASSERT_FALSE(web_view.lastCommittedURL); + ASSERT_FALSE(web_view.visibleURL); + ASSERT_FALSE(web_view.canGoBack); + ASSERT_FALSE(web_view.canGoForward); + LoadUrl(web_view, [NSURL URLWithString:@"about:newtab"]); + ASSERT_NSEQ(@"about:newtab", web_view.lastCommittedURL.absoluteString); + ASSERT_NSEQ(@"about:newtab", web_view.visibleURL.absoluteString); + LoadUrl(web_view, [NSURL URLWithString:@"about:blank"]); + ASSERT_NSEQ(@"about:blank", web_view.lastCommittedURL.absoluteString); + ASSERT_NSEQ(@"about:blank", web_view.visibleURL.absoluteString); + ASSERT_TRUE(web_view.canGoBack); + ASSERT_FALSE(web_view.canGoForward); + + // Create second web view and restore its state from the first web view. + CWVWebView* restored_web_view = CreateWebViewWithState(web_view); + + // Verify that the state has been restored correctly. + EXPECT_NSEQ(@"about:blank", + restored_web_view.lastCommittedURL.absoluteString); + EXPECT_NSEQ(@"about:blank", restored_web_view.visibleURL.absoluteString); + EXPECT_TRUE(web_view.canGoBack); + EXPECT_FALSE(web_view.canGoForward); +} + +} // namespace ios_web_view
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc index 764a7c2..34f72c09 100644 --- a/media/gpu/dxva_video_decode_accelerator_win.cc +++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -1629,9 +1629,14 @@ } } + // Each picture buffer can store a sample, plus one in + // pending_output_samples_. The decoder adds this number to the number of + // reference pictures it expects to need and uses that to determine the + // array size of the output texture. + const int kMaxOutputSamples = kNumPictureBuffers + 1; attributes->SetUINT32(MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE, - kNumPictureBuffers); - attributes->SetUINT32(MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, kNumPictureBuffers); + kMaxOutputSamples); + attributes->SetUINT32(MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, kMaxOutputSamples); auto* gl_context = get_gl_context_cb_.Run(); RETURN_ON_FAILURE(gl_context, "Couldn't get GL context", false); @@ -2077,6 +2082,9 @@ base::AutoLock lock(decoder_lock_); sample_count = pending_output_samples_.size(); } + size_t stale_output_picture_buffers_size = + stale_output_picture_buffers_.size(); + PictureBufferMechanism mechanism = GetPictureBufferMechanism(); base::debug::Alias(&last_exception_code); base::debug::Alias(&last_unhandled_error); @@ -2086,6 +2094,8 @@ base::debug::Alias(&perf_frequency.QuadPart); base::debug::Alias(&output_array_size); base::debug::Alias(&sample_count); + base::debug::Alias(&stale_output_picture_buffers_size); + base::debug::Alias(&mechanism); decoder_thread_.Stop(); }
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc index d2386f6..d36e948 100644 --- a/media/renderers/renderer_impl.cc +++ b/media/renderers/renderer_impl.cc
@@ -167,17 +167,13 @@ } cdm_context_ = cdm_context; + cdm_attached_cb.Run(true); - if (state_ != STATE_INIT_PENDING_CDM) { - cdm_attached_cb.Run(true); + if (state_ != STATE_INIT_PENDING_CDM) return; - } DCHECK(!init_cb_.is_null()); state_ = STATE_INITIALIZING; - // |cdm_attached_cb| will be fired after initialization finishes. - pending_cdm_attached_cb_ = cdm_attached_cb; - InitializeAudioRenderer(); } @@ -334,10 +330,6 @@ void RendererImpl::FinishInitialization(PipelineStatus status) { DCHECK(!init_cb_.is_null()); - - if (!pending_cdm_attached_cb_.is_null()) - base::ResetAndReturn(&pending_cdm_attached_cb_).Run(status == PIPELINE_OK); - base::ResetAndReturn(&init_cb_).Run(status); }
diff --git a/media/renderers/renderer_impl.h b/media/renderers/renderer_impl.h index aae8b52..7e78749 100644 --- a/media/renderers/renderer_impl.h +++ b/media/renderers/renderer_impl.h
@@ -214,7 +214,6 @@ bool video_ended_; CdmContext* cdm_context_; - CdmAttachedCB pending_cdm_attached_cb_; bool underflow_disabled_for_testing_; bool clockless_video_playback_enabled_for_testing_;
diff --git a/media/renderers/renderer_impl_unittest.cc b/media/renderers/renderer_impl_unittest.cc index 6075b8f..c5ff649 100644 --- a/media/renderers/renderer_impl_unittest.cc +++ b/media/renderers/renderer_impl_unittest.cc
@@ -372,7 +372,7 @@ // SetCdm() will trigger the initialization to start. But it will not complete // because the |video_renderer_| is not returning the initialization callback. - SetCdmAndExpect(false); + SetCdmAndExpect(true); EXPECT_EQ(PIPELINE_OK, initialization_status_); Destroy(); @@ -455,7 +455,7 @@ // Initialization is pending until CDM is set. EXPECT_EQ(PIPELINE_OK, initialization_status_); - SetCdmAndExpect(false); + SetCdmAndExpect(true); EXPECT_EQ(PIPELINE_ERROR_INITIALIZATION_FAILED, initialization_status_); }
diff --git a/net/cert/x509_certificate_nss.cc b/net/cert/x509_certificate_nss.cc index 4f3339f..4f5baa3 100644 --- a/net/cert/x509_certificate_nss.cc +++ b/net/cert/x509_certificate_nss.cc
@@ -26,15 +26,189 @@ namespace net { -bool X509Certificate::Initialize() { - serial_number_ = x509_util::ParseSerialNumber(cert_handle_); +namespace { - return ( - !serial_number_.empty() && - x509_util::ParsePrincipal(&cert_handle_->subject, &subject_) && - x509_util::ParsePrincipal(&cert_handle_->issuer, &issuer_) && - x509_util::ParseDate(&cert_handle_->validity.notBefore, &valid_start_) && - x509_util::ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_)); +// Callback for CERT_DecodeCertPackage(), used in +// CreateOSCertHandlesFromBytes(). +SECStatus PR_CALLBACK CollectCertsCallback(void* arg, + SECItem** certs, + int num_certs) { + X509Certificate::OSCertHandles* results = + reinterpret_cast<X509Certificate::OSCertHandles*>(arg); + + for (int i = 0; i < num_certs; ++i) { + X509Certificate::OSCertHandle handle = + X509Certificate::CreateOSCertHandleFromBytes( + reinterpret_cast<char*>(certs[i]->data), certs[i]->len); + if (handle) + results->push_back(handle); + } + + return SECSuccess; +} + +// Parses the Principal attribute from |name| and outputs the result in +// |principal|. Returns true on success. +bool ParsePrincipal(CERTName* name, CertPrincipal* principal) { +// Starting in NSS 3.15, CERTGetNameFunc takes a const CERTName* argument. +#if NSS_VMINOR >= 15 + typedef char* (*CERTGetNameFunc)(const CERTName* name); +#else + typedef char* (*CERTGetNameFunc)(CERTName * name); +#endif + + // TODO(jcampan): add business_category and serial_number. + // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and + // CERT_GetDomainComponentName functions, but they return only the most + // general (the first) RDN. NSS doesn't have a function for the street + // address. + static const SECOidTag kOIDs[] = { + SEC_OID_AVA_STREET_ADDRESS, SEC_OID_AVA_ORGANIZATION_NAME, + SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, SEC_OID_AVA_DC}; + + std::vector<std::string>* values[] = { + &principal->street_addresses, &principal->organization_names, + &principal->organization_unit_names, &principal->domain_components}; + DCHECK_EQ(arraysize(kOIDs), arraysize(values)); + + CERTRDN** rdns = name->rdns; + for (size_t rdn = 0; rdns[rdn]; ++rdn) { + CERTAVA** avas = rdns[rdn]->avas; + for (size_t pair = 0; avas[pair] != 0; ++pair) { + SECOidTag tag = CERT_GetAVATag(avas[pair]); + for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { + if (kOIDs[oid] == tag) { + SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); + if (!decode_item) + return false; + // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote. + std::string value(reinterpret_cast<char*>(decode_item->data), + decode_item->len); + values[oid]->push_back(value); + SECITEM_FreeItem(decode_item, PR_TRUE); + break; + } + } + } + } + + // Get CN, L, S, and C. + CERTGetNameFunc get_name_funcs[4] = {CERT_GetCommonName, CERT_GetLocalityName, + CERT_GetStateName, CERT_GetCountryName}; + std::string* single_values[4] = { + &principal->common_name, &principal->locality_name, + &principal->state_or_province_name, &principal->country_name}; + for (size_t i = 0; i < arraysize(get_name_funcs); ++i) { + char* value = get_name_funcs[i](name); + if (value) { + single_values[i]->assign(value); + PORT_Free(value); + } + } + + return true; +} + +// Parses the date from |der_date| and outputs the result in |result|. +// Returns true on success. +bool ParseDate(const SECItem* der_date, base::Time* result) { + PRTime prtime; + SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date); + if (rv != SECSuccess) + return false; + *result = crypto::PRTimeToBaseTime(prtime); + return true; +} + +// Parses the serial number from |certificate|. +std::string ParseSerialNumber(const CERTCertificate* certificate) { + return std::string(reinterpret_cast<char*>(certificate->serialNumber.data), + certificate->serialNumber.len); +} + +typedef std::unique_ptr<CERTName, + crypto::NSSDestroyer<CERTName, CERT_DestroyName>> + ScopedCERTName; + +// Create a new CERTName object from its encoded representation. +// |arena| is the allocation pool to use. +// |data| points to a DER-encoded X.509 DistinguishedName. +// Return a new CERTName pointer on success, or NULL. +CERTName* CreateCertNameFromEncoded(PLArenaPool* arena, + const base::StringPiece& data) { + if (!arena) + return NULL; + + ScopedCERTName name(PORT_ArenaZNew(arena, CERTName)); + if (!name.get()) + return NULL; + + SECItem item; + item.len = static_cast<unsigned int>(data.length()); + item.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())); + + SECStatus rv = SEC_ASN1DecodeItem(arena, name.get(), + SEC_ASN1_GET(CERT_NameTemplate), &item); + if (rv != SECSuccess) + return NULL; + + return name.release(); +} + +// Create a list of CERTName objects from a list of DER-encoded X.509 +// DistinguishedName items. All objects are created in a given arena. +// |encoded_issuers| is the list of encoded DNs. +// |arena| is the arena used for all allocations. +// |out| will receive the result list on success. +// Return true on success. On failure, the caller must free the +// intermediate CERTName objects pushed to |out|. +bool GetIssuersFromEncodedList(const std::vector<std::string>& encoded_issuers, + PLArenaPool* arena, + std::vector<CERTName*>* out) { + std::vector<CERTName*> result; + for (size_t n = 0; n < encoded_issuers.size(); ++n) { + CERTName* name = CreateCertNameFromEncoded(arena, encoded_issuers[n]); + if (name != NULL) + result.push_back(name); + } + + if (result.size() == encoded_issuers.size()) { + out->swap(result); + return true; + } + + for (size_t n = 0; n < result.size(); ++n) + CERT_DestroyName(result[n]); + return false; +} + +// Returns true iff a certificate is issued by any of the issuers listed +// by name in |valid_issuers|. +// |cert_chain| is the certificate's chain. +// |valid_issuers| is a list of strings, where each string contains +// a DER-encoded X.509 Distinguished Name. +bool IsCertificateIssuedBy(const std::vector<CERTCertificate*>& cert_chain, + const std::vector<CERTName*>& valid_issuers) { + for (size_t n = 0; n < cert_chain.size(); ++n) { + CERTName* cert_issuer = &cert_chain[n]->issuer; + for (size_t i = 0; i < valid_issuers.size(); ++i) { + if (CERT_CompareName(valid_issuers[i], cert_issuer) == SECEqual) + return true; + } + } + return false; +} + +} // namespace + +bool X509Certificate::Initialize() { + serial_number_ = ParseSerialNumber(cert_handle_); + + return (!serial_number_.empty() && + ParsePrincipal(&cert_handle_->subject, &subject_) && + ParsePrincipal(&cert_handle_->issuer, &issuer_) && + ParseDate(&cert_handle_->validity.notBefore, &valid_start_) && + ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_)); } std::string X509Certificate::GetDefaultNickname(CertType type) const { @@ -92,7 +266,54 @@ bool X509Certificate::GetSubjectAltName( std::vector<std::string>* dns_names, std::vector<std::string>* ip_addrs) const { - return x509_util::GetSubjectAltName(cert_handle_, dns_names, ip_addrs); + if (dns_names) + dns_names->clear(); + if (ip_addrs) + ip_addrs->clear(); + + SECItem alt_name; + SECStatus rv = CERT_FindCertExtension( + cert_handle_, SEC_OID_X509_SUBJECT_ALT_NAME, &alt_name); + if (rv != SECSuccess) + return false; + + crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + + CERTGeneralName* alt_name_list; + alt_name_list = CERT_DecodeAltNameExtension(arena.get(), &alt_name); + SECITEM_FreeItem(&alt_name, PR_FALSE); + + bool has_san = false; + CERTGeneralName* name = alt_name_list; + while (name) { + // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs + // respectively, both of which can be byte copied from + // SECItemType::data into the appropriate output vector. + if (name->type == certDNSName) { + has_san = true; + if (dns_names) { + dns_names->push_back( + std::string(reinterpret_cast<char*>(name->name.other.data), + name->name.other.len)); + } + } else if (name->type == certIPAddress) { + has_san = true; + if (ip_addrs) { + ip_addrs->push_back( + std::string(reinterpret_cast<char*>(name->name.other.data), + name->name.other.len)); + } + } + // Fast path: Found at least one subjectAltName and the caller doesn't + // need the actual values. + if (has_san && !ip_addrs && !dns_names) + return true; + + name = CERT_GetNextGeneralName(name); + if (name == alt_name_list) + break; + } + return has_san; } bool X509Certificate::IsIssuedByEncoded( @@ -106,12 +327,10 @@ // Convert encoded issuers to scoped CERTName* list. std::vector<CERTName*> issuers; crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - if (!x509_util::GetIssuersFromEncodedList(valid_issuers, - arena.get(), - &issuers)) { + if (!GetIssuersFromEncodedList(valid_issuers, arena.get(), &issuers)) { return false; } - return x509_util::IsCertificateIssuedBy(cert_chain, issuers); + return IsCertificateIssuedBy(cert_chain, issuers); } // static @@ -167,7 +386,38 @@ const char* data, size_t length, Format format) { - return x509_util::CreateOSCertHandlesFromBytes(data, length, format); + X509Certificate::OSCertHandles results; + + crypto::EnsureNSSInit(); + + if (!NSS_IsInitialized()) + return results; + + switch (format) { + case X509Certificate::FORMAT_SINGLE_CERTIFICATE: { + X509Certificate::OSCertHandle handle = + X509Certificate::CreateOSCertHandleFromBytes(data, length); + if (handle) + results.push_back(handle); + break; + } + case X509Certificate::FORMAT_PKCS7: { + // Make a copy since CERT_DecodeCertPackage may modify it + std::vector<char> data_copy(data, data + length); + + SECStatus result = CERT_DecodeCertPackage( + data_copy.data(), base::checked_cast<int>(data_copy.size()), + CollectCertsCallback, &results); + if (result != SECSuccess) + results.clear(); + break; + } + default: + NOTREACHED() << "Certificate format " << format << " unimplemented"; + break; + } + + return results; } // static @@ -221,7 +471,12 @@ // static X509Certificate::OSCertHandle X509Certificate::ReadOSCertHandleFromPickle( base::PickleIterator* pickle_iter) { - return x509_util::ReadOSCertHandleFromPickle(pickle_iter); + const char* data; + int length; + if (!pickle_iter->ReadData(&data, &length)) + return NULL; + + return CreateOSCertHandleFromBytes(data, length); } // static @@ -236,7 +491,34 @@ void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, size_t* size_bits, PublicKeyType* type) { - x509_util::GetPublicKeyInfo(cert_handle, size_bits, type); + // Since we might fail, set the output parameters to default values first. + *type = X509Certificate::kPublicKeyTypeUnknown; + *size_bits = 0; + + crypto::ScopedSECKEYPublicKey key(CERT_ExtractPublicKey(cert_handle)); + if (!key.get()) + return; + + *size_bits = SECKEY_PublicKeyStrengthInBits(key.get()); + + switch (key->keyType) { + case rsaKey: + *type = X509Certificate::kPublicKeyTypeRSA; + break; + case dsaKey: + *type = X509Certificate::kPublicKeyTypeDSA; + break; + case dhKey: + *type = X509Certificate::kPublicKeyTypeDH; + break; + case ecKey: + *type = X509Certificate::kPublicKeyTypeECDSA; + break; + default: + *type = X509Certificate::kPublicKeyTypeUnknown; + *size_bits = 0; + break; + } } // static
diff --git a/net/cert/x509_util_nss.cc b/net/cert/x509_util_nss.cc index 1175bd80..13d7e36 100644 --- a/net/cert/x509_util_nss.cc +++ b/net/cert/x509_util_nss.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "net/cert/x509_util_nss.h" + #include <cert.h> // Must be included before certdb.h #include <certdb.h> #include <cryptohi.h> @@ -12,22 +14,9 @@ #include <secmod.h> #include <secport.h> -#include <memory> - -#include "base/debug/leak_annotations.h" #include "base/logging.h" -#include "base/memory/singleton.h" -#include "base/numerics/safe_conversions.h" -#include "base/pickle.h" #include "base/strings/stringprintf.h" -#include "crypto/ec_private_key.h" -#include "crypto/nss_util.h" -#include "crypto/nss_util_internal.h" -#include "crypto/rsa_private_key.h" #include "crypto/scoped_nss_types.h" -#include "net/cert/x509_certificate.h" -#include "net/cert/x509_util.h" -#include "net/cert/x509_util_nss.h" namespace net { @@ -37,184 +26,10 @@ const uint8_t kUpnOid[] = {0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37, 0x14, 0x2, 0x3}; -// Callback for CERT_DecodeCertPackage(), used in -// CreateOSCertHandlesFromBytes(). -SECStatus PR_CALLBACK CollectCertsCallback(void* arg, - SECItem** certs, - int num_certs) { - X509Certificate::OSCertHandles* results = - reinterpret_cast<X509Certificate::OSCertHandles*>(arg); - - for (int i = 0; i < num_certs; ++i) { - X509Certificate::OSCertHandle handle = - X509Certificate::CreateOSCertHandleFromBytes( - reinterpret_cast<char*>(certs[i]->data), certs[i]->len); - if (handle) - results->push_back(handle); - } - - return SECSuccess; -} - -typedef std::unique_ptr<CERTName, - crypto::NSSDestroyer<CERTName, CERT_DestroyName>> - ScopedCERTName; - -// Create a new CERTName object from its encoded representation. -// |arena| is the allocation pool to use. -// |data| points to a DER-encoded X.509 DistinguishedName. -// Return a new CERTName pointer on success, or NULL. -CERTName* CreateCertNameFromEncoded(PLArenaPool* arena, - const base::StringPiece& data) { - if (!arena) - return NULL; - - ScopedCERTName name(PORT_ArenaZNew(arena, CERTName)); - if (!name.get()) - return NULL; - - SECItem item; - item.len = static_cast<unsigned int>(data.length()); - item.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())); - - SECStatus rv = SEC_ASN1DecodeItem(arena, name.get(), - SEC_ASN1_GET(CERT_NameTemplate), &item); - if (rv != SECSuccess) - return NULL; - - return name.release(); -} - } // namespace namespace x509_util { -bool ParsePrincipal(CERTName* name, CertPrincipal* principal) { -// Starting in NSS 3.15, CERTGetNameFunc takes a const CERTName* argument. -#if NSS_VMINOR >= 15 - typedef char* (*CERTGetNameFunc)(const CERTName* name); -#else - typedef char* (*CERTGetNameFunc)(CERTName * name); -#endif - - // TODO(jcampan): add business_category and serial_number. - // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and - // CERT_GetDomainComponentName functions, but they return only the most - // general (the first) RDN. NSS doesn't have a function for the street - // address. - static const SECOidTag kOIDs[] = { - SEC_OID_AVA_STREET_ADDRESS, SEC_OID_AVA_ORGANIZATION_NAME, - SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, SEC_OID_AVA_DC}; - - std::vector<std::string>* values[] = { - &principal->street_addresses, &principal->organization_names, - &principal->organization_unit_names, &principal->domain_components}; - DCHECK_EQ(arraysize(kOIDs), arraysize(values)); - - CERTRDN** rdns = name->rdns; - for (size_t rdn = 0; rdns[rdn]; ++rdn) { - CERTAVA** avas = rdns[rdn]->avas; - for (size_t pair = 0; avas[pair] != 0; ++pair) { - SECOidTag tag = CERT_GetAVATag(avas[pair]); - for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { - if (kOIDs[oid] == tag) { - SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); - if (!decode_item) - return false; - // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote. - std::string value(reinterpret_cast<char*>(decode_item->data), - decode_item->len); - values[oid]->push_back(value); - SECITEM_FreeItem(decode_item, PR_TRUE); - break; - } - } - } - } - - // Get CN, L, S, and C. - CERTGetNameFunc get_name_funcs[4] = {CERT_GetCommonName, CERT_GetLocalityName, - CERT_GetStateName, CERT_GetCountryName}; - std::string* single_values[4] = { - &principal->common_name, &principal->locality_name, - &principal->state_or_province_name, &principal->country_name}; - for (size_t i = 0; i < arraysize(get_name_funcs); ++i) { - char* value = get_name_funcs[i](name); - if (value) { - single_values[i]->assign(value); - PORT_Free(value); - } - } - - return true; -} - -bool ParseDate(const SECItem* der_date, base::Time* result) { - PRTime prtime; - SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date); - if (rv != SECSuccess) - return false; - *result = crypto::PRTimeToBaseTime(prtime); - return true; -} - -std::string ParseSerialNumber(const CERTCertificate* certificate) { - return std::string(reinterpret_cast<char*>(certificate->serialNumber.data), - certificate->serialNumber.len); -} - -bool GetSubjectAltName(CERTCertificate* cert_handle, - std::vector<std::string>* dns_names, - std::vector<std::string>* ip_addrs) { - if (dns_names) - dns_names->clear(); - if (ip_addrs) - ip_addrs->clear(); - - SECItem alt_name; - SECStatus rv = CERT_FindCertExtension( - cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, &alt_name); - if (rv != SECSuccess) - return false; - - crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - - CERTGeneralName* alt_name_list; - alt_name_list = CERT_DecodeAltNameExtension(arena.get(), &alt_name); - SECITEM_FreeItem(&alt_name, PR_FALSE); - - bool has_san = false; - CERTGeneralName* name = alt_name_list; - while (name) { - // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs - // respectively, both of which can be byte copied from - // SECItemType::data into the appropriate output vector. - if (name->type == certDNSName) { - has_san = true; - if (dns_names) { - dns_names->push_back( - std::string(reinterpret_cast<char*>(name->name.other.data), - name->name.other.len)); - } - } else if (name->type == certIPAddress) { - has_san = true; - if (ip_addrs) { - ip_addrs->push_back( - std::string(reinterpret_cast<char*>(name->name.other.data), - name->name.other.len)); - } - } - // Fast path: Found at least one subjectAltName and the caller doesn't - // need the actual values. - if (has_san && !ip_addrs && !dns_names) - return true; - - name = CERT_GetNextGeneralName(name); - if (name == alt_name_list) - break; - } - return has_san; -} void GetRFC822SubjectAltNames(CERTCertificate* cert_handle, std::vector<std::string>* names) { @@ -284,119 +99,6 @@ } } -X509Certificate::OSCertHandles CreateOSCertHandlesFromBytes( - const char* data, - size_t length, - X509Certificate::Format format) { - X509Certificate::OSCertHandles results; - - crypto::EnsureNSSInit(); - - if (!NSS_IsInitialized()) - return results; - - switch (format) { - case X509Certificate::FORMAT_SINGLE_CERTIFICATE: { - X509Certificate::OSCertHandle handle = - X509Certificate::CreateOSCertHandleFromBytes(data, length); - if (handle) - results.push_back(handle); - break; - } - case X509Certificate::FORMAT_PKCS7: { - // Make a copy since CERT_DecodeCertPackage may modify it - std::vector<char> data_copy(data, data + length); - - SECStatus result = CERT_DecodeCertPackage( - data_copy.data(), base::checked_cast<int>(data_copy.size()), - CollectCertsCallback, &results); - if (result != SECSuccess) - results.clear(); - break; - } - default: - NOTREACHED() << "Certificate format " << format << " unimplemented"; - break; - } - - return results; -} - -X509Certificate::OSCertHandle ReadOSCertHandleFromPickle( - base::PickleIterator* pickle_iter) { - const char* data; - int length; - if (!pickle_iter->ReadData(&data, &length)) - return NULL; - - return X509Certificate::CreateOSCertHandleFromBytes(data, length); -} - -void GetPublicKeyInfo(CERTCertificate* handle, - size_t* size_bits, - X509Certificate::PublicKeyType* type) { - // Since we might fail, set the output parameters to default values first. - *type = X509Certificate::kPublicKeyTypeUnknown; - *size_bits = 0; - - crypto::ScopedSECKEYPublicKey key(CERT_ExtractPublicKey(handle)); - if (!key.get()) - return; - - *size_bits = SECKEY_PublicKeyStrengthInBits(key.get()); - - switch (key->keyType) { - case rsaKey: - *type = X509Certificate::kPublicKeyTypeRSA; - break; - case dsaKey: - *type = X509Certificate::kPublicKeyTypeDSA; - break; - case dhKey: - *type = X509Certificate::kPublicKeyTypeDH; - break; - case ecKey: - *type = X509Certificate::kPublicKeyTypeECDSA; - break; - default: - *type = X509Certificate::kPublicKeyTypeUnknown; - *size_bits = 0; - break; - } -} - -bool GetIssuersFromEncodedList(const std::vector<std::string>& encoded_issuers, - PLArenaPool* arena, - std::vector<CERTName*>* out) { - std::vector<CERTName*> result; - for (size_t n = 0; n < encoded_issuers.size(); ++n) { - CERTName* name = CreateCertNameFromEncoded(arena, encoded_issuers[n]); - if (name != NULL) - result.push_back(name); - } - - if (result.size() == encoded_issuers.size()) { - out->swap(result); - return true; - } - - for (size_t n = 0; n < result.size(); ++n) - CERT_DestroyName(result[n]); - return false; -} - -bool IsCertificateIssuedBy(const std::vector<CERTCertificate*>& cert_chain, - const std::vector<CERTName*>& valid_issuers) { - for (size_t n = 0; n < cert_chain.size(); ++n) { - CERTName* cert_issuer = &cert_chain[n]->issuer; - for (size_t i = 0; i < valid_issuers.size(); ++i) { - if (CERT_CompareName(valid_issuers[i], cert_issuer) == SECEqual) - return true; - } - } - return false; -} - std::string GetUniqueNicknameForSlot(const std::string& nickname, const SECItem* subject, PK11SlotInfo* slot) {
diff --git a/net/cert/x509_util_nss.h b/net/cert/x509_util_nss.h index b5dfe795..7acabdf29 100644 --- a/net/cert/x509_util_nss.h +++ b/net/cert/x509_util_nss.h
@@ -10,44 +10,16 @@ #include <string> #include <vector> -#include "base/time/time.h" #include "net/base/net_export.h" -#include "net/cert/x509_certificate.h" - -namespace base { -class PickleIterator; -} typedef struct CERTCertificateStr CERTCertificate; -typedef struct CERTNameStr CERTName; typedef struct PK11SlotInfoStr PK11SlotInfo; -typedef struct PLArenaPool PLArenaPool; typedef struct SECItemStr SECItem; namespace net { namespace x509_util { -// Parses the Principal attribute from |name| and outputs the result in -// |principal|. Returns true on success. -bool ParsePrincipal(CERTName* name, CertPrincipal* principal); - -// Parses the date from |der_date| and outputs the result in |result|. -// Returns true on success. -bool ParseDate(const SECItem* der_date, base::Time* result); - -// Parses the serial number from |certificate|. -std::string ParseSerialNumber(const CERTCertificate* certificate); - -// Gets the dNSName and iPAddress name fields from the subjectAltName -// extension of |cert_handle|. -// If |dns_names| is non-null, each dNSName will be stored in |*dns_names|. -// If |ip_addrs| is non-null, each iPAddress will be stored in |*ip_addrs|. -// Returns true if any dNSName or iPAddress was present. -bool GetSubjectAltName(CERTCertificate* cert_handle, - std::vector<std::string>* dns_names, - std::vector<std::string>* ip_addrs); - // Stores the values of all rfc822Name subjectAltNames from |cert_handle| // into |names|. If no names are present, clears |names|. // WARNING: This method does not validate that the rfc822Name is @@ -77,45 +49,6 @@ NET_EXPORT void GetUPNSubjectAltNames(CERTCertificate* cert_handle, std::vector<std::string>* names); -// Creates all possible OS certificate handles from |data| encoded in a specific -// |format|. Returns an empty collection on failure. -X509Certificate::OSCertHandles CreateOSCertHandlesFromBytes( - const char* data, - size_t length, - X509Certificate::Format format); - -// Reads a single certificate from |pickle_iter| and returns a platform-specific -// certificate handle. Returns an invalid handle, NULL, on failure. -X509Certificate::OSCertHandle ReadOSCertHandleFromPickle( - base::PickleIterator* pickle_iter); - -// Sets |*size_bits| to be the length of the public key in bits, and sets -// |*type| to one of the |PublicKeyType| values. In case of -// |kPublicKeyTypeUnknown|, |*size_bits| will be set to 0. -void GetPublicKeyInfo(CERTCertificate* handle, - size_t* size_bits, - X509Certificate::PublicKeyType* type); - -// Create a list of CERTName objects from a list of DER-encoded X.509 -// DistinguishedName items. All objects are created in a given arena. -// |encoded_issuers| is the list of encoded DNs. -// |arena| is the arena used for all allocations. -// |out| will receive the result list on success. -// Return true on success. On failure, the caller must free the -// intermediate CERTName objects pushed to |out|. -bool GetIssuersFromEncodedList( - const std::vector<std::string>& issuers, - PLArenaPool* arena, - std::vector<CERTName*>* out); - -// Returns true iff a certificate is issued by any of the issuers listed -// by name in |valid_issuers|. -// |cert_chain| is the certificate's chain. -// |valid_issuers| is a list of strings, where each string contains -// a DER-encoded X.509 Distinguished Name. -bool IsCertificateIssuedBy(const std::vector<CERTCertificate*>& cert_chain, - const std::vector<CERTName*>& valid_issuers); - // Generates a unique nickname for |slot|, returning |nickname| if it is // already unique. //
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index afabf3b..0354406 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1571,6 +1571,10 @@ crbug.com/732829 css3/blending/mix-blend-mode-isolated-group-3.html [ NeedsManualRebaseline ] crbug.com/732829 css3/blending/mix-blend-mode-simple-text.html [ NeedsManualRebaseline ] crbug.com/732829 svg/filters/feBlend-all-modes.html [ NeedsManualRebaseline ] +crbug.com/732829 css3/blending/svg-blend-color.html [ NeedsManualRebaseline ] +crbug.com/732829 css3/blending/svg-blend-hue.html [ NeedsManualRebaseline ] +crbug.com/732829 css3/blending/svg-blend-luminosity.html [ NeedsManualRebaseline ] +crbug.com/732829 css3/blending/svg-blend-saturation.html [ NeedsManualRebaseline ] # Mac10.10-specific failures that still need triaging.
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations index f8043c5e..53d73ef 100644 --- a/third_party/WebKit/LayoutTests/W3CImportExpectations +++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -398,7 +398,7 @@ ## Owners: bsheedy@chromium.org # external/wpt/webvr [ Pass ] external/wpt/wai-aria [ Skip ] -## Owners: suzyh@chromium.org +## Owners: meade@chromium.org # external/wpt/web-animations [ Pass ] ## Owners: hongchan@chromium.org, rtoy@chromium.org # external/wpt/webaudio [ Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-insertNode-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-insertNode-expected.txt deleted file mode 100644 index 41ddbab..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-insertNode-expected.txt +++ /dev/null
@@ -1,1676 +0,0 @@ -This is a testharness.js-based test. -Found 1672 tests; 1671 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS 0,0: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node paras[0] -PASS 0,0: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node paras[0] -PASS 0,1: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node paras[0].firstChild -PASS 0,1: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node paras[0].firstChild -PASS 0,2: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node paras[1].firstChild -PASS 0,2: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node paras[1].firstChild -PASS 0,3: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignPara1 -PASS 0,3: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignPara1 -PASS 0,4: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignPara1.firstChild -PASS 0,4: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignPara1.firstChild -PASS 0,5: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedPara1 -PASS 0,5: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedPara1 -PASS 0,6: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedPara1.firstChild -PASS 0,6: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedPara1.firstChild -PASS 0,7: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node document -PASS 0,7: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node document -PASS 0,8: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedDiv -PASS 0,8: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedDiv -PASS 0,9: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignDoc -PASS 0,9: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignDoc -PASS 0,10: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignPara2 -PASS 0,10: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignPara2 -PASS 0,11: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node xmlDoc -PASS 0,11: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node xmlDoc -PASS 0,12: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node xmlElement -PASS 0,12: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node xmlElement -PASS 0,13: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedTextNode -PASS 0,13: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedTextNode -PASS 0,14: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignTextNode -PASS 0,14: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignTextNode -PASS 0,15: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node processingInstruction -PASS 0,15: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node processingInstruction -PASS 0,16: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedProcessingInstruction -PASS 0,16: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedProcessingInstruction -PASS 0,17: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node comment -PASS 0,17: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node comment -PASS 0,18: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedComment -PASS 0,18: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node detachedComment -PASS 0,19: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node docfrag -PASS 0,19: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node docfrag -PASS 0,20: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node doctype -PASS 0,20: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node doctype -PASS 0,21: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignDoctype -PASS 0,21: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 0], node foreignDoctype -PASS 1,0: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node paras[0] -PASS 1,0: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node paras[0] -PASS 1,1: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node paras[0].firstChild -PASS 1,1: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node paras[0].firstChild -PASS 1,2: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node paras[1].firstChild -PASS 1,2: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node paras[1].firstChild -PASS 1,3: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignPara1 -PASS 1,3: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignPara1 -PASS 1,4: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignPara1.firstChild -PASS 1,4: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignPara1.firstChild -PASS 1,5: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedPara1 -PASS 1,5: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedPara1 -PASS 1,6: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedPara1.firstChild -PASS 1,6: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedPara1.firstChild -PASS 1,7: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node document -PASS 1,7: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node document -PASS 1,8: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedDiv -PASS 1,8: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedDiv -PASS 1,9: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignDoc -PASS 1,9: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignDoc -PASS 1,10: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignPara2 -PASS 1,10: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignPara2 -PASS 1,11: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node xmlDoc -PASS 1,11: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node xmlDoc -PASS 1,12: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node xmlElement -PASS 1,12: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node xmlElement -PASS 1,13: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedTextNode -PASS 1,13: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedTextNode -PASS 1,14: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignTextNode -PASS 1,14: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignTextNode -PASS 1,15: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node processingInstruction -PASS 1,15: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node processingInstruction -PASS 1,16: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedProcessingInstruction -PASS 1,16: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedProcessingInstruction -PASS 1,17: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node comment -PASS 1,17: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node comment -PASS 1,18: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedComment -PASS 1,18: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node detachedComment -PASS 1,19: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node docfrag -PASS 1,19: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node docfrag -PASS 1,20: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node doctype -PASS 1,20: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node doctype -PASS 1,21: resulting DOM for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignDoctype -PASS 1,21: resulting range position for range [paras[0].firstChild, 0, paras[0].firstChild, 1], node foreignDoctype -PASS 2,0: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node paras[0] -PASS 2,0: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node paras[0] -PASS 2,1: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node paras[0].firstChild -PASS 2,1: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node paras[0].firstChild -PASS 2,2: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node paras[1].firstChild -PASS 2,2: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node paras[1].firstChild -PASS 2,3: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignPara1 -PASS 2,3: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignPara1 -PASS 2,4: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignPara1.firstChild -PASS 2,4: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignPara1.firstChild -PASS 2,5: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedPara1 -PASS 2,5: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedPara1 -PASS 2,6: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedPara1.firstChild -PASS 2,6: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedPara1.firstChild -PASS 2,7: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node document -PASS 2,7: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node document -PASS 2,8: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedDiv -PASS 2,8: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedDiv -PASS 2,9: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignDoc -PASS 2,9: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignDoc -PASS 2,10: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignPara2 -PASS 2,10: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignPara2 -PASS 2,11: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node xmlDoc -PASS 2,11: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node xmlDoc -PASS 2,12: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node xmlElement -PASS 2,12: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node xmlElement -PASS 2,13: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedTextNode -PASS 2,13: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedTextNode -PASS 2,14: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignTextNode -PASS 2,14: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignTextNode -PASS 2,15: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node processingInstruction -PASS 2,15: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node processingInstruction -PASS 2,16: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedProcessingInstruction -PASS 2,16: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedProcessingInstruction -PASS 2,17: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node comment -PASS 2,17: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node comment -PASS 2,18: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedComment -PASS 2,18: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node detachedComment -PASS 2,19: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node docfrag -PASS 2,19: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node docfrag -PASS 2,20: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node doctype -PASS 2,20: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node doctype -PASS 2,21: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignDoctype -PASS 2,21: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 8], node foreignDoctype -PASS 3,0: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node paras[0] -PASS 3,0: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node paras[0] -PASS 3,1: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node paras[0].firstChild -PASS 3,1: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node paras[0].firstChild -PASS 3,2: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node paras[1].firstChild -PASS 3,2: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node paras[1].firstChild -PASS 3,3: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignPara1 -PASS 3,3: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignPara1 -PASS 3,4: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignPara1.firstChild -PASS 3,4: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignPara1.firstChild -PASS 3,5: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedPara1 -PASS 3,5: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedPara1 -PASS 3,6: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedPara1.firstChild -PASS 3,6: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedPara1.firstChild -PASS 3,7: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node document -PASS 3,7: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node document -PASS 3,8: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedDiv -PASS 3,8: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedDiv -PASS 3,9: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignDoc -PASS 3,9: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignDoc -PASS 3,10: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignPara2 -PASS 3,10: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignPara2 -PASS 3,11: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node xmlDoc -PASS 3,11: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node xmlDoc -PASS 3,12: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node xmlElement -PASS 3,12: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node xmlElement -PASS 3,13: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedTextNode -PASS 3,13: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedTextNode -PASS 3,14: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignTextNode -PASS 3,14: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignTextNode -PASS 3,15: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node processingInstruction -PASS 3,15: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node processingInstruction -PASS 3,16: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedProcessingInstruction -PASS 3,16: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedProcessingInstruction -PASS 3,17: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node comment -PASS 3,17: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node comment -PASS 3,18: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedComment -PASS 3,18: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node detachedComment -PASS 3,19: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node docfrag -PASS 3,19: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node docfrag -PASS 3,20: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node doctype -PASS 3,20: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node doctype -PASS 3,21: resulting DOM for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignDoctype -PASS 3,21: resulting range position for range [paras[0].firstChild, 2, paras[0].firstChild, 9], node foreignDoctype -PASS 4,0: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node paras[0] -PASS 4,0: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node paras[0] -PASS 4,1: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node paras[0].firstChild -PASS 4,1: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node paras[0].firstChild -PASS 4,2: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node paras[1].firstChild -PASS 4,2: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node paras[1].firstChild -PASS 4,3: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignPara1 -PASS 4,3: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignPara1 -PASS 4,4: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignPara1.firstChild -PASS 4,4: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignPara1.firstChild -PASS 4,5: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedPara1 -PASS 4,5: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedPara1 -PASS 4,6: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedPara1.firstChild -PASS 4,6: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedPara1.firstChild -PASS 4,7: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node document -PASS 4,7: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node document -PASS 4,8: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedDiv -PASS 4,8: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedDiv -PASS 4,9: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignDoc -PASS 4,9: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignDoc -PASS 4,10: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignPara2 -PASS 4,10: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignPara2 -PASS 4,11: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node xmlDoc -PASS 4,11: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node xmlDoc -PASS 4,12: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node xmlElement -PASS 4,12: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node xmlElement -PASS 4,13: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedTextNode -PASS 4,13: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedTextNode -PASS 4,14: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignTextNode -PASS 4,14: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignTextNode -PASS 4,15: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node processingInstruction -PASS 4,15: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node processingInstruction -PASS 4,16: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedProcessingInstruction -PASS 4,16: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedProcessingInstruction -PASS 4,17: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node comment -PASS 4,17: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node comment -PASS 4,18: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedComment -PASS 4,18: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node detachedComment -PASS 4,19: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node docfrag -PASS 4,19: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node docfrag -PASS 4,20: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node doctype -PASS 4,20: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node doctype -PASS 4,21: resulting DOM for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignDoctype -PASS 4,21: resulting range position for range [paras[1].firstChild, 0, paras[1].firstChild, 0], node foreignDoctype -PASS 5,0: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node paras[0] -PASS 5,0: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node paras[0] -PASS 5,1: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node paras[0].firstChild -PASS 5,1: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node paras[0].firstChild -PASS 5,2: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node paras[1].firstChild -PASS 5,2: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node paras[1].firstChild -PASS 5,3: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignPara1 -PASS 5,3: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignPara1 -PASS 5,4: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignPara1.firstChild -PASS 5,4: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignPara1.firstChild -PASS 5,5: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedPara1 -PASS 5,5: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedPara1 -PASS 5,6: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedPara1.firstChild -PASS 5,6: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedPara1.firstChild -PASS 5,7: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node document -PASS 5,7: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node document -PASS 5,8: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedDiv -PASS 5,8: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedDiv -PASS 5,9: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignDoc -PASS 5,9: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignDoc -PASS 5,10: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignPara2 -PASS 5,10: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignPara2 -PASS 5,11: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node xmlDoc -PASS 5,11: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node xmlDoc -PASS 5,12: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node xmlElement -PASS 5,12: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node xmlElement -PASS 5,13: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedTextNode -PASS 5,13: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedTextNode -PASS 5,14: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignTextNode -PASS 5,14: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignTextNode -PASS 5,15: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node processingInstruction -PASS 5,15: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node processingInstruction -PASS 5,16: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedProcessingInstruction -PASS 5,16: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedProcessingInstruction -PASS 5,17: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node comment -PASS 5,17: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node comment -PASS 5,18: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedComment -PASS 5,18: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node detachedComment -PASS 5,19: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node docfrag -PASS 5,19: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node docfrag -PASS 5,20: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node doctype -PASS 5,20: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node doctype -PASS 5,21: resulting DOM for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignDoctype -PASS 5,21: resulting range position for range [paras[1].firstChild, 2, paras[1].firstChild, 9], node foreignDoctype -PASS 6,0: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node paras[0] -PASS 6,0: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node paras[0] -PASS 6,1: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node paras[0].firstChild -PASS 6,1: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node paras[0].firstChild -PASS 6,2: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node paras[1].firstChild -PASS 6,2: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node paras[1].firstChild -PASS 6,3: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignPara1 -PASS 6,3: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignPara1 -PASS 6,4: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignPara1.firstChild -PASS 6,4: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignPara1.firstChild -PASS 6,5: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedPara1 -PASS 6,5: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedPara1 -PASS 6,6: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedPara1.firstChild -PASS 6,6: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedPara1.firstChild -PASS 6,7: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node document -PASS 6,7: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node document -PASS 6,8: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedDiv -PASS 6,8: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedDiv -PASS 6,9: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignDoc -PASS 6,9: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignDoc -PASS 6,10: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignPara2 -PASS 6,10: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignPara2 -PASS 6,11: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node xmlDoc -PASS 6,11: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node xmlDoc -PASS 6,12: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node xmlElement -PASS 6,12: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node xmlElement -PASS 6,13: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedTextNode -PASS 6,13: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedTextNode -PASS 6,14: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignTextNode -PASS 6,14: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignTextNode -PASS 6,15: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node processingInstruction -PASS 6,15: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node processingInstruction -PASS 6,16: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedProcessingInstruction -PASS 6,16: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedProcessingInstruction -PASS 6,17: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node comment -PASS 6,17: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node comment -PASS 6,18: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedComment -PASS 6,18: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node detachedComment -PASS 6,19: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node docfrag -PASS 6,19: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node docfrag -PASS 6,20: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node doctype -PASS 6,20: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node doctype -PASS 6,21: resulting DOM for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignDoctype -PASS 6,21: resulting range position for range [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node foreignDoctype -PASS 7,0: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node paras[0] -PASS 7,0: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node paras[0] -PASS 7,1: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node paras[0].firstChild -PASS 7,1: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node paras[0].firstChild -PASS 7,2: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node paras[1].firstChild -PASS 7,2: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node paras[1].firstChild -PASS 7,3: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignPara1 -PASS 7,3: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignPara1 -PASS 7,4: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignPara1.firstChild -PASS 7,4: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignPara1.firstChild -PASS 7,5: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedPara1 -PASS 7,5: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedPara1 -PASS 7,6: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedPara1.firstChild -PASS 7,6: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedPara1.firstChild -PASS 7,7: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node document -PASS 7,7: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node document -PASS 7,8: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedDiv -PASS 7,8: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedDiv -PASS 7,9: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignDoc -PASS 7,9: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignDoc -PASS 7,10: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignPara2 -PASS 7,10: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignPara2 -PASS 7,11: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node xmlDoc -PASS 7,11: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node xmlDoc -PASS 7,12: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node xmlElement -PASS 7,12: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node xmlElement -PASS 7,13: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedTextNode -PASS 7,13: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedTextNode -PASS 7,14: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignTextNode -PASS 7,14: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignTextNode -PASS 7,15: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node processingInstruction -PASS 7,15: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node processingInstruction -PASS 7,16: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedProcessingInstruction -PASS 7,16: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedProcessingInstruction -PASS 7,17: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node comment -PASS 7,17: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node comment -PASS 7,18: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedComment -PASS 7,18: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node detachedComment -PASS 7,19: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node docfrag -PASS 7,19: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node docfrag -PASS 7,20: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node doctype -PASS 7,20: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node doctype -PASS 7,21: resulting DOM for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignDoctype -PASS 7,21: resulting range position for range [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node foreignDoctype -PASS 8,0: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node paras[0] -PASS 8,0: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node paras[0] -PASS 8,1: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node paras[0].firstChild -PASS 8,1: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node paras[0].firstChild -PASS 8,2: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node paras[1].firstChild -PASS 8,2: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node paras[1].firstChild -PASS 8,3: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignPara1 -PASS 8,3: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignPara1 -PASS 8,4: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignPara1.firstChild -PASS 8,4: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignPara1.firstChild -PASS 8,5: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedPara1 -PASS 8,5: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedPara1 -PASS 8,6: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedPara1.firstChild -PASS 8,6: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedPara1.firstChild -PASS 8,7: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node document -PASS 8,7: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node document -PASS 8,8: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedDiv -PASS 8,8: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedDiv -PASS 8,9: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignDoc -PASS 8,9: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignDoc -PASS 8,10: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignPara2 -PASS 8,10: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignPara2 -PASS 8,11: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node xmlDoc -PASS 8,11: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node xmlDoc -PASS 8,12: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node xmlElement -PASS 8,12: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node xmlElement -PASS 8,13: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedTextNode -PASS 8,13: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedTextNode -PASS 8,14: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignTextNode -PASS 8,14: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignTextNode -PASS 8,15: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node processingInstruction -PASS 8,15: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node processingInstruction -PASS 8,16: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedProcessingInstruction -PASS 8,16: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedProcessingInstruction -PASS 8,17: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node comment -PASS 8,17: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node comment -PASS 8,18: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedComment -PASS 8,18: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node detachedComment -PASS 8,19: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node docfrag -PASS 8,19: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node docfrag -PASS 8,20: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node doctype -PASS 8,20: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node doctype -PASS 8,21: resulting DOM for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignDoctype -PASS 8,21: resulting range position for range [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node foreignDoctype -PASS 9,0: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node paras[0] -PASS 9,0: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node paras[0] -PASS 9,1: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node paras[0].firstChild -PASS 9,1: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node paras[0].firstChild -PASS 9,2: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node paras[1].firstChild -PASS 9,2: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node paras[1].firstChild -PASS 9,3: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignPara1 -PASS 9,3: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignPara1 -PASS 9,4: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignPara1.firstChild -PASS 9,4: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignPara1.firstChild -PASS 9,5: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedPara1 -PASS 9,5: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedPara1 -PASS 9,6: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedPara1.firstChild -PASS 9,6: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedPara1.firstChild -PASS 9,7: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node document -PASS 9,7: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node document -PASS 9,8: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedDiv -PASS 9,8: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedDiv -PASS 9,9: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignDoc -PASS 9,9: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignDoc -PASS 9,10: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignPara2 -PASS 9,10: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignPara2 -PASS 9,11: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node xmlDoc -PASS 9,11: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node xmlDoc -PASS 9,12: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node xmlElement -PASS 9,12: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node xmlElement -PASS 9,13: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedTextNode -PASS 9,13: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedTextNode -PASS 9,14: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignTextNode -PASS 9,14: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignTextNode -PASS 9,15: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node processingInstruction -PASS 9,15: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node processingInstruction -PASS 9,16: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedProcessingInstruction -PASS 9,16: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedProcessingInstruction -PASS 9,17: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node comment -PASS 9,17: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node comment -PASS 9,18: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedComment -PASS 9,18: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node detachedComment -PASS 9,19: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node docfrag -PASS 9,19: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node docfrag -PASS 9,20: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node doctype -PASS 9,20: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node doctype -PASS 9,21: resulting DOM for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignDoctype -PASS 9,21: resulting range position for range [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node foreignDoctype -PASS 10,0: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node paras[0] -PASS 10,0: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node paras[0] -PASS 10,1: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node paras[0].firstChild -PASS 10,1: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node paras[0].firstChild -PASS 10,2: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node paras[1].firstChild -PASS 10,2: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node paras[1].firstChild -PASS 10,3: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node foreignPara1 -PASS 10,3: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node foreignPara1 -PASS 10,4: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node foreignPara1.firstChild -PASS 10,4: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node foreignPara1.firstChild -PASS 10,5: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node detachedPara1 -PASS 10,5: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node detachedPara1 -PASS 10,6: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node detachedPara1.firstChild -PASS 10,6: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node detachedPara1.firstChild -PASS 10,7: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node document -PASS 10,7: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node document -PASS 10,8: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node detachedDiv -PASS 10,8: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node detachedDiv -PASS 10,9: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node foreignDoc -PASS 10,9: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node foreignDoc -PASS 10,10: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node foreignPara2 -PASS 10,10: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node foreignPara2 -PASS 10,11: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node xmlDoc -PASS 10,11: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node xmlDoc -PASS 10,12: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node xmlElement -PASS 10,12: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node xmlElement -PASS 10,13: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node detachedTextNode -PASS 10,13: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node detachedTextNode -PASS 10,14: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node foreignTextNode -PASS 10,14: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node foreignTextNode -PASS 10,15: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node processingInstruction -PASS 10,15: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node processingInstruction -PASS 10,16: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node detachedProcessingInstruction -PASS 10,16: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node detachedProcessingInstruction -PASS 10,17: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node comment -PASS 10,17: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node comment -PASS 10,18: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node detachedComment -PASS 10,18: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node detachedComment -PASS 10,19: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node docfrag -PASS 10,19: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node docfrag -PASS 10,20: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node doctype -PASS 10,20: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node doctype -PASS 10,21: resulting DOM for range [document.documentElement, 0, document.documentElement, 1], node foreignDoctype -PASS 10,21: resulting range position for range [document.documentElement, 0, document.documentElement, 1], node foreignDoctype -PASS 11,0: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node paras[0] -PASS 11,0: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node paras[0] -PASS 11,1: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node paras[0].firstChild -PASS 11,1: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node paras[0].firstChild -PASS 11,2: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node paras[1].firstChild -PASS 11,2: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node paras[1].firstChild -PASS 11,3: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node foreignPara1 -PASS 11,3: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node foreignPara1 -PASS 11,4: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node foreignPara1.firstChild -PASS 11,4: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node foreignPara1.firstChild -PASS 11,5: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node detachedPara1 -PASS 11,5: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node detachedPara1 -PASS 11,6: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node detachedPara1.firstChild -PASS 11,6: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node detachedPara1.firstChild -PASS 11,7: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node document -PASS 11,7: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node document -PASS 11,8: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node detachedDiv -PASS 11,8: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node detachedDiv -PASS 11,9: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node foreignDoc -PASS 11,9: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node foreignDoc -PASS 11,10: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node foreignPara2 -PASS 11,10: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node foreignPara2 -PASS 11,11: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node xmlDoc -PASS 11,11: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node xmlDoc -PASS 11,12: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node xmlElement -PASS 11,12: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node xmlElement -PASS 11,13: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node detachedTextNode -PASS 11,13: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node detachedTextNode -PASS 11,14: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node foreignTextNode -PASS 11,14: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node foreignTextNode -PASS 11,15: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node processingInstruction -PASS 11,15: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node processingInstruction -PASS 11,16: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node detachedProcessingInstruction -PASS 11,16: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node detachedProcessingInstruction -PASS 11,17: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node comment -PASS 11,17: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node comment -PASS 11,18: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node detachedComment -PASS 11,18: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node detachedComment -PASS 11,19: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node docfrag -PASS 11,19: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node docfrag -PASS 11,20: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node doctype -PASS 11,20: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node doctype -PASS 11,21: resulting DOM for range [document.documentElement, 0, document.documentElement, 2], node foreignDoctype -PASS 11,21: resulting range position for range [document.documentElement, 0, document.documentElement, 2], node foreignDoctype -PASS 12,0: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node paras[0] -PASS 12,0: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node paras[0] -PASS 12,1: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node paras[0].firstChild -PASS 12,1: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node paras[0].firstChild -PASS 12,2: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node paras[1].firstChild -PASS 12,2: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node paras[1].firstChild -PASS 12,3: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node foreignPara1 -PASS 12,3: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node foreignPara1 -PASS 12,4: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node foreignPara1.firstChild -PASS 12,4: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node foreignPara1.firstChild -PASS 12,5: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node detachedPara1 -PASS 12,5: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node detachedPara1 -PASS 12,6: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node detachedPara1.firstChild -PASS 12,6: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node detachedPara1.firstChild -PASS 12,7: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node document -PASS 12,7: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node document -PASS 12,8: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node detachedDiv -PASS 12,8: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node detachedDiv -PASS 12,9: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node foreignDoc -PASS 12,9: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node foreignDoc -PASS 12,10: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node foreignPara2 -PASS 12,10: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node foreignPara2 -PASS 12,11: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node xmlDoc -PASS 12,11: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node xmlDoc -PASS 12,12: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node xmlElement -PASS 12,12: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node xmlElement -PASS 12,13: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node detachedTextNode -PASS 12,13: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node detachedTextNode -PASS 12,14: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node foreignTextNode -PASS 12,14: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node foreignTextNode -PASS 12,15: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node processingInstruction -PASS 12,15: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node processingInstruction -PASS 12,16: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node detachedProcessingInstruction -PASS 12,16: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node detachedProcessingInstruction -PASS 12,17: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node comment -PASS 12,17: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node comment -PASS 12,18: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node detachedComment -PASS 12,18: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node detachedComment -PASS 12,19: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node docfrag -PASS 12,19: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node docfrag -PASS 12,20: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node doctype -PASS 12,20: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node doctype -PASS 12,21: resulting DOM for range [document.documentElement, 1, document.documentElement, 2], node foreignDoctype -PASS 12,21: resulting range position for range [document.documentElement, 1, document.documentElement, 2], node foreignDoctype -PASS 13,0: resulting DOM for range [document.head, 1, document.head, 1], node paras[0] -PASS 13,0: resulting range position for range [document.head, 1, document.head, 1], node paras[0] -PASS 13,1: resulting DOM for range [document.head, 1, document.head, 1], node paras[0].firstChild -PASS 13,1: resulting range position for range [document.head, 1, document.head, 1], node paras[0].firstChild -PASS 13,2: resulting DOM for range [document.head, 1, document.head, 1], node paras[1].firstChild -PASS 13,2: resulting range position for range [document.head, 1, document.head, 1], node paras[1].firstChild -PASS 13,3: resulting DOM for range [document.head, 1, document.head, 1], node foreignPara1 -PASS 13,3: resulting range position for range [document.head, 1, document.head, 1], node foreignPara1 -PASS 13,4: resulting DOM for range [document.head, 1, document.head, 1], node foreignPara1.firstChild -PASS 13,4: resulting range position for range [document.head, 1, document.head, 1], node foreignPara1.firstChild -PASS 13,5: resulting DOM for range [document.head, 1, document.head, 1], node detachedPara1 -PASS 13,5: resulting range position for range [document.head, 1, document.head, 1], node detachedPara1 -PASS 13,6: resulting DOM for range [document.head, 1, document.head, 1], node detachedPara1.firstChild -PASS 13,6: resulting range position for range [document.head, 1, document.head, 1], node detachedPara1.firstChild -PASS 13,7: resulting DOM for range [document.head, 1, document.head, 1], node document -PASS 13,7: resulting range position for range [document.head, 1, document.head, 1], node document -PASS 13,8: resulting DOM for range [document.head, 1, document.head, 1], node detachedDiv -PASS 13,8: resulting range position for range [document.head, 1, document.head, 1], node detachedDiv -PASS 13,9: resulting DOM for range [document.head, 1, document.head, 1], node foreignDoc -PASS 13,9: resulting range position for range [document.head, 1, document.head, 1], node foreignDoc -PASS 13,10: resulting DOM for range [document.head, 1, document.head, 1], node foreignPara2 -PASS 13,10: resulting range position for range [document.head, 1, document.head, 1], node foreignPara2 -PASS 13,11: resulting DOM for range [document.head, 1, document.head, 1], node xmlDoc -PASS 13,11: resulting range position for range [document.head, 1, document.head, 1], node xmlDoc -PASS 13,12: resulting DOM for range [document.head, 1, document.head, 1], node xmlElement -PASS 13,12: resulting range position for range [document.head, 1, document.head, 1], node xmlElement -PASS 13,13: resulting DOM for range [document.head, 1, document.head, 1], node detachedTextNode -PASS 13,13: resulting range position for range [document.head, 1, document.head, 1], node detachedTextNode -PASS 13,14: resulting DOM for range [document.head, 1, document.head, 1], node foreignTextNode -PASS 13,14: resulting range position for range [document.head, 1, document.head, 1], node foreignTextNode -PASS 13,15: resulting DOM for range [document.head, 1, document.head, 1], node processingInstruction -PASS 13,15: resulting range position for range [document.head, 1, document.head, 1], node processingInstruction -PASS 13,16: resulting DOM for range [document.head, 1, document.head, 1], node detachedProcessingInstruction -PASS 13,16: resulting range position for range [document.head, 1, document.head, 1], node detachedProcessingInstruction -PASS 13,17: resulting DOM for range [document.head, 1, document.head, 1], node comment -PASS 13,17: resulting range position for range [document.head, 1, document.head, 1], node comment -PASS 13,18: resulting DOM for range [document.head, 1, document.head, 1], node detachedComment -PASS 13,18: resulting range position for range [document.head, 1, document.head, 1], node detachedComment -PASS 13,19: resulting DOM for range [document.head, 1, document.head, 1], node docfrag -PASS 13,19: resulting range position for range [document.head, 1, document.head, 1], node docfrag -PASS 13,20: resulting DOM for range [document.head, 1, document.head, 1], node doctype -PASS 13,20: resulting range position for range [document.head, 1, document.head, 1], node doctype -PASS 13,21: resulting DOM for range [document.head, 1, document.head, 1], node foreignDoctype -PASS 13,21: resulting range position for range [document.head, 1, document.head, 1], node foreignDoctype -PASS 14,0: resulting DOM for range [document.body, 4, document.body, 5], node paras[0] -PASS 14,0: resulting range position for range [document.body, 4, document.body, 5], node paras[0] -PASS 14,1: resulting DOM for range [document.body, 4, document.body, 5], node paras[0].firstChild -PASS 14,1: resulting range position for range [document.body, 4, document.body, 5], node paras[0].firstChild -PASS 14,2: resulting DOM for range [document.body, 4, document.body, 5], node paras[1].firstChild -PASS 14,2: resulting range position for range [document.body, 4, document.body, 5], node paras[1].firstChild -PASS 14,3: resulting DOM for range [document.body, 4, document.body, 5], node foreignPara1 -PASS 14,3: resulting range position for range [document.body, 4, document.body, 5], node foreignPara1 -PASS 14,4: resulting DOM for range [document.body, 4, document.body, 5], node foreignPara1.firstChild -PASS 14,4: resulting range position for range [document.body, 4, document.body, 5], node foreignPara1.firstChild -PASS 14,5: resulting DOM for range [document.body, 4, document.body, 5], node detachedPara1 -PASS 14,5: resulting range position for range [document.body, 4, document.body, 5], node detachedPara1 -PASS 14,6: resulting DOM for range [document.body, 4, document.body, 5], node detachedPara1.firstChild -PASS 14,6: resulting range position for range [document.body, 4, document.body, 5], node detachedPara1.firstChild -PASS 14,7: resulting DOM for range [document.body, 4, document.body, 5], node document -PASS 14,7: resulting range position for range [document.body, 4, document.body, 5], node document -PASS 14,8: resulting DOM for range [document.body, 4, document.body, 5], node detachedDiv -PASS 14,8: resulting range position for range [document.body, 4, document.body, 5], node detachedDiv -PASS 14,9: resulting DOM for range [document.body, 4, document.body, 5], node foreignDoc -PASS 14,9: resulting range position for range [document.body, 4, document.body, 5], node foreignDoc -PASS 14,10: resulting DOM for range [document.body, 4, document.body, 5], node foreignPara2 -PASS 14,10: resulting range position for range [document.body, 4, document.body, 5], node foreignPara2 -PASS 14,11: resulting DOM for range [document.body, 4, document.body, 5], node xmlDoc -PASS 14,11: resulting range position for range [document.body, 4, document.body, 5], node xmlDoc -PASS 14,12: resulting DOM for range [document.body, 4, document.body, 5], node xmlElement -PASS 14,12: resulting range position for range [document.body, 4, document.body, 5], node xmlElement -PASS 14,13: resulting DOM for range [document.body, 4, document.body, 5], node detachedTextNode -PASS 14,13: resulting range position for range [document.body, 4, document.body, 5], node detachedTextNode -PASS 14,14: resulting DOM for range [document.body, 4, document.body, 5], node foreignTextNode -PASS 14,14: resulting range position for range [document.body, 4, document.body, 5], node foreignTextNode -PASS 14,15: resulting DOM for range [document.body, 4, document.body, 5], node processingInstruction -PASS 14,15: resulting range position for range [document.body, 4, document.body, 5], node processingInstruction -PASS 14,16: resulting DOM for range [document.body, 4, document.body, 5], node detachedProcessingInstruction -PASS 14,16: resulting range position for range [document.body, 4, document.body, 5], node detachedProcessingInstruction -PASS 14,17: resulting DOM for range [document.body, 4, document.body, 5], node comment -PASS 14,17: resulting range position for range [document.body, 4, document.body, 5], node comment -PASS 14,18: resulting DOM for range [document.body, 4, document.body, 5], node detachedComment -PASS 14,18: resulting range position for range [document.body, 4, document.body, 5], node detachedComment -PASS 14,19: resulting DOM for range [document.body, 4, document.body, 5], node docfrag -PASS 14,19: resulting range position for range [document.body, 4, document.body, 5], node docfrag -PASS 14,20: resulting DOM for range [document.body, 4, document.body, 5], node doctype -PASS 14,20: resulting range position for range [document.body, 4, document.body, 5], node doctype -PASS 14,21: resulting DOM for range [document.body, 4, document.body, 5], node foreignDoctype -PASS 14,21: resulting range position for range [document.body, 4, document.body, 5], node foreignDoctype -PASS 15,0: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node paras[0] -PASS 15,0: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node paras[0] -PASS 15,1: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node paras[0].firstChild -PASS 15,1: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node paras[0].firstChild -PASS 15,2: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node paras[1].firstChild -PASS 15,2: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node paras[1].firstChild -PASS 15,3: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignPara1 -PASS 15,3: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignPara1 -PASS 15,4: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignPara1.firstChild -PASS 15,4: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignPara1.firstChild -PASS 15,5: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedPara1 -PASS 15,5: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedPara1 -PASS 15,6: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedPara1.firstChild -PASS 15,6: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedPara1.firstChild -PASS 15,7: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node document -PASS 15,7: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node document -PASS 15,8: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedDiv -PASS 15,8: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedDiv -PASS 15,9: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignDoc -PASS 15,9: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignDoc -PASS 15,10: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignPara2 -PASS 15,10: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignPara2 -PASS 15,11: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node xmlDoc -PASS 15,11: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node xmlDoc -PASS 15,12: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node xmlElement -PASS 15,12: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node xmlElement -PASS 15,13: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedTextNode -PASS 15,13: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedTextNode -PASS 15,14: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignTextNode -PASS 15,14: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignTextNode -PASS 15,15: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node processingInstruction -PASS 15,15: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node processingInstruction -PASS 15,16: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedProcessingInstruction -PASS 15,16: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedProcessingInstruction -PASS 15,17: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node comment -PASS 15,17: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node comment -PASS 15,18: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedComment -PASS 15,18: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node detachedComment -PASS 15,19: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node docfrag -PASS 15,19: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node docfrag -PASS 15,20: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node doctype -PASS 15,20: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node doctype -PASS 15,21: resulting DOM for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignDoctype -PASS 15,21: resulting range position for range [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node foreignDoctype -PASS 16,0: resulting DOM for range [paras[0], 0, paras[0], 1], node paras[0] -PASS 16,0: resulting range position for range [paras[0], 0, paras[0], 1], node paras[0] -PASS 16,1: resulting DOM for range [paras[0], 0, paras[0], 1], node paras[0].firstChild -PASS 16,1: resulting range position for range [paras[0], 0, paras[0], 1], node paras[0].firstChild -PASS 16,2: resulting DOM for range [paras[0], 0, paras[0], 1], node paras[1].firstChild -PASS 16,2: resulting range position for range [paras[0], 0, paras[0], 1], node paras[1].firstChild -PASS 16,3: resulting DOM for range [paras[0], 0, paras[0], 1], node foreignPara1 -PASS 16,3: resulting range position for range [paras[0], 0, paras[0], 1], node foreignPara1 -PASS 16,4: resulting DOM for range [paras[0], 0, paras[0], 1], node foreignPara1.firstChild -PASS 16,4: resulting range position for range [paras[0], 0, paras[0], 1], node foreignPara1.firstChild -PASS 16,5: resulting DOM for range [paras[0], 0, paras[0], 1], node detachedPara1 -PASS 16,5: resulting range position for range [paras[0], 0, paras[0], 1], node detachedPara1 -PASS 16,6: resulting DOM for range [paras[0], 0, paras[0], 1], node detachedPara1.firstChild -PASS 16,6: resulting range position for range [paras[0], 0, paras[0], 1], node detachedPara1.firstChild -PASS 16,7: resulting DOM for range [paras[0], 0, paras[0], 1], node document -PASS 16,7: resulting range position for range [paras[0], 0, paras[0], 1], node document -PASS 16,8: resulting DOM for range [paras[0], 0, paras[0], 1], node detachedDiv -PASS 16,8: resulting range position for range [paras[0], 0, paras[0], 1], node detachedDiv -PASS 16,9: resulting DOM for range [paras[0], 0, paras[0], 1], node foreignDoc -PASS 16,9: resulting range position for range [paras[0], 0, paras[0], 1], node foreignDoc -PASS 16,10: resulting DOM for range [paras[0], 0, paras[0], 1], node foreignPara2 -PASS 16,10: resulting range position for range [paras[0], 0, paras[0], 1], node foreignPara2 -PASS 16,11: resulting DOM for range [paras[0], 0, paras[0], 1], node xmlDoc -PASS 16,11: resulting range position for range [paras[0], 0, paras[0], 1], node xmlDoc -PASS 16,12: resulting DOM for range [paras[0], 0, paras[0], 1], node xmlElement -PASS 16,12: resulting range position for range [paras[0], 0, paras[0], 1], node xmlElement -PASS 16,13: resulting DOM for range [paras[0], 0, paras[0], 1], node detachedTextNode -PASS 16,13: resulting range position for range [paras[0], 0, paras[0], 1], node detachedTextNode -PASS 16,14: resulting DOM for range [paras[0], 0, paras[0], 1], node foreignTextNode -PASS 16,14: resulting range position for range [paras[0], 0, paras[0], 1], node foreignTextNode -PASS 16,15: resulting DOM for range [paras[0], 0, paras[0], 1], node processingInstruction -PASS 16,15: resulting range position for range [paras[0], 0, paras[0], 1], node processingInstruction -PASS 16,16: resulting DOM for range [paras[0], 0, paras[0], 1], node detachedProcessingInstruction -PASS 16,16: resulting range position for range [paras[0], 0, paras[0], 1], node detachedProcessingInstruction -PASS 16,17: resulting DOM for range [paras[0], 0, paras[0], 1], node comment -PASS 16,17: resulting range position for range [paras[0], 0, paras[0], 1], node comment -PASS 16,18: resulting DOM for range [paras[0], 0, paras[0], 1], node detachedComment -PASS 16,18: resulting range position for range [paras[0], 0, paras[0], 1], node detachedComment -PASS 16,19: resulting DOM for range [paras[0], 0, paras[0], 1], node docfrag -PASS 16,19: resulting range position for range [paras[0], 0, paras[0], 1], node docfrag -PASS 16,20: resulting DOM for range [paras[0], 0, paras[0], 1], node doctype -PASS 16,20: resulting range position for range [paras[0], 0, paras[0], 1], node doctype -PASS 16,21: resulting DOM for range [paras[0], 0, paras[0], 1], node foreignDoctype -PASS 16,21: resulting range position for range [paras[0], 0, paras[0], 1], node foreignDoctype -PASS 17,0: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node paras[0] -PASS 17,0: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node paras[0] -PASS 17,1: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node paras[0].firstChild -PASS 17,1: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node paras[0].firstChild -PASS 17,2: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node paras[1].firstChild -PASS 17,2: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node paras[1].firstChild -PASS 17,3: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node foreignPara1 -PASS 17,3: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node foreignPara1 -PASS 17,4: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node foreignPara1.firstChild -PASS 17,4: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node foreignPara1.firstChild -PASS 17,5: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node detachedPara1 -PASS 17,5: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node detachedPara1 -PASS 17,6: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node detachedPara1.firstChild -PASS 17,6: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node detachedPara1.firstChild -PASS 17,7: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node document -PASS 17,7: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node document -PASS 17,8: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node detachedDiv -PASS 17,8: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node detachedDiv -PASS 17,9: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node foreignDoc -PASS 17,9: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node foreignDoc -PASS 17,10: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node foreignPara2 -PASS 17,10: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node foreignPara2 -PASS 17,11: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node xmlDoc -PASS 17,11: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node xmlDoc -PASS 17,12: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node xmlElement -PASS 17,12: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node xmlElement -PASS 17,13: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node detachedTextNode -PASS 17,13: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node detachedTextNode -PASS 17,14: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node foreignTextNode -PASS 17,14: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node foreignTextNode -PASS 17,15: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node processingInstruction -PASS 17,15: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node processingInstruction -PASS 17,16: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node detachedProcessingInstruction -PASS 17,16: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node detachedProcessingInstruction -PASS 17,17: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node comment -PASS 17,17: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node comment -PASS 17,18: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node detachedComment -PASS 17,18: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node detachedComment -PASS 17,19: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node docfrag -PASS 17,19: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node docfrag -PASS 17,20: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node doctype -PASS 17,20: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node doctype -PASS 17,21: resulting DOM for range [detachedPara1, 0, detachedPara1, 1], node foreignDoctype -PASS 17,21: resulting range position for range [detachedPara1, 0, detachedPara1, 1], node foreignDoctype -PASS 18,0: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node paras[0] -PASS 18,0: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node paras[0] -PASS 18,1: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node paras[0].firstChild -PASS 18,1: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node paras[0].firstChild -PASS 18,2: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node paras[1].firstChild -PASS 18,2: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node paras[1].firstChild -PASS 18,3: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignPara1 -PASS 18,3: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignPara1 -PASS 18,4: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignPara1.firstChild -PASS 18,4: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignPara1.firstChild -PASS 18,5: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedPara1 -PASS 18,5: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedPara1 -PASS 18,6: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedPara1.firstChild -PASS 18,6: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedPara1.firstChild -PASS 18,7: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node document -PASS 18,7: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node document -PASS 18,8: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedDiv -PASS 18,8: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedDiv -PASS 18,9: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignDoc -PASS 18,9: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignDoc -PASS 18,10: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignPara2 -PASS 18,10: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignPara2 -PASS 18,11: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node xmlDoc -PASS 18,11: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node xmlDoc -PASS 18,12: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node xmlElement -PASS 18,12: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node xmlElement -PASS 18,13: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedTextNode -PASS 18,13: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedTextNode -PASS 18,14: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignTextNode -PASS 18,14: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignTextNode -PASS 18,15: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node processingInstruction -PASS 18,15: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node processingInstruction -PASS 18,16: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedProcessingInstruction -PASS 18,16: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedProcessingInstruction -PASS 18,17: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node comment -PASS 18,17: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node comment -PASS 18,18: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedComment -PASS 18,18: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node detachedComment -PASS 18,19: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node docfrag -PASS 18,19: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node docfrag -PASS 18,20: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node doctype -PASS 18,20: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node doctype -PASS 18,21: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignDoctype -PASS 18,21: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 0], node foreignDoctype -PASS 19,0: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node paras[0] -PASS 19,0: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node paras[0] -PASS 19,1: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node paras[0].firstChild -PASS 19,1: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node paras[0].firstChild -PASS 19,2: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node paras[1].firstChild -PASS 19,2: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node paras[1].firstChild -PASS 19,3: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignPara1 -PASS 19,3: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignPara1 -PASS 19,4: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignPara1.firstChild -PASS 19,4: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignPara1.firstChild -PASS 19,5: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedPara1 -PASS 19,5: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedPara1 -PASS 19,6: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedPara1.firstChild -PASS 19,6: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedPara1.firstChild -PASS 19,7: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node document -PASS 19,7: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node document -PASS 19,8: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedDiv -PASS 19,8: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedDiv -PASS 19,9: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignDoc -PASS 19,9: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignDoc -PASS 19,10: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignPara2 -PASS 19,10: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignPara2 -PASS 19,11: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node xmlDoc -PASS 19,11: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node xmlDoc -PASS 19,12: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node xmlElement -PASS 19,12: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node xmlElement -PASS 19,13: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedTextNode -PASS 19,13: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedTextNode -PASS 19,14: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignTextNode -PASS 19,14: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignTextNode -PASS 19,15: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node processingInstruction -PASS 19,15: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node processingInstruction -PASS 19,16: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedProcessingInstruction -PASS 19,16: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedProcessingInstruction -PASS 19,17: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node comment -PASS 19,17: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node comment -PASS 19,18: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedComment -PASS 19,18: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node detachedComment -PASS 19,19: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node docfrag -PASS 19,19: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node docfrag -PASS 19,20: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node doctype -PASS 19,20: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node doctype -PASS 19,21: resulting DOM for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignDoctype -PASS 19,21: resulting range position for range [paras[0].firstChild, 0, paras[1].firstChild, 8], node foreignDoctype -PASS 20,0: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node paras[0] -PASS 20,0: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node paras[0] -PASS 20,1: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node paras[0].firstChild -PASS 20,1: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node paras[0].firstChild -PASS 20,2: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node paras[1].firstChild -PASS 20,2: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node paras[1].firstChild -PASS 20,3: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node foreignPara1 -PASS 20,3: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node foreignPara1 -PASS 20,4: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node foreignPara1.firstChild -PASS 20,4: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node foreignPara1.firstChild -PASS 20,5: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node detachedPara1 -PASS 20,5: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node detachedPara1 -PASS 20,6: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node detachedPara1.firstChild -PASS 20,6: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node detachedPara1.firstChild -PASS 20,7: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node document -PASS 20,7: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node document -PASS 20,8: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node detachedDiv -PASS 20,8: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node detachedDiv -PASS 20,9: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node foreignDoc -PASS 20,9: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node foreignDoc -PASS 20,10: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node foreignPara2 -PASS 20,10: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node foreignPara2 -PASS 20,11: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node xmlDoc -PASS 20,11: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node xmlDoc -PASS 20,12: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node xmlElement -PASS 20,12: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node xmlElement -PASS 20,13: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node detachedTextNode -PASS 20,13: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node detachedTextNode -PASS 20,14: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node foreignTextNode -PASS 20,14: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node foreignTextNode -PASS 20,15: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node processingInstruction -PASS 20,15: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node processingInstruction -PASS 20,16: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node detachedProcessingInstruction -PASS 20,16: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node detachedProcessingInstruction -PASS 20,17: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node comment -PASS 20,17: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node comment -PASS 20,18: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node detachedComment -PASS 20,18: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node detachedComment -PASS 20,19: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node docfrag -PASS 20,19: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node docfrag -PASS 20,20: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node doctype -PASS 20,20: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node doctype -PASS 20,21: resulting DOM for range [paras[0].firstChild, 3, paras[3], 1], node foreignDoctype -PASS 20,21: resulting range position for range [paras[0].firstChild, 3, paras[3], 1], node foreignDoctype -PASS 21,0: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node paras[0] -PASS 21,0: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node paras[0] -PASS 21,1: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node paras[0].firstChild -FAIL 21,1: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node paras[0].firstChild assert_equals: Unexpected endOffset after insertNode() expected 1 but got 7 -PASS 21,2: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node paras[1].firstChild -PASS 21,2: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node paras[1].firstChild -PASS 21,3: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node foreignPara1 -PASS 21,3: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node foreignPara1 -PASS 21,4: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node foreignPara1.firstChild -PASS 21,4: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node foreignPara1.firstChild -PASS 21,5: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node detachedPara1 -PASS 21,5: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node detachedPara1 -PASS 21,6: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node detachedPara1.firstChild -PASS 21,6: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node detachedPara1.firstChild -PASS 21,7: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node document -PASS 21,7: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node document -PASS 21,8: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node detachedDiv -PASS 21,8: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node detachedDiv -PASS 21,9: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node foreignDoc -PASS 21,9: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node foreignDoc -PASS 21,10: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node foreignPara2 -PASS 21,10: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node foreignPara2 -PASS 21,11: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node xmlDoc -PASS 21,11: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node xmlDoc -PASS 21,12: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node xmlElement -PASS 21,12: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node xmlElement -PASS 21,13: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node detachedTextNode -PASS 21,13: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node detachedTextNode -PASS 21,14: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node foreignTextNode -PASS 21,14: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node foreignTextNode -PASS 21,15: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node processingInstruction -PASS 21,15: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node processingInstruction -PASS 21,16: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node detachedProcessingInstruction -PASS 21,16: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node detachedProcessingInstruction -PASS 21,17: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node comment -PASS 21,17: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node comment -PASS 21,18: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node detachedComment -PASS 21,18: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node detachedComment -PASS 21,19: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node docfrag -PASS 21,19: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node docfrag -PASS 21,20: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node doctype -PASS 21,20: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node doctype -PASS 21,21: resulting DOM for range [paras[0], 0, paras[0].firstChild, 7], node foreignDoctype -PASS 21,21: resulting range position for range [paras[0], 0, paras[0].firstChild, 7], node foreignDoctype -PASS 22,0: resulting DOM for range [testDiv, 2, paras[4], 1], node paras[0] -PASS 22,0: resulting range position for range [testDiv, 2, paras[4], 1], node paras[0] -PASS 22,1: resulting DOM for range [testDiv, 2, paras[4], 1], node paras[0].firstChild -PASS 22,1: resulting range position for range [testDiv, 2, paras[4], 1], node paras[0].firstChild -PASS 22,2: resulting DOM for range [testDiv, 2, paras[4], 1], node paras[1].firstChild -PASS 22,2: resulting range position for range [testDiv, 2, paras[4], 1], node paras[1].firstChild -PASS 22,3: resulting DOM for range [testDiv, 2, paras[4], 1], node foreignPara1 -PASS 22,3: resulting range position for range [testDiv, 2, paras[4], 1], node foreignPara1 -PASS 22,4: resulting DOM for range [testDiv, 2, paras[4], 1], node foreignPara1.firstChild -PASS 22,4: resulting range position for range [testDiv, 2, paras[4], 1], node foreignPara1.firstChild -PASS 22,5: resulting DOM for range [testDiv, 2, paras[4], 1], node detachedPara1 -PASS 22,5: resulting range position for range [testDiv, 2, paras[4], 1], node detachedPara1 -PASS 22,6: resulting DOM for range [testDiv, 2, paras[4], 1], node detachedPara1.firstChild -PASS 22,6: resulting range position for range [testDiv, 2, paras[4], 1], node detachedPara1.firstChild -PASS 22,7: resulting DOM for range [testDiv, 2, paras[4], 1], node document -PASS 22,7: resulting range position for range [testDiv, 2, paras[4], 1], node document -PASS 22,8: resulting DOM for range [testDiv, 2, paras[4], 1], node detachedDiv -PASS 22,8: resulting range position for range [testDiv, 2, paras[4], 1], node detachedDiv -PASS 22,9: resulting DOM for range [testDiv, 2, paras[4], 1], node foreignDoc -PASS 22,9: resulting range position for range [testDiv, 2, paras[4], 1], node foreignDoc -PASS 22,10: resulting DOM for range [testDiv, 2, paras[4], 1], node foreignPara2 -PASS 22,10: resulting range position for range [testDiv, 2, paras[4], 1], node foreignPara2 -PASS 22,11: resulting DOM for range [testDiv, 2, paras[4], 1], node xmlDoc -PASS 22,11: resulting range position for range [testDiv, 2, paras[4], 1], node xmlDoc -PASS 22,12: resulting DOM for range [testDiv, 2, paras[4], 1], node xmlElement -PASS 22,12: resulting range position for range [testDiv, 2, paras[4], 1], node xmlElement -PASS 22,13: resulting DOM for range [testDiv, 2, paras[4], 1], node detachedTextNode -PASS 22,13: resulting range position for range [testDiv, 2, paras[4], 1], node detachedTextNode -PASS 22,14: resulting DOM for range [testDiv, 2, paras[4], 1], node foreignTextNode -PASS 22,14: resulting range position for range [testDiv, 2, paras[4], 1], node foreignTextNode -PASS 22,15: resulting DOM for range [testDiv, 2, paras[4], 1], node processingInstruction -PASS 22,15: resulting range position for range [testDiv, 2, paras[4], 1], node processingInstruction -PASS 22,16: resulting DOM for range [testDiv, 2, paras[4], 1], node detachedProcessingInstruction -PASS 22,16: resulting range position for range [testDiv, 2, paras[4], 1], node detachedProcessingInstruction -PASS 22,17: resulting DOM for range [testDiv, 2, paras[4], 1], node comment -PASS 22,17: resulting range position for range [testDiv, 2, paras[4], 1], node comment -PASS 22,18: resulting DOM for range [testDiv, 2, paras[4], 1], node detachedComment -PASS 22,18: resulting range position for range [testDiv, 2, paras[4], 1], node detachedComment -PASS 22,19: resulting DOM for range [testDiv, 2, paras[4], 1], node docfrag -PASS 22,19: resulting range position for range [testDiv, 2, paras[4], 1], node docfrag -PASS 22,20: resulting DOM for range [testDiv, 2, paras[4], 1], node doctype -PASS 22,20: resulting range position for range [testDiv, 2, paras[4], 1], node doctype -PASS 22,21: resulting DOM for range [testDiv, 2, paras[4], 1], node foreignDoctype -PASS 22,21: resulting range position for range [testDiv, 2, paras[4], 1], node foreignDoctype -PASS 23,0: resulting DOM for range [document, 0, document, 1], node paras[0] -PASS 23,0: resulting range position for range [document, 0, document, 1], node paras[0] -PASS 23,1: resulting DOM for range [document, 0, document, 1], node paras[0].firstChild -PASS 23,1: resulting range position for range [document, 0, document, 1], node paras[0].firstChild -PASS 23,2: resulting DOM for range [document, 0, document, 1], node paras[1].firstChild -PASS 23,2: resulting range position for range [document, 0, document, 1], node paras[1].firstChild -PASS 23,3: resulting DOM for range [document, 0, document, 1], node foreignPara1 -PASS 23,3: resulting range position for range [document, 0, document, 1], node foreignPara1 -PASS 23,4: resulting DOM for range [document, 0, document, 1], node foreignPara1.firstChild -PASS 23,4: resulting range position for range [document, 0, document, 1], node foreignPara1.firstChild -PASS 23,5: resulting DOM for range [document, 0, document, 1], node detachedPara1 -PASS 23,5: resulting range position for range [document, 0, document, 1], node detachedPara1 -PASS 23,6: resulting DOM for range [document, 0, document, 1], node detachedPara1.firstChild -PASS 23,6: resulting range position for range [document, 0, document, 1], node detachedPara1.firstChild -PASS 23,7: resulting DOM for range [document, 0, document, 1], node document -PASS 23,7: resulting range position for range [document, 0, document, 1], node document -PASS 23,8: resulting DOM for range [document, 0, document, 1], node detachedDiv -PASS 23,8: resulting range position for range [document, 0, document, 1], node detachedDiv -PASS 23,9: resulting DOM for range [document, 0, document, 1], node foreignDoc -PASS 23,9: resulting range position for range [document, 0, document, 1], node foreignDoc -PASS 23,10: resulting DOM for range [document, 0, document, 1], node foreignPara2 -PASS 23,10: resulting range position for range [document, 0, document, 1], node foreignPara2 -PASS 23,11: resulting DOM for range [document, 0, document, 1], node xmlDoc -PASS 23,11: resulting range position for range [document, 0, document, 1], node xmlDoc -PASS 23,12: resulting DOM for range [document, 0, document, 1], node xmlElement -PASS 23,12: resulting range position for range [document, 0, document, 1], node xmlElement -PASS 23,13: resulting DOM for range [document, 0, document, 1], node detachedTextNode -PASS 23,13: resulting range position for range [document, 0, document, 1], node detachedTextNode -PASS 23,14: resulting DOM for range [document, 0, document, 1], node foreignTextNode -PASS 23,14: resulting range position for range [document, 0, document, 1], node foreignTextNode -PASS 23,15: resulting DOM for range [document, 0, document, 1], node processingInstruction -PASS 23,15: resulting range position for range [document, 0, document, 1], node processingInstruction -PASS 23,16: resulting DOM for range [document, 0, document, 1], node detachedProcessingInstruction -PASS 23,16: resulting range position for range [document, 0, document, 1], node detachedProcessingInstruction -PASS 23,17: resulting DOM for range [document, 0, document, 1], node comment -PASS 23,17: resulting range position for range [document, 0, document, 1], node comment -PASS 23,18: resulting DOM for range [document, 0, document, 1], node detachedComment -PASS 23,18: resulting range position for range [document, 0, document, 1], node detachedComment -PASS 23,19: resulting DOM for range [document, 0, document, 1], node docfrag -PASS 23,19: resulting range position for range [document, 0, document, 1], node docfrag -PASS 23,20: resulting DOM for range [document, 0, document, 1], node doctype -PASS 23,20: resulting range position for range [document, 0, document, 1], node doctype -PASS 23,21: resulting DOM for range [document, 0, document, 1], node foreignDoctype -PASS 23,21: resulting range position for range [document, 0, document, 1], node foreignDoctype -PASS 24,0: resulting DOM for range [document, 0, document, 2], node paras[0] -PASS 24,0: resulting range position for range [document, 0, document, 2], node paras[0] -PASS 24,1: resulting DOM for range [document, 0, document, 2], node paras[0].firstChild -PASS 24,1: resulting range position for range [document, 0, document, 2], node paras[0].firstChild -PASS 24,2: resulting DOM for range [document, 0, document, 2], node paras[1].firstChild -PASS 24,2: resulting range position for range [document, 0, document, 2], node paras[1].firstChild -PASS 24,3: resulting DOM for range [document, 0, document, 2], node foreignPara1 -PASS 24,3: resulting range position for range [document, 0, document, 2], node foreignPara1 -PASS 24,4: resulting DOM for range [document, 0, document, 2], node foreignPara1.firstChild -PASS 24,4: resulting range position for range [document, 0, document, 2], node foreignPara1.firstChild -PASS 24,5: resulting DOM for range [document, 0, document, 2], node detachedPara1 -PASS 24,5: resulting range position for range [document, 0, document, 2], node detachedPara1 -PASS 24,6: resulting DOM for range [document, 0, document, 2], node detachedPara1.firstChild -PASS 24,6: resulting range position for range [document, 0, document, 2], node detachedPara1.firstChild -PASS 24,7: resulting DOM for range [document, 0, document, 2], node document -PASS 24,7: resulting range position for range [document, 0, document, 2], node document -PASS 24,8: resulting DOM for range [document, 0, document, 2], node detachedDiv -PASS 24,8: resulting range position for range [document, 0, document, 2], node detachedDiv -PASS 24,9: resulting DOM for range [document, 0, document, 2], node foreignDoc -PASS 24,9: resulting range position for range [document, 0, document, 2], node foreignDoc -PASS 24,10: resulting DOM for range [document, 0, document, 2], node foreignPara2 -PASS 24,10: resulting range position for range [document, 0, document, 2], node foreignPara2 -PASS 24,11: resulting DOM for range [document, 0, document, 2], node xmlDoc -PASS 24,11: resulting range position for range [document, 0, document, 2], node xmlDoc -PASS 24,12: resulting DOM for range [document, 0, document, 2], node xmlElement -PASS 24,12: resulting range position for range [document, 0, document, 2], node xmlElement -PASS 24,13: resulting DOM for range [document, 0, document, 2], node detachedTextNode -PASS 24,13: resulting range position for range [document, 0, document, 2], node detachedTextNode -PASS 24,14: resulting DOM for range [document, 0, document, 2], node foreignTextNode -PASS 24,14: resulting range position for range [document, 0, document, 2], node foreignTextNode -PASS 24,15: resulting DOM for range [document, 0, document, 2], node processingInstruction -PASS 24,15: resulting range position for range [document, 0, document, 2], node processingInstruction -PASS 24,16: resulting DOM for range [document, 0, document, 2], node detachedProcessingInstruction -PASS 24,16: resulting range position for range [document, 0, document, 2], node detachedProcessingInstruction -PASS 24,17: resulting DOM for range [document, 0, document, 2], node comment -PASS 24,17: resulting range position for range [document, 0, document, 2], node comment -PASS 24,18: resulting DOM for range [document, 0, document, 2], node detachedComment -PASS 24,18: resulting range position for range [document, 0, document, 2], node detachedComment -PASS 24,19: resulting DOM for range [document, 0, document, 2], node docfrag -PASS 24,19: resulting range position for range [document, 0, document, 2], node docfrag -PASS 24,20: resulting DOM for range [document, 0, document, 2], node doctype -PASS 24,20: resulting range position for range [document, 0, document, 2], node doctype -PASS 24,21: resulting DOM for range [document, 0, document, 2], node foreignDoctype -PASS 24,21: resulting range position for range [document, 0, document, 2], node foreignDoctype -PASS 25,0: resulting DOM for range [comment, 2, comment, 3], node paras[0] -PASS 25,0: resulting range position for range [comment, 2, comment, 3], node paras[0] -PASS 25,1: resulting DOM for range [comment, 2, comment, 3], node paras[0].firstChild -PASS 25,1: resulting range position for range [comment, 2, comment, 3], node paras[0].firstChild -PASS 25,2: resulting DOM for range [comment, 2, comment, 3], node paras[1].firstChild -PASS 25,2: resulting range position for range [comment, 2, comment, 3], node paras[1].firstChild -PASS 25,3: resulting DOM for range [comment, 2, comment, 3], node foreignPara1 -PASS 25,3: resulting range position for range [comment, 2, comment, 3], node foreignPara1 -PASS 25,4: resulting DOM for range [comment, 2, comment, 3], node foreignPara1.firstChild -PASS 25,4: resulting range position for range [comment, 2, comment, 3], node foreignPara1.firstChild -PASS 25,5: resulting DOM for range [comment, 2, comment, 3], node detachedPara1 -PASS 25,5: resulting range position for range [comment, 2, comment, 3], node detachedPara1 -PASS 25,6: resulting DOM for range [comment, 2, comment, 3], node detachedPara1.firstChild -PASS 25,6: resulting range position for range [comment, 2, comment, 3], node detachedPara1.firstChild -PASS 25,7: resulting DOM for range [comment, 2, comment, 3], node document -PASS 25,7: resulting range position for range [comment, 2, comment, 3], node document -PASS 25,8: resulting DOM for range [comment, 2, comment, 3], node detachedDiv -PASS 25,8: resulting range position for range [comment, 2, comment, 3], node detachedDiv -PASS 25,9: resulting DOM for range [comment, 2, comment, 3], node foreignDoc -PASS 25,9: resulting range position for range [comment, 2, comment, 3], node foreignDoc -PASS 25,10: resulting DOM for range [comment, 2, comment, 3], node foreignPara2 -PASS 25,10: resulting range position for range [comment, 2, comment, 3], node foreignPara2 -PASS 25,11: resulting DOM for range [comment, 2, comment, 3], node xmlDoc -PASS 25,11: resulting range position for range [comment, 2, comment, 3], node xmlDoc -PASS 25,12: resulting DOM for range [comment, 2, comment, 3], node xmlElement -PASS 25,12: resulting range position for range [comment, 2, comment, 3], node xmlElement -PASS 25,13: resulting DOM for range [comment, 2, comment, 3], node detachedTextNode -PASS 25,13: resulting range position for range [comment, 2, comment, 3], node detachedTextNode -PASS 25,14: resulting DOM for range [comment, 2, comment, 3], node foreignTextNode -PASS 25,14: resulting range position for range [comment, 2, comment, 3], node foreignTextNode -PASS 25,15: resulting DOM for range [comment, 2, comment, 3], node processingInstruction -PASS 25,15: resulting range position for range [comment, 2, comment, 3], node processingInstruction -PASS 25,16: resulting DOM for range [comment, 2, comment, 3], node detachedProcessingInstruction -PASS 25,16: resulting range position for range [comment, 2, comment, 3], node detachedProcessingInstruction -PASS 25,17: resulting DOM for range [comment, 2, comment, 3], node comment -PASS 25,17: resulting range position for range [comment, 2, comment, 3], node comment -PASS 25,18: resulting DOM for range [comment, 2, comment, 3], node detachedComment -PASS 25,18: resulting range position for range [comment, 2, comment, 3], node detachedComment -PASS 25,19: resulting DOM for range [comment, 2, comment, 3], node docfrag -PASS 25,19: resulting range position for range [comment, 2, comment, 3], node docfrag -PASS 25,20: resulting DOM for range [comment, 2, comment, 3], node doctype -PASS 25,20: resulting range position for range [comment, 2, comment, 3], node doctype -PASS 25,21: resulting DOM for range [comment, 2, comment, 3], node foreignDoctype -PASS 25,21: resulting range position for range [comment, 2, comment, 3], node foreignDoctype -PASS 26,0: resulting DOM for range [testDiv, 0, comment, 5], node paras[0] -PASS 26,0: resulting range position for range [testDiv, 0, comment, 5], node paras[0] -PASS 26,1: resulting DOM for range [testDiv, 0, comment, 5], node paras[0].firstChild -PASS 26,1: resulting range position for range [testDiv, 0, comment, 5], node paras[0].firstChild -PASS 26,2: resulting DOM for range [testDiv, 0, comment, 5], node paras[1].firstChild -PASS 26,2: resulting range position for range [testDiv, 0, comment, 5], node paras[1].firstChild -PASS 26,3: resulting DOM for range [testDiv, 0, comment, 5], node foreignPara1 -PASS 26,3: resulting range position for range [testDiv, 0, comment, 5], node foreignPara1 -PASS 26,4: resulting DOM for range [testDiv, 0, comment, 5], node foreignPara1.firstChild -PASS 26,4: resulting range position for range [testDiv, 0, comment, 5], node foreignPara1.firstChild -PASS 26,5: resulting DOM for range [testDiv, 0, comment, 5], node detachedPara1 -PASS 26,5: resulting range position for range [testDiv, 0, comment, 5], node detachedPara1 -PASS 26,6: resulting DOM for range [testDiv, 0, comment, 5], node detachedPara1.firstChild -PASS 26,6: resulting range position for range [testDiv, 0, comment, 5], node detachedPara1.firstChild -PASS 26,7: resulting DOM for range [testDiv, 0, comment, 5], node document -PASS 26,7: resulting range position for range [testDiv, 0, comment, 5], node document -PASS 26,8: resulting DOM for range [testDiv, 0, comment, 5], node detachedDiv -PASS 26,8: resulting range position for range [testDiv, 0, comment, 5], node detachedDiv -PASS 26,9: resulting DOM for range [testDiv, 0, comment, 5], node foreignDoc -PASS 26,9: resulting range position for range [testDiv, 0, comment, 5], node foreignDoc -PASS 26,10: resulting DOM for range [testDiv, 0, comment, 5], node foreignPara2 -PASS 26,10: resulting range position for range [testDiv, 0, comment, 5], node foreignPara2 -PASS 26,11: resulting DOM for range [testDiv, 0, comment, 5], node xmlDoc -PASS 26,11: resulting range position for range [testDiv, 0, comment, 5], node xmlDoc -PASS 26,12: resulting DOM for range [testDiv, 0, comment, 5], node xmlElement -PASS 26,12: resulting range position for range [testDiv, 0, comment, 5], node xmlElement -PASS 26,13: resulting DOM for range [testDiv, 0, comment, 5], node detachedTextNode -PASS 26,13: resulting range position for range [testDiv, 0, comment, 5], node detachedTextNode -PASS 26,14: resulting DOM for range [testDiv, 0, comment, 5], node foreignTextNode -PASS 26,14: resulting range position for range [testDiv, 0, comment, 5], node foreignTextNode -PASS 26,15: resulting DOM for range [testDiv, 0, comment, 5], node processingInstruction -PASS 26,15: resulting range position for range [testDiv, 0, comment, 5], node processingInstruction -PASS 26,16: resulting DOM for range [testDiv, 0, comment, 5], node detachedProcessingInstruction -PASS 26,16: resulting range position for range [testDiv, 0, comment, 5], node detachedProcessingInstruction -PASS 26,17: resulting DOM for range [testDiv, 0, comment, 5], node comment -PASS 26,17: resulting range position for range [testDiv, 0, comment, 5], node comment -PASS 26,18: resulting DOM for range [testDiv, 0, comment, 5], node detachedComment -PASS 26,18: resulting range position for range [testDiv, 0, comment, 5], node detachedComment -PASS 26,19: resulting DOM for range [testDiv, 0, comment, 5], node docfrag -PASS 26,19: resulting range position for range [testDiv, 0, comment, 5], node docfrag -PASS 26,20: resulting DOM for range [testDiv, 0, comment, 5], node doctype -PASS 26,20: resulting range position for range [testDiv, 0, comment, 5], node doctype -PASS 26,21: resulting DOM for range [testDiv, 0, comment, 5], node foreignDoctype -PASS 26,21: resulting range position for range [testDiv, 0, comment, 5], node foreignDoctype -PASS 27,0: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node paras[0] -PASS 27,0: resulting range position for range [foreignDoc, 1, foreignComment, 2], node paras[0] -PASS 27,1: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node paras[0].firstChild -PASS 27,1: resulting range position for range [foreignDoc, 1, foreignComment, 2], node paras[0].firstChild -PASS 27,2: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node paras[1].firstChild -PASS 27,2: resulting range position for range [foreignDoc, 1, foreignComment, 2], node paras[1].firstChild -PASS 27,3: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node foreignPara1 -PASS 27,3: resulting range position for range [foreignDoc, 1, foreignComment, 2], node foreignPara1 -PASS 27,4: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node foreignPara1.firstChild -PASS 27,4: resulting range position for range [foreignDoc, 1, foreignComment, 2], node foreignPara1.firstChild -PASS 27,5: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node detachedPara1 -PASS 27,5: resulting range position for range [foreignDoc, 1, foreignComment, 2], node detachedPara1 -PASS 27,6: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node detachedPara1.firstChild -PASS 27,6: resulting range position for range [foreignDoc, 1, foreignComment, 2], node detachedPara1.firstChild -PASS 27,7: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node document -PASS 27,7: resulting range position for range [foreignDoc, 1, foreignComment, 2], node document -PASS 27,8: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node detachedDiv -PASS 27,8: resulting range position for range [foreignDoc, 1, foreignComment, 2], node detachedDiv -PASS 27,9: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node foreignDoc -PASS 27,9: resulting range position for range [foreignDoc, 1, foreignComment, 2], node foreignDoc -PASS 27,10: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node foreignPara2 -PASS 27,10: resulting range position for range [foreignDoc, 1, foreignComment, 2], node foreignPara2 -PASS 27,11: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node xmlDoc -PASS 27,11: resulting range position for range [foreignDoc, 1, foreignComment, 2], node xmlDoc -PASS 27,12: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node xmlElement -PASS 27,12: resulting range position for range [foreignDoc, 1, foreignComment, 2], node xmlElement -PASS 27,13: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node detachedTextNode -PASS 27,13: resulting range position for range [foreignDoc, 1, foreignComment, 2], node detachedTextNode -PASS 27,14: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node foreignTextNode -PASS 27,14: resulting range position for range [foreignDoc, 1, foreignComment, 2], node foreignTextNode -PASS 27,15: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node processingInstruction -PASS 27,15: resulting range position for range [foreignDoc, 1, foreignComment, 2], node processingInstruction -PASS 27,16: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node detachedProcessingInstruction -PASS 27,16: resulting range position for range [foreignDoc, 1, foreignComment, 2], node detachedProcessingInstruction -PASS 27,17: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node comment -PASS 27,17: resulting range position for range [foreignDoc, 1, foreignComment, 2], node comment -PASS 27,18: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node detachedComment -PASS 27,18: resulting range position for range [foreignDoc, 1, foreignComment, 2], node detachedComment -PASS 27,19: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node docfrag -PASS 27,19: resulting range position for range [foreignDoc, 1, foreignComment, 2], node docfrag -PASS 27,20: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node doctype -PASS 27,20: resulting range position for range [foreignDoc, 1, foreignComment, 2], node doctype -PASS 27,21: resulting DOM for range [foreignDoc, 1, foreignComment, 2], node foreignDoctype -PASS 27,21: resulting range position for range [foreignDoc, 1, foreignComment, 2], node foreignDoctype -PASS 28,0: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node paras[0] -PASS 28,0: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node paras[0] -PASS 28,1: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node paras[0].firstChild -PASS 28,1: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node paras[0].firstChild -PASS 28,2: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node paras[1].firstChild -PASS 28,2: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node paras[1].firstChild -PASS 28,3: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignPara1 -PASS 28,3: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignPara1 -PASS 28,4: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignPara1.firstChild -PASS 28,4: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignPara1.firstChild -PASS 28,5: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedPara1 -PASS 28,5: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedPara1 -PASS 28,6: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedPara1.firstChild -PASS 28,6: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedPara1.firstChild -PASS 28,7: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node document -PASS 28,7: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node document -PASS 28,8: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedDiv -PASS 28,8: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedDiv -PASS 28,9: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignDoc -PASS 28,9: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignDoc -PASS 28,10: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignPara2 -PASS 28,10: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignPara2 -PASS 28,11: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node xmlDoc -PASS 28,11: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node xmlDoc -PASS 28,12: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node xmlElement -PASS 28,12: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node xmlElement -PASS 28,13: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedTextNode -PASS 28,13: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedTextNode -PASS 28,14: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignTextNode -PASS 28,14: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignTextNode -PASS 28,15: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node processingInstruction -PASS 28,15: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node processingInstruction -PASS 28,16: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedProcessingInstruction -PASS 28,16: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedProcessingInstruction -PASS 28,17: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node comment -PASS 28,17: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node comment -PASS 28,18: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedComment -PASS 28,18: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node detachedComment -PASS 28,19: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node docfrag -PASS 28,19: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node docfrag -PASS 28,20: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node doctype -PASS 28,20: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node doctype -PASS 28,21: resulting DOM for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignDoctype -PASS 28,21: resulting range position for range [foreignDoc.body, 0, foreignTextNode, 36], node foreignDoctype -PASS 29,0: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node paras[0] -PASS 29,0: resulting range position for range [xmlDoc, 1, xmlComment, 0], node paras[0] -PASS 29,1: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node paras[0].firstChild -PASS 29,1: resulting range position for range [xmlDoc, 1, xmlComment, 0], node paras[0].firstChild -PASS 29,2: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node paras[1].firstChild -PASS 29,2: resulting range position for range [xmlDoc, 1, xmlComment, 0], node paras[1].firstChild -PASS 29,3: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node foreignPara1 -PASS 29,3: resulting range position for range [xmlDoc, 1, xmlComment, 0], node foreignPara1 -PASS 29,4: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node foreignPara1.firstChild -PASS 29,4: resulting range position for range [xmlDoc, 1, xmlComment, 0], node foreignPara1.firstChild -PASS 29,5: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node detachedPara1 -PASS 29,5: resulting range position for range [xmlDoc, 1, xmlComment, 0], node detachedPara1 -PASS 29,6: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node detachedPara1.firstChild -PASS 29,6: resulting range position for range [xmlDoc, 1, xmlComment, 0], node detachedPara1.firstChild -PASS 29,7: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node document -PASS 29,7: resulting range position for range [xmlDoc, 1, xmlComment, 0], node document -PASS 29,8: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node detachedDiv -PASS 29,8: resulting range position for range [xmlDoc, 1, xmlComment, 0], node detachedDiv -PASS 29,9: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node foreignDoc -PASS 29,9: resulting range position for range [xmlDoc, 1, xmlComment, 0], node foreignDoc -PASS 29,10: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node foreignPara2 -PASS 29,10: resulting range position for range [xmlDoc, 1, xmlComment, 0], node foreignPara2 -PASS 29,11: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node xmlDoc -PASS 29,11: resulting range position for range [xmlDoc, 1, xmlComment, 0], node xmlDoc -PASS 29,12: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node xmlElement -PASS 29,12: resulting range position for range [xmlDoc, 1, xmlComment, 0], node xmlElement -PASS 29,13: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node detachedTextNode -PASS 29,13: resulting range position for range [xmlDoc, 1, xmlComment, 0], node detachedTextNode -PASS 29,14: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node foreignTextNode -PASS 29,14: resulting range position for range [xmlDoc, 1, xmlComment, 0], node foreignTextNode -PASS 29,15: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node processingInstruction -PASS 29,15: resulting range position for range [xmlDoc, 1, xmlComment, 0], node processingInstruction -PASS 29,16: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node detachedProcessingInstruction -PASS 29,16: resulting range position for range [xmlDoc, 1, xmlComment, 0], node detachedProcessingInstruction -PASS 29,17: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node comment -PASS 29,17: resulting range position for range [xmlDoc, 1, xmlComment, 0], node comment -PASS 29,18: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node detachedComment -PASS 29,18: resulting range position for range [xmlDoc, 1, xmlComment, 0], node detachedComment -PASS 29,19: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node docfrag -PASS 29,19: resulting range position for range [xmlDoc, 1, xmlComment, 0], node docfrag -PASS 29,20: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node doctype -PASS 29,20: resulting range position for range [xmlDoc, 1, xmlComment, 0], node doctype -PASS 29,21: resulting DOM for range [xmlDoc, 1, xmlComment, 0], node foreignDoctype -PASS 29,21: resulting range position for range [xmlDoc, 1, xmlComment, 0], node foreignDoctype -PASS 30,0: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node paras[0] -PASS 30,0: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node paras[0] -PASS 30,1: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node paras[0].firstChild -PASS 30,1: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node paras[0].firstChild -PASS 30,2: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node paras[1].firstChild -PASS 30,2: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node paras[1].firstChild -PASS 30,3: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node foreignPara1 -PASS 30,3: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node foreignPara1 -PASS 30,4: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node foreignPara1.firstChild -PASS 30,4: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node foreignPara1.firstChild -PASS 30,5: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node detachedPara1 -PASS 30,5: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node detachedPara1 -PASS 30,6: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node detachedPara1.firstChild -PASS 30,6: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node detachedPara1.firstChild -PASS 30,7: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node document -PASS 30,7: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node document -PASS 30,8: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node detachedDiv -PASS 30,8: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node detachedDiv -PASS 30,9: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node foreignDoc -PASS 30,9: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node foreignDoc -PASS 30,10: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node foreignPara2 -PASS 30,10: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node foreignPara2 -PASS 30,11: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node xmlDoc -PASS 30,11: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node xmlDoc -PASS 30,12: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node xmlElement -PASS 30,12: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node xmlElement -PASS 30,13: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node detachedTextNode -PASS 30,13: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node detachedTextNode -PASS 30,14: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node foreignTextNode -PASS 30,14: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node foreignTextNode -PASS 30,15: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node processingInstruction -PASS 30,15: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node processingInstruction -PASS 30,16: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node detachedProcessingInstruction -PASS 30,16: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node detachedProcessingInstruction -PASS 30,17: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node comment -PASS 30,17: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node comment -PASS 30,18: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node detachedComment -PASS 30,18: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node detachedComment -PASS 30,19: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node docfrag -PASS 30,19: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node docfrag -PASS 30,20: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node doctype -PASS 30,20: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node doctype -PASS 30,21: resulting DOM for range [detachedTextNode, 0, detachedTextNode, 8], node foreignDoctype -PASS 30,21: resulting range position for range [detachedTextNode, 0, detachedTextNode, 8], node foreignDoctype -PASS 31,0: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node paras[0] -PASS 31,0: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node paras[0] -PASS 31,1: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node paras[0].firstChild -PASS 31,1: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node paras[0].firstChild -PASS 31,2: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node paras[1].firstChild -PASS 31,2: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node paras[1].firstChild -PASS 31,3: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignPara1 -PASS 31,3: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignPara1 -PASS 31,4: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignPara1.firstChild -PASS 31,4: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignPara1.firstChild -PASS 31,5: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedPara1 -PASS 31,5: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedPara1 -PASS 31,6: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedPara1.firstChild -PASS 31,6: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedPara1.firstChild -PASS 31,7: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node document -PASS 31,7: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node document -PASS 31,8: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedDiv -PASS 31,8: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedDiv -PASS 31,9: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignDoc -PASS 31,9: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignDoc -PASS 31,10: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignPara2 -PASS 31,10: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignPara2 -PASS 31,11: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node xmlDoc -PASS 31,11: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node xmlDoc -PASS 31,12: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node xmlElement -PASS 31,12: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node xmlElement -PASS 31,13: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedTextNode -PASS 31,13: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedTextNode -PASS 31,14: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignTextNode -PASS 31,14: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignTextNode -PASS 31,15: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node processingInstruction -PASS 31,15: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node processingInstruction -PASS 31,16: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedProcessingInstruction -PASS 31,16: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedProcessingInstruction -PASS 31,17: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node comment -PASS 31,17: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node comment -PASS 31,18: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedComment -PASS 31,18: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node detachedComment -PASS 31,19: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node docfrag -PASS 31,19: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node docfrag -PASS 31,20: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node doctype -PASS 31,20: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node doctype -PASS 31,21: resulting DOM for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignDoctype -PASS 31,21: resulting range position for range [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node foreignDoctype -PASS 32,0: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node paras[0] -PASS 32,0: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node paras[0] -PASS 32,1: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node paras[0].firstChild -PASS 32,1: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node paras[0].firstChild -PASS 32,2: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node paras[1].firstChild -PASS 32,2: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node paras[1].firstChild -PASS 32,3: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignPara1 -PASS 32,3: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignPara1 -PASS 32,4: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignPara1.firstChild -PASS 32,4: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignPara1.firstChild -PASS 32,5: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedPara1 -PASS 32,5: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedPara1 -PASS 32,6: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedPara1.firstChild -PASS 32,6: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedPara1.firstChild -PASS 32,7: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node document -PASS 32,7: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node document -PASS 32,8: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedDiv -PASS 32,8: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedDiv -PASS 32,9: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignDoc -PASS 32,9: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignDoc -PASS 32,10: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignPara2 -PASS 32,10: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignPara2 -PASS 32,11: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node xmlDoc -PASS 32,11: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node xmlDoc -PASS 32,12: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node xmlElement -PASS 32,12: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node xmlElement -PASS 32,13: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedTextNode -PASS 32,13: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedTextNode -PASS 32,14: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignTextNode -PASS 32,14: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignTextNode -PASS 32,15: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node processingInstruction -PASS 32,15: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node processingInstruction -PASS 32,16: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedProcessingInstruction -PASS 32,16: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedProcessingInstruction -PASS 32,17: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node comment -PASS 32,17: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node comment -PASS 32,18: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedComment -PASS 32,18: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node detachedComment -PASS 32,19: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node docfrag -PASS 32,19: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node docfrag -PASS 32,20: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node doctype -PASS 32,20: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node doctype -PASS 32,21: resulting DOM for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignDoctype -PASS 32,21: resulting range position for range [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node foreignDoctype -PASS 33,0: resulting DOM for range [detachedComment, 3, detachedComment, 4], node paras[0] -PASS 33,0: resulting range position for range [detachedComment, 3, detachedComment, 4], node paras[0] -PASS 33,1: resulting DOM for range [detachedComment, 3, detachedComment, 4], node paras[0].firstChild -PASS 33,1: resulting range position for range [detachedComment, 3, detachedComment, 4], node paras[0].firstChild -PASS 33,2: resulting DOM for range [detachedComment, 3, detachedComment, 4], node paras[1].firstChild -PASS 33,2: resulting range position for range [detachedComment, 3, detachedComment, 4], node paras[1].firstChild -PASS 33,3: resulting DOM for range [detachedComment, 3, detachedComment, 4], node foreignPara1 -PASS 33,3: resulting range position for range [detachedComment, 3, detachedComment, 4], node foreignPara1 -PASS 33,4: resulting DOM for range [detachedComment, 3, detachedComment, 4], node foreignPara1.firstChild -PASS 33,4: resulting range position for range [detachedComment, 3, detachedComment, 4], node foreignPara1.firstChild -PASS 33,5: resulting DOM for range [detachedComment, 3, detachedComment, 4], node detachedPara1 -PASS 33,5: resulting range position for range [detachedComment, 3, detachedComment, 4], node detachedPara1 -PASS 33,6: resulting DOM for range [detachedComment, 3, detachedComment, 4], node detachedPara1.firstChild -PASS 33,6: resulting range position for range [detachedComment, 3, detachedComment, 4], node detachedPara1.firstChild -PASS 33,7: resulting DOM for range [detachedComment, 3, detachedComment, 4], node document -PASS 33,7: resulting range position for range [detachedComment, 3, detachedComment, 4], node document -PASS 33,8: resulting DOM for range [detachedComment, 3, detachedComment, 4], node detachedDiv -PASS 33,8: resulting range position for range [detachedComment, 3, detachedComment, 4], node detachedDiv -PASS 33,9: resulting DOM for range [detachedComment, 3, detachedComment, 4], node foreignDoc -PASS 33,9: resulting range position for range [detachedComment, 3, detachedComment, 4], node foreignDoc -PASS 33,10: resulting DOM for range [detachedComment, 3, detachedComment, 4], node foreignPara2 -PASS 33,10: resulting range position for range [detachedComment, 3, detachedComment, 4], node foreignPara2 -PASS 33,11: resulting DOM for range [detachedComment, 3, detachedComment, 4], node xmlDoc -PASS 33,11: resulting range position for range [detachedComment, 3, detachedComment, 4], node xmlDoc -PASS 33,12: resulting DOM for range [detachedComment, 3, detachedComment, 4], node xmlElement -PASS 33,12: resulting range position for range [detachedComment, 3, detachedComment, 4], node xmlElement -PASS 33,13: resulting DOM for range [detachedComment, 3, detachedComment, 4], node detachedTextNode -PASS 33,13: resulting range position for range [detachedComment, 3, detachedComment, 4], node detachedTextNode -PASS 33,14: resulting DOM for range [detachedComment, 3, detachedComment, 4], node foreignTextNode -PASS 33,14: resulting range position for range [detachedComment, 3, detachedComment, 4], node foreignTextNode -PASS 33,15: resulting DOM for range [detachedComment, 3, detachedComment, 4], node processingInstruction -PASS 33,15: resulting range position for range [detachedComment, 3, detachedComment, 4], node processingInstruction -PASS 33,16: resulting DOM for range [detachedComment, 3, detachedComment, 4], node detachedProcessingInstruction -PASS 33,16: resulting range position for range [detachedComment, 3, detachedComment, 4], node detachedProcessingInstruction -PASS 33,17: resulting DOM for range [detachedComment, 3, detachedComment, 4], node comment -PASS 33,17: resulting range position for range [detachedComment, 3, detachedComment, 4], node comment -PASS 33,18: resulting DOM for range [detachedComment, 3, detachedComment, 4], node detachedComment -PASS 33,18: resulting range position for range [detachedComment, 3, detachedComment, 4], node detachedComment -PASS 33,19: resulting DOM for range [detachedComment, 3, detachedComment, 4], node docfrag -PASS 33,19: resulting range position for range [detachedComment, 3, detachedComment, 4], node docfrag -PASS 33,20: resulting DOM for range [detachedComment, 3, detachedComment, 4], node doctype -PASS 33,20: resulting range position for range [detachedComment, 3, detachedComment, 4], node doctype -PASS 33,21: resulting DOM for range [detachedComment, 3, detachedComment, 4], node foreignDoctype -PASS 33,21: resulting range position for range [detachedComment, 3, detachedComment, 4], node foreignDoctype -PASS 34,0: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node paras[0] -PASS 34,0: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node paras[0] -PASS 34,1: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node paras[0].firstChild -PASS 34,1: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node paras[0].firstChild -PASS 34,2: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node paras[1].firstChild -PASS 34,2: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node paras[1].firstChild -PASS 34,3: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignPara1 -PASS 34,3: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignPara1 -PASS 34,4: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignPara1.firstChild -PASS 34,4: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignPara1.firstChild -PASS 34,5: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedPara1 -PASS 34,5: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedPara1 -PASS 34,6: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedPara1.firstChild -PASS 34,6: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedPara1.firstChild -PASS 34,7: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node document -PASS 34,7: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node document -PASS 34,8: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedDiv -PASS 34,8: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedDiv -PASS 34,9: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignDoc -PASS 34,9: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignDoc -PASS 34,10: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignPara2 -PASS 34,10: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignPara2 -PASS 34,11: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node xmlDoc -PASS 34,11: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node xmlDoc -PASS 34,12: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node xmlElement -PASS 34,12: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node xmlElement -PASS 34,13: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedTextNode -PASS 34,13: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedTextNode -PASS 34,14: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignTextNode -PASS 34,14: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignTextNode -PASS 34,15: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node processingInstruction -PASS 34,15: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node processingInstruction -PASS 34,16: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedProcessingInstruction -PASS 34,16: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedProcessingInstruction -PASS 34,17: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node comment -PASS 34,17: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node comment -PASS 34,18: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedComment -PASS 34,18: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node detachedComment -PASS 34,19: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node docfrag -PASS 34,19: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node docfrag -PASS 34,20: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node doctype -PASS 34,20: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node doctype -PASS 34,21: resulting DOM for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignDoctype -PASS 34,21: resulting range position for range [detachedForeignComment, 0, detachedForeignComment, 1], node foreignDoctype -PASS 35,0: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node paras[0] -PASS 35,0: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node paras[0] -PASS 35,1: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node paras[0].firstChild -PASS 35,1: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node paras[0].firstChild -PASS 35,2: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node paras[1].firstChild -PASS 35,2: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node paras[1].firstChild -PASS 35,3: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignPara1 -PASS 35,3: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignPara1 -PASS 35,4: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignPara1.firstChild -PASS 35,4: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignPara1.firstChild -PASS 35,5: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedPara1 -PASS 35,5: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedPara1 -PASS 35,6: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedPara1.firstChild -PASS 35,6: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedPara1.firstChild -PASS 35,7: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node document -PASS 35,7: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node document -PASS 35,8: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedDiv -PASS 35,8: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedDiv -PASS 35,9: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignDoc -PASS 35,9: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignDoc -PASS 35,10: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignPara2 -PASS 35,10: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignPara2 -PASS 35,11: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node xmlDoc -PASS 35,11: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node xmlDoc -PASS 35,12: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node xmlElement -PASS 35,12: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node xmlElement -PASS 35,13: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedTextNode -PASS 35,13: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedTextNode -PASS 35,14: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignTextNode -PASS 35,14: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignTextNode -PASS 35,15: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node processingInstruction -PASS 35,15: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node processingInstruction -PASS 35,16: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedProcessingInstruction -PASS 35,16: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedProcessingInstruction -PASS 35,17: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node comment -PASS 35,17: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node comment -PASS 35,18: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedComment -PASS 35,18: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node detachedComment -PASS 35,19: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node docfrag -PASS 35,19: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node docfrag -PASS 35,20: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node doctype -PASS 35,20: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node doctype -PASS 35,21: resulting DOM for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignDoctype -PASS 35,21: resulting range position for range [detachedXmlComment, 2, detachedXmlComment, 6], node foreignDoctype -PASS 36,0: resulting DOM for range [docfrag, 0, docfrag, 0], node paras[0] -PASS 36,0: resulting range position for range [docfrag, 0, docfrag, 0], node paras[0] -PASS 36,1: resulting DOM for range [docfrag, 0, docfrag, 0], node paras[0].firstChild -PASS 36,1: resulting range position for range [docfrag, 0, docfrag, 0], node paras[0].firstChild -PASS 36,2: resulting DOM for range [docfrag, 0, docfrag, 0], node paras[1].firstChild -PASS 36,2: resulting range position for range [docfrag, 0, docfrag, 0], node paras[1].firstChild -PASS 36,3: resulting DOM for range [docfrag, 0, docfrag, 0], node foreignPara1 -PASS 36,3: resulting range position for range [docfrag, 0, docfrag, 0], node foreignPara1 -PASS 36,4: resulting DOM for range [docfrag, 0, docfrag, 0], node foreignPara1.firstChild -PASS 36,4: resulting range position for range [docfrag, 0, docfrag, 0], node foreignPara1.firstChild -PASS 36,5: resulting DOM for range [docfrag, 0, docfrag, 0], node detachedPara1 -PASS 36,5: resulting range position for range [docfrag, 0, docfrag, 0], node detachedPara1 -PASS 36,6: resulting DOM for range [docfrag, 0, docfrag, 0], node detachedPara1.firstChild -PASS 36,6: resulting range position for range [docfrag, 0, docfrag, 0], node detachedPara1.firstChild -PASS 36,7: resulting DOM for range [docfrag, 0, docfrag, 0], node document -PASS 36,7: resulting range position for range [docfrag, 0, docfrag, 0], node document -PASS 36,8: resulting DOM for range [docfrag, 0, docfrag, 0], node detachedDiv -PASS 36,8: resulting range position for range [docfrag, 0, docfrag, 0], node detachedDiv -PASS 36,9: resulting DOM for range [docfrag, 0, docfrag, 0], node foreignDoc -PASS 36,9: resulting range position for range [docfrag, 0, docfrag, 0], node foreignDoc -PASS 36,10: resulting DOM for range [docfrag, 0, docfrag, 0], node foreignPara2 -PASS 36,10: resulting range position for range [docfrag, 0, docfrag, 0], node foreignPara2 -PASS 36,11: resulting DOM for range [docfrag, 0, docfrag, 0], node xmlDoc -PASS 36,11: resulting range position for range [docfrag, 0, docfrag, 0], node xmlDoc -PASS 36,12: resulting DOM for range [docfrag, 0, docfrag, 0], node xmlElement -PASS 36,12: resulting range position for range [docfrag, 0, docfrag, 0], node xmlElement -PASS 36,13: resulting DOM for range [docfrag, 0, docfrag, 0], node detachedTextNode -PASS 36,13: resulting range position for range [docfrag, 0, docfrag, 0], node detachedTextNode -PASS 36,14: resulting DOM for range [docfrag, 0, docfrag, 0], node foreignTextNode -PASS 36,14: resulting range position for range [docfrag, 0, docfrag, 0], node foreignTextNode -PASS 36,15: resulting DOM for range [docfrag, 0, docfrag, 0], node processingInstruction -PASS 36,15: resulting range position for range [docfrag, 0, docfrag, 0], node processingInstruction -PASS 36,16: resulting DOM for range [docfrag, 0, docfrag, 0], node detachedProcessingInstruction -PASS 36,16: resulting range position for range [docfrag, 0, docfrag, 0], node detachedProcessingInstruction -PASS 36,17: resulting DOM for range [docfrag, 0, docfrag, 0], node comment -PASS 36,17: resulting range position for range [docfrag, 0, docfrag, 0], node comment -PASS 36,18: resulting DOM for range [docfrag, 0, docfrag, 0], node detachedComment -PASS 36,18: resulting range position for range [docfrag, 0, docfrag, 0], node detachedComment -PASS 36,19: resulting DOM for range [docfrag, 0, docfrag, 0], node docfrag -PASS 36,19: resulting range position for range [docfrag, 0, docfrag, 0], node docfrag -PASS 36,20: resulting DOM for range [docfrag, 0, docfrag, 0], node doctype -PASS 36,20: resulting range position for range [docfrag, 0, docfrag, 0], node doctype -PASS 36,21: resulting DOM for range [docfrag, 0, docfrag, 0], node foreignDoctype -PASS 36,21: resulting range position for range [docfrag, 0, docfrag, 0], node foreignDoctype -PASS 37,0: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node paras[0] -PASS 37,0: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node paras[0] -PASS 37,1: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node paras[0].firstChild -PASS 37,1: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node paras[0].firstChild -PASS 37,2: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node paras[1].firstChild -PASS 37,2: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node paras[1].firstChild -PASS 37,3: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignPara1 -PASS 37,3: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignPara1 -PASS 37,4: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignPara1.firstChild -PASS 37,4: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignPara1.firstChild -PASS 37,5: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedPara1 -PASS 37,5: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedPara1 -PASS 37,6: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedPara1.firstChild -PASS 37,6: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedPara1.firstChild -PASS 37,7: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node document -PASS 37,7: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node document -PASS 37,8: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedDiv -PASS 37,8: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedDiv -PASS 37,9: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignDoc -PASS 37,9: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignDoc -PASS 37,10: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignPara2 -PASS 37,10: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignPara2 -PASS 37,11: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node xmlDoc -PASS 37,11: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node xmlDoc -PASS 37,12: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node xmlElement -PASS 37,12: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node xmlElement -PASS 37,13: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedTextNode -PASS 37,13: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedTextNode -PASS 37,14: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignTextNode -PASS 37,14: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignTextNode -PASS 37,15: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node processingInstruction -PASS 37,15: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node processingInstruction -PASS 37,16: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedProcessingInstruction -PASS 37,16: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedProcessingInstruction -PASS 37,17: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node comment -PASS 37,17: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node comment -PASS 37,18: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node detachedComment -PASS 37,18: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node detachedComment -PASS 37,19: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node docfrag -PASS 37,19: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node docfrag -PASS 37,20: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node doctype -PASS 37,20: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node doctype -PASS 37,21: resulting DOM for range [processingInstruction, 0, processingInstruction, 4], node foreignDoctype -PASS 37,21: resulting range position for range [processingInstruction, 0, processingInstruction, 4], node foreignDoctype -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Range/range-exceptions-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Range/range-exceptions-expected.txt index a81976f..670454b 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Range/range-exceptions-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/Range/range-exceptions-expected.txt
@@ -5,7 +5,7 @@ PASS node.innerHTML is '<bar>AB<moo>C</moo>DE</bar>' PASS r.surroundContents(document.createElement('a')) threw exception InvalidStateError: Failed to execute 'surroundContents' on 'Range': The Range has partially selected a non-Text node.. -PASS r.surroundContents(document.createElement('a')) threw exception HierarchyRequestError: Failed to execute 'surroundContents' on 'Range': The node to be inserted is a 'A' node, which may not be inserted here.. +PASS r.surroundContents(document.createElement('a')) threw exception HierarchyRequestError: Failed to execute 'surroundContents' on 'Range': Nodes of type 'A' may not be inserted inside nodes of type '#comment'.. PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Range/range-exceptions.html b/third_party/WebKit/LayoutTests/fast/dom/Range/range-exceptions.html index deee2328..da2a819 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Range/range-exceptions.html +++ b/third_party/WebKit/LayoutTests/fast/dom/Range/range-exceptions.html
@@ -28,7 +28,7 @@ // But not when we don't try to split the comment. r.setStart(c1, 0); r.setEnd(c1, 5); -shouldThrow("r.surroundContents(document.createElement('a'))", '"HierarchyRequestError: Failed to execute \'surroundContents\' on \'Range\': The node to be inserted is a \'A\' node, which may not be inserted here."'); +shouldThrow("r.surroundContents(document.createElement('a'))", '"HierarchyRequestError: Failed to execute \'surroundContents\' on \'Range\': Nodes of type \'A\' may not be inserted inside nodes of type \'#comment\'."'); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/slots-fallback.html b/third_party/WebKit/LayoutTests/shadow-dom/slots-fallback.html deleted file mode 100644 index 3f085ec..0000000 --- a/third_party/WebKit/LayoutTests/shadow-dom/slots-fallback.html +++ /dev/null
@@ -1,219 +0,0 @@ -<!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="resources/shadow-dom.js"></script> - -<div id="test1"> - <div id="host"> - <template data-mode="open"> - <slot id="s1" name="slot1"> - <div id="f1"></div> - </slot> - </template> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test1); - removeWhiteSpaceOnlyTextNodes(n.test1); - - assert_equals(n.f1.assignedSlot, null); - - assert_array_equals(n.s1.assignedNodes(), []); - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]); -}, 'Slots fallback: Basic.'); -</script> - -<div id="test2"> - <div id="host"> - <template data-mode="open"> - <slot id="s1" name="slot1"> - <slot id="s2" name="slot2"> - <div id="f1"></div> - </slot> - </slot> - </template> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test2); - removeWhiteSpaceOnlyTextNodes(n.test2); - - assert_equals(n.f1.assignedSlot, null); - - assert_array_equals(n.s1.assignedNodes(), []); - assert_array_equals(n.s2.assignedNodes(), []); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f1]); -}, 'Slots fallback: Slots in Slots.'); -</script> - -<div id="test3"> - <div id="host"> - <template data-mode="open"> - <slot id="s1" name="slot1"> - <slot id="s2" name="slot2"> - <div id="f1"></div> - </slot> - </slot> - </template> - <div id="c1" slot="slot1"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test3); - removeWhiteSpaceOnlyTextNodes(n.test3); - - assert_equals(n.c1.assignedSlot, n.s1); - assert_equals(n.f1.assignedSlot, null); - - assert_array_equals(n.s1.assignedNodes(), [n.c1]); - assert_array_equals(n.s2.assignedNodes(), []); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f1]); -}, 'Slots fallback: Fallback contents should not be used if a node is assigned.'); -</script> - -<div id="test4"> - <div id="host"> - <template data-mode="open"> - <slot id="s1" name="slot1"> - <slot id="s2" name="slot2"> - <div id="f1"></div> - </slot> - </slot> - </template> - <div id="c1" slot="slot2"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test4); - removeWhiteSpaceOnlyTextNodes(n.test4); - - assert_equals(n.c1.assignedSlot, n.s2); - assert_equals(n.f1.assignedSlot, null); - - assert_array_equals(n.s1.assignedNodes(), []); - assert_array_equals(n.s2.assignedNodes(), [n.c1]); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]); -}, 'Slots fallback: Slots in Slots: Assinged nodes should be used as fallback contents of another slot'); -</script> - -<div id="test5"> - <div id="host1"> - <template data-mode="open"> - <div id="host2"> - <template data-mode="open"> - <slot id="s4" name="slot4"> - <slot id="s3" name="slot3"> - <div id="f3"></div> - </slot> - <div id="f4"></div> - </slot> - </template> - <slot id="s2" name="slot2" slot="slot3"> - <slot id="s1" name="slot1"> - <div id="f1"></div> - </slot> - <div id="f2"></div> - </slot> - </div> - </template> - <div id="c1" slot="slot1"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test5); - removeWhiteSpaceOnlyTextNodes(n.test5); - - assert_array_equals(n.s1.assignedNodes(), [n.c1]); - assert_array_equals(n.s2.assignedNodes(), []); - assert_array_equals(n.s3.assignedNodes(), [n.s2]); - assert_array_equals(n.s4.assignedNodes(), []); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1, n.f2]); - assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c1, n.f2]); - assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.c1, n.f2, n.f4]); -}, 'Slots fallback: Complex case.'); - -test(() => { - let n = createTestTree(test5); - removeWhiteSpaceOnlyTextNodes(n.test5); - - let d1 = document.createElement('div'); - n.s2.appendChild(d1); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1, n.f2, d1]); - assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c1, n.f2, d1]); - assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.c1, n.f2, d1, n.f4]); -}, 'Slots fallback: Mutation. Append fallback contents.'); - -test(() => { - let n = createTestTree(test5); - removeWhiteSpaceOnlyTextNodes(n.test5); - - n.f2.remove(); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.c1, n.f4]); -}, 'Slots fallback: Mutation. Remove fallback contents.'); - -test(() => { - let n = createTestTree(test5); - removeWhiteSpaceOnlyTextNodes(n.test5); - - let d2 = document.createElement('div'); - d2.setAttribute('slot', 'slot2'); - n.host1.appendChild(d2); - - assert_array_equals(n.s2.assignedNodes(), [d2]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [d2]); - assert_array_equals(n.s3.assignedNodes({ flatten: true }), [d2]); - assert_array_equals(n.s4.assignedNodes({ flatten: true }), [d2, n.f4]); -}, 'Slots fallback: Mutation. Assign a node to a slot so that fallback contens are no longer used.'); - -test(() => { - let n = createTestTree(test5); - removeWhiteSpaceOnlyTextNodes(n.test5); - - n.c1.remove(); - - assert_array_equals(n.s1.assignedNodes(), []); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f1, n.f2]); - assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.f1, n.f2]); - assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.f1, n.f2, n.f4]); -}, 'Slots fallback: Mutation. Remove an assigned node from a slot so that fallback contens will be used.'); - -test(() => { - let n = createTestTree(test5); - removeWhiteSpaceOnlyTextNodes(n.test5); - - n.s1.remove(); - - assert_array_equals(n.s1.assignedNodes(), []); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f2]); - assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.f2]); - assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.f2, n.f4]); -}, 'Slots fallback: Mutation. Remove a slot which is a fallback content of another slot.'); -</script>
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/slots.html b/third_party/WebKit/LayoutTests/shadow-dom/slots.html index 50bcfa9..28897b52 100644 --- a/third_party/WebKit/LayoutTests/shadow-dom/slots.html +++ b/third_party/WebKit/LayoutTests/shadow-dom/slots.html
@@ -1,511 +1,12 @@ <!DOCTYPE html> <script src="../resources/testharness.js"></script> <script src="../resources/testharnessreport.js"></script> -<script src="resources/shadow-dom.js"></script> <slot id='slot_in_document'></slot> -<div id="test_basic"> - <div id="host"> - <template data-mode="open"> - <slot id="s1" name="slot1"></slot> - </template> - <div id="c1" slot="slot1"></div> - </div> -</div> - <script> test(() => { assert_equals(window.getComputedStyle(slot_in_document).getPropertyValue('display'), 'contents'); - - let n = createTestTree(test_basic); - removeWhiteSpaceOnlyTextNodes(n.test_basic); - - assert_equals(n.c1.assignedSlot, n.s1); - assert_array_equals(n.s1.assignedNodes(), [n.c1]); -}, 'Slots: Basic.'); -</script> - -<div id="test_basic_closed"> - <div id="host"> - <template data-mode="closed"> - <slot id="s1" name="slot1"></slot> - </template> - <div id="c1" slot="slot1"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_basic_closed); - removeWhiteSpaceOnlyTextNodes(n.test_basic_closed); - - assert_equals(n.c1.assignedSlot, null); - assert_array_equals(n.s1.assignedNodes(), [n.c1]); -}, 'Slots: Slots in closed.'); -</script> - -<div id="test_slot_not_in_shadow"> - <slot id="s1"></slot> -</div> - -<script> -test(() => { - let n = createTestTree(test_slot_not_in_shadow); - removeWhiteSpaceOnlyTextNodes(n.test_slot_not_in_shadow); - - assert_array_equals(n.s1.assignedNodes(), []); -}, 'Slots: Slots not in a shadow tree.'); -</script> - -<div id="test_slot_not_in_shadow_2"> - <slot id="s1"> - <div id="c1"></div> - </slot> - <slot id="s2"> - <div id="c2"></div> - <slot id="s3"> - <div id="c3_1"></div> - <div id="c3_2"></div> - </slot> - </slot> -</div> - -<script> -test(() => { - let n = createTestTree(test_slot_not_in_shadow_2); - removeWhiteSpaceOnlyTextNodes(n.test_slot_not_in_shadow_2); - - assert_equals(n.c1.assignedSlot, null); - assert_equals(n.c2.assignedSlot, null); - assert_equals(n.c3_1.assignedSlot, null); - assert_equals(n.c3_2.assignedSlot, null); - - assert_array_equals(n.s1.assignedNodes(), []); - assert_array_equals(n.s2.assignedNodes(), []); - assert_array_equals(n.s3.assignedNodes(), []); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c2, n.c3_1, n.c3_2]); - assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c3_1, n.c3_2]); -}, 'Slots: Distributed nooes for Slots not in a shadow tree.'); -</script> - -<div id="test_slot_name_matching"> - <div id="host"> - <template data-mode="open"> - <slot id="s1" name="slot1"></slot> - <slot id="s2" name="slot2"></slot> - <slot id="s3" name="xxx"></slot> - </template> - <div id="c1" slot="slot1"></div> - <div id="c2" slot="slot2"></div> - <div id="c3" slot="yyy"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_slot_name_matching); - removeWhiteSpaceOnlyTextNodes(n.test_slot_name_matching); - - assert_equals(n.c1.assignedSlot, n.s1); - assert_equals(n.c2.assignedSlot, n.s2); - assert_equals(n.c3.assignedSlot, null); -}, 'Slots: Name matching'); -</script> - -<div id="test_no_direct_host_child"> - <div id="host"> - <template data-mode="open"> - <slot id="s1" name="slot1"></slot> - <slot id="s2" name="slot1"></slot> - </template> - <div id="c1" slot="slot1"></div> - <div id="c2" slot="slot1"></div> - <div> - <div id="c3" slot="slot1"></div> - </div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_no_direct_host_child); - removeWhiteSpaceOnlyTextNodes(n.test_no_direct_host_child); - - assert_equals(n.c1.assignedSlot, n.s1); - assert_equals(n.c2.assignedSlot, n.s1); - assert_equals(n.c3.assignedSlot, null); - - assert_array_equals(n.s1.assignedNodes(), [n.c1, n.c2]); -}, 'Slots: No direct host child.'); -</script> - -<div id="test_default_slot"> - <div id="host"> - <template data-mode="open"> - <slot id="s1" name="slot1"></slot> - <slot id="s2"></slot> - <slot id="s3"></slot> - </template> - <div id="c1"></div> - <div id="c2" slot=""></div> - <div id="c3" slot="foo"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_default_slot); - removeWhiteSpaceOnlyTextNodes(n.test_default_slot); - - assert_equals(n.c1.assignedSlot, n.s2); - assert_equals(n.c2.assignedSlot, n.s2); - assert_equals(n.c3.assignedSlot, null); -}, 'Slots: Default Slot.'); -</script> - -<div id="test_slot_in_slot"> - <div id="host"> - <template data-mode="open"> - <slot id="s1" name="slot1"> - <slot id="s2" name="slot2"></slot> - </slot> - </template> - <div id="c1" slot="slot2"></div> - <div id="c2" slot="slot1"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_slot_in_slot); - removeWhiteSpaceOnlyTextNodes(n.test_slot_in_slot); - - assert_equals(n.c1.assignedSlot, n.s2); - assert_equals(n.c2.assignedSlot, n.s1); -}, 'Slots: Slot in Slot does not matter in assignment.'); -</script> - -<div id="test_slot_is_assigned_to_slot"> - <div id="host1"> - <template data-mode="open"> - <div id="host2"> - <template data-mode="open"> - <slot id="s2" name="slot2"></slot> - </template> - <slot id="s1" name="slot1" slot="slot2"></slot> - </div> - </template> - <div id="c1" slot="slot1"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_slot_is_assigned_to_slot); - removeWhiteSpaceOnlyTextNodes(n.test_slot_is_assigned_to_slot); - - assert_equals(n.c1.assignedSlot, n.s1); - assert_equals(n.s1.assignedSlot, n.s2); - - assert_array_equals(n.s1.assignedNodes(), [n.c1]); - assert_array_equals(n.s2.assignedNodes(), [n.s1]); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]); -}, 'Slots: Slot is assigned to another slot'); -</script> - -<div id="test_open_closed"> - <div id="host1"> - <template data-mode="open"> - <div id="host2"> - <template data-mode="closed"> - <slot id="s2" name="slot2"></slot> - </template> - <slot id="s1" name="slot1" slot="slot2"></slot> - </div> - </template> - <div id="c1" slot="slot1"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_open_closed); - removeWhiteSpaceOnlyTextNodes(n.test_open_closed); - - assert_equals(n.c1.assignedSlot, n.s1); - assert_equals(n.s1.assignedSlot, null, - 'A slot in a closed shadow tree should not be accessed via assignedSlot'); - - assert_array_equals(n.s1.assignedNodes(), [n.c1]); - assert_array_equals(n.s2.assignedNodes(), [n.s1]); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]); -}, 'Slots: Open > Closed.'); -</script> - -<div id="test_closed_closed"> - <div id="host1"> - <template data-mode="closed"> - <div id="host2"> - <template data-mode="closed"> - <slot id="s2" name="slot2"></slot> - </template> - <slot id="s1" name="slot1" slot="slot2"></slot> - </div> - </template> - <div id="c1" slot="slot1"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_closed_closed); - removeWhiteSpaceOnlyTextNodes(n.test_closed_closed); - - assert_equals(n.c1.assignedSlot, null, - 'A slot in a closed shadow tree should not be accessed via assignedSlot'); - assert_equals(n.s1.assignedSlot, null, - 'A slot in a closed shadow tree should not be accessed via assignedSlot'); - - assert_array_equals(n.s1.assignedNodes(), [n.c1]); - assert_array_equals(n.s2.assignedNodes(), [n.s1]); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]); -}, 'Slots: Closed > Closed.'); -</script> - -<div id="test_closed_open"> - <div id="host1"> - <template data-mode="closed"> - <div id="host2"> - <template data-mode="open"> - <slot id="s2" name="slot2"></slot> - </template> - <slot id="s1" name="slot1" slot="slot2"></slot> - </div> - </template> - <div id="c1" slot="slot1"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_closed_open); - removeWhiteSpaceOnlyTextNodes(n.test_closed_open); - - assert_equals(n.c1.assignedSlot, null, - 'A slot in a closed shadow tree should not be accessed via assignedSlot'); - assert_equals(n.s1.assignedSlot, n.s2); - - assert_array_equals(n.s1.assignedNodes(), [n.c1]); - assert_array_equals(n.s2.assignedNodes(), [n.s1]); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]); -}, 'Slots: Closed > Open.'); -</script> - -<div id="test_complex"> - <div id="host1"> - <template data-mode="open"> - <div id="host2"> - <template data-mode="open"> - <slot id="s5" name="slot5"></slot> - <slot id="s6" name="slot6"></slot> - <slot id="s7"></slot> - <slot id="s8" name="slot8"></slot> - </template> - <slot id="s1" name="slot1" slot="slot5"></slot> - <slot id="s2" name="slot2" slot="slot6"></slot> - <slot id="s3"></slot> - <slot id="s4" name="slot4" slot="slot-none"></slot> - <div id="c5" slot="slot5"></div> - <div id="c6" slot="slot6"></div> - <div id="c7"></div> - <div id="c8" slot="slot-none"></div> - </div> - </template> - <div id="c1" slot="slot1"></div> - <div id="c2" slot="slot2"></div> - <div id="c3"></div> - <div id="c4" slot="slot-none"></div> - </div> -</div> - -<script> -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - assert_equals(n.c1.assignedSlot, n.s1); - assert_equals(n.c2.assignedSlot, n.s2); - assert_equals(n.c3.assignedSlot, n.s3); - assert_equals(n.c4.assignedSlot, null); - - assert_equals(n.s1.assignedSlot, n.s5); - assert_equals(n.s2.assignedSlot, n.s6); - assert_equals(n.s3.assignedSlot, n.s7); - assert_equals(n.s4.assignedSlot, null); - - assert_equals(n.c5.assignedSlot, n.s5); - assert_equals(n.c6.assignedSlot, n.s6); - assert_equals(n.c7.assignedSlot, n.s7); - assert_equals(n.c8.assignedSlot, null); - - assert_array_equals(n.s1.assignedNodes(), [n.c1]); - assert_array_equals(n.s2.assignedNodes(), [n.c2]); - assert_array_equals(n.s3.assignedNodes(), [n.c3]); - assert_array_equals(n.s4.assignedNodes(), []); - assert_array_equals(n.s5.assignedNodes(), [n.s1, n.c5]); - assert_array_equals(n.s6.assignedNodes(), [n.s2, n.c6]); - assert_array_equals(n.s7.assignedNodes(), [n.s3, n.c7]); - assert_array_equals(n.s8.assignedNodes(), []); - - assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]); - assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c2]); - assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c3]); - assert_array_equals(n.s4.assignedNodes({ flatten: true }), []); - assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c1, n.c5]); - assert_array_equals(n.s6.assignedNodes({ flatten: true }), [n.c2, n.c6]); - assert_array_equals(n.s7.assignedNodes({ flatten: true }), [n.c3, n.c7]); - assert_array_equals(n.s8.assignedNodes({ flatten: true }), []); -}, 'Slots: Complex case: Basi line.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - let d1 = document.createElement('div'); - d1.setAttribute('slot', 'slot1'); - n.host1.appendChild(d1); - - assert_array_equals(n.s1.assignedNodes(), [n.c1, d1]); - assert_equals(d1.assignedSlot, n.s1); - - assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c1, d1, n.c5]); -}, 'Slots: Mutation: appendChild.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - n.c1.setAttribute('slot', 'slot-none'); - - assert_array_equals(n.s1.assignedNodes(), []); - assert_equals(n.c1.assignedSlot, null); - - assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]); -}, 'Slots: Mutation: Change slot= attribute 1.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - n.c1.setAttribute('slot', 'slot2'); - - assert_array_equals(n.s1.assignedNodes(), []); - assert_array_equals(n.s2.assignedNodes(), [n.c1, n.c2]); - assert_equals(n.c1.assignedSlot, n.s2); - - assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]); - assert_array_equals(n.s6.assignedNodes({ flatten: true }), [n.c1, n.c2, n.c6]); -}, 'Slots: Mutation: Change slot= attribute 2.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - n.c4.setAttribute('slot', 'slot1'); - - assert_array_equals(n.s1.assignedNodes(), [n.c1, n.c4]); - assert_equals(n.c4.assignedSlot, n.s1); - - assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c1, n.c4, n.c5]); -}, 'Slots: Mutation: Change slot= attribute 3.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - n.c1.remove(); - - assert_array_equals(n.s1.assignedNodes(), []); - assert_equals(n.c1.assignedSlot, null); - - assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]); -}, 'Slots: Mutation: Remove a child.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - let slot = document.createElement('slot'); - slot.setAttribute('name', 'slot1'); - n.host2.appendChild(slot); - - assert_array_equals(slot.assignedNodes(), []); -}, 'Slots: Mutation: Add a slot: after.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - let slot = document.createElement('slot'); - slot.setAttribute('name', 'slot1'); - n.host2.insertBefore(slot, n.s1); - - assert_array_equals(slot.assignedNodes(), [n.c1]); - assert_equals(n.c1.assignedSlot, slot); - - assert_array_equals(n.s7.assignedNodes(), [slot, n.s3, n.c7]); - assert_array_equals(n.s7.assignedNodes({ flatten: true }), [n.c1, n.c3, n.c7]); -}, 'Slots: Mutation: Add a slot: before.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - n.s1.remove(); - - assert_array_equals(n.s1.assignedNodes(), []); - assert_equals(n.c1.assignedSlot, null); - - assert_array_equals(n.s5.assignedNodes(), [n.c5]); - assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]); -}, 'Slots: Mutation: Remove a slot.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - n.s1.setAttribute('name', 'slot2'); - - assert_array_equals(n.s1.assignedNodes(), [n.c2]); - assert_equals(n.c1.assignedSlot, null); - assert_equals(n.c2.assignedSlot, n.s1); - - assert_array_equals(n.s5.assignedNodes(), [n.s1, n.c5]); - assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c2, n.c5]); -}, 'Slots: Mutation: Change slot name= attribute.'); - -test(() => { - let n = createTestTree(test_complex); - removeWhiteSpaceOnlyTextNodes(n.test_complex); - - n.s1.setAttribute('slot', 'slot6'); - - assert_array_equals(n.s1.assignedNodes(), [n.c1]); - - assert_array_equals(n.s5.assignedNodes(), [n.c5]); - assert_array_equals(n.s6.assignedNodes(), [n.s1, n.s2, n.c6]); - assert_array_equals(n.s6.assignedNodes({ flatten: true }), [n.c1, n.c2, n.c6]); -}, 'Slots: Mutation: Change slot slot= attribute.'); +}, 'Slots: Blink specific tests for slots.'); </script>
diff --git a/third_party/WebKit/Source/core/dom/AXObjectCacheBase.h b/third_party/WebKit/Source/core/dom/AXObjectCacheBase.h index 6d6c0c06..4192e4102 100644 --- a/third_party/WebKit/Source/core/dom/AXObjectCacheBase.h +++ b/third_party/WebKit/Source/core/dom/AXObjectCacheBase.h
@@ -10,7 +10,9 @@ namespace blink { +class LayoutObject; class Node; +class AXObject; class AXObjectImpl; // AXObjectCacheBase is a temporary class that sits between AXObjectCache and @@ -25,7 +27,8 @@ public: virtual ~AXObjectCacheBase(); - virtual AXObjectImpl* Get(const Node*) = 0; + virtual AXObject* Get(const Node*) = 0; + virtual AXObject* GetOrCreate(LayoutObject*) = 0; protected: AXObjectCacheBase();
diff --git a/third_party/WebKit/Source/core/dom/DocumentWriteIntervention.cpp b/third_party/WebKit/Source/core/dom/DocumentWriteIntervention.cpp index 3ddd87f..cd50894 100644 --- a/third_party/WebKit/Source/core/dom/DocumentWriteIntervention.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentWriteIntervention.cpp
@@ -128,7 +128,7 @@ } EmitWarningForDocWriteScripts(request.Url().GetString(), document); - request.SetHTTPHeaderField("Intervention", + request.AddHTTPHeaderField("Intervention", "<https://www.chromestatus.com/feature/" "5718547946799104>; level=\"warning\"");
diff --git a/third_party/WebKit/Source/core/dom/Range.cpp b/third_party/WebKit/Source/core/dom/Range.cpp index 302303e4..fbbf2649 100644 --- a/third_party/WebKit/Source/core/dom/Range.cpp +++ b/third_party/WebKit/Source/core/dom/Range.cpp
@@ -852,6 +852,7 @@ return ProcessContents(CLONE_CONTENTS, exception_state); } +// https://dom.spec.whatwg.org/#concept-range-insert void Range::insertNode(Node* new_node, ExceptionState& exception_state) { if (!new_node) { // FIXME: Generated bindings code never calls with null, and neither should @@ -860,140 +861,105 @@ return; } - // HierarchyRequestError: Raised if the container of the start of the Range is - // of a type that does not allow children of the type of newNode or if newNode - // is an ancestor of the container. - - // an extra one here - if a text node is going to split, it must have a parent - // to insert into - bool start_is_text = start_.Container().IsTextNode(); - if (start_is_text && !start_.Container().parentNode()) { + // 1. If range’s start node is a ProcessingInstruction or Comment node, is a + // Text node whose parent is null, or is node, then throw a + // HierarchyRequestError. + Node& start_node = start_.Container(); + if (start_node.getNodeType() == Node::kProcessingInstructionNode || + start_node.getNodeType() == Node::kCommentNode) { + exception_state.ThrowDOMException( + kHierarchyRequestError, + "Nodes of type '" + new_node->nodeName() + + "' may not be inserted inside nodes of type '" + + start_node.nodeName() + "'."); + return; + } + const bool start_is_text = start_node.IsTextNode(); + if (start_is_text && !start_node.parentNode()) { exception_state.ThrowDOMException(kHierarchyRequestError, "This operation would split a text node, " "but there's no parent into which to " "insert."); return; } + if (start_node == new_node) { + exception_state.ThrowDOMException( + kHierarchyRequestError, + "Unable to insert a node into a Range starting from the node itself."); + return; + } - // In the case where the container is a text node, we check against the - // container's parent, because text nodes get split up upon insertion. - Node* check_against; + // According to the specification, the following condition is checked in the + // step 6. However our EnsurePreInsertionValidity() supports only + // ContainerNode parent. + if (start_node.IsAttributeNode()) { + exception_state.ThrowDOMException( + kHierarchyRequestError, + "Nodes of type '" + new_node->nodeName() + + "' may not be inserted inside nodes of type 'Attr'."); + return; + } + + // 2. Let referenceNode be null. + Node* reference_node = nullptr; + // 3. If range’s start node is a Text node, set referenceNode to that Text + // node. + // 4. Otherwise, set referenceNode to the child of start node whose index is + // start offset, and null if there is no such child. if (start_is_text) - check_against = start_.Container().parentNode(); + reference_node = &start_node; else - check_against = &start_.Container(); + reference_node = NodeTraversal::ChildAt(start_node, start_.Offset()); - Node::NodeType new_node_type = new_node->getNodeType(); - int num_new_children; - if (new_node_type == Node::kDocumentFragmentNode) { - // check each child node, not the DocumentFragment itself - num_new_children = 0; - for (Node* c = ToDocumentFragment(new_node)->firstChild(); c; - c = c->nextSibling()) { - if (!check_against->ChildTypeAllowed(c->getNodeType())) { - exception_state.ThrowDOMException( - kHierarchyRequestError, - "The node to be inserted contains a '" + c->nodeName() + - "' node, which may not be inserted here."); - return; - } - ++num_new_children; - } - } else { - num_new_children = 1; - if (!check_against->ChildTypeAllowed(new_node_type)) { - exception_state.ThrowDOMException( - kHierarchyRequestError, - "The node to be inserted is a '" + new_node->nodeName() + - "' node, which may not be inserted here."); - return; - } - } + // 5. Let parent be range’s start node if referenceNode is null, and + // referenceNode’s parent otherwise. + ContainerNode& parent = reference_node ? *reference_node->parentNode() + : ToContainerNode(start_node); - for (Node& node : NodeTraversal::InclusiveAncestorsOf(start_.Container())) { - if (node == new_node) { - exception_state.ThrowDOMException(kHierarchyRequestError, - "The node to be inserted contains the " - "insertion point; it may not be " - "inserted into itself."); - return; - } - } - - // InvalidNodeTypeError: Raised if new_node is an Attr or Document node. - switch (new_node_type) { - case Node::kAttributeNode: - case Node::kDocumentNode: - exception_state.ThrowDOMException( - kInvalidNodeTypeError, "The node to be inserted is a '" + - new_node->nodeName() + - "' node, which may not be inserted here."); - return; - default: - break; - } + // 6. Ensure pre-insertion validity of node into parent before referenceNode. + if (!parent.EnsurePreInsertionValidity(*new_node, reference_node, nullptr, + exception_state)) + return; EventQueueScope scope; - bool collapsed = start_ == end_; - Node* container = nullptr; + // 7. If range's start node is a Text node, set referenceNode to the result of + // splitting it with offset range’s start offset. if (start_is_text) { - container = &start_.Container(); - Text* new_text = - ToText(container)->splitText(start_.Offset(), exception_state); + reference_node = + ToText(start_node).splitText(start_.Offset(), exception_state); if (exception_state.HadException()) return; - - container = &start_.Container(); - container->parentNode()->InsertBefore(new_node, new_text, exception_state); - if (exception_state.HadException()) - return; - - if (collapsed) { - // Some types of events don't support EventQueueScope. Given - // circumstance may mutate the tree so newText->parentNode() may - // become null. - if (!new_text->parentNode()) { - exception_state.ThrowDOMException( - kHierarchyRequestError, - "This operation would set range's end to parent with new offset, " - "but there's no parent into which to continue."); - return; - } - end_.SetToBeforeChild(*new_text); - } - } else { - Node* last_child = (new_node_type == Node::kDocumentFragmentNode) - ? ToDocumentFragment(new_node)->lastChild() - : new_node; - if (last_child && last_child == start_.ChildBefore()) { - // The insertion will do nothing, but we need to extend the range to - // include the inserted nodes. - Node* first_child = (new_node_type == Node::kDocumentFragmentNode) - ? ToDocumentFragment(new_node)->firstChild() - : new_node; - DCHECK(first_child); - start_.SetToBeforeChild(*first_child); - return; - } - - container = &start_.Container(); - Node* reference_node = NodeTraversal::ChildAt(*container, start_.Offset()); - // TODO(tkent): The following check must be unnecessary if we follow the - // algorithm defined in the specification. - // https://dom.spec.whatwg.org/#concept-range-insert - if (new_node != reference_node) { - container->insertBefore(new_node, reference_node, exception_state); - if (exception_state.HadException()) - return; - } - - // Note that m_start.offset() may have changed as a result of - // container->insertBefore, when the node we are inserting comes before the - // range in the same container. - if (collapsed && num_new_children) - end_.Set(start_.Container(), start_.Offset() + num_new_children, - last_child); } + + // 8. If node is referenceNode, set referenceNode to its next sibling. + if (new_node == reference_node) + reference_node = reference_node->nextSibling(); + + // 9. If node's parent is not null, remove node from its parent. + if (new_node->parentNode()) { + new_node->remove(exception_state); + if (exception_state.HadException()) + return; + } + + // 10. Let newOffset be parent's length if referenceNode is null, and + // referenceNode's index otherwise. + unsigned new_offset = + reference_node ? reference_node->NodeIndex() : LengthOfContents(&parent); + + // 11. Increase newOffset by node's length if node is a DocumentFragment node, + // and one otherwise. + new_offset += new_node->IsDocumentFragment() ? LengthOfContents(new_node) : 1; + + // 12. Pre-insert node into parent before referenceNode. + parent.insertBefore(new_node, reference_node, exception_state); + if (exception_state.HadException()) + return; + + // 13. If range's start and end are the same, set range's end to (parent, + // newOffset). + if (start_ == end_) + setEnd(&parent, new_offset, exception_state); } String Range::toString() const {
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp index 4a1c471..9d19f83 100644 --- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -705,7 +705,7 @@ // [Intervention] if (document_write_intervention_ == DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { - resource_request.SetHTTPHeaderField( + resource_request.AddHTTPHeaderField( "Intervention", "<https://www.chromestatus.com/feature/5718547946799104>"); defer = FetchParameters::kIdleLoad;
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp index 10d7bb2..5def9600 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -755,6 +755,20 @@ UnicodeBidi, TextDirection); +// Returns true if |caret_offset| is at edge of |box| based on |affinity|. +// |caret_offset| must be either |box.CaretMinOffset()| or +// |box.CaretMaxOffset()|. +static bool IsCaretAtEdgeOfInlineTextBox(int caret_offset, + const InlineTextBox& box, + TextAffinity affinity) { + if (caret_offset == box.CaretMinOffset()) + return affinity == TextAffinity::kDownstream; + DCHECK_EQ(caret_offset, box.CaretMaxOffset()); + if (affinity == TextAffinity::kUpstream) + return true; + return box.NextLeafChild() && box.NextLeafChild()->IsLineBreak(); +} + template <typename Strategy> static InlineBoxPosition ComputeInlineBoxPositionTemplate( const PositionTemplate<Strategy>& position, @@ -790,15 +804,17 @@ UpstreamIgnoringEditingBoundaries(position); if (upstream_equivalent == position || DownstreamIgnoringEditingBoundaries(upstream_equivalent) == position) - return InlineBoxPosition(inline_box, caret_offset); + return InlineBoxPosition(); return ComputeInlineBoxPosition( upstream_equivalent, TextAffinity::kUpstream, primary_direction); } if (layout_object->IsBox()) { inline_box = ToLayoutBox(layout_object)->InlineBoxWrapper(); - if (!inline_box || (caret_offset > inline_box->CaretMinOffset() && - caret_offset < inline_box->CaretMaxOffset())) + if (!inline_box) + return InlineBoxPosition(); + if ((caret_offset > inline_box->CaretMinOffset() && + caret_offset < inline_box->CaretMaxOffset())) return InlineBoxPosition(inline_box, caret_offset); } } else { @@ -817,12 +833,7 @@ if (caret_offset > caret_min_offset && caret_offset < caret_max_offset) return InlineBoxPosition(box, caret_offset); - if (((caret_offset == caret_max_offset) ^ - (affinity == TextAffinity::kDownstream)) || - ((caret_offset == caret_min_offset) ^ - (affinity == TextAffinity::kUpstream)) || - (caret_offset == caret_max_offset && box->NextLeafChild() && - box->NextLeafChild()->IsLineBreak())) { + if (IsCaretAtEdgeOfInlineTextBox(caret_offset, *box, affinity)) { inline_box = box; break; } @@ -840,7 +851,7 @@ } if (!inline_box) - return InlineBoxPosition(inline_box, caret_offset); + return InlineBoxPosition(); return AdjustInlineBoxPositionForTextDirection( inline_box, caret_offset, layout_object->Style()->GetUnicodeBidi(), primary_direction); @@ -1024,7 +1035,11 @@ box_position.inline_box->GetLineLayoutItem()), box_position); } - return ComputeLocalCaretRect(layout_object, box_position); + // DeleteSelectionCommandTest.deleteListFromTable goes here. + return LocalCaretRect( + layout_object, + layout_object->LocalCaretRect( + nullptr, position.GetPosition().ComputeEditingOffset())); } // This function was added because the caret rect that is calculated by
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.h b/third_party/WebKit/Source/core/editing/VisibleUnits.h index 16e3a9e49..77618f7 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.h +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.h
@@ -52,7 +52,10 @@ InlineBoxPosition() : inline_box(nullptr), offset_in_box(0) {} InlineBoxPosition(InlineBox* inline_box, int offset_in_box) - : inline_box(inline_box), offset_in_box(offset_in_box) {} + : inline_box(inline_box), offset_in_box(offset_in_box) { + DCHECK(inline_box); + DCHECK_GE(offset_in_box, 0); + } bool operator==(const InlineBoxPosition& other) const { return inline_box == other.inline_box &&
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp b/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp index f463135..6b2f9149 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp
@@ -303,9 +303,7 @@ Position::LastPositionInNode(sample), TextAffinity::kDownstream); // Should not be in infinite-loop EXPECT_EQ(nullptr, actual.inline_box); - // TODO(editing-dev): We should return 0 for |InlineBoxPosition| when - // |inline_box| is null. - EXPECT_EQ(2, actual.offset_in_box); + EXPECT_EQ(0, actual.offset_in_box); } TEST_F(VisibleUnitsTest, endOfDocument) {
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameClient.h b/third_party/WebKit/Source/core/frame/LocalFrameClient.h index 46fe331..2f8236e 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrameClient.h +++ b/third_party/WebKit/Source/core/frame/LocalFrameClient.h
@@ -322,6 +322,10 @@ return WebEffectiveConnectionType::kTypeUnknown; } + // Returns whether or not Client Lo-Fi is enabled for the frame + // (and so image requests may be replaced with a placeholder). + virtual bool IsClientLoFiActiveForFrame() { return false; } + // Returns whether or not the requested image should be replaced with a // placeholder as part of the Client Lo-Fi previews feature. virtual bool ShouldUseClientLoFiForRequest(const ResourceRequest&) {
diff --git a/third_party/WebKit/Source/core/html/BUILD.gn b/third_party/WebKit/Source/core/html/BUILD.gn index 72434e53..9bc0f97 100644 --- a/third_party/WebKit/Source/core/html/BUILD.gn +++ b/third_party/WebKit/Source/core/html/BUILD.gn
@@ -317,6 +317,8 @@ "forms/DateTimeSymbolicFieldElement.h", "forms/EmailInputType.cpp", "forms/EmailInputType.h", + "forms/ExternalDateTimeChooser.cpp", + "forms/ExternalDateTimeChooser.h", "forms/FileInputType.cpp", "forms/FileInputType.h", "forms/FormController.cpp",
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index d14730b3..c4f80b5 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -510,6 +510,12 @@ return true; } +CanvasColorParams HTMLCanvasElement::GetCanvasColorParams() const { + if (context_) + return context_->color_params(); + return CanvasColorParams(); +} + void HTMLCanvasElement::NotifyListenersCanvasChanged() { if (listeners_.size() == 0) return; @@ -872,7 +878,7 @@ // Rasterization of web contents will blend in the output space. Only embed // the canvas as a display list if it intended to do output space blending as // well. - if (!context_->color_params().UsesOutputSpaceBlending()) + if (!GetCanvasColorParams().UsesOutputSpaceBlending()) return false; if (RuntimeEnabledFeatures::ForceDisplayList2dCanvasEnabled()) @@ -894,7 +900,7 @@ // then make a non-accelerated ImageBuffer. This means copying the internal // Image will require a pixel readback, but that is unavoidable in this case. auto surface = WTF::MakeUnique<AcceleratedImageBufferSurface>( - Size(), opacity_mode, context_->color_params()); + Size(), opacity_mode, GetCanvasColorParams()); if (surface->IsValid()) return std::move(surface); return nullptr; @@ -923,7 +929,7 @@ auto surface = WTF::MakeUnique<Canvas2DImageBufferSurface>( std::move(context_provider), Size(), *msaa_sample_count, opacity_mode, - Canvas2DLayerBridge::kEnableAcceleration, context_->color_params()); + Canvas2DLayerBridge::kEnableAcceleration, GetCanvasColorParams()); if (!surface->IsValid()) { CanvasMetrics::CountCanvasContextUsage( CanvasMetrics::kGPUAccelerated2DCanvasImageBufferCreationFailed); @@ -944,7 +950,7 @@ if (ShouldUseDisplayList()) { auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( Size(), RecordingImageBufferSurface::kAllowFallback, opacity_mode, - context_->color_params()); + GetCanvasColorParams()); if (surface->IsValid()) { CanvasMetrics::CountCanvasContextUsage( CanvasMetrics::kDisplayList2DCanvasImageBufferCreated); @@ -955,7 +961,7 @@ } auto surface = WTF::MakeUnique<UnacceleratedImageBufferSurface>( - Size(), opacity_mode, kInitializeImagePixels, context_->color_params()); + Size(), opacity_mode, kInitializeImagePixels, GetCanvasColorParams()); if (surface->IsValid()) { CanvasMetrics::CountCanvasContextUsage( CanvasMetrics::kUnaccelerated2DCanvasImageBufferCreated);
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h index 23675df..0221e32 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -56,6 +56,7 @@ namespace blink { class AffineTransform; +class CanvasColorParams; class CanvasContextCreationAttributes; class CanvasRenderingContext; class CanvasRenderingContextFactory; @@ -304,6 +305,7 @@ void SetSurfaceSize(const IntSize&); bool PaintsIntoCanvasBuffer() const; + CanvasColorParams GetCanvasColorParams() const; ImageData* ToImageData(SourceDrawingBuffer, SnapshotReason) const;
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp index 2e459e0..8cc37030 100644 --- a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
@@ -220,7 +220,7 @@ if (!insertion_point->isConnected()) return; - link_loader_->Released(); + link_loader_->Abort(); if (!was_connected) { DCHECK(!GetLinkStyle() || !GetLinkStyle()->HasSheet());
diff --git a/third_party/WebKit/Source/web/ExternalDateTimeChooser.cpp b/third_party/WebKit/Source/core/html/forms/ExternalDateTimeChooser.cpp similarity index 98% rename from third_party/WebKit/Source/web/ExternalDateTimeChooser.cpp rename to third_party/WebKit/Source/core/html/forms/ExternalDateTimeChooser.cpp index 41602c9..cd06e5d 100644 --- a/third_party/WebKit/Source/web/ExternalDateTimeChooser.cpp +++ b/third_party/WebKit/Source/core/html/forms/ExternalDateTimeChooser.cpp
@@ -23,7 +23,7 @@ * SUCH DAMAGE. */ -#include "web/ExternalDateTimeChooser.h" +#include "core/html/forms/ExternalDateTimeChooser.h" #include "core/InputTypeNames.h" #include "core/html/forms/DateTimeChooserClient.h"
diff --git a/third_party/WebKit/Source/web/ExternalDateTimeChooser.h b/third_party/WebKit/Source/core/html/forms/ExternalDateTimeChooser.h similarity index 95% rename from third_party/WebKit/Source/web/ExternalDateTimeChooser.h rename to third_party/WebKit/Source/core/html/forms/ExternalDateTimeChooser.h index 207abb4..e1c96e4 100644 --- a/third_party/WebKit/Source/web/ExternalDateTimeChooser.h +++ b/third_party/WebKit/Source/core/html/forms/ExternalDateTimeChooser.h
@@ -26,6 +26,7 @@ #ifndef ExternalDateTimeChooser_h #define ExternalDateTimeChooser_h +#include "core/CoreExport.h" #include "core/html/forms/DateTimeChooser.h" namespace blink { @@ -35,7 +36,7 @@ class WebString; class WebViewClient; -class ExternalDateTimeChooser final : public DateTimeChooser { +class CORE_EXPORT ExternalDateTimeChooser final : public DateTimeChooser { public: static ExternalDateTimeChooser* Create(ChromeClient*, WebViewClient*,
diff --git a/third_party/WebKit/Source/core/loader/BUILD.gn b/third_party/WebKit/Source/core/loader/BUILD.gn index 01821207..45e3cf7 100644 --- a/third_party/WebKit/Source/core/loader/BUILD.gn +++ b/third_party/WebKit/Source/core/loader/BUILD.gn
@@ -105,8 +105,6 @@ "resource/ImageResourceObserver.h", "resource/LinkFetchResource.cpp", "resource/LinkFetchResource.h", - "resource/LinkPreloadResourceClients.cpp", - "resource/LinkPreloadResourceClients.h", "resource/MultipartImageResourceParser.cpp", "resource/MultipartImageResourceParser.h", "resource/ScriptResource.cpp",
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp index 8b4ff1cf..de9a99e 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -284,6 +284,13 @@ if (GetFrame()->GetSettings() && GetFrame()->GetSettings()->GetDataSaverEnabled()) request.SetHTTPHeaderField("Save-Data", "on"); + + if (GetLocalFrameClient()->IsClientLoFiActiveForFrame()) { + request.AddHTTPHeaderField( + "Intervention", + "<https://www.chromestatus.com/features/6072546726248448>; " + "level=\"warning\""); + } } // TODO(toyoshim, arthursonzogni): PlzNavigate doesn't use this function to set
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp index 4c6b217..6c976d2 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
@@ -88,6 +88,8 @@ MOCK_METHOD2(DispatchDidLoadResourceFromMemoryCache, void(const ResourceRequest&, const ResourceResponse&)); MOCK_METHOD0(UserAgent, String()); + MOCK_METHOD0(MayUseClientLoFiForImageRequests, bool()); + MOCK_METHOD0(IsClientLoFiActiveForFrame, bool()); }; class FixedPolicySubresourceFilter : public WebDocumentSubresourceFilter { @@ -1278,4 +1280,38 @@ EXPECT_EQ(nullptr, child_fetch_context->Archive()); } +// Tests if "Intervention" header is added for frame with Client Lo-Fi enabled. +TEST_F(FrameFetchContextMockedLocalFrameClientTest, + ClientLoFiInterventionHeader) { + // Verify header not added if Lo-Fi not active. + EXPECT_CALL(*client, IsClientLoFiActiveForFrame()) + .WillRepeatedly(testing::Return(false)); + ResourceRequest resource_request("http://www.example.com/style.css"); + fetch_context->AddAdditionalRequestHeaders(resource_request, + kFetchMainResource); + EXPECT_EQ(g_null_atom, resource_request.HttpHeaderField("Intervention")); + + // Verify header is added if Lo-Fi is active. + EXPECT_CALL(*client, IsClientLoFiActiveForFrame()) + .WillRepeatedly(testing::Return(true)); + fetch_context->AddAdditionalRequestHeaders(resource_request, + kFetchSubresource); + EXPECT_EQ( + "<https://www.chromestatus.com/features/6072546726248448>; " + "level=\"warning\"", + resource_request.HttpHeaderField("Intervention")); + + // Verify appended to an existing "Intervention" header value. + ResourceRequest resource_request2("http://www.example.com/getad.js"); + resource_request2.SetHTTPHeaderField("Intervention", + "<https://otherintervention.org>"); + fetch_context->AddAdditionalRequestHeaders(resource_request2, + kFetchSubresource); + EXPECT_EQ( + "<https://otherintervention.org>, " + "<https://www.chromestatus.com/features/6072546726248448>; " + "level=\"warning\"", + resource_request2.HttpHeaderField("Intervention")); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.cpp b/third_party/WebKit/Source/core/loader/LinkLoader.cpp index 8843652d..0a4f022 100644 --- a/third_party/WebKit/Source/core/loader/LinkLoader.cpp +++ b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
@@ -47,11 +47,12 @@ #include "core/loader/private/PrerenderHandle.h" #include "core/loader/resource/LinkFetchResource.h" #include "platform/Prerender.h" -#include "platform/Timer.h" #include "platform/loader/LinkHeader.h" #include "platform/loader/fetch/FetchInitiatorTypeNames.h" #include "platform/loader/fetch/FetchParameters.h" +#include "platform/loader/fetch/ResourceClient.h" #include "platform/loader/fetch/ResourceFetcher.h" +#include "platform/loader/fetch/ResourceFinishObserver.h" #include "platform/loader/fetch/ResourceLoaderOptions.h" #include "platform/network/mime/MIMETypeRegistry.h" #include "public/platform/WebPrerender.h" @@ -74,40 +75,65 @@ return result; } +class LinkLoader::FinishObserver final + : public GarbageCollectedFinalized<ResourceFinishObserver>, + public ResourceFinishObserver { + USING_GARBAGE_COLLECTED_MIXIN(FinishObserver); + USING_PRE_FINALIZER(FinishObserver, ClearResource); + + public: + FinishObserver(LinkLoader* loader, + Resource* resource, + Resource::PreloadReferencePolicy reference_policy) + : loader_(loader), resource_(resource) { + resource_->AddFinishObserver(this, reference_policy); + } + + // ResourceFinishObserver implementation + void NotifyFinished() override { + if (!resource_) + return; + loader_->NotifyFinished(); + ClearResource(); + } + String DebugName() const override { + return "LinkLoader::ResourceFinishObserver"; + } + + Resource* GetResource() { return resource_; } + void ClearResource() { + if (!resource_) + return; + resource_->RemoveFinishObserver(this); + resource_ = nullptr; + } + + DEFINE_INLINE_VIRTUAL_TRACE() { + visitor->Trace(loader_); + visitor->Trace(resource_); + blink::ResourceFinishObserver::Trace(visitor); + } + + private: + Member<LinkLoader> loader_; + Member<Resource> resource_; +}; + LinkLoader::LinkLoader(LinkLoaderClient* client, RefPtr<WebTaskRunner> task_runner) - : client_(client), - link_load_timer_(task_runner, this, &LinkLoader::LinkLoadTimerFired), - link_loading_error_timer_(task_runner, - this, - &LinkLoader::LinkLoadingErrorTimerFired) { + : client_(client) { DCHECK(client_); } LinkLoader::~LinkLoader() {} -void LinkLoader::LinkLoadTimerFired(TimerBase* timer) { - DCHECK_EQ(timer, &link_load_timer_); - client_->LinkLoaded(); -} - -void LinkLoader::LinkLoadingErrorTimerFired(TimerBase* timer) { - DCHECK_EQ(timer, &link_loading_error_timer_); - client_->LinkLoadingErrored(); -} - -void LinkLoader::TriggerEvents(const Resource* resource) { +void LinkLoader::NotifyFinished() { + DCHECK(finish_observer_); + Resource* resource = finish_observer_->GetResource(); if (resource->ErrorOccurred()) - link_loading_error_timer_.StartOneShot(0, BLINK_FROM_HERE); + client_->LinkLoadingErrored(); else - link_load_timer_.StartOneShot(0, BLINK_FROM_HERE); -} - -void LinkLoader::NotifyFinished(Resource* resource) { - DCHECK_EQ(this->GetResource(), resource); - - TriggerEvents(resource); - ClearResource(); + client_->LinkLoaded(); } void LinkLoader::DidStartPrerender() { @@ -233,41 +259,8 @@ return WTF::nullopt; } -Resource* LinkLoader::LinkPreloadedResourceForTesting() { - return link_preload_resource_client_ - ? link_preload_resource_client_->GetResource() - : nullptr; -} - -void LinkLoader::CreateLinkPreloadResourceClient(Resource* resource) { - if (!resource) - return; - switch (resource->GetType()) { - case Resource::kImage: - link_preload_resource_client_ = LinkPreloadImageResourceClient::Create( - this, ToImageResource(resource)); - break; - case Resource::kScript: - link_preload_resource_client_ = LinkPreloadScriptResourceClient::Create( - this, ToScriptResource(resource)); - break; - case Resource::kCSSStyleSheet: - link_preload_resource_client_ = LinkPreloadStyleResourceClient::Create( - this, ToCSSStyleSheetResource(resource)); - break; - case Resource::kFont: - link_preload_resource_client_ = - LinkPreloadFontResourceClient::Create(this, ToFontResource(resource)); - break; - case Resource::kMedia: - case Resource::kTextTrack: - case Resource::kRaw: - link_preload_resource_client_ = - LinkPreloadRawResourceClient::Create(this, ToRawResource(resource)); - break; - default: - NOTREACHED(); - } +Resource* LinkLoader::GetResourceForTesting() { + return finish_observer_ ? finish_observer_->GetResource() : nullptr; } static bool IsSupportedType(Resource::Type resource_type, @@ -473,6 +466,9 @@ const KURL& href, Document& document, const NetworkHintsInterface& network_hints_interface) { + // If any loading process is in progress, abort it. + Abort(); + if (!client_->ShouldLoadLink()) return false; @@ -483,17 +479,22 @@ cross_origin, network_hints_interface, kLinkCalledFromMarkup); - CreateLinkPreloadResourceClient(PreloadIfNeeded( + Resource* preloaded_resource = PreloadIfNeeded( rel_attribute, href, document, as, type, media, cross_origin, - kLinkCalledFromMarkup, nullptr, referrer_policy)); + kLinkCalledFromMarkup, nullptr, referrer_policy); + Resource* prefetched_resource = PrefetchIfNeeded( + document, href, rel_attribute, cross_origin, referrer_policy); - if (href.IsEmpty() || !href.IsValid()) - Released(); + DCHECK(!preloaded_resource || !prefetched_resource); - Resource* resource = PrefetchIfNeeded(document, href, rel_attribute, - cross_origin, referrer_policy); - if (resource) - SetResource(resource); + if (preloaded_resource) { + finish_observer_ = new FinishObserver(this, preloaded_resource, + Resource::kDontMarkAsReferenced); + } + if (prefetched_resource) { + finish_observer_ = new FinishObserver(this, prefetched_resource, + Resource::kMarkAsReferenced); + } if (const unsigned prerender_rel_types = PrerenderRelTypesFromRelAttribute(rel_attribute, document)) { @@ -513,22 +514,21 @@ return true; } -void LinkLoader::Released() { - // Only prerenders need treatment here; other links either use the Resource - // interface, or are notionally atomic (dns prefetch). +void LinkLoader::Abort() { if (prerender_) { prerender_->Cancel(); prerender_.Clear(); } - if (link_preload_resource_client_) - link_preload_resource_client_->Clear(); + if (finish_observer_) { + finish_observer_->ClearResource(); + finish_observer_ = nullptr; + } } DEFINE_TRACE(LinkLoader) { + visitor->Trace(finish_observer_); visitor->Trace(client_); visitor->Trace(prerender_); - visitor->Trace(link_preload_resource_client_); - ResourceOwner<Resource, ResourceClient>::Trace(visitor); PrerenderClient::Trace(visitor); }
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.h b/third_party/WebKit/Source/core/loader/LinkLoader.h index 35a4ad81..48233cc 100644 --- a/third_party/WebKit/Source/core/loader/LinkLoader.h +++ b/third_party/WebKit/Source/core/loader/LinkLoader.h
@@ -34,10 +34,8 @@ #include "core/CoreExport.h" #include "core/loader/LinkLoaderClient.h" -#include "core/loader/resource/LinkPreloadResourceClients.h" #include "platform/CrossOriginAttributeValue.h" #include "platform/PrerenderClient.h" -#include "platform/loader/fetch/ResourceClient.h" #include "platform/loader/fetch/ResourceOwner.h" #include "platform/wtf/Optional.h" @@ -54,7 +52,6 @@ // prerender. class CORE_EXPORT LinkLoader final : public GarbageCollectedFinalized<LinkLoader>, - public ResourceOwner<Resource, ResourceClient>, public PrerenderClient { USING_GARBAGE_COLLECTED_MIXIN(LinkLoader); @@ -64,19 +61,13 @@ } ~LinkLoader() override; - // from ResourceClient - void NotifyFinished(Resource*) override; - String DebugName() const override { return "LinkLoader"; } - // from PrerenderClient void DidStartPrerender() override; void DidStopPrerender() override; void DidSendLoadForPrerender() override; void DidSendDOMContentLoadedForPrerender() override; - void TriggerEvents(const Resource*); - - void Released(); + void Abort(); bool LoadLink(const LinkRelAttribute&, CrossOriginAttributeValue, const String& type, @@ -105,24 +96,20 @@ static WTF::Optional<Resource::Type> GetResourceTypeFromAsAttribute( const String& as); - Resource* LinkPreloadedResourceForTesting(); + Resource* GetResourceForTesting(); DECLARE_TRACE(); private: + class FinishObserver; LinkLoader(LinkLoaderClient*, RefPtr<WebTaskRunner>); - void LinkLoadTimerFired(TimerBase*); - void LinkLoadingErrorTimerFired(TimerBase*); - void CreateLinkPreloadResourceClient(Resource*); + void NotifyFinished(); + Member<FinishObserver> finish_observer_; Member<LinkLoaderClient> client_; - TaskRunnerTimer<LinkLoader> link_load_timer_; - TaskRunnerTimer<LinkLoader> link_loading_error_timer_; - Member<PrerenderHandle> prerender_; - Member<LinkPreloadResourceClient> link_preload_resource_client_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp index b6c2d5343..fe995f5f 100644 --- a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp +++ b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
@@ -125,7 +125,7 @@ if (test_case.expecting_load && test_case.priority != kResourceLoadPriorityUnresolved) { ASSERT_EQ(1, fetcher->CountPreloads()); - Resource* resource = loader->LinkPreloadedResourceForTesting(); + Resource* resource = loader->GetResourceForTesting(); ASSERT_NE(resource, nullptr); EXPECT_TRUE(fetcher->ContainsAsPreload(resource)); EXPECT_EQ(test_case.priority, resource->GetResourceRequest().Priority()); @@ -310,7 +310,7 @@ test_case.referrer_policy, href_url, dummy_page_holder->GetDocument(), NetworkHintsMock()); ASSERT_TRUE(dummy_page_holder->GetDocument().Fetcher()); - Resource* resource = loader->GetResource(); + Resource* resource = loader->GetResourceForTesting(); if (test_case.expecting_load) { EXPECT_TRUE(resource); } else {
diff --git a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp index 1cb7788..66ff744 100644 --- a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp +++ b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp
@@ -149,6 +149,8 @@ } void CSSStyleSheetResource::CheckNotify() { + TriggerNotificationForFinishObservers(); + // Decode the data to find out the encoding and cache the decoded sheet text. if (Data()) SetDecodedSheetText(DecodedText());
diff --git a/third_party/WebKit/Source/core/loader/resource/LinkPreloadResourceClients.cpp b/third_party/WebKit/Source/core/loader/resource/LinkPreloadResourceClients.cpp deleted file mode 100644 index ea9e65cc..0000000 --- a/third_party/WebKit/Source/core/loader/resource/LinkPreloadResourceClients.cpp +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "core/loader/resource/LinkPreloadResourceClients.h" - -#include "core/loader/LinkLoader.h" - -namespace blink { - -void LinkPreloadResourceClient::TriggerEvents(const Resource* resource) { - if (loader_) - loader_->TriggerEvents(resource); -} -}
diff --git a/third_party/WebKit/Source/core/loader/resource/LinkPreloadResourceClients.h b/third_party/WebKit/Source/core/loader/resource/LinkPreloadResourceClients.h deleted file mode 100644 index a3e73d3..0000000 --- a/third_party/WebKit/Source/core/loader/resource/LinkPreloadResourceClients.h +++ /dev/null
@@ -1,228 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef LinkPreloadResourceClients_h -#define LinkPreloadResourceClients_h - -#include "core/loader/resource/CSSStyleSheetResource.h" -#include "core/loader/resource/FontResource.h" -#include "core/loader/resource/ImageResource.h" -#include "core/loader/resource/ScriptResource.h" -#include "core/loader/resource/StyleSheetResourceClient.h" -#include "platform/loader/fetch/RawResource.h" -#include "platform/loader/fetch/ResourceOwner.h" - -namespace blink { - -class LinkLoader; - -class LinkPreloadResourceClient - : public GarbageCollectedFinalized<LinkPreloadResourceClient> { - public: - virtual ~LinkPreloadResourceClient() {} - - void TriggerEvents(const Resource*); - virtual Resource* GetResource() = 0; - virtual void Clear() = 0; - - DEFINE_INLINE_VIRTUAL_TRACE() { visitor->Trace(loader_); } - - protected: - explicit LinkPreloadResourceClient(LinkLoader* loader) : loader_(loader) { - DCHECK(loader); - } - - private: - Member<LinkLoader> loader_; -}; - -class LinkPreloadScriptResourceClient - : public LinkPreloadResourceClient, - public ResourceOwner<ScriptResource, ScriptResourceClient> { - USING_GARBAGE_COLLECTED_MIXIN(LinkPreloadScriptResourceClient); - - public: - static LinkPreloadScriptResourceClient* Create(LinkLoader* loader, - ScriptResource* resource) { - return new LinkPreloadScriptResourceClient(loader, resource); - } - - virtual String DebugName() const { return "LinkPreloadScript"; } - virtual ~LinkPreloadScriptResourceClient() {} - - Resource* GetResource() override { - return ResourceOwner<ScriptResource>::GetResource(); - } - void Clear() override { ClearResource(); } - - void NotifyFinished(Resource* resource) override { - DCHECK_EQ(this->GetResource(), resource); - TriggerEvents(resource); - } - - DEFINE_INLINE_VIRTUAL_TRACE() { - LinkPreloadResourceClient::Trace(visitor); - ResourceOwner<ScriptResource, ScriptResourceClient>::Trace(visitor); - } - - private: - LinkPreloadScriptResourceClient(LinkLoader* loader, ScriptResource* resource) - : LinkPreloadResourceClient(loader) { - SetResource(resource, Resource::kDontMarkAsReferenced); - } -}; - -class LinkPreloadStyleResourceClient - : public LinkPreloadResourceClient, - public ResourceOwner<CSSStyleSheetResource, StyleSheetResourceClient> { - USING_GARBAGE_COLLECTED_MIXIN(LinkPreloadStyleResourceClient); - - public: - static LinkPreloadStyleResourceClient* Create( - LinkLoader* loader, - CSSStyleSheetResource* resource) { - return new LinkPreloadStyleResourceClient(loader, resource); - } - - virtual String DebugName() const { return "LinkPreloadStyle"; } - virtual ~LinkPreloadStyleResourceClient() {} - - Resource* GetResource() override { - return ResourceOwner<CSSStyleSheetResource>::GetResource(); - } - void Clear() override { ClearResource(); } - - void SetCSSStyleSheet(const String&, - const KURL&, - ReferrerPolicy, - const String&, - const CSSStyleSheetResource* resource) override { - DCHECK_EQ(this->GetResource(), resource); - TriggerEvents(static_cast<const Resource*>(resource)); - } - - DEFINE_INLINE_VIRTUAL_TRACE() { - LinkPreloadResourceClient::Trace(visitor); - ResourceOwner<CSSStyleSheetResource, StyleSheetResourceClient>::Trace( - visitor); - } - - private: - LinkPreloadStyleResourceClient(LinkLoader* loader, - CSSStyleSheetResource* resource) - : LinkPreloadResourceClient(loader) { - SetResource(resource, Resource::kDontMarkAsReferenced); - } -}; - -class LinkPreloadImageResourceClient : public LinkPreloadResourceClient, - public ResourceOwner<ImageResource> { - USING_GARBAGE_COLLECTED_MIXIN(LinkPreloadImageResourceClient); - - public: - static LinkPreloadImageResourceClient* Create(LinkLoader* loader, - ImageResource* resource) { - return new LinkPreloadImageResourceClient(loader, resource); - } - - virtual String DebugName() const { return "LinkPreloadImage"; } - virtual ~LinkPreloadImageResourceClient() {} - - Resource* GetResource() override { - return ResourceOwner<ImageResource>::GetResource(); - } - void Clear() override { ClearResource(); } - - void NotifyFinished(Resource* resource) override { - DCHECK_EQ(this->GetResource(), ToImageResource(resource)); - TriggerEvents(resource); - } - - DEFINE_INLINE_VIRTUAL_TRACE() { - LinkPreloadResourceClient::Trace(visitor); - ResourceOwner<ImageResource>::Trace(visitor); - } - - private: - LinkPreloadImageResourceClient(LinkLoader* loader, ImageResource* resource) - : LinkPreloadResourceClient(loader) { - SetResource(resource, Resource::kDontMarkAsReferenced); - } -}; - -class LinkPreloadFontResourceClient - : public LinkPreloadResourceClient, - public ResourceOwner<FontResource, FontResourceClient> { - USING_GARBAGE_COLLECTED_MIXIN(LinkPreloadFontResourceClient); - - public: - static LinkPreloadFontResourceClient* Create(LinkLoader* loader, - FontResource* resource) { - return new LinkPreloadFontResourceClient(loader, resource); - } - - virtual String DebugName() const { return "LinkPreloadFont"; } - virtual ~LinkPreloadFontResourceClient() {} - - Resource* GetResource() override { - return ResourceOwner<FontResource>::GetResource(); - } - void Clear() override { ClearResource(); } - - void NotifyFinished(Resource* resource) override { - DCHECK_EQ(this->GetResource(), ToFontResource(resource)); - TriggerEvents(resource); - } - - DEFINE_INLINE_VIRTUAL_TRACE() { - LinkPreloadResourceClient::Trace(visitor); - ResourceOwner<FontResource, FontResourceClient>::Trace(visitor); - } - - private: - LinkPreloadFontResourceClient(LinkLoader* loader, FontResource* resource) - : LinkPreloadResourceClient(loader) { - SetResource(resource, Resource::kDontMarkAsReferenced); - } -}; - -class LinkPreloadRawResourceClient - : public LinkPreloadResourceClient, - public ResourceOwner<RawResource, RawResourceClient> { - USING_GARBAGE_COLLECTED_MIXIN(LinkPreloadRawResourceClient); - - public: - static LinkPreloadRawResourceClient* Create(LinkLoader* loader, - RawResource* resource) { - return new LinkPreloadRawResourceClient(loader, resource); - } - - virtual String DebugName() const { return "LinkPreloadRaw"; } - virtual ~LinkPreloadRawResourceClient() {} - - Resource* GetResource() override { - return ResourceOwner<RawResource>::GetResource(); - } - void Clear() override { ClearResource(); } - - void NotifyFinished(Resource* resource) override { - DCHECK_EQ(this->GetResource(), ToRawResource(resource)); - TriggerEvents(resource); - } - - DEFINE_INLINE_VIRTUAL_TRACE() { - LinkPreloadResourceClient::Trace(visitor); - ResourceOwner<RawResource, RawResourceClient>::Trace(visitor); - } - - private: - LinkPreloadRawResourceClient(LinkLoader* loader, RawResource* resource) - : LinkPreloadResourceClient(loader) { - SetResource(resource, Resource::kDontMarkAsReferenced); - } -}; - -} // namespace blink - -#endif // LinkPreloadResourceClients_h
diff --git a/third_party/WebKit/Source/core/loader/resource/XSLStyleSheetResource.cpp b/third_party/WebKit/Source/core/loader/resource/XSLStyleSheetResource.cpp index 4ee7c443..f222f060 100644 --- a/third_party/WebKit/Source/core/loader/resource/XSLStyleSheetResource.cpp +++ b/third_party/WebKit/Source/core/loader/resource/XSLStyleSheetResource.cpp
@@ -88,6 +88,8 @@ } void XSLStyleSheetResource::CheckNotify() { + TriggerNotificationForFinishObservers(); + if (Data()) sheet_ = DecodedText();
diff --git a/third_party/WebKit/Source/core/page/BUILD.gn b/third_party/WebKit/Source/core/page/BUILD.gn index b210479..2e1a05dd 100644 --- a/third_party/WebKit/Source/core/page/BUILD.gn +++ b/third_party/WebKit/Source/core/page/BUILD.gn
@@ -26,6 +26,8 @@ "DragState.h", "EditorClient.h", "EventWithHitTestResults.h", + "ExternalPopupMenu.cpp", + "ExternalPopupMenu.h", "FocusChangedObserver.cpp", "FocusChangedObserver.h", "FocusController.cpp", @@ -52,6 +54,8 @@ "PageWidgetDelegate.h", "PointerLockController.cpp", "PointerLockController.h", + "PopupMenuImpl.cpp", + "PopupMenuImpl.h", "PopupOpeningObserver.h", "PrintContext.cpp", "PrintContext.h",
diff --git a/third_party/WebKit/Source/web/ExternalPopupMenu.cpp b/third_party/WebKit/Source/core/page/ExternalPopupMenu.cpp similarity index 95% rename from third_party/WebKit/Source/web/ExternalPopupMenu.cpp rename to third_party/WebKit/Source/core/page/ExternalPopupMenu.cpp index e1cb3c49..9b78c24 100644 --- a/third_party/WebKit/Source/web/ExternalPopupMenu.cpp +++ b/third_party/WebKit/Source/core/page/ExternalPopupMenu.cpp
@@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "web/ExternalPopupMenu.h" +#include "core/page/ExternalPopupMenu.h" #include "core/dom/NodeComputedStyle.h" #include "core/dom/TaskRunnerHelper.h" @@ -53,6 +53,9 @@ #include "public/web/WebMenuItemInfo.h" #include "public/web/WebPopupMenuInfo.h" #include "public/web/WebView.h" +#if OS(MACOSX) +#include "core/page/ChromeClient.h" +#endif namespace blink { @@ -103,19 +106,22 @@ IntRect rect_in_viewport = local_frame_->View()->ContentsToViewport(rect); web_external_popup_menu_->Show(rect_in_viewport); return true; - } else { - // The client might refuse to create a popup (when there is already one - // pending to be shown for example). - DidCancel(); - return false; } + + // The client might refuse to create a popup (when there is already one + // pending to be shown for example). + DidCancel(); + return false; } void ExternalPopupMenu::Show() { if (!ShowInternal()) return; #if OS(MACOSX) - const WebInputEvent* current_event = WebViewBase::CurrentInputEvent(); + // TODO(sashab): Change this back to WebViewBase::CurrentInputEvent() once + // WebViewImpl is in core/. + const WebInputEvent* current_event = + local_frame_->GetPage()->GetChromeClient().GetCurrentInputEvent(); if (current_event && current_event->GetType() == WebInputEvent::kMouseDown) { synthetic_event_ = WTF::WrapUnique(new WebMouseEvent); *synthetic_event_ = *static_cast<const WebMouseEvent*>(current_event);
diff --git a/third_party/WebKit/Source/web/ExternalPopupMenu.h b/third_party/WebKit/Source/core/page/ExternalPopupMenu.h similarity index 94% rename from third_party/WebKit/Source/web/ExternalPopupMenu.h rename to third_party/WebKit/Source/core/page/ExternalPopupMenu.h index aa6d8019..67469e27 100644 --- a/third_party/WebKit/Source/web/ExternalPopupMenu.h +++ b/third_party/WebKit/Source/core/page/ExternalPopupMenu.h
@@ -32,13 +32,13 @@ #define ExternalPopupMenu_h #include <memory> +#include "core/CoreExport.h" #include "platform/PopupMenu.h" #include "platform/Timer.h" #include "platform/wtf/Compiler.h" #include "public/platform/WebCanvas.h" #include "public/platform/WebScrollbar.h" #include "public/web/WebExternalPopupMenuClient.h" -#include "web/WebExport.h" namespace blink { @@ -51,8 +51,8 @@ // The ExternalPopupMenu connects the actual implementation of the popup menu // to the WebCore popup menu. -class WEB_EXPORT ExternalPopupMenu final : NON_EXPORTED_BASE(public PopupMenu), - public WebExternalPopupMenuClient { +class CORE_EXPORT ExternalPopupMenu final : NON_EXPORTED_BASE(public PopupMenu), + public WebExternalPopupMenuClient { public: ExternalPopupMenu(LocalFrame&, HTMLSelectElement&, WebView&); ~ExternalPopupMenu() override;
diff --git a/third_party/WebKit/Source/web/PopupMenuImpl.cpp b/third_party/WebKit/Source/core/page/PopupMenuImpl.cpp similarity index 98% rename from third_party/WebKit/Source/web/PopupMenuImpl.cpp rename to third_party/WebKit/Source/core/page/PopupMenuImpl.cpp index 0cdfa6d9..fe25f2ef 100644 --- a/third_party/WebKit/Source/web/PopupMenuImpl.cpp +++ b/third_party/WebKit/Source/core/page/PopupMenuImpl.cpp
@@ -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 "web/PopupMenuImpl.h" +#include "core/page/PopupMenuImpl.h" #include "core/HTMLNames.h" #include "core/css/CSSFontSelector.h" @@ -366,9 +366,10 @@ AddProperty("fontSize", font_description.ComputedPixelSize(), data); } // Our UA stylesheet has font-weight:normal for OPTION. - if (kFontWeightNormal != font_description.Weight()) + if (kFontWeightNormal != font_description.Weight()) { AddProperty("fontWeight", String(FontWeightToString(font_description.Weight())), data); + } if (base_font.Family() != font_description.Family()) { PagePopupClient::AddString("fontFamily: [\n", data); for (const FontFamily* f = &font_description.Family(); f; f = f->Next()) { @@ -378,17 +379,19 @@ } PagePopupClient::AddString("],\n", data); } - if (base_font.Style() != font_description.Style()) + if (base_font.Style() != font_description.Style()) { AddProperty("fontStyle", String(FontStyleToString(font_description.Style())), data); + } if (base_font.VariantCaps() != font_description.VariantCaps() && font_description.VariantCaps() == FontDescription::kSmallCaps) AddProperty("fontVariant", String("small-caps"), data); - if (base_style.TextTransform() != style->TextTransform()) + if (base_style.TextTransform() != style->TextTransform()) { AddProperty("textTransform", String(TextTransformToString(style->TextTransform())), data); + } PagePopupClient::AddString("},\n", data); }
diff --git a/third_party/WebKit/Source/web/PopupMenuImpl.h b/third_party/WebKit/Source/core/page/PopupMenuImpl.h similarity index 87% rename from third_party/WebKit/Source/web/PopupMenuImpl.h rename to third_party/WebKit/Source/core/page/PopupMenuImpl.h index 4ddebf4..3f1c13fa 100644 --- a/third_party/WebKit/Source/web/PopupMenuImpl.h +++ b/third_party/WebKit/Source/core/page/PopupMenuImpl.h
@@ -5,6 +5,7 @@ #ifndef PopupMenuImpl_h #define PopupMenuImpl_h +#include "core/CoreExport.h" #include "core/page/PagePopupClient.h" #include "platform/PopupMenu.h" @@ -18,7 +19,9 @@ class HTMLOptionElement; class HTMLSelectElement; -class PopupMenuImpl final : public PopupMenu, public PagePopupClient { +// TODO(sashab): Merge this class with its parent (PopupMenu). +class CORE_EXPORT PopupMenuImpl final : NON_EXPORTED_BASE(public PopupMenu), + public PagePopupClient { public: static PopupMenuImpl* Create(ChromeClient*, HTMLSelectElement&); ~PopupMenuImpl() override;
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js index 09f65a3..b2c8e893 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js +++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js
@@ -99,6 +99,8 @@ */ backgroundColor() { var bgColors = Network.NetworkNode._themedBackgroundColors(); + if (this.selected) + return /** @type {string} */ (bgColors.Selected.asString(Common.Color.Format.HEX)); var color = this.isStriped() ? bgColors.Stripe : bgColors.Default; if (this.isNavigationRequest()) color = color.blendWith(bgColors.Navigation); @@ -108,8 +110,6 @@ color = color.blendWith(bgColors.InitiatorPath); if (this.isOnInitiatedPath()) color = color.blendWith(bgColors.InitiatedPath); - if (this.selected) - color = color.blendWith(bgColors.Selected); return /** @type {string} */ (color.asString(Common.Color.Format.HEX)); }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js index 8270c73..12ad336 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -1274,6 +1274,7 @@ showPane(parent) { this.show(parent); parent.classList.add('tinted'); + this._stopButton.focus(); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js index 3899a4b..097c516a 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
@@ -84,7 +84,7 @@ this._splitWidget.setSidebarWidget(this._detailsView); this._splitWidget.hideSidebar(); this._splitWidget.show(this.element); - this._splitWidget.addEventListener(UI.SplitWidget.Events.ShowModeChanged, this._updateDetailsForSelection, this); + this._splitWidget.addEventListener(UI.SplitWidget.Events.ShowModeChanged, this._onShowModeChanged, this); /** @type {?TimelineModel.TimelineProfileTree.Node|undefined} */ this._lastSelectedNode; @@ -352,6 +352,13 @@ } } + _onShowModeChanged() { + if (this._splitWidget.showMode() === UI.SplitWidget.ShowMode.OnlyMain) + return; + this._lastSelectedNode = undefined; + this._updateDetailsForSelection(); + } + _updateDetailsForSelection() { var selectedNode = this._dataGrid.selectedNode ? /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (this._dataGrid.selectedNode)._profileNode : @@ -363,10 +370,10 @@ return; this._detailsView.detachChildWidgets(); this._detailsView.element.removeChildren(); - if (!selectedNode || !this._showDetailsForNode(selectedNode)) { - var banner = this._detailsView.element.createChild('div', 'full-widget-dimmed-banner'); - banner.createTextChild(Common.UIString('Select item for details.')); - } + if (selectedNode && this._showDetailsForNode(selectedNode)) + return; + var banner = this._detailsView.element.createChild('div', 'full-widget-dimmed-banner'); + banner.createTextChild(Common.UIString('Select item for details.')); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css index 2c66eae..729a8fc 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css +++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
@@ -623,11 +623,12 @@ } .timeline-stack-view-header { - height: 26px; + height: 27px; background-color: white; padding: 6px 10px; color: #5a5a5a; white-space: nowrap; + border-bottom: 1px solid #dadada; } .timeline-landing-page {
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.h b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.h index d6e2aef..9097193fb 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.h +++ b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.h
@@ -125,7 +125,7 @@ // used for objects without backing elements AXObjectImpl* GetOrCreate(AccessibilityRole); - AXObjectImpl* GetOrCreate(LayoutObject*); + AXObjectImpl* GetOrCreate(LayoutObject*) override; AXObjectImpl* GetOrCreate(Node*); AXObjectImpl* GetOrCreate(AbstractInlineTextBox*);
diff --git a/third_party/WebKit/Source/modules/exported/WebAXObject.cpp b/third_party/WebKit/Source/modules/exported/WebAXObject.cpp index 52efb1f..088e3a3a 100644 --- a/third_party/WebKit/Source/modules/exported/WebAXObject.cpp +++ b/third_party/WebKit/Source/modules/exported/WebAXObject.cpp
@@ -1554,7 +1554,7 @@ WebAXObject WebAXObject::FromWebNode(const WebNode& web_node) { WebDocument web_document = web_node.GetDocument(); const Document* doc = web_document.ConstUnwrap<Document>(); - AXObjectCacheBase* cache = ToAXObjectCacheBase(doc->ExistingAXObjectCache()); + AXObjectCacheImpl* cache = ToAXObjectCacheImpl(doc->ExistingAXObjectCache()); const Node* node = web_node.ConstUnwrap<Node>(); return cache ? WebAXObject(cache->Get(node)) : WebAXObject(); }
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni index 25f7705..f4c23b11 100644 --- a/third_party/WebKit/Source/modules/modules_idl_files.gni +++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -477,6 +477,7 @@ "payments/AndroidPayMethodData.idl", "payments/AndroidPayTokenization.idl", "payments/BasicCardRequest.idl", + "payments/ImageObject.idl", "payments/PaymentAppResponse.idl", "payments/PaymentRequestEventInit.idl", "payments/PaymentCurrencyAmount.idl",
diff --git a/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtilsClientImpl.h b/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtilsClientImpl.h index f6409f1..ae823f1 100644 --- a/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtilsClientImpl.h +++ b/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtilsClientImpl.h
@@ -14,8 +14,9 @@ class WebLocalFrameBase; +// TODO(sashab): Merge this class with its parent (NavigatorContentUtilsClient). class MODULES_EXPORT NavigatorContentUtilsClientImpl final - : public NON_EXPORTED_BASE(NavigatorContentUtilsClient) { + : NON_EXPORTED_BASE(public NavigatorContentUtilsClient) { public: static NavigatorContentUtilsClientImpl* Create(WebLocalFrameBase*); ~NavigatorContentUtilsClientImpl() override {}
diff --git a/third_party/WebKit/Source/modules/payments/ImageObject.idl b/third_party/WebKit/Source/modules/payments/ImageObject.idl new file mode 100644 index 0000000..ac8f460 --- /dev/null +++ b/third_party/WebKit/Source/modules/payments/ImageObject.idl
@@ -0,0 +1,16 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://github.com/w3c/payment-handler/pull/174/files/6e6768c423e24719cb0e592cd98614f052e52a78 + +dictionary ImageObject { + // Note that the src could be relative path to the service worker + // scope. + required USVString src; + + // TODO(gogerald): Below two attributes have not been used for now. + // Enable them when necessary. + // DOMString sizes; + // DOMString type; +}; \ No newline at end of file
diff --git a/third_party/WebKit/Source/modules/payments/PaymentInstrument.idl b/third_party/WebKit/Source/modules/payments/PaymentInstrument.idl index 9f57261..ad09a3376 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentInstrument.idl +++ b/third_party/WebKit/Source/modules/payments/PaymentInstrument.idl
@@ -2,15 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://w3c.github.io/webpayments-payment-apps-api/#payment-instrument +// https://w3c.github.io/payment-handler/#paymentinstrument-dictionary dictionary PaymentInstrument { required DOMString name; - // TODO(zino): PaymentInstrument should have icons attribute. - // The spec[1] defines it as a sequence of ImageObject but its definition - // is not clear yet. - // Please see: https://github.com/w3c/webpayments-payment-apps-api/issues/69 - // sequence<ImageObject> icons; + sequence<ImageObject> icons; sequence<DOMString> enabledMethods; object capabilities; };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentInstruments.cpp b/third_party/WebKit/Source/modules/payments/PaymentInstruments.cpp index 8905048b..2da969b6 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentInstruments.cpp +++ b/third_party/WebKit/Source/modules/payments/PaymentInstruments.cpp
@@ -41,6 +41,11 @@ resolver->Reject(DOMException::Create(kInvalidStateError, "Storage operation is failed")); return true; + case payments::mojom::blink::PaymentHandlerStatus:: + FETCH_INSTRUMENT_ICON_FAILED: + resolver->Reject(DOMException::Create( + kNotFoundError, "Fetch or decode instrument icon failed")); + return true; } NOTREACHED(); return false; @@ -139,6 +144,22 @@ payments::mojom::blink::PaymentInstrumentPtr instrument = payments::mojom::blink::PaymentInstrument::New(); instrument->name = details.hasName() ? details.name() : WTF::g_empty_string; + if (details.hasIcons()) { + ExecutionContext* context = ExecutionContext::From(script_state); + for (const ImageObject image_object : details.icons()) { + KURL parsed_url = context->CompleteURL(image_object.src()); + if (!parsed_url.IsValid() || !parsed_url.ProtocolIsInHTTPFamily()) { + resolver->Reject(V8ThrowException::CreateTypeError( + script_state->GetIsolate(), + "'" + image_object.src() + "' is not a valid URL.")); + return promise; + } + + instrument->icons.push_back(payments::mojom::blink::ImageObject::New()); + instrument->icons.back()->src = parsed_url; + } + } + if (details.hasEnabledMethods()) { instrument->enabled_methods = details.enabledMethods(); } @@ -200,6 +221,15 @@ return; PaymentInstrument instrument; instrument.setName(stored_instrument->name); + + HeapVector<ImageObject> icons; + for (const auto& icon : stored_instrument->icons) { + ImageObject image_object; + image_object.setSrc(icon->src.GetString()); + icons.emplace_back(image_object); + } + instrument.setIcons(icons); + Vector<String> enabled_methods; for (const auto& method : stored_instrument->enabled_methods) { enabled_methods.push_back(method);
diff --git a/third_party/WebKit/Source/platform/PopupMenu.h b/third_party/WebKit/Source/platform/PopupMenu.h index 58f2159..25b6aca 100644 --- a/third_party/WebKit/Source/platform/PopupMenu.h +++ b/third_party/WebKit/Source/platform/PopupMenu.h
@@ -26,6 +26,7 @@ namespace blink { +// TODO(sashab): Move PopupMenu to core/page. class PopupMenu : public GarbageCollectedFinalized<PopupMenu> { public: virtual ~PopupMenu() {}
diff --git a/third_party/WebKit/Source/platform/loader/BUILD.gn b/third_party/WebKit/Source/platform/loader/BUILD.gn index 62e39ebc..60842f9c 100644 --- a/third_party/WebKit/Source/platform/loader/BUILD.gn +++ b/third_party/WebKit/Source/platform/loader/BUILD.gn
@@ -51,6 +51,7 @@ "fetch/ResourceError.h", "fetch/ResourceFetcher.cpp", "fetch/ResourceFetcher.h", + "fetch/ResourceFinishObserver.h", "fetch/ResourceLoadInfo.h", "fetch/ResourceLoadPriority.h", "fetch/ResourceLoadTiming.cpp",
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchUtils.cpp b/third_party/WebKit/Source/platform/loader/fetch/FetchUtils.cpp index 5580e6d..b1c5137 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/FetchUtils.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/FetchUtils.cpp
@@ -93,13 +93,16 @@ // Data Saver feature is enabled. // Treat inspector headers as a simple headers, since they are added by blink // when the inspector is open. + // Treat 'Intervention' as a simple header, since it is added by Chrome when + // an intervention is (or may be) applied. if (EqualIgnoringASCIICase(name, "accept") || EqualIgnoringASCIICase(name, "accept-language") || EqualIgnoringASCIICase(name, "content-language") || EqualIgnoringASCIICase( name, HTTPNames::X_DevTools_Emulate_Network_Conditions_Client_Id) || - EqualIgnoringASCIICase(name, "save-data")) + EqualIgnoringASCIICase(name, "save-data") || + EqualIgnoringASCIICase(name, "intervention")) return true; if (EqualIgnoringASCIICase(name, "content-type"))
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp index d67a8fa..0e554ea5 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
@@ -42,6 +42,7 @@ #include "platform/loader/fetch/MemoryCache.h" #include "platform/loader/fetch/ResourceClient.h" #include "platform/loader/fetch/ResourceClientWalker.h" +#include "platform/loader/fetch/ResourceFinishObserver.h" #include "platform/loader/fetch/ResourceLoader.h" #include "platform/network/HTTPParsers.h" #include "platform/scheduler/child/web_scheduler.h" @@ -58,6 +59,16 @@ namespace blink { +namespace { + +void NotifyFinishObservers( + HeapHashSet<WeakMember<ResourceFinishObserver>> observers) { + for (const auto& observer : observers) + observer->NotifyFinished(); +} + +} // namespace + // These response headers are not copied from a revalidated response to the // cached response headers. For compatibility, this list is based on Chromium's // net/http/http_response_headers.cc. @@ -302,6 +313,7 @@ visitor->Trace(clients_); visitor->Trace(clients_awaiting_callback_); visitor->Trace(finished_clients_); + visitor->Trace(finish_observers_); MemoryCoordinatorClient::Trace(visitor); } @@ -316,6 +328,8 @@ if (IsLoading()) return; + TriggerNotificationForFinishObservers(); + ResourceClientWalker<ResourceClient> w(clients_); while (ResourceClient* c = w.Next()) { MarkClientFinished(c); @@ -356,6 +370,18 @@ encoded_size_memory_usage_ = 0; } +void Resource::TriggerNotificationForFinishObservers() { + Platform::Current() + ->CurrentThread() + ->Scheduler() + ->LoadingTaskRunner() + ->PostTask(BLINK_FROM_HERE, WTF::Bind(&NotifyFinishObservers, + std::move(finish_observers_))); + + finish_observers_.clear(); + DidRemoveClientOrObserver(); +} + void Resource::SetDataBufferingPolicy( DataBufferingPolicy data_buffering_policy) { options_.data_buffering_policy = data_buffering_policy; @@ -711,6 +737,24 @@ DidRemoveClientOrObserver(); } +void Resource::AddFinishObserver(ResourceFinishObserver* client, + PreloadReferencePolicy policy) { + CHECK(!is_add_remove_client_prohibited_); + DCHECK(!finish_observers_.Contains(client)); + + WillAddClientOrObserver(policy); + finish_observers_.insert(client); + if (IsLoaded()) + TriggerNotificationForFinishObservers(); +} + +void Resource::RemoveFinishObserver(ResourceFinishObserver* client) { + CHECK(!is_add_remove_client_prohibited_); + + finish_observers_.erase(client); + DidRemoveClientOrObserver(); +} + void Resource::DidRemoveClientOrObserver() { if (!HasClientsOrObservers() && is_alive_) { is_alive_ = false;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.h b/third_party/WebKit/Source/platform/loader/fetch/Resource.h index 537d2954..7c07f6e 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/Resource.h +++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.h
@@ -52,6 +52,7 @@ class FetchParameters; class ResourceClient; class ResourceFetcher; +class ResourceFinishObserver; class ResourceTimingInfo; class ResourceLoader; class SecurityOrigin; @@ -157,6 +158,10 @@ void AddClient(ResourceClient*, PreloadReferencePolicy = kMarkAsReferenced); void RemoveClient(ResourceClient*); + void AddFinishObserver(ResourceFinishObserver*, + PreloadReferencePolicy = kMarkAsReferenced); + void RemoveFinishObserver(ResourceFinishObserver*); + enum PreloadResult { kPreloadNotReferenced, kPreloadReferenced, @@ -363,7 +368,7 @@ virtual bool HasClientsOrObservers() const { return !clients_.IsEmpty() || !clients_awaiting_callback_.IsEmpty() || - !finished_clients_.IsEmpty(); + !finished_clients_.IsEmpty() || !finish_observers_.IsEmpty(); } virtual void DestroyDecodedDataForFailedRevalidation() {} @@ -413,6 +418,8 @@ SharedBuffer* Data() const { return data_.Get(); } void ClearData(); + void TriggerNotificationForFinishObservers(); + private: class CachedMetadataHandlerImpl; class ServiceWorkerResponseCachedMetadataHandler; @@ -474,6 +481,7 @@ HeapHashCountedSet<WeakMember<ResourceClient>> clients_; HeapHashCountedSet<WeakMember<ResourceClient>> clients_awaiting_callback_; HeapHashCountedSet<WeakMember<ResourceClient>> finished_clients_; + HeapHashSet<WeakMember<ResourceFinishObserver>> finish_observers_; ResourceLoaderOptions options_;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h index f2b238c0..d1eadea 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h
@@ -61,6 +61,7 @@ protected: ResourceClient() {} }; + } // namespace blink #endif
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFinishObserver.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceFinishObserver.h new file mode 100644 index 0000000..404343e --- /dev/null +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFinishObserver.h
@@ -0,0 +1,38 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ResourceFinishObserver_h +#define ResourceFinishObserver_h + +#include "platform/PlatformExport.h" +#include "platform/heap/Handle.h" +#include "platform/wtf/text/WTFString.h" + +namespace blink { + +// ResourceFinishObserver is different from ResourceClient in several ways. +// - NotifyFinished is dispatched asynchronously. +// - ResourceFinishObservers will be removed from Resource when the load +// finishes. - This class is not intended to be "subclassed" per each Resource +// subclass. +// There is no ImageResourceFinishObserver, for example. +// ResourceFinishObserver should be quite simple. All notifications must be +// notified AFTER the loading finishes. +class PLATFORM_EXPORT ResourceFinishObserver : public GarbageCollectedMixin { + public: + virtual ~ResourceFinishObserver() = default; + + // Called asynchronously when loading finishes. + // Note that this can be dispatched after removing |this| client from a + // Resource, because of the asynchronicity. + virtual void NotifyFinished() = 0; + // Name for debugging + virtual String DebugName() const = 0; + + DEFINE_INLINE_VIRTUAL_TRACE() {} +}; + +} // namespace blink + +#endif // ResourceFinishObserver_h
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceOwner.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceOwner.h index cd607ee..339acf8 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceOwner.h +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceOwner.h
@@ -56,9 +56,7 @@ protected: ResourceOwner() {} - void SetResource( - ResourceType*, - Resource::PreloadReferencePolicy = Resource::kMarkAsReferenced); + void SetResource(ResourceType*); void ClearResource() { SetResource(nullptr); } private: @@ -66,9 +64,7 @@ }; template <class R, class C> -inline void ResourceOwner<R, C>::SetResource( - R* new_resource, - Resource::PreloadReferencePolicy preload_reference_policy) { +inline void ResourceOwner<R, C>::SetResource(R* new_resource) { if (new_resource == resource_) return; @@ -79,7 +75,7 @@ if (new_resource) { resource_ = new_resource; - resource_->AddClient(this, preload_reference_policy); + resource_->AddClient(this); } }
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn index 3c11a1b2..3994284 100644 --- a/third_party/WebKit/Source/web/BUILD.gn +++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -43,10 +43,6 @@ "DedicatedWorkerMessagingProxyProviderImpl.h", "EditorClientImpl.cpp", "EditorClientImpl.h", - "ExternalDateTimeChooser.cpp", - "ExternalDateTimeChooser.h", - "ExternalPopupMenu.cpp", - "ExternalPopupMenu.h", "InspectorOverlayAgent.cpp", "InspectorOverlayAgent.h", "LocalFrameClientImpl.cpp", @@ -55,8 +51,6 @@ "MediaKeysClientImpl.h", "PageOverlay.cpp", "PageOverlay.h", - "PopupMenuImpl.cpp", - "PopupMenuImpl.h", "PrerendererClientImpl.cpp", "PrerendererClientImpl.h", "ServiceWorkerGlobalScopeClientImpl.cpp",
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp index b3f87fa..9a4be596 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp +++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -55,6 +55,7 @@ #include "core/html/forms/DateTimeChooser.h" #include "core/html/forms/DateTimeChooserClient.h" #include "core/html/forms/DateTimeChooserImpl.h" +#include "core/html/forms/ExternalDateTimeChooser.h" #include "core/inspector/DevToolsEmulator.h" #include "core/layout/HitTestResult.h" #include "core/layout/LayoutEmbeddedContent.h" @@ -62,7 +63,9 @@ #include "core/loader/DocumentLoader.h" #include "core/loader/FrameLoadRequest.h" #include "core/page/ChromeClient.h" +#include "core/page/ExternalPopupMenu.h" #include "core/page/Page.h" +#include "core/page/PopupMenuImpl.h" #include "core/page/PopupOpeningObserver.h" #include "platform/Cursor.h" #include "platform/FileChooser.h" @@ -104,9 +107,6 @@ #include "public/web/WebUserGestureToken.h" #include "public/web/WebViewClient.h" #include "public/web/WebWindowFeatures.h" -#include "web/ExternalDateTimeChooser.h" -#include "web/ExternalPopupMenu.h" -#include "web/PopupMenuImpl.h" #include "web/WebFrameWidgetImpl.h" #include "web/WebLocalFrameImpl.h"
diff --git a/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp b/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp index 1ab2b97..a9b58da5 100644 --- a/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp +++ b/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp
@@ -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 "web/ExternalPopupMenu.h" +#include "core/page/ExternalPopupMenu.h" #include <memory> #include "core/HTMLNames.h"
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp index b6d1616..7bc97f1 100644 --- a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp +++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
@@ -1006,6 +1006,12 @@ return WebEffectiveConnectionType::kTypeUnknown; } +bool LocalFrameClientImpl::IsClientLoFiActiveForFrame() { + if (web_frame_->Client()) + return web_frame_->Client()->IsClientLoFiActiveForFrame(); + return false; +} + bool LocalFrameClientImpl::ShouldUseClientLoFiForRequest( const ResourceRequest& request) { if (web_frame_->Client()) {
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.h b/third_party/WebKit/Source/web/LocalFrameClientImpl.h index da335fb..9b8d95b 100644 --- a/third_party/WebKit/Source/web/LocalFrameClientImpl.h +++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.h
@@ -220,6 +220,8 @@ WebEffectiveConnectionType GetEffectiveConnectionType() override; + bool IsClientLoFiActiveForFrame() override; + bool ShouldUseClientLoFiForRequest(const ResourceRequest&) override; KURL OverrideFlashEmbedWithHTML(const KURL&) override;
diff --git a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp index 80293a5e..08bc2c9 100644 --- a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp +++ b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
@@ -29,6 +29,7 @@ #include "web/WebPagePopupImpl.h" +#include "core/dom/AXObjectCacheBase.h" #include "core/dom/ContextFeatures.h" #include "core/events/MessageEvent.h" #include "core/events/WebInputEventConversion.h" @@ -48,8 +49,6 @@ #include "core/page/Page.h" #include "core/page/PagePopupClient.h" #include "core/page/PagePopupSupplement.h" -#include "modules/accessibility/AXObjectCacheImpl.h" -#include "modules/accessibility/AXObjectImpl.h" #include "platform/EventDispatchForbiddenScope.h" #include "platform/LayoutTestSupport.h" #include "platform/ScriptForbiddenScope.h" @@ -350,7 +349,7 @@ return 0; AXObjectCache* cache = document->AxObjectCache(); DCHECK(cache); - return ToAXObjectCacheImpl(cache)->GetOrCreate(ToLayoutView( + return ToAXObjectCacheBase(cache)->GetOrCreate(ToLayoutView( LayoutAPIShim::LayoutObjectFrom(document->GetLayoutViewItem()))); }
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index 551f670..6fc9ba0 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -81,6 +81,7 @@ #include "core/layout/TextAutosizer.h" #include "core/layout/api/LayoutViewItem.h" #include "core/layout/compositing/PaintLayerCompositor.h" +#include "core/loader/DocumentLoader.h" #include "core/loader/FrameLoadRequest.h" #include "core/loader/FrameLoader.h" #include "core/loader/FrameLoaderStateMachine.h" @@ -3285,6 +3286,14 @@ scrollable_area->SetScrollOffset(ScrollOffset(), kProgrammaticScroll); } + if (Document* document = + ToLocalFrame(GetPage()->MainFrame())->GetDocument()) { + if (DocumentLoader* loader = document->Loader()) { + if (HistoryItem* item = loader->GetHistoryItem()) + item->SetDidSaveScrollOrScaleState(false); + } + } + GetPageScaleConstraintsSet().SetNeedsReset(true); }
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index 6567f197..0ec5d4048 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -4273,20 +4273,15 @@ WebSize(kPageWidth / 4, kPageHeight / 4)); web_view_helper.WebView()->SetPageScaleFactor(kPageScaleFactor); - WebSize previous_offset = - web_view_helper.WebView()->MainFrame()->GetScrollOffset(); - float previous_scale = web_view_helper.WebView()->PageScaleFactor(); - - // Reload the page and end up at the same url. State should be propagated. + // Reload the page and end up at the same url. State should not be propagated. web_view_helper.WebView()->MainFrame()->ReloadWithOverrideURL( ToKURL(base_url_ + first_url), WebFrameLoadType::kReload); FrameTestHelpers::PumpPendingRequestsForFrameToLoad( web_view_helper.WebView()->MainFrame()); - EXPECT_EQ(previous_offset.width, - web_view_helper.WebView()->MainFrame()->GetScrollOffset().width); - EXPECT_EQ(previous_offset.height, + EXPECT_EQ(0, web_view_helper.WebView()->MainFrame()->GetScrollOffset().width); + EXPECT_EQ(0, web_view_helper.WebView()->MainFrame()->GetScrollOffset().height); - EXPECT_EQ(previous_scale, web_view_helper.WebView()->PageScaleFactor()); + EXPECT_EQ(1.0f, web_view_helper.WebView()->PageScaleFactor()); // Reload the page using the cache. State should not be propagated. web_view_helper.WebView()->MainFrame()->ReloadWithOverrideURL(
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit.py index 09f461e1..d20e0ea 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit.py
@@ -5,19 +5,21 @@ from webkitpy.w3c.chromium_finder import absolute_chromium_dir, absolute_chromium_wpt_dir from webkitpy.common.system.executive import ScriptError +# TODO(qyearsley): Use PathFinder to get this path. CHROMIUM_WPT_DIR = 'third_party/WebKit/LayoutTests/external/wpt/' class ChromiumCommit(object): def __init__(self, host, sha=None, position=None): - """ + """Initializes a ChomiumCommit object, given a sha or commit position. + Args: - host: A Host object - sha: A Chromium commit SHA - position: A string of the form: + host: A Host object. + sha: A Chromium commit SHA hash. + position: A commit position footer string of the form: 'Cr-Commit-Position: refs/heads/master@{#431915}' - or just: + or just the commit position string: 'refs/heads/master@{#431915}' """ self.host = host @@ -46,6 +48,7 @@ def num_behind_master(self): """Returns the number of commits this commit is behind origin/master. + It is inclusive of this commit and of the latest commit. """ return len(self.host.executive.run_command([ @@ -63,7 +66,8 @@ 'git', 'footers', '--position', sha ], cwd=self.absolute_chromium_dir).strip() except ScriptError as e: - # Some commits don't have a position, e.g. when creating PRs for Gerrit CLs. + # Commits from Gerrit CLs that have not yet been committed in + # Chromium do not have a commit position. if 'Unable to infer commit position from footers' in e.message: return 'no-commit-position-yet' else: @@ -91,6 +95,7 @@ ], cwd=self.absolute_chromium_dir) def change_id(self): + """Returns the Change-Id footer if it is present.""" return self.host.executive.run_command([ 'git', 'footers', '--key', 'Change-Id', self.sha ], cwd=self.absolute_chromium_dir).strip() @@ -117,6 +122,7 @@ @staticmethod def is_baseline(basename): + """Checks whether a given file name in wpt appears to be a baseline.""" # TODO(qyearsley): Find a better, centralized place for this. return basename.endswith('-expected.txt')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py index bd2db91..1c8ed5e 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py
@@ -17,12 +17,17 @@ self.owner_map = None def read_owner_map(self): - """Reads the W3CImportExpectations file and returns a map of directories to owners.""" + """Reads W3CImportExpectations and stores the owner information.""" input_path = self.finder.path_from_layout_tests('W3CImportExpectations') input_contents = self.filesystem.read_text_file(input_path) self.owner_map = self.lines_to_owner_map(input_contents.splitlines()) def lines_to_owner_map(self, lines): + """Returns a dict mapping directories to owners. + + Args: + lines: Lines in W3CImportExpectations. + """ current_owners = [] owner_map = {} for line in lines: @@ -49,6 +54,7 @@ @staticmethod def extract_directory(line): + """Extracts the directory substring for an enabled directory.""" match = re.match(r'# ?(?P<directory>\S+) \[ (Pass|Skip) \]', line) if match and match.group('directory'): return match.group('directory')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/gerrit.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/gerrit.py index 70c4140..ddc16e1 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/gerrit.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/gerrit.py
@@ -133,6 +133,7 @@ return True def exportable_filename(self, filename): + """Returns True if the file could be exportable, or False otherwise.""" filename = os.path.basename(filename.lower()) return ( not filename.endswith('-expected.txt') @@ -175,7 +176,7 @@ else: in_exportable_diff = False - # Join into string, newline at end is required. + # Join into string; the newline at the end is required. if not filtered_patch[-1].strip(): filtered_patch = filtered_patch[:-1] patch = '\n'.join(filtered_patch) + '\n'
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py index 9517116..c934c5b 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py
@@ -10,14 +10,14 @@ from webkitpy.w3c.chromium_commit import ChromiumCommit from webkitpy.w3c.common import WPT_GH_SSH_URL_TEMPLATE, CHROMIUM_WPT_DIR - _log = logging.getLogger(__name__) class LocalWPT(object): def __init__(self, host, gh_token=None, path='/tmp/wpt'): - """ + """Initializes a LocalWPT instance. + Args: host: A Host object. path: Optional, the path to the web-platform-tests repo. @@ -29,6 +29,7 @@ self.gh_token = gh_token def fetch(self): + """Fetches a copy of the web-platform-tests repo into `self.path`.""" assert self.gh_token, 'LocalWPT.gh_token required for fetch' if self.host.filesystem.exists(self.path): _log.info('WPT checkout exists at %s, fetching latest', self.path) @@ -44,7 +45,11 @@ return self.host.executive.run_command(command, cwd=self.path, **kwargs) def most_recent_chromium_commit(self): - """Finds the most recent commit in WPT with a Chromium commit position.""" + """Finds the most recent commit in WPT with a Chromium commit position. + + Returns: + A pair (commit hash, ChromiumCommit instance). + """ wpt_commit_hash = self.run(['git', 'rev-list', 'HEAD', '-n', '1', '--grep=Cr-Commit-Position']) if not wpt_commit_hash: return None, None @@ -58,6 +63,7 @@ return wpt_commit_hash, chromium_commit def clean(self): + """Resets git to a clean state, on origin/master with no changed files.""" self.run(['git', 'reset', '--hard', 'HEAD']) self.run(['git', 'clean', '-fdx']) self.run(['git', 'checkout', 'origin/master']) @@ -81,7 +87,7 @@ _log.info('Deleting old branch %s', branch_name) self.run(['git', 'branch', '-D', branch_name]) except ScriptError: - # Ignore errors if branch not found. + # This might mean the branch wasn't found. Ignore this error. pass _log.info('Creating local branch %s', branch_name)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py index 6898af1..07ac7033 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -8,11 +8,7 @@ 1. Upload a CL. 2. Trigger try jobs and wait for them to complete. 3. Make any changes that are required for new failing tests. - 4. Commit the CL. - -If this script is given the argument --auto-update, it will also attempt to -upload a CL, trigger try jobs, and make any changes that are required for -new failing tests before committing. + 4. Attempt to land the CL. """ import argparse @@ -166,6 +162,7 @@ return exportable_commits_since(chromium_commit.sha, self.host, local_wpt) def clean_up_temp_repo(self, temp_repo_path): + """Removes the temporary copy of the wpt repo that was downloaded.""" _log.info('Deleting temp repo directory %s.', temp_repo_path) self.fs.rmtree(temp_repo_path) @@ -240,6 +237,13 @@ self._generate_manifest(dest_path) + # TODO(qyearsley): Consider running the imported tests with + # `run-webkit-tests --reset-results external/wpt` to get most of + # the cross-platform baselines without having to wait for try jobs. + # TODO(qyearsley): Consider updating manifest after adding baselines. + # TODO(qyearsley): Consider starting CQ at the same time as the + # initial try jobs. + _log.info('Updating TestExpectations for any removed or renamed tests.') self.update_all_test_expectations_files(self._list_deleted_tests(), self._list_renamed_tests()) @@ -438,13 +442,24 @@ return '\n'.join(message_lines) def fetch_new_expectations_and_baselines(self): - """Adds new expectations and downloads baselines based on try job results, then commits and uploads the change.""" + """Modifies expectation lines and baselines based on try job results. + + Assuming that there are some try job results available, this + adds new expectation lines to TestExpectations and downloads new + baselines based on the try job results. + + This is the same as invoking the `wpt-update-expectations` script. + """ _log.info('Adding test expectations lines to LayoutTests/TestExpectations.') expectation_updater = WPTExpectationsUpdater(self.host) expectation_updater.run(args=[]) def update_all_test_expectations_files(self, deleted_tests, renamed_tests): - """Updates all test expectations files for tests that have been deleted or renamed.""" + """Updates all test expectations files for tests that have been deleted or renamed. + + This is only for deleted or renamed tests in the initial import, + not for tests that have failures in try jobs. + """ port = self.host.port_factory.get() for path, file_contents in port.all_expectations_dict().iteritems(): parser = TestExpectationParser(port, all_tests=None, is_lint_mode=False) @@ -452,7 +467,7 @@ self._update_single_test_expectations_file(path, expectation_lines, deleted_tests, renamed_tests) def _update_single_test_expectations_file(self, path, expectation_lines, deleted_tests, renamed_tests): - """Updates single test expectations file.""" + """Updates a single test expectations file.""" # FIXME: This won't work for removed or renamed directories with test expectations # that are directories rather than individual tests. new_lines = [] @@ -473,7 +488,7 @@ self.host.filesystem.write_text_file(path, new_file_contents) def _list_deleted_tests(self): - """Returns a list of layout tests that have been deleted.""" + """List of layout tests that have been deleted.""" out = self.check_run(['git', 'diff', 'origin/master', '-M100%', '--diff-filter=D', '--name-only']) deleted_tests = [] for line in out.splitlines(): @@ -483,7 +498,10 @@ return deleted_tests def _list_renamed_tests(self): - """Returns a dict mapping source to dest name for layout tests that have been renamed.""" + """Lists tests that have been renamed. + + Returns a dict mapping source name to destination name. + """ out = self.check_run(['git', 'diff', 'origin/master', '-M100%', '--diff-filter=R', '--name-status']) renamed_tests = {} for line in out.splitlines():
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py index c6bc6aa6..15387d00 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
@@ -11,13 +11,16 @@ from webkitpy.w3c.common import WPT_GH_ORG, WPT_GH_REPO_NAME from webkitpy.common.memoized import memoized - _log = logging.getLogger(__name__) API_BASE = 'https://api.github.com' EXPORT_LABEL = 'chromium-export' class WPTGitHub(object): + """An interface to GitHub for interacting with the web-platform-tests repo. + + This class contains methods for sending requests to the GitHub API. + """ def __init__(self, host, user, token, pr_history_window=30): self.host = host @@ -224,7 +227,6 @@ return None - class MergeError(Exception): """An error specifically for when a PR cannot be merged. @@ -233,4 +235,5 @@ """ pass + PullRequest = namedtuple('PullRequest', ['title', 'number', 'body', 'state'])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_mock.py index 8f40df1..951233c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_mock.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_mock.py
@@ -7,6 +7,9 @@ class MockWPTGitHub(object): + # Some unused arguments may be included to match the real class's API. + # pylint: disable=unused-argument + def __init__(self, pull_requests, unsuccessful_merge_index=-1, create_pr_fail_index=-1): self.pull_requests = pull_requests self.calls = [] @@ -16,7 +19,7 @@ self.create_pr_index = 0 self.create_pr_fail_index = create_pr_fail_index - def all_pull_requests(self, limit=30): # pylint: disable=unused-argument + def all_pull_requests(self, limit=30): self.calls.append('all_pull_requests') return self.pull_requests @@ -39,7 +42,7 @@ return {'number': 5678} - def update_pr(self, pr_number, desc_title, body): # pylint: disable=unused-argument + def update_pr(self, pr_number, desc_title, body): self.calls.append('update_pr') return {'number': 5678}
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py index 05cee668..25be40d 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
@@ -27,13 +27,12 @@ def _items_for_path(self, path_in_wpt): """Returns manifest items for the given WPT path, or None if not found. - The format of a manifest item depends on - https://github.com/w3c/wpt-tools/blob/master/manifest/item.py - and is assumed to be a list of the format [url, extras], - or [url, references, extras] for reftests, or None if not found. + The format of a manifest item depends on: + https://github.com/w3c/web-platform-tests/blob/master/tools/manifest/item.py For most testharness tests, the returned items is expected - to look like this:: [["/some/test/path.html", {}]] + to look like this: [["/some/test/path.html", {}]]. For reference tests, + it will be a list with three items ([url, references, extras]). """ items = self.raw_dict['items'] if path_in_wpt in items['manual']: @@ -74,7 +73,7 @@ """Extracts reference information of the specified reference test. The return value is a list of (match/not-match, reference path in wpt) - like: + pairs, like: [("==", "foo/bar/baz-match.html"), ("!=", "foo/bar/baz-mismatch.html")] """ @@ -89,7 +88,7 @@ @staticmethod def ensure_manifest(host): - """Checks whether the manifest exists, and then generates it if necessary.""" + """Generates the MANIFEST.json file if it does not exist.""" finder = PathFinder(host.filesystem) manifest_path = finder.path_from_layout_tests('external', 'wpt', 'MANIFEST.json') base_manifest_path = finder.path_from_layout_tests('external', 'WPT_BASE_MANIFEST.json')
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h index fe89d1b..10a10b0e 100644 --- a/third_party/WebKit/public/web/WebFrameClient.h +++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -484,6 +484,10 @@ return WebEffectiveConnectionType::kTypeUnknown; } + // Returns whether or not Client LoFi is enabled for the frame (and + // so any image requests may be replaced with a placeholder). + virtual bool IsClientLoFiActiveForFrame() { return false; } + // Returns whether or not the requested image should be replaced with a // placeholder as part of the Client Lo-Fi previews feature. virtual bool ShouldUseClientLoFiForRequest(const WebURLRequest&) {
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath index e933cd8..3fb0f5e 100644 --- a/tools/android/eclipse/.classpath +++ b/tools/android/eclipse/.classpath
@@ -45,6 +45,9 @@ <classpathentry kind="src" path="chrome/test/chromedriver/test/webview_shell/java/src"/> <classpathentry kind="src" path="chromecast/browser/android/apk/src"/> <classpathentry kind="src" path="components/autofill/android/java/src"/> + <classpathentry kind="src" path="components/background_task_scheduler/android/java/src"/> + <classpathentry kind="src" path="components/background_task_scheduler/android/javatests/src"/> + <classpathentry kind="src" path="components/background_task_scheduler/android/junit/src"/> <classpathentry kind="src" path="components/bookmarks/common/android/java/src"/> <classpathentry kind="src" path="components/cronet/android/api/src"/> <classpathentry kind="src" path="components/cronet/android/java/src"/>
diff --git a/tools/chrome_proxy/webdriver/lofi.py b/tools/chrome_proxy/webdriver/lofi.py index 5960ad0bc..ac1198ad 100644 --- a/tools/chrome_proxy/webdriver/lofi.py +++ b/tools/chrome_proxy/webdriver/lofi.py
@@ -211,5 +211,26 @@ # Verify that Lo-Fi responses were seen. self.assertNotEqual(0, lofi_responses) + # Checks that Client LoFi resource requests have the Intervention header + # (in case page has https images that may not be fully loaded). + def testClientLoFiInterventionHeader(self): + with TestDriver() as test_driver: + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--force-fieldtrials=' + 'PreviewsClientLoFi/Enabled') + test_driver.AddChromeArg('--force-fieldtrial-params=' + 'PreviewsClientLoFi.Enabled:' + 'max_allowed_effective_connection_type/4G') + + test_driver.LoadURL('http://check.googlezip.net/static/index.html') + + intervention_headers = 0 + for response in test_driver.GetHTTPResponses(): + if not response.url.endswith('html'): + self.assertIn('intervention', response.request_headers) + intervention_headers = intervention_headers + 1 + + self.assertNotEqual(0, intervention_headers) + if __name__ == '__main__': IntegrationTest.RunAllTests()
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 6f8ac11..5c17759 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -5646,7 +5646,6 @@ <int value="31" label="Permission autoblocker data setting"/> <int value="32" label="Ads setting"/> <int value="33" label="Ads metadata"/> - <int value="34" label="Password protection setting"/> </enum> <enum name="ContentTypeParseableResult" type="int">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index b155d0f40..ede5304 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -51672,8 +51672,8 @@ </summary> </histogram> -<histogram base="true" - name="PasswordProtection.NumberOfCachedVerdictBeforeShutdown" units="count"> +<histogram name="PasswordProtection.NumberOfCachedVerdictBeforeShutdown" + units="count"> <owner>jialiul@chromium.org</owner> <owner>nparker@chromium.org</owner> <summary> @@ -93039,8 +93039,6 @@ </histogram_suffixes> <histogram_suffixes name="PasswordProtectionTrigger" separator="."> - <affected-histogram - name="PasswordProtection.NumberOfCachedVerdictBeforeShutdown"/> <suffix name="PasswordFieldOnFocus" label="Password protection triggered by password field on focus event."/> <suffix name="ProtectedPasswordEntry"
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py index 6b1581a..c97e754 100644 --- a/tools/perf/benchmarks/blink_perf.py +++ b/tools/perf/benchmarks/blink_perf.py
@@ -67,8 +67,7 @@ else: _AddPage(path) ps = story.StorySet(base_dir=os.getcwd() + os.sep, - serving_dirs=serving_dirs, - verify_names=True) + serving_dirs=serving_dirs) all_urls = [p.rstrip('/') for p in page_urls] common_prefix = os.path.dirname(os.path.commonprefix(all_urls))
diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py index c34714a..b2cbdb1c 100644 --- a/tools/perf/benchmarks/dromaeo.py +++ b/tools/perf/benchmarks/dromaeo.py
@@ -118,8 +118,7 @@ ps = story.StorySet( archive_data_file=archive_data_file, base_dir=os.path.dirname(os.path.abspath(__file__)), - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) url = 'http://dromaeo.com?%s' % self.query_param ps.AddStory(page_module.Page( url, ps, ps.base_dir, make_javascript_deterministic=False, name=url))
diff --git a/tools/perf/benchmarks/jetstream.py b/tools/perf/benchmarks/jetstream.py index d00db53..b594f50b 100644 --- a/tools/perf/benchmarks/jetstream.py +++ b/tools/perf/benchmarks/jetstream.py
@@ -87,8 +87,7 @@ ps = story.StorySet( archive_data_file='../page_sets/data/jetstream.json', base_dir=os.path.dirname(os.path.abspath(__file__)), - cloud_storage_bucket=story.INTERNAL_BUCKET, - verify_names=True) + cloud_storage_bucket=story.INTERNAL_BUCKET) ps.AddStory(page_module.Page( 'http://browserbench.org/JetStream/', ps, ps.base_dir, make_javascript_deterministic=False,
diff --git a/tools/perf/benchmarks/kraken.py b/tools/perf/benchmarks/kraken.py index df0fcda3..521c27e 100644 --- a/tools/perf/benchmarks/kraken.py +++ b/tools/perf/benchmarks/kraken.py
@@ -132,8 +132,7 @@ ps = story.StorySet( archive_data_file='../page_sets/data/kraken.json', base_dir=os.path.dirname(os.path.abspath(__file__)), - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) ps.AddStory(page_module.Page( 'http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html', ps, ps.base_dir,
diff --git a/tools/perf/benchmarks/octane.py b/tools/perf/benchmarks/octane.py index 117c0fe..d6de296 100644 --- a/tools/perf/benchmarks/octane.py +++ b/tools/perf/benchmarks/octane.py
@@ -148,8 +148,7 @@ ps = story.StorySet( archive_data_file='../page_sets/data/octane.json', base_dir=os.path.dirname(os.path.abspath(__file__)), - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) ps.AddStory(page_module.Page( 'http://chromium.github.io/octane/index.html?auto=1', ps, ps.base_dir, make_javascript_deterministic=False,
diff --git a/tools/perf/benchmarks/speedometer.py b/tools/perf/benchmarks/speedometer.py index cf325400..fbe431da 100644 --- a/tools/perf/benchmarks/speedometer.py +++ b/tools/perf/benchmarks/speedometer.py
@@ -101,8 +101,7 @@ ps = story.StorySet( base_dir=os.path.dirname(os.path.abspath(__file__)), archive_data_file='../page_sets/data/speedometer.json', - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) ps.AddStory(page_module.Page( 'http://browserbench.org/Speedometer/', ps, ps.base_dir, make_javascript_deterministic=False,
diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py index 975a24f..b1cf856 100644 --- a/tools/perf/benchmarks/tab_switching.py +++ b/tools/perf/benchmarks/tab_switching.py
@@ -36,8 +36,7 @@ story_set = story.StorySet( archive_data_file='../page_sets/data/system_health_desktop.json', base_dir=os.path.dirname(os.path.abspath(__file__)), - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) story_set.AddStory(multi_tab_stories.MultiTabTypical24Story( story_set, False, options.tabset_repeat)) return story_set
diff --git a/tools/perf/page_sets/blank_page.py b/tools/perf/page_sets/blank_page.py index a7ce08e..b44d4c1 100644 --- a/tools/perf/page_sets/blank_page.py +++ b/tools/perf/page_sets/blank_page.py
@@ -26,6 +26,6 @@ """A single blank page.""" def __init__(self): - super(BlankPageSet, self).__init__(verify_names=True) + super(BlankPageSet, self).__init__() self.AddStory(BlankPage('file://blank_page/blank_page.html', self, 'blank_page.html'))
diff --git a/tools/perf/page_sets/blank_page_with_extension_profile.py b/tools/perf/page_sets/blank_page_with_extension_profile.py index a20afee..bae248e 100644 --- a/tools/perf/page_sets/blank_page_with_extension_profile.py +++ b/tools/perf/page_sets/blank_page_with_extension_profile.py
@@ -22,7 +22,7 @@ """PageSet tied to BlankPageWithExtensionProfile.""" def __init__(self): - super(BlankPageSetWithExtensionProfile, self).__init__(verify_names=True) + super(BlankPageSetWithExtensionProfile, self).__init__() self.AddStory(BlankPageWithExtensionProfile( 'file://blank_page/blank_page.html', self, 'blank_page.html'))
diff --git a/tools/perf/page_sets/blank_page_with_large_profile.py b/tools/perf/page_sets/blank_page_with_large_profile.py index 9d268d5..c86bf22a 100644 --- a/tools/perf/page_sets/blank_page_with_large_profile.py +++ b/tools/perf/page_sets/blank_page_with_large_profile.py
@@ -19,7 +19,7 @@ """A single blank page loaded with a large profile.""" def __init__(self): - super(BlankPageSetWithLargeProfile, self).__init__(verify_names=True) + super(BlankPageSetWithLargeProfile, self).__init__() self.AddStory(BlankPageWithLargeProfile( 'file://blank_page/blank_page.html', self, 'blank_page.html'))
diff --git a/tools/perf/page_sets/blink_memory_mobile.py b/tools/perf/page_sets/blink_memory_mobile.py index 68d9766..e6c53c94 100644 --- a/tools/perf/page_sets/blink_memory_mobile.py +++ b/tools/perf/page_sets/blink_memory_mobile.py
@@ -92,8 +92,7 @@ def __init__(self): super(BlinkMemoryMobilePageSet, self).__init__( archive_data_file='data/blink_memory_mobile.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) # Why: High rate of Blink's memory consumption rate. self.AddStory(BlinkMemoryMobilePage(
diff --git a/tools/perf/page_sets/blob_workshop.py b/tools/perf/page_sets/blob_workshop.py index 0643173a..049983f 100644 --- a/tools/perf/page_sets/blob_workshop.py +++ b/tools/perf/page_sets/blob_workshop.py
@@ -73,7 +73,7 @@ """The BlobWorkshop page set.""" def __init__(self): - super(BlobWorkshopPageSet, self).__init__(verify_names=True) + super(BlobWorkshopPageSet, self).__init__() self.AddStory( BlobMassCreate('2Bx200', [2] * 200, self)) self.AddStory(
diff --git a/tools/perf/page_sets/chrome_signin.py b/tools/perf/page_sets/chrome_signin.py index db695ff..68ff691 100644 --- a/tools/perf/page_sets/chrome_signin.py +++ b/tools/perf/page_sets/chrome_signin.py
@@ -33,6 +33,5 @@ def __init__(self): super(ChromeSigninPageSet, self).__init__( archive_data_file='data/chrome_signin_archive.json', - cloud_storage_bucket=story.INTERNAL_BUCKET, - verify_names=True) + cloud_storage_bucket=story.INTERNAL_BUCKET) self.AddStory(ChromeSigninPage(self))
diff --git a/tools/perf/page_sets/desktop_memory.py b/tools/perf/page_sets/desktop_memory.py index b3a95fd..59f9005 100644 --- a/tools/perf/page_sets/desktop_memory.py +++ b/tools/perf/page_sets/desktop_memory.py
@@ -50,7 +50,7 @@ """ Desktop sites with interesting memory characteristics """ def __init__(self): - super(DesktopMemoryPageSet, self).__init__(verify_names=True) + super(DesktopMemoryPageSet, self).__init__() urls_list = [ 'http://www.google.com',
diff --git a/tools/perf/page_sets/dual_browser_story.py b/tools/perf/page_sets/dual_browser_story.py index 08240623..e50fbe7 100644 --- a/tools/perf/page_sets/dual_browser_story.py +++ b/tools/perf/page_sets/dual_browser_story.py
@@ -241,8 +241,7 @@ def __init__(self): super(DualBrowserStorySet, self).__init__( archive_data_file='data/dual_browser_story.json', - cloud_storage_bucket=story_module.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story_module.PARTNER_BUCKET) for query, url in zip(SEARCH_QUERIES, URL_LIST): # Stories that run on the android-webview browser.
diff --git a/tools/perf/page_sets/dummy_story_set.py b/tools/perf/page_sets/dummy_story_set.py index d3609db..884b00dd 100644 --- a/tools/perf/page_sets/dummy_story_set.py +++ b/tools/perf/page_sets/dummy_story_set.py
@@ -20,5 +20,5 @@ class DummyStorySet(story.StorySet): def __init__(self): - super(DummyStorySet, self).__init__(verify_names=True) + super(DummyStorySet, self).__init__() self.AddStory(DummyPage(self))
diff --git a/tools/perf/page_sets/idle_after_loading_stories.py b/tools/perf/page_sets/idle_after_loading_stories.py index 47c62906..fc2248c 100644 --- a/tools/perf/page_sets/idle_after_loading_stories.py +++ b/tools/perf/page_sets/idle_after_loading_stories.py
@@ -47,8 +47,7 @@ def __init__(self, wait_in_seconds=0): super(IdleAfterLoadingStories, self).__init__( archive_data_file='data/idle_after_loading_stories.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) # Chrome has high idle CPU usage on this site, even after its quiesced. # https://crbug.com/638365.
diff --git a/tools/perf/page_sets/idle_platform.py b/tools/perf/page_sets/idle_platform.py index 4f478f4..b25af54 100644 --- a/tools/perf/page_sets/idle_platform.py +++ b/tools/perf/page_sets/idle_platform.py
@@ -44,7 +44,7 @@ class IdleStorySet(story.StorySet): def __init__(self): - super(IdleStorySet, self).__init__(verify_names=True) + super(IdleStorySet, self).__init__() self.AddStory(_IdleStory('IdleStory_10s', 10)) self.AddStory(_IdleStory('IdleStory_60s', 60)) self.AddStory(_IdleStory('IdleStory_120s', 120))
diff --git a/tools/perf/page_sets/image_decoding_cases.py b/tools/perf/page_sets/image_decoding_cases.py index 826858cc..735c90f 100644 --- a/tools/perf/page_sets/image_decoding_cases.py +++ b/tools/perf/page_sets/image_decoding_cases.py
@@ -19,7 +19,7 @@ """ A directed benchmark of accelerated jpeg image decoding performance """ def __init__(self): - super(ImageDecodingCasesPageSet, self).__init__(verify_names=True) + super(ImageDecodingCasesPageSet, self).__init__() urls_list = [ ('file://image_decoding_cases/yuv_decoding.html', 'yuv_decoding.html')
diff --git a/tools/perf/page_sets/image_decoding_measurement.py b/tools/perf/page_sets/image_decoding_measurement.py index 24325b59..c192afe7 100644 --- a/tools/perf/page_sets/image_decoding_measurement.py +++ b/tools/perf/page_sets/image_decoding_measurement.py
@@ -24,7 +24,7 @@ """ A directed benchmark of image decoding performance """ def __init__(self): - super(ImageDecodingMeasurementPageSet, self).__init__(verify_names=True) + super(ImageDecodingMeasurementPageSet, self).__init__() self.image_decoding_measurement_limit_results_to_min_iterations = True urls_list = [
diff --git a/tools/perf/page_sets/indexeddb_endure_page.py b/tools/perf/page_sets/indexeddb_endure_page.py index 7f100ba..80feb6e 100644 --- a/tools/perf/page_sets/indexeddb_endure_page.py +++ b/tools/perf/page_sets/indexeddb_endure_page.py
@@ -29,7 +29,7 @@ """ def __init__(self): - super(IndexedDBEndurePageSet, self).__init__(verify_names=True) + super(IndexedDBEndurePageSet, self).__init__() tests = [ 'testCreateAndDeleteDatabases', 'testCreateAndDeleteDatabase',
diff --git a/tools/perf/page_sets/infinite_scroll_cases.py b/tools/perf/page_sets/infinite_scroll_cases.py index 1268f408..25221f0 100644 --- a/tools/perf/page_sets/infinite_scroll_cases.py +++ b/tools/perf/page_sets/infinite_scroll_cases.py
@@ -134,8 +134,7 @@ def __init__(self): super(InfiniteScrollStorySet, self).__init__( archive_data_file='data/infinite_scroll.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) for story_class in _FindInfiniteScrollStoryClasses(platforms.DESKTOP): self.AddStory(story_class(self)) @@ -144,8 +143,7 @@ def __init__(self): super(MobileInfiniteScrollStorySet, self).__init__( archive_data_file='data/mobile_infinite_scroll.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) for story_class in _FindInfiniteScrollStoryClasses(platforms.MOBILE): self.AddStory(story_class(self))
diff --git a/tools/perf/page_sets/intl_ar_fa_he.py b/tools/perf/page_sets/intl_ar_fa_he.py index 46c6b28..0f2f727 100644 --- a/tools/perf/page_sets/intl_ar_fa_he.py +++ b/tools/perf/page_sets/intl_ar_fa_he.py
@@ -26,8 +26,7 @@ def __init__(self, cache_temperatures=None): super(IntlArFaHePageSet, self).__init__( archive_data_file='data/intl_ar_fa_he.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY]
diff --git a/tools/perf/page_sets/intl_es_fr_pt-BR.py b/tools/perf/page_sets/intl_es_fr_pt-BR.py index f2053eb5..416108e 100644 --- a/tools/perf/page_sets/intl_es_fr_pt-BR.py +++ b/tools/perf/page_sets/intl_es_fr_pt-BR.py
@@ -28,8 +28,7 @@ def __init__(self, cache_temperatures=None): super(IntlEsFrPtBrPageSet, self).__init__( archive_data_file='data/intl_es_fr_pt-BR.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY]
diff --git a/tools/perf/page_sets/intl_hi_ru.py b/tools/perf/page_sets/intl_hi_ru.py index 7a1c052d..4bf42c09 100644 --- a/tools/perf/page_sets/intl_hi_ru.py +++ b/tools/perf/page_sets/intl_hi_ru.py
@@ -26,8 +26,7 @@ def __init__(self, cache_temperatures=None): super(IntlHiRuPageSet, self).__init__( archive_data_file='data/intl_hi_ru.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY]
diff --git a/tools/perf/page_sets/intl_ja_zh.py b/tools/perf/page_sets/intl_ja_zh.py index dd804f6..b5439795 100644 --- a/tools/perf/page_sets/intl_ja_zh.py +++ b/tools/perf/page_sets/intl_ja_zh.py
@@ -25,8 +25,7 @@ def __init__(self, cache_temperatures=None): super(IntlJaZhPageSet, self).__init__( archive_data_file='data/intl_ja_zh.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY]
diff --git a/tools/perf/page_sets/intl_ko_th_vi.py b/tools/perf/page_sets/intl_ko_th_vi.py index 0a1e7eb..928b7245c 100644 --- a/tools/perf/page_sets/intl_ko_th_vi.py +++ b/tools/perf/page_sets/intl_ko_th_vi.py
@@ -25,8 +25,7 @@ def __init__(self, cache_temperatures=None): super(IntlKoThViPageSet, self).__init__( archive_data_file='data/intl_ko_th_vi.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY]
diff --git a/tools/perf/page_sets/key_desktop_move_cases.py b/tools/perf/page_sets/key_desktop_move_cases.py index 1cd6811..180cdc9 100644 --- a/tools/perf/page_sets/key_desktop_move_cases.py +++ b/tools/perf/page_sets/key_desktop_move_cases.py
@@ -118,8 +118,7 @@ def __init__(self): super(KeyDesktopMoveCasesPageSet, self).__init__( archive_data_file='data/key_desktop_move_cases.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) self.AddStory(GmailMouseScrollPage(self)) self.AddStory(GoogleMapsPage(self))
diff --git a/tools/perf/page_sets/key_hit_test_cases.py b/tools/perf/page_sets/key_hit_test_cases.py index eedf710..d9dd86c 100644 --- a/tools/perf/page_sets/key_hit_test_cases.py +++ b/tools/perf/page_sets/key_hit_test_cases.py
@@ -40,6 +40,6 @@ class KeyHitTestCasesPageSet(story.StorySet): def __init__(self): - super(KeyHitTestCasesPageSet, self).__init__(verify_names=True) + super(KeyHitTestCasesPageSet, self).__init__() self.AddStory(PaperCalculatorHitTest(self))
diff --git a/tools/perf/page_sets/key_idle_power_cases.py b/tools/perf/page_sets/key_idle_power_cases.py index 43ca9fc..73c90a7 100644 --- a/tools/perf/page_sets/key_idle_power_cases.py +++ b/tools/perf/page_sets/key_idle_power_cases.py
@@ -58,7 +58,7 @@ """ Key idle power cases """ def __init__(self): - super(KeyIdlePowerCasesPageSet, self).__init__(verify_names=True) + super(KeyIdlePowerCasesPageSet, self).__init__() foreground_urls_list = [ # Why: Ensure minimal activity for static, empty pages in the foreground.
diff --git a/tools/perf/page_sets/key_mobile_sites.py b/tools/perf/page_sets/key_mobile_sites.py index b73a474..b3c0e812 100644 --- a/tools/perf/page_sets/key_mobile_sites.py +++ b/tools/perf/page_sets/key_mobile_sites.py
@@ -29,8 +29,7 @@ def __init__(self): super(KeyMobileSitesPageSet, self).__init__( archive_data_file='data/key_mobile_sites.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) # Add pages with predefined classes that contain custom navigation logic.
diff --git a/tools/perf/page_sets/key_mobile_sites_smooth.py b/tools/perf/page_sets/key_mobile_sites_smooth.py index 19d96a8..fd2b15d 100644 --- a/tools/perf/page_sets/key_mobile_sites_smooth.py +++ b/tools/perf/page_sets/key_mobile_sites_smooth.py
@@ -132,8 +132,7 @@ def __init__(self): super(KeyMobileSitesSmoothPageSet, self).__init__( archive_data_file='data/key_mobile_sites_smooth.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) # Add pages with predefined classes that contain custom navigation logic.
diff --git a/tools/perf/page_sets/key_noop_cases.py b/tools/perf/page_sets/key_noop_cases.py index a4639e4..0d05765 100644 --- a/tools/perf/page_sets/key_noop_cases.py +++ b/tools/perf/page_sets/key_noop_cases.py
@@ -42,7 +42,7 @@ """ Key no-op cases """ def __init__(self): - super(KeyNoOpCasesPageSet, self).__init__(verify_names=True) + super(KeyNoOpCasesPageSet, self).__init__() # Why: An infinite rAF loop which does not modify the page should incur # minimal activity.
diff --git a/tools/perf/page_sets/key_silk_cases.py b/tools/perf/page_sets/key_silk_cases.py index 078915c0..ec2b4b4 100644 --- a/tools/perf/page_sets/key_silk_cases.py +++ b/tools/perf/page_sets/key_silk_cases.py
@@ -727,8 +727,7 @@ def __init__(self, run_no_page_interactions=False): super(KeySilkCasesPageSet, self).__init__( archive_data_file='data/key_silk_cases.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) self.AddStory(Page1(self, run_no_page_interactions)) self.AddStory(Page2(self, run_no_page_interactions))
diff --git a/tools/perf/page_sets/loading_desktop.py b/tools/perf/page_sets/loading_desktop.py index 9d266f5c..1ee6f1c 100644 --- a/tools/perf/page_sets/loading_desktop.py +++ b/tools/perf/page_sets/loading_desktop.py
@@ -18,8 +18,7 @@ def __init__(self, cache_temperatures=None): super(LoadingDesktopStorySet, self).__init__( archive_data_file='data/loading_desktop.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) if cache_temperatures is None: cache_temperatures = [
diff --git a/tools/perf/page_sets/loading_mobile.py b/tools/perf/page_sets/loading_mobile.py index 54f9ffe2..23d39d3 100644 --- a/tools/perf/page_sets/loading_mobile.py +++ b/tools/perf/page_sets/loading_mobile.py
@@ -19,8 +19,7 @@ def __init__(self, cache_temperatures=None, traffic_settings=None): super(LoadingMobileStorySet, self).__init__( archive_data_file='data/loading_mobile.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY]
diff --git a/tools/perf/page_sets/long_running_idle_google_cases.py b/tools/perf/page_sets/long_running_idle_google_cases.py index 559e5421..302cddf 100644 --- a/tools/perf/page_sets/long_running_idle_google_cases.py +++ b/tools/perf/page_sets/long_running_idle_google_cases.py
@@ -35,8 +35,7 @@ def __init__(self): super(LongRunningIdleGmailPageSet, self).__init__( archive_data_file='data/long_running_idle_gmail_page.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) self.AddStory( _CreateIdlePageClass(google_pages.GmailPage)(self)) @@ -46,7 +45,6 @@ # Reuse the wpr of foreground gmail. super(LongRunningIdleGmailBackgroundPageSet, self).__init__( archive_data_file='data/long_running_idle_gmail_page.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) self.AddStory( _CreateIdleBackgroundPageClass(google_pages.GmailPage)(self))
diff --git a/tools/perf/page_sets/maps.py b/tools/perf/page_sets/maps.py index cb112fb..bfdab2e 100644 --- a/tools/perf/page_sets/maps.py +++ b/tools/perf/page_sets/maps.py
@@ -42,7 +42,6 @@ def __init__(self): super(MapsPageSet, self).__init__( archive_data_file='data/maps.json', - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) self.AddStory(MapsPage(self))
diff --git a/tools/perf/page_sets/media_cns_cases.py b/tools/perf/page_sets/media_cns_cases.py index c0ddc19..b09c1e4 100644 --- a/tools/perf/page_sets/media_cns_cases.py +++ b/tools/perf/page_sets/media_cns_cases.py
@@ -46,7 +46,7 @@ """ Media benchmark on network constrained conditions. """ def __init__(self): - super(MediaCnsCasesPageSet, self).__init__(verify_names=True) + super(MediaCnsCasesPageSet, self).__init__() urls_list = [ # pylint: disable=line-too-long
diff --git a/tools/perf/page_sets/memory_top_10_mobile.py b/tools/perf/page_sets/memory_top_10_mobile.py index 95a622e..260af357 100644 --- a/tools/perf/page_sets/memory_top_10_mobile.py +++ b/tools/perf/page_sets/memory_top_10_mobile.py
@@ -68,8 +68,7 @@ def __init__(self): super(MemoryTop10Mobile, self).__init__( archive_data_file='data/memory_top_10_mobile.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) for url in top_10_mobile.URL_LIST: # We name pages so their foreground/background counterparts are easy
diff --git a/tools/perf/page_sets/mse_cases.py b/tools/perf/page_sets/mse_cases.py index b39ca19..75477b1 100644 --- a/tools/perf/page_sets/mse_cases.py +++ b/tools/perf/page_sets/mse_cases.py
@@ -21,8 +21,7 @@ def __init__(self): super(MseCasesPageSet, self).__init__( - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) urls_list = [ 'file://mse_cases/startup_test.html?testType=AV',
diff --git a/tools/perf/page_sets/oopif_basic_page_set.py b/tools/perf/page_sets/oopif_basic_page_set.py index 9276096..6aa886e 100644 --- a/tools/perf/page_sets/oopif_basic_page_set.py +++ b/tools/perf/page_sets/oopif_basic_page_set.py
@@ -13,8 +13,7 @@ def __init__(self, cache_temperatures=None): super(OopifBasicPageSet, self).__init__( archive_data_file='data/oopif_basic.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY]
diff --git a/tools/perf/page_sets/oortonline.py b/tools/perf/page_sets/oortonline.py index 312f580..570630d6 100644 --- a/tools/perf/page_sets/oortonline.py +++ b/tools/perf/page_sets/oortonline.py
@@ -43,8 +43,7 @@ def __init__(self): super(OortOnlinePageSet, self).__init__( archive_data_file='data/oortonline.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) self.AddStory(OortOnlinePage(self)) class OortOnlineTBMPage(OortOnlinePage): @@ -78,6 +77,5 @@ def __init__(self): super(OortOnlineTBMPageSet, self).__init__( archive_data_file='data/oortonline.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) self.AddStory(OortOnlineTBMPage(self))
diff --git a/tools/perf/page_sets/page_reload_cases.py b/tools/perf/page_sets/page_reload_cases.py index 9887809..9851401 100644 --- a/tools/perf/page_sets/page_reload_cases.py +++ b/tools/perf/page_sets/page_reload_cases.py
@@ -33,8 +33,7 @@ def __init__(self): super(PageReloadCasesPageSet, self).__init__( archive_data_file='data/top_25.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) shared_desktop_state = shared_page_state.SharedDesktopPageState
diff --git a/tools/perf/page_sets/partial_invalidation_cases.py b/tools/perf/page_sets/partial_invalidation_cases.py index a8a9473b..939df7be0 100644 --- a/tools/perf/page_sets/partial_invalidation_cases.py +++ b/tools/perf/page_sets/partial_invalidation_cases.py
@@ -24,7 +24,7 @@ def __init__(self): super(PartialInvalidationCasesPageSet, self).__init__( - cloud_storage_bucket=story.PARTNER_BUCKET, verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) other_urls = [ # Why: Reduced test case similar to the single page html5 spec wherein
diff --git a/tools/perf/page_sets/pathological_mobile_sites.py b/tools/perf/page_sets/pathological_mobile_sites.py index bbef7db..514f3cc4 100644 --- a/tools/perf/page_sets/pathological_mobile_sites.py +++ b/tools/perf/page_sets/pathological_mobile_sites.py
@@ -26,8 +26,7 @@ def __init__(self): super(PathologicalMobileSitesPageSet, self).__init__( archive_data_file='data/pathological_mobile_sites.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) sites = ['http://edition.cnn.com', 'http://m.espn.go.com/nhl/rankings',
diff --git a/tools/perf/page_sets/polymer.py b/tools/perf/page_sets/polymer.py index bb8b998..fb465044 100644 --- a/tools/perf/page_sets/polymer.py +++ b/tools/perf/page_sets/polymer.py
@@ -224,8 +224,7 @@ def __init__(self, run_no_page_interactions=False): super(PolymerPageSet, self).__init__( archive_data_file='data/polymer.json', - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) self.AddStory(PolymerCalculatorPage(self, run_no_page_interactions)) self.AddStory(PolymerShadowPage(self, run_no_page_interactions))
diff --git a/tools/perf/page_sets/service_worker.py b/tools/perf/page_sets/service_worker.py index 58e2eea..798bfc5 100644 --- a/tools/perf/page_sets/service_worker.py +++ b/tools/perf/page_sets/service_worker.py
@@ -15,8 +15,7 @@ def __init__(self): super(ServiceWorkerPageSet, self).__init__( archive_data_file=archive_data_file_path, - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) # Why: the first application using ServiceWorker # 1st time: registration
diff --git a/tools/perf/page_sets/service_worker_micro_benchmark.py b/tools/perf/page_sets/service_worker_micro_benchmark.py index 57f9848..788defc 100644 --- a/tools/perf/page_sets/service_worker_micro_benchmark.py +++ b/tools/perf/page_sets/service_worker_micro_benchmark.py
@@ -20,8 +20,7 @@ def __init__(self): super(ServiceWorkerMicroBenchmarkPageSet, self).__init__( archive_data_file='data/service_worker_micro_benchmark.json', - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) # pylint: disable=line-too-long # The latest code of localhost:8091 is from:
diff --git a/tools/perf/page_sets/simple_mobile_sites.py b/tools/perf/page_sets/simple_mobile_sites.py index f3cb9a6..0e2b1ea 100644 --- a/tools/perf/page_sets/simple_mobile_sites.py +++ b/tools/perf/page_sets/simple_mobile_sites.py
@@ -38,8 +38,7 @@ def __init__(self): super(SimpleMobileSitesPageSet, self).__init__( archive_data_file='data/simple_mobile_sites.json', - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) scroll_page_list = [ # Why: Scrolls moderately complex pages (up to 60 layers)
diff --git a/tools/perf/page_sets/startup_pages.py b/tools/perf/page_sets/startup_pages.py index 0b6327d..f40edc7 100644 --- a/tools/perf/page_sets/startup_pages.py +++ b/tools/perf/page_sets/startup_pages.py
@@ -48,8 +48,7 @@ def __init__(self): super(StartupPagesPageSet, self).__init__( archive_data_file='data/startup_pages.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) # Typical page. self.AddStory(StartedPage('about:blank', self))
diff --git a/tools/perf/page_sets/system_health/system_health_stories.py b/tools/perf/page_sets/system_health/system_health_stories.py index 63e90e4..578d7fb 100644 --- a/tools/perf/page_sets/system_health/system_health_stories.py +++ b/tools/perf/page_sets/system_health/system_health_stories.py
@@ -20,8 +20,7 @@ def __init__(self, platform, case=None, take_memory_measurement=False): super(SystemHealthStorySet, self).__init__( archive_data_file=('../data/system_health_%s.json' % platform), - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) assert platform in platforms.ALL_PLATFORMS @@ -35,7 +34,7 @@ class SystemHealthBlankStorySet(story.StorySet): """A story set containing the chrome:blank story only.""" - def __init__(self, take_memory_measurement=False, verify_names=True): + def __init__(self, take_memory_measurement=False): super(SystemHealthBlankStorySet, self).__init__() self.AddStory( chrome_stories.BlankAboutBlankStory(self, take_memory_measurement))
diff --git a/tools/perf/page_sets/top_10.py b/tools/perf/page_sets/top_10.py index 9692ee6..2d7b0a4 100644 --- a/tools/perf/page_sets/top_10.py +++ b/tools/perf/page_sets/top_10.py
@@ -94,8 +94,7 @@ def __init__(self): super(Top10PageSet, self).__init__( archive_data_file='data/top_10.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) # top google property; a google tab is often open self.AddStory(Google(self))
diff --git a/tools/perf/page_sets/top_10_mobile.py b/tools/perf/page_sets/top_10_mobile.py index fca2dfe..40691dca 100644 --- a/tools/perf/page_sets/top_10_mobile.py +++ b/tools/perf/page_sets/top_10_mobile.py
@@ -67,8 +67,7 @@ """ Base class for Top 10 mobile sites """ def __init__(self, run_no_page_interactions=False, - collect_memory_dumps=False, cache_temperatures=None, - verify_names=True): + collect_memory_dumps=False, cache_temperatures=None): super(_Top10MobilePageSet, self).__init__( archive_data_file='data/top_10_mobile.json', cloud_storage_bucket=story.PARTNER_BUCKET)
diff --git a/tools/perf/page_sets/top_25_pages.py b/tools/perf/page_sets/top_25_pages.py index 670aaa39..2032d63 100644 --- a/tools/perf/page_sets/top_25_pages.py +++ b/tools/perf/page_sets/top_25_pages.py
@@ -15,8 +15,7 @@ def __init__(self): super(Top25PageSet, self).__init__( archive_data_file='data/top_25.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) shared_desktop_state = shared_page_state.SharedDesktopPageState self.AddStory(top_pages.GoogleWebSearchPage(self, shared_desktop_state))
diff --git a/tools/perf/page_sets/top_25_smooth.py b/tools/perf/page_sets/top_25_smooth.py index cb90c55..f23261a 100644 --- a/tools/perf/page_sets/top_25_smooth.py +++ b/tools/perf/page_sets/top_25_smooth.py
@@ -114,8 +114,7 @@ def __init__(self, techcrunch=True): super(Top25SmoothPageSet, self).__init__( archive_data_file='data/top_25_smooth.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) desktop_state_class = shared_page_state.SharedDesktopPageState
diff --git a/tools/perf/page_sets/tough_ad_cases.py b/tools/perf/page_sets/tough_ad_cases.py index f1748d01..6ad608b 100644 --- a/tools/perf/page_sets/tough_ad_cases.py +++ b/tools/perf/page_sets/tough_ad_cases.py
@@ -119,8 +119,7 @@ def __init__(self): super(SyntheticToughAdCasesPageSet, self).__init__( archive_data_file='data/tough_ad_cases.json', - cloud_storage_bucket=story.INTERNAL_BUCKET, - verify_names=True) + cloud_storage_bucket=story.INTERNAL_BUCKET) base_url = 'http://localhost:8000' @@ -150,8 +149,7 @@ def __init__(self): super(SyntheticToughWebglAdCasesPageSet, self).__init__( archive_data_file='data/tough_ad_cases.json', - cloud_storage_bucket=story.INTERNAL_BUCKET, - verify_names=True) + cloud_storage_bucket=story.INTERNAL_BUCKET) base_url = 'http://localhost:8000' @@ -181,8 +179,7 @@ def __init__(self, scroll=False): super(ToughAdCasesPageSet, self).__init__( archive_data_file='data/tough_ad_cases.json', - cloud_storage_bucket=story.INTERNAL_BUCKET, - verify_names=True) + cloud_storage_bucket=story.INTERNAL_BUCKET) self.AddStory(AdPage('file://tough_ad_cases/' 'swiffy_collection.html', self, make_javascript_deterministic=False,
diff --git a/tools/perf/page_sets/tough_animation_cases.py b/tools/perf/page_sets/tough_animation_cases.py index 2adafbaf..da5cbf9 100644 --- a/tools/perf/page_sets/tough_animation_cases.py +++ b/tools/perf/page_sets/tough_animation_cases.py
@@ -31,8 +31,7 @@ def __init__(self): super(ToughAnimationCasesPageSet, self).__init__( archive_data_file='data/tough_animation_cases.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) urls_list_one = [ # Why: Tests the balls animation implemented with SVG animations.
diff --git a/tools/perf/page_sets/tough_canvas_cases.py b/tools/perf/page_sets/tough_canvas_cases.py index d9b50b0..aa0ab93 100644 --- a/tools/perf/page_sets/tough_canvas_cases.py +++ b/tools/perf/page_sets/tough_canvas_cases.py
@@ -43,8 +43,7 @@ def __init__(self): super(ToughCanvasCasesPageSet, self).__init__( archive_data_file='data/tough_canvas_cases.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) # Crashes on Galaxy Nexus. crbug.com/314131 # self.AddStory(MicrosofFirefliesPage(self))
diff --git a/tools/perf/page_sets/tough_compositor_cases.py b/tools/perf/page_sets/tough_compositor_cases.py index 82ee6f2f..d49e09e 100644 --- a/tools/perf/page_sets/tough_compositor_cases.py +++ b/tools/perf/page_sets/tough_compositor_cases.py
@@ -48,8 +48,7 @@ def __init__(self): super(ToughCompositorCasesPageSet, self).__init__( archive_data_file='data/tough_compositor_cases.json', - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) scroll_urls_list = [ # Why: Baseline CC scrolling page. A long page with only text. """
diff --git a/tools/perf/page_sets/tough_filters_cases.py b/tools/perf/page_sets/tough_filters_cases.py index 7aa88c8..1056d1a 100644 --- a/tools/perf/page_sets/tough_filters_cases.py +++ b/tools/perf/page_sets/tough_filters_cases.py
@@ -34,8 +34,7 @@ def __init__(self): super(ToughFiltersCasesPageSet, self).__init__( archive_data_file='data/tough_filters_cases.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) urls_list = [ ('http://rawgit.com/WebKit/webkit/master/PerformanceTests/Animometer/developer.html?test-interval=20&display=minimal&controller=fixed&frame-rate=50&kalman-process-error=1&kalman-measurement-error=4&time-measurement=performance&suite-name=Animometer&test-name=Focus&complexity=100', # pylint: disable=line-too-long
diff --git a/tools/perf/page_sets/tough_image_decode_cases.py b/tools/perf/page_sets/tough_image_decode_cases.py index a140fdf..fd20064 100644 --- a/tools/perf/page_sets/tough_image_decode_cases.py +++ b/tools/perf/page_sets/tough_image_decode_cases.py
@@ -31,8 +31,7 @@ def __init__(self): super(ToughImageDecodeCasesPageSet, self).__init__( archive_data_file='data/tough_image_decode_cases.json', - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) page_name_list = [ 'http://localhost:9000/cats-unscaled.html',
diff --git a/tools/perf/page_sets/tough_path_rendering_cases.py b/tools/perf/page_sets/tough_path_rendering_cases.py index c99bb215..debbabf 100644 --- a/tools/perf/page_sets/tough_path_rendering_cases.py +++ b/tools/perf/page_sets/tough_path_rendering_cases.py
@@ -28,8 +28,7 @@ def __init__(self): super(ToughPathRenderingCasesPageSet, self).__init__( archive_data_file='data/tough_path_rendering_cases.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) page_list = [ ('GUIMark Vector Chart Test',
diff --git a/tools/perf/page_sets/tough_pinch_zoom_cases.py b/tools/perf/page_sets/tough_pinch_zoom_cases.py index 371870e2..cecbc7e 100644 --- a/tools/perf/page_sets/tough_pinch_zoom_cases.py +++ b/tools/perf/page_sets/tough_pinch_zoom_cases.py
@@ -218,8 +218,7 @@ def __init__(self, target_scale_factor): super(ToughPinchZoomCasesPageSet, self).__init__( archive_data_file='data/tough_pinch_zoom_cases.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) self.target_scale_factor = target_scale_factor
diff --git a/tools/perf/page_sets/tough_scheduling_cases.py b/tools/perf/page_sets/tough_scheduling_cases.py index b7b6edba..68e8f48 100644 --- a/tools/perf/page_sets/tough_scheduling_cases.py +++ b/tools/perf/page_sets/tough_scheduling_cases.py
@@ -397,8 +397,7 @@ def __init__(self): super(ToughSchedulingCasesPageSet, self).__init__( archive_data_file='data/tough_scheduling_cases.json', - cloud_storage_bucket=story.INTERNAL_BUCKET, - verify_names=True) + cloud_storage_bucket=story.INTERNAL_BUCKET) # Why: Simple scrolling baseline self.AddStory(ToughSchedulingCasesPage(
diff --git a/tools/perf/page_sets/tough_scrolling_cases.py b/tools/perf/page_sets/tough_scrolling_cases.py index dce65ce9..0f5e91d 100644 --- a/tools/perf/page_sets/tough_scrolling_cases.py +++ b/tools/perf/page_sets/tough_scrolling_cases.py
@@ -31,7 +31,7 @@ """ def __init__(self): - super(ToughScrollingCasesPageSet, self).__init__(verify_names=True) + super(ToughScrollingCasesPageSet, self).__init__() fast_scrolling_page_name_list = [ 'text',
diff --git a/tools/perf/page_sets/tough_texture_upload_cases.py b/tools/perf/page_sets/tough_texture_upload_cases.py index 9f6fe47..cfd686e 100644 --- a/tools/perf/page_sets/tough_texture_upload_cases.py +++ b/tools/perf/page_sets/tough_texture_upload_cases.py
@@ -27,7 +27,7 @@ """ def __init__(self): - super(ToughTextureUploadCasesPageSet, self).__init__(verify_names=True) + super(ToughTextureUploadCasesPageSet, self).__init__() urls_list = [ 'file://tough_texture_upload_cases/background_color_animation.html',
diff --git a/tools/perf/page_sets/tough_video_cases.py b/tools/perf/page_sets/tough_video_cases.py index e32cf3ef..80be1cf1 100644 --- a/tools/perf/page_sets/tough_video_cases.py +++ b/tools/perf/page_sets/tough_video_cases.py
@@ -395,8 +395,7 @@ """ def __init__(self, measure_memory=False): super(ToughVideoCasesPageSet, self).__init__( - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) self.measure_memory = measure_memory
diff --git a/tools/perf/page_sets/tough_webgl_cases.py b/tools/perf/page_sets/tough_webgl_cases.py index cdbeacd..34f8d1d7 100644 --- a/tools/perf/page_sets/tough_webgl_cases.py +++ b/tools/perf/page_sets/tough_webgl_cases.py
@@ -46,8 +46,7 @@ def __init__(self): super(ToughWebglCasesPageSet, self).__init__( archive_data_file='data/tough_webgl_cases.json', - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) urls_list = [ # pylint: disable=line-too-long
diff --git a/tools/perf/page_sets/trivial_sites.py b/tools/perf/page_sets/trivial_sites.py index 192ce5b..ae951d7 100644 --- a/tools/perf/page_sets/trivial_sites.py +++ b/tools/perf/page_sets/trivial_sites.py
@@ -133,12 +133,10 @@ class TrivialSitesStorySet(story.StorySet): def __init__(self, shared_state = shared_page_state.SharedPageState, - wait_in_seconds=0, measure_memory=False, - verify_names=True): + wait_in_seconds=0, measure_memory=False): # Wait is time to wait_in_seconds on page in seconds. super(TrivialSitesStorySet, self).__init__( - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) self.AddStory(TrivialScrollingPage( self, shared_state, wait_in_seconds, measure_memory)) self.AddStory(TrivialBlinkingCursorPage(
diff --git a/tools/perf/page_sets/typical_10_mobile.py b/tools/perf/page_sets/typical_10_mobile.py index 53ffbcc6..7ef61b2 100644 --- a/tools/perf/page_sets/typical_10_mobile.py +++ b/tools/perf/page_sets/typical_10_mobile.py
@@ -51,8 +51,7 @@ def __init__(self): super(Typical10MobilePageSet, self).__init__( archive_data_file='data/typical_10_mobile.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) for url in urls_list: self.AddStory(Typical10MobilePage(url, self, name=url))
diff --git a/tools/perf/page_sets/typical_25.py b/tools/perf/page_sets/typical_25.py index 87fc8e3..fbee296 100644 --- a/tools/perf/page_sets/typical_25.py +++ b/tools/perf/page_sets/typical_25.py
@@ -37,8 +37,7 @@ cache_temperatures=None): super(Typical25PageSet, self).__init__( archive_data_file='data/typical_25.json', - cloud_storage_bucket=story.PARTNER_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PARTNER_BUCKET) if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY]
diff --git a/tools/perf/page_sets/v8_top_25.py b/tools/perf/page_sets/v8_top_25.py index f7f98c93..c34ed2e5 100644 --- a/tools/perf/page_sets/v8_top_25.py +++ b/tools/perf/page_sets/v8_top_25.py
@@ -67,8 +67,7 @@ def __init__(self): super(V8Top25StorySet, self).__init__( archive_data_file='data/v8_top_25.json', - cloud_storage_bucket=story.INTERNAL_BUCKET, - verify_names=True) + cloud_storage_bucket=story.INTERNAL_BUCKET) for url in urls_list: self.AddStory(V8Top25(url, self, url))
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py index 9a554a1..582dc53 100644 --- a/tools/perf/page_sets/webrtc_cases.py +++ b/tools/perf/page_sets/webrtc_cases.py
@@ -122,8 +122,7 @@ class WebrtcPageSet(story.StorySet): def __init__(self): super(WebrtcPageSet, self).__init__( - cloud_storage_bucket=story.PUBLIC_BUCKET, - verify_names=True) + cloud_storage_bucket=story.PUBLIC_BUCKET) self.AddStory(MultiplePeerConnections(self, tags=['stress'])) self.AddStory(DataChannel(self, tags=['datachannel']))
diff --git a/tools/sublime/OWNERS b/tools/sublime/OWNERS new file mode 100644 index 0000000..21010ce --- /dev/null +++ b/tools/sublime/OWNERS
@@ -0,0 +1,2 @@ +jkarlin@chromium.org +sashab@chromium.org
diff --git a/ui/events/gesture_detection/gesture_provider.cc b/ui/events/gesture_detection/gesture_provider.cc index 1572b70..2c0c9bf 100644 --- a/ui/events/gesture_detection/gesture_provider.cc +++ b/ui/events/gesture_detection/gesture_provider.cc
@@ -327,6 +327,9 @@ ET_GESTURE_SCROLL_BEGIN, -raw_distance_x, -raw_distance_y); scroll_details.set_device_type(GestureDeviceType::DEVICE_TOUCHSCREEN); + // Scroll focus point always starts with the first touch down point. + scroll_focus_point_.SetPoint(e1.GetX(), e1.GetY()); + // Use the co-ordinates from the touch down, as these co-ordinates are // used to determine which layer the scroll should affect. Send(CreateGesture(scroll_details, e2.GetPointerId(), e2.GetToolType(), @@ -336,18 +339,20 @@ e2.GetFlags())); DCHECK(scroll_event_sent_); } + scroll_focus_point_.SetPoint(scroll_focus_point_.x() - raw_distance_x, + scroll_focus_point_.y() - raw_distance_y); GestureEventDetails scroll_details(ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y); scroll_details.set_device_type(GestureDeviceType::DEVICE_TOUCHSCREEN); const gfx::RectF bounding_box = GetBoundingBox(e2, scroll_details.type()); - const gfx::PointF center = bounding_box.CenterPoint(); const gfx::PointF raw_center = - center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY()); + scroll_focus_point_ + + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY()); Send(CreateGesture(scroll_details, e2.GetPointerId(), e2.GetToolType(), - e2.GetEventTime(), center.x(), center.y(), - raw_center.x(), raw_center.y(), e2.GetPointerCount(), - bounding_box, e2.GetFlags())); + e2.GetEventTime(), scroll_focus_point_.x(), + scroll_focus_point_.y(), raw_center.x(), raw_center.y(), + e2.GetPointerCount(), bounding_box, e2.GetFlags())); return true; } @@ -747,6 +752,9 @@ // sequence. bool show_press_event_sent_; + // The scroll focus point is set to the first touch down point when scroll + // begins and is later updated based on the delta of touch points. + gfx::PointF scroll_focus_point_; DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); };
diff --git a/ui/events/test/event_generator.cc b/ui/events/test/event_generator.cc index 190d70e..071198be3 100644 --- a/ui/events/test/event_generator.cc +++ b/ui/events/test/event_generator.cc
@@ -398,16 +398,90 @@ callback.Run(ui::ET_GESTURE_SCROLL_END, gfx::Vector2dF()); } -void EventGenerator::GestureMultiFingerScroll(int count, - const gfx::Point start[], - int event_separation_time_ms, - int steps, - int move_x, - int move_y) { +void EventGenerator::GestureMultiFingerScrollWithDelays( + int count, + const gfx::Point start[], + const gfx::Vector2d delta[], + const int delay_adding_finger_ms[], + const int delay_releasing_finger_ms[], + int event_separation_time_ms, + int steps) { const int kMaxTouchPoints = 10; - int delays[kMaxTouchPoints] = { 0 }; - GestureMultiFingerScrollWithDelays( - count, start, delays, event_separation_time_ms, steps, move_x, move_y); + CHECK_LE(count, kMaxTouchPoints); + CHECK_GT(steps, 0); + + gfx::Point points[kMaxTouchPoints]; + gfx::Vector2d delta_per_step[kMaxTouchPoints]; + for (int i = 0; i < count; ++i) { + points[i] = start[i]; + delta_per_step[i].set_x(delta[i].x() / steps); + delta_per_step[i].set_y(delta[i].y() / steps); + } + + base::TimeTicks press_time_first = ui::EventTimeForNow(); + base::TimeTicks press_time[kMaxTouchPoints]; + base::TimeTicks release_time[kMaxTouchPoints]; + bool pressed[kMaxTouchPoints]; + for (int i = 0; i < count; ++i) { + pressed[i] = false; + press_time[i] = press_time_first + + base::TimeDelta::FromMilliseconds(delay_adding_finger_ms[i]); + release_time[i] = press_time_first + base::TimeDelta::FromMilliseconds( + delay_releasing_finger_ms[i]); + DCHECK_LE(press_time[i], release_time[i]); + } + + for (int step = 0; step < steps; ++step) { + base::TimeTicks move_time = + press_time_first + + base::TimeDelta::FromMilliseconds(event_separation_time_ms * step); + + for (int i = 0; i < count; ++i) { + if (!pressed[i] && move_time >= press_time[i]) { + ui::TouchEvent press( + ui::ET_TOUCH_PRESSED, points[i], press_time[i], + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, i)); + Dispatch(&press); + pressed[i] = true; + } + } + + // All touch release events should occur at the end if + // |event_separation_time_ms| is 0. + for (int i = 0; i < count && event_separation_time_ms > 0; ++i) { + if (pressed[i] && move_time >= release_time[i]) { + ui::TouchEvent release( + ui::ET_TOUCH_RELEASED, points[i], release_time[i], + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, i)); + Dispatch(&release); + pressed[i] = false; + } + } + + for (int i = 0; i < count; ++i) { + points[i] += delta_per_step[i]; + if (pressed[i]) { + ui::TouchEvent move( + ui::ET_TOUCH_MOVED, points[i], move_time, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, i)); + Dispatch(&move); + } + } + } + + base::TimeTicks default_release_time = + press_time_first + + base::TimeDelta::FromMilliseconds(event_separation_time_ms * steps); + // Ensures that all pressed fingers are released in the end. + for (int i = 0; i < count; ++i) { + if (pressed[i]) { + ui::TouchEvent release( + ui::ET_TOUCH_RELEASED, points[i], default_release_time, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, i)); + Dispatch(&release); + pressed[i] = false; + } + } } void EventGenerator::GestureMultiFingerScrollWithDelays( @@ -419,64 +493,28 @@ int move_x, int move_y) { const int kMaxTouchPoints = 10; - gfx::Point points[kMaxTouchPoints]; - CHECK_LE(count, kMaxTouchPoints); - CHECK_GT(steps, 0); - - int delta_x = move_x / steps; - int delta_y = move_y / steps; - - for (int i = 0; i < count; ++i) { - points[i] = start[i]; + int delay_releasing_finger_ms[kMaxTouchPoints]; + gfx::Vector2d delta[kMaxTouchPoints]; + for (int i = 0; i < kMaxTouchPoints; ++i) { + delay_releasing_finger_ms[i] = event_separation_time_ms * steps; + delta[i].set_x(move_x); + delta[i].set_y(move_y); } + GestureMultiFingerScrollWithDelays( + count, start, delta, delay_adding_finger_ms, delay_releasing_finger_ms, + event_separation_time_ms, steps); +} - base::TimeTicks press_time_first = ui::EventTimeForNow(); - base::TimeTicks press_time[kMaxTouchPoints]; - bool pressed[kMaxTouchPoints]; - for (int i = 0; i < count; ++i) { - pressed[i] = false; - press_time[i] = press_time_first + - base::TimeDelta::FromMilliseconds(delay_adding_finger_ms[i]); - } - - int last_id = 0; - for (int step = 0; step < steps; ++step) { - base::TimeTicks move_time = - press_time_first + - base::TimeDelta::FromMilliseconds(event_separation_time_ms * step); - - while (last_id < count && - !pressed[last_id] && - move_time >= press_time[last_id]) { - ui::TouchEvent press( - ui::ET_TOUCH_PRESSED, points[last_id], press_time[last_id], - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, - last_id)); - Dispatch(&press); - pressed[last_id] = true; - last_id++; - } - - for (int i = 0; i < count; ++i) { - points[i].Offset(delta_x, delta_y); - if (i >= last_id) - continue; - ui::TouchEvent move( - ui::ET_TOUCH_MOVED, points[i], move_time, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, i)); - Dispatch(&move); - } - } - - base::TimeTicks release_time = - press_time_first + - base::TimeDelta::FromMilliseconds(event_separation_time_ms * steps); - for (int i = 0; i < last_id; ++i) { - ui::TouchEvent release( - ui::ET_TOUCH_RELEASED, points[i], release_time, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, i)); - Dispatch(&release); - } +void EventGenerator::GestureMultiFingerScroll(int count, + const gfx::Point start[], + int event_separation_time_ms, + int steps, + int move_x, + int move_y) { + const int kMaxTouchPoints = 10; + int delays[kMaxTouchPoints] = {0}; + GestureMultiFingerScrollWithDelays( + count, start, delays, event_separation_time_ms, steps, move_x, move_y); } void EventGenerator::ScrollSequence(const gfx::Point& start,
diff --git a/ui/events/test/event_generator.h b/ui/events/test/event_generator.h index c262dcf3..1ce4542 100644 --- a/ui/events/test/event_generator.h +++ b/ui/events/test/event_generator.h
@@ -356,29 +356,26 @@ // Generates press, move, release touch-events to generate a sequence of // multi-finger scroll events. |count| specifies the number of touch-points // that should generate the scroll events. |start| are the starting positions - // of all the touch points. |steps| and |event_separation_time_ms| are - // relevant when testing velocity/fling/swipe, otherwise these can be any - // non-zero value. |delta_x| and |delta_y| are the amount that each finger - // should be moved. Internally calls GestureMultiFingerScrollWithDelays - // with zeros as |delay_adding_finger_ms| forcing all touch down events to be - // immediate. - void GestureMultiFingerScroll(int count, - const gfx::Point start[], - int event_separation_time_ms, - int steps, - int move_x, - int move_y); + // of all the touch points. |delta| specifies the moving vectors for all + // fingers. |delay_adding_finger_ms| are delays in ms from the starting time + // till touching down of each finger. |delay_releasing_finger_ms| are delays + // in ms from starting time till touching release of each finger. These two + // parameters are useful when testing complex gestures that start with 1 or 2 + // fingers and add fingers with a delay. |steps| and + // |event_separation_time_ms| are relevant when testing velocity/fling/swipe, + // otherwise these can be any non-zero value. + void GestureMultiFingerScrollWithDelays(int count, + const gfx::Point start[], + const gfx::Vector2d delta[], + const int delay_adding_finger_ms[], + const int delay_releasing_finger_ms[], + int event_separation_time_ms, + int steps); - // Generates press, move, release touch-events to generate a sequence of - // multi-finger scroll events. |count| specifies the number of touch-points - // that should generate the scroll events. |start| are the starting positions - // of all the touch points. |delay_adding_finger_ms| are delays in ms from the - // starting time till touching down of each finger. |delay_adding_finger_ms| - // is useful when testing complex gestures that start with 1 or 2 fingers and - // add fingers with a delay. |steps| and |event_separation_time_ms| are - // relevant when testing velocity/fling/swipe, otherwise these can be any - // non-zero value. |delta_x| and |delta_y| are the amount that each finger - // should be moved. + // Similar to GestureMultiFingerScrollWithDelays() above. Generates press, + // move, release touch-events to generate a sequence of multi-finger scroll + // events. All fingers are released at the end of scrolling together. All + // fingers move the same amount specified by |move_x| and |move_y|. void GestureMultiFingerScrollWithDelays(int count, const gfx::Point start[], const int delay_adding_finger_ms[], @@ -387,6 +384,18 @@ int move_x, int move_y); + // Similar to GestureMultiFingerScrollWithDelays(). Generates press, move, + // release touch-events to generate a sequence of multi-finger scroll events. + // All fingers are pressed at the beginning together and are released at the + // end of scrolling together. All fingers move move the same amount specified + // by |move_x| and |move_y|. + void GestureMultiFingerScroll(int count, + const gfx::Point start[], + int event_separation_time_ms, + int steps, + int move_x, + int move_y); + // Generates scroll sequences of a FlingCancel, Scrolls, FlingStart, with // constant deltas to |x_offset| and |y_offset| in |steps|. void ScrollSequence(const gfx::Point& start,
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc index d8b64def..068a2a55 100644 --- a/ui/message_center/views/notification_view_md.cc +++ b/ui/message_center/views/notification_view_md.cc
@@ -90,6 +90,41 @@ return gfx::CreateVectorIcon(kProductIcon, kSmallImageColor); } +// ItemView //////////////////////////////////////////////////////////////////// + +// ItemViews are responsible for drawing each list notification item's title and +// message next to each other within a single column. +class ItemView : public views::View { + public: + explicit ItemView(const message_center::NotificationItem& item); + ~ItemView() override; + + private: + DISALLOW_COPY_AND_ASSIGN(ItemView); +}; + +ItemView::ItemView(const message_center::NotificationItem& item) { + SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kHorizontal, gfx::Insets(), + message_center::kItemTitleToMessagePadding)); + + views::Label* title = new views::Label(item.title); + title->set_collapse_when_hidden(true); + title->SetHorizontalAlignment(gfx::ALIGN_LEFT); + title->SetEnabledColor(message_center::kRegularTextColor); + title->SetBackgroundColor(message_center::kDimTextBackgroundColor); + AddChildView(title); + + views::Label* message = new views::Label(item.message); + message->set_collapse_when_hidden(true); + message->SetHorizontalAlignment(gfx::ALIGN_LEFT); + message->SetEnabledColor(message_center::kDimTextColor); + message->SetBackgroundColor(message_center::kDimTextBackgroundColor); + AddChildView(message); +} + +ItemView::~ItemView() {} + } // anonymous namespace // //////////////////////////////////////////////////////////// @@ -347,6 +382,8 @@ } else { message_view_->SetText(text); } + + message_view_->SetVisible(notification.items().empty()); } void NotificationViewMD::CreateOrUpdateProgressBarView( @@ -356,7 +393,21 @@ void NotificationViewMD::CreateOrUpdateListItemViews( const Notification& notification) { - // TODO(yoshiki): Implement this. + for (auto* item_view : item_views_) + delete item_view; + item_views_.clear(); + + const std::vector<NotificationItem>& items = notification.items(); + + for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) { + ItemView* item_view = new ItemView(items[i]); + item_views_.push_back(item_view); + left_content_->AddChildView(item_view); + } + + // Needed when CreateOrUpdateViews is called for update. + if (!item_views_.empty()) + left_content_->InvalidateLayout(); } void NotificationViewMD::CreateOrUpdateIconView( @@ -485,6 +536,10 @@ if (image_view_) return true; + // Expandable if there are multiple list items. + if (item_views_.size() > 1) + return true; + // TODO(fukino): Expandable if both progress bar and message exist. return false; @@ -507,6 +562,9 @@ if (image_container_) image_container_->SetVisible(expanded); actions_row_->SetVisible(expanded && actions_row_->has_children()); + for (size_t i = 1; i < item_views_.size(); ++i) { + item_views_[i]->SetVisible(expanded); + } } void NotificationViewMD::UpdateControlButtonsVisibility() {
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h index 4d8054e2..38ff06d 100644 --- a/ui/message_center/views/notification_view_md.h +++ b/ui/message_center/views/notification_view_md.h
@@ -98,6 +98,7 @@ views::View* image_container_ = nullptr; ProportionalImageView* image_view_ = nullptr; std::vector<views::LabelButton*> action_buttons_; + std::vector<views::View*> item_views_; DISALLOW_COPY_AND_ASSIGN(NotificationViewMD); };
diff --git a/ui/views/bubble/bubble_dialog_delegate.cc b/ui/views/bubble/bubble_dialog_delegate.cc index b8be537..502bc0b8 100644 --- a/ui/views/bubble/bubble_dialog_delegate.cc +++ b/ui/views/bubble/bubble_dialog_delegate.cc
@@ -98,7 +98,11 @@ ClientView* BubbleDialogDelegateView::CreateClientView(Widget* widget) { DialogClientView* client = new DialogClientView(widget, GetContentsView()); - client->SetButtonRowInsets(gfx::Insets()); + LayoutProvider* provider = LayoutProvider::Get(); + // The other three sides are taken care of by the |margins_| given to + // BubbleFrameView in CreateNonClientFrameView(). + client->SetButtonRowInsets(gfx::Insets( + provider->GetDistanceMetric(DISTANCE_BUBBLE_BUTTON_TOP_MARGIN), 0, 0, 0)); widget->non_client_view()->set_mirror_client_in_rtl(mirror_arrow_in_rtl_); return client; }
diff --git a/ui/views/layout/layout_provider.cc b/ui/views/layout/layout_provider.cc index a4fd678..10b40e3 100644 --- a/ui/views/layout/layout_provider.cc +++ b/ui/views/layout/layout_provider.cc
@@ -86,6 +86,7 @@ return kRelatedButtonHSpacing; case DistanceMetric::DISTANCE_RELATED_CONTROL_HORIZONTAL: return kRelatedControlHorizontalSpacing; + case DistanceMetric::DISTANCE_BUBBLE_BUTTON_TOP_MARGIN: case DistanceMetric::DISTANCE_RELATED_CONTROL_VERTICAL: return kRelatedControlVerticalSpacing; case DISTANCE_DIALOG_BUTTON_BOTTOM_MARGIN:
diff --git a/ui/views/layout/layout_provider.h b/ui/views/layout/layout_provider.h index 5d67084..92b5fdf 100644 --- a/ui/views/layout/layout_provider.h +++ b/ui/views/layout/layout_provider.h
@@ -49,8 +49,11 @@ // two types have not been interchanged. VIEWS_DISTANCE_START = VIEWS_INSETS_MAX, + // If a bubble has buttons, this is the margin between them and the rest of + // the content. + DISTANCE_BUBBLE_BUTTON_TOP_MARGIN = VIEWS_DISTANCE_START, // Margin on the left and right of the contents of a bubble. - DISTANCE_BUBBLE_CONTENTS_HORIZONTAL_MARGIN = VIEWS_DISTANCE_START, + DISTANCE_BUBBLE_CONTENTS_HORIZONTAL_MARGIN, // Margin on the top and bottom of the contents of a bubble. DISTANCE_BUBBLE_CONTENTS_VERTICAL_MARGIN, // The default padding to add on each side of a button's label.
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc index 0e4a4c34..7d62cadf 100644 --- a/ui/views/window/dialog_client_view.cc +++ b/ui/views/window/dialog_client_view.cc
@@ -342,17 +342,6 @@ if (std::count(views.begin(), views.end(), nullptr) == kNumButtons) return; - gfx::Insets insets = button_row_insets_; - LayoutProvider* const layout_provider = LayoutProvider::Get(); - // Support dialogs that clear |button_row_insets_| to do their own layout. - // They expect GetDialogRelatedControlVerticalSpacing() in this case. - if (insets.top() == 0 && - !ui::MaterialDesignController::IsSecondaryUiMaterial()) { - const int top = - layout_provider->GetDistanceMetric(DISTANCE_RELATED_CONTROL_VERTICAL); - insets.Set(top, insets.left(), insets.bottom(), insets.right()); - } - // The |resize_percent| constants. There's only one stretchy column (padding // to the left of ok/cancel buttons). constexpr float kFixed = 0.f; @@ -361,6 +350,7 @@ // Button row is [ extra <pad+stretchy> second <pad> third ]. Ensure the <pad> // column is zero width if there isn't a button on either side. // GetExtraViewSpacing() handles <pad+stretchy>. + LayoutProvider* const layout_provider = LayoutProvider::Get(); const int button_spacing = (ok_button_ && cancel_button_) ? layout_provider->GetDistanceMetric( DISTANCE_RELATED_BUTTON_HORIZONTAL) @@ -371,7 +361,7 @@ // Rather than giving |button_row_container_| a Border, incorporate the insets // into the layout. This simplifies min/max size calculations. - column_set->AddPaddingColumn(kFixed, insets.left()); + column_set->AddPaddingColumn(kFixed, button_row_insets_.left()); column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed, GridLayout::USE_PREF, 0, 0); column_set->AddPaddingColumn(kStretchy, GetExtraViewSpacing()); @@ -380,14 +370,15 @@ column_set->AddPaddingColumn(kFixed, button_spacing); column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed, GridLayout::USE_PREF, 0, 0); - column_set->AddPaddingColumn(kFixed, insets.right()); + column_set->AddPaddingColumn(kFixed, button_row_insets_.right()); // Track which columns to link sizes under MD. constexpr int kViewToColumnIndex[] = {1, 3, 5}; int link[] = {-1, -1, -1}; size_t link_index = 0; - layout->StartRowWithPadding(kFixed, kButtonRowId, kFixed, insets.top()); + layout->StartRowWithPadding(kFixed, kButtonRowId, kFixed, + button_row_insets_.top()); for (size_t view_index = 0; view_index < kNumButtons; ++view_index) { if (views[view_index]) { layout->AddView(views[view_index]); @@ -411,7 +402,7 @@ else column_set->LinkColumnSizes(link[0], link[1], link[2], -1); - layout->AddPaddingRow(kFixed, insets.bottom()); + layout->AddPaddingRow(kFixed, button_row_insets_.bottom()); // The default focus is lost when child views are added back into the dialog. // This restores focus if the button is still available.