diff --git a/.gn b/.gn index 50a8a2f..375c60c 100644 --- a/.gn +++ b/.gn
@@ -113,7 +113,6 @@ "//extensions/renderer:unit_tests", "//extensions/shell:browser_tests", "//extensions/shell:unit_tests", - "//extensions/utility:unit_tests", "//gin/*", "//google_apis/*", "//google_update/*",
diff --git a/DEPS b/DEPS index dd0cdcf..25ab214 100644 --- a/DEPS +++ b/DEPS
@@ -79,7 +79,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': 'b537879c7214efd87840c9a7267ab3b3facda873', + 'skia_revision': '8c4cbf4cfb6d9236dfd69273bff7e8384744c29a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -103,7 +103,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '3baef5c6daf58cec2df193714b5727802d0bd42e', + 'pdfium_revision': '69da36c5f841e8c6e5ded6c704d9ef58c57d532a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -135,7 +135,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'b90b97cf8dec1060b14197b68a7c862bab7e4ed5', + 'catapult_revision': '21ff400bb4884e9a601168e7fa08559a76e06a75', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index fafc895..d9435634 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -2180,15 +2180,21 @@ results = [] # First, check for new / deleted .pydeps. for f in input_api.AffectedFiles(include_deletes=True): - if f.LocalPath().endswith('.pydeps'): - if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES: - results.append(output_api.PresubmitError( - 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to ' - 'remove %s' % f.LocalPath())) - elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES: - results.append(output_api.PresubmitError( - 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to ' - 'include %s' % f.LocalPath())) + # Check whether we are running the presubmit check for a file in src. + # f.LocalPath is relative to repo (src, or internal repo). + # os_path.exists is relative to src repo. + # Therefore if os_path.exists is true, it means f.LocalPath is relative + # to src and we can conclude that the pydeps is in src. + if input_api.os_path.exists(f.LocalPath()): + if f.LocalPath().endswith('.pydeps'): + if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES: + results.append(output_api.PresubmitError( + 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to ' + 'remove %s' % f.LocalPath())) + elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES: + results.append(output_api.PresubmitError( + 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to ' + 'include %s' % f.LocalPath())) if results: return results
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py index bcca909f..b83d58ad 100755 --- a/PRESUBMIT_test.py +++ b/PRESUBMIT_test.py
@@ -656,10 +656,21 @@ MockAffectedFile('new.pydeps', [], action='A'), ] + self.mock_input_api.CreateMockFileInPath( + [x.LocalPath() for x in self.mock_input_api.AffectedFiles( + include_deletes=True)]) results = self._RunCheck() self.assertEqual(1, len(results)) self.assertTrue('PYDEPS_FILES' in str(results[0])) + def testPydepNotInSrc(self): + self.mock_input_api.files = [ + MockAffectedFile('new.pydeps', [], action='A'), + ] + self.mock_input_api.CreateMockFileInPath([]) + results = self._RunCheck() + self.assertEqual(0, len(results)) + def testRemovedPydep(self): # PRESUBMIT._CheckPydepsNeedsUpdating is only implemented for Android. if self.mock_input_api.platform != 'linux2': @@ -668,7 +679,9 @@ self.mock_input_api.files = [ MockAffectedFile(PRESUBMIT._ALL_PYDEPS_FILES[0], [], action='D'), ] - + self.mock_input_api.CreateMockFileInPath( + [x.LocalPath() for x in self.mock_input_api.AffectedFiles( + include_deletes=True)]) results = self._RunCheck() self.assertEqual(1, len(results)) self.assertTrue('PYDEPS_FILES' in str(results[0]))
diff --git a/PRESUBMIT_test_mocks.py b/PRESUBMIT_test_mocks.py index 732da0e..846f8413 100644 --- a/PRESUBMIT_test_mocks.py +++ b/PRESUBMIT_test_mocks.py
@@ -51,6 +51,7 @@ return errors + class MockInputApi(object): """Mock class for the InputApi class. @@ -75,6 +76,9 @@ self.change = MockChange([]) self.presubmit_local_path = os.path.dirname(__file__) + def CreateMockFileInPath(self, f_list): + self.os_path.exists = lambda x: x in f_list + def AffectedFiles(self, file_filter=None, include_deletes=False): for file in self.files: if file_filter and not file_filter(file):
diff --git a/WATCHLISTS b/WATCHLISTS index 23c7b43a..e6f16160 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1880,7 +1880,8 @@ 'shimazu+worker@chromium.org'], 'blink_wtf': ['blink-reviews-wtf@chromium.org', 'mikhail.pozdnyakov@intel.com'], - 'blink_xml': ['dominicc+watchlist@chromium.org', 'joelhockey@chromium.org'], + 'blink_xml': ['dominicc+watchlist@chromium.org', + 'joelhockey+watch@chromium.org'], 'bookmarks': ['tfarina@chromium.org'], 'bottombar': ['donnd+watch@chromium.org', 'mdjones+watch@chromium.org'], @@ -2018,7 +2019,8 @@ 'nhiroki@chromium.org', 'tzik@chromium.org'], 'filebrowse': ['rginda+watch@chromium.org'], - 'filesapp': ['fukino+watch@chromium.org', + 'filesapp': ['filesapp-reviews@chromium.org', + 'fukino+watch@chromium.org', 'oka+watch@chromium.org', 'yamaguchi+watch@chromium.org'], 'fsp': ['mtomasz+watch@chromium.org'],
diff --git a/android_webview/browser/aw_browser_terminator.cc b/android_webview/browser/aw_browser_terminator.cc index 8a0d1c3..eb284e68 100644 --- a/android_webview/browser/aw_browser_terminator.cc +++ b/android_webview/browser/aw_browser_terminator.cc
@@ -17,6 +17,7 @@ #include "base/task_scheduler/post_task.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_data.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" @@ -106,7 +107,7 @@ void AwBrowserTerminator::OnChildStart( int process_host_id, content::PosixFileDescriptorInfo* mappings) { - DCHECK_CURRENTLY_ON(content::BrowserThread::PROCESS_LAUNCHER); + DCHECK(content::CurrentlyOnProcessLauncherTaskRunner()); base::AutoLock auto_lock(process_host_id_to_pipe_lock_); DCHECK(!ContainsKey(process_host_id_to_pipe_, process_host_id));
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 50a014d..cdd3378 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -298,6 +298,8 @@ "login/ui/login_button.h", "login/ui/login_data_dispatcher.cc", "login/ui/login_data_dispatcher.h", + "login/ui/login_detachable_base_model.cc", + "login/ui/login_detachable_base_model.h", "login/ui/login_password_view.cc", "login/ui/login_password_view.h", "login/ui/login_pin_view.cc", @@ -1107,6 +1109,7 @@ deps = [ "//ash/autoclick/common:autoclick", "//ash/components/autoclick/public/mojom", + "//ash/components/cursor", "//ash/components/fast_ink", "//ash/components/quick_launch/public/mojom", "//ash/touch_hud", @@ -1454,6 +1457,8 @@ "login/login_screen_controller_unittest.cc", "login/mock_login_screen_client.cc", "login/mock_login_screen_client.h", + "login/ui/fake_login_detachable_base_model.cc", + "login/ui/fake_login_detachable_base_model.h", "login/ui/lock_contents_view_unittest.cc", "login/ui/lock_screen_sanity_unittest.cc", "login/ui/lock_window_unittest.cc",
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc index 4e0b8ea5..3c2406f 100644 --- a/ash/accelerators/accelerator_controller_unittest.cc +++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -1026,6 +1026,10 @@ AshTestBase::SetUp(); Shell::Get()->lock_state_controller()->set_animator_for_test( new TestSessionStateAnimator); + Shell::Get()->power_button_controller()->OnGetSwitchStates( + chromeos::PowerManagerClient::SwitchStates{ + chromeos::PowerManagerClient::LidState::OPEN, + chromeos::PowerManagerClient::TabletMode::ON}); } private:
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 41b39e9..375c514 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -535,6 +535,11 @@ No recent items </message> + <!-- Window Selector --> + <message name="IDS_ASH_WINDOW_SELECTOR_INPUT_FILTER_ACCESSIBLE_NAME" desc="The accessible name for the window selector filter search input box."> + Type the name of an app or document + </message> + <!-- Status tray charging strings. --> <message name="IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_TITLE" desc="The title of a notification indicating that a low-current USB charger has been connected."> Low-power charger connected
diff --git a/ash/components/cursor/BUILD.gn b/ash/components/cursor/BUILD.gn new file mode 100644 index 0000000..8184365 --- /dev/null +++ b/ash/components/cursor/BUILD.gn
@@ -0,0 +1,23 @@ +# Copyright 2018 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. + +source_set("cursor") { + sources = [ + "cursor_view.cc", + "cursor_view.h", + ] + + deps = [ + "//ash/components/fast_ink", + "//base", + "//cc", + "//components/viz/common", + "//skia", + "//ui/aura", + "//ui/events", + "//ui/events/ozone:events_ozone", + "//ui/gfx", + "//ui/views:views", + ] +}
diff --git a/ash/components/cursor/DEPS b/ash/components/cursor/DEPS new file mode 100644 index 0000000..f95cf84 --- /dev/null +++ b/ash/components/cursor/DEPS
@@ -0,0 +1,10 @@ +include_rules = [ + "+ash/components/fast_ink", + "+base", + "+cc/paint", + "+components/viz/common", + "+ui/aura", + "+ui/events", + "+ui/gfx", + "+ui/views", +]
diff --git a/ash/components/cursor/OWNERS b/ash/components/cursor/OWNERS new file mode 100644 index 0000000..6701591 --- /dev/null +++ b/ash/components/cursor/OWNERS
@@ -0,0 +1,2 @@ +reveman@chromium.org +oshima@chromium.org
diff --git a/ash/components/cursor/cursor_view.cc b/ash/components/cursor/cursor_view.cc new file mode 100644 index 0000000..dcb993e --- /dev/null +++ b/ash/components/cursor/cursor_view.cc
@@ -0,0 +1,339 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/components/cursor/cursor_view.h" + +#include "base/task_scheduler/post_task.h" +#include "base/threading/thread_task_runner_handle.h" +#include "cc/paint/paint_canvas.h" +#include "ui/aura/window.h" +#include "ui/events/base_event_utils.h" +#include "ui/gfx/skia_util.h" +#include "ui/views/widget/widget.h" + +namespace cursor { +namespace { + +// Amount of time without cursor movement before entering stationary state. +const int kStationaryDelayMs = 500; + +// Clamp velocity to this value. +const float kVelocityMax = 5000.0f; + +// Interpolation factor used to compute responsive velocity. Valid range +// is 0.0 to 1.0, where 1.0 takes only current velocity into account. +const float kResponsiveVelocityFactor = 0.75f; + +// Interpolation factor used to compute smooth velocity. Valid range +// is 0.0 to 1.0, where 1.0 takes only current velocity into account. +const float kSmoothVelocityFactor = 0.25f; + +// Interpolation factor used to compute cursor movement. Valid range +// is 0.0 to 1.0, where 1.0 takes only smooth velocity into account. +const float kMovementFactor = 0.25f; + +// Minimum movement for motion blur to be added. +const float kMinimumMovementForMotionBlur = 2.0f; + +// Clamp motion blur sigma to this value. +const float kSigmaMax = 48.0f; + +// Offset relative to VSYNC at which to request a redraw. +const int kVSyncOffsetMs = -4; + +gfx::Vector2dF InterpolateBetween(const gfx::Vector2dF& start, + const gfx::Vector2dF& end, + float f) { + return start + gfx::ScaleVector2d(end - start, f); +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// CursorView, public: + +CursorView::CursorView(aura::Window* container, + const gfx::Point& initial_location, + bool is_motion_blur_enabled) + : fast_ink::FastInkView( + container, + base::BindRepeating(&CursorView::DidPresentCompositorFrame, + base::Unretained(this))), + is_motion_blur_enabled_(is_motion_blur_enabled), + ui_task_runner_(base::ThreadTaskRunnerHandle::Get()), + paint_task_runner_(base::CreateSingleThreadTaskRunnerWithTraits( + {base::TaskPriority::USER_BLOCKING, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})), + new_location_(initial_location), + stationary_timer_(new base::Timer( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kStationaryDelayMs), + base::BindRepeating(&CursorView::StationaryOnPaintThread, + base::Unretained(this)), + /*is_repeating=*/false)), + weak_ptr_factory_(this) { + DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_); + + // Detach sequence checker for future usage on paint thread. + DETACH_FROM_SEQUENCE(paint_sequence_checker_); + + // Create update surface callback that will be posted from paint thread + // to UI thread. + update_surface_callback_ = base::BindRepeating( + &CursorView::UpdateSurface, weak_ptr_factory_.GetWeakPtr()); + + // Create transform used to convert cursor controller coordinates to screen + // coordinates. + bool rv = + screen_to_buffer_transform_.GetInverse(&buffer_to_screen_transform_); + DCHECK(rv); + + ui::CursorController::GetInstance()->AddCursorObserver(this); +} + +CursorView::~CursorView() { + DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_); + + ui::CursorController::GetInstance()->RemoveCursorObserver(this); +} + +void CursorView::SetCursorImage(const gfx::ImageSkia& cursor_image, + const gfx::Size& cursor_size, + const gfx::Point& cursor_hotspot) { + DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_); + + { + base::AutoLock lock(lock_); + + new_cursor_image_ = cursor_image; + new_cursor_size_ = cursor_size; + new_cursor_hotspot_ = cursor_hotspot; + } + + // Unretained is safe as |paint_task_runner_| uses SKIP_ON_SHUTDOWN. + paint_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&CursorView::SetActiveOnPaintThread, + base::Unretained(this), true)); +} + +//////////////////////////////////////////////////////////////////////////////// +// ui::CursorController::CursorObserver overrides: + +void CursorView::OnCursorLocationChanged(const gfx::PointF& location) { + gfx::PointF new_location_f = location; + buffer_to_screen_transform_.TransformPoint(&new_location_f); + gfx::Point new_location = gfx::ToRoundedPoint(new_location_f); + + { + base::AutoLock lock(lock_); + + if (new_location_ == new_location) + return; + new_location_ = new_location; + } + + // Unretained is safe as |paint_task_runner_| uses SKIP_ON_SHUTDOWN. + paint_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&CursorView::SetActiveOnPaintThread, + base::Unretained(this), true)); +} + +//////////////////////////////////////////////////////////////////////////////// +// viz::DelayBasedTimeSourceClient overrides: + +void CursorView::OnTimerTick() { + DCHECK_CALLED_ON_VALID_SEQUENCE(paint_sequence_checker_); + + gfx::Point old_location = location_; + + { + base::AutoLock lock(lock_); + + location_ = new_location_; + cursor_size_ = new_cursor_size_; + cursor_image_ = new_cursor_image_; + cursor_hotspot_ = new_cursor_hotspot_; + } + + // Restart stationary timer if pointer location changed. + if (location_ != old_location) + stationary_timer_->Reset(); + + base::TimeDelta interval = time_source_->Interval(); + // Compute velocity unless this is the first tick. + if (time_source_->LastTickTime() == next_tick_time_) { + // Velocity is pixels/second as interval might change. + velocity_ = gfx::ScaleVector2d(old_location - location_, + 1.f / interval.InSecondsF()); + velocity_.SetToMin(gfx::Vector2dF(kVelocityMax, kVelocityMax)); + } + + // Save next tick time. + next_tick_time_ = time_source_->NextTickTime(); + + // Use "Complementary Filter" algorithm to determine velocity. + // This allows us to be responsive in the short term and accurate + // in the long term. + responsive_velocity_ = InterpolateBetween(responsive_velocity_, velocity_, + kResponsiveVelocityFactor); + smooth_velocity_ = + InterpolateBetween(smooth_velocity_, velocity_, kSmoothVelocityFactor); + + // Estimate movement over one time source (VSYNC) interval. + gfx::Vector2dF movement = + gfx::ScaleVector2d(InterpolateBetween(responsive_velocity_, + smooth_velocity_, kMovementFactor), + interval.InSecondsF()); + + float distance = movement.Length(); + if (is_motion_blur_enabled_ && distance >= kMinimumMovementForMotionBlur) { + float sigma = std::min(distance / 3.f, kSigmaMax); + + // Create directional blur filter for |sigma|. + motion_blur_filter_ = sk_make_sp<cc::BlurPaintFilter>( + sigma, 0.f, SkBlurImageFilter::TileMode::kClampToBlack_TileMode, + nullptr); + + // Compute blur offset. + motion_blur_offset_ = + gfx::ScaleVector2d(movement, std::ceil(sigma * 3.f) / distance); + + // Determine angle of movement. + SkScalar angle = SkScalarATan2(SkFloatToScalar(movement.y()), + SkFloatToScalar(movement.x())); + SkScalar cos_angle = SkScalarCos(angle); + SkScalar sin_angle = SkScalarSin(angle); + + // Create transformation matrices for blur space. + motion_blur_matrix_.setSinCos(-sin_angle, cos_angle); + motion_blur_inverse_matrix_.setSinCos(sin_angle, cos_angle); + } else { + motion_blur_filter_.reset(); + responsive_velocity_ = gfx::Vector2dF(); + smooth_velocity_ = gfx::Vector2dF(); + time_source_->SetActive(false); + } + + // Damage is the union of old and new cursor rectangles. + gfx::Rect damage_rect = cursor_rect_; + cursor_rect_ = CalculateCursorRectOnPaintThread(); + damage_rect.Union(cursor_rect_); + + // Paint damaged area now that all parameters have been determined. + { + TRACE_EVENT1("ui", "CursorView::Paint", "damage_rect", + damage_rect.ToString()); + + ScopedPaint paint(gpu_memory_buffer_.get(), screen_to_buffer_transform_, + damage_rect); + cc::PaintCanvas* sk_canvas = paint.canvas().sk_canvas(); + sk_canvas->translate(SkIntToScalar(location_.x() - cursor_hotspot_.x()), + SkIntToScalar(location_.y() - cursor_hotspot_.y())); + + if (motion_blur_filter_) { + sk_canvas->translate(SkIntToScalar(motion_blur_offset_.x()), + SkIntToScalar(motion_blur_offset_.y())); + + sk_canvas->concat(motion_blur_inverse_matrix_); + SkRect blur_rect = SkRect::MakeWH(SkIntToScalar(cursor_size_.width()), + SkIntToScalar(cursor_size_.height())); + motion_blur_matrix_.mapRect(&blur_rect); + cc::PaintFlags flags; + flags.setImageFilter(motion_blur_filter_); + sk_canvas->saveLayer(&blur_rect, &flags); + sk_canvas->concat(motion_blur_matrix_); + paint.canvas().DrawImageInt(cursor_image_, 0, 0); + sk_canvas->restore(); + } else { + // Fast path for when motion blur is not present. + paint.canvas().DrawImageInt(cursor_image_, 0, 0); + } + } + + ui_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(update_surface_callback_, cursor_rect_, damage_rect, + /*auto_refresh=*/stationary_timer_->IsRunning())); +} + +//////////////////////////////////////////////////////////////////////////////// +// CursorView, private: + +void CursorView::StationaryOnPaintThread() { + DCHECK_CALLED_ON_VALID_SEQUENCE(paint_sequence_checker_); + + stationary_timer_->Stop(); + ui_task_runner_->PostTask( + FROM_HERE, base::BindOnce(update_surface_callback_, cursor_rect_, + /*damage_rect=*/gfx::Rect(), + /*auto_refresh=*/false)); +} + +gfx::Rect CursorView::CalculateCursorRectOnPaintThread() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(paint_sequence_checker_); + + if (cursor_size_.IsEmpty()) + return gfx::Rect(); + + SkRect cursor_rect = SkRect::MakeWH(SkIntToScalar(cursor_size_.width()), + SkIntToScalar(cursor_size_.height())); + + if (motion_blur_filter_) { + // Map curser rectangle to blur space. + motion_blur_matrix_.mapRect(&cursor_rect); + + // Expand rectangle using current blur filter. + cc::PaintFlags flags; + flags.setImageFilter(motion_blur_filter_); + DCHECK(flags.ToSkPaint().canComputeFastBounds()); + flags.ToSkPaint().computeFastBounds(cursor_rect, &cursor_rect); + + // Map rectangle back to cursor space. + motion_blur_inverse_matrix_.mapRect(&cursor_rect); + + // Add motion blur offset. + cursor_rect.offset(SkIntToScalar(motion_blur_offset_.x()), + SkIntToScalar(motion_blur_offset_.y())); + } + + cursor_rect.offset(SkIntToScalar(location_.x() - cursor_hotspot_.x()), + SkIntToScalar(location_.y() - cursor_hotspot_.y())); + + return gfx::ToEnclosingRect(gfx::SkRectToRectF(cursor_rect)); +} + +void CursorView::SetActiveOnPaintThread(bool active) { + DCHECK_CALLED_ON_VALID_SEQUENCE(paint_sequence_checker_); + + // Create time source if it doesn't exist. + if (!time_source_) { + time_source_ = + std::make_unique<viz::DelayBasedTimeSource>(paint_task_runner_.get()); + time_source_->SetClient(this); + } + time_source_->SetActive(active); +} + +void CursorView::SetTimebaseAndIntervalOnPaintThread(base::TimeTicks timebase, + base::TimeDelta interval) { + DCHECK_CALLED_ON_VALID_SEQUENCE(paint_sequence_checker_); + + DCHECK(time_source_); + time_source_->SetTimebaseAndInterval( + timebase + base::TimeDelta::FromMilliseconds(kVSyncOffsetMs), interval); +} + +void CursorView::DidPresentCompositorFrame(base::TimeTicks time, + base::TimeDelta refresh, + uint32_t flags) { + DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_); + + // Unretained is safe as |paint_task_runner_| uses SKIP_ON_SHUTDOWN. + paint_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&CursorView::SetTimebaseAndIntervalOnPaintThread, + base::Unretained(this), time, refresh)); +} + +} // namespace cursor
diff --git a/ash/components/cursor/cursor_view.h b/ash/components/cursor/cursor_view.h new file mode 100644 index 0000000..600b5c8 --- /dev/null +++ b/ash/components/cursor/cursor_view.h
@@ -0,0 +1,94 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMPONENTS_CURSOR_CURSOR_VIEW_H_ +#define ASH_COMPONENTS_CURSOR_CURSOR_VIEW_H_ + +#include "ash/components/fast_ink/fast_ink_view.h" +#include "base/sequence_checker.h" +#include "components/viz/common/frame_sinks/delay_based_time_source.h" +#include "ui/events/ozone/chromeos/cursor_controller.h" + +namespace base { +class SingleThreadTaskRunner; +} // namespace base + +namespace cursor { + +// CursorView class can be used to display a cursor image with minimal +// latency/jank and optional motion blur. +class CursorView : public fast_ink::FastInkView, + public viz::DelayBasedTimeSourceClient, + public ui::CursorController::CursorObserver { + public: + CursorView(aura::Window* container, + const gfx::Point& initial_location, + bool is_motion_blur_enabled); + ~CursorView() override; + + void SetCursorLocation(const gfx::Point& new_location); + void SetCursorImage(const gfx::ImageSkia& cursor_image, + const gfx::Size& cursor_size, + const gfx::Point& cursor_hotspot); + + // ui::CursorController::CursorObserver overrides: + void OnCursorLocationChanged(const gfx::PointF& location) override; + + // viz::DelayBasedTimeSourceClient overrides: + void OnTimerTick() override; + + private: + void StationaryOnPaintThread(); + gfx::Rect CalculateCursorRectOnPaintThread() const; + void SetActiveOnPaintThread(bool active); + void SetTimebaseAndIntervalOnPaintThread(base::TimeTicks timebase, + base::TimeDelta interval); + void DidPresentCompositorFrame(base::TimeTicks time, + base::TimeDelta refresh, + uint32_t flags); + + // Constants that can be used on any thread. + const bool is_motion_blur_enabled_; + const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; + const scoped_refptr<base::SingleThreadTaskRunner> paint_task_runner_; + gfx::Transform buffer_to_screen_transform_; + + base::Lock lock_; + // Shared state protected by |lock_|. + gfx::Point new_location_; + gfx::Size new_cursor_size_; + gfx::ImageSkia new_cursor_image_; + gfx::Point new_cursor_hotspot_; + + // Paint thread state. + gfx::Point location_; + gfx::ImageSkia cursor_image_; + gfx::Size cursor_size_; + gfx::Point cursor_hotspot_; + gfx::Rect cursor_rect_; + base::TimeTicks next_tick_time_; + gfx::Vector2dF velocity_; + gfx::Vector2dF responsive_velocity_; + gfx::Vector2dF smooth_velocity_; + sk_sp<cc::PaintFilter> motion_blur_filter_; + gfx::Vector2dF motion_blur_offset_; + SkMatrix motion_blur_matrix_; + SkMatrix motion_blur_inverse_matrix_; + std::unique_ptr<viz::DelayBasedTimeSource> time_source_; + std::unique_ptr<base::Timer> stationary_timer_; + base::RepeatingCallback<void(const gfx::Rect&, const gfx::Rect&, bool)> + update_surface_callback_; + SEQUENCE_CHECKER(paint_sequence_checker_); + + // UI thread state. + ui::Compositor* compositor_ = nullptr; + SEQUENCE_CHECKER(ui_sequence_checker_); + base::WeakPtrFactory<CursorView> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(CursorView); +}; + +} // namespace cursor + +#endif // ASH_COMPONENTS_CURSOR_CURSOR_VIEW_H_
diff --git a/ash/components/fast_ink/fast_ink_view.cc b/ash/components/fast_ink/fast_ink_view.cc index ced5301..e567adf 100644 --- a/ash/components/fast_ink/fast_ink_view.cc +++ b/ash/components/fast_ink/fast_ink_view.cc
@@ -220,7 +220,10 @@ void DidPresentCompositorFrame(uint32_t presentation_token, base::TimeTicks time, base::TimeDelta refresh, - uint32_t flags) override {} + uint32_t flags) override { + if (view_) + view_->DidPresentCompositorFrame(time, refresh, flags); + } void DidDiscardCompositorFrame(uint32_t presentation_token) override {} void DidLoseLayerTreeFrameSink() override { exported_resources_.clear(); @@ -265,7 +268,9 @@ DISALLOW_COPY_AND_ASSIGN(LayerTreeFrameSinkHolder); }; -FastInkView::FastInkView(aura::Window* container) : weak_ptr_factory_(this) { +FastInkView::FastInkView(aura::Window* container, + const PresentationCallback& presentation_callback) + : presentation_callback_(presentation_callback), weak_ptr_factory_(this) { widget_.reset(new views::Widget); views::Widget::InitParams params; params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; @@ -476,6 +481,13 @@ viz::BeginFrameAck::CreateManualAckWithDamage(); frame.metadata.device_scale_factor = device_scale_factor; + if (!presentation_callback_.is_null()) { + // If overflow happens, we increase it again. + if (!++presentation_token_) + ++presentation_token_; + frame.metadata.presentation_token = presentation_token_; + } + viz::TextureDrawQuad* texture_quad = render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>(); float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; @@ -514,6 +526,13 @@ } } +void FastInkView::DidPresentCompositorFrame(base::TimeTicks time, + base::TimeDelta refresh, + uint32_t flags) { + DCHECK(!presentation_callback_.is_null()); + presentation_callback_.Run(time, refresh, flags); +} + void FastInkView::ReclaimResource(std::unique_ptr<Resource> resource) { returned_resources_.push_back(std::move(resource)); }
diff --git a/ash/components/fast_ink/fast_ink_view.h b/ash/components/fast_ink/fast_ink_view.h index 75143935..5d7f0e5 100644 --- a/ash/components/fast_ink/fast_ink_view.h +++ b/ash/components/fast_ink/fast_ink_view.h
@@ -35,10 +35,16 @@ // when possible and trigger continious updates. class FastInkView : public views::View { public: + using PresentationCallback = + base::RepeatingCallback<void(base::TimeTicks presentation_time, + base::TimeDelta refresh, + uint32_t flags)>; + // Creates a FastInkView filling the bounds of |root_window|. // If |root_window| is resized (e.g. due to a screen size change), // a new instance of FastInkView should be created. - explicit FastInkView(aura::Window* container); + FastInkView(aura::Window* container, + const PresentationCallback& presentation_callback); ~FastInkView() override; protected: @@ -67,6 +73,7 @@ bool auto_refresh); // Constants initialized in constructor. + const PresentationCallback presentation_callback_; gfx::Transform screen_to_buffer_transform_; gfx::Size buffer_size_; std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_; @@ -79,6 +86,9 @@ void SubmitPendingCompositorFrame(); void ReclaimResource(std::unique_ptr<Resource> resource); void DidReceiveCompositorFrameAck(); + void DidPresentCompositorFrame(base::TimeTicks time, + base::TimeDelta refresh, + uint32_t flags); std::unique_ptr<views::Widget> widget_; gfx::Rect content_rect_; @@ -87,6 +97,7 @@ bool pending_compositor_frame_ = false; bool pending_compositor_frame_ack_ = false; int next_resource_id_ = 1; + uint32_t presentation_token_ = 0; std::vector<std::unique_ptr<Resource>> returned_resources_; std::unique_ptr<LayerTreeFrameSinkHolder> frame_sink_holder_; base::WeakPtrFactory<FastInkView> weak_ptr_factory_;
diff --git a/ash/components/shortcut_viewer_strings.grdp b/ash/components/shortcut_viewer_strings.grdp index 36cb6417..4a8b59f6 100644 --- a/ash/components/shortcut_viewer_strings.grdp +++ b/ash/components/shortcut_viewer_strings.grdp
@@ -271,7 +271,7 @@ Highlight the bookmarks bar (if shown) </message> <message name="IDS_KSV_DESCRIPTION_IDC_FOCUS_SEARCH" desc="Description of the command in keyboard shortcut viewer."> - Focus address bar on search + Place focus in search address bar </message> <message name="IDS_KSV_SHORTCUT_IDC_FOCUS_SEARCH" desc="Description of the command in keyboard shortcut viewer."> <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator">$2<ex>+</ex></ph><ph name="k">$3<ex>v</ex></ph> or <ph name="e">$4<ex>v</ex></ph> @@ -295,7 +295,7 @@ Paste content from the clipboard </message> <message name="IDS_KSV_DESCRIPTION_SELECT_NUMBERED_TAB" desc="Description of the command in keyboard shortcut viewer."> - Go to numbered tab + Go to tabs 1 through 8 </message> <message name="IDS_KSV_SHORTCUT_SELECT_NUMBERED_TAB" desc="Human readable version of the keyboard shortcut."> <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator">$2<ex>+</ex></ph> 1 through 8 @@ -454,19 +454,19 @@ <ph name="shift1">$1<ex>Shift</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="alt">$3<ex>Alt</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="l">$5<ex>v</ex></ph>, then <ph name="shift2">$6<ex>Shift</ex></ph><ph name="separator3">$7<ex>+</ex></ph><ph name="tab">$8<ex>v</ex></ph> or <ph name="left">$9<ex>v</ex></ph> </message> <message name="IDS_KSV_DESCRIPTION_OPEN_HIGHLIGHTED_ITEM_ON_SHELF" desc="Description of the command in keyboard shortcut viewer."> - Open the highlighted button on your shelf + Open the highlighted item on your shelf </message> <message name="IDS_KSV_SHORTCUT_OPEN_HIGHLIGHTED_ITEM_ON_SHELF" desc="Human readable version of the keyboard shortcut."> <ph name="shift">$1<ex>Shift</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="alt">$3<ex>Alt</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="l">$5<ex>v</ex></ph>, then <ph name="space">$6<ex>v</ex></ph> or <ph name="enter">$7<ex>v</ex></ph> </message> <message name="IDS_KSV_DESCRIPTION_REMOVE_HIGHLIGHT_ON_SHELF" desc="Description of the command in keyboard shortcut viewer."> - Remove the highlight from a button on your shelf + Remove the highlight from an item on your shelf </message> <message name="IDS_KSV_SHORTCUT_REMOVE_HIGHLIGHT_ON_SHELF" desc="Human readable version of the keyboard shortcut."> <ph name="shift">$1<ex>Shift</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="alt">$3<ex>Alt</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="l">$5<ex>v</ex></ph>, then <ph name="esc">$6<ex>v</ex></ph> </message> <message name="IDS_KSV_DESCRIPTION_SWITCH_FOCUS" desc="Description of the command in keyboard shortcut viewer."> - Switch focus between: Status area (where your account picture appears) Launcher Address bar Bookmarks bar (if visible) The webpage that's open Downloads bar (if visible) + Switch focus between: Status area (where your account picture appears), Launcher, Address bar, Bookmarks bar (if visible), The webpage that's open, and Downloads bar (if visible). </message> <message name="IDS_KSV_SHORTCUT_SWITCH_FOCUS" desc="Human readable version of the keyboard shortcut."> <ph name="ctrl1">$1<ex>Ctrl</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="left">$3<ex>v</ex></ph> or <ph name="ctrl2">$4<ex>Ctrl</ex></ph><ph name="separator2">$5<ex>+</ex></ph><ph name="right">$6<ex>v</ex></ph>
diff --git a/ash/display/DEPS b/ash/display/DEPS index d68ef13f..c67ef1e 100644 --- a/ash/display/DEPS +++ b/ash/display/DEPS
@@ -10,4 +10,7 @@ "screen_orientation_controller_(chromeos|test_api)\.h": [ "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h", ], + "cursor_window_controller.cc": [ + "+ash/components/cursor", + ], }
diff --git a/ash/display/cursor_window_controller.cc b/ash/display/cursor_window_controller.cc index 22dfc73..754fa0c 100644 --- a/ash/display/cursor_window_controller.cc +++ b/ash/display/cursor_window_controller.cc
@@ -5,14 +5,17 @@ #include "ash/display/cursor_window_controller.h" #include "ash/ash_constants.h" +#include "ash/components/cursor/cursor_view.h" #include "ash/display/mirror_window_controller.h" #include "ash/display/window_tree_host_manager.h" #include "ash/magnifier/magnification_controller.h" #include "ash/public/cpp/ash_pref_names.h" +#include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller.h" #include "ash/shell.h" +#include "base/command_line.h" #include "components/prefs/pref_service.h" #include "services/ui/public/interfaces/window_tree_constants.mojom.h" #include "ui/aura/env.h" @@ -30,6 +33,7 @@ #include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_operations.h" +#include "ui/views/widget/widget.h" namespace ash { namespace { @@ -92,7 +96,10 @@ }; CursorWindowController::CursorWindowController() - : delegate_(new CursorWindowDelegate()) {} + : delegate_(new CursorWindowDelegate()), + is_cursor_motion_blur_enabled_( + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshEnableCursorMotionBlur)) {} CursorWindowController::~CursorWindowController() { SetContainer(NULL); @@ -115,6 +122,9 @@ } bool CursorWindowController::ShouldEnableCursorCompositing() { + if (is_cursor_motion_blur_enabled_) + return true; + // During startup, we may not have a preference service yet. We need to check // display manager state first so that we don't accidentally ignore it while // early outing when there isn't a PrefService yet. @@ -192,20 +202,20 @@ SetContainer(RootWindowController::ForWindow(root_window) ->GetContainer(kShellWindowId_MouseCursorContainer)); - SetBoundsInScreen(display.bounds()); + SetBoundsInScreenAndRotation(display.bounds(), display.rotation()); // Updates the hot point based on the current display. UpdateCursorImage(); } void CursorWindowController::UpdateLocation() { - if (!cursor_window_) - return; gfx::Point point = aura::Env::GetInstance()->last_mouse_location(); if (!is_cursor_compositing_enabled_) { Shell::GetPrimaryRootWindow()->GetHost()->ConvertDIPToPixels(&point); } else { point.Offset(-bounds_in_screen_.x(), -bounds_in_screen_.y()); } + if (!cursor_window_) + return; point.Offset(-hot_point_.x(), -hot_point_.y()); gfx::Rect bounds = cursor_window_->bounds(); bounds.set_origin(point); @@ -236,27 +246,41 @@ container_ = container; if (!container) { cursor_window_.reset(); + cursor_view_.reset(); return; } - // Reusing the window does not work when the display is disconnected. - // Just creates a new one instead. crbug.com/384218. - cursor_window_.reset(new aura::Window(delegate_.get())); - cursor_window_->SetTransparent(true); - cursor_window_->Init(ui::LAYER_TEXTURED); - cursor_window_->SetEventTargetingPolicy( - ui::mojom::EventTargetingPolicy::NONE); - cursor_window_->set_owned_by_parent(false); - // Call UpdateCursorImage() to figure out |cursor_window_|'s desired size. - UpdateCursorImage(); + bounds_in_screen_ = display_.bounds(); + rotation_ = display_.rotation(); - container->AddChild(cursor_window_.get()); + if (is_cursor_motion_blur_enabled_) { + UpdateCursorView(); + } else { + // Reusing the window does not work when the display is disconnected. + // Just creates a new one instead. crbug.com/384218. + cursor_window_.reset(new aura::Window(delegate_.get())); + cursor_window_->SetTransparent(true); + cursor_window_->Init(ui::LAYER_TEXTURED); + cursor_window_->SetEventTargetingPolicy( + ui::mojom::EventTargetingPolicy::NONE); + cursor_window_->set_owned_by_parent(false); + // Call UpdateCursorImage() to figure out |cursor_window_|'s desired size. + UpdateCursorImage(); + container->AddChild(cursor_window_.get()); + } UpdateCursorVisibility(); - SetBoundsInScreen(container->bounds()); + UpdateLocation(); } -void CursorWindowController::SetBoundsInScreen(const gfx::Rect& bounds) { +void CursorWindowController::SetBoundsInScreenAndRotation( + const gfx::Rect& bounds, + display::Display::Rotation rotation) { + if (bounds == bounds_in_screen_ && rotation == rotation_) + return; bounds_in_screen_ = bounds; + rotation_ = rotation; + if (cursor_view_) + UpdateCursorView(); UpdateLocation(); } @@ -337,22 +361,38 @@ hot_point_ = gfx::ConvertPointToDIP(cursor_scale, hot_point_); } + if (cursor_view_) { + cursor_view_->SetCursorImage(delegate_->cursor_image(), delegate_->size(), + hot_point_); + } if (cursor_window_) { cursor_window_->SetBounds(gfx::Rect(delegate_->size())); cursor_window_->SchedulePaintInRect( gfx::Rect(cursor_window_->bounds().size())); - UpdateLocation(); } + UpdateLocation(); } void CursorWindowController::UpdateCursorVisibility() { - if (!cursor_window_) - return; bool visible = (visible_ && cursor_type_ != ui::CursorType::kNone); - if (visible) - cursor_window_->Show(); - else - cursor_window_->Hide(); + if (visible) { + if (cursor_view_) + cursor_view_->GetWidget()->Show(); + if (cursor_window_) + cursor_window_->Show(); + } else { + if (cursor_view_) + cursor_view_->GetWidget()->Hide(); + if (cursor_window_) + cursor_window_->Hide(); + } +} + +void CursorWindowController::UpdateCursorView() { + cursor_view_.reset(new cursor::CursorView( + container_, aura::Env::GetInstance()->last_mouse_location(), + is_cursor_motion_blur_enabled_)); + UpdateCursorImage(); } const gfx::ImageSkia& CursorWindowController::GetCursorImageForTest() const {
diff --git a/ash/display/cursor_window_controller.h b/ash/display/cursor_window_controller.h index 9614cb7..829e072 100644 --- a/ash/display/cursor_window_controller.h +++ b/ash/display/cursor_window_controller.h
@@ -14,6 +14,10 @@ #include "ui/base/cursor/cursor.h" #include "ui/display/display.h" +namespace cursor { +class CursorView; +} + namespace ash { class CursorWindowControllerTest; @@ -64,8 +68,9 @@ // Closes the cursor window if |container| is NULL. void SetContainer(aura::Window* container); - // Sets the bounds of the container in screen coordinates. - void SetBoundsInScreen(const gfx::Rect& bounds); + // Sets the bounds of the container in screen coordinates and rotation. + void SetBoundsInScreenAndRotation(const gfx::Rect& bounds, + display::Display::Rotation rotation); // Updates cursor image based on current cursor state. void UpdateCursorImage(); @@ -73,6 +78,9 @@ // Hides/shows cursor window based on current cursor state. void UpdateCursorVisibility(); + // Updates cursor view based on current cursor state. + void UpdateCursorView(); + const gfx::ImageSkia& GetCursorImageForTest() const; aura::Window* container_ = nullptr; @@ -83,6 +91,9 @@ // The bounds of the container in screen coordinates. gfx::Rect bounds_in_screen_; + // The rotation of the container. + display::Display::Rotation rotation_ = display::Display::ROTATE_0; + // The native_type of the cursor, see definitions in cursor.h ui::CursorType cursor_type_ = ui::CursorType::kNone; @@ -100,6 +111,9 @@ std::unique_ptr<aura::Window> cursor_window_; std::unique_ptr<CursorWindowDelegate> delegate_; + std::unique_ptr<cursor::CursorView> cursor_view_; + + const bool is_cursor_motion_blur_enabled_; DISALLOW_COPY_AND_ASSIGN(CursorWindowController); };
diff --git a/ash/display/persistent_window_controller.cc b/ash/display/persistent_window_controller.cc index 3a6ef8a..f7cb7bb 100644 --- a/ash/display/persistent_window_controller.cc +++ b/ash/display/persistent_window_controller.cc
@@ -5,7 +5,7 @@ #include "ash/display/persistent_window_controller.h" #include "ash/display/persistent_window_info.h" -#include "ash/public/cpp/ash_switches.h" +#include "ash/public/cpp/ash_features.h" #include "ash/session/session_controller.h" #include "ash/shell.h" #include "ash/wm/mru_window_tracker.h" @@ -30,10 +30,8 @@ // Returns true when window cycle list can be processed to perform save/restore // operations on observing display changes. bool ShouldProcessWindowList() { - if (!base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshEnablePersistentWindowBounds)) { + if (!features::IsPersistentWindowBoundsEnabled()) return false; - } // Window cycle list exists in active user session only. if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted()) @@ -45,7 +43,54 @@ return true; } -void MaybeRestorePersistentWindowBounds() { +} // namespace + +constexpr char PersistentWindowController::kNumOfWindowsRestoredHistogramName[]; + +PersistentWindowController::PersistentWindowController() { + display::Screen::GetScreen()->AddObserver(this); + Shell::Get()->session_controller()->AddObserver(this); + Shell::Get()->window_tree_host_manager()->AddObserver(this); +} + +PersistentWindowController::~PersistentWindowController() { + Shell::Get()->window_tree_host_manager()->RemoveObserver(this); + Shell::Get()->session_controller()->RemoveObserver(this); + display::Screen::GetScreen()->RemoveObserver(this); +} + +void PersistentWindowController::OnWillProcessDisplayChanges() { + if (!ShouldProcessWindowList()) + return; + + for (auto* window : GetWindowList()) { + wm::WindowState* window_state = wm::GetWindowState(window); + // This implies that we keep the first persistent info until they're valid + // to restore, or until they're cleared by user-invoked bounds change. + if (window_state->persistent_window_info()) + continue; + window_state->SetPersistentWindowInfo(PersistentWindowInfo(window)); + } +} + +void PersistentWindowController::OnDisplayAdded( + const display::Display& new_display) { + restore_callback_ = base::BindOnce( + &PersistentWindowController::MaybeRestorePersistentWindowBounds, + base::Unretained(this)); +} + +void PersistentWindowController::OnSessionStateChanged( + session_manager::SessionState state) { + MaybeRestorePersistentWindowBounds(); +} + +void PersistentWindowController::OnDisplayConfigurationChanged() { + if (restore_callback_) + std::move(restore_callback_).Run(); +} + +void PersistentWindowController::MaybeRestorePersistentWindowBounds() { if (!ShouldProcessWindowList()) return; @@ -93,43 +138,5 @@ } } -} // namespace - -constexpr char PersistentWindowController::kNumOfWindowsRestoredHistogramName[]; - -PersistentWindowController::PersistentWindowController() { - display::Screen::GetScreen()->AddObserver(this); - Shell::Get()->session_controller()->AddObserver(this); - Shell::Get()->window_tree_host_manager()->AddObserver(this); -} - -PersistentWindowController::~PersistentWindowController() { - Shell::Get()->window_tree_host_manager()->RemoveObserver(this); - Shell::Get()->session_controller()->RemoveObserver(this); - display::Screen::GetScreen()->RemoveObserver(this); -} - -void PersistentWindowController::OnWillProcessDisplayChanges() { - if (!ShouldProcessWindowList()) - return; - - for (auto* window : GetWindowList()) { - wm::WindowState* window_state = wm::GetWindowState(window); - // This implies that we keep the first persistent info until they're valid - // to restore, or until they're cleared by user-invoked bounds change. - if (window_state->persistent_window_info()) - continue; - window_state->SetPersistentWindowInfo(PersistentWindowInfo(window)); - } -} - -void PersistentWindowController::OnSessionStateChanged( - session_manager::SessionState state) { - MaybeRestorePersistentWindowBounds(); -} - -void PersistentWindowController::OnDisplayConfigurationChanged() { - MaybeRestorePersistentWindowBounds(); -} } // namespace ash
diff --git a/ash/display/persistent_window_controller.h b/ash/display/persistent_window_controller.h index fa6edcdab..044e842d 100644 --- a/ash/display/persistent_window_controller.h +++ b/ash/display/persistent_window_controller.h
@@ -8,6 +8,7 @@ #include "ash/ash_export.h" #include "ash/display/window_tree_host_manager.h" #include "ash/session/session_observer.h" +#include "base/callback.h" #include "base/macros.h" #include "ui/display/display_observer.h" @@ -30,6 +31,7 @@ private: // display::DisplayObserver: void OnWillProcessDisplayChanges() override; + void OnDisplayAdded(const display::Display& new_display) override; // SessionObserver: void OnSessionStateChanged(session_manager::SessionState state) override; @@ -37,6 +39,12 @@ // WindowTreeHostManager::Observer: void OnDisplayConfigurationChanged() override; + // Called when restoring persistent window placement is wanted. + void MaybeRestorePersistentWindowBounds(); + + // Callback binded on display added and run on display configuration changed. + base::OnceCallback<void()> restore_callback_; + DISALLOW_COPY_AND_ASSIGN(PersistentWindowController); };
diff --git a/ash/display/persistent_window_controller_unittest.cc b/ash/display/persistent_window_controller_unittest.cc index 51e8dd4..5a014093 100644 --- a/ash/display/persistent_window_controller_unittest.cc +++ b/ash/display/persistent_window_controller_unittest.cc
@@ -7,15 +7,14 @@ #include "ash/display/display_move_window_util.h" #include "ash/display/window_tree_host_manager.h" #include "ash/public/cpp/ash_features.h" -#include "ash/public/cpp/ash_switches.h" #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" -#include "base/command_line.h" #include "base/test/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "ui/display/test/display_manager_test_api.h" using session_manager::SessionState; @@ -28,10 +27,11 @@ // AshTestBase: void SetUp() override { - scoped_feature_list_.InitAndEnableFeature( - features::kDisplayMoveWindowAccels); - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kAshEnablePersistentWindowBounds); + // Explicitly enable persistent window bounds and displays move window + // accels features for the tests. + scoped_feature_list_.InitWithFeatures( + {features::kPersistentWindowBounds, features::kDisplayMoveWindowAccels}, + {}); AshTestBase::SetUp(); } @@ -398,4 +398,37 @@ PersistentWindowController::kNumOfWindowsRestoredHistogramName, 1); } +// Tests that swapping primary display shall not do persistent window restore. +TEST_F(PersistentWindowControllerTest, SwapPrimaryDisplay) { + const int64_t internal_display_id = + display::test::DisplayManagerTestApi(display_manager()) + .SetFirstDisplayAsInternalDisplay(); + const display::ManagedDisplayInfo native_display_info = + display::CreateDisplayInfo(internal_display_id, + gfx::Rect(0, 0, 500, 500)); + const display::ManagedDisplayInfo secondary_display_info = + display::CreateDisplayInfo(10, gfx::Rect(1, 1, 400, 400)); + + std::vector<display::ManagedDisplayInfo> display_info_list; + display_info_list.push_back(native_display_info); + display_info_list.push_back(secondary_display_info); + display_manager()->OnNativeDisplaysChanged(display_info_list); + + aura::Window* w1 = + CreateTestWindowInShellWithBounds(gfx::Rect(200, 0, 100, 200)); + aura::Window* w2 = + CreateTestWindowInShellWithBounds(gfx::Rect(501, 0, 200, 100)); + EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen()); + EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen()); + + // Swaps primary display and check window bounds. + SwapPrimaryDisplay(); + ASSERT_EQ(gfx::Rect(-500, 0, 500, 500), + display_manager()->GetDisplayForId(internal_display_id).bounds()); + ASSERT_EQ(gfx::Rect(0, 0, 400, 400), + display_manager()->GetDisplayForId(10).bounds()); + EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen()); + EXPECT_EQ(gfx::Rect(-499, 0, 200, 100), w2->GetBoundsInScreen()); +} + } // namespace ash
diff --git a/ash/highlighter/highlighter_view.cc b/ash/highlighter/highlighter_view.cc index 7eb937f..4707a0d 100644 --- a/ash/highlighter/highlighter_view.cc +++ b/ash/highlighter/highlighter_view.cc
@@ -71,7 +71,7 @@ HighlighterView::HighlighterView(base::TimeDelta presentation_delay, aura::Window* container) - : FastInkView(container), + : FastInkView(container, PresentationCallback()), points_(base::TimeDelta()), predicted_points_(base::TimeDelta()), presentation_delay_(presentation_delay),
diff --git a/ash/laser/laser_pointer_view.cc b/ash/laser/laser_pointer_view.cc index 49ada7ae..12aa9a8 100644 --- a/ash/laser/laser_pointer_view.cc +++ b/ash/laser/laser_pointer_view.cc
@@ -160,7 +160,7 @@ base::TimeDelta presentation_delay, base::TimeDelta stationary_point_delay, aura::Window* container) - : FastInkView(container), + : FastInkView(container, PresentationCallback()), laser_points_(life_duration), predicted_laser_points_(life_duration), presentation_delay_(presentation_delay),
diff --git a/ash/login/ui/fake_login_detachable_base_model.cc b/ash/login/ui/fake_login_detachable_base_model.cc new file mode 100644 index 0000000..6f9d187 --- /dev/null +++ b/ash/login/ui/fake_login_detachable_base_model.cc
@@ -0,0 +1,65 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/login/ui/fake_login_detachable_base_model.h" + +#include "ash/login/ui/login_data_dispatcher.h" +#include "ash/public/interfaces/user_info.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { + +FakeLoginDetachableBaseModel::FakeLoginDetachableBaseModel( + LoginDataDispatcher* data_dispatcher) + : data_dispatcher_(data_dispatcher) {} + +FakeLoginDetachableBaseModel::~FakeLoginDetachableBaseModel() = default; + +void FakeLoginDetachableBaseModel::InitLastUsedBases( + const std::map<AccountId, std::string>& last_used_bases) { + ASSERT_TRUE(last_used_bases_.empty()); + last_used_bases_ = last_used_bases; +} + +std::string FakeLoginDetachableBaseModel::GetLastUsedBase( + const AccountId& account_id) { + auto it = last_used_bases_.find(account_id); + if (it == last_used_bases_.end()) + return ""; + return it->second; +} + +void FakeLoginDetachableBaseModel::SetPairingStatus( + DetachableBasePairingStatus pairing_status, + const std::string& base_id) { + ASSERT_EQ(pairing_status == DetachableBasePairingStatus::kAuthenticated, + !base_id.empty()); + + current_authenticated_base_ = base_id; + pairing_status_ = pairing_status; + data_dispatcher_->SetDetachableBasePairingStatus(pairing_status); +} + +DetachableBasePairingStatus FakeLoginDetachableBaseModel::GetPairingStatus() { + return pairing_status_; +} + +bool FakeLoginDetachableBaseModel::PairedBaseMatchesLastUsedByUser( + const mojom::UserInfo& user_info) { + EXPECT_FALSE(current_authenticated_base_.empty()); + + std::string last_used = GetLastUsedBase(user_info.account_id); + return last_used.empty() || last_used == current_authenticated_base_; +} + +bool FakeLoginDetachableBaseModel::SetPairedBaseAsLastUsedByUser( + const mojom::UserInfo& user_info) { + if (current_authenticated_base_.empty()) + return false; + + last_used_bases_[user_info.account_id] = current_authenticated_base_; + return true; +} + +} // namespace ash
diff --git a/ash/login/ui/fake_login_detachable_base_model.h b/ash/login/ui/fake_login_detachable_base_model.h new file mode 100644 index 0000000..eb4fe845 --- /dev/null +++ b/ash/login/ui/fake_login_detachable_base_model.h
@@ -0,0 +1,70 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_LOGIN_UI_FAKE_LOGIN_DETACHABLE_BASE_MODEL_H_ +#define ASH_LOGIN_UI_FAKE_LOGIN_DETACHABLE_BASE_MODEL_H_ + +#include <map> +#include <string> + +#include "ash/detachable_base/detachable_base_pairing_status.h" +#include "ash/login/ui/login_detachable_base_model.h" +#include "base/macros.h" +#include "components/signin/core/account_id/account_id.h" + +namespace ash { + +class LoginDataDispatcher; + +// Fake LoginDetachableBaseModel implementation. To be used in tests to hide +// dependency on DetachableBaseHandler. +class FakeLoginDetachableBaseModel : public LoginDetachableBaseModel { + public: + // |data_dispatcher| - the dispatcher to which the pairing status changes + // should be forwarded. + explicit FakeLoginDetachableBaseModel(LoginDataDispatcher* data_dispatcher); + ~FakeLoginDetachableBaseModel() override; + + // Sets the initial mapping for user -> last used detachable base. + // It will assert if called while |last_used_bases_| is not empty. + void InitLastUsedBases( + const std::map<AccountId, std::string>& last_used_bases); + + // Gets the last recorded base for the user with the provided account id. + // Returns empty string if the user does not have a recorded detcachable base + // usage. + std::string GetLastUsedBase(const AccountId& account_id); + + // Changes current detachable base pairing status. + // |pairing_status| - the new pairing status. + // |base_id| - the authenticated base ID. It is expect to be set if and only + // if pairing_status is kAuthenticated. + void SetPairingStatus(DetachableBasePairingStatus pairing_status, + const std::string& base_id); + + // LoginDetachableBaseModel: + DetachableBasePairingStatus GetPairingStatus() override; + bool PairedBaseMatchesLastUsedByUser( + const mojom::UserInfo& user_info) override; + bool SetPairedBaseAsLastUsedByUser(const mojom::UserInfo& user_info) override; + + private: + LoginDataDispatcher* data_dispatcher_; + + // Current pairing status. + DetachableBasePairingStatus pairing_status_ = + DetachableBasePairingStatus::kNone; + + // The ID if the currently authenticated detachable base. + std::string current_authenticated_base_; + + // Maps user account Id to the ID of the last used detachable base. + std::map<AccountId, std::string> last_used_bases_; + + DISALLOW_COPY_AND_ASSIGN(FakeLoginDetachableBaseModel); +}; + +} // namespace ash + +#endif // ASH_LOGIN_UI_FAKE_LOGIN_DETACHABLE_BASE_MODEL_H_
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc index 2f939080..90b346d 100644 --- a/ash/login/ui/lock_contents_view.cc +++ b/ash/login/ui/lock_contents_view.cc
@@ -4,8 +4,11 @@ #include "ash/login/ui/lock_contents_view.h" +#include <algorithm> #include <memory> +#include <utility> +#include "ash/detachable_base/detachable_base_pairing_status.h" #include "ash/focus_cycler.h" #include "ash/ime/ime_controller.h" #include "ash/keyboard/keyboard_observer_register.h" @@ -14,6 +17,7 @@ #include "ash/login/ui/lock_screen.h" #include "ash/login/ui/login_auth_user_view.h" #include "ash/login/ui/login_bubble.h" +#include "ash/login/ui/login_detachable_base_model.h" #include "ash/login/ui/login_user_view.h" #include "ash/login/ui/non_accessible_view.h" #include "ash/login/ui/note_action_launch_button.h" @@ -46,6 +50,7 @@ #include "ui/views/focus/focus_search.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" +#include "ui/views/style/typography.h" #include "ui/views/view.h" namespace ash { @@ -196,6 +201,14 @@ return view_->tooltip_bubble_.get(); } +LoginBubble* LockContentsView::TestApi::auth_error_bubble() const { + return view_->auth_error_bubble_.get(); +} + +LoginBubble* LockContentsView::TestApi::detachable_base_error_bubble() const { + return view_->detachable_base_error_bubble_.get(); +} + views::View* LockContentsView::TestApi::dev_channel_info() const { return view_->dev_channel_info_; } @@ -209,9 +222,11 @@ LockContentsView::LockContentsView( mojom::TrayActionState initial_note_action_state, - LoginDataDispatcher* data_dispatcher) + LoginDataDispatcher* data_dispatcher, + std::unique_ptr<LoginDetachableBaseModel> detachable_base_model) : NonAccessibleView(kLockContentsViewName), data_dispatcher_(data_dispatcher), + detachable_base_model_(std::move(detachable_base_model)), display_observer_(this), session_observer_(this), keyboard_observer_(this) { @@ -219,7 +234,8 @@ display_observer_.Add(display::Screen::GetScreen()); Shell::Get()->login_screen_controller()->AddLockScreenAppsFocusObserver(this); Shell::Get()->system_tray_notifier()->AddSystemTrayFocusObserver(this); - error_bubble_ = std::make_unique<LoginBubble>(); + auth_error_bubble_ = std::make_unique<LoginBubble>(); + detachable_base_error_bubble_ = std::make_unique<LoginBubble>(); tooltip_bubble_ = std::make_unique<LoginBubble>(); // We reuse the focusable state on this view as a signal that focus should @@ -496,6 +512,43 @@ NOTIMPLEMENTED(); } +void LockContentsView::OnDetachableBasePairingStatusChanged( + DetachableBasePairingStatus pairing_status) { + const mojom::UserInfoPtr& user_info = + CurrentAuthUserView()->current_user()->basic_user_info; + // If the base is not paired, or the paired base matches the last used by the + // current user, the detachable base error bubble should be hidden. Otherwise, + // the bubble should be shown. + if (pairing_status == DetachableBasePairingStatus::kNone || + (pairing_status == DetachableBasePairingStatus::kAuthenticated && + detachable_base_model_->PairedBaseMatchesLastUsedByUser(*user_info))) { + detachable_base_error_bubble_->Close(); + return; + } + + auth_error_bubble_->Close(); + + base::string16 error_text = + l10n_util::GetStringUTF16(IDS_ASH_LOGIN_ERROR_DETACHABLE_BASE_CHANGED); + + views::Label* label = + new views::Label(error_text, views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT, + views::style::STYLE_PRIMARY); + label->SetMultiLine(true); + label->SetAutoColorReadabilityEnabled(false); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + label->SetEnabledColor(SK_ColorWHITE); + + detachable_base_error_bubble_->ShowErrorBubble( + label, CurrentAuthUserView()->password_view() /*anchor_view*/, + LoginBubble::kFlagPersistent); + + // Remove the focus from the password field, to make user less likely to enter + // the password without seeing the warning about detachable base change. + if (GetWidget()->IsActive()) + GetWidget()->GetFocusManager()->ClearFocus(); +} + void LockContentsView::OnFocusLeavingLockScreenApps(bool reverse) { if (!reverse || lock_screen_apps_active_) FocusNextWidget(reverse); @@ -696,9 +749,20 @@ void LockContentsView::OnAuthenticate(bool auth_success) { if (auth_success) { - error_bubble_->Close(); + auth_error_bubble_->Close(); + detachable_base_error_bubble_->Close(); + + // Now that the user has been authenticated, update the user's last used + // detachable base (if one is attached). This will prevent further + // detachable base change notifications from appearing for this base (until + // the user uses another detachable base). + if (detachable_base_model_->GetPairingStatus() == + DetachableBasePairingStatus::kAuthenticated) { + detachable_base_model_->SetPairedBaseAsLastUsedByUser( + *CurrentAuthUserView()->current_user()->basic_user_info); + } } else { - ShowErrorMessage(); + ShowAuthErrorMessage(); ++unlock_attempt_; } } @@ -778,6 +842,11 @@ // Reset unlock attempt when the auth user changes. unlock_attempt_ = 0; } + + // The new auth user might have different last used detachable base - make + // sure the detachable base pairing error is updated if needed. + OnDetachableBasePairingStatusChanged( + detachable_base_model_->GetPairingStatus()); } void LockContentsView::UpdateEasyUnlockIconForUser(const AccountId& user) { @@ -818,7 +887,7 @@ return primary_auth_; } -void LockContentsView::ShowErrorMessage() { +void LockContentsView::ShowAuthErrorMessage() { base::string16 error_text = l10n_util::GetStringUTF16( unlock_attempt_ ? IDS_ASH_LOGIN_ERROR_AUTHENTICATING_2ND_TIME : IDS_ASH_LOGIN_ERROR_AUTHENTICATING); @@ -848,8 +917,11 @@ views::StyledLabel* label = new views::StyledLabel(error_text, this); MakeSectionBold(label, error_text, bold_start, bold_length); - error_bubble_->ShowErrorBubble( - label, CurrentAuthUserView()->password_view() /*anchor_view*/); + label->set_auto_color_readability_enabled(false); + + auth_error_bubble_->ShowErrorBubble( + label, CurrentAuthUserView()->password_view() /*anchor_view*/, + LoginBubble::kFlagsNone); } void LockContentsView::OnEasyUnlockIconHovered() {
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h index 7f9ccb70..4c0ee10 100644 --- a/ash/login/ui/lock_contents_view.h +++ b/ash/login/ui/lock_contents_view.h
@@ -39,6 +39,7 @@ class LoginAuthUserView; class LoginBubble; +class LoginDetachableBaseModel; class NoteActionLaunchButton; class ScrollableUsersListView; @@ -71,14 +72,18 @@ ScrollableUsersListView* users_list() const; views::View* note_action() const; LoginBubble* tooltip_bubble() const; + LoginBubble* auth_error_bubble() const; + LoginBubble* detachable_base_error_bubble() const; views::View* dev_channel_info() const; private: LockContentsView* const view_; }; - LockContentsView(mojom::TrayActionState initial_note_action_state, - LoginDataDispatcher* data_dispatcher); + LockContentsView( + mojom::TrayActionState initial_note_action_state, + LoginDataDispatcher* data_dispatcher, + std::unique_ptr<LoginDetachableBaseModel> detachable_base_model); ~LockContentsView() override; // views::View: @@ -111,6 +116,8 @@ const base::ListValue& locales, const std::string& default_locale, bool show_advanced_view) override; + void OnDetachableBasePairingStatusChanged( + DetachableBasePairingStatus pairing_status) override; // SystemTrayFocusObserver: void OnFocusLeavingSystemTray(bool reverse) override; @@ -216,7 +223,7 @@ LoginAuthUserView* CurrentAuthUserView(); // Opens an error bubble to indicate authentication failure. - void ShowErrorMessage(); + void ShowAuthErrorMessage(); // Called when the easy unlock icon is hovered. void OnEasyUnlockIconHovered(); @@ -247,6 +254,7 @@ std::vector<UserState> users_; LoginDataDispatcher* const data_dispatcher_; // Unowned. + std::unique_ptr<LoginDetachableBaseModel> detachable_base_model_; LoginAuthUserView* primary_auth_ = nullptr; LoginAuthUserView* opt_secondary_auth_ = nullptr; @@ -279,7 +287,12 @@ keyboard::KeyboardControllerObserver> keyboard_observer_; - std::unique_ptr<LoginBubble> error_bubble_; + // Bubbles for displaying authentication error. + std::unique_ptr<LoginBubble> auth_error_bubble_; + + // Bubble for displaying error when the user's detachable base changes. + std::unique_ptr<LoginBubble> detachable_base_error_bubble_; + std::unique_ptr<LoginBubble> tooltip_bubble_; int unlock_attempt_ = 0;
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc index a01c086..9240825 100644 --- a/ash/login/ui/lock_contents_view_unittest.cc +++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -3,8 +3,13 @@ // found in the LICENSE file. #include <memory> +#include <string> #include <unordered_set> +#include <utility> +#include "ash/detachable_base/detachable_base_pairing_status.h" +#include "ash/login/mock_login_screen_client.h" +#include "ash/login/ui/fake_login_detachable_base_model.h" #include "ash/login/ui/lock_contents_view.h" #include "ash/login/ui/lock_screen.h" #include "ash/login/ui/login_auth_user_view.h" @@ -16,6 +21,7 @@ #include "ash/login/ui/login_user_view.h" #include "ash/login/ui/scrollable_users_list_view.h" #include "ash/public/interfaces/tray_action.mojom.h" +#include "ash/shell.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/display/manager/display_manager.h" @@ -24,6 +30,8 @@ #include "ui/gfx/geometry/rect.h" #include "ui/views/widget/widget.h" +using ::testing::_; + namespace ash { using LockContentsViewUnitTest = LoginTestBase; @@ -31,8 +39,9 @@ TEST_F(LockContentsViewUnitTest, DisplayMode) { // Build lock screen with 1 user. - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); @@ -76,8 +85,9 @@ // Verifies that the single user view is centered. TEST_F(LockContentsViewUnitTest, SingleUserCentered) { - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); @@ -97,8 +107,9 @@ // Verifies that the single user view is centered when lock screen notes are // enabled. TEST_F(LockContentsViewUnitTest, SingleUserCenteredNoteActionEnabled) { - auto* contents = new LockContentsView(mojom::TrayActionState::kAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); @@ -120,8 +131,9 @@ // mode. TEST_F(LockContentsViewUnitTest, AutoLayoutAfterRotation) { // Build lock screen with three users. - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); LockContentsView::TestApi lock_contents(contents); SetUserCount(3); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); @@ -169,8 +181,9 @@ TEST_F(LockContentsViewUnitTest, AutoLayoutExtraSmallUsersListAfterRotation) { // Build lock screen with extra small layout (> 6 users). - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(9); ScrollableUsersListView* users_list = LockContentsView::TestApi(contents).users_list(); @@ -204,8 +217,9 @@ TEST_F(LockContentsViewUnitTest, AutoLayoutSmallUsersListAfterRotation) { // Build lock screen with small layout (3-6 users). - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(4); ScrollableUsersListView* users_list = LockContentsView::TestApi(contents).users_list(); @@ -317,8 +331,9 @@ // Ensures that when swapping between two users, only auth method display swaps. TEST_F(LockContentsViewUnitTest, SwapAuthUsersInTwoUserLayout) { // Build lock screen with two users. - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); LockContentsView::TestApi test_api(contents); SetUserCount(2); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); @@ -362,8 +377,9 @@ // Ensures that when swapping from a user list, the entire user info is swapped. TEST_F(LockContentsViewUnitTest, SwapUserListToPrimaryAuthUser) { // Build lock screen with five users. - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); LockContentsView::TestApi lock_contents(contents); SetUserCount(5); ScrollableUsersListView::TestApi users_list(lock_contents.users_list()); @@ -403,8 +419,9 @@ // Test goes through different lock screen note state changes and tests that // the note action visibility is updated accordingly. TEST_F(LockContentsViewUnitTest, NoteActionButtonVisibilityChanges) { - auto* contents = new LockContentsView(mojom::TrayActionState::kAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); SetWidget(CreateWidgetWithContent(contents)); @@ -435,8 +452,9 @@ // Verifies note action view bounds. TEST_F(LockContentsViewUnitTest, NoteActionButtonBounds) { - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); @@ -469,8 +487,9 @@ // Verifies the note action view bounds when note action is available at lock // contents view creation. TEST_F(LockContentsViewUnitTest, NoteActionButtonBoundsInitiallyAvailable) { - auto* contents = new LockContentsView(mojom::TrayActionState::kAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); @@ -494,8 +513,9 @@ // Verifies the dev channel info view bounds. TEST_F(LockContentsViewUnitTest, DevChannelInfoViewBounds) { - auto* contents = new LockContentsView(mojom::TrayActionState::kAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); @@ -527,8 +547,9 @@ // Verifies the easy unlock tooltip is automatically displayed when requested. TEST_F(LockContentsViewUnitTest, EasyUnlockForceTooltipCreatesTooltipWidget) { - auto* lock = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* lock = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); SetWidget(CreateWidgetWithContent(lock)); @@ -556,8 +577,9 @@ // Verifies that easy unlock icon state persists when changing auth user. TEST_F(LockContentsViewUnitTest, EasyUnlockIconUpdatedDuringUserSwap) { // Build lock screen with two users. - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(2); SetWidget(CreateWidgetWithContent(contents)); @@ -639,6 +661,323 @@ EXPECT_FALSE(showing_easy_unlock_icon(secondary)); } +TEST_F(LockContentsViewUnitTest, ShowErrorBubbleOnAuthFailure) { + // Build lock screen with a single user. + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); + SetUserCount(1); + SetWidget(CreateWidgetWithContent(contents)); + + LockContentsView::TestApi test_api(contents); + + // Password submit runs mojo. + std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient(); + client->set_authenticate_user_callback_result(false); + EXPECT_CALL(*client, + AuthenticateUser_(users()[0]->basic_user_info->account_id, _, _, + false, _)); + + // Submit password. + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.PressKey(ui::KeyboardCode::VKEY_A, 0); + generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(test_api.auth_error_bubble()->IsVisible()); + + // The error bubble is expected to close on a user action - e.g. if they start + // typing the password again. + generator.PressKey(ui::KeyboardCode::VKEY_B, 0); + EXPECT_FALSE(test_api.auth_error_bubble()->IsVisible()); +} + +TEST_F(LockContentsViewUnitTest, ErrorBubbleOnUntrustedDetachableBase) { + auto fake_detachable_base_model = + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher()); + FakeLoginDetachableBaseModel* detachable_base_model = + fake_detachable_base_model.get(); + + // Build lock screen with 2 users. + auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, + data_dispatcher(), + std::move(fake_detachable_base_model)); + SetUserCount(2); + + const AccountId& kFirstUserAccountId = + users()[0]->basic_user_info->account_id; + const AccountId& kSecondUserAccountId = + users()[1]->basic_user_info->account_id; + + // Initialize the detachable base state, so the user 1 has previously used + // detachable base. + detachable_base_model->InitLastUsedBases({{kFirstUserAccountId, "1234"}}); + detachable_base_model->SetPairingStatus( + DetachableBasePairingStatus::kAuthenticated, "1234"); + SetWidget(CreateWidgetWithContent(contents)); + + LockContentsView::TestApi test_api(contents); + ui::test::EventGenerator& generator = GetEventGenerator(); + + EXPECT_FALSE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Change detachable base to a base different than the one previously used by + // the user - verify that a detachable base error bubble is shown. + detachable_base_model->SetPairingStatus( + DetachableBasePairingStatus::kAuthenticated, "5678"); + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Verify that the bubble is not hidden if the user starts typing. + generator.PressKey(ui::KeyboardCode::VKEY_B, 0); + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Switching to the user that doesn't have previously used detachable base + // (and should thus not be warned about the detachable base missmatch) should + // hide the login bubble. + LoginAuthUserView::TestApi secondary_test_api(test_api.opt_secondary_auth()); + generator.MoveMouseTo( + secondary_test_api.user_view()->GetBoundsInScreen().CenterPoint()); + generator.ClickLeftButton(); + + EXPECT_FALSE(test_api.detachable_base_error_bubble()->IsVisible()); + + // The error should be shown again when switching back to the primary user. + LoginAuthUserView::TestApi primary_test_api(test_api.primary_auth()); + generator.MoveMouseTo( + primary_test_api.user_view()->GetBoundsInScreen().CenterPoint()); + generator.ClickLeftButton(); + + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + EXPECT_FALSE(primary_test_api.password_view()->HasFocus()); + + EXPECT_EQ("1234", + detachable_base_model->GetLastUsedBase(kFirstUserAccountId)); + EXPECT_EQ("", detachable_base_model->GetLastUsedBase(kSecondUserAccountId)); + + // The current detachable base should be set as the last used one by the user + // after they authenticate - test for this. + std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient(); + client->set_authenticate_user_callback_result(true); + EXPECT_CALL(*client, AuthenticateUser_(kFirstUserAccountId, _, _, false, _)); + + // Submit password. + primary_test_api.password_view()->RequestFocus(); + generator.PressKey(ui::KeyboardCode::VKEY_A, 0); + generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ("5678", + detachable_base_model->GetLastUsedBase(kFirstUserAccountId)); + EXPECT_EQ("", detachable_base_model->GetLastUsedBase(kSecondUserAccountId)); +} + +TEST_F(LockContentsViewUnitTest, ErrorBubbleForUnauthenticatedDetachableBase) { + auto fake_detachable_base_model = + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher()); + FakeLoginDetachableBaseModel* detachable_base_model = + fake_detachable_base_model.get(); + + // Build lock screen with 2 users. + auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, + data_dispatcher(), + std::move(fake_detachable_base_model)); + SetUserCount(2); + + const AccountId& kFirstUserAccountId = + users()[0]->basic_user_info->account_id; + const AccountId& kSecondUserAccountId = + users()[1]->basic_user_info->account_id; + + detachable_base_model->InitLastUsedBases({{kSecondUserAccountId, "5678"}}); + + SetWidget(CreateWidgetWithContent(contents)); + + LockContentsView::TestApi test_api(contents); + ui::test::EventGenerator& generator = GetEventGenerator(); + + EXPECT_FALSE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Show notification if unauthenticated base is attached. + detachable_base_model->SetPairingStatus( + DetachableBasePairingStatus::kNotAuthenticated, ""); + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Verify that the bubble is not hidden if the user starts typing. + generator.PressKey(ui::KeyboardCode::VKEY_B, 0); + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Switching to another user should not hide the error bubble. + LoginAuthUserView::TestApi secondary_test_api(test_api.opt_secondary_auth()); + generator.MoveMouseTo( + secondary_test_api.user_view()->GetBoundsInScreen().CenterPoint()); + generator.ClickLeftButton(); + + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + EXPECT_FALSE(secondary_test_api.password_view()->HasFocus()); + + // The last trusted detachable used by the user should not be overriden by + // user authentication. + std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient(); + client->set_authenticate_user_callback_result(true); + EXPECT_CALL(*client, AuthenticateUser_(kSecondUserAccountId, _, _, false, _)); + + // Submit password. + secondary_test_api.password_view()->RequestFocus(); + generator.PressKey(ui::KeyboardCode::VKEY_A, 0); + generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ("", detachable_base_model->GetLastUsedBase(kFirstUserAccountId)); + EXPECT_EQ("5678", + detachable_base_model->GetLastUsedBase(kSecondUserAccountId)); +} +TEST_F(LockContentsViewUnitTest, + RemovingAttachedBaseHidesDetachableBaseNotification) { + auto fake_detachable_base_model = + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher()); + FakeLoginDetachableBaseModel* detachable_base_model = + fake_detachable_base_model.get(); + + // Build lock screen with 2 users. + auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, + data_dispatcher(), + std::move(fake_detachable_base_model)); + SetUserCount(1); + + const AccountId& kUserAccountId = users()[0]->basic_user_info->account_id; + + // Initialize the detachable base state, as if the user has previously used + // detachable base. + detachable_base_model->InitLastUsedBases({{kUserAccountId, "1234"}}); + detachable_base_model->SetPairingStatus( + DetachableBasePairingStatus::kAuthenticated, "1234"); + + SetWidget(CreateWidgetWithContent(contents)); + + LockContentsView::TestApi test_api(contents); + + // Change detachable base to a base different than the one previously used by + // the user - verify that a detachable base error bubble is shown. + detachable_base_model->SetPairingStatus( + DetachableBasePairingStatus::kAuthenticated, "5678"); + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + + // The notification should be hidden if the base gets detached. + detachable_base_model->SetPairingStatus(DetachableBasePairingStatus::kNone, + ""); + EXPECT_FALSE(test_api.detachable_base_error_bubble()->IsVisible()); +} + +TEST_F(LockContentsViewUnitTest, DetachableBaseErrorClearsAuthError) { + auto fake_detachable_base_model = + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher()); + FakeLoginDetachableBaseModel* detachable_base_model = + fake_detachable_base_model.get(); + + // Build lock screen with a single user. + auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, + data_dispatcher(), + std::move(fake_detachable_base_model)); + SetUserCount(1); + + const AccountId& kUserAccountId = users()[0]->basic_user_info->account_id; + + // Initialize the detachable base state, as if the user has previously used + // detachable base. + detachable_base_model->InitLastUsedBases({{kUserAccountId, "1234"}}); + detachable_base_model->SetPairingStatus( + DetachableBasePairingStatus::kAuthenticated, "1234"); + + SetWidget(CreateWidgetWithContent(contents)); + + LockContentsView::TestApi test_api(contents); + ui::test::EventGenerator& generator = GetEventGenerator(); + + EXPECT_FALSE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Attempt and fail user auth - an auth error is expected to be shown. + std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient(); + client->set_authenticate_user_callback_result(false); + EXPECT_CALL(*client, AuthenticateUser_(kUserAccountId, _, _, false, _)); + + // Submit password. + generator.PressKey(ui::KeyboardCode::VKEY_A, 0); + generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(test_api.auth_error_bubble()->IsVisible()); + EXPECT_FALSE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Change detachable base to a base different than the one previously used by + // the user - verify that a detachable base error bubble is shown, and the + // auth error is hidden. + detachable_base_model->SetPairingStatus( + DetachableBasePairingStatus::kAuthenticated, "5678"); + + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + EXPECT_FALSE(test_api.auth_error_bubble()->IsVisible()); +} + +TEST_F(LockContentsViewUnitTest, AuthErrorDoesNotRemoveDetachableBaseError) { + auto fake_detachable_base_model = + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher()); + FakeLoginDetachableBaseModel* detachable_base_model = + fake_detachable_base_model.get(); + + // Build lock screen with a single user. + auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, + data_dispatcher(), + std::move(fake_detachable_base_model)); + SetUserCount(1); + + const AccountId& kUserAccountId = users()[0]->basic_user_info->account_id; + + // Initialize the detachable base state, as if the user has previously used + // detachable base. + detachable_base_model->InitLastUsedBases({{kUserAccountId, "1234"}}); + SetWidget(CreateWidgetWithContent(contents)); + + detachable_base_model->SetPairingStatus( + DetachableBasePairingStatus::kAuthenticated, "1234"); + + LockContentsView::TestApi test_api(contents); + ui::test::EventGenerator& generator = GetEventGenerator(); + + EXPECT_FALSE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Change detachable base to a base different than the one previously used by + // the user - verify that a detachable base error bubble is shown, and the + // auth error is hidden. + detachable_base_model->SetPairingStatus( + DetachableBasePairingStatus::kAuthenticated, "5678"); + + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + + // Attempt and fail user auth - an auth error is expected to be shown. + // Detachable base error should not be hidden. + std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient(); + client->set_authenticate_user_callback_result(false); + EXPECT_CALL(*client, AuthenticateUser_(kUserAccountId, _, _, false, _)); + + // Submit password. + LoginAuthUserView::TestApi(test_api.primary_auth()) + .password_view() + ->RequestFocus(); + generator.PressKey(ui::KeyboardCode::VKEY_A, 0); + generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(test_api.auth_error_bubble()->IsVisible()); + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + + // User action, like pressing a key should close the auth error bubble, but + // not the detachable base error bubble. + generator.PressKey(ui::KeyboardCode::VKEY_A, 0); + + EXPECT_TRUE(test_api.detachable_base_error_bubble()->IsVisible()); + EXPECT_FALSE(test_api.auth_error_bubble()->IsVisible()); +} + TEST_F(LockContentsViewKeyboardUnitTest, SwitchPinAndVirtualKeyboard) { ASSERT_NO_FATAL_FAILURE(ShowLockScreen()); LockContentsView* contents =
diff --git a/ash/login/ui/lock_debug_view.cc b/ash/login/ui/lock_debug_view.cc index 12bef5f1..cd1b1b24 100644 --- a/ash/login/ui/lock_debug_view.cc +++ b/ash/login/ui/lock_debug_view.cc
@@ -6,7 +6,7 @@ #include <algorithm> #include <memory> -#include <string> +#include <utility> #include "ash/ime/ime_controller.h" #include "ash/login/login_screen_controller.h" @@ -14,6 +14,7 @@ #include "ash/login/ui/lock_contents_view.h" #include "ash/login/ui/lock_screen.h" #include "ash/login/ui/login_data_dispatcher.h" +#include "ash/login/ui/login_detachable_base_model.h" #include "ash/login/ui/non_accessible_view.h" #include "ash/shell.h" #include "base/strings/utf_string_conversions.h" @@ -232,6 +233,10 @@ const mojom::EasyUnlockIconOptionsPtr& icon) override { debug_dispatcher_.ShowEasyUnlockIcon(user, icon); } + void OnDetachableBasePairingStatusChanged( + DetachableBasePairingStatus pairing_status) override { + debug_dispatcher_.SetDetachableBasePairingStatus(pairing_status); + } private: // The debug overlay UI takes ground-truth data from |root_dispatcher_|, @@ -252,8 +257,10 @@ DISALLOW_COPY_AND_ASSIGN(DebugDataDispatcherTransformer); }; -LockDebugView::LockDebugView(mojom::TrayActionState initial_note_action_state, - LoginDataDispatcher* data_dispatcher) +LockDebugView::LockDebugView( + mojom::TrayActionState initial_note_action_state, + LoginDataDispatcher* data_dispatcher, + std::unique_ptr<LoginDetachableBaseModel> detachable_base_model) : debug_data_dispatcher_(std::make_unique<DebugDataDispatcherTransformer>( initial_note_action_state, data_dispatcher)) { @@ -261,7 +268,8 @@ std::make_unique<views::BoxLayout>(views::BoxLayout::kHorizontal)); lock_ = new LockContentsView(initial_note_action_state, - debug_data_dispatcher_->debug_dispatcher()); + debug_data_dispatcher_->debug_dispatcher(), + std::move(detachable_base_model)); AddChildView(lock_); debug_row_ = new NonAccessibleView(); @@ -326,7 +334,7 @@ // Iteratively adds more info to the dev channel labels to test 7 permutations // and then disables the button. if (sender == add_dev_channel_info_) { - DCHECK(num_dev_channel_info_clicks_ < 7u); + DCHECK_LT(num_dev_channel_info_clicks_, 7u); ++num_dev_channel_info_clicks_; if (num_dev_channel_info_clicks_ == 7u) add_dev_channel_info_->SetEnabled(false);
diff --git a/ash/login/ui/lock_debug_view.h b/ash/login/ui/lock_debug_view.h index b27b9c333..74acbe2f 100644 --- a/ash/login/ui/lock_debug_view.h +++ b/ash/login/ui/lock_debug_view.h
@@ -6,8 +6,10 @@ #define ASH_LOGIN_UI_LOCK_DEBUG_VIEW_H_ #include <memory> +#include <string> #include <vector> +#include "ash/detachable_base/detachable_base_pairing_status.h" #include "ash/login/login_screen_controller.h" #include "ui/views/controls/button/button.h" #include "ui/views/view.h" @@ -19,6 +21,7 @@ namespace ash { class LoginDataDispatcher; +class LoginDetachableBaseModel; class LockContentsView; namespace mojom { @@ -28,8 +31,10 @@ // Contains the debug UI row (ie, add user, toggle PIN buttons). class LockDebugView : public views::View, public views::ButtonListener { public: - LockDebugView(mojom::TrayActionState initial_note_action_state, - LoginDataDispatcher* data_dispatcher); + LockDebugView( + mojom::TrayActionState initial_note_action_state, + LoginDataDispatcher* data_dispatcher, + std::unique_ptr<LoginDetachableBaseModel> detachable_base_model); ~LockDebugView() override; // views::View:
diff --git a/ash/login/ui/lock_screen.cc b/ash/login/ui/lock_screen.cc index 322007d4..7d6e8d2 100644 --- a/ash/login/ui/lock_screen.cc +++ b/ash/login/ui/lock_screen.cc
@@ -11,6 +11,7 @@ #include "ash/login/ui/lock_debug_view.h" #include "ash/login/ui/lock_window.h" #include "ash/login/ui/login_data_dispatcher.h" +#include "ash/login/ui/login_detachable_base_model.h" #include "ash/public/cpp/login_constants.h" #include "ash/public/interfaces/session_controller.mojom.h" #include "ash/root_window_controller.h" @@ -72,17 +73,21 @@ display::Screen::GetScreen()->GetPrimaryDisplay().bounds()); auto data_dispatcher = std::make_unique<LoginDataDispatcher>(); + auto detachable_base_model = LoginDetachableBaseModel::Create( + Shell::Get()->detachable_base_handler(), data_dispatcher.get()); auto initial_note_action_state = - ash::Shell::Get()->tray_action()->GetLockScreenNoteState(); + Shell::Get()->tray_action()->GetLockScreenNoteState(); if (base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kShowLoginDevOverlay)) { auto* debug_view = - new LockDebugView(initial_note_action_state, data_dispatcher.get()); + new LockDebugView(initial_note_action_state, data_dispatcher.get(), + std::move(detachable_base_model)); instance_->contents_view_ = debug_view->lock(); instance_->window_->SetContentsView(debug_view); } else { instance_->contents_view_ = - new LockContentsView(initial_note_action_state, data_dispatcher.get()); + new LockContentsView(initial_note_action_state, data_dispatcher.get(), + std::move(detachable_base_model)); instance_->window_->SetContentsView(instance_->contents_view_); }
diff --git a/ash/login/ui/lock_screen_sanity_unittest.cc b/ash/login/ui/lock_screen_sanity_unittest.cc index 91a5de38..bcb5723f 100644 --- a/ash/login/ui/lock_screen_sanity_unittest.cc +++ b/ash/login/ui/lock_screen_sanity_unittest.cc
@@ -6,6 +6,7 @@ #include "ash/login/login_screen_controller.h" #include "ash/login/mock_login_screen_client.h" +#include "ash/login/ui/fake_login_detachable_base_model.h" #include "ash/login/ui/lock_contents_view.h" #include "ash/login/ui/login_test_base.h" #include "ash/login/ui/login_test_utils.h" @@ -102,8 +103,9 @@ // Verifies that the password input box has focus. TEST_F(LockScreenSanityTest, PasswordIsInitiallyFocused) { // Build lock screen. - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); // The lock screen requires at least one user. SetUserCount(1); @@ -118,8 +120,9 @@ // Verifies submitting the password invokes mojo lock screen client. TEST_F(LockScreenSanityTest, PasswordSubmitCallsLoginScreenClient) { // Build lock screen. - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); // The lock screen requires at least one user. SetUserCount(1); @@ -144,8 +147,9 @@ PasswordSubmitClearsPasswordAfterFailedAuthentication) { std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient(); - auto* contents = new LockContentsView(mojom::TrayActionState::kAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); LoginPasswordView::TestApi password_test_api = @@ -197,8 +201,9 @@ session_manager::SessionState::LOCKED); // Create lock screen. - auto* lock = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* lock = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(lock); views::View* shelf = Shelf::ForWindow(lock->GetWidget()->GetNativeWindow()) @@ -228,8 +233,9 @@ GetSessionControllerClient()->SetSessionState( session_manager::SessionState::LOCKED); - auto* lock = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* lock = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(lock); views::View* status_area = @@ -258,8 +264,9 @@ GetSessionControllerClient()->SetSessionState( session_manager::SessionState::LOCKED); - auto* lock = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* lock = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(lock); @@ -329,8 +336,9 @@ // Set up lock screen. GetSessionControllerClient()->SetSessionState( session_manager::SessionState::LOCKED); - auto* lock = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* lock = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(lock);
diff --git a/ash/login/ui/login_bubble.cc b/ash/login/ui/login_bubble.cc index e0f1674f..50867ed 100644 --- a/ash/login/ui/login_bubble.cc +++ b/ash/login/ui/login_bubble.cc
@@ -4,6 +4,9 @@ #include "ash/login/ui/login_bubble.h" +#include <memory> +#include <utility> + #include "ash/ash_constants.h" #include "ash/focus_cycler.h" #include "ash/login/ui/layout_util.h" @@ -86,7 +89,7 @@ class LoginErrorBubbleView : public LoginBaseBubbleView { public: - LoginErrorBubbleView(views::StyledLabel* label, views::View* anchor_view) + LoginErrorBubbleView(views::View* content, views::View* anchor_view) : LoginBaseBubbleView(anchor_view) { SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::kVertical, gfx::Insets(), @@ -104,8 +107,7 @@ alert_view->AddChildView(alert_icon); AddChildView(alert_view); - label->set_auto_color_readability_enabled(false); - AddChildView(label); + AddChildView(content); } ~LoginErrorBubbleView() override = default; @@ -361,12 +363,15 @@ } } -void LoginBubble::ShowErrorBubble(views::StyledLabel* label, - views::View* anchor_view) { +void LoginBubble::ShowErrorBubble(views::View* content, + views::View* anchor_view, + uint32_t flags) { if (bubble_view_) CloseImmediately(); - bubble_view_ = new LoginErrorBubbleView(label, anchor_view); + flags_ = flags; + bubble_view_ = new LoginErrorBubbleView(content, anchor_view); + Show(); } @@ -381,6 +386,7 @@ if (bubble_view_) CloseImmediately(); + flags_ = kFlagsNone; bubble_opener_ = bubble_opener; bubble_view_ = new LoginUserMenuView(this, username, email, type, is_owner, anchor_view, @@ -400,6 +406,7 @@ if (bubble_view_) CloseImmediately(); + flags_ = kFlagsNone; bubble_view_ = new LoginTooltipView(message, anchor_view); Show(); } @@ -415,6 +422,7 @@ void LoginBubble::OnWidgetClosing(views::Widget* widget) { bubble_opener_ = nullptr; bubble_view_ = nullptr; + flags_ = kFlagsNone; widget->RemoveObserver(this); } @@ -447,7 +455,9 @@ if (bubble_view_->GetWidget()->IsActive()) return; - Close(); + if (!(flags_ & kFlagPersistent)) { + Close(); + } } void LoginBubble::OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) { @@ -461,9 +471,10 @@ void LoginBubble::Show() { DCHECK(bubble_view_); - views::BubbleDialogDelegateView::CreateBubble(bubble_view_)->Show(); + views::BubbleDialogDelegateView::CreateBubble(bubble_view_)->ShowInactive(); bubble_view_->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); bubble_view_->GetWidget()->AddObserver(this); + bubble_view_->GetWidget()->StackAtTop(); ScheduleAnimation(true /*visible*/); @@ -498,7 +509,8 @@ return; } - Close(); + if (!(flags_ & kFlagPersistent)) + Close(); } void LoginBubble::ScheduleAnimation(bool visible) {
diff --git a/ash/login/ui/login_bubble.h b/ash/login/ui/login_bubble.h index b756dab1..52be89c 100644 --- a/ash/login/ui/login_bubble.h +++ b/ash/login/ui/login_bubble.h
@@ -13,10 +13,6 @@ #include "ui/views/view.h" #include "ui/views/widget/widget_observer.h" -namespace views { -class StyledLabel; -} - namespace ash { class LoginButton; @@ -29,12 +25,20 @@ public: static const int kUserMenuRemoveUserButtonIdForTest; + // Flags passed to ShowErrorBubble(). + static constexpr uint32_t kFlagsNone = 0; + // If set, the shown error bubble will not be closed due to an unrelated user + // action - e.g. the bubble will not be closed if the user starts typing. + static constexpr uint32_t kFlagPersistent = 1 << 0; + LoginBubble(); ~LoginBubble() override; // Shows an error bubble for authentication failure. // |anchor_view| is the anchor for placing the bubble view. - void ShowErrorBubble(views::StyledLabel* label, views::View* anchor_view); + void ShowErrorBubble(views::View* content, + views::View* anchor_view, + uint32_t flags); // Shows a user menu bubble. // |anchor_view| is the anchor for placing the bubble view. @@ -91,6 +95,9 @@ // Starts show/hide animation. void ScheduleAnimation(bool visible); + // Flags passed to ShowErrorBubble(). + uint32_t flags_ = kFlagsNone; + LoginBaseBubbleView* bubble_view_ = nullptr; // A button that could open/close the bubble.
diff --git a/ash/login/ui/login_bubble_unittest.cc b/ash/login/ui/login_bubble_unittest.cc index 980a3c76..cbf07da7 100644 --- a/ash/login/ui/login_bubble_unittest.cc +++ b/ash/login/ui/login_bubble_unittest.cc
@@ -3,13 +3,16 @@ // found in the LICENSE file. #include <memory> +#include <utility> #include "ash/login/ui/login_bubble.h" #include "ash/login/ui/login_button.h" #include "ash/login/ui/login_test_base.h" +#include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/test/event_generator.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" +#include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" #include "ui/views/widget/widget.h" @@ -236,4 +239,95 @@ EXPECT_TRUE(remove_called); } +TEST_F(LoginBubbleTest, ErrorBubbleKeyEventHandling) { + ui::test::EventGenerator& generator = GetEventGenerator(); + + EXPECT_FALSE(bubble_->IsVisible()); + views::Label* error_text = new views::Label(base::ASCIIToUTF16("Error text")); + bubble_->ShowErrorBubble(error_text, container_, LoginBubble::kFlagsNone); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that key event on a view other than error closes the error bubble. + other_view_->RequestFocus(); + generator.PressKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE); + EXPECT_FALSE(bubble_->IsVisible()); +} + +TEST_F(LoginBubbleTest, ErrorBubbleMouseEventHandling) { + ui::test::EventGenerator& generator = GetEventGenerator(); + + EXPECT_FALSE(bubble_->IsVisible()); + views::Label* error_text = new views::Label(base::ASCIIToUTF16("Error text")); + bubble_->ShowErrorBubble(error_text, container_, LoginBubble::kFlagsNone); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that mouse event on the bubble itself won't close the bubble. + generator.MoveMouseTo( + bubble_->bubble_view_for_test()->GetBoundsInScreen().CenterPoint()); + generator.ClickLeftButton(); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that mouse event on the other view will close the bubble. + generator.MoveMouseTo(other_view_->GetBoundsInScreen().CenterPoint()); + generator.ClickLeftButton(); + EXPECT_FALSE(bubble_->IsVisible()); +} + +TEST_F(LoginBubbleTest, ErrorBubbleGestureEventHandling) { + ui::test::EventGenerator& generator = GetEventGenerator(); + + EXPECT_FALSE(bubble_->IsVisible()); + views::Label* error_text = new views::Label(base::ASCIIToUTF16("Error text")); + bubble_->ShowErrorBubble(error_text, container_, LoginBubble::kFlagsNone); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that gesture event on the bubble itself won't close the bubble. + generator.GestureTapAt( + bubble_->bubble_view_for_test()->GetBoundsInScreen().CenterPoint()); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that gesture event on the other view will close the bubble. + generator.GestureTapAt(other_view_->GetBoundsInScreen().CenterPoint()); + EXPECT_FALSE(bubble_->IsVisible()); +} + +TEST_F(LoginBubbleTest, PersistentErrorBubbleEventHandling) { + ui::test::EventGenerator& generator = GetEventGenerator(); + + EXPECT_FALSE(bubble_->IsVisible()); + views::Label* error_text = new views::Label(base::ASCIIToUTF16("Error text")); + bubble_->ShowErrorBubble(error_text, container_, + LoginBubble::kFlagPersistent); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that mouse event on the bubble itself won't close the bubble. + generator.MoveMouseTo( + bubble_->bubble_view_for_test()->GetBoundsInScreen().CenterPoint()); + generator.ClickLeftButton(); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that mouse event on the other view won't close the bubble. + generator.MoveMouseTo(other_view_->GetBoundsInScreen().CenterPoint()); + generator.ClickLeftButton(); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that gesture event on the bubble itself won't close the bubble. + generator.GestureTapAt( + bubble_->bubble_view_for_test()->GetBoundsInScreen().CenterPoint()); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that gesture event on the other view won't close the bubble. + generator.GestureTapAt(other_view_->GetBoundsInScreen().CenterPoint()); + EXPECT_TRUE(bubble_->IsVisible()); + + // Verifies that key event on the other view won't close the bubble. + other_view_->RequestFocus(); + generator.PressKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE); + EXPECT_TRUE(bubble_->IsVisible()); + + // LoginBubble::Close should close the persistent error bubble. + bubble_->Close(); + EXPECT_FALSE(bubble_->IsVisible()); +} + } // namespace ash
diff --git a/ash/login/ui/login_data_dispatcher.cc b/ash/login/ui/login_data_dispatcher.cc index f280408c..c1177fe 100644 --- a/ash/login/ui/login_data_dispatcher.cc +++ b/ash/login/ui/login_data_dispatcher.cc
@@ -41,6 +41,9 @@ const std::string& default_locale, bool show_advanced_view) {} +void LoginDataDispatcher::Observer::OnDetachableBasePairingStatusChanged( + DetachableBasePairingStatus pairing_status) {} + LoginDataDispatcher::LoginDataDispatcher() = default; LoginDataDispatcher::~LoginDataDispatcher() = default; @@ -111,4 +114,10 @@ } } +void LoginDataDispatcher::SetDetachableBasePairingStatus( + DetachableBasePairingStatus pairing_status) { + for (auto& observer : observers_) + observer.OnDetachableBasePairingStatusChanged(pairing_status); +} + } // namespace ash
diff --git a/ash/login/ui/login_data_dispatcher.h b/ash/login/ui/login_data_dispatcher.h index 4fef1be..4155560 100644 --- a/ash/login/ui/login_data_dispatcher.h +++ b/ash/login/ui/login_data_dispatcher.h
@@ -5,9 +5,12 @@ #ifndef ASH_LOGIN_UI_LOGIN_DATA_DISPATCHER_H_ #define ASH_LOGIN_UI_LOGIN_DATA_DISPATCHER_H_ +#include <memory> +#include <string> #include <vector> #include "ash/ash_export.h" +#include "ash/detachable_base/detachable_base_pairing_status.h" #include "ash/public/interfaces/login_user_info.mojom.h" #include "ash/public/interfaces/tray_action.mojom.h" #include "base/macros.h" @@ -77,6 +80,11 @@ const base::ListValue& locales, const std::string& default_locale, bool show_advanced_view); + + // Called when the pairing status of detachable base changes - e.g. when the + // base is attached or detached. + virtual void OnDetachableBasePairingStatusChanged( + DetachableBasePairingStatus pairing_status); }; LoginDataDispatcher(); @@ -100,6 +108,8 @@ std::unique_ptr<base::ListValue> locales, const std::string& default_locale, bool show_advanced_view); + void SetDetachableBasePairingStatus( + DetachableBasePairingStatus pairing_status); private: base::ObserverList<Observer> observers_;
diff --git a/ash/login/ui/login_detachable_base_model.cc b/ash/login/ui/login_detachable_base_model.cc new file mode 100644 index 0000000..a1fc69b --- /dev/null +++ b/ash/login/ui/login_detachable_base_model.cc
@@ -0,0 +1,70 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/login/ui/login_detachable_base_model.h" + +#include "ash/detachable_base/detachable_base_handler.h" +#include "ash/detachable_base/detachable_base_observer.h" +#include "ash/detachable_base/detachable_base_pairing_status.h" +#include "ash/login/ui/login_data_dispatcher.h" +#include "ash/public/interfaces/user_info.mojom.h" +#include "base/macros.h" +#include "base/scoped_observer.h" + +namespace ash { + +namespace { + +class LoginDetachableBaseModelImpl : public LoginDetachableBaseModel, + public DetachableBaseObserver { + public: + LoginDetachableBaseModelImpl(DetachableBaseHandler* detachable_base_handler, + LoginDataDispatcher* login_data_dispatcher) + : detachable_base_handler_(detachable_base_handler), + detachable_base_observer_(this), + login_data_dispatcher_(login_data_dispatcher) { + detachable_base_observer_.Add(detachable_base_handler); + } + + ~LoginDetachableBaseModelImpl() override = default; + + // LoginDetachableBaseModel: + DetachableBasePairingStatus GetPairingStatus() override { + return detachable_base_handler_->GetPairingStatus(); + } + bool PairedBaseMatchesLastUsedByUser( + const mojom::UserInfo& user_info) override { + return detachable_base_handler_->PairedBaseMatchesLastUsedByUser(user_info); + } + bool SetPairedBaseAsLastUsedByUser( + const mojom::UserInfo& user_info) override { + return detachable_base_handler_->SetPairedBaseAsLastUsedByUser(user_info); + } + + // DetachableBaseObserver: + void OnDetachableBasePairingStatusChanged( + DetachableBasePairingStatus pairing_status) override { + login_data_dispatcher_->SetDetachableBasePairingStatus(pairing_status); + } + + private: + DetachableBaseHandler* detachable_base_handler_; + ScopedObserver<DetachableBaseHandler, DetachableBaseObserver> + detachable_base_observer_; + LoginDataDispatcher* login_data_dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(LoginDetachableBaseModelImpl); +}; + +} // namespace + +// static +std::unique_ptr<LoginDetachableBaseModel> LoginDetachableBaseModel::Create( + DetachableBaseHandler* detachable_base_handler, + LoginDataDispatcher* login_data_dispatcher) { + return std::make_unique<LoginDetachableBaseModelImpl>(detachable_base_handler, + login_data_dispatcher); +} + +} // namespace ash
diff --git a/ash/login/ui/login_detachable_base_model.h b/ash/login/ui/login_detachable_base_model.h new file mode 100644 index 0000000..e21b0807 --- /dev/null +++ b/ash/login/ui/login_detachable_base_model.h
@@ -0,0 +1,53 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_LOGIN_UI_LOGIN_DETACHABLE_BASE_MODEL_H_ +#define ASH_LOGIN_UI_LOGIN_DETACHABLE_BASE_MODEL_H_ + +#include <memory> + +#include "ash/ash_export.h" + +namespace ash { + +class DetachableBaseHandler; +enum class DetachableBasePairingStatus; +class LoginDataDispatcher; + +namespace mojom { +class UserInfo; +} + +// Wrapper around ash::DetachableBaseHandler used by login UI. Exposed as an +// interface to ease faking the detachable base state in login UI tests, and in +// debug login view. +// +// It observes the detachable base pairing status, and informs login data +// dispatcher of pairing status changes. +// It provides methods for comparing the current base to the last based used by +// a user, and setting the last base used by the user. +class ASH_EXPORT LoginDetachableBaseModel { + public: + virtual ~LoginDetachableBaseModel() = default; + + static std::unique_ptr<LoginDetachableBaseModel> Create( + DetachableBaseHandler* detachable_base_handler, + LoginDataDispatcher* login_data_dispatcher); + + // Returns the current detachable base pairing status. + virtual DetachableBasePairingStatus GetPairingStatus() = 0; + + // Checks if the currently paired base is different than the last base used by + // the user. + virtual bool PairedBaseMatchesLastUsedByUser( + const mojom::UserInfo& user_info) = 0; + + // Sets the currently paired base as the last base used by the user. + virtual bool SetPairedBaseAsLastUsedByUser( + const mojom::UserInfo& user_info) = 0; +}; + +} // namespace ash + +#endif // ASH_LOGIN_UI_LOGIN_DETACHABLE_BASE_MODEL_H_
diff --git a/ash/metrics/login_metrics_recorder_unittest.cc b/ash/metrics/login_metrics_recorder_unittest.cc index 4c845cdc..ff437773 100644 --- a/ash/metrics/login_metrics_recorder_unittest.cc +++ b/ash/metrics/login_metrics_recorder_unittest.cc
@@ -4,8 +4,12 @@ #include "ash/metrics/login_metrics_recorder.h" +#include <memory> +#include <string> + #include "ash/login/login_screen_controller.h" #include "ash/login/mock_login_screen_client.h" +#include "ash/login/ui/fake_login_detachable_base_model.h" #include "ash/login/ui/lock_contents_view.h" #include "ash/login/ui/lock_screen.h" #include "ash/login/ui/login_auth_user_view.h" @@ -106,8 +110,9 @@ std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient(); client->set_authenticate_user_callback_result(false); - auto* contents = new LockContentsView(mojom::TrayActionState::kNotAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); LockContentsView::TestApi test_api(contents); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); @@ -184,8 +189,9 @@ GetSessionControllerClient()->SetSessionState( session_manager::SessionState::LOCKED); - auto* contents = new LockContentsView(mojom::TrayActionState::kAvailable, - data_dispatcher()); + auto* contents = new LockContentsView( + mojom::TrayActionState::kAvailable, data_dispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher())); SetUserCount(1); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents);
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc index 882c29f..6310e535 100644 --- a/ash/public/cpp/ash_features.cc +++ b/ash/public/cpp/ash_features.cc
@@ -19,6 +19,9 @@ const base::Feature kNewOverviewAnimations{"NewOverviewAnimations", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kPersistentWindowBounds{"PersistentWindowBounds", + base::FEATURE_ENABLED_BY_DEFAULT}; + const base::Feature kSystemTrayUnified{"SystemTrayUnified", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -45,6 +48,10 @@ return base::FeatureList::IsEnabled(kSystemTrayUnified); } +bool IsPersistentWindowBoundsEnabled() { + return base::FeatureList::IsEnabled(kPersistentWindowBounds); +} + bool IsLockScreenNotificationsEnabled() { return base::FeatureList::IsEnabled(kLockScreenNotifications); }
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h index 1551c70..6c2e714 100644 --- a/ash/public/cpp/ash_features.h +++ b/ash/public/cpp/ash_features.h
@@ -31,6 +31,11 @@ // https://crbug.com/801465. ASH_PUBLIC_EXPORT extern const base::Feature kNewOverviewAnimations; +// Enables persistent window bounds in multi-displays scenario. +// TODO(warx): Remove this after the feature is fully launched. +// https://crbug.com/805046. +ASH_PUBLIC_EXPORT extern const base::Feature kPersistentWindowBounds; + // Enables new system menu. ASH_PUBLIC_EXPORT extern const base::Feature kSystemTrayUnified; @@ -45,6 +50,8 @@ ASH_PUBLIC_EXPORT bool IsNewOverviewAnimationsEnabled(); +ASH_PUBLIC_EXPORT bool IsPersistentWindowBoundsEnabled(); + ASH_PUBLIC_EXPORT bool IsSystemTrayUnifiedEnabled(); ASH_PUBLIC_EXPORT bool IsLockScreenNotificationsEnabled();
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h index 1be5a0f..b91c5b5 100644 --- a/ash/public/cpp/ash_pref_names.h +++ b/ash/public/cpp/ash_pref_names.h
@@ -67,6 +67,8 @@ ASH_PUBLIC_EXPORT extern const char kDetachableBaseDevices[]; +ASH_PUBLIC_EXPORT extern const char kCursorMotionBlurEnabled[]; + } // namespace prefs } // namespace ash
diff --git a/ash/public/cpp/ash_switches.cc b/ash/public/cpp/ash_switches.cc index 5e38cf60..d30ca17 100644 --- a/ash/public/cpp/ash_switches.cc +++ b/ash/public/cpp/ash_switches.cc
@@ -41,6 +41,9 @@ // TODO(oshima): Remove this once the feature is launched. crbug.com/749713. const char kAshEnableV1AppBackButton[] = "ash-enable-v1-app-back-button"; +// Enable cursor motion blur. +const char kAshEnableCursorMotionBlur[] = "ash-enable-cursor-motion-blur"; + // Enables key bindings to scroll magnified screen. const char kAshEnableMagnifierKeyScroller[] = "ash-enable-magnifier-key-scroller"; @@ -56,11 +59,6 @@ const char kAshEnablePaletteOnAllDisplays[] = "ash-enable-palette-on-all-displays"; -// Enables persistent window bounds in multi-displays scenario. -// TODO(warx): Remove this once the feature is launched. crbug.com/805046. -const char kAshEnablePersistentWindowBounds[] = - "ash-enable-persistent-window-bounds"; - // Enables the sidebar. const char kAshSidebarEnabled[] = "enable-ash-sidebar"; const char kAshSidebarDisabled[] = "disable-ash-sidebar";
diff --git a/ash/public/cpp/ash_switches.h b/ash/public/cpp/ash_switches.h index 0f3493b..f9fc18f 100644 --- a/ash/public/cpp/ash_switches.h +++ b/ash/public/cpp/ash_switches.h
@@ -24,12 +24,12 @@ ASH_PUBLIC_EXPORT extern const char kAshDisableTabletSplitView[]; ASH_PUBLIC_EXPORT extern const char kAshDisableTrilinearFiltering[]; ASH_PUBLIC_EXPORT extern const char kAshDisableTouchExplorationMode[]; +ASH_PUBLIC_EXPORT extern const char kAshEnableCursorMotionBlur[]; ASH_PUBLIC_EXPORT extern const char kAshEnableV1AppBackButton[]; ASH_PUBLIC_EXPORT extern const char kAshEnableMagnifierKeyScroller[]; ASH_PUBLIC_EXPORT extern const char kAshEnableNewOverviewUi[]; ASH_PUBLIC_EXPORT extern const char kAshEnableNightLight[]; ASH_PUBLIC_EXPORT extern const char kAshEnablePaletteOnAllDisplays[]; -ASH_PUBLIC_EXPORT extern const char kAshEnablePersistentWindowBounds[]; ASH_PUBLIC_EXPORT extern const char kAshEnableScaleSettingsTray[]; ASH_PUBLIC_EXPORT extern const char kAshEnableTabletMode[]; ASH_PUBLIC_EXPORT extern const char kAshEnableWaylandServer[];
diff --git a/ash/shell.cc b/ash/shell.cc index 14f1138..7c37a35 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -1142,6 +1142,8 @@ cursor_manager_->SetCursor(ui::CursorType::kPointer); } + UpdateCursorCompositingEnabled(); + peripheral_battery_notifier_ = std::make_unique<PeripheralBatteryNotifier>(); power_event_observer_.reset(new PowerEventObserver()); user_activity_notifier_.reset(
diff --git a/ash/system/power/power_button_controller.cc b/ash/system/power/power_button_controller.cc index 9b11e70b..9fc4ca4 100644 --- a/ash/system/power/power_button_controller.cc +++ b/ash/system/power/power_button_controller.cc
@@ -30,10 +30,13 @@ namespace ash { namespace { -// Time that power button should be pressed before starting to show the power -// button menu animation. -constexpr base::TimeDelta kStartPowerButtonMenuAnimationTimeout = +// Amount of time power button must be held to start the power menu animation +// for convertible/slate/detachable devices. This differs depending on whether +// the screen is on or off when the power button is initially pressed. +constexpr base::TimeDelta kShowMenuWhenScreenOnTimeout = base::TimeDelta::FromMilliseconds(500); +constexpr base::TimeDelta kShowMenuWhenScreenOffTimeout = + base::TimeDelta::FromMilliseconds(2000); // Time that power button should be pressed before starting to shutdown. constexpr base::TimeDelta kStartShutdownTimeout = @@ -136,6 +139,7 @@ } if (down) { + show_menu_animation_done_ = false; if (turn_screen_off_for_tap_) { force_off_on_button_up_ = true; @@ -160,9 +164,17 @@ screen_off_when_power_button_down_ = !display_controller_->IsScreenOn(); display_controller_->SetBacklightsForcedOff(false); - power_button_menu_timer_.Start( - FROM_HERE, kStartPowerButtonMenuAnimationTimeout, this, - &PowerButtonController::OnPowerButtonMenuTimeout); + if (!turn_screen_off_for_tap_) { + StartPowerMenuAnimation(); + } else { + base::TimeDelta timeout = screen_off_when_power_button_down_ + ? kShowMenuWhenScreenOffTimeout + : kShowMenuWhenScreenOnTimeout; + + power_button_menu_timer_.Start( + FROM_HERE, timeout, this, + &PowerButtonController::StartPowerMenuAnimation); + } shutdown_timer_.Start(FROM_HERE, kStartShutdownTimeout, this, &PowerButtonController::OnShutdownTimeout); @@ -183,6 +195,13 @@ display_controller_->SetBacklightsForcedOff(true); LockScreenIfRequired(); } + + // Cancel the menu animation if it's still ongoing when the button is + // released on a clamshell device. + if (!turn_screen_off_for_tap_ && !show_menu_animation_done_) { + static_cast<PowerButtonMenuScreenView*>(menu_widget_->GetContentsView()) + ->ScheduleShowHideAnimation(false); + } } } @@ -305,7 +324,8 @@ void PowerButtonController::OnScreenStateChanged( BacklightsForcedOffSetter::ScreenState screen_state) { - DismissMenu(); + if (screen_state != BacklightsForcedOffSetter::ScreenState::ON) + DismissMenu(); } void PowerButtonController::OnTabletModeStarted() { @@ -332,10 +352,12 @@ DismissMenu(); } -void PowerButtonController::OnPowerButtonMenuTimeout() { +void PowerButtonController::StartPowerMenuAnimation() { if (!menu_widget_) menu_widget_ = CreateMenuWidget(); - menu_widget_->SetContentsView(new PowerButtonMenuScreenView()); + menu_widget_->SetContentsView(new PowerButtonMenuScreenView( + base::BindRepeating(&PowerButtonController::SetShowMenuAnimationDone, + base::Unretained(this)))); menu_widget_->Show(); // Hide cursor, but let it reappear if the mouse moves. @@ -383,4 +405,8 @@ } } +void PowerButtonController::SetShowMenuAnimationDone() { + show_menu_animation_done_ = true; +} + } // namespace ash
diff --git a/ash/system/power/power_button_controller.h b/ash/system/power/power_button_controller.h index 8a684a4..63c365bd 100644 --- a/ash/system/power/power_button_controller.h +++ b/ash/system/power/power_button_controller.h
@@ -135,8 +135,9 @@ // button menu. void StopTimersAndDismissMenu(); - // Called by |power_button_menu_timer_| to start showing power button menu. - void OnPowerButtonMenuTimeout(); + // Starts the power menu animation. Called when a clamshell device's power + // button is pressed or when |power_button_menu_timer_| fires. + void StartPowerMenuAnimation(); // Called by |shutdown_timer_| to turn the screen off and request shutdown. void OnShutdownTimeout(); @@ -153,6 +154,9 @@ // set and locking is possible. void LockScreenIfRequired(); + // Sets |show_menu_animation_done_| to true. + void SetShowMenuAnimationDone(); + // Are the power or lock buttons currently held? bool power_button_down_ = false; bool lock_button_down_ = false; @@ -165,6 +169,9 @@ // external display is connected). bool internal_display_off_and_external_display_on_ = false; + // True after the animation that shows the power menu has finished. + bool show_menu_animation_done_ = false; + // Saves the button type for this power button. ButtonType button_type_ = ButtonType::NORMAL; @@ -213,8 +220,9 @@ // Runs OnShutdownTimeout() to start shutdown. base::OneShotTimer shutdown_timer_; - // Started when the power button is pressed and stopped when it's released. - // Runs OnPowerButtonMenuTimeout() to show the power button menu. + // Started when the power button of convertible/slate/detachable devices is + // pressed and stopped when it's released. Runs StartPowerMenuAnimation() to + // show the power button menu. base::OneShotTimer power_button_menu_timer_; // The fullscreen widget of power button menu.
diff --git a/ash/system/power/power_button_controller_test_api.cc b/ash/system/power/power_button_controller_test_api.cc index 0ebad831..e50c320 100644 --- a/ash/system/power/power_button_controller_test_api.cc +++ b/ash/system/power/power_button_controller_test_api.cc
@@ -102,4 +102,9 @@ controller_->turn_screen_off_for_tap_ = turn_screen_off_for_tap; } +void PowerButtonControllerTestApi::SetShowMenuAnimationDone( + bool show_menu_animation_done) { + controller_->show_menu_animation_done_ = show_menu_animation_done; +} + } // namespace ash
diff --git a/ash/system/power/power_button_controller_test_api.h b/ash/system/power/power_button_controller_test_api.h index ed9680a..8c07d08 100644 --- a/ash/system/power/power_button_controller_test_api.h +++ b/ash/system/power/power_button_controller_test_api.h
@@ -72,6 +72,8 @@ void SetTurnScreenOffForTap(bool turn_screen_off_for_tap); + void SetShowMenuAnimationDone(bool show_menu_animation_done); + private: PowerButtonController* controller_; // Not owned.
diff --git a/ash/system/power/power_button_controller_unittest.cc b/ash/system/power/power_button_controller_unittest.cc index 4d3b6e4f..db46e90 100644 --- a/ash/system/power/power_button_controller_unittest.cc +++ b/ash/system/power/power_button_controller_unittest.cc
@@ -97,7 +97,6 @@ void TappingPowerButtonWhenScreenIsIdleOff() { SendBrightnessChange(0, kUserCause); PressPowerButton(); - EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning()); EXPECT_FALSE(power_manager_client_->backlights_forced_off()); SendBrightnessChange(kNonZeroBrightness, kUserCause); ReleasePowerButton(); @@ -168,12 +167,34 @@ EXPECT_FALSE(turn_screen_off_for_tap_); EXPECT_FALSE(power_manager_client_->backlights_forced_off()); PressPowerButton(); + power_button_test_api_->SetShowMenuAnimationDone(false); + // Start the showing power menu animation immediately as pressing the + // clamshell power button. + EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning()); + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); ReleasePowerButton(); EXPECT_FALSE(power_manager_client_->backlights_forced_off()); + // Start the dimissing power menu animation immediately as releasing the + // clamsehll power button if showing animation hasn't finished. + EXPECT_FALSE(power_button_test_api_->IsMenuOpened()); AdvanceClockToAvoidIgnoring(); // Should turn screen on if screen is off. TappingPowerButtonWhenScreenIsIdleOff(); + + AdvanceClockToAvoidIgnoring(); + // Should not start the dismissing menu animation if showing menu animation + // has finished. + PressPowerButton(); + // Start the showing power menu animation immediately as pressing the + // clamshell power button. + EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning()); + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); + power_button_test_api_->SetShowMenuAnimationDone(true); + ReleasePowerButton(); + EXPECT_FALSE(power_manager_client_->backlights_forced_off()); + // Power button menu should keep opened if showing animation has finished. + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); } // Tests that tapping power button of a device that has tablet mode switch. @@ -182,16 +203,31 @@ // shown. EXPECT_TRUE(turn_screen_off_for_tap_); PressPowerButton(); + // Showing power menu animation hasn't started as power menu timer is running. EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning()); EXPECT_FALSE(power_manager_client_->backlights_forced_off()); + EXPECT_FALSE(power_button_test_api_->IsMenuOpened()); ReleasePowerButton(); EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning()); EXPECT_TRUE(power_manager_client_->backlights_forced_off()); + EXPECT_FALSE(power_button_test_api_->IsMenuOpened()); // Should turn screen on if screen is off. AdvanceClockToAvoidIgnoring(); TappingPowerButtonWhenScreenIsIdleOff(); + // Showing power menu animation should start until power menu timer is + // timeout. + PressPowerButton(); + power_button_test_api_->SetShowMenuAnimationDone(false); + EXPECT_TRUE(power_button_test_api_->TriggerPowerButtonMenuTimeout()); + EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning()); + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); + ReleasePowerButton(); + // Showing animation will continue until show the power button menu even + // release the power button. + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); + // Should not turn screen off if clamshell-like power button behavior is // requested. ForceClamshellPowerButton(); @@ -200,8 +236,15 @@ EXPECT_FALSE(turn_screen_off_for_tap_); EXPECT_FALSE(power_manager_client_->backlights_forced_off()); PressPowerButton(); + power_button_test_api_->SetShowMenuAnimationDone(false); + // Forced clamshell power button device should start showing menu animation + // immediately as pressing the power button. + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); ReleasePowerButton(); EXPECT_FALSE(power_manager_client_->backlights_forced_off()); + // Forced clamshell power button device should start dismissing menu animation + // immediately as releasing the power button. + EXPECT_FALSE(power_button_test_api_->IsMenuOpened()); } // Tests that release power button after menu is opened but before trigger
diff --git a/ash/system/power/power_button_menu_screen_view.cc b/ash/system/power/power_button_menu_screen_view.cc index d4e3198..72bc31a 100644 --- a/ash/system/power/power_button_menu_screen_view.cc +++ b/ash/system/power/power_button_menu_screen_view.cc
@@ -30,7 +30,8 @@ : public views::View, public ui::ImplicitAnimationObserver { public: - PowerButtonMenuBackgroundView() { + PowerButtonMenuBackgroundView(base::RepeatingClosure show_animation_done) + : show_animation_done_(show_animation_done) { SetPaintToLayer(ui::LAYER_SOLID_COLOR); layer()->SetColor(kShieldColor); } @@ -38,15 +39,20 @@ ~PowerButtonMenuBackgroundView() override = default; void OnImplicitAnimationsCompleted() override { + PowerButtonController* power_button_controller = + Shell::Get()->power_button_controller(); if (layer()->opacity() == 0.f) { SetVisible(false); - Shell::Get()->power_button_controller()->DismissMenu(); + power_button_controller->DismissMenu(); } + + if (layer()->opacity() == kPowerButtonMenuOpacity) + show_animation_done_.Run(); } void ScheduleShowHideAnimation(bool show) { - layer()->GetAnimator()->StopAnimating(); - layer()->SetOpacity(show ? 0.f : kPowerButtonMenuOpacity); + layer()->GetAnimator()->AbortAllAnimations(); + layer()->SetOpacity(show ? 0.f : layer()->opacity()); ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); animation.AddObserver(this); @@ -59,11 +65,16 @@ } private: + // A callback for when the animation that shows the power menu has finished. + base::RepeatingClosure show_animation_done_; + DISALLOW_COPY_AND_ASSIGN(PowerButtonMenuBackgroundView); }; -PowerButtonMenuScreenView::PowerButtonMenuScreenView() { - power_button_screen_background_shield_ = new PowerButtonMenuBackgroundView(); +PowerButtonMenuScreenView::PowerButtonMenuScreenView( + base::RepeatingClosure show_animation_done) { + power_button_screen_background_shield_ = + new PowerButtonMenuBackgroundView(show_animation_done); AddChildView(power_button_screen_background_shield_); power_button_menu_view_ = new PowerButtonMenuView();
diff --git a/ash/system/power/power_button_menu_screen_view.h b/ash/system/power/power_button_menu_screen_view.h index d906cb6a..0118b78 100644 --- a/ash/system/power/power_button_menu_screen_view.h +++ b/ash/system/power/power_button_menu_screen_view.h
@@ -19,7 +19,10 @@ class ASH_EXPORT PowerButtonMenuScreenView : public views::View, public display::DisplayObserver { public: - PowerButtonMenuScreenView(); + // |show_animation_done| is a callback for when the animation that shows the + // power menu has finished. + explicit PowerButtonMenuScreenView( + base::RepeatingClosure show_animation_done); ~PowerButtonMenuScreenView() override; PowerButtonMenuView* power_button_menu_view() const {
diff --git a/ash/system/power/power_button_menu_view.cc b/ash/system/power/power_button_menu_view.cc index 8627d73..d7caccc 100644 --- a/ash/system/power/power_button_menu_view.cc +++ b/ash/system/power/power_button_menu_view.cc
@@ -38,12 +38,12 @@ PowerButtonMenuView::~PowerButtonMenuView() = default; void PowerButtonMenuView::ScheduleShowHideAnimation(bool show) { - // Stop any previous animation. - layer()->GetAnimator()->StopAnimating(); + // Cancel any previous animation. + layer()->GetAnimator()->AbortAllAnimations(); // Set initial state. SetVisible(true); - layer()->SetOpacity(show ? 0.f : 1.0f); + layer()->SetOpacity(show ? 0.f : layer()->opacity()); ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); animation.AddObserver(this);
diff --git a/ash/system/tray_accessibility.h b/ash/system/tray_accessibility.h index 99e010e..410c41da 100644 --- a/ash/system/tray_accessibility.h +++ b/ash/system/tray_accessibility.h
@@ -29,6 +29,7 @@ namespace ash { class HoverHighlightView; class SystemTrayItem; +class TrayAccessibilityTest; namespace tray { @@ -41,6 +42,7 @@ void OnAccessibilityStatusChanged(); private: + friend class ::ash::TrayAccessibilityTest; friend class chromeos::TrayAccessibilityTest; // TrayDetailsView: @@ -104,6 +106,7 @@ ~TrayAccessibility() override; private: + friend class TrayAccessibilityTest; friend class chromeos::TrayAccessibilityTest; void SetTrayIconVisible(bool visible);
diff --git a/ash/system/tray_accessibility_unittest.cc b/ash/system/tray_accessibility_unittest.cc index 5c28402..c1a41301 100644 --- a/ash/system/tray_accessibility_unittest.cc +++ b/ash/system/tray_accessibility_unittest.cc
@@ -34,7 +34,101 @@ ->SetBoolean(prefs::kAccessibilityLargeCursorEnabled, enabled); } -using TrayAccessibilityTest = AshTestBase; +} // namespace + +class TrayAccessibilityTest : public AshTestBase { + public: + TrayAccessibilityTest() = default; + ~TrayAccessibilityTest() override = default; + + // testing::Test: + void SetUp() override { + AshTestBase::SetUp(); + tray_item_ = SystemTrayTestApi(Shell::Get()->GetPrimarySystemTray()) + .tray_accessibility(); + } + + // These functions are members so TrayAccessibility can friend the test. + bool CreateDetailedMenu() { + tray_item_->ShowDetailedView(0); + return tray_item_->detailed_menu_ != nullptr; + } + + void CloseDetailMenu() { + ASSERT_TRUE(tray_item_->detailed_menu_); + tray_item_->OnDetailedViewDestroyed(); + ASSERT_FALSE(tray_item_->detailed_menu_); + } + + bool IsSpokenFeedbackMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->spoken_feedback_view_; + } + + bool IsSelectToSpeakShownOnDetailMenu() const { + return tray_item_->detailed_menu_->select_to_speak_view_; + } + + bool IsHighContrastMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->high_contrast_view_; + } + + bool IsScreenMagnifierMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->screen_magnifier_view_; + } + + bool IsLargeCursorMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->large_cursor_view_; + } + + bool IsAutoclickMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->autoclick_view_; + } + + bool IsVirtualKeyboardMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->virtual_keyboard_view_; + } + + bool IsMonoAudioMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->mono_audio_view_; + } + + bool IsCaretHighlightMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->caret_highlight_view_; + } + + bool IsHighlightMouseCursorMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->highlight_mouse_cursor_view_; + } + + bool IsHighlightKeyboardFocusMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->highlight_keyboard_focus_view_; + } + + bool IsStickyKeysMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->sticky_keys_view_; + } + + bool IsTapDraggingMenuShownOnDetailMenu() const { + return tray_item_->detailed_menu_->tap_dragging_view_; + } + + // In material design we show the help button but theme it as disabled if + // it is not possible to load the help page. + bool IsHelpAvailableOnDetailMenu() { + return tray_item_->detailed_menu_->help_view_->state() == + views::Button::STATE_NORMAL; + } + + // In material design we show the settings button but theme it as disabled if + // it is not possible to load the settings page. + bool IsSettingsAvailableOnDetailMenu() { + return tray_item_->detailed_menu_->settings_view_->state() == + views::Button::STATE_NORMAL; + } + + private: + TrayAccessibility* tray_item_; +}; // Tests that the icon becomes visible when the tray menu toggles a feature. TEST_F(TrayAccessibilityTest, VisibilityFromMenu) { @@ -134,5 +228,68 @@ EXPECT_EQ(kChromeVoxEnabled, (*notifications.begin())->message()); } -} // namespace +TEST_F(TrayAccessibilityTest, CheckMenuVisibilityOnDetailMenu) { + // Except help & settings, others should be kept the same + // in LOGIN | NOT LOGIN | LOCKED. https://crbug.com/632107. + EXPECT_TRUE(CreateDetailedMenu()); + EXPECT_TRUE(IsSpokenFeedbackMenuShownOnDetailMenu()); + EXPECT_TRUE(IsSelectToSpeakShownOnDetailMenu()); + EXPECT_TRUE(IsHighContrastMenuShownOnDetailMenu()); + EXPECT_TRUE(IsScreenMagnifierMenuShownOnDetailMenu()); + EXPECT_TRUE(IsAutoclickMenuShownOnDetailMenu()); + EXPECT_TRUE(IsVirtualKeyboardMenuShownOnDetailMenu()); + EXPECT_TRUE(IsHelpAvailableOnDetailMenu()); + EXPECT_TRUE(IsSettingsAvailableOnDetailMenu()); + EXPECT_TRUE(IsLargeCursorMenuShownOnDetailMenu()); + EXPECT_TRUE(IsMonoAudioMenuShownOnDetailMenu()); + EXPECT_TRUE(IsCaretHighlightMenuShownOnDetailMenu()); + EXPECT_TRUE(IsHighlightMouseCursorMenuShownOnDetailMenu()); + EXPECT_TRUE(IsHighlightKeyboardFocusMenuShownOnDetailMenu()); + EXPECT_TRUE(IsStickyKeysMenuShownOnDetailMenu()); + EXPECT_TRUE(IsTapDraggingMenuShownOnDetailMenu()); + CloseDetailMenu(); + + // Simulate screen lock. + BlockUserSession(BLOCKED_BY_LOCK_SCREEN); + EXPECT_TRUE(CreateDetailedMenu()); + EXPECT_TRUE(IsSpokenFeedbackMenuShownOnDetailMenu()); + EXPECT_TRUE(IsSelectToSpeakShownOnDetailMenu()); + EXPECT_TRUE(IsHighContrastMenuShownOnDetailMenu()); + EXPECT_TRUE(IsScreenMagnifierMenuShownOnDetailMenu()); + EXPECT_TRUE(IsAutoclickMenuShownOnDetailMenu()); + EXPECT_TRUE(IsVirtualKeyboardMenuShownOnDetailMenu()); + EXPECT_FALSE(IsHelpAvailableOnDetailMenu()); + EXPECT_FALSE(IsSettingsAvailableOnDetailMenu()); + EXPECT_TRUE(IsLargeCursorMenuShownOnDetailMenu()); + EXPECT_TRUE(IsMonoAudioMenuShownOnDetailMenu()); + EXPECT_TRUE(IsCaretHighlightMenuShownOnDetailMenu()); + EXPECT_TRUE(IsHighlightMouseCursorMenuShownOnDetailMenu()); + EXPECT_TRUE(IsHighlightKeyboardFocusMenuShownOnDetailMenu()); + EXPECT_TRUE(IsStickyKeysMenuShownOnDetailMenu()); + EXPECT_TRUE(IsTapDraggingMenuShownOnDetailMenu()); + CloseDetailMenu(); + UnblockUserSession(); + + // Simulate adding multiprofile user. + BlockUserSession(BLOCKED_BY_USER_ADDING_SCREEN); + EXPECT_TRUE(CreateDetailedMenu()); + EXPECT_TRUE(IsSpokenFeedbackMenuShownOnDetailMenu()); + EXPECT_TRUE(IsSelectToSpeakShownOnDetailMenu()); + EXPECT_TRUE(IsHighContrastMenuShownOnDetailMenu()); + EXPECT_TRUE(IsScreenMagnifierMenuShownOnDetailMenu()); + EXPECT_TRUE(IsAutoclickMenuShownOnDetailMenu()); + EXPECT_TRUE(IsVirtualKeyboardMenuShownOnDetailMenu()); + EXPECT_FALSE(IsHelpAvailableOnDetailMenu()); + EXPECT_FALSE(IsSettingsAvailableOnDetailMenu()); + EXPECT_TRUE(IsLargeCursorMenuShownOnDetailMenu()); + EXPECT_TRUE(IsMonoAudioMenuShownOnDetailMenu()); + EXPECT_TRUE(IsCaretHighlightMenuShownOnDetailMenu()); + EXPECT_TRUE(IsHighlightMouseCursorMenuShownOnDetailMenu()); + EXPECT_TRUE(IsHighlightKeyboardFocusMenuShownOnDetailMenu()); + EXPECT_TRUE(IsStickyKeysMenuShownOnDetailMenu()); + EXPECT_TRUE(IsTapDraggingMenuShownOnDetailMenu()); + CloseDetailMenu(); + UnblockUserSession(); +} + } // namespace ash
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc index cb26375..8bdd4aa 100644 --- a/ash/wm/overview/window_selector.cc +++ b/ash/wm/overview/window_selector.cc
@@ -18,6 +18,7 @@ #include "ash/screen_util.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/overview/overview_utils.h" #include "ash/wm/overview/overview_window_drag_controller.h" @@ -37,6 +38,8 @@ #include "base/metrics/user_metrics.h" #include "base/threading/thread_task_runner_handle.h" #include "components/vector_icons/vector_icons.h" +#include "ui/accessibility/ax_enums.mojom.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/compositor/layer.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/display/screen.h" @@ -45,6 +48,7 @@ #include "ui/gfx/image/image_skia.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/skia_util.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/border.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/textfield/textfield.h" @@ -194,6 +198,8 @@ textfield->SetTextColor(IsNewOverviewUi() ? kTextFilterTextColor : kOldTextFilterTextColor); textfield->SetFontList(font_list); + textfield->SetAccessibleName(l10n_util::GetStringUTF16( + IDS_ASH_WINDOW_SELECTOR_INPUT_FILTER_ACCESSIBLE_NAME)); views::ImageView* image_view = new views::ImageView(); image_view->SetImage(image);
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc index 61b5ff0..b43ddd6 100644 --- a/ash/wm/overview/window_selector_item.cc +++ b/ash/wm/overview/window_selector_item.cc
@@ -1304,6 +1304,19 @@ widget_window->parent()->StackChildAtTop(widget_window); widget_window->parent()->StackChildBelow(window, widget_window); } + + // If split view mode is actvie and there is already a snapped window, stack + // this item's window below the snapped window. Note: this should be temporary + // for M66, see https://crbug.com/809298 for details. + if (Shell::Get()->IsSplitViewModeActive()) { + aura::Window* snapped_window = + Shell::Get()->split_view_controller()->GetDefaultSnappedWindow(); + if (widget_window && widget_window->parent() == window->parent() && + widget_window->parent() == snapped_window->parent()) { + widget_window->parent()->StackChildBelow(widget_window, snapped_window); + widget_window->parent()->StackChildBelow(window, widget_window); + } + } } void WindowSelectorItem::EndDrag() {
diff --git a/ash/wm/workspace/multi_window_resize_controller.cc b/ash/wm/workspace/multi_window_resize_controller.cc index 48131d7..487ccc9 100644 --- a/ash/wm/workspace/multi_window_resize_controller.cc +++ b/ash/wm/workspace/multi_window_resize_controller.cc
@@ -226,8 +226,8 @@ } windows_ = windows; - windows_.window1->AddObserver(this); - windows_.window2->AddObserver(this); + StartObserving(windows_.window1); + StartObserving(windows_.window2); show_location_in_parent_ = ConvertPointToTarget(window, window->parent(), point_in_window); show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kShowDelayMS), @@ -240,11 +240,11 @@ return; // Ignore hides while actively resizing. if (windows_.window1) { - windows_.window1->RemoveObserver(this); + StopObserving(windows_.window1); windows_.window1 = nullptr; } if (windows_.window2) { - windows_.window2->RemoveObserver(this); + StopObserving(windows_.window2); windows_.window2 = nullptr; } @@ -254,7 +254,7 @@ return; for (size_t i = 0; i < windows_.other_windows.size(); ++i) - windows_.other_windows[i]->RemoveObserver(this); + StopObserving(windows_.other_windows[i]); mouse_watcher_.reset(); resize_widget_.reset(); windows_ = ResizeWindows(); @@ -270,6 +270,16 @@ Hide(); } +void MultiWindowResizeController::OnPostWindowStateTypeChange( + wm::WindowState* window_state, + mojom::WindowStateType old_type) { + if (window_state->IsMaximized() || window_state->IsFullscreen() || + window_state->IsMinimized()) { + window_resizer_.reset(); + Hide(); + } +} + MultiWindowResizeController::ResizeWindows MultiWindowResizeController::DetermineWindowsFromScreenPoint( aura::Window* window) const { @@ -416,6 +426,16 @@ } } +void MultiWindowResizeController::StartObserving(aura::Window* window) { + window->AddObserver(this); + wm::GetWindowState(window)->AddObserver(this); +} + +void MultiWindowResizeController::StopObserving(aura::Window* window) { + window->RemoveObserver(this); + wm::GetWindowState(window)->RemoveObserver(this); +} + void MultiWindowResizeController::ShowIfValidMouseLocation() { if (DetermineWindowsFromScreenPoint(windows_.window1).Equals(windows_) || DetermineWindowsFromScreenPoint(windows_.window2).Equals(windows_)) { @@ -467,7 +487,7 @@ FindWindowsTouching(windows_.window2, windows_.direction, &windows_.other_windows); for (size_t i = 0; i < windows_.other_windows.size(); ++i) { - windows_.other_windows[i]->AddObserver(this); + StartObserving(windows_.other_windows[i]); windows.push_back(windows_.other_windows[i]); } int component = windows_.direction == LEFT_RIGHT ? HTRIGHT : HTBOTTOM; @@ -510,7 +530,7 @@ // the |other_windows|. If we start another resize we'll recalculate the // |other_windows| and invoke AddObserver() as necessary. for (size_t i = 0; i < windows_.other_windows.size(); ++i) - windows_.other_windows[i]->RemoveObserver(this); + StopObserving(windows_.other_windows[i]); windows_.other_windows.clear(); CreateMouseWatcher();
diff --git a/ash/wm/workspace/multi_window_resize_controller.h b/ash/wm/workspace/multi_window_resize_controller.h index 1b98294..43c47ea 100644 --- a/ash/wm/workspace/multi_window_resize_controller.h +++ b/ash/wm/workspace/multi_window_resize_controller.h
@@ -9,6 +9,7 @@ #include <vector> #include "ash/ash_export.h" +#include "ash/wm/window_state_observer.h" #include "base/macros.h" #include "base/timer/timer.h" #include "ui/aura/window_observer.h" @@ -34,7 +35,8 @@ // MultiWindowResizeController is driven by WorkspaceEventFilter. class ASH_EXPORT MultiWindowResizeController : public views::MouseWatcherListener, - public aura::WindowObserver { + public aura::WindowObserver, + public wm::WindowStateObserver { public: MultiWindowResizeController(); ~MultiWindowResizeController() override; @@ -46,12 +48,16 @@ // Hides the resize widget. void Hide(); - // MouseWatcherListenre overrides: + // MouseWatcherListener: void MouseMovedOutOfHost() override; - // WindowObserver overrides: + // WindowObserver: void OnWindowDestroying(aura::Window* window) override; + // wm::WindowStateObserver: + void OnPostWindowStateTypeChange(wm::WindowState* window_state, + mojom::WindowStateType old_type) override; + private: friend class MultiWindowResizeControllerTest; @@ -112,6 +118,10 @@ Direction direction, std::vector<aura::Window*>* others) const; + // Starts/Stops observing |window|. + void StartObserving(aura::Window* window); + void StopObserving(aura::Window* window); + // Shows the resizer if the mouse is still at a valid location. This is called // from the |show_timer_|. void ShowIfValidMouseLocation();
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc index a1ca3b09..f94350b 100644 --- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc +++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -9,6 +9,7 @@ #include "ash/shell.h" #include "ash/shell_test_api.h" #include "ash/test/ash_test_base.h" +#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_state_delegate.h" #include "ash/wm/window_util.h" @@ -17,8 +18,10 @@ #include "ash/wm/workspace_controller.h" #include "ash/wm/workspace_controller_test_api.h" #include "base/stl_util.h" +#include "ui/aura/client/aura_constants.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" +#include "ui/base/class_property.h" #include "ui/base/hit_test.h" #include "ui/events/test/event_generator.h" #include "ui/views/widget/widget.h" @@ -351,6 +354,57 @@ EXPECT_FALSE(IsShowing()); } +// Tests that if the resized window is maximized/fullscreen/minimized, the +// resizer widget should be dismissed. +TEST_F(MultiWindowResizeControllerTest, WindowStateChange) { + aura::test::TestWindowDelegate delegate1; + std::unique_ptr<aura::Window> w1(CreateTestWindowInShellWithDelegate( + &delegate1, -1, gfx::Rect(0, 0, 100, 100))); + delegate1.set_window_component(HTRIGHT); + aura::test::TestWindowDelegate delegate2; + std::unique_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegate( + &delegate2, -2, gfx::Rect(100, 0, 100, 100))); + delegate2.set_window_component(HTLEFT); + + ui::test::EventGenerator& generator = GetEventGenerator(); + gfx::Point w1_center_in_screen = w1->GetBoundsInScreen().CenterPoint(); + generator.MoveMouseTo(w1_center_in_screen); + ShowNow(); + EXPECT_TRUE(IsShowing()); + + // Maxmize one window should dismiss the resizer. + w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); + EXPECT_FALSE(IsShowing()); + + w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); + generator.MoveMouseTo(w1_center_in_screen); + ShowNow(); + EXPECT_TRUE(IsShowing()); + + // Entering Fullscreen should dismiss the resizer. + w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); + EXPECT_FALSE(IsShowing()); + + w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); + generator.MoveMouseTo(w1_center_in_screen); + ShowNow(); + EXPECT_TRUE(IsShowing()); + + // Minimize one window should dimiss the resizer. + w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); + EXPECT_FALSE(IsShowing()); + + w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); + generator.MoveMouseTo(w1_center_in_screen); + ShowNow(); + EXPECT_TRUE(IsShowing()); + + // When entering tablet mode, the windows will be maximized, thus the resizer + // widget should be dismissed. + Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true); + EXPECT_FALSE(IsShowing()); +} + namespace { class TestWindowStateDelegate : public wm::WindowStateDelegate {
diff --git a/base/atomicops.h b/base/atomicops.h index 3428fe8..4d8510e8 100644 --- a/base/atomicops.h +++ b/base/atomicops.h
@@ -145,8 +145,8 @@ } // namespace base #if defined(OS_WIN) -// TODO(jfb): The MSVC header includes windows.h, which other files end up -// relying on. Fix this as part of crbug.com/559247. +// TODO(jfb): Try to use base/atomicops_internals_portable.h everywhere. +// https://crbug.com/559247. # include "base/atomicops_internals_x86_msvc.h" #else # include "base/atomicops_internals_portable.h"
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h index 7150815..52adb693 100644 --- a/base/process/process_metrics.h +++ b/base/process/process_metrics.h
@@ -154,7 +154,7 @@ #if defined(OS_LINUX) || defined(OS_ANDROID) // Resident Set Size is a Linux/Android specific memory concept. Do not // attempt to extend this to other platforms. - BASE_EXPORT size_t GetRSS() const; + BASE_EXPORT size_t GetResidentSetSize() const; #endif #if defined(OS_MACOSX)
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc index e388fe30..27c1496 100644 --- a/base/process/process_metrics_linux.cc +++ b/base/process/process_metrics_linux.cc
@@ -211,7 +211,7 @@ return WrapUnique(new ProcessMetrics(process)); } -size_t ProcessMetrics::GetRSS() const { +size_t ProcessMetrics::GetResidentSetSize() const { return internal::ReadProcStatsAndGetFieldAsSizeT(process_, internal::VM_RSS) * getpagesize(); }
diff --git a/base/win/win_includes_unittest.cc b/base/win/win_includes_unittest.cc index 73b7b55..20c6cbc 100644 --- a/base/win/win_includes_unittest.cc +++ b/base/win/win_includes_unittest.cc
@@ -5,6 +5,7 @@ // This file ensures that these header files don't include Windows.h and can // compile without including Windows.h. This helps to improve compile times. +#include "base/atomicops.h" #include "base/files/file_util.h" #include "base/files/platform_file.h" #include "base/process/process_handle.h"
diff --git a/cc/input/scrollbar_animation_controller.cc b/cc/input/scrollbar_animation_controller.cc index 0ee16d5..55f97f09 100644 --- a/cc/input/scrollbar_animation_controller.cc +++ b/cc/input/scrollbar_animation_controller.cc
@@ -54,6 +54,7 @@ show_scrollbars_on_scroll_gesture_(false), need_thinning_animation_(false), is_mouse_down_(false), + tickmarks_showing_(false), weak_factory_(this) {} ScrollbarAnimationController::ScrollbarAnimationController( @@ -76,6 +77,7 @@ show_scrollbars_on_scroll_gesture_(true), need_thinning_animation_(true), is_mouse_down_(false), + tickmarks_showing_(false), weak_factory_(this) { vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create( scroll_element_id, ScrollbarOrientation::VERTICAL, client, @@ -194,11 +196,15 @@ if (need_thinning_animation_ && MouseIsNearAnyScrollbar()) return; - if (has_scrolled) + if (has_scrolled && !tickmarks_showing_) PostDelayedAnimation(FADE_OUT); } void ScrollbarAnimationController::DidScrollUpdate() { + UpdateScrollbarState(); +} + +void ScrollbarAnimationController::UpdateScrollbarState() { if (need_thinning_animation_ && Captured()) return; @@ -209,10 +215,14 @@ // As an optimization, we avoid spamming fade delay tasks during active fast // scrolls. But if we're not within one, we need to post every scroll update. if (!currently_scrolling_) { - // We don't fade out scrollbar if they need thinning animation and mouse is - // near. - if (!need_thinning_animation_ || !MouseIsNearAnyScrollbar()) + // We don't fade out scrollbar if they need thinning animation (Aura + // Overlay) and mouse is near or tickmarks show. + if (need_thinning_animation_) { + if (!MouseIsNearAnyScrollbar() && !tickmarks_showing_) + PostDelayedAnimation(FADE_OUT); + } else { PostDelayedAnimation(FADE_OUT); + } } else { show_in_fast_scroll_ = true; } @@ -225,11 +235,22 @@ void ScrollbarAnimationController::WillUpdateScroll() { if (show_scrollbars_on_scroll_gesture_) - DidScrollUpdate(); + UpdateScrollbarState(); } void ScrollbarAnimationController::DidRequestShowFromMainThread() { - DidScrollUpdate(); + UpdateScrollbarState(); +} + +void ScrollbarAnimationController::UpdateTickmarksVisibility(bool show) { + if (!need_thinning_animation_) + return; + + if (tickmarks_showing_ == show) + return; + + tickmarks_showing_ = show; + UpdateScrollbarState(); } void ScrollbarAnimationController::DidMouseDown() { @@ -267,7 +288,7 @@ vertical_controller_->DidMouseUp(); horizontal_controller_->DidMouseUp(); - if (!MouseIsNearAnyScrollbar() && !ScrollbarsHidden()) + if (!MouseIsNearAnyScrollbar() && !ScrollbarsHidden() && !tickmarks_showing_) PostDelayedAnimation(FADE_OUT); } @@ -281,7 +302,7 @@ delayed_scrollbar_animation_.Cancel(); need_trigger_scrollbar_fade_in_ = false; - if (ScrollbarsHidden() || Captured()) + if (ScrollbarsHidden() || Captured() || tickmarks_showing_) return; PostDelayedAnimation(FADE_OUT); @@ -297,7 +318,7 @@ vertical_controller_->DidMouseMove(device_viewport_point); horizontal_controller_->DidMouseMove(device_viewport_point); - if (Captured()) { + if (Captured() || tickmarks_showing_) { DCHECK(!ScrollbarsHidden()); return; }
diff --git a/cc/input/scrollbar_animation_controller.h b/cc/input/scrollbar_animation_controller.h index 64bf2b6..9473b41 100644 --- a/cc/input/scrollbar_animation_controller.h +++ b/cc/input/scrollbar_animation_controller.h
@@ -84,6 +84,8 @@ // ScrollableArea::showOverlayScrollbars). void DidRequestShowFromMainThread(); + void UpdateTickmarksVisibility(bool show); + // These methods are public for testing. bool MouseIsOverScrollbarThumb(ScrollbarOrientation orientation) const; bool MouseIsNearScrollbarThumb(ScrollbarOrientation orientation) const; @@ -114,6 +116,10 @@ SingleScrollbarAnimationControllerThinning& GetScrollbarAnimationController( ScrollbarOrientation) const; + // Any scrollbar state update would show scrollbar hen post the delay fade out + // if needed. + void UpdateScrollbarState(); + // Returns how far through the animation we are as a progress value from // 0 to 1. float AnimationProgressAtTime(base::TimeTicks now); @@ -156,6 +162,8 @@ bool is_mouse_down_; + bool tickmarks_showing_; + std::unique_ptr<SingleScrollbarAnimationControllerThinning> vertical_controller_; std::unique_ptr<SingleScrollbarAnimationControllerThinning>
diff --git a/cc/input/scrollbar_animation_controller_unittest.cc b/cc/input/scrollbar_animation_controller_unittest.cc index b142096e..9749fc7 100644 --- a/cc/input/scrollbar_animation_controller_unittest.cc +++ b/cc/input/scrollbar_animation_controller_unittest.cc
@@ -1318,6 +1318,54 @@ client_.start_fade().IsCancelled()); } +// Ensure Aura Overlay Scrollbars shows and did not fade out when tickmarks show +// and fade out when tickmarks hide. +TEST_F(ScrollbarAnimationControllerAuraOverlayTest, TickmakrsShowHide) { + base::TimeTicks time; + time += base::TimeDelta::FromSeconds(1); + + // Overlay Scrollbar hidden at beginnging. + EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden()); + EXPECT_TRUE(client_.start_fade().is_null() || + client_.start_fade().IsCancelled()); + + // Scrollbars show when tickmarks show. + scrollbar_controller_->UpdateTickmarksVisibility(true); + EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden()); + EXPECT_TRUE(client_.start_fade().is_null() || + client_.start_fade().IsCancelled()); + + // Scroll update, no delay fade animation. + scrollbar_controller_->DidScrollUpdate(); + EXPECT_TRUE(client_.start_fade().is_null() || + client_.start_fade().IsCancelled()); + + // Scroll update with phase, no delay fade animation. + scrollbar_controller_->DidScrollBegin(); + scrollbar_controller_->DidScrollUpdate(); + EXPECT_TRUE(client_.start_fade().is_null() || + client_.start_fade().IsCancelled()); + scrollbar_controller_->DidScrollEnd(); + EXPECT_TRUE(client_.start_fade().is_null() || + client_.start_fade().IsCancelled()); + + // Move mouse, no delay fade animation. + scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0)); + EXPECT_TRUE(client_.start_fade().is_null() || + client_.start_fade().IsCancelled()); + + // Mouse leave, no delay fade animation. + scrollbar_controller_->DidMouseLeave(); + EXPECT_TRUE(client_.start_fade().is_null() || + client_.start_fade().IsCancelled()); + + // Scrollbars fade out animation has enqueued when tickmarks hide. + scrollbar_controller_->UpdateTickmarksVisibility(false); + EXPECT_FALSE(client_.start_fade().is_null()); + EXPECT_FALSE(client_.start_fade().IsCancelled()); + EXPECT_EQ(kFadeDelay, client_.delay()); +} + class ScrollbarAnimationControllerAndroidTest : public testing::Test, public ScrollbarAnimationControllerClient {
diff --git a/cc/layers/painted_overlay_scrollbar_layer_impl.cc b/cc/layers/painted_overlay_scrollbar_layer_impl.cc index 79724d1..4f5a61e 100644 --- a/cc/layers/painted_overlay_scrollbar_layer_impl.cc +++ b/cc/layers/painted_overlay_scrollbar_layer_impl.cc
@@ -232,4 +232,8 @@ return "cc::PaintedOverlayScrollbarLayerImpl"; } +bool PaintedOverlayScrollbarLayerImpl::HasFindInPageTickmarks() const { + return track_ui_resource_id_ != 0; +} + } // namespace cc
diff --git a/cc/layers/painted_overlay_scrollbar_layer_impl.h b/cc/layers/painted_overlay_scrollbar_layer_impl.h index 1152992ad..ca436bd 100644 --- a/cc/layers/painted_overlay_scrollbar_layer_impl.h +++ b/cc/layers/painted_overlay_scrollbar_layer_impl.h
@@ -51,6 +51,8 @@ track_ui_resource_id_ = uid; } + bool HasFindInPageTickmarks() const override; + protected: PaintedOverlayScrollbarLayerImpl(LayerTreeImpl* tree_impl, int id,
diff --git a/cc/layers/scrollbar_layer_impl_base.cc b/cc/layers/scrollbar_layer_impl_base.cc index 1758c6f..6a0f9eb6 100644 --- a/cc/layers/scrollbar_layer_impl_base.cc +++ b/cc/layers/scrollbar_layer_impl_base.cc
@@ -270,4 +270,8 @@ return layer_tree_impl()->settings().scrollbar_animator; } +bool ScrollbarLayerImplBase::HasFindInPageTickmarks() const { + return false; +} + } // namespace cc
diff --git a/cc/layers/scrollbar_layer_impl_base.h b/cc/layers/scrollbar_layer_impl_base.h index df9b3d1..8c38e0e 100644 --- a/cc/layers/scrollbar_layer_impl_base.h +++ b/cc/layers/scrollbar_layer_impl_base.h
@@ -64,6 +64,10 @@ virtual LayerTreeSettings::ScrollbarAnimator GetScrollbarAnimator() const; + // Only PaintedOverlayScrollbar(Aura Overlay Scrollbar) need to know + // tickmarks's state. + virtual bool HasFindInPageTickmarks() const; + protected: ScrollbarLayerImplBase(LayerTreeImpl* tree_impl, int id,
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc index 87026c7..0e0378a 100644 --- a/cc/resources/video_resource_updater.cc +++ b/cc/resources/video_resource_updater.cc
@@ -338,6 +338,7 @@ bool texture_needs_rgb_conversion = !software_compositor && output_resource_format == viz::ResourceFormat::RGBA_8888; + size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB @@ -348,6 +349,11 @@ output_resource_format = viz::RGBA_8888; output_plane_count = 1; bits_per_channel = 8; + + // The YUV to RGB conversion will be performed when we convert + // from single-channel textures to an RGBA texture via + // ConvertVideoFrameToRGBPixels below. + output_color_space = output_color_space.GetAsFullRangeRGB(); } // Drop recycled resources that are the wrong format.
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index 4139dfa..8f5409f 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc
@@ -816,7 +816,6 @@ did_draw_ = true; active_tree_needs_first_draw_ = false; - did_draw_in_last_frame_ = true; last_frame_number_draw_performed_ = current_frame_number_; if (forced_redraw_state_ == ForcedRedrawOnTimeoutState::WAITING_FOR_DRAW) @@ -863,6 +862,10 @@ void SchedulerStateMachine::WillDraw() { DCHECK(!did_draw_); WillDrawInternal(); + // Set this to true to proactively request a new BeginFrame. We can't set this + // in WillDrawInternal because AbortDraw calls WillDrawInternal but shouldn't + // request another frame. + did_draw_in_last_frame_ = true; } void SchedulerStateMachine::DidDraw(DrawResult draw_result) { @@ -910,11 +913,6 @@ did_invalidate_layer_tree_frame_sink_ = true; last_frame_number_invalidate_layer_tree_frame_sink_performed_ = current_frame_number_; - - // The synchronous compositor makes no guarantees about a draw coming in after - // an invalidate so clear any flags that would cause the compositor's pipeline - // to stall. - active_tree_needs_first_draw_ = false; // blocks commit if true } void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency(
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 9069538..a4e1fddb 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -2555,7 +2555,10 @@ task_runner().RunPendingTasks(); // Run posted deadline. // Sync tree should be forced to activate. - EXPECT_ACTIONS("ScheduledActionActivateSyncTree"); + // Pausing the begin frame source aborts the draw. Then + // ProactiveBeginFrameWanted is no longer true, so the scheduler stops + // listening for begin frames. + EXPECT_ACTIONS("ScheduledActionActivateSyncTree", "RemoveObserver(this)"); } // Tests to ensure frame sources can be successfully changed while drawing. @@ -2977,7 +2980,10 @@ task_runner().RunPendingTasks(); // Run posted deadline. // Should not try to schedule a draw. (ScheduledActionDrawIfPossible should // not appear.) - EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame"); + // When the frame is aborted, the scheduler does not ask for a proactive begin + // frame, so stop listening for begin frames. + EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame", + "RemoveObserver(this)"); EXPECT_EQ(0, client_->num_draws()); scheduler_->SetNeedsRedraw(); @@ -3063,49 +3069,6 @@ client_->Reset(); } -TEST_F(SchedulerTest, SynchronousCompositorDoubleCommitWithoutDraw) { - scheduler_settings_.using_synchronous_renderer_compositor = true; - SetUpScheduler(EXTERNAL_BFS); - - scheduler_->SetNeedsBeginMainFrame(); - EXPECT_ACTIONS("AddObserver(this)"); - client_->Reset(); - - // Next vsync. - AdvanceFrame(); - EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame"); - EXPECT_FALSE(client_->IsInsideBeginImplFrame()); - client_->Reset(); - - scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks()); - EXPECT_NO_ACTION(); - - scheduler_->NotifyReadyToCommit(); - EXPECT_ACTIONS("ScheduledActionCommit"); - client_->Reset(); - - scheduler_->NotifyReadyToActivate(); - EXPECT_ACTIONS("ScheduledActionActivateSyncTree"); - client_->Reset(); - - // Ask for another commit. - scheduler_->SetNeedsBeginMainFrame(); - - AdvanceFrame(); - EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", - "ScheduledActionInvalidateLayerTreeFrameSink"); - EXPECT_FALSE(client_->IsInsideBeginImplFrame()); - client_->Reset(); - - scheduler_->NotifyBeginMainFrameStarted(now_src()->NowTicks()); - EXPECT_NO_ACTION(); - - // Allow new commit even though previous commit hasn't been drawn. - scheduler_->NotifyReadyToCommit(); - EXPECT_ACTIONS("ScheduledActionCommit"); - client_->Reset(); -} - class SchedulerClientSetNeedsPrepareTilesOnDraw : public FakeSchedulerClient { public: SchedulerClientSetNeedsPrepareTilesOnDraw() : FakeSchedulerClient() {}
diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc index 77d3bca..145c765 100644 --- a/cc/test/test_in_process_context_provider.cc +++ b/cc/test/test_in_process_context_provider.cc
@@ -72,18 +72,6 @@ cache_controller_.reset(new viz::ContextCacheController( context_->GetImplementation(), base::ThreadTaskRunnerHandle::Get())); - capabilities_.texture_rectangle = true; - capabilities_.sync_query = true; - capabilities_.texture_norm16 = true; - switch (viz::PlatformColor::Format()) { - case viz::PlatformColor::SOURCE_FORMAT_RGBA8: - capabilities_.texture_format_bgra8888 = false; - break; - case viz::PlatformColor::SOURCE_FORMAT_BGRA8: - capabilities_.texture_format_bgra8888 = true; - break; - } - raster_implementation_ = std::make_unique<gpu::raster::RasterImplementationGLES>( context_->GetImplementation(), context_->GetImplementation(), @@ -146,7 +134,7 @@ const gpu::Capabilities& TestInProcessContextProvider::ContextCapabilities() const { - return capabilities_; + return context_->GetCapabilities(); } const gpu::GpuFeatureInfo& TestInProcessContextProvider::GetGpuFeatureInfo()
diff --git a/cc/test/test_in_process_context_provider.h b/cc/test/test_in_process_context_provider.h index a34c42c..cb684bf 100644 --- a/cc/test/test_in_process_context_provider.h +++ b/cc/test/test_in_process_context_provider.h
@@ -60,9 +60,6 @@ const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override; void AddObserver(viz::ContextLostObserver* obs) override {} void RemoveObserver(viz::ContextLostObserver* obs) override {} - void SetSupportTextureNorm16(bool support) { - capabilities_texture_norm16_ = support; - } protected: friend class base::RefCountedThreadSafe<TestInProcessContextProvider>; @@ -76,8 +73,6 @@ std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_; std::unique_ptr<viz::ContextCacheController> cache_controller_; base::Lock context_lock_; - bool capabilities_texture_norm16_ = false; - gpu::Capabilities capabilities_; gpu::GpuFeatureInfo gpu_feature_info_; };
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index b5b2da7..55f8727 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -505,9 +505,33 @@ target_tree->has_ever_been_drawn_ = false; // Note: this needs to happen after SetPropertyTrees. + target_tree->HandleTickmarksVisibilityChange(); target_tree->HandleScrollbarShowRequestsFromMain(); } +void LayerTreeImpl::HandleTickmarksVisibilityChange() { + if (!host_impl_->ViewportMainScrollLayer()) + return; + + ScrollbarAnimationController* controller = + host_impl_->ScrollbarAnimationControllerForElementId( + OuterViewportScrollLayer()->element_id()); + + if (!controller) + return; + + for (ScrollbarLayerImplBase* scrollbar : controller->Scrollbars()) { + if (scrollbar->orientation() != VERTICAL) + continue; + + // Android Overlay Scrollbar don't have FindInPage Tickmarks. + if (scrollbar->GetScrollbarAnimator() != LayerTreeSettings::AURA_OVERLAY) + DCHECK(!scrollbar->HasFindInPageTickmarks()); + + controller->UpdateTickmarksVisibility(scrollbar->HasFindInPageTickmarks()); + } +} + void LayerTreeImpl::HandleScrollbarShowRequestsFromMain() { LayerTreeHostCommon::CallFunctionForEveryLayer(this, [this]( LayerImpl* layer) {
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index 5dda067..801e631 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -551,6 +551,8 @@ void ClearLayerList(); void BuildLayerListForTesting(); + + void HandleTickmarksVisibilityChange(); void HandleScrollbarShowRequestsFromMain(); void InvalidateRegionForImages(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java index 67d95eb..8917449 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
@@ -228,11 +228,13 @@ // Click event happens before the up event. mClicked is set to mute the up event. mClicked = true; PortraitViewport viewportParams = getViewportParameters(); - int stackIndexAt = viewportParams.getStackIndexAt(x, y); - if (stackIndexAt == getTabStackIndex()) { + final int stackIndexDeltaAt = viewportParams.getStackIndexDeltaAt(x, y); + if (stackIndexDeltaAt == 0) { mStacks.get(getTabStackIndex()).click(time(), x, y); } else { - flingStacks(getTabStackIndex() == 0); + final int newStackIndex = getTabStackIndex() + stackIndexDeltaAt; + if (newStackIndex < 0 || newStackIndex >= mStacks.size()) return; + flingStacks(newStackIndex); } requestStackUpdate(); } @@ -274,12 +276,19 @@ private void onUpOrCancel(long time) { int currentIndex = getTabStackIndex(); - int nextIndex = 1 - currentIndex; if (!mClicked - && Math.abs(currentIndex + mRenderedScrollOffset) > THRESHOLD_TO_SWITCH_STACK - && mStacks.get(nextIndex).isDisplayable()) { - setActiveStackState(nextIndex == 1); + && Math.abs(currentIndex + mRenderedScrollOffset) > THRESHOLD_TO_SWITCH_STACK) { + int nextIndex; + if (currentIndex + mRenderedScrollOffset < 0) { + nextIndex = currentIndex + 1; + } else { + nextIndex = currentIndex - 1; + } + if (mStacks.get(nextIndex).isDisplayable()) { + setActiveStackState(nextIndex); + } } + mClicked = false; finishScrollStacks(); mStacks.get(getTabStackIndex()).onUpOrCancel(time); @@ -444,7 +453,7 @@ startMarginAnimation(true); // Animate the stack to leave incognito mode. - if (!mStacks.get(1).isDisplayable()) uiPreemptivelySelectTabModel(false); + if (!mStacks.get(1).isDisplayable()) onTabModelSwitched(false); } @Override @@ -455,7 +464,7 @@ // trigger the overlap animation. startMarginAnimation(true); // Animate the stack to leave incognito mode. - if (!mStacks.get(1).isDisplayable()) uiPreemptivelySelectTabModel(false); + if (!mStacks.get(1).isDisplayable()) onTabModelSwitched(false); } @Override @@ -549,7 +558,7 @@ startMarginAnimation(false); } - uiPreemptivelySelectTabModel(newIsIncognito); + onTabModelSwitched(newIsIncognito); } @Override @@ -562,7 +571,7 @@ @Override public void onTabModelSwitched(boolean toIncognitoTabModel) { - flingStacks(toIncognitoTabModel); + flingStacks(toIncognitoTabModel ? INCOGNITO_STACK_INDEX : NORMAL_STACK_INDEX); mFlingFromModelChange = true; } @@ -640,7 +649,7 @@ // Make sure we show/hide both stacks depending on which tab we're closing. startMarginAnimation(true, incognitoVisible); - if (!incognitoVisible) uiPreemptivelySelectTabModel(false); + if (!incognitoVisible) onTabModelSwitched(false); } /** @@ -676,10 +685,6 @@ doneShowing(); } - private void uiPreemptivelySelectTabModel(boolean incognito) { - onTabModelSwitched(incognito); - } - /** * Starts the animation for the opposite stack to slide in or out when entering * or leaving stack view. The animation should be super fast to match more or less @@ -744,7 +749,7 @@ } startMarginAnimation(true); startYOffsetAnimation(true); - flingStacks(getTabStackIndex() == 1); + flingStacks(getTabStackIndex()); if (!animate) onUpdateAnimation(time, true); @@ -817,7 +822,12 @@ * @return The input mode to select. */ private @SwipeMode int computeInputMode(long time, float x, float y, float dx, float dy) { - if (!mStacks.get(1).isDisplayable()) return SWIPE_MODE_SEND_TO_STACK; + if (mStacks.size() == 0) return SWIPE_MODE_NONE; + + if (mStacks.size() == 1 || (mStacks.size() == 2 && !mStacks.get(1).isDisplayable())) { + return SWIPE_MODE_SEND_TO_STACK; + } + int currentIndex = getTabStackIndex(); // When a drag starts, lock the drag into being either horizontal or vertical until the @@ -881,21 +891,58 @@ return margin; } - int getStackIndexAt(float x, float y) { - if (LocalizationUtils.isLayoutRtl()) { - // On RTL portrait mode, stack1 (incognito) is on the left. - float separation = getStack0Left(); - return x < separation ? 1 : 0; - } else { - float separation = getStack0Left() + getWidth(); - return x < separation ? 0 : 1; + /** + * Returns an offset that can be added to the index of the current stack to get the index of + * the stack at the specified on-screen location. + * @param x The x coordinate of the specified on-screen location. + * @param y The x coordinate of the specified on-screen location. + * @return The offset to be added to the index of the current stack. + */ + int getStackIndexDeltaAt(float x, float y) { + int delta = 0; + if (x < getCurrentStackLeft()) { + delta = -1; + } else if (x > getCurrentStackLeft() + getWidth()) { + delta = 1; } + + // Tabs are counted from left to right in LTR mode, but from right to left in RTL mode. + if (LocalizationUtils.isLayoutRtl()) delta *= -1; + + return delta; } + /** + * @return The current x coordinate for the left edge of the first stack (right edge if in + * RTL mode). + */ float getStack0Left() { - return LocalizationUtils.isLayoutRtl() - ? getInnerMargin() - getClampedRenderedScrollOffset() * getFullScrollDistance() - : getClampedRenderedScrollOffset() * getFullScrollDistance(); + float stack0LeftLtr = getClampedRenderedScrollOffset() * getFullScrollDistance(); + if (mStacks.size() > 2) { + // If we have one or two stacks, we only show a margin on the right side of the left + // stack and on the left side of the right stack. But if we have three or more + // stacks, we put a margin on both sides + stack0LeftLtr += getInnerMargin() / 2; + } + + if (LocalizationUtils.isLayoutRtl()) return getInnerMargin() - stack0LeftLtr; + + return stack0LeftLtr; + } + + /** + * @return The current x coordinate for the left edge of the current stack (actually the + * right edge if in RTL mode). + */ + float getCurrentStackLeft() { + float offset = getClampedRenderedScrollOffset() + getTabStackIndex(); + if (mStacks.size() > 2) { + return offset * getFullScrollDistance() + getInnerMargin() / 2; + } + + // Note: getInnerMargin() is zero if there's only one stack. + boolean isRightStack = (getTabStackIndex() == 1) ^ LocalizationUtils.isLayoutRtl(); + return offset * getFullScrollDistance() + (isRightStack ? getInnerMargin() : 0); } float getWidth() { @@ -941,9 +988,10 @@ } @Override - int getStackIndexAt(float x, float y) { - float separation = getStack0Top() + getHeight(); - return y < separation ? 0 : 1; + int getStackIndexDeltaAt(float x, float y) { + if (y < getCurrentStackTop()) return -1; + if (y > getCurrentStackTop() + getHeight()) return 1; + return 0; } @Override @@ -957,6 +1005,20 @@ + getTopHeightOffset(); } + /** + * @return The current y coordinate for the top edge of the current stack. + */ + float getCurrentStackTop() { + float offset = getClampedRenderedScrollOffset() + getTabStackIndex(); + if (mStacks.size() > 2) { + return offset * getFullScrollDistance() + getInnerMargin() / 2 + + getTopHeightOffset(); + } + + return offset * getFullScrollDistance() + + ((getTabStackIndex() == 1) ? getInnerMargin() : 0) + getTopHeightOffset(); + } + @Override float getWidth() { return super.getHeight(); @@ -992,18 +1054,30 @@ } } + /** + * Scrolls the tab stacks by amount delta (clamped so that it's not possible to scroll past the + * last stack in either direciton). Positive delta corresponds to increasing the x coordinate + * in portrait mode (in both LTR and RTL modes), or increasing the y coordinate in landscape + * mode. + * @param delta The amount to scroll by. + */ private void scrollStacks(float delta) { cancelAnimation(this, Property.STACK_SNAP); float fullDistance = getFullScrollDistance(); mScrollIndexOffset += MathUtils.flipSignIf(delta / fullDistance, getOrientation() == Orientation.PORTRAIT && LocalizationUtils.isLayoutRtl()); - mRenderedScrollOffset = MathUtils.clamp(mScrollIndexOffset, 0, -1); + mRenderedScrollOffset = MathUtils.clamp(mScrollIndexOffset, 0, -(mStacks.size() - 1)); requestStackUpdate(); } - private void flingStacks(boolean toIncognito) { + /** + * Scrolls over to the tab stack at the specified index, and records that it's now the current + * tab stack. + * @param index The index of the newly-selected tab stack. + */ + private void flingStacks(int index) { // velocityX is measured in pixel per second. - setActiveStackState(toIncognito); + setActiveStackState(index); finishScrollStacks(); requestStackUpdate(); } @@ -1148,13 +1222,10 @@ /** * Sets the active tab stack. * - * @param isIncognito True if the model to select is incognito. - * @return Whether the tab stack index passed in differed from the currently selected stack. + * @param stackIndex Index of the tab stack to be made active. */ - public boolean setActiveStackState(boolean isIncognito) { - if (isIncognito == mTabModelSelector.isIncognitoSelected()) return false; - mTemporarySelectedStack = isIncognito ? INCOGNITO_STACK_INDEX : NORMAL_STACK_INDEX; - return true; + public void setActiveStackState(int stackIndex) { + mTemporarySelectedStack = stackIndex; } private void resetScrollData() { @@ -1162,9 +1233,16 @@ mRenderedScrollOffset = mScrollIndexOffset; } + /** + * @return The distance between two neighboring tab stacks. + */ private float getFullScrollDistance() { float distance = getOrientation() == Orientation.PORTRAIT ? getWidth() : getHeightMinusBrowserControls(); + if (mStacks.size() > 2) { + return distance - getViewportParameters().getInnerMargin(); + } + return distance - 2 * getViewportParameters().getInnerMargin(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java index cdb0118..5b618b5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -322,10 +322,16 @@ break; case FROM_CHROME_UI: case FROM_LONGPRESS_FOREGROUND: - case FROM_LONGPRESS_BACKGROUND: case FROM_LAUNCHER_SHORTCUT: transition = PageTransition.AUTO_TOPLEVEL; break; + case FROM_LONGPRESS_BACKGROUND: + // On low end devices tabs are backgrounded in a frozen state, so we set the + // transition type to RELOAD to avoid handling intents when the tab is foregrounded. + // (https://crbug.com/758027) + transition = SysUtils.isLowEndDevice() ? PageTransition.RELOAD + : PageTransition.AUTO_TOPLEVEL; + break; default: assert false; break;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java index be08b58..28cce39 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
@@ -26,8 +26,10 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.components.safe_browsing.SafeBrowsingApiBridge; import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import org.chromium.content.browser.test.util.DOMUtils; import org.chromium.content.browser.test.util.TouchCommon; import org.chromium.net.test.EmbeddedTestServer; @@ -46,6 +48,9 @@ private static final String POPUP_HTML_PATH = "/chrome/test/data/android/popup_test.html"; + private static final String METADATA_FOR_ABUSIVE_ENFORCEMENT = + "{\"matches\":[{\"threat_type\":\"13\",\"sf_absv\":\"\"}]}"; + private String mPopupHtmlUrl; private EmbeddedTestServer mTestServer; @@ -55,6 +60,10 @@ @Before public void setUp() throws Exception { + // Create a new temporary instance to ensure the Class is loaded. Otherwise we will get a + // ClassNotFoundException when trying to instantiate during startup. + SafeBrowsingApiBridge.setSafeBrowsingHandlerType( + new MockSafeBrowsingApiHandler().getClass()); mActivityTestRule.startMainActivityOnBlankPage(); ThreadUtils.runOnUiThread(() -> Assert.assertTrue(getNumInfobarsShowing() == 0)); @@ -66,6 +75,7 @@ @After public void tearDown() throws Exception { mTestServer.stopAndDestroyServer(); + MockSafeBrowsingApiHandler.clearMockResponses(); } @Test @@ -79,6 +89,38 @@ @Test @MediumTest @Feature({"Popup"}) + public void testSafeGestureTabNotBlocked() throws Exception { + final TabModelSelector selector = mActivityTestRule.getActivity().getTabModelSelector(); + + String url = mTestServer.getURL("/chrome/test/data/android/popup_on_click.html"); + + mActivityTestRule.loadUrl(url); + CriteriaHelper.pollUiThread(Criteria.equals(0, () -> getNumInfobarsShowing())); + DOMUtils.clickNode( + mActivityTestRule.getActivity().getActivityTab().getContentViewCore(), "link"); + CriteriaHelper.pollUiThread(Criteria.equals(0, () -> getNumInfobarsShowing())); + } + + @Test + @MediumTest + @Feature({"Popup"}) + public void testAbusiveGesturePopupBlocked() throws Exception { + final TabModelSelector selector = mActivityTestRule.getActivity().getTabModelSelector(); + + String url = mTestServer.getURL("/chrome/test/data/android/popup_on_click.html"); + MockSafeBrowsingApiHandler.addMockResponse(url, METADATA_FOR_ABUSIVE_ENFORCEMENT); + + mActivityTestRule.loadUrl(url); + CriteriaHelper.pollUiThread(Criteria.equals(0, () -> getNumInfobarsShowing())); + DOMUtils.clickNode( + mActivityTestRule.getActivity().getActivityTab().getContentViewCore(), "link"); + CriteriaHelper.pollUiThread(Criteria.equals(1, () -> getNumInfobarsShowing())); + Assert.assertEquals(1, selector.getTotalTabCount()); + } + + @Test + @MediumTest + @Feature({"Popup"}) @FlakyTest(message = "crbug.com/771103") public void testPopupWindowsAppearWhenAllowed() throws Exception { final TabModelSelector selector = mActivityTestRule.getActivity().getTabModelSelector();
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 9d09a9d0..448e077 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-67.0.3366.0_rc-r1.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-67.0.3366.3_rc-r1.afdo.bz2 \ No newline at end of file
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn index 00d201d..7a197fed 100644 --- a/chrome/app/vector_icons/BUILD.gn +++ b/chrome/app/vector_icons/BUILD.gn
@@ -34,8 +34,11 @@ # Alternative squarer content_paste icon optimised for display at 18x18dip. # Currently only used in the Page Info bubble. - "page_info_content_paste.icon", + "back_arrow_touch.icon", "bookmarkbar_touch_overflow.icon", + "browser_tools_error_touch.icon", + "browser_tools_touch.icon", + "browser_tools_update_touch.icon", "content_paste.icon", "cookie.icon", "crashed_tab.icon", @@ -51,6 +54,7 @@ "folder.icon", "folder_supervised.1x.icon", "folder_supervised.icon", + "forward_arrow_touch.icon", "globe.icon", "google_g_logo.icon", "google_pay_logo_with_vertical_separator.icon", @@ -65,16 +69,20 @@ "my_location.icon", "navigate_home.1x.icon", "navigate_home.icon", + "navigate_home_touch.icon", "navigate_stop.1x.icon", "navigate_stop.icon", + "navigate_stop_touch.icon", "new_tab_button_incognito.icon", "new_tab_button_plus.icon", "overflow_chevron.1x.icon", "overflow_chevron.icon", + "page_info_content_paste.icon", "paintbrush.icon", "photo.icon", "photo_camera.icon", "profile_switcher_outline.icon", + "reload_touch.icon", "remove.icon", "remove_box.icon", "sad_tab.icon", @@ -93,10 +101,10 @@ "tab.icon", "tab_audio.1x.icon", "tab_audio.icon", - "tab_audio_rounded.icon", "tab_audio_muting.1x.icon", "tab_audio_muting.icon", "tab_audio_muting_rounded.icon", + "tab_audio_rounded.icon", "tab_bluetooth_connected.icon", "tab_close_button_touch.icon", "tab_close_button_touch_incognito.icon",
diff --git a/chrome/app/vector_icons/back_arrow_touch.icon b/chrome/app/vector_icons/back_arrow_touch.icon new file mode 100644 index 0000000..974a7c83 --- /dev/null +++ b/chrome/app/vector_icons/back_arrow_touch.icon
@@ -0,0 +1,26 @@ +// Copyright 2018 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 12.91f, 18.59f, +R_LINE_TO, 0.09f, -0.09f, +LINE_TO, 7.49f, 13, +H_LINE_TO, 19, +R_ARC_TO, 1, 1, 0, 0, 0, 0, -2, +H_LINE_TO, 7.49f, +LINE_TO, 13, 5.49f, +R_LINE_TO, -0.09f, -0.09f, +R_ARC_TO, 1, 1, 0, 0, 0, -1.32f, -1.32f, +R_H_LINE_TO, 0, +LINE_TO, 11.51f, 4, +LINE_TO, 4, 11.51f, +R_LINE_TO, 0.09f, 0.09f, +R_ARC_TO, 1, 1, 0, 0, 0, 0, 0.82f, +LINE_TO, 4, 12.5f, +LINE_TO, 11.51f, 20, +R_LINE_TO, 0.09f, -0.09f, +R_ARC_TO, 1, 1, 0, 0, 0, 1.32f, -1.32f, +R_V_LINE_TO, 0, +CLOSE, +END \ No newline at end of file
diff --git a/chrome/app/vector_icons/browser_tools_error_touch.icon b/chrome/app/vector_icons/browser_tools_error_touch.icon new file mode 100644 index 0000000..2ae9ce0c --- /dev/null +++ b/chrome/app/vector_icons/browser_tools_error_touch.icon
@@ -0,0 +1,29 @@ +// Copyright 2018 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 12, 22, +R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10, +CUBIC_TO_SHORTHAND, 17.52f, 2, 12, 2, +CUBIC_TO_SHORTHAND, 2, 6.48f, 2, 12, +R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10, +CLOSE, +R_MOVE_TO, 1, -9, +R_H_LINE_TO, -2, +V_LINE_TO, 7, +R_H_LINE_TO, 2, +R_V_LINE_TO, 6, +CLOSE, +R_MOVE_TO, 0, 4, +R_H_LINE_TO, -2, +R_V_LINE_TO, -2, +R_H_LINE_TO, 2, +R_V_LINE_TO, 2, +CLOSE, +MOVE_TO, 0, 0, +R_H_LINE_TO, 24, +R_V_LINE_TO, 24, +H_LINE_TO, 0, +CLOSE, +END \ No newline at end of file
diff --git a/chrome/app/vector_icons/browser_tools_touch.icon b/chrome/app/vector_icons/browser_tools_touch.icon new file mode 100644 index 0000000..8e92a38 --- /dev/null +++ b/chrome/app/vector_icons/browser_tools_touch.icon
@@ -0,0 +1,18 @@ +// Copyright 2018 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 12, 8, +R_ARC_TO, 2, 2, 0, 1, 0, 0, -4, +R_ARC_TO, 2, 2, 0, 0, 0, 0, 4, +CLOSE, +R_MOVE_TO, 0, 2, +R_ARC_TO, 2, 2, 0, 1, 0, 0, 4, +R_ARC_TO, 2, 2, 0, 0, 0, 0, -4, +CLOSE, +R_MOVE_TO, 0, 6, +R_ARC_TO, 2, 2, 0, 1, 0, 0, 4, +R_ARC_TO, 2, 2, 0, 0, 0, 0, -4, +CLOSE, +END \ No newline at end of file
diff --git a/chrome/app/vector_icons/browser_tools_update_touch.icon b/chrome/app/vector_icons/browser_tools_update_touch.icon new file mode 100644 index 0000000..b3a8b9c --- /dev/null +++ b/chrome/app/vector_icons/browser_tools_update_touch.icon
@@ -0,0 +1,26 @@ +// Copyright 2018 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 12, 22, +CUBIC_TO, 6.48f, 22, 2, 17.52f, 2, 12, +CUBIC_TO_SHORTHAND, 6.48f, 2, 12, 2, +R_CUBIC_TO, 5.52f, 0, 10, 4.48f, 10, 10, +R_CUBIC_TO, 0, 5.52f, -4.48f, 10, -10, 10, +CLOSE, +R_MOVE_TO, -2, -5, +R_H_LINE_TO, 4, +R_V_LINE_TO, -4, +R_H_LINE_TO, 3.5f, +LINE_TO, 12, 6.5f, +LINE_TO, 6.5f, 13, +H_LINE_TO, 10, +R_V_LINE_TO, 4, +CLOSE, +MOVE_TO, 0, 0, +R_H_LINE_TO, 24, +R_V_LINE_TO, 24, +H_LINE_TO, 0, +CLOSE, +END \ No newline at end of file
diff --git a/chrome/app/vector_icons/forward_arrow_touch.icon b/chrome/app/vector_icons/forward_arrow_touch.icon new file mode 100644 index 0000000..b7bb8ce --- /dev/null +++ b/chrome/app/vector_icons/forward_arrow_touch.icon
@@ -0,0 +1,26 @@ +// Copyright 2018 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 11.09f, 18.59f, +LINE_TO, 11, 18.51f, +LINE_TO, 16.51f, 13, +H_LINE_TO, 5, +R_ARC_TO, 1, 1, 0, 0, 1, 0, -2, +R_H_LINE_TO, 11.51f, +LINE_TO, 11, 5.49f, +R_LINE_TO, 0.09f, -0.09f, +R_ARC_TO, 1, 1, 0, 0, 1, 1.32f, -1.32f, +R_H_LINE_TO, 0, +LINE_TO, 12.49f, 4, +LINE_TO, 20, 11.51f, +R_LINE_TO, -0.09f, 0.09f, +R_ARC_TO, 1, 1, 0, 0, 1, 0, 0.82f, +R_LINE_TO, 0.09f, 0.09f, +LINE_TO, 12.49f, 20, +R_LINE_TO, -0.09f, -0.09f, +R_ARC_TO, 1, 1, 0, 0, 1, -1.32f, -1.32f, +R_V_LINE_TO, 0, +CLOSE, +END \ No newline at end of file
diff --git a/chrome/app/vector_icons/navigate_home_touch.icon b/chrome/app/vector_icons/navigate_home_touch.icon new file mode 100644 index 0000000..d266a1e --- /dev/null +++ b/chrome/app/vector_icons/navigate_home_touch.icon
@@ -0,0 +1,32 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 12.87f, 3.54f, +CUBIC_TO, 12.67f, 3.33f, 12.33f, 3, 12, 3, +R_CUBIC_TO, -0.33f, 0, -0.67f, 0.33f, -0.87f, 0.54f, +R_LINE_TO, -7.89f, 7.84f, +ARC_TO, 0.98f, 0.98f, 0, 0, 0, 3, 12, +R_ARC_TO, 1, 1, 0, 0, 0, 1, 1, +R_CUBIC_TO, 0.24f, 0, 0.45f, -0.09f, 0.62f, -0.24f, +R_LINE_TO, 0.38f, -0.35f, +V_LINE_TO, 19, +R_ARC_TO, 2, 2, 0, 0, 0, 2, 2, +R_H_LINE_TO, 10, +R_ARC_TO, 2, 2, 0, 0, 0, 2, -2, +R_V_LINE_TO, -6.59f, +R_LINE_TO, 0.38f, 0.35f, +ARC_TO, 0.98f, 0.98f, 0, 0, 0, 20, 13, +R_ARC_TO, 1, 1, 0, 0, 0, 1, -1, +R_ARC_TO, 0.98f, 0.98f, 0, 0, 0, -0.24f, -0.62f, +R_CUBIC_TO, 0, 0, -5.91f, -5.88f, -7.89f, -7.84f, +CLOSE, +MOVE_TO, 7, 19, +R_V_LINE_TO, -8.85f, +LINE_TO, 12, 5, +R_LINE_TO, 5, 5.15f, +V_LINE_TO, 19, +H_LINE_TO, 7, +CLOSE, +END \ No newline at end of file
diff --git a/chrome/app/vector_icons/navigate_stop_touch.icon b/chrome/app/vector_icons/navigate_stop_touch.icon new file mode 100644 index 0000000..1ef5b4f --- /dev/null +++ b/chrome/app/vector_icons/navigate_stop_touch.icon
@@ -0,0 +1,32 @@ +// Copyright 2018 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 17.51f, 5, +R_LINE_TO, 0.09f, 0.09f, +R_ARC_TO, 1, 1, 0, 0, 1, 1.32f, 1.32f, +R_LINE_TO, 0.09f, 0.09f, +LINE_TO, 14.49f, 11, +R_LINE_TO, -0.99f, 1, +R_LINE_TO, 0.99f, 1, +LINE_TO, 19, 17.51f, +R_LINE_TO, -0.09f, 0.09f, +R_ARC_TO, 1, 1, 0, 0, 1, -1.32f, 1.32f, +R_LINE_TO, -0.09f, 0.09f, +LINE_TO, 12, 13.5f, +LINE_TO, 6.49f, 19, +R_LINE_TO, -0.09f, -0.09f, +R_ARC_TO, 1, 1, 0, 0, 1, -1.32f, -1.32f, +LINE_TO, 5, 17.51f, +LINE_TO, 9.51f, 13, +R_LINE_TO, 0.99f, -1, +R_LINE_TO, -0.99f, -1, +LINE_TO, 5, 6.49f, +R_LINE_TO, 0.09f, -0.09f, +R_ARC_TO, 1, 1, 0, 0, 1, 1.32f, -1.32f, +LINE_TO, 6.5f, 5, +LINE_TO, 12, 10.51f, +LINE_TO, 17.51f, 5, +CLOSE, +END \ No newline at end of file
diff --git a/chrome/app/vector_icons/reload_touch.icon b/chrome/app/vector_icons/reload_touch.icon new file mode 100644 index 0000000..0e3d14b --- /dev/null +++ b/chrome/app/vector_icons/reload_touch.icon
@@ -0,0 +1,25 @@ +// Copyright 2018 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 17.68f, 6.32f, +LINE_TO, 20, 4, +R_V_LINE_TO, 7, +R_H_LINE_TO, -7, +R_LINE_TO, 3.27f, -3.27f, +ARC_TO, 6.01f, 6.01f, 0, 0, 0, 12.04f, 6, +R_CUBIC_TO, -3.33f, 0, -6.03f, 2.69f, -6.03f, 6, +R_CUBIC_TO, 0, 3.31f, 2.7f, 6, 6.03f, 6, +R_CUBIC_TO, 2.62f, 0, 4.71f, -1.62f, 5.47f, -3.89f, +R_LINE_TO, 0.11f, -0.01f, +R_ARC_TO, 1, 1, 0, 0, 1, 0.89f, -0.6f, +R_CUBIC_TO, 0.44f, 0, 1, 0.32f, 1, 1, +R_ARC_TO, 1, 1, 0, 0, 1, -0.09f, 0.41f, +R_LINE_TO, 0.05f, 0, +CUBIC_TO, 18.26f, 17.84f, 15.41f, 20, 12.04f, 20, +CUBIC_TO, 7.6f, 20, 4, 16.42f, 4, 12, +R_CUBIC_TO, 0, -4.42f, 3.6f, -8, 8.04f, -8, +R_CUBIC_TO, 2.2f, 0, 4.2f, 0.88f, 5.65f, 2.32f, +CLOSE, +END \ No newline at end of file
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index 848151f..40b6df11 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -45,6 +45,7 @@ "+media/capture", "+media/midi", # For midi switches "+media/mojo", # For mojo media services. + "+media/renderers", "+ppapi/c", # For various types. "+ppapi/host", "+ppapi/proxy", @@ -74,6 +75,7 @@ "+services/ui/common", "+services/ui/public", "+services/ui/service.h", + "+services/viz/privileged", "+skia/ext", "+third_party/boringssl/src/include", "+third_party/crashpad",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 9207a97..6023d43b 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -695,6 +695,12 @@ switches::kEnableUseZoomForDSF, "false"}, }; +const FeatureEntry::Choice kSiteIsolationTrialOptOutChoices[] = { + {flag_descriptions::kSiteIsolationTrialOptOutChoiceDefault, "", ""}, + {flag_descriptions::kSiteIsolationTrialOptOutChoiceOptOut, + switches::kDisableSiteIsolationTrials, ""}, +}; + const FeatureEntry::Choice kTLS13VariantChoices[] = { {flags_ui::kGenericExperimentChoiceDefault, "", ""}, {flag_descriptions::kTLS13VariantDisabled, switches::kTLS13Variant, @@ -1466,6 +1472,10 @@ SINGLE_VALUE_TYPE_AND_VALUE(switches::kAllowNaClSocketAPI, "*")}, #endif // ENABLE_PLUGINS #if defined(OS_CHROMEOS) + {"ash-enable-cursor-motion-blur", + flag_descriptions::kEnableCursorMotionBlurName, + flag_descriptions::kEnableCursorMotionBlurDescription, kOsAll, + SINGLE_VALUE_TYPE(ash::switches::kAshEnableCursorMotionBlur)}, {"ash-enable-docked-magnifier", flag_descriptions::kEnableDockedMagnifierName, flag_descriptions::kEnableDockedMagnifierDescription, kOsCrOS, @@ -2025,9 +2035,13 @@ {"committed-interstitials", flag_descriptions::kCommittedInterstitialsName, flag_descriptions::kCommittedInterstitialsDescription, kOsAll, SINGLE_VALUE_TYPE(switches::kCommittedInterstitials)}, - {"enable-site-per-process", flag_descriptions::kSitePerProcessName, - flag_descriptions::kSitePerProcessDescription, kOsAll, + {"enable-site-per-process", flag_descriptions::kStrictSiteIsolationName, + flag_descriptions::kStrictSiteIsolationDescription, kOsAll, SINGLE_VALUE_TYPE(switches::kSitePerProcess)}, + {"site-isolation-trial-opt-out", + flag_descriptions::kSiteIsolationTrialOptOutName, + flag_descriptions::kSiteIsolationTrialOptOutDescription, kOsAll, + MULTI_VALUE_TYPE(kSiteIsolationTrialOptOutChoices)}, {"enable-top-document-isolation", flag_descriptions::kTopDocumentIsolationName, flag_descriptions::kTopDocumentIsolationDescription, kOsAll, @@ -3590,7 +3604,7 @@ {"ash-enable-persistent-window-bounds", flag_descriptions::kAshEnablePersistentWindowBoundsName, flag_descriptions::kAshEnablePersistentWindowBoundsDescription, kOsCrOS, - SINGLE_VALUE_TYPE(ash::switches::kAshEnablePersistentWindowBounds)}, + FEATURE_VALUE_TYPE(ash::features::kPersistentWindowBounds)}, #endif // OS_CHROMEOS {"clipboard-content-setting",
diff --git a/chrome/browser/android/vr/vr_gl_thread.cc b/chrome/browser/android/vr/vr_gl_thread.cc index d2e7bfb..76f27f2d 100644 --- a/chrome/browser/android/vr/vr_gl_thread.cc +++ b/chrome/browser/android/vr/vr_gl_thread.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/vr/model/assets.h" #include "chrome/browser/vr/model/omnibox_suggestions.h" #include "chrome/browser/vr/model/toolbar_state.h" +#include "chrome/browser/vr/sounds_manager_audio_delegate.h" #include "chrome/browser/vr/ui.h" #include "chrome/common/chrome_features.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -66,8 +67,12 @@ !keyboard_delegate_ ? nullptr : keyboard_delegate_.get(); if (!keyboard_delegate) ui_initial_state_.needs_keyboard_update = true; + + audio_delegate_ = std::make_unique<SoundsManagerAudioDelegate>(); + auto ui = std::make_unique<Ui>(this, this, keyboard_delegate, - text_input_delegate_.get(), ui_initial_state_); + text_input_delegate_.get(), + audio_delegate_.get(), ui_initial_state_); if (keyboard_enabled) { text_input_delegate_->SetRequestFocusCallback( base::BindRepeating(&Ui::RequestFocus, base::Unretained(ui.get()))); @@ -91,6 +96,7 @@ } void VrGLThread::CleanUp() { + audio_delegate_.reset(); vr_shell_gl_.reset(); }
diff --git a/chrome/browser/android/vr/vr_gl_thread.h b/chrome/browser/android/vr/vr_gl_thread.h index 3c39270a..24315371 100644 --- a/chrome/browser/android/vr/vr_gl_thread.h +++ b/chrome/browser/android/vr/vr_gl_thread.h
@@ -16,6 +16,7 @@ #include "chrome/browser/vr/browser_ui_interface.h" #include "chrome/browser/vr/content_input_delegate.h" #include "chrome/browser/vr/model/omnibox_suggestions.h" +#include "chrome/browser/vr/model/sound_id.h" #include "chrome/browser/vr/text_input_delegate.h" #include "chrome/browser/vr/ui.h" #include "chrome/browser/vr/ui_browser_interface.h" @@ -27,6 +28,7 @@ namespace vr { +class AudioDelegate; class VrInputConnection; class VrShell; class VrShellGl; @@ -131,6 +133,7 @@ std::unique_ptr<VrShellGl> vr_shell_gl_; std::unique_ptr<GvrKeyboardDelegate> keyboard_delegate_; std::unique_ptr<TextInputDelegate> text_input_delegate_; + std::unique_ptr<AudioDelegate> audio_delegate_; base::WeakPtr<VrShell> weak_vr_shell_; base::WeakPtr<BrowserUiInterface> weak_browser_ui_;
diff --git a/chrome/browser/chromeos/customization/customization_document_unittest.cc b/chrome/browser/chromeos/customization/customization_document_unittest.cc index 85eef2e93..8907032 100644 --- a/chrome/browser/chromeos/customization/customization_document_unittest.cc +++ b/chrome/browser/chromeos/customization/customization_document_unittest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h" #include "chrome/browser/extensions/external_provider_impl.h" #include "chrome/browser/prefs/browser_prefs.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/app_list/app_list_syncable_service.h" #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h" #include "chrome/test/base/testing_browser_process.h" @@ -202,7 +203,7 @@ } TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_); - ServicesCustomizationDocument::RegisterPrefs(local_state_.registry()); + RegisterLocalState(local_state_.registry()); } void TearDown() override { @@ -265,7 +266,11 @@ factory.CreateSyncable(registry.get())); RegisterUserProfilePrefs(registry.get()); profile_builder.SetPrefService(std::move(prefs)); - return profile_builder.Build(); + std::unique_ptr<TestingProfile> profile = profile_builder.Build(); + // Make sure we have a Profile Manager. + TestingBrowserProcess::GetGlobal()->SetProfileManager( + new ProfileManagerWithoutInit(profile->GetPath())); + return profile; } network::TestURLLoaderFactory factory_;
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.cc b/chrome/browser/chromeos/smb_client/smb_file_system.cc index 9500103..de04230c 100644 --- a/chrome/browser/chromeos/smb_client/smb_file_system.cc +++ b/chrome/browser/chromeos/smb_client/smb_file_system.cc
@@ -288,9 +288,9 @@ const base::FilePath& entry_path, bool recursive, const storage::AsyncFileUtil::StatusCallback& callback) { - GetSmbProviderClient()->DeleteEntry( - GetMountId(), entry_path, recursive, - base::BindOnce(&SmbFileSystem::HandleStatusCallback, + GetSmbProviderClient()->GetDeleteList( + GetMountId(), entry_path, + base::BindOnce(&SmbFileSystem::HandleGetDeleteListCallback, weak_ptr_factory_.GetWeakPtr(), callback)); return CreateAbortCallback(); } @@ -441,6 +441,43 @@ callback.Run(TranslateError(error), entry_list, false /* has_more */); } +void SmbFileSystem::HandleGetDeleteListCallback( + storage::AsyncFileUtil::StatusCallback callback, + smbprovider::ErrorType list_error, + const smbprovider::DeleteListProto& delete_list) { + if (delete_list.entries_size() == 0) { + // There are no entries to delete. + DCHECK_NE(smbprovider::ERROR_OK, list_error); + callback.Run(TranslateError(list_error)); + return; + } + + for (int i = 0; i < delete_list.entries_size(); ++i) { + const base::FilePath entry_path(delete_list.entries(i)); + bool is_last_entry = (i == delete_list.entries_size() - 1); + + GetSmbProviderClient()->DeleteEntry( + GetMountId(), entry_path, false /* recursive */, + base::BindOnce(&SmbFileSystem::HandleDeleteEntryCallback, + weak_ptr_factory_.GetWeakPtr(), callback, list_error, + is_last_entry)); + } +} + +void SmbFileSystem::HandleDeleteEntryCallback( + storage::AsyncFileUtil::StatusCallback callback, + smbprovider::ErrorType list_error, + bool is_last_entry, + smbprovider::ErrorType delete_error) const { + if (is_last_entry) { + // Only run the callback once. + if (list_error != smbprovider::ERROR_OK) { + delete_error = list_error; + } + callback.Run(TranslateError(delete_error)); + } +} + void SmbFileSystem::HandleRequestGetMetadataEntryCallback( ProvidedFileSystemInterface::MetadataFieldMask fields, const ProvidedFileSystemInterface::GetMetadataCallback& callback,
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.h b/chrome/browser/chromeos/smb_client/smb_file_system.h index d855c88..f17f486 100644 --- a/chrome/browser/chromeos/smb_client/smb_file_system.h +++ b/chrome/browser/chromeos/smb_client/smb_file_system.h
@@ -213,6 +213,17 @@ smbprovider::ErrorType error, const base::ScopedFD& fd) const; + void HandleGetDeleteListCallback( + storage::AsyncFileUtil::StatusCallback callback, + smbprovider::ErrorType list_error, + const smbprovider::DeleteListProto& delete_list); + + void HandleDeleteEntryCallback( + storage::AsyncFileUtil::StatusCallback callback, + smbprovider::ErrorType list_error, + bool is_last_entry, + smbprovider::ErrorType delete_error) const; + int32_t GetMountId() const; SmbProviderClient* GetSmbProviderClient() const;
diff --git a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc index 50e2219..175f4b2 100644 --- a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc +++ b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
@@ -344,54 +344,6 @@ return tray()->detailed_menu_->tap_dragging_enabled_; } - bool IsSpokenFeedbackMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->spoken_feedback_view_; - } - - bool IsHighContrastMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->high_contrast_view_; - } - - bool IsScreenMagnifierMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->screen_magnifier_view_; - } - - bool IsLargeCursorMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->large_cursor_view_; - } - - bool IsAutoclickMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->autoclick_view_; - } - - bool IsVirtualKeyboardMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->virtual_keyboard_view_; - } - - bool IsMonoAudioMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->mono_audio_view_; - } - - bool IsCaretHighlightMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->caret_highlight_view_; - } - - bool IsHighlightMouseCursorMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->highlight_mouse_cursor_view_; - } - - bool IsHighlightKeyboardFocusMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->highlight_keyboard_focus_view_; - } - - bool IsStickyKeysMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->sticky_keys_view_; - } - - bool IsTapDraggingMenuShownOnDetailMenu() const { - return tray()->detailed_menu_->tap_dragging_view_; - } - // In material design we show the help button but theme it as disabled if // it is not possible to load the help page. static bool IsHelpAvailableOnDetailMenu() { @@ -994,6 +946,7 @@ EXPECT_TRUE(CanCreateMenuItem()); } +// TODO: Move to ash_unittests. IN_PROC_BROWSER_TEST_P(TrayAccessibilityTest, KeepMenuVisibilityOnLockScreen) { // Enables high contrast mode. EnableHighContrast(true); @@ -1158,6 +1111,7 @@ EXPECT_FALSE(AccessibilityManager::Get()->IsSelectToSpeakEnabled()); } +// TODO: Move to ash_unittests. IN_PROC_BROWSER_TEST_P(TrayAccessibilityTest, CheckMarksOnDetailMenu) { SetLoginStatus(ash::LoginStatus::NOT_LOGGED_IN); @@ -1668,82 +1622,11 @@ CloseDetailMenu(); } -// Flaky failures of IsHelpAvailableOnDetailMenu(). Possible race condition -// with session state. https://crbug.com/819987 -IN_PROC_BROWSER_TEST_P(TrayAccessibilityTest, - DISABLED_CheckMenuVisibilityOnDetailMenu) { - // Except help & settings, others should be kept the same - // in LOGIN | NOT LOGIN | LOCKED. https://crbug.com/632107. - EXPECT_TRUE(CreateDetailedMenu()); - EXPECT_TRUE(IsSpokenFeedbackMenuShownOnDetailMenu()); - EXPECT_FALSE(IsSelectToSpeakEnabledOnDetailMenu()); - EXPECT_TRUE(IsHighContrastMenuShownOnDetailMenu()); - EXPECT_TRUE(IsScreenMagnifierMenuShownOnDetailMenu()); - EXPECT_TRUE(IsAutoclickMenuShownOnDetailMenu()); - EXPECT_TRUE(IsVirtualKeyboardMenuShownOnDetailMenu()); - EXPECT_TRUE(IsHelpAvailableOnDetailMenu()); - EXPECT_TRUE(IsSettingsAvailableOnDetailMenu()); - EXPECT_TRUE(IsLargeCursorMenuShownOnDetailMenu()); - EXPECT_TRUE(IsMonoAudioMenuShownOnDetailMenu()); - EXPECT_TRUE(IsCaretHighlightMenuShownOnDetailMenu()); - EXPECT_TRUE(IsHighlightMouseCursorMenuShownOnDetailMenu()); - EXPECT_TRUE(IsHighlightKeyboardFocusMenuShownOnDetailMenu()); - EXPECT_TRUE(IsStickyKeysMenuShownOnDetailMenu()); - EXPECT_TRUE(IsTapDraggingMenuShownOnDetailMenu()); - CloseDetailMenu(); - - // Simulate screen lock. - session_manager::SessionManager::Get()->SetSessionState( - session_manager::SessionState::LOCKED); - // Flush to ensure the session state reaches ash and updates login status. - SessionControllerClient::FlushForTesting(); - EXPECT_TRUE(CreateDetailedMenu()); - EXPECT_TRUE(IsSpokenFeedbackMenuShownOnDetailMenu()); - EXPECT_FALSE(IsSelectToSpeakEnabledOnDetailMenu()); - EXPECT_TRUE(IsHighContrastMenuShownOnDetailMenu()); - EXPECT_TRUE(IsScreenMagnifierMenuShownOnDetailMenu()); - EXPECT_TRUE(IsAutoclickMenuShownOnDetailMenu()); - EXPECT_TRUE(IsVirtualKeyboardMenuShownOnDetailMenu()); - EXPECT_FALSE(IsHelpAvailableOnDetailMenu()); - EXPECT_FALSE(IsSettingsAvailableOnDetailMenu()); - EXPECT_TRUE(IsLargeCursorMenuShownOnDetailMenu()); - EXPECT_TRUE(IsMonoAudioMenuShownOnDetailMenu()); - EXPECT_TRUE(IsCaretHighlightMenuShownOnDetailMenu()); - EXPECT_TRUE(IsHighlightMouseCursorMenuShownOnDetailMenu()); - EXPECT_TRUE(IsHighlightKeyboardFocusMenuShownOnDetailMenu()); - EXPECT_TRUE(IsStickyKeysMenuShownOnDetailMenu()); - EXPECT_TRUE(IsTapDraggingMenuShownOnDetailMenu()); - CloseDetailMenu(); - - // Simulate adding multiprofile user. - session_manager::SessionManager::Get()->SetSessionState( - session_manager::SessionState::LOGIN_SECONDARY); - // Flush to ensure the session state reaches ash and updates login status. - SessionControllerClient::FlushForTesting(); - EXPECT_TRUE(CreateDetailedMenu()); - EXPECT_TRUE(IsSpokenFeedbackMenuShownOnDetailMenu()); - EXPECT_FALSE(IsSelectToSpeakEnabledOnDetailMenu()); - EXPECT_TRUE(IsHighContrastMenuShownOnDetailMenu()); - EXPECT_TRUE(IsScreenMagnifierMenuShownOnDetailMenu()); - EXPECT_TRUE(IsAutoclickMenuShownOnDetailMenu()); - EXPECT_TRUE(IsVirtualKeyboardMenuShownOnDetailMenu()); - EXPECT_FALSE(IsHelpAvailableOnDetailMenu()); - EXPECT_FALSE(IsSettingsAvailableOnDetailMenu()); - EXPECT_TRUE(IsLargeCursorMenuShownOnDetailMenu()); - EXPECT_TRUE(IsMonoAudioMenuShownOnDetailMenu()); - EXPECT_TRUE(IsCaretHighlightMenuShownOnDetailMenu()); - EXPECT_TRUE(IsHighlightMouseCursorMenuShownOnDetailMenu()); - EXPECT_TRUE(IsHighlightKeyboardFocusMenuShownOnDetailMenu()); - EXPECT_TRUE(IsStickyKeysMenuShownOnDetailMenu()); - EXPECT_TRUE(IsTapDraggingMenuShownOnDetailMenu()); - CloseDetailMenu(); -} - // Verify that the accessiblity system detailed menu remains open when an item // is selected or deselected. +// TODO: Move to ash_unittests. IN_PROC_BROWSER_TEST_P(TrayAccessibilityTest, DetailMenuRemainsOpen) { EXPECT_TRUE(CreateDetailedMenu()); - ASSERT_TRUE(IsAutoclickMenuShownOnDetailMenu()); ClickAutoclickOnDetailMenu(); EXPECT_TRUE(IsAutoclickEnabledOnDetailMenu());
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc index ef80069..6d87646 100644 --- a/chrome/browser/client_hints/client_hints_browsertest.cc +++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -29,54 +29,50 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" -#include "net/test/url_request/url_request_mock_data_job.h" -#include "net/url_request/url_request_context.h" -#include "net/url_request/url_request_context_getter.h" -#include "net/url_request/url_request_filter.h" -#include "net/url_request/url_request_interceptor.h" -#include "net/url_request/url_request_job.h" -#include "net/url_request/url_request_test_job.h" namespace { // An interceptor that records count of fetches and client hint headers for // requests to https://foo.com/non-existing-image.jpg. -class ThirdPartyRequestInterceptor : public net::URLRequestInterceptor { +class ThirdPartyURLLoaderInterceptor { public: - ThirdPartyRequestInterceptor() - : request_count_seen_(0u), client_hints_count_seen_(0u) {} + explicit ThirdPartyURLLoaderInterceptor(const GURL intercepted_url) + : intercepted_url_(intercepted_url), + interceptor_(base::BindRepeating( + &ThirdPartyURLLoaderInterceptor::InterceptURLRequest, + base::Unretained(this))) {} - ~ThirdPartyRequestInterceptor() override = default; - - // net::URLRequestInterceptor implementation - net::URLRequestJob* MaybeInterceptRequest( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - net::HttpRequestHeaders headers = request->extra_request_headers(); - - request_count_seen_++; - if (headers.HasHeader("dpr")) { - client_hints_count_seen_++; - } - if (headers.HasHeader("device-memory")) { - client_hints_count_seen_++; - } - return new net::URLRequestMockDataJob(request, network_delegate, "contents", - 1, false); - } + ~ThirdPartyURLLoaderInterceptor() = default; size_t request_count_seen() const { return request_count_seen_; } size_t client_hints_count_seen() const { return client_hints_count_seen_; } private: - mutable size_t request_count_seen_; + bool InterceptURLRequest( + content::URLLoaderInterceptor::RequestParams* params) { + if (params->url_request.url != intercepted_url_) + return false; - mutable size_t client_hints_count_seen_; + request_count_seen_++; + if (params->url_request.headers.HasHeader("dpr")) { + client_hints_count_seen_++; + } + if (params->url_request.headers.HasHeader("device-memory")) { + client_hints_count_seen_++; + } + return false; + } - DISALLOW_COPY_AND_ASSIGN(ThirdPartyRequestInterceptor); + GURL intercepted_url_; + + size_t request_count_seen_ = 0u; + + size_t client_hints_count_seen_ = 0u; + + content::URLLoaderInterceptor interceptor_; + + DISALLOW_COPY_AND_ASSIGN(ThirdPartyURLLoaderInterceptor); }; } // namespace @@ -151,17 +147,13 @@ content::BrowserThread::IO, FROM_HERE, base::BindOnce(&chrome_browser_net::SetUrlRequestMocksEnabled, true)); - request_interceptor_ = new ThirdPartyRequestInterceptor(); - std::unique_ptr<net::URLRequestInterceptor> owned_interceptor( - request_interceptor_); - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&InstallMockInterceptors, - GURL("https://foo.com/non-existing-image.jpg"), - std::move(owned_interceptor))); + request_interceptor_ = std::make_unique<ThirdPartyURLLoaderInterceptor>( + GURL("https://foo.com/non-existing-image.jpg")); base::RunLoop().RunUntilIdle(); } + void TearDownOnMainThread() override { request_interceptor_.reset(); } + void SetUpCommandLine(base::CommandLine* cmd) override { cmd->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures); } @@ -241,16 +233,6 @@ } private: - static void InstallMockInterceptors( - const GURL& url, - std::unique_ptr<net::URLRequestInterceptor> request_interceptor) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - chrome_browser_net::SetUrlRequestMocksEnabled(true); - - net::URLRequestFilter::GetInstance()->AddUrlInterceptor( - url, std::move(request_interceptor)); - } - // Called by |https_server_|. void MonitorResourceRequest(const net::test_server::HttpRequest& request) { bool is_main_frame_navigation = @@ -297,8 +279,7 @@ size_t count_client_hints_headers_seen_; - // Not owned. May be null. - ThirdPartyRequestInterceptor* request_interceptor_; + std::unique_ptr<ThirdPartyURLLoaderInterceptor> request_interceptor_; DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTest); };
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn index dd7f4e8e..a1264b2e 100644 --- a/chrome/browser/devtools/BUILD.gn +++ b/chrome/browser/devtools/BUILD.gn
@@ -117,6 +117,7 @@ "//base", "//content/public/browser", "//net", + "//services/viz/privileged/interfaces/compositing", "//third_party/WebKit/public:features", "//ui/events:dom_keycode_converter", ]
diff --git a/chrome/browser/devtools/devtools_eye_dropper.cc b/chrome/browser/devtools/devtools_eye_dropper.cc index 742b752..7b1c93b 100644 --- a/chrome/browser/devtools/devtools_eye_dropper.cc +++ b/chrome/browser/devtools/devtools_eye_dropper.cc
@@ -6,12 +6,15 @@ #include "base/bind.h" #include "build/build_config.h" +#include "cc/paint/skia_paint_canvas.h" +#include "components/viz/common/features.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" #include "content/public/common/cursor_info.h" #include "content/public/common/screen_info.h" +#include "media/base/limits.h" #include "third_party/WebKit/public/platform/WebInputEvent.h" #include "third_party/WebKit/public/platform/WebMouseEvent.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -27,6 +30,9 @@ last_cursor_x_(-1), last_cursor_y_(-1), host_(nullptr), + video_consumer_binding_(this), + enable_viz_( + base::FeatureList::IsEnabled(features::kVizDisplayCompositor)), weak_factory_(this) { mouse_event_callback_ = base::Bind(&DevToolsEyeDropper::HandleMouseEvent, base::Unretained(this)); @@ -44,6 +50,29 @@ void DevToolsEyeDropper::AttachToHost(content::RenderWidgetHost* host) { host_ = host; host_->AddMouseEventCallback(mouse_event_callback_); + + // TODO(crbug.com/813929): Use video capturer even if viz is not enabled. + if (!enable_viz_) + return; + + // Capturing a full-page screenshot can be costly so we shouldn't do it too + // often. We can capture at a lower frame rate without hurting the user + // experience. + constexpr static int kMaxFrameRate = 15; + + // Create and configure the video capturer. + video_capturer_ = host_->GetView()->CreateVideoCapturer(); + video_capturer_->SetResolutionConstraints( + gfx::Size(1, 1), + gfx::Size(media::limits::kMaxDimension, media::limits::kMaxDimension), + false); + video_capturer_->SetMinCapturePeriod(base::TimeDelta::FromSeconds(1) / + kMaxFrameRate); + + // Start video capture. + viz::mojom::FrameSinkVideoConsumerPtr consumer; + video_consumer_binding_.Bind(mojo::MakeRequest(&consumer)); + video_capturer_->Start(std::move(consumer)); } void DevToolsEyeDropper::DetachFromHost() { @@ -53,6 +82,8 @@ content::CursorInfo cursor_info; cursor_info.type = blink::WebCursorInfo::kTypePointer; host_->SetCursor(cursor_info); + video_consumer_binding_.Close(); + video_capturer_.reset(); host_ = nullptr; } @@ -85,7 +116,7 @@ } void DevToolsEyeDropper::UpdateFrame() { - if (!host_ || !host_->GetView()) + if (enable_viz_ || !host_ || !host_->GetView()) return; // TODO(miu): This is the wrong size. It's the size of the view on-screen, and @@ -106,6 +137,7 @@ } void DevToolsEyeDropper::FrameUpdated(const SkBitmap& bitmap) { + DCHECK(!enable_viz_); if (bitmap.drawsNothing()) return; frame_ = bitmap; @@ -271,3 +303,42 @@ kHotspotOffset * device_scale_factor); host_->SetCursor(cursor_info); } + +void DevToolsEyeDropper::OnFrameCaptured( + mojo::ScopedSharedBufferHandle buffer, + uint32_t buffer_size, + ::media::mojom::VideoFrameInfoPtr info, + const gfx::Rect& update_rect, + const gfx::Rect& content_rect, + viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) { + if (!buffer.is_valid()) { + callbacks->Done(); + return; + } + mojo::ScopedSharedBufferMapping mapping = buffer->Map(buffer_size); + if (!mapping) { + DLOG(ERROR) << "Shared memory mapping failed."; + return; + } + scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData( + info->pixel_format, info->coded_size, info->visible_rect, + info->visible_rect.size(), static_cast<uint8_t*>(mapping.get()), + buffer_size, info->timestamp); + if (!frame) + return; + frame->AddDestructionObserver(base::BindOnce( + [](mojo::ScopedSharedBufferMapping mapping) {}, std::move(mapping))); + + SkBitmap skbitmap; + skbitmap.allocN32Pixels(info->visible_rect.width(), + info->visible_rect.height()); + cc::SkiaPaintCanvas canvas(skbitmap); + video_renderer_.Copy(frame, &canvas, media::Context3D()); + + frame_ = skbitmap; + UpdateCursor(); +} + +void DevToolsEyeDropper::OnTargetLost(const viz::FrameSinkId& frame_sink_id) {} + +void DevToolsEyeDropper::OnStopped() {}
diff --git a/chrome/browser/devtools/devtools_eye_dropper.h b/chrome/browser/devtools/devtools_eye_dropper.h index 4956dce6..cf1ce5b0 100644 --- a/chrome/browser/devtools/devtools_eye_dropper.h +++ b/chrome/browser/devtools/devtools_eye_dropper.h
@@ -9,13 +9,17 @@ #include "base/macros.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents_observer.h" +#include "media/renderers/paint_canvas_video_renderer.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h" #include "third_party/skia/include/core/SkBitmap.h" namespace blink { class WebMouseEvent; } -class DevToolsEyeDropper : public content::WebContentsObserver { +class DevToolsEyeDropper : public content::WebContentsObserver, + public viz::mojom::FrameSinkVideoConsumer { public: typedef base::Callback<void(int, int, int, int)> EyeDropperCallback; @@ -40,12 +44,27 @@ bool HandleMouseEvent(const blink::WebMouseEvent& event); void UpdateCursor(); + // viz::mojom::FrameSinkVideoConsumer implementation. + void OnFrameCaptured( + mojo::ScopedSharedBufferHandle buffer, + uint32_t buffer_size, + ::media::mojom::VideoFrameInfoPtr info, + const gfx::Rect& update_rect, + const gfx::Rect& content_rect, + viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) override; + void OnTargetLost(const viz::FrameSinkId& frame_sink_id) override; + void OnStopped() override; + EyeDropperCallback callback_; SkBitmap frame_; int last_cursor_x_; int last_cursor_y_; content::RenderWidgetHost::MouseEventCallback mouse_event_callback_; content::RenderWidgetHost* host_; + viz::mojom::FrameSinkVideoCapturerPtr video_capturer_; + mojo::Binding<viz::mojom::FrameSinkVideoConsumer> video_consumer_binding_; + const bool enable_viz_; + media::PaintCanvasVideoRenderer video_renderer_; base::WeakPtrFactory<DevToolsEyeDropper> weak_factory_; DISALLOW_COPY_AND_ASSIGN(DevToolsEyeDropper);
diff --git a/chrome/browser/download/download_service_factory.cc b/chrome/browser/download/download_service_factory.cc index 4de785d9b..9776dc5 100644 --- a/chrome/browser/download/download_service_factory.cc +++ b/chrome/browser/download/download_service_factory.cc
@@ -29,7 +29,6 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" -#include "net/url_request/url_request_context_getter.h" #if defined(OS_ANDROID) #include "chrome/browser/android/download/service/download_task_scheduler.h" @@ -79,10 +78,6 @@ // Build in memory download service for incognito profile. if (context->IsOffTheRecord() && base::FeatureList::IsEnabled(download::kDownloadServiceIncognito)) { - scoped_refptr<net::URLRequestContextGetter> url_request_context = - content::BrowserContext::GetDefaultStoragePartition( - Profile::FromBrowserContext(context)) - ->GetURLRequestContext(); content::BrowserContext::BlobContextGetter blob_context_getter = content::BrowserContext::GetBlobStorageContext(context); scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = @@ -90,8 +85,8 @@ content::BrowserThread::IO); return download::BuildInMemoryDownloadService( - context, std::move(clients), base::FilePath(), url_request_context, - blob_context_getter, io_task_runner); + context, std::move(clients), base::FilePath(), blob_context_getter, + io_task_runner); } else { // Build download service for normal profile. base::FilePath storage_dir;
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index 2fbe7a4..fdcee0a 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -853,6 +853,7 @@ "//components/sync_sessions", "//components/translate/core/browser", "//components/undo", + "//components/unzip_service/public/cpp", "//components/update_client", "//components/url_matcher", "//components/user_prefs",
diff --git a/chrome/browser/extensions/DEPS b/chrome/browser/extensions/DEPS index 5e0ad1d..73dab839 100644 --- a/chrome/browser/extensions/DEPS +++ b/chrome/browser/extensions/DEPS
@@ -37,6 +37,9 @@ # TODO(mash): Remove. http://crbug.com/678705 "+ash/shell.h", ], + "zipfile_installer_unittest.cc": [ + "+services/data_decoder", + ], "test_extension_system.cc": [ "+services/data_decoder", ],
diff --git a/chrome/browser/extensions/zipfile_installer_unittest.cc b/chrome/browser/extensions/zipfile_installer_unittest.cc index b347b3f7..43994cc 100644 --- a/chrome/browser/extensions/zipfile_installer_unittest.cc +++ b/chrome/browser/extensions/zipfile_installer_unittest.cc
@@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <vector> + #include "base/bind.h" #include "base/command_line.h" +#include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" @@ -19,12 +22,16 @@ #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/testing_profile.h" +#include "components/unzip_service/unzip_service.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry_observer.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" +#include "services/data_decoder/data_decoder_service.h" +#include "services/service_manager/public/cpp/connector.h" +#include "services/service_manager/public/cpp/test/test_connector_factory.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_CHROMEOS) @@ -81,12 +88,27 @@ base::Closure quit_closure; }; +struct UnzipFileFilterTestCase { + const base::FilePath::CharType* input; + const bool should_unzip; +}; + } // namespace class ZipFileInstallerTest : public testing::Test { public: ZipFileInstallerTest() - : browser_threads_(content::TestBrowserThreadBundle::IO_MAINLOOP) {} + : browser_threads_(content::TestBrowserThreadBundle::IO_MAINLOOP) { + service_manager::TestConnectorFactory::NameToServiceMap services; + services.insert(std::make_pair("data_decoder", + data_decoder::DataDecoderService::Create())); + services.insert( + std::make_pair("unzip_service", unzip::UnzipService::CreateService())); + test_connector_factory_ = + service_manager::TestConnectorFactory::CreateForServices( + std::move(services)); + connector_ = test_connector_factory_->CreateConnector(); + } void SetUp() override { extensions::LoadErrorReporter::Init(/*enable_noisy_errors=*/false); @@ -121,8 +143,8 @@ .AppendASCII("zipfile_installer") .AppendASCII(zip_name); ASSERT_TRUE(base::PathExists(original_path)) << original_path.value(); - zipfile_installer_ = ZipFileInstaller::Create( + connector_.get(), MakeRegisterInExtensionServiceCallback(extension_service_)); base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -131,6 +153,17 @@ observer_.WaitForInstall(expect_error); } + void RunZipFileFilterTest( + const std::vector<UnzipFileFilterTestCase>& cases, + base::RepeatingCallback<bool(const base::FilePath&)>& filter) { + for (size_t i = 0; i < cases.size(); ++i) { + base::FilePath input(cases[i].input); + bool observed = filter.Run(input); + EXPECT_EQ(cases[i].should_unzip, observed) + << "i: " << i << ", input: " << input.value(); + } + } + protected: scoped_refptr<ZipFileInstaller> zipfile_installer_; @@ -148,6 +181,11 @@ // ChromeOS needs a user manager to instantiate an extension service. chromeos::ScopedTestUserManager test_user_manager_; #endif + + private: + std::unique_ptr<service_manager::TestConnectorFactory> + test_connector_factory_; + std::unique_ptr<service_manager::Connector> connector_; }; TEST_F(ZipFileInstallerTest, GoodZip) { @@ -165,4 +203,49 @@ EXPECT_EQ(observer_.last_extension_installed, kIdForPublicKey); } +TEST_F(ZipFileInstallerTest, NonTheme_FileExtractionFilter) { + const std::vector<UnzipFileFilterTestCase> cases = { + {FILE_PATH_LITERAL("foo"), true}, + {FILE_PATH_LITERAL("foo.nexe"), true}, + {FILE_PATH_LITERAL("foo.dll"), true}, + {FILE_PATH_LITERAL("foo.jpg.exe"), false}, + {FILE_PATH_LITERAL("foo.exe"), false}, + {FILE_PATH_LITERAL("foo.EXE"), false}, + {FILE_PATH_LITERAL("file_without_extension"), true}, + }; + base::RepeatingCallback<bool(const base::FilePath&)> filter = + base::BindRepeating(&ZipFileInstaller::ShouldExtractFile, false); + RunZipFileFilterTest(cases, filter); +} + +TEST_F(ZipFileInstallerTest, Theme_FileExtractionFilter) { + const std::vector<UnzipFileFilterTestCase> cases = { + {FILE_PATH_LITERAL("image.jpg"), true}, + {FILE_PATH_LITERAL("IMAGE.JPEG"), true}, + {FILE_PATH_LITERAL("test/image.bmp"), true}, + {FILE_PATH_LITERAL("test/IMAGE.gif"), true}, + {FILE_PATH_LITERAL("test/image.WEBP"), true}, + {FILE_PATH_LITERAL("test/dir/file.image.png"), true}, + {FILE_PATH_LITERAL("manifest.json"), true}, + {FILE_PATH_LITERAL("other.html"), false}, + {FILE_PATH_LITERAL("file_without_extension"), true}, + }; + base::RepeatingCallback<bool(const base::FilePath&)> filter = + base::BindRepeating(&ZipFileInstaller::ShouldExtractFile, true); + RunZipFileFilterTest(cases, filter); +} + +TEST_F(ZipFileInstallerTest, ManifestExtractionFilter) { + const std::vector<UnzipFileFilterTestCase> cases = { + {FILE_PATH_LITERAL("manifest.json"), true}, + {FILE_PATH_LITERAL("MANIFEST.JSON"), true}, + {FILE_PATH_LITERAL("test/manifest.json"), false}, + {FILE_PATH_LITERAL("manifest.json/test"), false}, + {FILE_PATH_LITERAL("other.file"), false}, + }; + base::RepeatingCallback<bool(const base::FilePath&)> filter = + base::BindRepeating(&ZipFileInstaller::IsManifestFile); + RunZipFileFilterTest(cases, filter); +} + } // namespace extensions
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 81e265c4..b5a72027 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -347,6 +347,10 @@ const char kEnableClientLoFiDescription[] = "Enable showing low fidelity images on some pages on slow networks."; +const char kEnableCursorMotionBlurName[] = "Enable Cursor Motion Blur"; +const char kEnableCursorMotionBlurDescription[] = + "Enable motion blur effect for the cursor."; + const char kEnableNoScriptPreviewsName[] = "NoScript previews"; const char kEnableNoScriptPreviewsDescription[] = @@ -1400,11 +1404,25 @@ const char kSingleClickAutofillDescription[] = "Make autofill suggestions on initial mouse click on a form element."; -const char kSitePerProcessName[] = "Strict site isolation"; -const char kSitePerProcessDescription[] = - "Experimental security mode that ensures each renderer process " - "contains pages from at most one site. In this mode, out-of-process " - "iframes will be used whenever an iframe is cross-site."; +const char kStrictSiteIsolationName[] = "Strict site isolation"; +const char kStrictSiteIsolationDescription[] = + "Security mode that enables site isolation for all sites. When enabled, " + "each renderer process will contain pages from at most one site, using " + "out-of-process iframes when needed. When enabled, this flag forces the " + "strictest site isolation mode (SitePerProcess). When disabled, the site " + "isolation mode will be determined by enterprise policy or field trial."; + +const char kSiteIsolationTrialOptOutName[] = "Site isolation trial opt-out"; +const char kSiteIsolationTrialOptOutDescription[] = + "Opts out of field trials that enable site isolation modes " + "(SitePerProcess, IsolateOrigins, etc). Intended for diagnosing bugs that " + "may be due to out-of-process iframes. Opt-out has no effect if site " + "isolation is force-enabled via #enable-site-per-process or enterprise " + "policy. Caution: this disables important mitigations for the Spectre CPU " + "vulnerability affecting most computers."; +extern const char kSiteIsolationTrialOptOutChoiceDefault[] = "Default"; +extern const char kSiteIsolationTrialOptOutChoiceOptOut[] = + "Opt-out (not recommended)"; const char kSiteSettings[] = "Site settings with All sites and Site details"; const char kSiteSettingsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 0d746b6..0e2e9fa 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -244,6 +244,9 @@ extern const char kEnableClientLoFiName[]; extern const char kEnableClientLoFiDescription[]; +extern const char kEnableCursorMotionBlurName[]; +extern const char kEnableCursorMotionBlurDescription[]; + extern const char kEnableNoScriptPreviewsName[]; extern const char kEnableNoScriptPreviewsDescription[]; @@ -857,8 +860,13 @@ extern const char kSingleClickAutofillName[]; extern const char kSingleClickAutofillDescription[]; -extern const char kSitePerProcessName[]; -extern const char kSitePerProcessDescription[]; +extern const char kStrictSiteIsolationName[]; +extern const char kStrictSiteIsolationDescription[]; + +extern const char kSiteIsolationTrialOptOutName[]; +extern const char kSiteIsolationTrialOptOutDescription[]; +extern const char kSiteIsolationTrialOptOutChoiceDefault[]; +extern const char kSiteIsolationTrialOptOutChoiceOptOut[]; extern const char kSiteSettings[]; extern const char kSiteSettingsDescription[];
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc index 1cc2961..5b7be3d3 100644 --- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc +++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
@@ -53,11 +53,12 @@ base::BindRepeating(&DialMediaSinkServiceImpl::OnAppInfoParseCompleted, base::Unretained(this))); + MediaSinkServiceBase::StartTimer(); + dial_registry_ = test_dial_registry_ ? test_dial_registry_ : DialRegistry::GetInstance(); dial_registry_->RegisterObserver(this); dial_registry_->OnListenerAdded(); - MediaSinkServiceBase::StartTimer(); } void DialMediaSinkServiceImpl::OnUserGesture() { @@ -127,6 +128,9 @@ current_devices_ = devices; description_service_->GetDeviceDescriptions(devices); + + // Makes sure the timer fires even if there is no device. + MediaSinkServiceBase::RestartTimer(); } void DialMediaSinkServiceImpl::OnDialError(DialRegistry::DialErrorCode type) {
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h index a5b6da6..56e87ad0 100644 --- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h +++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
@@ -84,7 +84,10 @@ friend class DialMediaSinkServiceImplTest; friend class MockDialMediaSinkServiceImpl; FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest, TestStart); - FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest, TestTimer); + FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest, + TestOnDeviceDescriptionRestartsTimer); + FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest, + TestOnDialDeviceEventRestartsTimer); FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest, TestOnDeviceDescriptionAvailable); FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc index 521463a..37332f9 100644 --- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc +++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
@@ -166,7 +166,7 @@ } } -TEST_F(DialMediaSinkServiceImplTest, TestTimer) { +TEST_F(DialMediaSinkServiceImplTest, TestOnDeviceDescriptionRestartsTimer) { DialDeviceData device_data("first", GURL("http://127.0.0.1/dd.xml"), base::Time::Now()); ParsedDialDeviceDescription device_description; @@ -196,6 +196,32 @@ EXPECT_TRUE(mock_timer_->IsRunning()); } +TEST_F(DialMediaSinkServiceImplTest, TestOnDialDeviceEventRestartsTimer) { + MediaSinkInternal dial_sink = CreateDialSink(1); + media_sink_service_->current_sinks_.insert_or_assign(dial_sink.sink().id(), + dial_sink); + + EXPECT_CALL(mock_sink_discovered_cb_, Run(_)); + media_sink_service_->OnDiscoveryComplete(); + + EXPECT_FALSE(mock_timer_->IsRunning()); + EXPECT_CALL(*mock_description_service_, + GetDeviceDescriptions(std::vector<DialDeviceData>())); + media_sink_service_->OnDialDeviceEvent(std::vector<DialDeviceData>()); + EXPECT_TRUE(mock_timer_->IsRunning()); + + EXPECT_CALL(mock_sink_discovered_cb_, Run(std::vector<MediaSinkInternal>())); + mock_timer_->Fire(); + + EXPECT_CALL(*mock_description_service_, + GetDeviceDescriptions(std::vector<DialDeviceData>())); + media_sink_service_->OnDialDeviceEvent(std::vector<DialDeviceData>()); + EXPECT_TRUE(mock_timer_->IsRunning()); + + EXPECT_CALL(mock_sink_discovered_cb_, Run(_)).Times(0); + mock_timer_->Fire(); +} + TEST_F(DialMediaSinkServiceImplTest, OnDialSinkAddedCallback) { DialDeviceData device_data1("first", GURL("http://127.0.0.1/dd.xml"), base::Time::Now());
diff --git a/chrome/browser/metrics/thread_watcher_report_hang.cc b/chrome/browser/metrics/thread_watcher_report_hang.cc index 5385f87..0e45e1e 100644 --- a/chrome/browser/metrics/thread_watcher_report_hang.cc +++ b/chrome/browser/metrics/thread_watcher_report_hang.cc
@@ -50,12 +50,6 @@ ReportThreadHang(); } -NOINLINE void ThreadUnresponsive_PROCESS_LAUNCHER() { - volatile int inhibit_comdat = __LINE__; - ALLOW_UNUSED_LOCAL(inhibit_comdat); - ReportThreadHang(); -} - NOINLINE void ThreadUnresponsive_IO() { volatile int inhibit_comdat = __LINE__; ALLOW_UNUSED_LOCAL(inhibit_comdat); @@ -67,8 +61,6 @@ switch (thread_id) { case content::BrowserThread::UI: return ThreadUnresponsive_UI(); - case content::BrowserThread::PROCESS_LAUNCHER: - return ThreadUnresponsive_PROCESS_LAUNCHER(); case content::BrowserThread::IO: return ThreadUnresponsive_IO(); case content::BrowserThread::ID_COUNT:
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index 0610049..bef2eac7 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -55,7 +55,6 @@ #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/content_features.h" #include "content/public/common/context_menu_params.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_navigation_observer.h" @@ -888,42 +887,6 @@ EXPECT_EQ(base::ASCIIToUTF16("test.pdf"), GetActiveWebContents()->GetTitle()); } -IN_PROC_BROWSER_TEST_F(PDFExtensionTest, MultipleDomains) { - for (const auto& url : - {embedded_test_server()->GetURL("a.com", "/pdf/test.pdf"), - embedded_test_server()->GetURL("b.com", "/pdf/test.pdf"), - embedded_test_server()->GetURL("c.com", "/pdf/test.pdf"), - embedded_test_server()->GetURL("d.com", "/pdf/test.pdf")}) { - ASSERT_TRUE(LoadPdf(url)); - } - EXPECT_EQ(1, CountPDFProcesses()); -} - -class PDFIsolatedExtensionTest : public PDFExtensionTest { - public: - PDFIsolatedExtensionTest() {} - ~PDFIsolatedExtensionTest() override {} - - void SetUp() override { - features_.InitAndEnableFeature(features::kPdfIsolation); - PDFExtensionTest::SetUp(); - } - - private: - base::test::ScopedFeatureList features_; -}; - -IN_PROC_BROWSER_TEST_F(PDFIsolatedExtensionTest, MultipleDomains) { - for (const auto& url : - {embedded_test_server()->GetURL("a.com", "/pdf/test.pdf"), - embedded_test_server()->GetURL("b.com", "/pdf/test.pdf"), - embedded_test_server()->GetURL("c.com", "/pdf/test.pdf"), - embedded_test_server()->GetURL("d.com", "/pdf/test.pdf")}) { - ASSERT_TRUE(LoadPdf(url)); - } - EXPECT_EQ(4, CountPDFProcesses()); -} - class PDFExtensionLinkClickTest : public PDFExtensionTest { public: PDFExtensionLinkClickTest() : guest_contents_(nullptr) {}
diff --git a/chrome/browser/policy/site_isolation_policy_browsertest.cc b/chrome/browser/policy/site_isolation_policy_browsertest.cc index 911056d..d5d4b47 100644 --- a/chrome/browser/policy/site_isolation_policy_browsertest.cc +++ b/chrome/browser/policy/site_isolation_policy_browsertest.cc
@@ -140,6 +140,19 @@ DISALLOW_COPY_AND_ASSIGN(WebDriverSitePerProcessPolicyBrowserTest); }; +// Ensure that --disable-site-isolation-trials does not override policies. +class NoOverrideSitePerProcessPolicyBrowserTest + : public SitePerProcessPolicyBrowserTest { + protected: + NoOverrideSitePerProcessPolicyBrowserTest() {} + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch(switches::kDisableSiteIsolationTrials); + } + + private: + DISALLOW_COPY_AND_ASSIGN(NoOverrideSitePerProcessPolicyBrowserTest); +}; + IN_PROC_BROWSER_TEST_F(SitePerProcessPolicyBrowserTest, Simple) { Expectations expectations[] = { {"https://foo.com/noodles.html", true}, @@ -170,3 +183,11 @@ }; CheckExpectations(expectations, arraysize(expectations)); } + +IN_PROC_BROWSER_TEST_F(NoOverrideSitePerProcessPolicyBrowserTest, Simple) { + Expectations expectations[] = { + {"https://foo.com/noodles.html", true}, + {"http://example.org/pumpkins.html", true}, + }; + CheckExpectations(expectations, arraysize(expectations)); +}
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc index 8fbcb35..f8306073 100644 --- a/chrome/browser/printing/print_view_manager_base.cc +++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -191,6 +191,11 @@ print_job_->StartPdfToEmfConversion(print_data, page_size, content_area, print_text_with_gdi); } + // Indicate that the PDF is fully rendered and we no longer need the renderer + // and web contents, so the print job does not need to be cancelled if they + // die. This is needed on Windows because the PrintedDocument will not be + // considered complete until PDF conversion finishes. + document->SetConvertingPdf(); #else std::unique_ptr<PdfMetafileSkia> metafile = std::make_unique<PdfMetafileSkia>(); @@ -518,6 +523,12 @@ if (!print_job_.get() || !print_job_->is_job_pending()) return false; + // Is the document already complete? + if (print_job_->document() && print_job_->document()->IsComplete()) { + printing_succeeded_ = true; + return true; + } + // We can't print if there is no renderer. if (!web_contents() || !web_contents()->GetRenderViewHost() || @@ -525,12 +536,6 @@ return false; } - // Is the document already complete? - if (print_job_->document() && print_job_->document()->IsComplete()) { - printing_succeeded_ = true; - return true; - } - // WebContents is either dying or a second consecutive request to print // happened before the first had time to finish. We need to render all the // pages in an hurry if a print_job_ is still pending. No need to wait for it
diff --git a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc index bae652f..f6c52d67 100644 --- a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc +++ b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
@@ -22,6 +22,7 @@ #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" @@ -130,9 +131,8 @@ // Ensures that the backgrounding / foregrounding gets a chance to run. void WaitForLauncherThread() { base::RunLoop run_loop; - content::BrowserThread::PostTaskAndReply( - content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE, base::DoNothing(), - run_loop.QuitWhenIdleClosure()); + content::GetProcessLauncherTaskRunner()->PostTaskAndReply( + FROM_HERE, base::DoNothing(), run_loop.QuitWhenIdleClosure()); run_loop.Run(); }
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc index a11970a..266b911 100644 --- a/chrome/browser/resource_coordinator/tab_manager.cc +++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -430,11 +430,23 @@ if (index == -1) return nullptr; - VLOG(1) << "Discarding tab " << index << " id " << tab_id; + DVLOG(1) << "Discarding tab " << index << " id " << tab_id; return DiscardWebContentsAt(index, model, reason); } +void TabManager::FreezeTabById(int32_t tab_id) { + TabStripModel* model = nullptr; + int index = FindTabStripModelById(tab_id, &model); + + if (index == -1) + return; + + DVLOG(1) << "Freezing tab " << index << " id " << tab_id; + + FreezeWebContentsAt(index, model); +} + WebContents* TabManager::DiscardTabByExtension(content::WebContents* contents) { if (contents) { return DiscardTabById(IdFromWebContents(contents), @@ -849,6 +861,17 @@ return null_contents; } +void TabManager::FreezeWebContentsAt(int index, TabStripModel* model) { + WebContents* content = model->GetWebContentsAt(index); + + // Can't freeze tabs that are already discarded or frozen. + // TODO(fmeawad): Only freeze non-frozen tabs. + if (!content || GetWebContentsData(content)->IsDiscarded()) + return; + + content->FreezePage(); +} + void TabManager::PauseBackgroundTabOpeningIfNeeded() { TRACE_EVENT_INSTANT0("navigation", "TabManager::PauseBackgroundTabOpeningIfNeeded",
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h index 5783651..892a73e 100644 --- a/chrome/browser/resource_coordinator/tab_manager.h +++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -125,6 +125,11 @@ // of the discarded tab. content::WebContents* DiscardTabById(int32_t tab_id, DiscardReason reason); + // Freezes a tab with the given unique ID. Unlike discarding, freezing does + // not kill or change the tab other than stopping its task queues. Revisiting + // the tab causes it to unfreeze. + void FreezeTabById(int32_t tab_id); + // Method used by the extensions API to discard tabs. If |contents| is null, // discards the least important tab using DiscardTab(). Otherwise discards // the given contents. Returns the new web_contents or null if no tab @@ -290,6 +295,7 @@ UrgentFastShutdownWithBeforeunloadHandler); FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsTabRestoredInForeground); FRIEND_TEST_ALL_PREFIXES(TabManagerTest, EnablePageAlmostIdleSignal); + FRIEND_TEST_ALL_PREFIXES(TabManagerTest, FreezeTab); // The time of the first purging after a renderer is backgrounded. // The initial value was chosen because most of users activate backgrounded @@ -367,6 +373,10 @@ TabStripModel* model, DiscardReason reason); + // Makes a request to the WebContents at the specified index to freeze its + // page. + void FreezeWebContentsAt(int index, TabStripModel* model); + // Pause or resume background tab opening according to memory pressure change // if there are pending background tabs. void PauseBackgroundTabOpeningIfNeeded();
diff --git a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc index d09b8b5..fd7497c 100644 --- a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc +++ b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
@@ -12,7 +12,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h" -#include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h" #include "chrome/browser/resource_coordinator/tab_manager.h" #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h" #include "chrome/browser/resource_coordinator/time.h" @@ -36,6 +35,7 @@ #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" +#include "net/dns/mock_host_resolver.h" #include "url/gurl.h" using content::OpenURLParams; @@ -58,6 +58,11 @@ kBlinkPageLifecycleFeature); } + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + host_resolver()->AddRule("*", "127.0.0.1"); + } + void OpenTwoTabs(const GURL& first_url, const GURL& second_url) { // Open two tabs. Wait for both of them to load. content::WindowedNotificationObserver load1( @@ -791,6 +796,76 @@ "TabManager.Discarding.DiscardedTabCouldFastShutdown", false, 1); } +IN_PROC_BROWSER_TEST_F(TabManagerTest, FreezeTab) { + const char kMainFrameFrozenStateJS[] = + "window.domAutomationController.send(mainFrameFreezeCount);"; + const char kChildFrameFrozenStateJS[] = + "window.domAutomationController.send(childFrameFreezeCount);"; + + const int freezing_index = 1; // The second tab. + // Setup the embedded_test_server to serve a cross-site frame. + content::SetupCrossSiteRedirector(embedded_test_server()); + ASSERT_TRUE(embedded_test_server()->Start()); + + // Opening two tabs, where the second tab is backgrounded. + GURL main_url( + embedded_test_server()->GetURL("a.com", "/iframe_cross_site.html")); + OpenTwoTabs(GURL(chrome::kChromeUIAboutURL), main_url); + content::WebContents* content = + browser()->tab_strip_model()->GetWebContentsAt(freezing_index); + + // Grab the frames. + content::RenderFrameHost* main_frame = content->GetMainFrame(); + ASSERT_EQ(3u, content->GetAllFrames().size()); + // The page has 2 iframes, we will use the first one. + content::RenderFrameHost* child_frame = content->GetAllFrames()[1]; + // Verify that the main frame and subframe are cross-site. + EXPECT_FALSE(content::SiteInstance::IsSameWebSite( + browser()->profile(), main_frame->GetLastCommittedURL(), + child_frame->GetLastCommittedURL())); + if (content::AreAllSitesIsolatedForTesting()) { + EXPECT_NE(main_frame->GetProcess()->GetID(), + child_frame->GetProcess()->GetID()); + } + + EXPECT_TRUE(content::ExecuteScript( + main_frame, + "if (window.location.pathname != '/iframe_cross_site.html')" + " throw 'Incorrect frame';" + "mainFrameFreezeCount = 0;" + "window.onfreeze = function(){ mainFrameFreezeCount++; };")); + + EXPECT_TRUE(content::ExecuteScript( + child_frame, + "if (window.location.pathname != '/title1.html') throw 'Incorrect frame';" + "childFrameFreezeCount = 0;" + "window.onfreeze = function(){ childFrameFreezeCount++; };")); + + // freeze_count_result should be 0 for both frames, if it is undefined then we + // are in the wrong frame/tab. + int freeze_count_result; + EXPECT_TRUE(content::ExecuteScriptAndExtractInt( + main_frame, kMainFrameFrozenStateJS, &freeze_count_result)); + EXPECT_EQ(0, freeze_count_result); + EXPECT_TRUE(content::ExecuteScriptAndExtractInt( + child_frame, kChildFrameFrozenStateJS, &freeze_count_result)); + EXPECT_EQ(0, freeze_count_result); + + // Freeze the tab. If it fails then we might be freezing a visible tab. + g_browser_process->GetTabManager()->FreezeWebContentsAt( + freezing_index, browser()->tab_strip_model()); + + // freeze_count_result should be exactly 1 for both frames. The valus is + // incremented in the onfreeze callback. If it is >1, then the callback was + // called more than once. + EXPECT_TRUE(content::ExecuteScriptAndExtractInt( + main_frame, kMainFrameFrozenStateJS, &freeze_count_result)); + EXPECT_EQ(1, freeze_count_result); + EXPECT_TRUE(content::ExecuteScriptAndExtractInt( + child_frame, kChildFrameFrozenStateJS, &freeze_count_result)); + EXPECT_EQ(1, freeze_count_result); +} + IN_PROC_BROWSER_TEST_F(TabManagerTest, TabManagerWasDiscarded) { const char kDiscardedStateJS[] = "window.domAutomationController.send("
diff --git a/chrome/browser/resources/chromeos/select_to_speak/options.css b/chrome/browser/resources/chromeos/select_to_speak/options.css index 5fc5037d..c1c426c 100644 --- a/chrome/browser/resources/chromeos/select_to_speak/options.css +++ b/chrome/browser/resources/chromeos/select_to_speak/options.css
@@ -142,10 +142,45 @@ } .highlight { - opacity: .3; - z-index: 10; - top: -40px; - position: relative; height: 20px; + opacity: .3; + position: relative; + top: -40px; width: 100%; + z-index: 10; +} + +.slider { + -webkit-appearance: none; + padding: 15px 0 15px 0; + width: 200px; +} + +.slider::-webkit-slider-runnable-track { + background: #bbb; + border: none; + border-radius: 1px; + height: 2px; +} + +.slider::-webkit-slider-thumb { + -webkit-appearance: none; + -webkit-transition: .200ms; + appearance: none; + background: rgb(51, 103, 214); + border-radius: 50%; + height: 10px; + margin-top: -3px; + transition: width .200ms, height .200ms, margin-top .200ms; + width: 10px; +} + +.slider:active::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + background: rgb(51, 103, 214); + border-radius: 50%; + height: 20px; + margin-top: -10px; + width: 20px; }
diff --git a/chrome/browser/resources/chromeos/select_to_speak/options.html b/chrome/browser/resources/chromeos/select_to_speak/options.html index 26b525f3..7945d08 100644 --- a/chrome/browser/resources/chromeos/select_to_speak/options.html +++ b/chrome/browser/resources/chromeos/select_to_speak/options.html
@@ -23,25 +23,21 @@ </div> <div class="option"> - <span class="i18n" msgid="options_rate_description" - id="rate_description"></span> - <select id="rate" aria-labelledby="rate_description"> + <label class="i18n" msgid="options_rate_description" + id="rate_description"></label> + <div class="example"> <!-- If these options are changed, make sure to update the SelectToSpeak.speechRateToEnum_ function and add new enums in tools/metrics/histograms/enums.xml --> - <option value="0.5" class="i18n" msgid="options_rate_slowest"> - </option> - <option value="0.75" class="i18n" msgid="options_rate_slow"> - </option> - <option value="1.0" class="i18n" msgid="options_rate_normal"> - </option> - <option value="1.25" class="i18n" msgid="options_rate_fast"> - </option> - <option value="1.5" class="i18n" msgid="options_rate_faster"> - </option> - <option value="2.0" class="i18n" msgid="options_rate_fastest"> - </option> - </select> + <input type="range" min="0.5" max="5.0" step=".25" id="rate" + aria-labelledby="rate_description" class="slider"> + <div style="line-height:0px; margin-top:-1.5em"> + <span class="i18n" msgid="options_rate_slowest" + style="float:left"></span> + <span class="i18n" msgid="options_rate_fastest" + style="float:right"></span> + </div> + </div> </div> <div class="option"> @@ -65,11 +61,11 @@ <h2 class="i18n" msgid="options_highlight"></h2> <div class="option"> - <input id="wordHighlight" type="checkbox" class="checkbox pref" - name="wordHighlight" aria-labeledby="wordHighlightLabel"> <label id="wordHighlightLabel" class="i18n" msgid="options_highlight_description"> </label> + <input id="wordHighlight" type="checkbox" class="checkbox" + name="wordHighlight" aria-labeledby="wordHighlightLabel"> <div class="sub-option hidden" id="highlightSubOption"> <span class="i18n" msgid="options_highlight_color_description" id="highlight_color_description"></span>
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js index 37346798..a1250cc 100644 --- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js +++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
@@ -202,7 +202,7 @@ this.trackingMouse_ = true; this.didTrackMouse_ = true; this.mouseStart_ = {x: evt.screenX, y: evt.screenY}; - this.cancelIfSpeaking_(); + this.cancelIfSpeaking_(false /* don't clear the focus ring */); // Fire a hit test event on click to warm up the cache. this.desktop_.hitTest(evt.screenX, evt.screenY, EventType.MOUSE_PRESSED); @@ -345,7 +345,7 @@ if (this.isSelectionKeyDown_ && this.keysPressedTogether_.size == 2 && this.keysPressedTogether_.has(evt.keyCode) && this.keysPressedTogether_.has(SelectToSpeak.SEARCH_KEY_CODE)) { - this.cancelIfSpeaking_(); + this.cancelIfSpeaking_(true /* clear the focus ring */); chrome.automation.getFocus(this.requestSpeakSelectedText_.bind(this)); } this.isSelectionKeyDown_ = false; @@ -367,7 +367,7 @@ this.keysPressedTogether_.has(evt.keyCode) && this.keysPressedTogether_.size == 1) { this.trackingMouse_ = false; - this.cancelIfSpeaking_(); + this.cancelIfSpeaking_(true /* clear the focus ring */); } this.keysCurrentlyDown_.delete(evt.keyCode); @@ -750,7 +750,7 @@ * Prepares for speech. Call once before chrome.tts.speak is called. */ prepareForSpeech_: function() { - this.cancelIfSpeaking_(); + this.cancelIfSpeaking_(true /* clear the focus ring */); if (this.intervalRef_ !== undefined) { clearInterval(this.intervalRef_); } @@ -798,10 +798,17 @@ * record a cancel event if speech was in progress. We must cancel * before the callback (rather than in it) to avoid race conditions * where cancel is called twice. + * @param {boolean} clearFocusRing Whether to clear the focus ring + * as well. */ - cancelIfSpeaking_: function() { + cancelIfSpeaking_: function(clearFocusRing) { chrome.tts.isSpeaking(this.recordCancelIfSpeaking_.bind(this)); - this.stopAll_(); + if (clearFocusRing) { + this.stopAll_(); + } else { + // Just stop speech + chrome.tts.stop(); + } }, /**
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_options.js b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_options.js index d9bd60f..99df1f7 100644 --- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_options.js +++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_options.js
@@ -21,7 +21,7 @@ this.populateVoiceList_('voice'); }.bind(this)); this.syncSelectControlToPref_('voice', 'voice'); - this.syncSelectControlToPref_('rate', 'rate'); + this.syncRangeControlToPref_('rate', 'rate'); this.syncSelectControlToPref_('pitch', 'pitch'); this.syncCheckboxControlToPref_( 'wordHighlight', 'wordHighlight', function(checked) { @@ -146,10 +146,10 @@ * pref, sync them both ways. * @param {string} selectId The id of the select element. * @param {string} pref The name of a chrome.storage pref. - * @param {?function(string): undefined=} onChange Optional change + * @param {?function(string): undefined=} opt_onChange Optional change * listener to call when the setting has been changed. */ - syncSelectControlToPref_: function(selectId, pref, onChange) { + syncSelectControlToPref_: function(selectId, pref, opt_onChange) { var element = document.getElementById(selectId); function updateFromPref() { @@ -162,8 +162,8 @@ break; } } - if (onChange) { - onChange(value); + if (opt_onChange) { + opt_onChange(value); } }); } @@ -181,6 +181,39 @@ }, /** + * Given the id of an HTML range element and the name of a chrome.storage + * pref, sync them both ways. + * @param {string} rangeId The id of the range element. + * @param {string} pref The name of a chrome.storage pref. + * @param {?function(string): undefined=} opt_onChange Optional change + * listener to call when the setting has been changed. + */ + syncRangeControlToPref_: function(rangeId, pref, opt_onChange) { + var element = document.getElementById(rangeId); + + function updateFromPref() { + chrome.storage.sync.get(pref, function(items) { + var value = items[pref]; + element.value = value; + if (opt_onChange) { + opt_onChange(value); + } + }); + } + + element.addEventListener('change', function() { + var newValue = element.value; + var setParams = {}; + setParams[pref] = newValue; + chrome.storage.sync.set(setParams); + }); + + element.updateFunction = updateFromPref; + updateFromPref(); + chrome.storage.onChanged.addListener(updateFromPref); + }, + + /** * Sets up the highlight listeners and preferences. */ setUpHighlightListener_: function() {
diff --git a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd index df00c43..f543b8474 100644 --- a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd +++ b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd
@@ -138,18 +138,6 @@ <message desc="Label for the slowest synthesized speech rate in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_RATE_SLOWEST"> Slowest </message> - <message desc="Label for slow synthesized speech rate in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_RATE_SLOW"> - Slow - </message> - <message desc="Label for a normal synthesized speech rate in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_RATE_NORMAL"> - Normal - </message> - <message desc="Label for fast synthesized speech rate in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_RATE_FAST"> - Fast - </message> - <message desc="Label for faster synthesized speech rate in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_RATE_FASTER"> - Faster - </message> <message desc="Label for the fastest synthesized speech rate in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_RATE_FASTEST"> Fastest </message>
diff --git a/chrome/browser/resources/discards/discards.html b/chrome/browser/resources/discards/discards.html index 4d5828f..96ae713 100644 --- a/chrome/browser/resources/discards/discards.html +++ b/chrome/browser/resources/discards/discards.html
@@ -71,6 +71,7 @@ <div is="action-link" class="discard-urgent-link"> [Urgent Discard] </div> + <div is="action-link" class="freeze-link">[Freeze]</div> </td> </tr> </template>
diff --git a/chrome/browser/resources/discards/discards.js b/chrome/browser/resources/discards/discards.js index b09684e..2c2da84 100644 --- a/chrome/browser/resources/discards/discards.js +++ b/chrome/browser/resources/discards/discards.js
@@ -229,6 +229,20 @@ discardLink.addEventListener('click', discardListener); discardUrgentLink.addEventListener('click', discardListener); + + // Set up the listeners for freeze links. + let lifecycleListener = function(e) { + // Get the info backing this row. + let info = infos[getRowIndex(e.target)]; + // TODO(fmeawad): Disable the action, and let the update function + // re-enable it. Blocked on acquiring freeze status. + // Perform the action. + uiHandler.freezeById(info.id); + }; + + let freezeLink = row.querySelector('.freeze-link'); + freezeLink.addEventListener('click', lifecycleListener); + return row; }
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.js b/chrome/browser/resources/settings/controls/settings_toggle_button.js index b4e7c83..3cd57ae 100644 --- a/chrome/browser/resources/settings/controls/settings_toggle_button.js +++ b/chrome/browser/resources/settings/controls/settings_toggle_button.js
@@ -26,7 +26,7 @@ }, listeners: { - 'tap': 'onHostTap_', + 'click': 'onHostTap_', }, observers: [ @@ -68,7 +68,7 @@ }, /** - * Handles non cr-toggle button taps (cr-toggle handles its own tap events + * Handles non cr-toggle button clicks (cr-toggle handles its own click events * which don't bubble). * @param {!Event} e * @private
diff --git a/chrome/browser/resources/settings/device_page/display.html b/chrome/browser/resources/settings/device_page/display.html index 3255e932..5d7c874 100644 --- a/chrome/browser/resources/settings/device_page/display.html +++ b/chrome/browser/resources/settings/device_page/display.html
@@ -115,7 +115,7 @@ </div> </div> <cr-toggle checked="[[unifiedDesktopMode_]]" - on-tap="onUnifiedDesktopTap_" + on-click="onUnifiedDesktopTap_" aria-labelledby="displayUnifiedDesktopCheckboxLabel"> </cr-toggle> </div>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html index d0bd4cf..38cb20e3 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.html +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -101,7 +101,7 @@ on-settings-boolean-control-change="onMetricsReportingChange_" no-set-pref> <template is="dom-if" if="[[showRestart_]]" restamp> - <paper-button on-tap="onRestartTap_" id="restart" + <paper-button on-click="onRestartTap_" id="restart" slot="more-actions"> $i18n{restart} </paper-button>
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.js b/chrome/browser/resources/settings/settings_menu/settings_menu.js index aec2a0c..81160f27 100644 --- a/chrome/browser/resources/settings/settings_menu/settings_menu.js +++ b/chrome/browser/resources/settings/settings_menu/settings_menu.js
@@ -25,8 +25,8 @@ }, listeners: { - 'topMenu.tap': 'onLinkTap_', - 'subMenu.tap': 'onLinkTap_', + 'topMenu.click': 'onLinkTap_', + 'subMenu.click': 'onLinkTap_', }, /** @param {!settings.Route} newRoute */
diff --git a/chrome/browser/resources/settings/system_page/system_page.html b/chrome/browser/resources/settings/system_page/system_page.html index fb4ed50..7eb8d44 100644 --- a/chrome/browser/resources/settings/system_page/system_page.html +++ b/chrome/browser/resources/settings/system_page/system_page.html
@@ -24,7 +24,7 @@ label="$i18n{hardwareAccelerationLabel}"> <template is="dom-if" if="[[shouldShowRestart_( prefs.hardware_acceleration_mode.enabled.value)]]"> - <paper-button on-tap="onRestartTap_" slot="more-actions"> + <paper-button on-click="onRestartTap_" slot="more-actions"> $i18n{restart} </paper-button> </template>
diff --git a/chrome/browser/service_process/service_process_control.cc b/chrome/browser/service_process/service_process_control.cc index e0d8e7a..00e3d77f 100644 --- a/chrome/browser/service_process/service_process_control.cc +++ b/chrome/browser/service_process/service_process_control.cc
@@ -28,6 +28,7 @@ #include "chrome/browser/upgrade_detector.h" #include "chrome/common/service_process_util.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/named_platform_handle.h" #include "mojo/edk/embedder/named_platform_handle_utils.h" @@ -338,8 +339,8 @@ void ServiceProcessControl::Launcher::Run(const base::Closure& task) { DCHECK_CURRENTLY_ON(BrowserThread::UI); notify_task_ = task; - BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, - base::Bind(&Launcher::DoRun, this)); + content::GetProcessLauncherTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&Launcher::DoRun, this)); } ServiceProcessControl::Launcher::~Launcher() {
diff --git a/chrome/browser/task_manager/sampling/shared_sampler_win_unittest.cc b/chrome/browser/task_manager/sampling/shared_sampler_win_unittest.cc index b0e21c8..5814200 100644 --- a/chrome/browser/task_manager/sampling/shared_sampler_win_unittest.cc +++ b/chrome/browser/task_manager/sampling/shared_sampler_win_unittest.cc
@@ -7,6 +7,7 @@ #include <windows.h> #include <memory> +#include <numeric> #include "base/callback.h" #include "base/macros.h" @@ -133,10 +134,17 @@ int64_t initial_value = physical_bytes(); - // Allocate a large continuos block of memory. + // Allocate a large continuous block of memory. const int allocated_size = 4 * 1024 * 1024; std::vector<uint8_t> memory_block(allocated_size); + // It appears the allocation is not counted when allocated, but when actually + // accessed. vector's constructor does access the memory to initialize it, + // but if the memory then isn't read the compiler might optimize away the + // initialization. So read the memory to prevent that. + uint8_t sum = std::accumulate(memory_block.begin(), memory_block.end(), 0); + EXPECT_EQ(0, sum); + StartRefresh(REFRESH_TYPE_PHYSICAL_MEMORY); WaitUntilRefreshDone();
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc index d2b2e71..d3a51a7 100644 --- a/chrome/browser/themes/theme_properties.cc +++ b/chrome/browser/themes/theme_properties.cc
@@ -174,38 +174,33 @@ return base::nullopt; switch (id) { - // Properties stored in theme pack. case ThemeProperties::COLOR_FRAME: - // Active frame colors. return incognito ? gfx::kGoogleGrey900 : kDefaultTouchUiColorActiveFrame; case ThemeProperties::COLOR_FRAME_INACTIVE: - // Inactive frame colors. return incognito ? kDefaultTouchUiColorInactiveFrameIncognito : kDefaultTouchUiColorInactiveFrame; - case ThemeProperties::COLOR_TOOLBAR: return incognito ? kDefaultTouchUiColorInactiveFrameIncognito : kDefaultTouchUiColorToolbar; + case ThemeProperties::COLOR_TAB_TEXT: case ThemeProperties::COLOR_BOOKMARK_TEXT: + case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_ACTIVE: + case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON: return incognito ? gfx::kGoogleGrey100 : gfx::kGoogleGrey800; + case ThemeProperties::COLOR_BACKGROUND_TAB_TEXT: + case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_INACTIVE: + case ThemeProperties::COLOR_TAB_ALERT_AUDIO: return incognito ? gfx::kGoogleGrey400 : gfx::kGoogleGrey700; - // Properties not stored in theme pack. case ThemeProperties::COLOR_BACKGROUND_TAB: return incognito ? kDefaultTouchUiColorTabBackgroundInactiveIncognito : kDefaultTouchUiColorTabBackgroundInactive; - case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_ACTIVE: - return incognito ? gfx::kGoogleGrey100 : gfx::kGoogleGrey800; - case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_INACTIVE: - return incognito ? gfx::kGoogleGrey400 : gfx::kGoogleGrey700; case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_HOVER: return incognito ? gfx::kGoogleRedDark600 : gfx::kGoogleRed600; case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_PRESSED: return incognito ? gfx::kGoogleRedDark800 : gfx::kGoogleRed800; - case ThemeProperties::COLOR_TAB_ALERT_AUDIO: - return incognito ? gfx::kGoogleGrey400 : gfx::kGoogleGrey700; case ThemeProperties::COLOR_TAB_ALERT_RECORDING: return incognito ? gfx::kGoogleGrey400 : gfx::kGoogleRed600; case ThemeProperties::COLOR_TAB_ALERT_CAPTURING:
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 56b1659..95c7eeb2 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -424,8 +424,17 @@ const int kNtpText = ThemeProperties::COLOR_NTP_TEXT; const int kLabelBackground = ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND; + const bool is_touch = + ui::MaterialDesignController::IsTouchOptimizedUiEnabled(); switch (id) { case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON: + // Touch-optimized UI uses different colors than gfx::kChromeIconGrey. + // They are two specific colors in normal and incognito modes which we + // can't get one from the other by HSLShift(). + // TODO: This will break custom themes. https://crbug.com/820495. + if (is_touch) + break; + return color_utils::HSLShift( gfx::kChromeIconGrey, GetTint(ThemeProperties::TINT_BUTTONS, incognito)); @@ -433,7 +442,7 @@ // The active color is overridden in GtkUi. return SkColorSetA( GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON, incognito), - 0x33); + is_touch ? 0x6E : 0x33); case ThemeProperties::COLOR_LOCATION_BAR_BORDER: return SkColorSetA(SK_ColorBLACK, 0x4D); case ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR: @@ -460,8 +469,8 @@ case ThemeProperties::COLOR_BACKGROUND_TAB: { // Touch optimized color design uses different tab background colors. // TODO(malaykeshav) - This will break custom themes on touch optimized - // UI. Use tint shift instead. - if (ui::MaterialDesignController::IsTouchOptimizedUiEnabled()) + // UI. Use tint shift instead. https://crbug.com/820495. + if (is_touch) break; // The tints here serve a different purpose than TINT_BACKGROUND_TAB.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index b5352b83..4e0f92e 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -3231,6 +3231,7 @@ "views/toolbar/toolbar_action_view_delegate_views.h", "views/toolbar/toolbar_button.cc", "views/toolbar/toolbar_button.h", + "views/toolbar/toolbar_ink_drop_util.h", "views/toolbar/toolbar_view.cc", "views/toolbar/toolbar_view.h", "views/touch_uma/touch_uma.h",
diff --git a/chrome/browser/ui/layout_constants.cc b/chrome/browser/ui/layout_constants.cc index a1f3476..dd3109d 100644 --- a/chrome/browser/ui/layout_constants.cc +++ b/chrome/browser/ui/layout_constants.cc
@@ -45,12 +45,14 @@ return hybrid ? 3 : 1; case LOCATION_BAR_PADDING: return hybrid ? 3 : 1; - case LOCATION_BAR_HEIGHT: - return hybrid ? 32 : 28; + case LOCATION_BAR_HEIGHT: { + constexpr int kHeights[] = {28, 32, 36}; + return kHeights[mode]; + } case LOCATION_BAR_ICON_SIZE: return 16; case LOCATION_BAR_ICON_INTERIOR_PADDING: - return 4; + return touch_optimized_material ? 8 : 4; case TABSTRIP_NEW_TAB_BUTTON_SPACING: { // In non-touch optimized UI, we make the new tab button overlap with the // last tab in the tabstrip (i.e negative spacing). However, in @@ -81,8 +83,10 @@ return touch_optimized_material ? 245 : 193; case TOOLBAR_ELEMENT_PADDING: return hybrid ? 8 : 0; - case TOOLBAR_STANDARD_SPACING: - return hybrid ? 8 : 4; + case TOOLBAR_STANDARD_SPACING: { + constexpr int kSpacings[] = {4, 8, 12}; + return kSpacings[mode]; + } } NOTREACHED(); return 0; @@ -90,10 +94,14 @@ gfx::Insets GetLayoutInsets(LayoutInset inset) { switch (inset) { - case TAB: + case TAB: { constexpr int kTabHorizontalInset[] = {16, 18, 24}; return gfx::Insets( 1, kTabHorizontalInset[ui::MaterialDesignController::GetMode()]); + } + case TOOLBAR_BUTTON: + return gfx::Insets( + ui::MaterialDesignController::IsTouchOptimizedUiEnabled() ? 12 : 6); } NOTREACHED(); return gfx::Insets();
diff --git a/chrome/browser/ui/layout_constants.h b/chrome/browser/ui/layout_constants.h index ef7338e..dda6cb5 100644 --- a/chrome/browser/ui/layout_constants.h +++ b/chrome/browser/ui/layout_constants.h
@@ -112,6 +112,9 @@ enum LayoutInset { // The padding inside the tab bounds that defines the tab contents region. TAB, + + // The padding inside the border of a toolbar button (around the image). + TOOLBAR_BUTTON, }; enum LayoutSize {
diff --git a/chrome/browser/ui/login/login_handler.cc b/chrome/browser/ui/login/login_handler.cc index 73151db..3dac9e9 100644 --- a/chrome/browser/ui/login/login_handler.cc +++ b/chrome/browser/ui/login/login_handler.cc
@@ -100,12 +100,25 @@ password_manager_(NULL), web_contents_getter_(web_contents_getter), login_model_(NULL), - auth_required_callback_(auth_required_callback) { + auth_required_callback_(auth_required_callback), + has_shown_login_handler_(false), + release_soon_has_been_called_(false) { // This constructor is called on the I/O thread, so we cannot load the nib // here. BuildViewImpl() will be invoked on the UI thread later, so wait with // loading the nib until then. DCHECK(auth_info_.get()) << "LoginHandler constructed with NULL auth info"; + // Note from erikchen@: + // The ownership semantics for this class are very confusing. The class is + // self-owned, and is only destroyed when LoginHandler::ReleaseSoon() is + // called. But this relies on the assumption that the LoginHandlerView is + // shown, which isn't always the case. So this class also tracks whether the + // LoginHandler has been shown, and if has never been shown but CancelAuth() + // is called, then LoginHandler::ReleaseSoon() will also be called. + // This relies on the assumption that if the LoginView is not shown, then + // CancelAuth() must be called. + // Ideally, the whole class should be refactored to have saner ownership + // semantics. AddRef(); // matched by LoginHandler::ReleaseSoon(). BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, @@ -133,12 +146,14 @@ password_manager_ = password_manager; password_form_ = observed_form; LoginHandler::LoginModelData model_data(password_manager, observed_form); + has_shown_login_handler_ = true; BuildViewImpl(authority, explanation, &model_data); } void LoginHandler::BuildViewWithoutPasswordManager( const base::string16& authority, const base::string16& explanation) { + has_shown_login_handler_ = true; BuildViewImpl(authority, explanation, nullptr); } @@ -298,6 +313,12 @@ } void LoginHandler::ReleaseSoon() { + if (release_soon_has_been_called_) { + return; + } else { + release_soon_has_been_called_ = true; + } + if (!TestAndSetAuthHandled()) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, @@ -378,6 +399,10 @@ service->Notify(chrome::NOTIFICATION_AUTH_CANCELLED, content::Source<NavigationController>(controller), content::Details<LoginNotificationDetails>(&details)); + + if (!has_shown_login_handler_) { + ReleaseSoon(); + } } // Marks authentication as handled and returns the previous handled state. @@ -517,12 +542,15 @@ LoginHandler* handler) { DCHECK_CURRENTLY_ON(BrowserThread::UI); WebContents* parent_contents = handler->GetWebContentsForLogin(); - if (!parent_contents) + if (!parent_contents) { + handler->CancelAuth(); return; + } prerender::PrerenderContents* prerender_contents = prerender::PrerenderContents::FromWebContents(parent_contents); if (prerender_contents) { prerender_contents->Destroy(prerender::FINAL_STATUS_AUTH_NEEDED); + handler->CancelAuth(); return; }
diff --git a/chrome/browser/ui/login/login_handler.h b/chrome/browser/ui/login/login_handler.h index 36fba38..458a1cb 100644 --- a/chrome/browser/ui/login/login_handler.h +++ b/chrome/browser/ui/login/login_handler.h
@@ -256,6 +256,13 @@ base::WeakPtr<LoginInterstitialDelegate> interstitial_delegate_; + // Default to |false|. Must be set to |true| anytime the login handler is + // shown. + bool has_shown_login_handler_; + + // ReleaseSoon() should be called exactly once to destroy the object. + bool release_soon_has_been_called_; + #if !defined(OS_ANDROID) std::unique_ptr<PopunderPreventer> popunder_preventer_; #endif
diff --git a/chrome/browser/ui/views/ime/ime_window_frame_view.cc b/chrome/browser/ui/views/ime/ime_window_frame_view.cc index 5b8457fe..04ac79f3 100644 --- a/chrome/browser/ui/views/ime/ime_window_frame_view.cc +++ b/chrome/browser/ui/views/ime/ime_window_frame_view.cc
@@ -8,10 +8,12 @@ #include "chrome/grit/browser_resources.h" #include "content/public/browser/web_contents.h" #include "ui/base/hit_test.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font_list.h" #include "ui/gfx/path.h" +#include "ui/strings/grit/ui_strings.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" @@ -57,6 +59,8 @@ rb.GetImageSkiaNamed(IDR_IME_WINDOW_CLOSE_C)); close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, views::ImageButton::ALIGN_MIDDLE); + close_button_->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); AddChildView(close_button_); title_icon_ = new views::ImageView();
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.cc b/chrome/browser/ui/views/toolbar/app_menu_button.cc index 8527fd9..24629c7 100644 --- a/chrome/browser/ui/views/toolbar/app_menu_button.cc +++ b/chrome/browser/ui/views/toolbar/app_menu_button.cc
@@ -24,10 +24,12 @@ #include "chrome/browser/ui/views/extensions/browser_action_drag_data.h" #include "chrome/browser/ui/views/toolbar/app_menu.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" +#include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "chrome/common/chrome_features.h" #include "chrome/grit/chromium_strings.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/material_design/material_design_controller.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/theme_provider.h" #include "ui/gfx/canvas.h" @@ -41,10 +43,13 @@ namespace { -constexpr float kIconSize = 16; - constexpr base::TimeDelta kDelayTime = base::TimeDelta::FromMilliseconds(1500); +// Returns true if the touch-optimized UI is enabled. +bool IsTouchOptimized() { + return ui::MaterialDesignController::IsTouchOptimizedUiEnabled(); +} + } // namespace // static @@ -61,6 +66,7 @@ false) { SetInkDropMode(InkDropMode::ON); SetFocusPainter(nullptr); + SetHorizontalAlignment(gfx::ALIGN_CENTER); if (base::FeatureList::IsEnabled(features::kAnimatedAppMenuIcon)) { toolbar_view_->browser()->tab_strip_model()->AddObserver(this); @@ -68,6 +74,9 @@ should_delay_animation_ = base::GetFieldTrialParamByFeatureAsBool( features::kAnimatedAppMenuIcon, "HasDelay", false); } + + if (IsTouchOptimized()) + set_ink_drop_visible_opacity(kTouchToolbarInkDropVisibleOpacity); } AppMenuButton::~AppMenuButton() {} @@ -151,8 +160,10 @@ } gfx::Size AppMenuButton::CalculatePreferredSize() const { - gfx::Rect rect(gfx::Size(kIconSize, kIconSize)); - rect.Inset(gfx::Insets(-ToolbarButton::kInteriorPadding)); + const int icon_size = IsTouchOptimized() ? 24 : 16; + gfx::Rect rect(gfx::Size(icon_size, icon_size)); + rect.Inset(-GetLayoutInsets(TOOLBAR_BUTTON)); + return rect.size(); } @@ -224,18 +235,21 @@ return; } + const bool is_touch = IsTouchOptimized(); const gfx::VectorIcon* icon_id = nullptr; switch (type_) { case AppMenuIconController::IconType::NONE: - icon_id = &kBrowserToolsIcon; + icon_id = is_touch ? &kBrowserToolsTouchIcon : &kBrowserToolsIcon; DCHECK_EQ(AppMenuIconController::Severity::NONE, severity_); break; case AppMenuIconController::IconType::UPGRADE_NOTIFICATION: - icon_id = &kBrowserToolsUpdateIcon; + icon_id = + is_touch ? &kBrowserToolsUpdateTouchIcon : &kBrowserToolsUpdateIcon; break; case AppMenuIconController::IconType::GLOBAL_ERROR: case AppMenuIconController::IconType::INCOMPATIBILITY_WARNING: - icon_id = &kBrowserToolsErrorIcon; + icon_id = + is_touch ? &kBrowserToolsErrorTouchIcon : &kBrowserToolsErrorIcon; break; } @@ -329,3 +343,25 @@ int AppMenuButton::OnPerformDrop(const ui::DropTargetEvent& event) { return ui::DragDropTypes::DRAG_MOVE; } + +std::unique_ptr<views::InkDrop> AppMenuButton::CreateInkDrop() { + return CreateToolbarInkDrop<MenuButton>(this); +} + +std::unique_ptr<views::InkDropRipple> AppMenuButton::CreateInkDropRipple() + const { + // FIXME: GetInkDropCenterBasedOnLastEvent() will always return the center + // of this view. https://crbug.com/819878. + return CreateToolbarInkDropRipple<MenuButton>( + this, GetInkDropCenterBasedOnLastEvent()); +} + +std::unique_ptr<views::InkDropHighlight> AppMenuButton::CreateInkDropHighlight() + const { + return CreateToolbarInkDropHighlight<MenuButton>( + this, GetMirroredRect(GetContentsBounds()).CenterPoint()); +} + +std::unique_ptr<views::InkDropMask> AppMenuButton::CreateInkDropMask() const { + return CreateToolbarInkDropMask<MenuButton>(this); +}
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.h b/chrome/browser/ui/views/toolbar/app_menu_button.h index 52a5ba01..1ca9749 100644 --- a/chrome/browser/ui/views/toolbar/app_menu_button.h +++ b/chrome/browser/ui/views/toolbar/app_menu_button.h
@@ -31,6 +31,8 @@ // The app menu button lives in the top right of the main browser window. It // shows three dots and animates to a hamburger-ish icon when there's a need to // alert the user. Clicking displays the app menu. +// TODO: Consider making ToolbarButton and AppMenuButton share a common base +// class https://crbug.com/819854. class AppMenuButton : public views::MenuButton, public TabStripModelObserver { public: explicit AppMenuButton(ToolbarView* toolbar_view); @@ -108,6 +110,11 @@ int OnDragUpdated(const ui::DropTargetEvent& event) override; void OnDragExited() override; int OnPerformDrop(const ui::DropTargetEvent& event) override; + std::unique_ptr<views::InkDrop> CreateInkDrop() override; + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() + const override; + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; AppMenuIconController::Severity severity_ = AppMenuIconController::Severity::NONE;
diff --git a/chrome/browser/ui/views/toolbar/reload_button.cc b/chrome/browser/ui/views/toolbar/reload_button.cc index 76c66d1..16e8a98 100644 --- a/chrome/browser/ui/views/toolbar/reload_button.cc +++ b/chrome/browser/ui/views/toolbar/reload_button.cc
@@ -15,6 +15,7 @@ #include "chrome/grit/generated_resources.h" #include "components/vector_icons/vector_icons.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/material_design/material_design_controller.h" #include "ui/base/models/simple_menu_model.h" #include "ui/base/theme_provider.h" #include "ui/base/window_open_disposition.h" @@ -31,6 +32,18 @@ IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM, }; +// Returns true if the touch-optimized UI is enabled. +bool IsTouchOptimized() { + return ui::MaterialDesignController::IsTouchOptimizedUiEnabled(); +} + +const gfx::VectorIcon& GetIconForMode(bool is_reload) { + if (IsTouchOptimized()) + return is_reload ? kReloadTouchIcon : kNavigateStopTouchIcon; + + return is_reload ? vector_icons::kReloadIcon : kNavigateStopIcon; +} + } // namespace // ReloadButton --------------------------------------------------------------- @@ -224,8 +237,7 @@ const ui::ThemeProvider* tp = GetThemeProvider(); // |tp| can be NULL in unit tests. if (tp) { - const gfx::VectorIcon& icon = - (mode == Mode::kReload) ? vector_icons::kReloadIcon : kNavigateStopIcon; + const gfx::VectorIcon& icon = GetIconForMode(mode == Mode::kReload); const SkColor normal_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON); const SkColor disabled_color =
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc index f72b9f0b..986882d 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_button.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -12,18 +12,28 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" +#include "chrome/browser/ui/layout_constants.h" +#include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/base/material_design/material_design_controller.h" #include "ui/base/models/menu_model.h" #include "ui/display/display.h" #include "ui/display/screen.h" -#include "ui/views/animation/ink_drop_highlight.h" -#include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/controls/button/label_button_border.h" #include "ui/views/controls/menu/menu_item_view.h" #include "ui/views/controls/menu/menu_model_adapter.h" #include "ui/views/controls/menu/menu_runner.h" #include "ui/views/widget/widget.h" +namespace { + +// Returns true if the touch-optimized UI is enabled. +bool IsTouchOptimized() { + return ui::MaterialDesignController::IsTouchOptimizedUiEnabled(); +} + +} // namespace + ToolbarButton::ToolbarButton(Profile* profile, views::ButtonListener* listener, std::unique_ptr<ui::MenuModel> model) @@ -36,6 +46,9 @@ SetInkDropMode(InkDropMode::ON); SetFocusPainter(nullptr); SetLeadingMargin(0); + + if (IsTouchOptimized()) + set_ink_drop_visible_opacity(kTouchToolbarInkDropVisibleOpacity); } ToolbarButton::~ToolbarButton() {} @@ -45,8 +58,9 @@ } void ToolbarButton::SetLeadingMargin(int margin) { - SetBorder(views::CreateEmptyBorder(gfx::Insets(kInteriorPadding) + - gfx::Insets(0, margin, 0, 0))); + const gfx::Insets insets = + GetLayoutInsets(TOOLBAR_BUTTON) + gfx::Insets(0, margin, 0, 0); + SetBorder(views::CreateEmptyBorder(insets)); } void ToolbarButton::ClearPendingMenu() { @@ -133,6 +147,26 @@ node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kPress); } +std::unique_ptr<views::InkDrop> ToolbarButton::CreateInkDrop() { + return CreateToolbarInkDrop<ImageButton>(this); +} + +std::unique_ptr<views::InkDropRipple> ToolbarButton::CreateInkDropRipple() + const { + return CreateToolbarInkDropRipple<ImageButton>( + this, GetInkDropCenterBasedOnLastEvent()); +} + +std::unique_ptr<views::InkDropHighlight> ToolbarButton::CreateInkDropHighlight() + const { + return CreateToolbarInkDropHighlight<ImageButton>( + this, GetMirroredRect(GetContentsBounds()).CenterPoint()); +} + +std::unique_ptr<views::InkDropMask> ToolbarButton::CreateInkDropMask() const { + return CreateToolbarInkDropMask<ImageButton>(this); +} + void ToolbarButton::ShowContextMenuForView(View* source, const gfx::Point& point, ui::MenuSourceType source_type) {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.h b/chrome/browser/ui/views/toolbar/toolbar_button.h index 00de1a0..db1f822542 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_button.h +++ b/chrome/browser/ui/views/toolbar/toolbar_button.h
@@ -30,12 +30,11 @@ // This class provides basic drawing and mouse-over behavior for buttons // appearing in the toolbar. +// TODO: Consider making ToolbarButton and AppMenuButton share a common base +// class https://crbug.com/819854. class ToolbarButton : public views::ImageButton, public views::ContextMenuController { public: - // Padding inside the border (around the image). - static constexpr int kInteriorPadding = 6; - // The profile and listener pointers must outlive this class. The model can // be null if no menu is to be shown. ToolbarButton(Profile* profile, @@ -64,6 +63,11 @@ void OnMouseExited(const ui::MouseEvent& event) override; void OnGestureEvent(ui::GestureEvent* event) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + std::unique_ptr<views::InkDrop> CreateInkDrop() override; + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() + const override; + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; // views::ContextMenuController: void ShowContextMenuForView(View* source,
diff --git a/chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h b/chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h new file mode 100644 index 0000000..c44b2d7 --- /dev/null +++ b/chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h
@@ -0,0 +1,110 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_INK_DROP_UTIL_H_ +#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_INK_DROP_UTIL_H_ + +#include <memory> + +#include "ui/base/material_design/material_design_controller.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop_highlight.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/ink_drop_mask.h" +#include "ui/views/animation/ink_drop_ripple.h" + +namespace { + +// Dimentions specific to the ink drop on the Browser's toolbar buttons when +// the Touch-optimized UI is being used. +constexpr int kTouchInkDropCornerRadius = 18; +constexpr gfx::Size kTouchInkDropHighlightSize{2 * kTouchInkDropCornerRadius, + 2 * kTouchInkDropCornerRadius}; +constexpr gfx::Insets kTouchInkDropInsets{6}; + +} // namespace + +constexpr float kTouchToolbarInkDropVisibleOpacity = 0.06f; + +// The below utility functions are templated since we have two different types +// of buttons on the toolbar (ToolbarButton and AppMenuButton) which don't share +// the same base classes (ImageButton and MenuButton respectively), and these +// functions need to call into the base classes' default implementations when +// needed. +// TODO: Consider making ToolbarButton and AppMenuButton share a common base +// class https://crbug.com/819854. + +// Creates the appropriate ink drop for the calling button. When the touch- +// optimized UI is not enabled, it uses the default implementation of the +// calling button's base class (the template argument BaseInkDropHostView). +// Otherwise, it uses an ink drop that shows a highlight on hover that is kept +// and combined with the ripple when the ripple is shown. +template <class BaseInkDropHostView> +std::unique_ptr<views::InkDrop> CreateToolbarInkDrop( + BaseInkDropHostView* host_view) { + if (!ui::MaterialDesignController::IsTouchOptimizedUiEnabled()) + return host_view->BaseInkDropHostView::CreateInkDrop(); + + auto ink_drop = + std::make_unique<views::InkDropImpl>(host_view, host_view->size()); + ink_drop->SetAutoHighlightMode( + views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE); + ink_drop->SetShowHighlightOnHover(true); + return ink_drop; +} + +// Creates the appropriate ink drop ripple for the calling button. When the +// touch-optimized UI is not enabled, it uses the default implementation of the +// calling button's base class (the template argument BaseInkDropHostView). +// Otherwise, it uses a |FloodFillInkDropRipple|. +template <class BaseInkDropHostView> +std::unique_ptr<views::InkDropRipple> CreateToolbarInkDropRipple( + const BaseInkDropHostView* host_view, + const gfx::Point& center_point) { + if (!ui::MaterialDesignController::IsTouchOptimizedUiEnabled()) + return host_view->BaseInkDropHostView::CreateInkDropRipple(); + + return std::make_unique<views::FloodFillInkDropRipple>( + host_view->size(), kTouchInkDropInsets, center_point, + host_view->GetInkDropBaseColor(), host_view->ink_drop_visible_opacity()); +} + +// Creates the appropriate ink drop highlight for the calling button. When the +// touch-optimized UI is not enabled, it uses the default implementation of the +// calling button's base class (the template argument BaseInkDropHostView). +// Otherwise, it uses a kTouchInkDropHighlightSize circular highlight. +template <class BaseInkDropHostView> +std::unique_ptr<views::InkDropHighlight> CreateToolbarInkDropHighlight( + const BaseInkDropHostView* host_view, + const gfx::Point& center_point) { + if (!ui::MaterialDesignController::IsTouchOptimizedUiEnabled()) + return host_view->BaseInkDropHostView::CreateInkDropHighlight(); + + auto highlight = std::make_unique<views::InkDropHighlight>( + kTouchInkDropHighlightSize, kTouchInkDropCornerRadius, + gfx::PointF(center_point), host_view->GetInkDropBaseColor()); + highlight->set_visible_opacity(0.08f); + return highlight; +} + +// Creates the appropriate ink drop mask for the calling button. When the +// touch-optimized UI is not enabled, it uses the default implementation of the +// calling button's base class (the template argument BaseInkDropHostView). +// Otherwise, it uses a circular mask that has the same size as that of the +// highlight, which is needed to make the flood +// fill ripple fill a circle rather than a default square shape. +template <class BaseInkDropHostView> +std::unique_ptr<views::InkDropMask> CreateToolbarInkDropMask( + const BaseInkDropHostView* host_view) { + if (!ui::MaterialDesignController::IsTouchOptimizedUiEnabled()) + return host_view->BaseInkDropHostView::CreateInkDropMask(); + + return std::make_unique<views::RoundRectInkDropMask>( + host_view->size(), kTouchInkDropInsets, kTouchInkDropCornerRadius); +} + +#endif // CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_INK_DROP_UTIL_H_
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 125d618..2ac1e4a 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -89,8 +89,17 @@ namespace { int GetToolbarHorizontalPadding() { + // In the touch-optimized UI, we don't use any horizontal paddings; the back + // button starts from the beginning of the view, and the app menu button ends + // at the end of the view. using Md = ui::MaterialDesignController; - return Md::GetMode() == Md::MATERIAL_HYBRID ? 8 : 4; + constexpr int kPaddings[] = {4, 8, 0}; + return kPaddings[Md::GetMode()]; +} + +// Returns true if the touch-optimized UI is enabled. +bool IsTouchOptimized() { + return ui::MaterialDesignController::IsTouchOptimizedUiEnabled(); } } // namespace @@ -334,13 +343,6 @@ } //////////////////////////////////////////////////////////////////////////////// -// ToolbarView, Menu::Delegate overrides: - -bool ToolbarView::GetAcceleratorInfo(int id, ui::Accelerator* accel) { - return GetWidget()->GetAccelerator(id, accel); -} - -//////////////////////////////////////////////////////////////////////////////// // ToolbarView, views::MenuButtonListener implementation: void ToolbarView::OnMenuButtonClicked(views::MenuButton* source, @@ -538,7 +540,6 @@ const int location_height = location_bar_->GetPreferredSize().height(); const int location_y = (height() - location_height) / 2; - location_bar_->SetBounds(next_element_x, location_y, location_bar_width, location_height); @@ -567,6 +568,7 @@ // we extend the back button to the left edge. if (maximized) app_menu_width += end_padding; + app_menu_button_->SetBounds(next_element_x, toolbar_button_y, app_menu_width, toolbar_button_height); app_menu_button_->SetTrailingMargin(maximized ? end_padding : 0); @@ -698,8 +700,10 @@ // and constant padding values. int content_height = std::max(back_->GetPreferredSize().height(), location_bar_->GetPreferredSize().height()); - const int kExtraVerticalSpace = 9; - size.SetToMax(gfx::Size(0, content_height + kExtraVerticalSpace)); + // In the touch-optimized UI, the toolbar buttons are big and occupy the + // entire view's height, we don't need to add any extra vertical space. + const int extra_vertical_space = IsTouchOptimized() ? 0 : 9; + size.SetToMax(gfx::Size(0, content_height + extra_vertical_space)); } return size; } @@ -712,26 +716,33 @@ const SkColor disabled_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON_INACTIVE); - back_->SetImage( - views::Button::STATE_NORMAL, - gfx::CreateVectorIcon(vector_icons::kBackArrowIcon, normal_color)); - back_->SetImage( - views::Button::STATE_DISABLED, - gfx::CreateVectorIcon(vector_icons::kBackArrowIcon, disabled_color)); - forward_->SetImage( - views::Button::STATE_NORMAL, - gfx::CreateVectorIcon(vector_icons::kForwardArrowIcon, normal_color)); - forward_->SetImage( - views::Button::STATE_DISABLED, - gfx::CreateVectorIcon(vector_icons::kForwardArrowIcon, disabled_color)); + const bool is_touch = IsTouchOptimized(); + const gfx::VectorIcon& back_image = + is_touch ? kBackArrowTouchIcon : vector_icons::kBackArrowIcon; + back_->SetImage(views::Button::STATE_NORMAL, + gfx::CreateVectorIcon(back_image, normal_color)); + back_->SetImage(views::Button::STATE_DISABLED, + gfx::CreateVectorIcon(back_image, disabled_color)); + + const gfx::VectorIcon& forward_image = + is_touch ? kForwardArrowTouchIcon : vector_icons::kForwardArrowIcon; + forward_->SetImage(views::Button::STATE_NORMAL, + gfx::CreateVectorIcon(forward_image, normal_color)); + forward_->SetImage(views::Button::STATE_DISABLED, + gfx::CreateVectorIcon(forward_image, disabled_color)); + + const gfx::VectorIcon& home_image = + is_touch ? kNavigateHomeTouchIcon : kNavigateHomeIcon; home_->SetImage(views::Button::STATE_NORMAL, - gfx::CreateVectorIcon(kNavigateHomeIcon, normal_color)); + gfx::CreateVectorIcon(home_image, normal_color)); app_menu_button_->UpdateIcon(false); - back_->set_ink_drop_base_color(normal_color); - forward_->set_ink_drop_base_color(normal_color); - home_->set_ink_drop_base_color(normal_color); - app_menu_button_->set_ink_drop_base_color(normal_color); + const SkColor ink_drop_color = color_utils::BlendTowardOppositeLuma( + tp->GetColor(ThemeProperties::COLOR_TOOLBAR), SK_AlphaOPAQUE); + back_->set_ink_drop_base_color(ink_drop_color); + forward_->set_ink_drop_base_color(ink_drop_color); + home_->set_ink_drop_base_color(ink_drop_color); + app_menu_button_->set_ink_drop_base_color(ink_drop_color); reload_->LoadImages(); }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h index c0f8b33..e88c1c4 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -81,8 +81,6 @@ // Returns true if the app menu is focused. bool IsAppMenuFocused(); - virtual bool GetAcceleratorInfo(int id, ui::Accelerator* accel); - #if defined(OS_CHROMEOS) void ShowIntentPickerBubble( const std::vector<IntentPickerBubbleView::AppInfo>& app_info,
diff --git a/chrome/browser/ui/webui/discards/discards.mojom b/chrome/browser/ui/webui/discards/discards.mojom index c1be52bd..52932e9bb 100644 --- a/chrome/browser/ui/webui/discards/discards.mojom +++ b/chrome/browser/ui/webui/discards/discards.mojom
@@ -53,6 +53,9 @@ // Invokes a callback when the discard is complete. DiscardById(int32 tab_id, bool urgent) => (); + // Freezes a tab given its |tab_id|. + FreezeById(int32 tab_id); + // Discards the least important tab. If |urgent| is specified the unload // handlers will not be run, and the tab will be unloaded with prejudice. // This can fail to discard a tab if no tabs are currently considered
diff --git a/chrome/browser/ui/webui/discards/discards_ui.cc b/chrome/browser/ui/webui/discards/discards_ui.cc index 9b986af..5b52a26 100644 --- a/chrome/browser/ui/webui/discards/discards_ui.cc +++ b/chrome/browser/ui/webui/discards/discards_ui.cc
@@ -94,6 +94,12 @@ std::move(callback).Run(); } + void FreezeById(int32_t tab_id) override { + resource_coordinator::TabManager* tab_manager = + g_browser_process->GetTabManager(); + tab_manager->FreezeTabById(tab_id); + } + void Discard(bool urgent, DiscardCallback callback) override { resource_coordinator::TabManager* tab_manager = g_browser_process->GetTabManager();
diff --git a/chrome/browser/ui/webui/extensions/install_extension_handler.cc b/chrome/browser/ui/webui/extensions/install_extension_handler.cc index 953306e..cafe0181 100644 --- a/chrome/browser/ui/webui/extensions/install_extension_handler.cc +++ b/chrome/browser/ui/webui/extensions/install_extension_handler.cc
@@ -20,6 +20,7 @@ #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" #include "content/public/common/drop_data.h" +#include "content/public/common/service_manager_connection.h" #include "extensions/browser/extension_system.h" #include "extensions/common/feature_switch.h" #include "net/base/filename_util.h" @@ -100,6 +101,7 @@ if (file_display_name_.MatchesExtension(FILE_PATH_LITERAL(".zip"))) { ZipFileInstaller::Create( + content::ServiceManagerConnection::GetForProcess()->GetConnector(), MakeRegisterInExtensionServiceCallback( ExtensionSystem::Get(profile)->extension_service())) ->LoadFromZipFile(file_to_install_);
diff --git a/chrome/browser/ui/webui/settings/incompatible_applications_handler_win.cc b/chrome/browser/ui/webui/settings/incompatible_applications_handler_win.cc index ad2dc069..810480f0 100644 --- a/chrome/browser/ui/webui/settings/incompatible_applications_handler_win.cc +++ b/chrome/browser/ui/webui/settings/incompatible_applications_handler_win.cc
@@ -141,7 +141,7 @@ const base::Value& callback_id = args->GetList()[0]; int num_applications = args->GetList()[1].GetInt(); - DCHECK_GT(0, num_applications); + DCHECK_GT(num_applications, 0); ResolveJavascriptCallback( callback_id,
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 5910e52..7e813f7 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -250,9 +250,8 @@ arraysize(localized_strings)); #if defined(OS_CHROMEOS) - html_source->AddString( - "a11yLearnMoreUrl", - GetHelpUrlWithBoard(chrome::kChromeAccessibilityHelpURL)); + html_source->AddString("a11yLearnMoreUrl", + chrome::kChromeAccessibilityHelpURL); html_source->AddBoolean( "showExperimentalA11yFeatures",
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn index 771ffffa..bcc195a4 100644 --- a/chrome/browser/vr/BUILD.gn +++ b/chrome/browser/vr/BUILD.gn
@@ -28,6 +28,7 @@ "assets_load_status.h", "assets_loader.cc", "assets_loader.h", + "audio_delegate.h", "browser_ui_interface.h", "content_input_delegate.cc", "content_input_delegate.h", @@ -82,6 +83,8 @@ "elements/render_text_wrapper.h", "elements/repositioner.cc", "elements/repositioner.h", + "elements/resizer.cc", + "elements/resizer.h", "elements/reticle.cc", "elements/reticle.h", "elements/scaled_depth_adjuster.cc", @@ -183,6 +186,8 @@ "service/vr_service_impl.h", "sliding_average.cc", "sliding_average.h", + "sounds_manager_audio_delegate.cc", + "sounds_manager_audio_delegate.h", "speech_recognizer.cc", "speech_recognizer.h", "target_property.cc", @@ -236,6 +241,7 @@ "//content/public/common", "//device/vr", "//device/vr/public/mojom", + "//media", "//net", "//skia", "//ui/base", @@ -258,6 +264,7 @@ "elements/omnibox_text_field_unittest.cc", "elements/rect_unittest.cc", "elements/repositioner_unittest.cc", + "elements/resizer_unittest.cc", "elements/scaled_depth_adjuster_unittest.cc", "elements/shadow_unittest.cc", "elements/spinner_unittest.cc",
diff --git a/chrome/browser/vr/assets_loader.cc b/chrome/browser/vr/assets_loader.cc index 5926379..11c72a99 100644 --- a/chrome/browser/vr/assets_loader.cc +++ b/chrome/browser/vr/assets_loader.cc
@@ -22,6 +22,9 @@ namespace { +constexpr char kMinVersionWithGradients[] = "1.1"; +constexpr char kMinVersionWithSounds[] = "2.0"; + static const base::FilePath::CharType kBackgroundBaseFilename[] = FILE_PATH_LITERAL("background"); static const base::FilePath::CharType kNormalGradientBaseFilename[] = @@ -35,7 +38,12 @@ static const base::FilePath::CharType kJpegExtension[] = FILE_PATH_LITERAL("jpeg"); -constexpr char kMinVersionWithGradients[] = "1.1"; +static const base::FilePath::CharType kButtonHoverSoundFilename[] = + FILE_PATH_LITERAL("button_hover.wav"); +static const base::FilePath::CharType kButtonClickSoundFilename[] = + FILE_PATH_LITERAL("button_click.wav"); +static const base::FilePath::CharType kBackButtonClickSoundFilename[] = + FILE_PATH_LITERAL("back_button_click.wav"); } // namespace @@ -147,6 +155,23 @@ return AssetsLoadStatus::kSuccess; } +AssetsLoadStatus LoadSound(const base::FilePath& component_install_dir, + const base::FilePath::CharType* file_name, + std::unique_ptr<std::string>* out_buffer) { + base::FilePath file_path = component_install_dir.Append(file_name); + if (!base::PathExists(file_path)) { + return AssetsLoadStatus::kNotFound; + } + + auto buffer = std::make_unique<std::string>(); + if (!base::ReadFileToString(file_path, buffer.get())) { + return AssetsLoadStatus::kParseFailure; + } + + *out_buffer = std::move(buffer); + return AssetsLoadStatus::kSuccess; +} + // static void AssetsLoader::LoadAssetsTask( scoped_refptr<base::SingleThreadTaskRunner> task_runner, @@ -174,6 +199,22 @@ } } + if (status == AssetsLoadStatus::kSuccess && + component_version >= base::Version(kMinVersionWithSounds)) { + std::vector<std::pair<const base::FilePath::CharType*, + std::unique_ptr<std::string>*>> + sounds = { + {kButtonHoverSoundFilename, &assets->button_hover_sound}, + {kButtonClickSoundFilename, &assets->button_click_sound}, + {kBackButtonClickSoundFilename, &assets->back_button_click_sound}, + }; + for (auto& sound : sounds) { + status = LoadSound(component_install_dir, sound.first, sound.second); + if (status != AssetsLoadStatus::kSuccess) + break; + } + } + if (status != AssetsLoadStatus::kSuccess) { assets.reset(); }
diff --git a/chrome/browser/vr/assets_loader.h b/chrome/browser/vr/assets_loader.h index eba61390..306ccb3 100644 --- a/chrome/browser/vr/assets_loader.h +++ b/chrome/browser/vr/assets_loader.h
@@ -22,7 +22,7 @@ namespace vr { -constexpr uint32_t kCompatibleMajorVrAssetsComponentVersion = 1; +constexpr uint32_t kCompatibleMajorVrAssetsComponentVersion = 2; class MetricsHelper; struct AssetsLoaderSingletonTrait;
diff --git a/chrome/browser/vr/audio_delegate.h b/chrome/browser/vr/audio_delegate.h new file mode 100644 index 0000000..1f5cfc9 --- /dev/null +++ b/chrome/browser/vr/audio_delegate.h
@@ -0,0 +1,34 @@ +// Copyright 2018 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_VR_AUDIO_DELEGATE_H_ +#define CHROME_BROWSER_VR_AUDIO_DELEGATE_H_ + +#include <memory> +#include <string> + +#include "chrome/browser/vr/model/sound_id.h" + +namespace vr { + +// This delegate interface describes an audio implementation supplied to the UI. +class AudioDelegate { + public: + virtual ~AudioDelegate() {} + + // Clears all registered sounds. This must be done before re-registering a + // particular sound. + virtual void ResetSounds() = 0; + + // The delegate must assume ownership of the audio data. A sound may only be + // registered once. To change the sound later, call ResetSounds and + // re-register all sounds. + virtual bool RegisterSound(SoundId id, std::unique_ptr<std::string> data) = 0; + + virtual void PlaySound(SoundId id) = 0; +}; + +} // namespace vr + +#endif // CHROME_BROWSER_VR_AUDIO_DELEGATE_H_
diff --git a/chrome/browser/vr/elements/disc_button.cc b/chrome/browser/vr/elements/disc_button.cc index 7242996..55c06a5 100644 --- a/chrome/browser/vr/elements/disc_button.cc +++ b/chrome/browser/vr/elements/disc_button.cc
@@ -21,7 +21,8 @@ } // namespace DiscButton::DiscButton(base::RepeatingCallback<void()> click_handler, - const gfx::VectorIcon& icon) + const gfx::VectorIcon& icon, + AudioDelegate* audio_delegate) : Button(click_handler) { auto vector_icon = std::make_unique<VectorIcon>(512); vector_icon->SetType(kTypeButtonForeground); @@ -35,6 +36,8 @@ auto target = RemoveChild(hit_plane()); vector_icon->AddChild(std::move(target)); AddChild(std::move(vector_icon)); + + SetSounds(kSoundButtonHover, kSoundBackButtonClick, audio_delegate); } DiscButton::~DiscButton() = default;
diff --git a/chrome/browser/vr/elements/disc_button.h b/chrome/browser/vr/elements/disc_button.h index 5bbfc62f..68123f8 100644 --- a/chrome/browser/vr/elements/disc_button.h +++ b/chrome/browser/vr/elements/disc_button.h
@@ -22,7 +22,8 @@ class DiscButton : public Button { public: DiscButton(base::RepeatingCallback<void()> click_handler, - const gfx::VectorIcon& icon); + const gfx::VectorIcon& icon, + AudioDelegate* audio_delegate); ~DiscButton() override; VectorIcon* foreground() const { return foreground_; }
diff --git a/chrome/browser/vr/elements/disc_button_unittest.cc b/chrome/browser/vr/elements/disc_button_unittest.cc index 4e7b2c30..b6975c74 100644 --- a/chrome/browser/vr/elements/disc_button_unittest.cc +++ b/chrome/browser/vr/elements/disc_button_unittest.cc
@@ -18,7 +18,8 @@ namespace vr { TEST(DiscButton, HoverTest) { - DiscButton button(base::RepeatingCallback<void()>(), vector_icons::kMicIcon); + DiscButton button(base::RepeatingCallback<void()>(), vector_icons::kMicIcon, + nullptr); button.SetSize(1.0f, 1.0f); button.set_hover_offset(0.5f); @@ -45,7 +46,8 @@ } TEST(DiscButton, SizePropagatesToSubElements) { - DiscButton button(base::RepeatingCallback<void()>(), vector_icons::kMicIcon); + DiscButton button(base::RepeatingCallback<void()>(), vector_icons::kMicIcon, + nullptr); gfx::SizeF size(1000.0f, 1000.0f); gfx::SizeF icon_size = size; icon_size.Scale(0.5f); @@ -69,7 +71,8 @@ } TEST(DiscButton, DrawPhasePropagatesToSubElements) { - DiscButton button(base::RepeatingCallback<void()>(), vector_icons::kMicIcon); + DiscButton button(base::RepeatingCallback<void()>(), vector_icons::kMicIcon, + nullptr); button.SetDrawPhase(kPhaseOverlayForeground); for (auto& child : button.children()) { @@ -78,7 +81,8 @@ } TEST(DiscButton, NamePropagatesToSubElements) { - DiscButton button(base::RepeatingCallback<void()>(), vector_icons::kMicIcon); + DiscButton button(base::RepeatingCallback<void()>(), vector_icons::kMicIcon, + nullptr); button.SetName(kCloseButton); for (auto& child : button.children()) {
diff --git a/chrome/browser/vr/elements/repositioner.h b/chrome/browser/vr/elements/repositioner.h index 832f459..33487b5 100644 --- a/chrome/browser/vr/elements/repositioner.h +++ b/chrome/browser/vr/elements/repositioner.h
@@ -9,7 +9,6 @@ #include "base/macros.h" #include "chrome/browser/vr/elements/ui_element.h" -#include "chrome/browser/vr/model/reticle_model.h" #include "ui/gfx/transform.h" namespace vr {
diff --git a/chrome/browser/vr/elements/resizer.cc b/chrome/browser/vr/elements/resizer.cc new file mode 100644 index 0000000..0e6498f --- /dev/null +++ b/chrome/browser/vr/elements/resizer.cc
@@ -0,0 +1,80 @@ +// Copyright 2018 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/vr/elements/resizer.h" + +#include "base/numerics/math_constants.h" +#include "base/numerics/ranges.h" +#include "chrome/browser/vr/pose_util.h" +#include "chrome/browser/vr/ui_scene_constants.h" +#include "ui/gfx/animation/tween.h" +#include "ui/gfx/geometry/angle_conversions.h" +#include "ui/gfx/geometry/quaternion.h" + +namespace vr { + +namespace { + +// Fraction here is in reference to "time fraction" terminology in web +// animations. +constexpr float kDefaultFraction = 0.5f; + +static_assert(0.5f * (kMinResizerScale + kMaxResizerScale) == 1.0f, + "1.0 must be the midpoint of the min and max scale"); + +} // namespace + +Resizer::Resizer() : t_(kDefaultFraction), initial_t_(kDefaultFraction) { + set_bounds_contain_children(true); +} + +Resizer::~Resizer() = default; + +gfx::Transform Resizer::LocalTransform() const { + return transform_; +} + +gfx::Transform Resizer::GetTargetLocalTransform() const { + return transform_; +} + +void Resizer::SetTouchingTouchpad(bool touching) { + if (enabled_ && touching) { + initial_t_ = t_; + initial_touchpad_position_ = touchpad_position_; + } +} + +void Resizer::SetEnabled(bool enabled) { + enabled_ = enabled; + if (enabled) { + initial_t_ = t_; + initial_touchpad_position_ = touchpad_position_; + } +} + +void Resizer::Reset() { + transform_.MakeIdentity(); + t_ = initial_t_ = kDefaultFraction; +} + +void Resizer::UpdateTransform(const gfx::Transform& head_pose) { + float delta = touchpad_position_.y() - initial_touchpad_position_.y(); + t_ = base::ClampToRange(initial_t_ - delta, 0.0f, 1.0f); + float scale = + gfx::Tween::FloatValueBetween(t_, kMinResizerScale, kMaxResizerScale); + transform_.MakeIdentity(); + transform_.Scale(scale, scale); +} + +bool Resizer::OnBeginFrame(const base::TimeTicks& time, + const gfx::Transform& head_pose) { + if (enabled_) { + UpdateTransform(head_pose); + return true; + } + return false; +} + +} // namespace vr
diff --git a/chrome/browser/vr/elements/resizer.h b/chrome/browser/vr/elements/resizer.h new file mode 100644 index 0000000..f79427cb1 --- /dev/null +++ b/chrome/browser/vr/elements/resizer.h
@@ -0,0 +1,55 @@ +// Copyright 2018 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_VR_ELEMENTS_RESIZER_H_ +#define CHROME_BROWSER_VR_ELEMENTS_RESIZER_H_ + +#include <sstream> + +#include "base/macros.h" +#include "chrome/browser/vr/elements/ui_element.h" +#include "ui/gfx/transform.h" + +namespace vr { + +// When enabled, a resizer scales its descendant elements in response to +// trackpad use. +class Resizer : public UiElement { + public: + Resizer(); + ~Resizer() override; + + void set_touch_position(const gfx::PointF& position) { + touchpad_position_ = position; + } + + void SetTouchingTouchpad(bool touching); + + void SetEnabled(bool enabled); + void Reset(); + + private: + gfx::Transform LocalTransform() const override; + gfx::Transform GetTargetLocalTransform() const override; + void UpdateTransform(const gfx::Transform& head_pose); + bool OnBeginFrame(const base::TimeTicks& time, + const gfx::Transform& head_pose) override; + + bool enabled_ = false; + + // Initialized via constants. + float t_; + float initial_t_; + + gfx::Transform transform_; + + gfx::PointF touchpad_position_; + gfx::PointF initial_touchpad_position_; + + DISALLOW_COPY_AND_ASSIGN(Resizer); +}; + +} // namespace vr + +#endif // CHROME_BROWSER_VR_ELEMENTS_RESIZER_H_
diff --git a/chrome/browser/vr/elements/resizer_unittest.cc b/chrome/browser/vr/elements/resizer_unittest.cc new file mode 100644 index 0000000..659c7ab --- /dev/null +++ b/chrome/browser/vr/elements/resizer_unittest.cc
@@ -0,0 +1,83 @@ +// Copyright 2018 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/vr/elements/resizer.h" + +#include <memory> + +#include "base/strings/stringprintf.h" +#include "cc/test/geometry_test_utils.h" +#include "chrome/browser/vr/test/animation_utils.h" +#include "chrome/browser/vr/test/constants.h" +#include "chrome/browser/vr/ui_scene.h" +#include "chrome/browser/vr/ui_scene_constants.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/transform.h" + +namespace vr { + +namespace { + +class ResizerTest : public testing::Test { + public: + ResizerTest() {} + ~ResizerTest() override {} + + void SetUp() override { + auto resizer = std::make_unique<Resizer>(); + resizer->set_touch_position({0.5f, 0.5f}); + resizer->SetEnabled(true); + resizer_ = resizer.get(); + scene_.AddUiElement(kRoot, std::move(resizer)); + } + + void Move(const gfx::PointF& from, const gfx::PointF& to) { + resizer_->set_touch_position(from); + resizer_->SetTouchingTouchpad(true); + scene_.OnBeginFrame(MsToTicks(1), gfx::Transform()); + resizer_->set_touch_position(to); + scene_.OnBeginFrame(MsToTicks(1), gfx::Transform()); + resizer_->SetTouchingTouchpad(false); + } + + float ComputeScale() { + gfx::Vector3dF v = {1.0f, 0.0f, 0.0f}; + static_cast<UiElement*>(resizer_)->LocalTransform().TransformVector(&v); + return v.x(); + } + + void CheckScale(float scale) { EXPECT_FLOAT_EQ(scale, ComputeScale()); } + + protected: + Resizer* resizer_ = nullptr; + UiScene scene_; +}; + +} // namespace + +TEST_F(ResizerTest, HorizontalMove) { + Move({0.5f, 0.5f}, {1.0f, 0.5f}); + CheckScale(1.0f); +} + +TEST_F(ResizerTest, UpwardMove) { + Move({0.5f, 0.5f}, {0.5f, 1.0f}); + CheckScale(kMinResizerScale); +} + +TEST_F(ResizerTest, DownwardMove) { + Move({0.5f, 0.5f}, {0.5f, 0.0f}); + CheckScale(kMaxResizerScale); +} + +TEST_F(ResizerTest, AccumulatedMove) { + Move({0.5f, 0.5f}, {0.5f, 0.25f}); + float scale = ComputeScale(); + EXPECT_LT(1.0f, scale); + EXPECT_GT(kMaxResizerScale, scale); + Move({0.5f, 0.5f}, {0.5f, 0.25f}); + CheckScale(kMaxResizerScale); +} + +} // namespace vr
diff --git a/chrome/browser/vr/elements/shadow.cc b/chrome/browser/vr/elements/shadow.cc index 20232f4..8474533 100644 --- a/chrome/browser/vr/elements/shadow.cc +++ b/chrome/browser/vr/elements/shadow.cc
@@ -149,6 +149,12 @@ set_corner_radius(children().front()->corner_radii().MaxRadius()); } +gfx::SizeF Shadow::ContributedSize() const { + gfx::RectF bounds(size()); + bounds.Inset(x_padding(), y_padding()); + return bounds.size(); +} + Shadow::Renderer::Renderer() : BaseQuadRenderer(kVertexShader, kFragmentShader) { model_view_proj_matrix_handle_ =
diff --git a/chrome/browser/vr/elements/shadow.h b/chrome/browser/vr/elements/shadow.h index bb3edcc..c773c0f 100644 --- a/chrome/browser/vr/elements/shadow.h +++ b/chrome/browser/vr/elements/shadow.h
@@ -25,6 +25,8 @@ void LayOutChildren() override; void set_intensity(float intensity) { intensity_ = intensity; } + gfx::SizeF ContributedSize() const override; + class Renderer : public BaseQuadRenderer { public: Renderer(); @@ -55,6 +57,7 @@ private: float depth_; float intensity_ = 1.0f; + gfx::SizeF contributed_size_; DISALLOW_COPY_AND_ASSIGN(Shadow); };
diff --git a/chrome/browser/vr/elements/ui_element.cc b/chrome/browser/vr/elements/ui_element.cc index 15fc1a7..b8d51e07 100644 --- a/chrome/browser/vr/elements/ui_element.cc +++ b/chrome/browser/vr/elements/ui_element.cc
@@ -13,6 +13,7 @@ #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "chrome/browser/vr/model/camera_model.h" +#include "chrome/browser/vr/model/sound_id.h" #include "third_party/WebKit/public/platform/WebGestureEvent.h" #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkRect.h" @@ -139,6 +140,9 @@ void UiElement::Initialize(SkiaSurfaceProvider* provider) {} void UiElement::OnHoverEnter(const gfx::PointF& position) { + if (hover_sound_id_ != kSoundNone && audio_delegate_) { + audio_delegate_->PlaySound(hover_sound_id_); + } if (event_handlers_.hover_enter) { event_handlers_.hover_enter.Run(); } else if (parent() && bubble_events()) { @@ -163,6 +167,9 @@ } void UiElement::OnButtonDown(const gfx::PointF& position) { + if (hover_sound_id_ != kSoundNone && audio_delegate_) { + audio_delegate_->PlaySound(click_sound_id_); + } if (event_handlers_.button_down) { event_handlers_.button_down.Run(); } else if (parent() && bubble_events()) { @@ -248,6 +255,10 @@ void UiElement::OnSetSize(const gfx::SizeF& size) {} +gfx::SizeF UiElement::ContributedSize() const { + return size(); +} + void UiElement::SetVisible(bool visible) { SetOpacity(visible ? opacity_when_visible_ : 0.0); } @@ -527,6 +538,14 @@ } #endif +void UiElement::SetSounds(SoundId hover, + SoundId click, + AudioDelegate* delegate) { + hover_sound_id_ = hover; + click_sound_id_ = click; + audio_delegate_ = delegate; +} + void UiElement::OnUpdatedWorldSpaceTransform() {} gfx::SizeF UiElement::stale_size() const { @@ -665,13 +684,13 @@ gfx::RectF bounds; for (auto& child : children_) { - if (!child->IsVisible() || child->size().IsEmpty() || + gfx::SizeF size = child->ContributedSize(); + if (!child->IsVisible() || size.IsEmpty() || !child->contributes_to_parent_bounds()) { continue; } gfx::Point3F child_center(child->local_origin()); - gfx::Vector3dF corner_offset(child->size().width(), child->size().height(), - 0); + gfx::Vector3dF corner_offset(size.width(), size.height(), 0); corner_offset.Scale(-0.5); gfx::Point3F child_upper_left = child_center + corner_offset; gfx::Point3F child_lower_right = child_center - corner_offset;
diff --git a/chrome/browser/vr/elements/ui_element.h b/chrome/browser/vr/elements/ui_element.h index 5bdcfd8d..5cf5467 100644 --- a/chrome/browser/vr/elements/ui_element.h +++ b/chrome/browser/vr/elements/ui_element.h
@@ -15,6 +15,7 @@ #include "cc/animation/animation_target.h" #include "cc/animation/transform_operations.h" #include "chrome/browser/vr/animation.h" +#include "chrome/browser/vr/audio_delegate.h" #include "chrome/browser/vr/databinding/binding_base.h" #include "chrome/browser/vr/elements/corner_radii.h" #include "chrome/browser/vr/elements/draw_phase.h" @@ -57,11 +58,11 @@ struct EventHandlers { EventHandlers(); ~EventHandlers(); - base::Callback<void()> hover_enter; - base::Callback<void()> hover_leave; - base::Callback<void(const gfx::PointF&)> hover_move; - base::Callback<void()> button_down; - base::Callback<void()> button_up; + base::RepeatingCallback<void()> hover_enter; + base::RepeatingCallback<void()> hover_leave; + base::RepeatingCallback<void(const gfx::PointF&)> hover_move; + base::RepeatingCallback<void()> button_down; + base::RepeatingCallback<void()> button_up; base::RepeatingCallback<void(bool)> focus_change; }; @@ -223,6 +224,12 @@ void SetSize(float width, float hight); virtual void OnSetSize(const gfx::SizeF& size); + // Elements may report a different size to parents that resize to contain + // their children. Eg, for shadows. + // TODO(crbug.com/820507): change this to LayoutSize and update all layout + // code to make use of this instead of size(). + virtual gfx::SizeF ContributedSize() const; + gfx::PointF local_origin() const { return local_origin_; } // These are convenience functions for setting the transform operations. They @@ -443,6 +450,10 @@ // change your size based on your old size). gfx::SizeF stale_size() const; + // Set the sounds that play when an applicable handler is executed. Elements + // that override element hover and click methods must manage their own sounds. + void SetSounds(SoundId hover, SoundId click, AudioDelegate* delegate); + protected: Animation& animation() { return animation_; } @@ -568,6 +579,10 @@ UpdatePhase phase_ = kClean; + AudioDelegate* audio_delegate_ = nullptr; + SoundId hover_sound_id_ = kSoundNone; + SoundId click_sound_id_ = kSoundNone; + DISALLOW_COPY_AND_ASSIGN(UiElement); };
diff --git a/chrome/browser/vr/elements/ui_element_name.cc b/chrome/browser/vr/elements/ui_element_name.cc index d01825af..8fb4ec8 100644 --- a/chrome/browser/vr/elements/ui_element_name.cc +++ b/chrome/browser/vr/elements/ui_element_name.cc
@@ -24,6 +24,7 @@ "k2dBrowsingViewportAwareRoot", "kWebVrRoot", "kWebVrViewportAwareRoot", + "kContentResizer", "kContentQuad", "kContentQuadShadow", "kContentQuadRepositionButton", @@ -41,6 +42,7 @@ "kFloor", "kStars", "kUpdateKeyboardPrompt", + "kUrlBarPositioner", "kUrlBarDmmRoot", "kUrlBar", "kUrlBarLayout",
diff --git a/chrome/browser/vr/elements/ui_element_name.h b/chrome/browser/vr/elements/ui_element_name.h index 6d5db0f..882ea8d1 100644 --- a/chrome/browser/vr/elements/ui_element_name.h +++ b/chrome/browser/vr/elements/ui_element_name.h
@@ -23,6 +23,7 @@ k2dBrowsingViewportAwareRoot, kWebVrRoot, kWebVrViewportAwareRoot, + kContentResizer, kContentQuad, kContentQuadShadow, kContentQuadRepositionButton, @@ -40,6 +41,7 @@ kFloor, kStars, kUpdateKeyboardPrompt, + kUrlBarPositioner, kUrlBarDmmRoot, kUrlBar, kUrlBarLayout,
diff --git a/chrome/browser/vr/model/assets.h b/chrome/browser/vr/model/assets.h index ff402e0..3d0f7e9 100644 --- a/chrome/browser/vr/model/assets.h +++ b/chrome/browser/vr/model/assets.h
@@ -29,6 +29,10 @@ std::unique_ptr<SkBitmap> incognito_gradient; std::unique_ptr<SkBitmap> fullscreen_gradient; + std::unique_ptr<std::string> button_hover_sound; + std::unique_ptr<std::string> button_click_sound; + std::unique_ptr<std::string> back_button_click_sound; + base::Version version; };
diff --git a/chrome/browser/vr/model/sound_id.h b/chrome/browser/vr/model/sound_id.h new file mode 100644 index 0000000..6b2ccd3 --- /dev/null +++ b/chrome/browser/vr/model/sound_id.h
@@ -0,0 +1,19 @@ +// Copyright 2018 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_VR_MODEL_SOUND_ID_H_ +#define CHROME_BROWSER_VR_MODEL_SOUND_ID_H_ + +namespace vr { + +enum SoundId { + kSoundNone, + kSoundButtonHover, + kSoundButtonClick, + kSoundBackButtonClick, +}; + +} // namespace vr + +#endif // CHROME_BROWSER_VR_MODEL_SOUND_ID_H_
diff --git a/chrome/browser/vr/sounds_manager_audio_delegate.cc b/chrome/browser/vr/sounds_manager_audio_delegate.cc new file mode 100644 index 0000000..b4dc3d02 --- /dev/null +++ b/chrome/browser/vr/sounds_manager_audio_delegate.cc
@@ -0,0 +1,43 @@ +// Copyright 2018 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/vr/sounds_manager_audio_delegate.h" +#include "media/audio/sounds/sounds_manager.h" + +namespace vr { + +SoundsManagerAudioDelegate::SoundsManagerAudioDelegate() {} + +SoundsManagerAudioDelegate::~SoundsManagerAudioDelegate() { + ResetSounds(); +} + +void SoundsManagerAudioDelegate::ResetSounds() { + // Because SoundsManager cannot replace a registered sound, start fresh + // with a new manager if needed. + if (!sounds_.empty()) { + media::SoundsManager::Shutdown(); + sounds_.clear(); + } +} + +bool SoundsManagerAudioDelegate::RegisterSound( + SoundId id, + std::unique_ptr<std::string> data) { + DCHECK_NE(id, kSoundNone); + DCHECK(sounds_.find(id) == sounds_.end()); + + if (sounds_.empty()) + media::SoundsManager::Create(); + + sounds_[id] = std::move(data); + return media::SoundsManager::Get()->Initialize(id, *sounds_[id]); +} + +void SoundsManagerAudioDelegate::PlaySound(SoundId id) { + if (sounds_.find(id) != sounds_.end()) + media::SoundsManager::Get()->Play(id); +} + +} // namespace vr
diff --git a/chrome/browser/vr/sounds_manager_audio_delegate.h b/chrome/browser/vr/sounds_manager_audio_delegate.h new file mode 100644 index 0000000..48e6a826 --- /dev/null +++ b/chrome/browser/vr/sounds_manager_audio_delegate.h
@@ -0,0 +1,33 @@ +// Copyright 2018 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_VR_SOUNDS_MANAGER_AUDIO_DELEGATE_H_ +#define CHROME_BROWSER_VR_SOUNDS_MANAGER_AUDIO_DELEGATE_H_ + +#include <unordered_map> + +#include "base/macros.h" +#include "chrome/browser/vr/audio_delegate.h" + +namespace vr { + +class SoundsManagerAudioDelegate : public AudioDelegate { + public: + SoundsManagerAudioDelegate(); + ~SoundsManagerAudioDelegate() override; + + // AudioDelegate implementation. + void ResetSounds() override; + bool RegisterSound(SoundId, std::unique_ptr<std::string> data) override; + void PlaySound(SoundId id) override; + + private: + std::unordered_map<SoundId, std::unique_ptr<std::string>> sounds_; + + DISALLOW_COPY_AND_ASSIGN(SoundsManagerAudioDelegate); +}; + +} // namespace vr + +#endif // CHROME_BROWSER_VR_SOUNDS_MANAGER_AUDIO_DELEGATE_H_
diff --git a/chrome/browser/vr/test/ui_pixel_test.cc b/chrome/browser/vr/test/ui_pixel_test.cc index 785d82a1..2b57fb29a 100644 --- a/chrome/browser/vr/test/ui_pixel_test.cc +++ b/chrome/browser/vr/test/ui_pixel_test.cc
@@ -57,7 +57,7 @@ void UiPixelTest::MakeUi(const UiInitialState& ui_initial_state, const ToolbarState& toolbar_state) { - ui_ = std::make_unique<Ui>(browser_.get(), nullptr, nullptr, nullptr, + ui_ = std::make_unique<Ui>(browser_.get(), nullptr, nullptr, nullptr, nullptr, ui_initial_state); ui_->OnGlInitialized(content_texture_, vr::UiElementRenderer::kTextureLocationLocal,
diff --git a/chrome/browser/vr/test/ui_test.cc b/chrome/browser/vr/test/ui_test.cc index 47d5110..44b738eb 100644 --- a/chrome/browser/vr/test/ui_test.cc +++ b/chrome/browser/vr/test/ui_test.cc
@@ -76,7 +76,7 @@ content_input_delegate_ = content_input_delegate.get(); ui_ = std::make_unique<Ui>(std::move(browser_.get()), std::move(content_input_delegate), nullptr, - nullptr, state); + nullptr, nullptr, state); scene_ = ui_->scene(); model_ = ui_->model_for_test(); model_->controller.transform.Translate3d(kStartControllerPosition);
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc index eecd327..1b25a21 100644 --- a/chrome/browser/vr/testapp/vr_test_context.cc +++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -57,6 +57,8 @@ constexpr gfx::Point3F kDefaultLaserOrigin = {0.5f, -0.5f, 0.f}; constexpr gfx::Vector3dF kLaserLocalOffset = {0.f, -0.0075f, -0.05f}; constexpr float kControllerScaleFactor = 1.5f; +constexpr float kTouchpadPositionDelta = 0.05f; +constexpr gfx::PointF kInitialTouchPosition = {0.5f, 0.5f}; void RotateToward(const gfx::Vector3dF& fwd, gfx::Transform* transform) { gfx::Quaternion quat(kForwardVector, fwd); @@ -90,7 +92,8 @@ UiInitialState ui_initial_state; ui_ = std::make_unique<Ui>(this, nullptr, keyboard_delegate_.get(), - text_input_delegate_.get(), ui_initial_state); + text_input_delegate_.get(), nullptr, + ui_initial_state); LoadAssets(); text_input_delegate_->SetRequestFocusCallback( @@ -102,6 +105,8 @@ base::Unretained(keyboard_delegate_.get()))); keyboard_delegate_->SetUiInterface(ui_.get()); + touchpad_touch_position_ = kInitialTouchPosition; + model_ = ui_->model_for_test(); CycleOrigin(); @@ -201,6 +206,9 @@ case ui::DomCode::US_X: ui_->OnAppButtonClicked(); break; + case ui::DomCode::US_T: + touching_touchpad_ = !touching_touchpad_; + break; case ui::DomCode::US_Q: model_->active_modal_prompt_type = kModalPromptTypeGenericUnsupportedFeature; @@ -214,9 +222,15 @@ if (event->IsMouseWheelEvent()) { int direction = base::ClampToRange(event->AsMouseWheelEvent()->y_offset(), -1, 1); - view_scale_factor_ *= (1 + direction * kViewScaleAdjustmentFactor); - view_scale_factor_ = base::ClampToRange( - view_scale_factor_, kMinViewScaleFactor, kMaxViewScaleFactor); + if (event->IsControlDown()) { + touchpad_touch_position_.set_y(base::ClampToRange( + touchpad_touch_position_.y() + kTouchpadPositionDelta * direction, + 0.0f, 1.0f)); + } else { + view_scale_factor_ *= (1 + direction * kViewScaleAdjustmentFactor); + view_scale_factor_ = base::ClampToRange( + view_scale_factor_, kMinViewScaleFactor, kMaxViewScaleFactor); + } return; } @@ -300,6 +314,8 @@ ControllerModel controller_model; controller_model.touchpad_button_state = touchpad_pressed_ ? UiInputManager::DOWN : UiInputManager::UP; + controller_model.touchpad_touch_position = touchpad_touch_position_; + controller_model.touching_touchpad = touching_touchpad_; controller_model.laser_origin = mouse_point_near; controller_model.laser_direction = mouse_point_far - mouse_point_near;
diff --git a/chrome/browser/vr/testapp/vr_test_context.h b/chrome/browser/vr/testapp/vr_test_context.h index 5ee4ae5a..0aa8e97 100644 --- a/chrome/browser/vr/testapp/vr_test_context.h +++ b/chrome/browser/vr/testapp/vr_test_context.h
@@ -80,6 +80,7 @@ int last_drag_y_pixels_ = 0; gfx::Point last_mouse_point_; bool touchpad_pressed_ = false; + gfx::PointF touchpad_touch_position_; float view_scale_factor_ = 1.f; @@ -90,6 +91,7 @@ bool incognito_ = false; bool show_web_vr_splash_screen_ = false; bool voice_search_enabled_ = false; + bool touching_touchpad_ = false; base::TimeTicks page_load_start_; ControllerModel last_controller_model_;
diff --git a/chrome/browser/vr/ui.cc b/chrome/browser/vr/ui.cc index ea703bf..b349a86 100644 --- a/chrome/browser/vr/ui.cc +++ b/chrome/browser/vr/ui.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/vr/model/assets.h" #include "chrome/browser/vr/model/model.h" #include "chrome/browser/vr/model/omnibox_suggestions.h" +#include "chrome/browser/vr/model/sound_id.h" #include "chrome/browser/vr/speech_recognizer.h" #include "chrome/browser/vr/ui_browser_interface.h" #include "chrome/browser/vr/ui_element_renderer.h" @@ -32,25 +33,29 @@ Ui::Ui(UiBrowserInterface* browser, ContentInputForwarder* content_input_forwarder, - vr::KeyboardDelegate* keyboard_delegate, - vr::TextInputDelegate* text_input_delegate, + KeyboardDelegate* keyboard_delegate, + TextInputDelegate* text_input_delegate, + AudioDelegate* audio_delegate, const UiInitialState& ui_initial_state) : Ui(browser, std::make_unique<ContentInputDelegate>(content_input_forwarder), keyboard_delegate, text_input_delegate, + audio_delegate, ui_initial_state) {} Ui::Ui(UiBrowserInterface* browser, std::unique_ptr<ContentInputDelegate> content_input_delegate, - vr::KeyboardDelegate* keyboard_delegate, - vr::TextInputDelegate* text_input_delegate, + KeyboardDelegate* keyboard_delegate, + TextInputDelegate* text_input_delegate, + AudioDelegate* audio_delegate, const UiInitialState& ui_initial_state) : browser_(browser), scene_(std::make_unique<UiScene>()), model_(std::make_unique<Model>()), content_input_delegate_(std::move(content_input_delegate)), input_manager_(std::make_unique<UiInputManager>(scene_.get())), + audio_delegate_(audio_delegate), weak_ptr_factory_(this) { UiInitialState state = ui_initial_state; if (keyboard_delegate != nullptr) @@ -58,7 +63,8 @@ InitializeModel(state); UiSceneCreator(browser, scene_.get(), this, content_input_delegate_.get(), - keyboard_delegate, text_input_delegate, model_.get()) + keyboard_delegate, text_input_delegate, audio_delegate, + model_.get()) .CreateScene(); } @@ -404,6 +410,19 @@ ColorScheme::UpdateForComponent(component_version); model_->background_loaded = true; + + if (audio_delegate_) { + std::vector<std::pair<SoundId, std::unique_ptr<std::string>&>> sounds = { + {kSoundButtonHover, assets->button_hover_sound}, + {kSoundButtonClick, assets->button_click_sound}, + {kSoundBackButtonClick, assets->back_button_click_sound}, + }; + audio_delegate_->ResetSounds(); + for (auto& sound : sounds) { + if (sound.second) + audio_delegate_->RegisterSound(sound.first, std::move(sound.second)); + } + } } void Ui::OnAssetsUnavailable() {
diff --git a/chrome/browser/vr/ui.h b/chrome/browser/vr/ui.h index ee25e69..decd571 100644 --- a/chrome/browser/vr/ui.h +++ b/chrome/browser/vr/ui.h
@@ -17,6 +17,7 @@ #include "chrome/browser/vr/ui_element_renderer.h" namespace vr { +class AudioDelegate; class BrowserUiInterface; class ContentInputDelegate; class ContentInputForwarder; @@ -51,14 +52,16 @@ public: Ui(UiBrowserInterface* browser, ContentInputForwarder* content_input_forwarder, - vr::KeyboardDelegate* keyboard_delegate, - vr::TextInputDelegate* text_input_delegate, + KeyboardDelegate* keyboard_delegate, + TextInputDelegate* text_input_delegate, + AudioDelegate* audio_delegate, const UiInitialState& ui_initial_state); Ui(UiBrowserInterface* browser, std::unique_ptr<ContentInputDelegate> content_input_delegate, - vr::KeyboardDelegate* keyboard_delegate, - vr::TextInputDelegate* text_input_delegate, + KeyboardDelegate* keyboard_delegate, + TextInputDelegate* text_input_delegate, + AudioDelegate* audio_delegate, const UiInitialState& ui_initial_state); ~Ui() override; @@ -71,7 +74,7 @@ UiRenderer* ui_renderer() { return ui_renderer_.get(); } UiInputManager* input_manager() { return input_manager_.get(); } - base::WeakPtr<vr::BrowserUiInterface> GetBrowserUiWeakPtr(); + base::WeakPtr<BrowserUiInterface> GetBrowserUiWeakPtr(); // BrowserUiInterface void SetWebVrMode(bool enabled, bool show_toast) override; @@ -165,14 +168,16 @@ UiBrowserInterface* browser_; // This state may be further abstracted into a SkiaUi object. - std::unique_ptr<vr::UiScene> scene_; - std::unique_ptr<vr::Model> model_; - std::unique_ptr<vr::ContentInputDelegate> content_input_delegate_; - std::unique_ptr<vr::UiElementRenderer> ui_element_renderer_; - std::unique_ptr<vr::UiInputManager> input_manager_; - std::unique_ptr<vr::UiRenderer> ui_renderer_; + std::unique_ptr<UiScene> scene_; + std::unique_ptr<Model> model_; + std::unique_ptr<ContentInputDelegate> content_input_delegate_; + std::unique_ptr<UiElementRenderer> ui_element_renderer_; + std::unique_ptr<UiInputManager> input_manager_; + std::unique_ptr<UiRenderer> ui_renderer_; std::unique_ptr<SkiaSurfaceProvider> provider_; + AudioDelegate* audio_delegate_ = nullptr; + base::WeakPtrFactory<Ui> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(Ui);
diff --git a/chrome/browser/vr/ui_scene_constants.h b/chrome/browser/vr/ui_scene_constants.h index a38e736f..985c683 100644 --- a/chrome/browser/vr/ui_scene_constants.h +++ b/chrome/browser/vr/ui_scene_constants.h
@@ -56,6 +56,10 @@ static constexpr float kUrlBarDistance = 2.4f; static constexpr float kUrlBarWidthDMM = 0.672f; static constexpr float kUrlBarHeightDMM = 0.088f; +// This is the non-DMM relative offset of the URL bar. It is used to position +// the DMM root of the URL bar. +static constexpr float kUrlBarRelativeOffset = -0.45f; +// This is the absolute offset of the URL bar's neutral position in DMM. static constexpr float kUrlBarVerticalOffsetDMM = -0.516f; static constexpr float kUrlBarRotationRad = gfx::DegToRad(-10.0f); static constexpr float kUrlBarFontHeightDMM = 0.027f; @@ -299,6 +303,9 @@ static constexpr float kPromptShadowOffsetDMM = 0.1f; static constexpr float kPromptDistance = 2.4f; +static constexpr float kMinResizerScale = 0.5f; +static constexpr float kMaxResizerScale = 1.5f; + } // namespace vr #endif // CHROME_BROWSER_VR_UI_SCENE_CONSTANTS_H_
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc index 1772b61..7b26b553 100644 --- a/chrome/browser/vr/ui_scene_creator.cc +++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -33,6 +33,7 @@ #include "chrome/browser/vr/elements/prompt.h" #include "chrome/browser/vr/elements/rect.h" #include "chrome/browser/vr/elements/repositioner.h" +#include "chrome/browser/vr/elements/resizer.h" #include "chrome/browser/vr/elements/reticle.h" #include "chrome/browser/vr/elements/scaled_depth_adjuster.h" #include "chrome/browser/vr/elements/spinner.h" @@ -132,6 +133,7 @@ UiBrowserInterface* browser, Ui* ui, Model* model, + AudioDelegate* audio_delegate, SuggestionBinding* element_binding) { auto icon = std::make_unique<VectorIcon>(100); icon->SetDrawPhase(kPhaseForeground); @@ -197,6 +199,7 @@ background->set_bubble_events(true); background->set_bounds_contain_children(true); background->set_hover_offset(0.0); + background->SetSounds(kSoundButtonHover, kSoundButtonClick, audio_delegate); VR_BIND_BUTTON_COLORS(model, background.get(), &ColorScheme::suggestion_button_colors, &Button::SetButtonColors); @@ -473,6 +476,7 @@ auto scaler = Create<ScaledDepthAdjuster>(name, kPhaseNone, kPromptDistance); scaler->SetType(kTypeScaledDepthAdjuster); scaler->AddChild(std::move(backplane)); + scaler->set_contributes_to_parent_bounds(false); return scaler; } @@ -592,6 +596,7 @@ ContentInputDelegate* content_input_delegate, KeyboardDelegate* keyboard_delegate, TextInputDelegate* text_input_delegate, + AudioDelegate* audio_delegate, Model* model) : browser_(browser), scene_(scene), @@ -599,6 +604,7 @@ content_input_delegate_(content_input_delegate), keyboard_delegate_(keyboard_delegate), text_input_delegate_(text_input_delegate), + audio_delegate_(audio_delegate), model_(model) {} UiSceneCreator::~UiSceneCreator() {} @@ -706,6 +712,7 @@ scene_->AddUiElement(k2dBrowsingRoot, std::move(element)); auto repositioner = Create<Repositioner>(k2dBrowsingRepositioner, kPhaseNone); + repositioner->set_bounds_contain_children(true); repositioner->AddBinding( VR_BIND_FUNC(bool, Model, model_, model->reposition_window_enabled(), Repositioner, repositioner.get(), SetEnabled)); @@ -718,10 +725,12 @@ scene_->AddUiElement(k2dBrowsingRoot, std::move(repositioner)); element = Create<UiElement>(k2dBrowsingVisibiltyControlForVoice, kPhaseNone); + element->set_bounds_contain_children(true); scene_->AddUiElement(k2dBrowsingRepositioner, std::move(element)); element = Create<UiElement>(k2dBrowsingVisibilityControlForPrompt, kPhaseNone); + element->set_bounds_contain_children(true); VR_BIND_VISIBILITY( element, model->active_modal_prompt_type == kModalPromptTypeNone || @@ -732,6 +741,7 @@ element = Create<UiElement>(k2dBrowsingVisibiltyControlForSiteInfoPrompt, kPhaseNone); + element->set_bounds_contain_children(true); VR_BIND_VISIBILITY(element, model->active_modal_prompt_type != kModalPromptTypeExitVRForSiteInfo); @@ -740,6 +750,7 @@ element = Create<UiElement>(k2dBrowsingOpacityControlForAudioPermissionPrompt, kPhaseNone); + element->set_bounds_contain_children(true); element->AddBinding( VR_BIND(bool, Model, model_, model->active_modal_prompt_type != @@ -751,6 +762,7 @@ element = Create<UiElement>(k2dBrowsingOpacityControlForNativeDialogPrompt, kPhaseNone); + element->set_bounds_contain_children(true); element->SetTransitionedProperties({OPACITY}); element->AddBinding(VR_BIND( bool, Model, model_, !model->native_ui.hosted_ui_enabled, UiElement, @@ -760,6 +772,7 @@ element = Create<UiElement>(k2dBrowsingOpacityControlForUpdateKeyboardPrompt, kPhaseNone); + element->set_bounds_contain_children(true); element->SetTransitionedProperties({OPACITY}); element->AddBinding( VR_BIND(bool, Model, model_, @@ -770,6 +783,7 @@ std::move(element)); element = Create<UiElement>(k2dBrowsingForeground, kPhaseNone); + element->set_bounds_contain_children(true); element->SetTransitionedProperties({OPACITY}); element->SetTransitionDuration(base::TimeDelta::FromMilliseconds( kSpeechRecognitionOpacityAnimationDurationMs)); @@ -780,8 +794,8 @@ element = Create<UiElement>(k2dBrowsingContentGroup, kPhaseNone); element->SetTranslate(0, kContentVerticalOffset, -kContentDistance); - element->SetSize(kContentWidth, kContentHeight); element->SetTransitionedProperties({TRANSFORM}); + element->set_bounds_contain_children(true); element->AddBinding( VR_BIND(bool, Model, model_, model->fullscreen_enabled(), UiElement, element.get(), @@ -866,6 +880,7 @@ indicator_layout->SetTranslate(0, kIndicatorVerticalOffset, kIndicatorDistanceOffset); indicator_layout->set_margin(kIndicatorGap); + indicator_layout->set_contributes_to_parent_bounds(false); VR_BIND_VISIBILITY(indicator_layout, !model->fullscreen_enabled()); for (const auto& indicator : indicators) { @@ -912,8 +927,23 @@ // reticle roughly planar with the content if near content. auto hit_plane = Create<InvisibleHitTarget>(kBackplane, kPhaseForeground); hit_plane->SetSize(kBackplaneSize, kSceneHeight); + hit_plane->set_contributes_to_parent_bounds(false); scene_->AddUiElement(k2dBrowsingContentGroup, std::move(hit_plane)); + auto resizer = Create<Resizer>(kContentResizer, kPhaseNone); + resizer->AddBinding(VR_BIND_FUNC(bool, Model, model_, + model->reposition_window_enabled(), Resizer, + resizer.get(), SetEnabled)); + resizer->AddBinding(VR_BIND_FUNC(gfx::PointF, Model, model_, + model->controller.touchpad_touch_position, + Resizer, resizer.get(), set_touch_position)); + resizer->AddBinding(VR_BIND_FUNC(bool, Model, model_, + model->controller.touching_touchpad, Resizer, + resizer.get(), SetTouchingTouchpad)); + resizer->AddBinding(VR_BIND(bool, Model, model_, model->controller.recentered, + Resizer, resizer.get(), + if (value) { view->Reset(); })); + auto shadow = Create<Shadow>(kContentQuadShadow, kPhaseForeground); shadow->set_intensity(kContentShadowIntesity); shadow->SetTranslate(0, 0, -kContentShadowOffset); @@ -983,7 +1013,8 @@ const EditedText& value) { e->UpdateInput(value); }, base::Unretained(main_content.get())))); shadow->AddChild(std::move(main_content)); - scene_->AddUiElement(k2dBrowsingContentGroup, std::move(shadow)); + resizer->AddChild(std::move(shadow)); + scene_->AddUiElement(k2dBrowsingContentGroup, std::move(resizer)); // Limit reticle distance to a sphere based on maximum content distance. scene_->set_background_distance(kFullscreenDistance * @@ -1130,7 +1161,7 @@ Create<DiscButton>(kWebVrTimeoutMessageButton, kPhaseForeground, base::BindRepeating(&UiBrowserInterface::ExitPresent, base::Unretained(browser_)), - vector_icons::kClose16Icon); + vector_icons::kClose16Icon, audio_delegate_); button->SetVisible(false); button->SetTranslate(0, -kTimeoutMessageTextWidthDMM, 0); button->SetRotate(1, 0, 0, kTimeoutButtonRotationRad); @@ -1271,12 +1302,14 @@ element = std::make_unique<ViewportAwareRoot>(); element->SetName(k2dBrowsingViewportAwareRoot); + element->set_contributes_to_parent_bounds(false); scene_->AddUiElement(k2dBrowsingRepositioner, std::move(element)); } void UiSceneCreator::CreateVoiceSearchUiGroup() { auto speech_recognition_root = std::make_unique<UiElement>(); speech_recognition_root->SetName(kSpeechRecognitionRoot); + speech_recognition_root->set_contributes_to_parent_bounds(false); speech_recognition_root->SetTranslate(0.f, 0.f, -kContentDistance); speech_recognition_root->SetTransitionedProperties({OPACITY}); speech_recognition_root->SetTransitionDuration( @@ -1403,7 +1436,7 @@ kSpeechRecognitionListeningCloseButton, kPhaseForeground, base::BindRepeating(&UiBrowserInterface::SetVoiceSearchActive, base::Unretained(browser_), false), - vector_icons::kClose16Icon); + vector_icons::kClose16Icon, audio_delegate_); close_button->SetSize(kVoiceSearchCloseButtonDiameter, kVoiceSearchCloseButtonDiameter); close_button->set_hover_offset(kButtonZOffsetHoverDMM * kContentDistance); @@ -1448,7 +1481,7 @@ base::BindRepeating( [](Model* model) { model->push_mode(kModeRepositionWindow); }, base::Unretained(model_)), - kRepositionIcon); + kRepositionIcon, audio_delegate_); reposition_button->SetSize(kRepositionButtonDiameter, kRepositionButtonDiameter); reposition_button->set_y_anchoring(BOTTOM); @@ -1463,6 +1496,7 @@ reposition_button->background()->SetTransitionedProperties( {BACKGROUND_COLOR, TRANSFORM}); reposition_button->SetOpacity(kRepositionButtonMinOpacity); + reposition_button->SetSounds(kSoundNone, kSoundNone, nullptr); reposition_button->AddBinding(std::make_unique<Binding<float>>( VR_BIND_LAMBDA( [](Model* model, Button* button) { @@ -1494,6 +1528,7 @@ label_background->set_corner_radius(kRepositionLabelBackgroundCornerRadius); label_background->set_padding(kRepositionLabelBackgroundPadding, kRepositionLabelBackgroundPadding); + label_background->set_contributes_to_parent_bounds(false); VR_BIND_COLOR(model_, label_background.get(), &ColorScheme::reposition_label_background, &Rect::SetColor); VR_BIND_VISIBILITY(label_background, model->reposition_window_enabled()); @@ -1515,14 +1550,16 @@ auto content_toggle = Create<UiElement>(kContentRepositionVisibilityToggle, kPhaseNone); content_toggle->SetTransitionedProperties({OPACITY}); + content_toggle->set_bounds_contain_children(true); content_toggle->AddBinding(VR_BIND_FUNC( float, Model, model_, model->reposition_window_enabled() ? kRepositionContentOpacity : 1.0f, UiElement, content_toggle.get(), SetOpacity)); - scene_->AddParentUiElement(kContentQuadShadow, std::move(content_toggle)); + scene_->AddParentUiElement(kContentResizer, std::move(content_toggle)); auto hit_plane = Create<InvisibleHitTarget>(kContentRepositionHitPlane, kPhaseForeground); + hit_plane->set_contributes_to_parent_bounds(false); hit_plane->SetSize(kSceneSize, kSceneSize); hit_plane->SetTranslate(0.0f, 0.0f, -kContentDistance); EventHandlers event_handlers; @@ -1625,6 +1662,7 @@ void UiSceneCreator::CreateKeyboard() { auto visibility_control_root = Create<UiElement>(kKeyboardVisibilityControlForVoice, kPhaseNone); + visibility_control_root->set_contributes_to_parent_bounds(false); BIND_VISIBILITY_CONTROL_FOR_VOICE(visibility_control_root.get(), model_, editing_enabled()); @@ -1657,12 +1695,18 @@ } void UiSceneCreator::CreateUrlBar() { + auto positioner = Create<UiElement>(kUrlBarPositioner, kPhaseNone); + positioner->set_y_anchoring(BOTTOM); + positioner->SetTranslate(0, kUrlBarRelativeOffset, 0); + positioner->set_contributes_to_parent_bounds(false); + scene_->AddUiElement(k2dBrowsingForeground, std::move(positioner)); + auto scaler = std::make_unique<ScaledDepthAdjuster>(kUrlBarDistance); scaler->SetName(kUrlBarDmmRoot); - scene_->AddUiElement(k2dBrowsingForeground, std::move(scaler)); + scaler->set_contributes_to_parent_bounds(false); + scene_->AddUiElement(kUrlBarPositioner, std::move(scaler)); auto url_bar = Create<UiElement>(kUrlBar, kPhaseNone); - url_bar->SetTranslate(0, kUrlBarVerticalOffsetDMM, 0); url_bar->SetRotate(1, 0, 0, kUrlBarRotationRad); url_bar->set_bounds_contain_children(true); VR_BIND_VISIBILITY(url_bar, !model->fullscreen_enabled()); @@ -1681,6 +1725,7 @@ back_button->SetCornerRadii( {kUrlBarHeightDMM / 2, 0, kUrlBarHeightDMM / 2, 0}); back_button->set_hover_offset(0.0f); + back_button->SetSounds(kSoundButtonHover, kSoundButtonClick, audio_delegate_); back_button->AddBinding(VR_BIND_FUNC(bool, Model, model_, model->can_navigate_back, Button, back_button.get(), set_enabled)); @@ -1826,6 +1871,7 @@ void UiSceneCreator::CreateOmnibox() { auto visibility_control_root = Create<UiElement>(kOmniboxVisibiltyControlForVoice, kPhaseNone); + visibility_control_root->set_contributes_to_parent_bounds(false); auto scaler = std::make_unique<ScaledDepthAdjuster>(kUrlBarDistance); scaler->SetName(kOmniboxDmmRoot); @@ -2043,6 +2089,8 @@ mic_icon_box->SetSize(kOmniboxTextFieldIconButtonSizeDMM, kOmniboxTextFieldIconButtonSizeDMM); mic_icon_box->set_corner_radius(kOmniboxTextFieldIconButtonRadiusDMM); + mic_icon_box->SetSounds(kSoundButtonHover, kSoundButtonClick, + audio_delegate_); VR_BIND_VISIBILITY(mic_icon_box, model->speech.has_or_can_request_audio_permission && !model->incognito && @@ -2072,10 +2120,10 @@ text_field_layout->AddChild(std::move(right_spacer)); // Set up the vector binding to manage suggestions dynamically. - SuggestionSetBinding::ModelAddedCallback added_callback = - base::BindRepeating(&OnSuggestionModelAdded, base::Unretained(scene_), - base::Unretained(browser_), base::Unretained(ui_), - base::Unretained(model_)); + SuggestionSetBinding::ModelAddedCallback added_callback = base::BindRepeating( + &OnSuggestionModelAdded, base::Unretained(scene_), + base::Unretained(browser_), base::Unretained(ui_), + base::Unretained(model_), base::Unretained(audio_delegate_)); SuggestionSetBinding::ModelRemovedCallback removed_callback = base::BindRepeating(&OnSuggestionModelRemoved, base::Unretained(scene_)); @@ -2097,7 +2145,7 @@ base::BindRepeating( [](Model* model) { model->pop_mode(kModeEditingOmnibox); }, base::Unretained(model_)), - vector_icons::kBackArrowIcon); + vector_icons::kBackArrowIcon, audio_delegate_); close_button->SetSize(kOmniboxCloseButtonDiameterDMM, kOmniboxCloseButtonDiameterDMM); close_button->SetTranslate(0, kOmniboxCloseButtonVerticalOffsetDMM, 0); @@ -2148,7 +2196,8 @@ base::Unretained(model_), base::Unretained(browser_)); std::unique_ptr<DiscButton> element = Create<DiscButton>(kCloseButton, kPhaseForeground, click_handler, - vector_icons::kClose16Icon); + vector_icons::kClose16Icon, audio_delegate_); + element->set_contributes_to_parent_bounds(false); element->SetSize(kCloseButtonDiameter, kCloseButtonDiameter); element->set_hover_offset(kButtonZOffsetHoverDMM * kCloseButtonDistance); element->SetTranslate(0, kCloseButtonVerticalOffset, -kCloseButtonDistance); @@ -2190,6 +2239,7 @@ auto backplane = std::make_unique<InvisibleHitTarget>(); backplane->SetDrawPhase(kPhaseForeground); backplane->SetName(kExitPromptBackplane); + backplane->set_contributes_to_parent_bounds(false); backplane->SetSize(kBackplaneSize, kBackplaneSize); backplane->SetTranslate(0.0, kContentVerticalOffset + kExitPromptVerticalOffset, @@ -2368,6 +2418,7 @@ void UiSceneCreator::CreateFullscreenToast() { auto parent = CreateTransientParent(kExclusiveScreenToastTransientParent, kToastTimeoutSeconds, false); + parent->set_contributes_to_parent_bounds(false); VR_BIND_VISIBILITY(parent, model->fullscreen_enabled()); scene_->AddUiElement(k2dBrowsingForeground, std::move(parent));
diff --git a/chrome/browser/vr/ui_scene_creator.h b/chrome/browser/vr/ui_scene_creator.h index f8b77bac..8395a0b7 100644 --- a/chrome/browser/vr/ui_scene_creator.h +++ b/chrome/browser/vr/ui_scene_creator.h
@@ -29,6 +29,7 @@ ContentInputDelegate* content_input_delegate, KeyboardDelegate* keyboard_delegate, TextInputDelegate* text_input_delegate, + AudioDelegate* audio_delegate, Model* model); ~UiSceneCreator(); @@ -66,6 +67,7 @@ ContentInputDelegate* content_input_delegate_; KeyboardDelegate* keyboard_delegate_; TextInputDelegate* text_input_delegate_; + AudioDelegate* audio_delegate_; Model* model_; DISALLOW_COPY_AND_ASSIGN(UiSceneCreator);
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc index a3b91be2..ed2dd20d 100644 --- a/chrome/browser/vr/ui_unittest.cc +++ b/chrome/browser/vr/ui_unittest.cc
@@ -1225,17 +1225,24 @@ TEST_F(UiTest, ResetRepositioner) { CreateScene(kNotInCct, kNotInWebVr); + Repositioner* repositioner = static_cast<Repositioner*>( scene_->GetUiElementByName(k2dBrowsingRepositioner)); + + OnBeginFrame(); + gfx::Transform original = repositioner->world_space_transform(); + repositioner->set_laser_direction(kForwardVector); repositioner->SetEnabled(true); repositioner->set_laser_direction({0, 1, 0}); OnBeginFrame(); - EXPECT_FALSE(repositioner->world_space_transform().IsIdentity()); + + EXPECT_NE(original, repositioner->world_space_transform()); repositioner->SetEnabled(false); model_->controller.recentered = true; + OnBeginFrame(); - EXPECT_TRUE(repositioner->world_space_transform().IsIdentity()); + EXPECT_EQ(original, repositioner->world_space_transform()); } // No element in the controller root's subtree should be hit testable. @@ -1246,4 +1253,20 @@ EXPECT_FALSE(child.IsHitTestable()); } +TEST_F(UiTest, BrowsingRootBounds) { + CreateScene(kNotInCct, kNotInWebVr); + auto* elem = scene_->GetUiElementByName(k2dBrowsingContentGroup); + auto* root = scene_->GetUiElementByName(k2dBrowsingRepositioner); + for (; elem; elem = elem->parent()) { + int num_bounds_contributors = 0; + for (auto& child : elem->children()) { + if (child->contributes_to_parent_bounds()) + num_bounds_contributors++; + } + EXPECT_EQ(1, num_bounds_contributors); + if (elem == root) + break; + } +} + } // namespace vr
diff --git a/chrome/common/media_router/media_status.cc b/chrome/common/media_router/media_status.cc index 3f21339..2b20f826 100644 --- a/chrome/common/media_router/media_status.cc +++ b/chrome/common/media_router/media_status.cc
@@ -20,7 +20,7 @@ MediaStatus& MediaStatus::operator=(const MediaStatus& other) = default; bool MediaStatus::operator==(const MediaStatus& other) const { - return title == other.title && description == other.description && + return title == other.title && can_play_pause == other.can_play_pause && can_mute == other.can_mute && can_set_volume == other.can_set_volume && can_seek == other.can_seek && play_state == other.play_state && is_muted == other.is_muted &&
diff --git a/chrome/common/media_router/media_status.h b/chrome/common/media_router/media_status.h index c2d464ac..9fbd24f 100644 --- a/chrome/common/media_router/media_status.h +++ b/chrome/common/media_router/media_status.h
@@ -43,12 +43,6 @@ // a YouTube Cast session, this could be the title of the video. std::string title; - // Text describing the media, or a secondary title. For example, in a - // MediaStatus representing a YouTube Cast session, this could be "YouTube". - // - // DEPRECATED. TODO(crbug.com/786208): Remove this when no longer used. - std::string description; - // If this is true, the media can be played and paused. bool can_play_pause = false;
diff --git a/chrome/common/media_router/mojo/media_status.mojom b/chrome/common/media_router/mojo/media_status.mojom index 09b6684..6811111 100644 --- a/chrome/common/media_router/mojo/media_status.mojom +++ b/chrome/common/media_router/mojo/media_status.mojom
@@ -22,15 +22,6 @@ // For a Presentation API route, it is the presentation page title. string title; - // Text describing the media, or a secondary title. For example, in a - // MediaStatus representing a YouTube Cast session, this could be "YouTube". - // - // DEPRECATED. This is used to override MediaRoute.description (defined in - // media_router.mojom) in the Media Router UX. We will be using - // MediaRoute.description exclusively once all MRPs have been updated. - // TODO(crbug.com/786208): Remove this when that is done. - string description; - // If this is true, the media can be played and paused through its // MediaController. bool can_play_pause;
diff --git a/chrome/common/media_router/mojo/media_status_struct_traits.cc b/chrome/common/media_router/mojo/media_status_struct_traits.cc index fd37cf88..9e4179ae 100644 --- a/chrome/common/media_router/mojo/media_status_struct_traits.cc +++ b/chrome/common/media_router/mojo/media_status_struct_traits.cc
@@ -17,11 +17,6 @@ if (!data.ReadTitle(&out->title) || !base::IsStringUTF8(out->title)) return false; - if (!data.ReadDescription(&out->description) || - !base::IsStringUTF8(out->description)) { - return false; - } - out->can_play_pause = data.can_play_pause(); out->can_mute = data.can_mute(); out->can_set_volume = data.can_set_volume();
diff --git a/chrome/common/media_router/mojo/media_status_struct_traits.h b/chrome/common/media_router/mojo/media_status_struct_traits.h index 4fe09f7..312fae4 100644 --- a/chrome/common/media_router/mojo/media_status_struct_traits.h +++ b/chrome/common/media_router/mojo/media_status_struct_traits.h
@@ -58,11 +58,6 @@ return status.title; } - static const std::string& description( - const media_router::MediaStatus& status) { - return status.description; - } - static bool can_play_pause(const media_router::MediaStatus& status) { return status.can_play_pause; }
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 301d6a6..3874615c 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -1372,12 +1372,6 @@ return module_name == "Native Client"; } -bool ChromeContentRendererClient::IsOriginIsolatedPepperPlugin( - const base::FilePath& plugin_path) { - return plugin_path == - base::FilePath::FromUTF8Unsafe(ChromeContentClient::kPDFPluginPath); -} - #if BUILDFLAG(ENABLE_PLUGINS) && BUILDFLAG(ENABLE_EXTENSIONS) bool ChromeContentRendererClient::IsExtensionOrSharedModuleWhitelisted( const GURL& url,
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h index 1b30fe68..d3bdf1b 100644 --- a/chrome/renderer/chrome_content_renderer_client.h +++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -169,7 +169,6 @@ const content::RenderFrame* render_frame, blink::mojom::PageVisibilityState* override_state) override; bool IsExternalPepperPlugin(const std::string& module_name) override; - bool IsOriginIsolatedPepperPlugin(const base::FilePath& plugin_path) override; std::unique_ptr<blink::WebSocketHandshakeThrottle> CreateWebSocketHandshakeThrottle() override; std::unique_ptr<blink::WebSpeechSynthesizer> OverrideSpeechSynthesizer(
diff --git a/chrome/renderer/resources/extensions/media_router_bindings.js b/chrome/renderer/resources/extensions/media_router_bindings.js index b270be5..1260b400 100644 --- a/chrome/renderer/resources/extensions/media_router_bindings.js +++ b/chrome/renderer/resources/extensions/media_router_bindings.js
@@ -160,7 +160,6 @@ */ function MediaStatusAdapter(fields) { this.title = null; - this.description = null; this.can_play_pause = false; this.can_mute = false; this.can_set_volume = false; @@ -180,7 +179,6 @@ MediaStatusAdapter.prototype.toNewVersion = function() { return new mediaRouter.mojom.MediaStatus({ 'title': this.title, - 'description': this.description, 'canPlayPause': this.can_play_pause, 'canMute': this.can_mute, 'canSetVolume': this.can_set_volume,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 143d085..4cad318 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2124,10 +2124,7 @@ group("performance_test_suite") { testonly = true deps = [ - # Comment this in when testing on a trybot so it does - # not have to rebuild chrome each time. - "//chrome/test:telemetry_perf_tests_experimental", - #"//chrome/test:telemetry_perf_tests", + "//chrome/test:telemetry_perf_tests", ] data = [
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations index e74c5a3..758e3be 100644 --- a/chrome/test/chromedriver/test/test_expectations +++ b/chrome/test/chromedriver/test/test_expectations
@@ -285,6 +285,7 @@ 'ElementAttributeTest.testShouldReturnValueOfOnClickAttribute', 'ElementAttributeTest.testCanRetrieveTheCurrentValueOfATextFormField_textInput', 'ElementAttributeTest.testGetAttributeDoesNotReturnAnObjectForSvgProperties', + 'ElementAttributeTest.testShouldReturnNullForNonPresentBooleanAttributes', 'JavascriptEnabledDriverTest.testShouldBeAbleToFindElementAfterJavascriptCausesANewPageToLoad', 'JavascriptEnabledDriverTest.testShouldBeAbleToSwitchToFocusedElement', 'JavascriptEnabledDriverTest.testShouldBeAbleToDetermineTheLocationOfAnElement', @@ -292,11 +293,14 @@ 'JavascriptEnabledDriverTest.testShouldWaitForLoadsToCompleteAfterJavascriptCausesANewPageToLoad', 'FormHandlingTest.testShouldSubmitAFormUsingTheEnterKey', 'FormHandlingTest.testShouldSubmitAFormUsingTheNewlineLiteral', + 'FormHandlingTest.testCanClickOnAnExternalSubmitButton', + 'FormHandlingTest.testShouldBeAbleToUploadTheSameFileTwice', 'BasicMouseInterfaceTest.testDoubleClickThenGet', 'MiscTest.testShouldReturnTheSourceOfAPage', 'MiscTest.testClickingShouldNotTrampleWOrHInGlobalScope', 'MiscTest.testShouldReportTheCurrentUrlCorrectly', 'MiscTest.testStimulatesStrangeOnloadInteractionInFirefox', + 'TypingTest.testShouldBeAbleToUseArrowKeys', ] ) _OS_NEGATIVE_FILTER['android:chrome_beta'] = (
diff --git a/chrome/test/data/android/popup_on_click.html b/chrome/test/data/android/popup_on_click.html new file mode 100644 index 0000000..61c3ba6 --- /dev/null +++ b/chrome/test/data/android/popup_on_click.html
@@ -0,0 +1,2 @@ +<p>This page opens new windows/tabs based on what is clicked.</p> +<a id="link" href="popup_on_click.html" target="_blank">Click for new tab</a>
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn index 2481d41..4dba9dbd 100644 --- a/chrome/utility/BUILD.gn +++ b/chrome/utility/BUILD.gn
@@ -116,7 +116,6 @@ "//chrome/common/extensions/api", "//chrome/services/media_gallery_util:lib", "//chrome/services/removable_storage_writer:lib", - "//extensions/utility", ] public_deps += [ "//chrome/common/extensions/api" ]
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS index 37bfc09..4f9afedc1 100644 --- a/chrome/utility/DEPS +++ b/chrome/utility/DEPS
@@ -29,7 +29,6 @@ "+content/public/utility", "+extensions/common", "+extensions/buildflags", - "+extensions/utility", "+media", "+services/network/public", "+services/network/url_request_context_builder_mojo.h",
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc index aabd610..c3a84e6 100644 --- a/chrome/utility/chrome_content_utility_client.cc +++ b/chrome/utility/chrome_content_utility_client.cc
@@ -51,7 +51,6 @@ #include "chrome/services/removable_storage_writer/public/mojom/constants.mojom.h" #include "chrome/services/removable_storage_writer/removable_storage_writer_service.h" #include "chrome/utility/extensions/extensions_handler.h" -#include "extensions/utility/utility_handler.h" #if defined(OS_WIN) #include "chrome/services/wifi_util_win/public/mojom/constants.mojom.h" #include "chrome/services/wifi_util_win/wifi_util_win_service.h" @@ -118,10 +117,6 @@ ChromeContentUtilityClient::~ChromeContentUtilityClient() = default; void ChromeContentUtilityClient::UtilityThreadStarted() { -#if BUILDFLAG(ENABLE_EXTENSIONS) - extensions::utility_handler::UtilityThreadStarted(); -#endif - #if defined(OS_WIN) base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); utility_process_running_elevated_ = command_line->HasSwitch( @@ -137,10 +132,6 @@ return; auto registry = std::make_unique<service_manager::BinderRegistry>(); -#if BUILDFLAG(ENABLE_EXTENSIONS) - extensions::utility_handler::ExposeInterfacesToBrowser( - registry.get(), utility_process_running_elevated_); -#endif // If our process runs with elevated privileges, only add elevated Mojo // interfaces to the interface registry. if (!utility_process_running_elevated_) {
diff --git a/chrome/utility/extensions/DEPS b/chrome/utility/extensions/DEPS index a62f289..4959379 100644 --- a/chrome/utility/extensions/DEPS +++ b/chrome/utility/extensions/DEPS
@@ -1,5 +1,5 @@ include_rules = [ "+extensions/buildflags", "+extensions/common", - "+extensions/utility", + "+extensions/features", ]
diff --git a/chromecast/browser/cast_display_configurator.cc b/chromecast/browser/cast_display_configurator.cc index df84a61..b5dfca3 100644 --- a/chromecast/browser/cast_display_configurator.cc +++ b/chromecast/browser/cast_display_configurator.cc
@@ -4,6 +4,8 @@ #include "chromecast/browser/cast_display_configurator.h" +#include <math.h> + #include "base/bind.h" #include "base/command_line.h" #include "base/feature_list.h" @@ -66,8 +68,28 @@ } float GetDeviceScaleFactor(gfx::Size display_resolution) { - // Device scale factor computed relative to 720p display - return display_resolution.height() / 720.0f; + // TODO(spang): Look into tightening up the allowed scale factors here + // rather than allowing all scales >= 1.f + int smaller_dimension = + std::min(display_resolution.width(), display_resolution.height()); + float ratio = smaller_dimension / 720.f; + if (ratio < 1.f) + return 1.f; + return ratio; +} + +gfx::Rect GetScreenBounds(const gfx::Size& size_in_pixels, + display::Display::Rotation rotation) { + switch (rotation) { + case display::Display::ROTATE_90: + case display::Display::ROTATE_270: + return gfx::Rect( + gfx::Size(size_in_pixels.height(), size_in_pixels.width())); + case display::Display::ROTATE_0: + case display::Display::ROTATE_180: + default: + return gfx::Rect(size_in_pixels); + } } } // namespace @@ -181,7 +203,7 @@ float device_scale_factor, display::Display::Rotation rotation) { cast_screen_->OnDisplayChanged(display_id, device_scale_factor, rotation, - bounds); + GetScreenBounds(bounds.size(), rotation)); touch_device_manager_->OnDisplayConfigured(display_id, rotation, bounds); }
diff --git a/chromecast/browser/cast_touch_device_manager.cc b/chromecast/browser/cast_touch_device_manager.cc index bc61fa3..a167c3a 100644 --- a/chromecast/browser/cast_touch_device_manager.cc +++ b/chromecast/browser/cast_touch_device_manager.cc
@@ -27,20 +27,9 @@ touch_device_transform.transform.Translate(native_bounds_in_pixel.x(), native_bounds_in_pixel.y()); - float touchscreen_width = touchscreen_size.width(); - float touchscreen_height = touchscreen_size.height(); - - // If the display orientation is rotated between portrait and landscape, - // the width and height of the touchscreen must be swapped as well. - if (rotation == display::Display::Rotation::ROTATE_90 || - rotation == display::Display::Rotation::ROTATE_270) { - touchscreen_width = touchscreen_size.height(); - touchscreen_height = touchscreen_size.width(); - } - touch_device_transform.transform.Scale( - native_bounds_in_pixel.width() / touchscreen_width, - native_bounds_in_pixel.height() / touchscreen_height); + native_bounds_in_pixel.width() / touchscreen_size.width(), + native_bounds_in_pixel.height() / touchscreen_size.height()); return touch_device_transform; }
diff --git a/chromecast/graphics/cast_window_manager_aura.cc b/chromecast/graphics/cast_window_manager_aura.cc index faf7a86..d24469d 100644 --- a/chromecast/graphics/cast_window_manager_aura.cc +++ b/chromecast/graphics/cast_window_manager_aura.cc
@@ -46,6 +46,23 @@ return rotation; } +gfx::Rect GetPrimaryDisplayHostBounds() { + display::Display display(display::Screen::GetScreen()->GetPrimaryDisplay()); + gfx::Point display_origin_in_pixel = display.bounds().origin(); + gfx::Size display_size_in_pixel = display.GetSizeInPixel(); + switch (display.rotation()) { + case display::Display::ROTATE_90: + case display::Display::ROTATE_270: + return gfx::Rect(display_origin_in_pixel, + gfx::Size(display_size_in_pixel.height(), + display_size_in_pixel.width())); + case display::Display::ROTATE_0: + case display::Display::ROTATE_180: + // default: + return gfx::Rect(display_origin_in_pixel, display_size_in_pixel); + } +} + } // namespace // An ui::EventTarget that ignores events. @@ -224,20 +241,11 @@ ui::InitializeInputMethodForTesting(); - gfx::Size display_size = - display::Screen::GetScreen()->GetPrimaryDisplay().GetSizeInPixel(); - display::Display::Rotation rotation = - display::Screen::GetScreen()->GetPrimaryDisplay().rotation(); - if (rotation == display::Display::ROTATE_90 || - rotation == display::Display::ROTATE_270) { - display_size = gfx::Size(display_size.height(), display_size.width()); - } + gfx::Rect host_bounds = GetPrimaryDisplayHostBounds(); - LOG(INFO) << "Starting window manager, screen size: " << display_size.width() - << "x" << display_size.height(); + LOG(INFO) << "Starting window manager, bounds: " << host_bounds.ToString(); CHECK(aura::Env::GetInstance()); - window_tree_host_.reset( - new CastWindowTreeHost(enable_input_, gfx::Rect(display_size))); + window_tree_host_.reset(new CastWindowTreeHost(enable_input_, host_bounds)); window_tree_host_->InitHost(); window_tree_host_->window()->SetLayoutManager(new CastLayoutManager()); window_tree_host_->SetRootTransform(GetPrimaryDisplayRotationTransform());
diff --git a/chromeos/dbus/fake_smb_provider_client.cc b/chromeos/dbus/fake_smb_provider_client.cc index a1657ab..b7e8f09 100644 --- a/chromeos/dbus/fake_smb_provider_client.cc +++ b/chromeos/dbus/fake_smb_provider_client.cc
@@ -131,4 +131,12 @@ FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK)); } +void FakeSmbProviderClient::GetDeleteList(int32_t mount_id, + const base::FilePath& entry_path, + GetDeleteListCallback callback) { + smbprovider::DeleteListProto delete_list; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), smbprovider::ERROR_OK, delete_list)); +} } // namespace chromeos
diff --git a/chromeos/dbus/fake_smb_provider_client.h b/chromeos/dbus/fake_smb_provider_client.h index 6692b36..b64e5a7 100644 --- a/chromeos/dbus/fake_smb_provider_client.h +++ b/chromeos/dbus/fake_smb_provider_client.h
@@ -76,6 +76,10 @@ const base::FilePath& target_path, StatusCallback callback) override; + void GetDeleteList(int32_t mount_id, + const base::FilePath& entry_path, + GetDeleteListCallback callback) override; + private: DISALLOW_COPY_AND_ASSIGN(FakeSmbProviderClient); };
diff --git a/chromeos/dbus/smb_provider_client.cc b/chromeos/dbus/smb_provider_client.cc index c53f945..e7eb9f2 100644 --- a/chromeos/dbus/smb_provider_client.cc +++ b/chromeos/dbus/smb_provider_client.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/files/file_util.h" #include "base/memory/weak_ptr.h" #include "dbus/bus.h" #include "dbus/message.h" @@ -45,6 +46,16 @@ return smbprovider::ERROR_OK; } +bool ParseDeleteList(const base::ScopedFD& fd, + int32_t bytes_written, + smbprovider::DeleteListProto* delete_list) { + DCHECK(delete_list); + std::vector<uint8_t> buffer(bytes_written); + return base::ReadFromFD(fd.get(), reinterpret_cast<char*>(buffer.data()), + buffer.size()) && + delete_list->ParseFromArray(buffer.data(), buffer.size()); +} + class SmbProviderClientImpl : public SmbProviderClient { public: SmbProviderClientImpl() : weak_ptr_factory_(this) {} @@ -208,6 +219,16 @@ CallDefaultMethod(smbprovider::kCopyEntryMethod, options, &callback); } + void GetDeleteList(int32_t mount_id, + const base::FilePath& entry_path, + GetDeleteListCallback callback) override { + smbprovider::GetDeleteListOptionsProto options; + options.set_mount_id(mount_id); + options.set_entry_path(entry_path.value()); + CallMethod(smbprovider::kGetDeleteListMethod, options, + &SmbProviderClientImpl::HandleGetDeleteListCallback, &callback); + } + protected: // DBusClient override. void Init(dbus::Bus* bus) override { @@ -335,6 +356,39 @@ std::move(callback).Run(smbprovider::ERROR_OK, fd); } + // Handles D-Bus callback for GetDeleteList. + void HandleGetDeleteListCallback(GetDeleteListCallback callback, + dbus::Response* response) { + base::ScopedFD fd; + smbprovider::DeleteListProto delete_list; + if (!response) { + LOG(ERROR) << "GetDeleteList: failed to call smbprovider"; + std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, + delete_list); + return; + } + + dbus::MessageReader reader(response); + smbprovider::ErrorType error = GetErrorFromReader(&reader); + if (error != smbprovider::ERROR_OK) { + std::move(callback).Run(error, delete_list); + return; + } + + int32_t bytes_written; + bool success = reader.PopFileDescriptor(&fd) && + reader.PopInt32(&bytes_written) && + ParseDeleteList(fd, bytes_written, &delete_list); + if (!success) { + LOG(ERROR) << "GetDeleteList: parse failure."; + std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, + delete_list); + return; + } + + std::move(callback).Run(smbprovider::ERROR_OK, delete_list); + } + // Default callback handler for D-Bus calls. void HandleDefaultCallback(const std::string& method_name, StatusCallback callback,
diff --git a/chromeos/dbus/smb_provider_client.h b/chromeos/dbus/smb_provider_client.h index a67d564..88a7846 100644 --- a/chromeos/dbus/smb_provider_client.h +++ b/chromeos/dbus/smb_provider_client.h
@@ -34,6 +34,9 @@ using StatusCallback = base::OnceCallback<void(smbprovider::ErrorType error)>; using ReadFileCallback = base::OnceCallback<void(smbprovider::ErrorType error, const base::ScopedFD& fd)>; + using GetDeleteListCallback = + base::OnceCallback<void(smbprovider::ErrorType error, + const smbprovider::DeleteListProto& delete_list)>; ~SmbProviderClient() override; @@ -144,6 +147,13 @@ const base::FilePath& target_path, StatusCallback callback) = 0; + // Calls GetDeleteList. Using the corresponding |mount_id|, this generates an + // ordered list of individual entries that must be deleted in order to delete + // |entry_path|. This operations does not modify the filesystem. + virtual void GetDeleteList(int32_t mount_id, + const base::FilePath& entry_path, + GetDeleteListCallback callback) = 0; + protected: // Create() should be used instead. SmbProviderClient();
diff --git a/components/component_updater/component_installer_unittest.cc b/components/component_updater/component_installer_unittest.cc index 4c52a80e..959ec1f 100644 --- a/components/component_updater/component_installer_unittest.cc +++ b/components/component_updater/component_installer_unittest.cc
@@ -114,10 +114,10 @@ ~MockUpdateClient() override {} }; -class FakeInstallerPolicy : public ComponentInstallerPolicy { +class MockInstallerPolicy : public ComponentInstallerPolicy { public: - FakeInstallerPolicy() {} - ~FakeInstallerPolicy() override {} + MockInstallerPolicy() {} + ~MockInstallerPolicy() override {} bool VerifyInstallation(const base::DictionaryValue& manifest, const base::FilePath& dir) const override { @@ -274,7 +274,7 @@ EXPECT_CALL(update_client(), Stop()).Times(1); auto installer = base::MakeRefCounted<ComponentInstaller>( - std::make_unique<FakeInstallerPolicy>()); + std::make_unique<MockInstallerPolicy>()); installer->Register(component_updater(), base::OnceClosure()); RunThreads(); @@ -301,7 +301,7 @@ // Tests that the unpack path is removed when the install succeeded. TEST_F(ComponentInstallerTest, UnpackPathInstallSuccess) { auto installer = base::MakeRefCounted<ComponentInstaller>( - std::make_unique<FakeInstallerPolicy>()); + std::make_unique<MockInstallerPolicy>()); Unpack(test_file("jebgalgnebhfojomionfpkfelancnnkf.crx")); @@ -329,7 +329,7 @@ // Tests that the unpack path is removed when the install failed. TEST_F(ComponentInstallerTest, UnpackPathInstallError) { auto installer = base::MakeRefCounted<ComponentInstaller>( - std::make_unique<FakeInstallerPolicy>()); + std::make_unique<MockInstallerPolicy>()); Unpack(test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
diff --git a/components/component_updater/timer_unittest.cc b/components/component_updater/timer_unittest.cc index b0523e9..9d5c63ea 100644 --- a/components/component_updater/timer_unittest.cc +++ b/components/component_updater/timer_unittest.cc
@@ -5,6 +5,7 @@ #include <string> #include <utility> +#include "base/bind.h" #include "base/run_loop.h" #include "base/test/scoped_task_environment.h" #include "base/time/time.h" @@ -27,9 +28,9 @@ }; TEST_F(ComponentUpdaterTimerTest, Start) { - class TimerClientFake { + class TimerClientMock { public: - TimerClientFake(int max_count, base::OnceClosure quit_closure) + TimerClientMock(int max_count, base::OnceClosure quit_closure) : max_count_(max_count), quit_closure_(std::move(quit_closure)), count_(0) {} @@ -50,13 +51,14 @@ }; base::RunLoop run_loop; - TimerClientFake timer_client_fake(3, run_loop.QuitClosure()); + TimerClientMock timer_client_fake(3, run_loop.QuitClosure()); EXPECT_EQ(0, timer_client_fake.count()); Timer timer; const base::TimeDelta delay(base::TimeDelta::FromMilliseconds(1)); - timer.Start(delay, delay, base::Bind(&TimerClientFake::OnTimerEvent, - base::Unretained(&timer_client_fake))); + timer.Start(delay, delay, + base::BindRepeating(&TimerClientMock::OnTimerEvent, + base::Unretained(&timer_client_fake))); run_loop.Run(); timer.Stop();
diff --git a/components/download/content/factory/download_service_factory.cc b/components/download/content/factory/download_service_factory.cc index 26686cb..a2f01ef2 100644 --- a/components/download/content/factory/download_service_factory.cc +++ b/components/download/content/factory/download_service_factory.cc
@@ -23,7 +23,7 @@ #include "components/download/internal/background_service/proto/entry.pb.h" #include "components/download/internal/background_service/scheduler/scheduler_impl.h" #include "components/leveldb_proto/proto_database_impl.h" -#include "net/url_request/url_request_context_getter.h" +#include "content/public/browser/storage_partition.h" #if defined(OS_ANDROID) #include "components/download/internal/background_service/android/battery_status_listener_android.h" @@ -111,12 +111,16 @@ content::BrowserContext* browser_context, std::unique_ptr<DownloadClientMap> clients, const base::FilePath& storage_dir, - scoped_refptr<net::URLRequestContextGetter> request_context_getter, BlobTaskProxy::BlobContextGetter blob_context_getter, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) { auto config = Configuration::CreateFromFinch(); + auto* url_loader_factory = + content::BrowserContext::GetDefaultStoragePartition(browser_context) + ->GetURLLoaderFactoryForBrowserProcess() + .get(); + DCHECK(url_loader_factory); auto download_factory = std::make_unique<InMemoryDownloadFactory>( - request_context_getter, blob_context_getter, io_task_runner); + url_loader_factory, blob_context_getter, io_task_runner); auto driver = std::make_unique<InMemoryDownloadDriver>(std::move(download_factory)); auto store = std::make_unique<NoopStore>();
diff --git a/components/download/content/factory/download_service_factory.h b/components/download/content/factory/download_service_factory.h index 9dbb7da..a1142c1 100644 --- a/components/download/content/factory/download_service_factory.h +++ b/components/download/content/factory/download_service_factory.h
@@ -17,10 +17,6 @@ class BrowserContext; } // namespace content -namespace net { -class URLRequestContextGetter; -} // namespace net - namespace download { class DownloadService; @@ -49,7 +45,6 @@ content::BrowserContext* browser_context, std::unique_ptr<DownloadClientMap> clients, const base::FilePath& storage_dir, - scoped_refptr<net::URLRequestContextGetter> request_context_getter, BlobTaskProxy::BlobContextGetter blob_context_getter, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
diff --git a/components/download/internal/background_service/BUILD.gn b/components/download/internal/background_service/BUILD.gn index 3f0a725..f695f87f 100644 --- a/components/download/internal/background_service/BUILD.gn +++ b/components/download/internal/background_service/BUILD.gn
@@ -87,6 +87,7 @@ "//components/download/public/background_service:public", "//components/leveldb_proto", "//net", + "//services/network/public/cpp", "//storage/browser", ] @@ -152,7 +153,7 @@ "//components/download/internal/background_service/test:test_support", "//components/download/public/background_service/test:test_support", "//components/leveldb_proto:test_support", - "//net:test_support", + "//services/network:test_support", "//storage/browser", "//testing/gmock", "//testing/gtest",
diff --git a/components/download/internal/background_service/DEPS b/components/download/internal/background_service/DEPS index ed5bc8c..9500a4e 100644 --- a/components/download/internal/background_service/DEPS +++ b/components/download/internal/background_service/DEPS
@@ -5,6 +5,8 @@ "+base", "+jni", "+net", + "+services/network/public", + "+services/network/test", "+storage/browser", "+storage/common", ]
diff --git a/components/download/internal/background_service/in_memory_download.cc b/components/download/internal/background_service/in_memory_download.cc index 091f0e1..18b72b7 100644 --- a/components/download/internal/background_service/in_memory_download.cc +++ b/components/download/internal/background_service/in_memory_download.cc
@@ -8,102 +8,14 @@ #include <string> #include "base/bind.h" -#include "base/strings/string_util.h" #include "components/download/internal/background_service/blob_task_proxy.h" -#include "net/base/completion_callback.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/http/http_status_code.h" +#include "net/base/load_flags.h" #include "net/traffic_annotation/network_traffic_annotation.h" -#include "net/url_request/url_fetcher.h" #include "storage/browser/blob/blob_data_handle.h" #include "storage/browser/blob/blob_storage_context.h" namespace download { -namespace { - -// Converts a string to HTTP method used by URLFetcher. -net::URLFetcher::RequestType ToRequestType(const std::string& method) { - // Only supports GET and POST. - if (base::EqualsCaseInsensitiveASCII(method, "GET")) - return net::URLFetcher::RequestType::GET; - if (base::EqualsCaseInsensitiveASCII(method, "POST")) - return net::URLFetcher::RequestType::POST; - - NOTREACHED(); - return net::URLFetcher::RequestType::GET; -} - -} // namespace - -InMemoryDownloadImpl::ResponseWriter::ResponseWriter( - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) - : paused_on_io_(false), io_task_runner_(io_task_runner) {} - -InMemoryDownloadImpl::ResponseWriter::~ResponseWriter() = default; - -void InMemoryDownloadImpl::ResponseWriter::Pause() { - io_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&ResponseWriter::PauseOnIO, base::Unretained(this))); -} - -void InMemoryDownloadImpl::ResponseWriter::PauseOnIO() { - io_task_runner_->BelongsToCurrentThread(); - paused_on_io_ = true; -} - -void InMemoryDownloadImpl::ResponseWriter::Resume() { - io_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&ResponseWriter::ResumeOnIO, base::Unretained(this))); -} - -void InMemoryDownloadImpl::ResponseWriter::ResumeOnIO() { - io_task_runner_->BelongsToCurrentThread(); - paused_on_io_ = false; - - // Continue read from network layer. Since we didn't write on pause, report - // 0 byte to network layer. - if (!write_callback_.is_null()) { - base::ResetAndReturn(&write_callback_).Run(0u); - } -} - -std::unique_ptr<std::string> InMemoryDownloadImpl::ResponseWriter::TakeData() { - return std::move(data_); -} - -int InMemoryDownloadImpl::ResponseWriter::Initialize( - const net::CompletionCallback& callback) { - data_ = std::make_unique<std::string>(); - return net::OK; -} - -int InMemoryDownloadImpl::ResponseWriter::Write( - net::IOBuffer* buffer, - int num_bytes, - const net::CompletionCallback& callback) { - io_task_runner_->BelongsToCurrentThread(); - - if (paused_on_io_) { - write_callback_ = callback; - return net::ERR_IO_PENDING; - } - - DCHECK(data_); - data_->append(buffer->data(), num_bytes); - return num_bytes; -} - -int InMemoryDownloadImpl::ResponseWriter::Finish( - int net_error, - const net::CompletionCallback& callback) { - io_task_runner_->BelongsToCurrentThread(); - return net::OK; -} - InMemoryDownload::InMemoryDownload(const std::string& guid) : guid_(guid), state_(State::INITIAL), bytes_downloaded_(0u) {} @@ -114,13 +26,13 @@ const RequestParams& request_params, const net::NetworkTrafficAnnotationTag& traffic_annotation, Delegate* delegate, - scoped_refptr<net::URLRequestContextGetter> request_context_getter, + network::mojom::URLLoaderFactory* url_loader_factory, BlobTaskProxy::BlobContextGetter blob_context_getter, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) : InMemoryDownload(guid), request_params_(request_params), traffic_annotation_(traffic_annotation), - request_context_getter_(request_context_getter), + url_loader_factory_(url_loader_factory), blob_task_proxy_( BlobTaskProxy::Create(blob_context_getter, io_task_runner)), io_task_runner_(io_task_runner), @@ -142,30 +54,11 @@ } void InMemoryDownloadImpl::Pause() { - if (paused_) - return; - paused_ = true; - - switch (state_) { - case State::INITIAL: - // Do nothing. - return; - case State::IN_PROGRESS: - // Do nothing if network operation is done. - DCHECK(response_writer_); - response_writer_->Pause(); - return; - case State::FAILED: - return; - case State::COMPLETE: - // Do nothing. - return; - } + if (state_ == State::IN_PROGRESS) + paused_ = true; } void InMemoryDownloadImpl::Resume() { - if (!paused_) - return; paused_ = false; switch (state_) { @@ -173,12 +66,13 @@ NOTREACHED(); return; case State::IN_PROGRESS: - // Do nothing if network operation is done. - DCHECK(response_writer_); - response_writer_->Resume(); + // Let the network pipe continue to read data. + if (resume_callback_) + std::move(resume_callback_).Run(); return; case State::FAILED: - // Restart the network layer. No ongoing blob task should exist. + // Restart the download. + Reset(); SendRequest(); state_ = State::IN_PROGRESS; return; @@ -199,64 +93,48 @@ return bytes_downloaded_; } -void InMemoryDownloadImpl::OnURLFetchDownloadProgress( - const net::URLFetcher* source, - int64_t current, - int64_t total, - int64_t current_network_bytes) { - bytes_downloaded_ = current; +void InMemoryDownloadImpl::OnDataReceived(base::StringPiece string_piece, + base::OnceClosure resume) { + size_t size = string_piece.as_string().size(); + data_.append(string_piece.as_string().data(), size); + bytes_downloaded_ += size; + + if (paused_) { + // Read data later and cache the resumption callback when paused. + resume_callback_ = std::move(resume); + return; + } + + // Continue to read data. + std::move(resume).Run(); // TODO(xingliu): Throttle the update frequency. See https://crbug.com/809674. if (delegate_) delegate_->OnDownloadProgress(this); } -void InMemoryDownloadImpl::OnURLFetchComplete(const net::URLFetcher* source) { - DCHECK(source); - response_headers_ = source->GetResponseHeaders(); - - switch (source->GetStatus().status()) { - case net::URLRequestStatus::Status::SUCCESS: - if (HandleResponseCode(source->GetResponseCode())) { - SaveAsBlob(); - return; - } - - state_ = State::FAILED; - NotifyDelegateDownloadComplete(); - return; - case net::URLRequestStatus::Status::IO_PENDING: - return; - case net::URLRequestStatus::Status::CANCELED: - case net::URLRequestStatus::Status::FAILED: - state_ = State::FAILED; - NotifyDelegateDownloadComplete(); - return; +void InMemoryDownloadImpl::OnComplete(bool success) { + if (success) { + SaveAsBlob(); + return; } + + state_ = State::FAILED; + + // Release download data. + data_.clear(); + NotifyDelegateDownloadComplete(); } -bool InMemoryDownloadImpl::HandleResponseCode(int response_code) { - switch (response_code) { - case -1: // Non-HTTP request. - case net::HTTP_OK: - case net::HTTP_NON_AUTHORITATIVE_INFORMATION: - case net::HTTP_PARTIAL_CONTENT: - case net::HTTP_CREATED: - case net::HTTP_ACCEPTED: - case net::HTTP_NO_CONTENT: - case net::HTTP_RESET_CONTENT: - return true; - // All other codes are considered as failed. - default: - return false; - } +void InMemoryDownloadImpl::OnRetry(base::OnceClosure start_retry) { + Reset(); + std::move(start_retry).Run(); } void InMemoryDownloadImpl::SaveAsBlob() { - DCHECK(url_fetcher_); - std::unique_ptr<std::string> data = response_writer_->TakeData(); auto callback = base::BindOnce(&InMemoryDownloadImpl::OnSaveBlobDone, weak_ptr_factory_.GetWeakPtr()); + auto data = std::make_unique<std::string>(std::move(data_)); blob_task_proxy_->SaveAsBlob(std::move(data), std::move(callback)); } @@ -270,12 +148,13 @@ // TODO(xingliu): Add metric for blob status code. If failed, consider remove // |blob_data_handle_|. See https://crbug.com/809674. + DCHECK(data_.empty()) + << "Download data should be contained in |blob_data_handle_|."; blob_data_handle_ = std::move(blob_handle); completion_time_ = base::Time::Now(); // Resets network backend. - response_writer_ = nullptr; - url_fetcher_.reset(); + loader_.reset(); // Not considering |paused_| here, if pause after starting a blob operation, // just let it finish. @@ -292,21 +171,25 @@ } void InMemoryDownloadImpl::SendRequest() { - url_fetcher_ = net::URLFetcher::Create(request_params_.url, - ToRequestType(request_params_.method), - this, traffic_annotation_); - url_fetcher_->SetRequestContext(request_context_getter_.get()); - url_fetcher_->SetExtraRequestHeaders( - request_params_.request_headers.ToString()); - response_writer_ = - new ResponseWriter(request_context_getter_->GetNetworkTaskRunner()); - url_fetcher_->SaveResponseWithWriter( - std::unique_ptr<ResponseWriter>(response_writer_)); - url_fetcher_->Start(); + auto request = std::make_unique<network::ResourceRequest>(); + request->url = request_params_.url; + request->method = request_params_.method; + request->headers = request_params_.request_headers; + request->load_flags = net::LOAD_DISABLE_CACHE; - // Pause on network thread if needed. - if (paused_) - response_writer_->Pause(); + loader_ = + network::SimpleURLLoader::Create(std::move(request), traffic_annotation_); + + // TODO(xingliu): Use SimpleURLLoader's retry when it won't hit CHECK in + // SharedURLLoaderFactory. + loader_->DownloadAsStream(url_loader_factory_, this); +} + +void InMemoryDownloadImpl::Reset() { + data_.clear(); + bytes_downloaded_ = 0u; + completion_notified_ = false; + resume_callback_.Reset(); } } // namespace download
diff --git a/components/download/internal/background_service/in_memory_download.h b/components/download/internal/background_service/in_memory_download.h index 8f97c9e..9b43751 100644 --- a/components/download/internal/background_service/in_memory_download.h +++ b/components/download/internal/background_service/in_memory_download.h
@@ -14,13 +14,11 @@ #include "base/single_thread_task_runner.h" #include "components/download/internal/background_service/blob_task_proxy.h" #include "components/download/public/background_service/download_params.h" -#include "net/base/completion_callback.h" -#include "net/url_request/url_fetcher_delegate.h" -#include "net/url_request/url_fetcher_response_writer.h" -#include "net/url_request/url_request_context_getter.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "services/network/public/cpp/simple_url_loader_stream_consumer.h" +#include "services/network/public/mojom/url_loader_factory.mojom.h" namespace net { -class URLFetcher; struct NetworkTrafficAnnotationTag; } // namespace net @@ -78,9 +76,7 @@ FAILED, // Download is completed, and data is successfully saved as a blob. - // 1. We guarantee the states of network responses. - // 2. Do not guarantee the state of blob data. The consumer of blob - // should validate its state when using it on IO thread. + // Guarantee the blob is fully constructed. COMPLETE, }; @@ -129,14 +125,15 @@ DISALLOW_COPY_AND_ASSIGN(InMemoryDownload); }; -// Implementation of InMemoryDownload and uses URLFetcher as network backend. +// Implementation of InMemoryDownload and uses SimpleURLLoader as network +// backend. // Threading contract: // 1. This object lives on the main thread. // 2. Reading/writing IO buffer from network is done on another thread, // based on |request_context_getter_|. When complete, main thread is notified. // 3. After network IO is done, Blob related work is done on IO thread with // |blob_task_proxy_|, then notify the result to main thread. -class InMemoryDownloadImpl : public net::URLFetcherDelegate, +class InMemoryDownloadImpl : public network::SimpleURLLoaderStreamConsumer, public InMemoryDownload { public: InMemoryDownloadImpl( @@ -144,51 +141,13 @@ const RequestParams& request_params, const net::NetworkTrafficAnnotationTag& traffic_annotation, Delegate* delegate, - scoped_refptr<net::URLRequestContextGetter> request_context_getter, + network::mojom::URLLoaderFactory* url_loader_factory, BlobTaskProxy::BlobContextGetter blob_context_getter, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + ~InMemoryDownloadImpl() override; private: - // Response writer that supports pause and resume operations. - class ResponseWriter : public net::URLFetcherResponseWriter { - public: - ResponseWriter(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); - ~ResponseWriter() override; - - // Pause writing data from pipe into |data_|. - void Pause(); - - // Resume writing data from the pipe into |data_|. - void Resume(); - - // Take the data, must be called after the network layer completes its job. - std::unique_ptr<std::string> TakeData(); - - private: - // net::URLFetcherResponseWriter implementation. - int Initialize(const net::CompletionCallback& callback) override; - int Write(net::IOBuffer* buffer, - int num_bytes, - const net::CompletionCallback& callback) override; - int Finish(int net_error, const net::CompletionCallback& callback) override; - - void PauseOnIO(); - void ResumeOnIO(); - - // Download data, should be moved to avoid extra copy. - std::unique_ptr<std::string> data_; - - bool paused_on_io_; - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - - // When paused, cached callback to trigger the next read. Must be set and - // called on fetcher's IO thread. - net::CompletionCallback write_callback_; - - DISALLOW_COPY_AND_ASSIGN(ResponseWriter); - }; - // InMemoryDownload implementation. void Start() override; void Pause() override; @@ -197,16 +156,11 @@ std::unique_ptr<storage::BlobDataHandle> ResultAsBlob() override; size_t EstimateMemoryUsage() const override; - // net::URLFetcherDelegate implementation. - void OnURLFetchDownloadProgress(const net::URLFetcher* source, - int64_t current, - int64_t total, - int64_t current_network_bytes) override; - void OnURLFetchComplete(const net::URLFetcher* source) override; - - // Handles response code and change the state accordingly. - // Returns if the response code is considered as successful code. - bool HandleResponseCode(int response_code); + // network::SimpleURLLoaderStreamConsumer implementation. + void OnDataReceived(base::StringPiece string_piece, + base::OnceClosure resume) override; + void OnComplete(bool success) override; + void OnRetry(base::OnceClosure start_retry) override; // Saves the download data into blob storage. void SaveAsBlob(); @@ -218,26 +172,23 @@ // call. void NotifyDelegateDownloadComplete(); - // Sends the network request. + // Sends a new network request. void SendRequest(); + // Resets local states. + void Reset(); + // Request parameters of the download. const RequestParams request_params_; // Traffic annotation of the request. const net::NetworkTrafficAnnotationTag traffic_annotation_; - // Used to send requests to servers. Also contains the download data in its - // string buffer. We should avoid extra copy on the data and release the - // memory when needed. - std::unique_ptr<net::URLFetcher> url_fetcher_; + // Used to send requests to servers. + std::unique_ptr<network::SimpleURLLoader> loader_; - // Owned by |url_fetcher_|. Lives on fetcher's delegate thread, perform - // network IO on fetcher's IO thread. - ResponseWriter* response_writer_; - - // Request context getter used by |url_fetcher_|. - scoped_refptr<net::URLRequestContextGetter> request_context_getter_; + // Used to handle network response. + network::mojom::URLLoaderFactory* url_loader_factory_; // Worker that does blob related task on IO thread. std::unique_ptr<BlobTaskProxy> blob_task_proxy_; @@ -253,6 +204,12 @@ bool paused_; + // Data downloaded from network, should be moved to avoid extra copy. + std::string data_; + + // Cached callback to let network backend continue to pull data. + base::OnceClosure resume_callback_; + // Ensures Delegate::OnDownloadComplete is only called once. bool completion_notified_;
diff --git a/components/download/internal/background_service/in_memory_download_driver.cc b/components/download/internal/background_service/in_memory_download_driver.cc index 186fda2..7f51c7c 100644 --- a/components/download/internal/background_service/in_memory_download_driver.cc +++ b/components/download/internal/background_service/in_memory_download_driver.cc
@@ -47,10 +47,10 @@ } // namespace InMemoryDownloadFactory::InMemoryDownloadFactory( - scoped_refptr<net::URLRequestContextGetter> request_context_getter, + network::mojom::URLLoaderFactory* url_loader_factory, BlobTaskProxy::BlobContextGetter blob_context_getter, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) - : request_context_getter_(request_context_getter), + : url_loader_factory_(url_loader_factory), blob_context_getter_(blob_context_getter), io_task_runner_(io_task_runner) {} @@ -61,9 +61,10 @@ const RequestParams& request_params, const net::NetworkTrafficAnnotationTag& traffic_annotation, InMemoryDownload::Delegate* delegate) { + DCHECK(url_loader_factory_); return std::make_unique<InMemoryDownloadImpl>( - guid, request_params, traffic_annotation, delegate, - request_context_getter_, blob_context_getter_, io_task_runner_); + guid, request_params, traffic_annotation, delegate, url_loader_factory_, + blob_context_getter_, io_task_runner_); } InMemoryDownloadDriver::InMemoryDownloadDriver(
diff --git a/components/download/internal/background_service/in_memory_download_driver.h b/components/download/internal/background_service/in_memory_download_driver.h index 019f7577..881a0b9 100644 --- a/components/download/internal/background_service/in_memory_download_driver.h +++ b/components/download/internal/background_service/in_memory_download_driver.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "components/download/internal/background_service/in_memory_download.h" +#include "services/network/public/mojom/url_loader_factory.mojom.h" namespace download { @@ -21,7 +22,7 @@ class InMemoryDownloadFactory : public InMemoryDownload::Factory { public: InMemoryDownloadFactory( - scoped_refptr<net::URLRequestContextGetter> request_context_getter, + network::mojom::URLLoaderFactory* url_loader_factory, BlobTaskProxy::BlobContextGetter blob_context_getter, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); ~InMemoryDownloadFactory() override; @@ -34,7 +35,8 @@ const net::NetworkTrafficAnnotationTag& traffic_annotation, InMemoryDownload::Delegate* delegate) override; - scoped_refptr<net::URLRequestContextGetter> request_context_getter_; + network::mojom::URLLoaderFactory* url_loader_factory_; + BlobTaskProxy::BlobContextGetter blob_context_getter_; scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
diff --git a/components/download/internal/background_service/in_memory_download_unittest.cc b/components/download/internal/background_service/in_memory_download_unittest.cc index 145f697..397bca1 100644 --- a/components/download/internal/background_service/in_memory_download_unittest.cc +++ b/components/download/internal/background_service/in_memory_download_unittest.cc
@@ -4,16 +4,14 @@ #include "components/download/internal/background_service/in_memory_download.h" -#include "base/files/file_util.h" #include "base/guid.h" -#include "base/path_service.h" #include "base/run_loop.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread.h" -#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/base/io_buffer.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" -#include "net/url_request/url_request_test_util.h" +#include "services/network/test/test_url_loader_factory.h" #include "storage/browser/blob/blob_reader.h" #include "storage/browser/blob/blob_storage_context.h" #include "testing/gmock/include/gmock/gmock.h" @@ -22,18 +20,9 @@ namespace download { namespace { -// Posts a dummy task on |task_runner| and wait for its callback, to drain all -// previous tasks on |task_runner|. -void DrainPreviousTasks( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { - base::RunLoop run_loop; - - auto dummy_task = []() {}; - task_runner->PostTaskAndReply(FROM_HERE, base::BindRepeating(dummy_task), - run_loop.QuitClosure()); - - run_loop.Run(); -} +const char kTestDownloadData[] = + "In earlier tellings, the dog had a better reputation than the cat, " + "however the president veto it."; // Dummy callback used for IO_PENDING state in blob operations, this is not // called when the blob operation is done, but called when chained with other @@ -78,14 +67,10 @@ ~InMemoryDownloadTest() override = default; void SetUp() override { - test_server_.ServeFilesFromDirectory(GetTestDataDirectory()); - ASSERT_TRUE(test_server_.Start()); - io_thread_.reset(new base::Thread("Network and Blob IO thread")); base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); io_thread_->StartWithOptions(options); - request_context_getter_ = - new net::TestURLRequestContextGetter(io_thread_->task_runner()); + base::RunLoop loop; io_thread_->task_runner()->PostTask( FROM_HERE, base::BindLambdaForTesting([&]() { @@ -103,17 +88,11 @@ } protected: - base::FilePath GetTestDataDirectory() { - base::FilePath test_data_dir; - EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); - return test_data_dir.AppendASCII("components/test/data/download"); - } - // Helper method to create a download with request_params. void CreateDownload(const RequestParams& request_params) { download_ = std::make_unique<InMemoryDownloadImpl>( base::GenerateGUID(), request_params, TRAFFIC_ANNOTATION_FOR_TESTS, - delegate(), request_context_getter_, + delegate(), &url_loader_factory_, base::BindRepeating(&BlobStorageContextGetter, blob_storage_context_.get()), io_thread_->task_runner()); @@ -121,9 +100,8 @@ InMemoryDownload* download() { return download_.get(); } MockDelegate* delegate() { return &mock_delegate_; } - net::EmbeddedTestServer* test_server() { return &test_server_; } - scoped_refptr<net::TestURLRequestContextGetter> request_context_getter() { - return request_context_getter_; + network::TestURLLoaderFactory* url_loader_factory() { + return &url_loader_factory_; } // Verifies if data read from |blob| is identical as |expected|. @@ -174,56 +152,27 @@ std::unique_ptr<InMemoryDownloadImpl> download_; MockDelegate mock_delegate_; - // Used by URLFetcher network backend. - scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_; + // Used by SimpleURLLoader network backend. + network::TestURLLoaderFactory url_loader_factory_; // Memory backed blob storage that can never page to disk. std::unique_ptr<storage::BlobStorageContext> blob_storage_context_; - net::EmbeddedTestServer test_server_; - DISALLOW_COPY_AND_ASSIGN(InMemoryDownloadTest); }; TEST_F(InMemoryDownloadTest, DownloadTest) { RequestParams request_params; - request_params.url = test_server()->GetURL("/text_data.json"); CreateDownload(request_params); + url_loader_factory()->AddResponse(request_params.url.spec(), + kTestDownloadData); + // TODO(xingliu): More tests on pause/resume. download()->Start(); delegate()->WaitForCompletion(); EXPECT_EQ(InMemoryDownload::State::COMPLETE, download()->state()); auto blob = download()->ResultAsBlob(); - - std::string expected; - EXPECT_TRUE(ReadFileToString( - GetTestDataDirectory().AppendASCII("text_data.json"), &expected)); - VerifyBlobData(expected, blob.get()); -} - -TEST_F(InMemoryDownloadTest, PauseResume) { - RequestParams request_params; - request_params.url = test_server()->GetURL("/text_data.json"); - CreateDownload(request_params); - - // Pause before sending request. - download()->Pause(); - download()->Start(); - - // Force to return ERR_IO_PENDING on network thread in - // InMemoryDownloadImpl::ResponseWriter::Write. - DrainPreviousTasks(request_context_getter()->GetNetworkTaskRunner()); - - download()->Resume(); - delegate()->WaitForCompletion(); - - EXPECT_EQ(InMemoryDownload::State::COMPLETE, download()->state()); - auto blob = download()->ResultAsBlob(); - - std::string expected; - EXPECT_TRUE(ReadFileToString( - GetTestDataDirectory().AppendASCII("text_data.json"), &expected)); - VerifyBlobData(expected, blob.get()); + VerifyBlobData(kTestDownloadData, blob.get()); } } // namespace
diff --git a/components/download/internal/common/stream_handle_input_stream.cc b/components/download/internal/common/stream_handle_input_stream.cc index eeea7be..a7e7a16c 100644 --- a/components/download/internal/common/stream_handle_input_stream.cc +++ b/components/download/internal/common/stream_handle_input_stream.cc
@@ -100,12 +100,7 @@ void StreamHandleInputStream::OnStreamCompleted( mojom::NetworkRequestStatus status) { // This can be called before or after data pipe is completely drained. - OnResponseCompleted(ConvertMojoNetworkRequestStatusToInterruptReason(status)); -} - -void StreamHandleInputStream::OnResponseCompleted( - DownloadInterruptReason status) { - completion_status_ = status; + completion_status_ = ConvertMojoNetworkRequestStatusToInterruptReason(status); is_response_completed_ = true; if (completion_callback_) std::move(completion_callback_).Run();
diff --git a/components/download/public/common/BUILD.gn b/components/download/public/common/BUILD.gn index 07d258c..e070097 100644 --- a/components/download/public/common/BUILD.gn +++ b/components/download/public/common/BUILD.gn
@@ -38,6 +38,7 @@ "download_url_parameters.cc", "download_url_parameters.h", "download_utils.h", + "input_stream.cc", "input_stream.h", "rate_estimator.h", "resume_mode.h",
diff --git a/components/download/public/common/input_stream.cc b/components/download/public/common/input_stream.cc new file mode 100644 index 0000000..83558fa --- /dev/null +++ b/components/download/public/common/input_stream.cc
@@ -0,0 +1,20 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/public/common/input_stream.h" + +namespace download { + +InputStream::~InputStream() = default; + +void InputStream::Initialize() {} + +void InputStream::RegisterDataReadyCallback( + const mojo::SimpleWatcher::ReadyCallback& callback) {} + +void InputStream::ClearDataReadyCallback() {} + +void InputStream::RegisterCompletionCallback(base::OnceClosure callback) {} + +} // namespace download
diff --git a/components/download/public/common/input_stream.h b/components/download/public/common/input_stream.h index e6c88dd..938daba2 100644 --- a/components/download/public/common/input_stream.h +++ b/components/download/public/common/input_stream.h
@@ -24,21 +24,21 @@ COMPLETE, }; - virtual ~InputStream() = default; + virtual ~InputStream(); // Initializes the inputStream object. - virtual void Initialize() {} + virtual void Initialize(); // Returns true if the input stream contains no data, or false otherwise. virtual bool IsEmpty() = 0; // Register/clear callbacks when data become available. virtual void RegisterDataReadyCallback( - const mojo::SimpleWatcher::ReadyCallback& callback) {} - virtual void ClearDataReadyCallback() {} + const mojo::SimpleWatcher::ReadyCallback& callback); + virtual void ClearDataReadyCallback(); // Registers stream completion callback if needed. - virtual void RegisterCompletionCallback(base::OnceClosure callback) {} + virtual void RegisterCompletionCallback(base::OnceClosure callback); // Reads data from the stream into |data|, |length| is the number of bytes // returned. @@ -47,9 +47,6 @@ // Returns the completion status. virtual DownloadInterruptReason GetCompletionStatus() = 0; - - // Mark the InputStream as completed and set the completion status. - virtual void OnResponseCompleted(DownloadInterruptReason status){}; }; } // namespace download
diff --git a/components/download/public/common/stream_handle_input_stream.h b/components/download/public/common/stream_handle_input_stream.h index 810ed005..a54097e 100644 --- a/components/download/public/common/stream_handle_input_stream.h +++ b/components/download/public/common/stream_handle_input_stream.h
@@ -32,7 +32,6 @@ InputStream::StreamState Read(scoped_refptr<net::IOBuffer>* data, size_t* length) override; DownloadInterruptReason GetCompletionStatus() override; - void OnResponseCompleted(DownloadInterruptReason status) override; // mojom::DownloadStreamClient void OnStreamCompleted(mojom::NetworkRequestStatus status) override;
diff --git a/components/mirroring/browser/cast_remoting_sender.cc b/components/mirroring/browser/cast_remoting_sender.cc index 2f365ac1..63f3557 100644 --- a/components/mirroring/browser/cast_remoting_sender.cc +++ b/components/mirroring/browser/cast_remoting_sender.cc
@@ -362,7 +362,7 @@ // Always force a post task to prevent the stack from growing too deep. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&CastRemotingSender::ProcessNextInputTask, - base::Unretained(this))); + weak_factory_.GetWeakPtr())); } void CastRemotingSender::ReadFrame(uint32_t size) {
diff --git a/components/printing/browser/print_manager_utils.cc b/components/printing/browser/print_manager_utils.cc index 5bd1fd71..6dffcb52 100644 --- a/components/printing/browser/print_manager_utils.cc +++ b/components/printing/browser/print_manager_utils.cc
@@ -37,8 +37,10 @@ switches::kSitePerProcess) || base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kIsolateOrigins) || - base::FeatureList::IsEnabled(features::kSitePerProcess) || - base::FeatureList::IsEnabled(features::kIsolateOrigins) || + ((base::FeatureList::IsEnabled(features::kSitePerProcess) || + base::FeatureList::IsEnabled(features::kIsolateOrigins)) && + !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableSiteIsolationTrials)) || base::FeatureList::IsEnabled(features::kTopDocumentIsolation)) { PrintCompositeClient::CreateForWebContents(web_contents); if (for_preview) {
diff --git a/components/test/data/download/text_data.json b/components/test/data/download/text_data.json deleted file mode 100644 index 369f7de..0000000 --- a/components/test/data/download/text_data.json +++ /dev/null
@@ -1,3 +0,0 @@ -{ - "data":"In earlier tellings, the dog had a better reputation than the cat, however the president veto it." -} \ No newline at end of file
diff --git a/components/update_client/component.h b/components/update_client/component.h index c7112400..5293f3a 100644 --- a/components/update_client/component.h +++ b/components/update_client/component.h
@@ -119,7 +119,7 @@ std::string session_id() const; private: - friend class FakePingManagerImpl; + friend class MockPingManagerImpl; friend class UpdateCheckerTest; FRIEND_TEST_ALL_PREFIXES(PingManagerTest, SendPing);
diff --git a/components/update_client/ping_manager_unittest.cc b/components/update_client/ping_manager_unittest.cc index 4d8b2fb..25f46ad 100644 --- a/components/update_client/ping_manager_unittest.cc +++ b/components/update_client/ping_manager_unittest.cc
@@ -34,7 +34,7 @@ ~PingManagerTest() override {} PingManager::Callback MakePingCallback(); - scoped_refptr<UpdateContext> MakeFakeUpdateContext() const; + scoped_refptr<UpdateContext> MakeMockUpdateContext() const; // Overrides from testing::Test. void SetUp() override; @@ -96,7 +96,7 @@ Quit(); } -scoped_refptr<UpdateContext> PingManagerTest::MakeFakeUpdateContext() const { +scoped_refptr<UpdateContext> PingManagerTest::MakeMockUpdateContext() const { return base::MakeRefCounted<UpdateContext>( config_, false, std::vector<std::string>(), UpdateClient::CrxDataCallback(), UpdateEngine::NotifyObserversCallback(), @@ -110,7 +110,7 @@ EXPECT_TRUE(interceptor); // Test eventresult="1" is sent for successful updates. - const auto update_context = MakeFakeUpdateContext(); + const auto update_context = MakeMockUpdateContext(); { Component component(*update_context, "abc"); @@ -303,7 +303,7 @@ TEST_F(PingManagerTest, RequiresEncryption) { config_->SetPingUrl(GURL("http:\\foo\bar")); - const auto update_context = MakeFakeUpdateContext(); + const auto update_context = MakeMockUpdateContext(); Component component(*update_context, "abc");
diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc index d37f2c9..ea07e24 100644 --- a/components/update_client/update_checker_unittest.cc +++ b/components/update_client/update_checker_unittest.cc
@@ -138,7 +138,7 @@ scoped_refptr<UpdateContext> update_context_; private: - scoped_refptr<UpdateContext> MakeFakeUpdateContext() const; + scoped_refptr<UpdateContext> MakeMockUpdateContext() const; base::test::ScopedTaskEnvironment scoped_task_environment_; base::OnceClosure quit_closure_; @@ -171,7 +171,7 @@ error_ = 0; retry_after_sec_ = 0; - update_context_ = MakeFakeUpdateContext(); + update_context_ = MakeMockUpdateContext(); } void UpdateCheckerTest::TearDown() { @@ -204,7 +204,7 @@ Quit(); } -scoped_refptr<UpdateContext> UpdateCheckerTest::MakeFakeUpdateContext() const { +scoped_refptr<UpdateContext> UpdateCheckerTest::MakeMockUpdateContext() const { return base::MakeRefCounted<UpdateContext>( config_, false, std::vector<std::string>(), UpdateClient::CrxDataCallback(), UpdateEngine::NotifyObserversCallback(),
diff --git a/components/update_client/update_client_unittest.cc b/components/update_client/update_client_unittest.cc index b59c57b..4b9c0b1f 100644 --- a/components/update_client/update_client_unittest.cc +++ b/components/update_client/update_client_unittest.cc
@@ -87,7 +87,7 @@ using std::string; -class FakePingManagerImpl : public PingManager { +class MockPingManagerImpl : public PingManager { public: struct PingData { std::string id; @@ -101,7 +101,7 @@ bool diff_update_failed = false; }; - explicit FakePingManagerImpl(scoped_refptr<Configurator> config); + explicit MockPingManagerImpl(scoped_refptr<Configurator> config); void SendPing(const Component& component, Callback callback) override; @@ -110,21 +110,20 @@ const std::vector<std::string>& events() const; protected: - ~FakePingManagerImpl() override; + ~MockPingManagerImpl() override; private: std::vector<PingData> ping_data_; std::vector<std::string> events_; - DISALLOW_COPY_AND_ASSIGN(FakePingManagerImpl); + DISALLOW_COPY_AND_ASSIGN(MockPingManagerImpl); }; -FakePingManagerImpl::FakePingManagerImpl(scoped_refptr<Configurator> config) +MockPingManagerImpl::MockPingManagerImpl(scoped_refptr<Configurator> config) : PingManager(config) {} -FakePingManagerImpl::~FakePingManagerImpl() { -} +MockPingManagerImpl::~MockPingManagerImpl() {} -void FakePingManagerImpl::SendPing(const Component& component, +void MockPingManagerImpl::SendPing(const Component& component, Callback callback) { PingData ping_data; ping_data.id = component.id_; @@ -144,12 +143,12 @@ std::move(callback).Run(0, ""); } -const std::vector<FakePingManagerImpl::PingData>& -FakePingManagerImpl::ping_data() const { +const std::vector<MockPingManagerImpl::PingData>& +MockPingManagerImpl::ping_data() const { return ping_data_; } -const std::vector<std::string>& FakePingManagerImpl::events() const { +const std::vector<std::string>& MockPingManagerImpl::events() const { return events_; } @@ -212,7 +211,7 @@ // Tests the scenario where one update check is done for one CRX. The CRX // has no update. TEST_F(UpdateClientTest, OneCrxNoUpdate) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -225,7 +224,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::NONE, error); @@ -233,12 +232,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -268,33 +267,33 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { EXPECT_TRUE(ping_data().empty()); } + ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); } }; scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; InSequence seq; @@ -307,8 +306,8 @@ const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"}; update_client->Update( - ids, base::BindOnce(&DataCallbackFake::Callback), true, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + ids, base::BindOnce(&DataCallbackMock::Callback), true, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -318,7 +317,7 @@ // Tests the scenario where two CRXs are checked for updates. On CRX has // an update, the other CRX does not. TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -339,7 +338,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::NONE, error); @@ -347,12 +346,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -362,7 +361,7 @@ bool enabled_component_updates, UpdateCheckCallback update_check_callback) override { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> @@ -430,15 +429,15 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { @@ -461,24 +460,24 @@ result.total_bytes = 1843; base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress, base::Unretained(this), result)); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete, base::Unretained(this), true, result, download_metrics)); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto ping_data = FakePingManagerImpl::ping_data(); + ~MockPingManager() override { + const auto ping_data = MockPingManagerImpl::ping_data(); EXPECT_EQ(1u, ping_data.size()); EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id); EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version); @@ -490,8 +489,8 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; { @@ -521,8 +520,8 @@ const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf", "abagagagagagagagagagagagagagagag"}; update_client->Update( - ids, base::BindOnce(&DataCallbackFake::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + ids, base::BindOnce(&DataCallbackMock::Callback), false, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -531,7 +530,7 @@ // Tests the update check for two CRXs scenario. Both CRXs have updates. TEST_F(UpdateClientTest, TwoCrxUpdate) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -552,7 +551,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::NONE, error); @@ -560,12 +559,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -575,7 +574,7 @@ bool enabled_component_updates, UpdateCheckCallback update_check_callback) override { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> @@ -666,15 +665,15 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { @@ -717,24 +716,24 @@ } base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress, base::Unretained(this), result)); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete, base::Unretained(this), true, result, download_metrics)); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto ping_data = FakePingManagerImpl::ping_data(); + ~MockPingManager() override { + const auto ping_data = MockPingManagerImpl::ping_data(); EXPECT_EQ(2u, ping_data.size()); EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id); EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version); @@ -751,8 +750,8 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; { @@ -791,8 +790,8 @@ const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf", "ihfokbkgjpifnbbojhneepfflplebdkc"}; update_client->Update( - ids, base::BindOnce(&DataCallbackFake::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + ids, base::BindOnce(&DataCallbackMock::Callback), false, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -803,7 +802,7 @@ // CRX. The update for the first CRX fails. The update client waits before // attempting the update for the second CRX. This update succeeds. TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -824,7 +823,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::NONE, error); @@ -832,12 +831,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -847,7 +846,7 @@ bool enabled_component_updates, UpdateCheckCallback update_check_callback) override { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> @@ -935,15 +934,15 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { @@ -983,24 +982,24 @@ } base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress, base::Unretained(this), result)); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete, base::Unretained(this), true, result, download_metrics)); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto ping_data = FakePingManagerImpl::ping_data(); + ~MockPingManager() override { + const auto ping_data = MockPingManagerImpl::ping_data(); EXPECT_EQ(2u, ping_data.size()); EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id); EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version); @@ -1017,8 +1016,8 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; { @@ -1057,8 +1056,8 @@ "ihfokbkgjpifnbbojhneepfflplebdkc"}; update_client->Update( - ids, base::BindOnce(&DataCallbackFake::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + ids, base::BindOnce(&DataCallbackMock::Callback), false, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -1067,7 +1066,7 @@ // Tests the differential update scenario for one CRX. TEST_F(UpdateClientTest, OneCrxDiffUpdate) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -1095,7 +1094,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::NONE, error); @@ -1103,12 +1102,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -1126,7 +1125,7 @@ if (num_call == 1) { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'> @@ -1166,7 +1165,7 @@ component->SetParseResult(result); } else if (num_call == 2) { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'> @@ -1223,15 +1222,15 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { @@ -1274,24 +1273,24 @@ } base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress, base::Unretained(this), result)); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete, base::Unretained(this), true, result, download_metrics)); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto ping_data = FakePingManagerImpl::ping_data(); + ~MockPingManager() override { + const auto ping_data = MockPingManagerImpl::ping_data(); EXPECT_EQ(2u, ping_data.size()); EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id); EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version); @@ -1311,8 +1310,8 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; { @@ -1346,18 +1345,18 @@ const std::vector<std::string> ids = {"ihfokbkgjpifnbbojhneepfflplebdkc"}; { base::RunLoop runloop; - update_client->Update(ids, base::BindOnce(&DataCallbackFake::Callback), + update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, + base::BindOnce(&CompletionCallbackMock::Callback, runloop.QuitClosure())); runloop.Run(); } { base::RunLoop runloop; - update_client->Update(ids, base::BindOnce(&DataCallbackFake::Callback), + update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, + base::BindOnce(&CompletionCallbackMock::Callback, runloop.QuitClosure())); runloop.Run(); } @@ -1407,7 +1406,7 @@ base::FilePath unpack_path_; }; - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -1428,7 +1427,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::NONE, error); @@ -1436,12 +1435,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -1451,7 +1450,7 @@ bool enabled_component_updates, UpdateCheckCallback update_check_callback) override { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> @@ -1498,15 +1497,15 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { @@ -1529,24 +1528,24 @@ result.total_bytes = 1843; base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress, base::Unretained(this), result)); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete, base::Unretained(this), true, result, download_metrics)); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto ping_data = FakePingManagerImpl::ping_data(); + ~MockPingManager() override { + const auto ping_data = MockPingManagerImpl::ping_data(); EXPECT_EQ(1u, ping_data.size()); EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id); EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version); @@ -1558,8 +1557,8 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; { @@ -1582,8 +1581,8 @@ std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"}; update_client->Update( - ids, base::BindOnce(&DataCallbackFake::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + ids, base::BindOnce(&DataCallbackMock::Callback), false, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -1592,7 +1591,7 @@ // Tests the fallback from differential to full update scenario for one CRX. TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -1620,7 +1619,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::NONE, error); @@ -1628,12 +1627,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -1651,7 +1650,7 @@ if (num_call == 1) { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'> @@ -1693,7 +1692,7 @@ component->SetParseResult(result); } else if (num_call == 2) { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'> @@ -1750,15 +1749,15 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { @@ -1813,24 +1812,24 @@ } base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress, base::Unretained(this), result)); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete, base::Unretained(this), true, result, download_metrics)); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto ping_data = FakePingManagerImpl::ping_data(); + ~MockPingManager() override { + const auto ping_data = MockPingManagerImpl::ping_data(); EXPECT_EQ(2u, ping_data.size()); EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id); EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version); @@ -1850,8 +1849,8 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; { @@ -1887,18 +1886,18 @@ { base::RunLoop runloop; - update_client->Update(ids, base::BindOnce(&DataCallbackFake::Callback), + update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, + base::BindOnce(&CompletionCallbackMock::Callback, runloop.QuitClosure())); runloop.Run(); } { base::RunLoop runloop; - update_client->Update(ids, base::BindOnce(&DataCallbackFake::Callback), + update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, + base::BindOnce(&CompletionCallbackMock::Callback, runloop.QuitClosure())); runloop.Run(); } @@ -1910,7 +1909,7 @@ // done for one CRX. The second update check call is queued up and will run // after the first check has completed. The CRX has no updates. TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -1923,7 +1922,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { static int num_call = 0; @@ -1936,12 +1935,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -1971,33 +1970,33 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { EXPECT_TRUE(ping_data().empty()); } + ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); } }; scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; InSequence seq; @@ -2014,11 +2013,11 @@ const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"}; update_client->Update( - ids, base::BindOnce(&DataCallbackFake::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + ids, base::BindOnce(&DataCallbackMock::Callback), false, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); update_client->Update( - ids, base::BindOnce(&DataCallbackFake::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + ids, base::BindOnce(&DataCallbackMock::Callback), false, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -2027,7 +2026,7 @@ // Tests the install of one CRX. TEST_F(UpdateClientTest, OneCrxInstall) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -2041,7 +2040,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::NONE, error); @@ -2049,12 +2048,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -2064,7 +2063,7 @@ bool enabled_component_updates, UpdateCheckCallback update_check_callback) override { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> @@ -2116,15 +2115,15 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { @@ -2151,24 +2150,24 @@ } base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress, base::Unretained(this), result)); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete, base::Unretained(this), true, result, download_metrics)); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto ping_data = FakePingManagerImpl::ping_data(); + ~MockPingManager() override { + const auto ping_data = MockPingManagerImpl::ping_data(); EXPECT_EQ(1u, ping_data.size()); EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id); EXPECT_EQ(base::Version("0.0"), ping_data[0].previous_version); @@ -2180,8 +2179,8 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; InSequence seq; @@ -2201,8 +2200,8 @@ update_client->Install( std::string("jebgalgnebhfojomionfpkfelancnnkf"), - base::BindOnce(&DataCallbackFake::Callback), - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + base::BindOnce(&DataCallbackMock::Callback), + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -2211,7 +2210,7 @@ // Tests that overlapping installs of the same CRX result in an error. TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -2225,7 +2224,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { static int num_call = 0; @@ -2244,12 +2243,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -2280,33 +2279,33 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { EXPECT_TRUE(ping_data().empty()); } + ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); } }; scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, @@ -2320,13 +2319,13 @@ update_client->Install( std::string("jebgalgnebhfojomionfpkfelancnnkf"), - base::BindOnce(&DataCallbackFake::Callback), - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + base::BindOnce(&DataCallbackMock::Callback), + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); update_client->Install( std::string("jebgalgnebhfojomionfpkfelancnnkf"), - base::BindOnce(&DataCallbackFake::Callback), - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + base::BindOnce(&DataCallbackMock::Callback), + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -2336,13 +2335,13 @@ // Tests that UpdateClient::Update returns Error::INVALID_ARGUMENT when // the |ids| parameter is empty. TEST_F(UpdateClientTest, EmptyIdList) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) {} }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { DCHECK_EQ(Error::INVALID_ARGUMENT, error); @@ -2350,12 +2349,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -2368,50 +2367,50 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { EXPECT_TRUE(ping_data().empty()); } + ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); } }; scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); const std::vector<std::string> empty_id_list; update_client->Update( - empty_id_list, base::BindOnce(&DataCallbackFake::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + empty_id_list, base::BindOnce(&DataCallbackMock::Callback), false, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); } TEST_F(UpdateClientTest, SendUninstallPing) { - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { std::move(quit_closure).Run(); } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, @@ -2429,7 +2428,7 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, @@ -2438,20 +2437,20 @@ } private: - FakeCrxDownloader() : CrxDownloader(nullptr) {} - ~FakeCrxDownloader() override {} + MockCrxDownloader() : CrxDownloader(nullptr) {} + ~MockCrxDownloader() override {} void DoStartDownload(const GURL& url) override {} }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto ping_data = FakePingManagerImpl::ping_data(); + ~MockPingManager() override { + const auto ping_data = MockPingManagerImpl::ping_data(); EXPECT_EQ(1u, ping_data.size()); EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id); EXPECT_EQ(base::Version("1.2.3.4"), ping_data[0].previous_version); @@ -2462,18 +2461,18 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); update_client->SendUninstallPing( "jebgalgnebhfojomionfpkfelancnnkf", base::Version("1.2.3.4"), 10, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); } TEST_F(UpdateClientTest, RetryAfter) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -2486,7 +2485,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { static int num_call = 0; @@ -2514,12 +2513,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -2559,33 +2558,33 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { EXPECT_TRUE(ping_data().empty()); } + ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); } }; scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; @@ -2616,9 +2615,9 @@ // The engine handles this Update call but responds with a valid // |retry_after_sec|, which causes subsequent calls to fail. base::RunLoop runloop; - update_client->Update(ids, base::BindOnce(&DataCallbackFake::Callback), + update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, + base::BindOnce(&CompletionCallbackMock::Callback, runloop.QuitClosure())); runloop.Run(); } @@ -2627,9 +2626,9 @@ // This call will result in a completion callback invoked with // Error::ERROR_UPDATE_RETRY_LATER. base::RunLoop runloop; - update_client->Update(ids, base::BindOnce(&DataCallbackFake::Callback), + update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, + base::BindOnce(&CompletionCallbackMock::Callback, runloop.QuitClosure())); runloop.Run(); } @@ -2639,8 +2638,8 @@ // the value of |retry_after_sec| in the completion callback. base::RunLoop runloop; update_client->Install(std::string("jebgalgnebhfojomionfpkfelancnnkf"), - base::BindOnce(&DataCallbackFake::Callback), - base::BindOnce(&CompletionCallbackFake::Callback, + base::BindOnce(&DataCallbackMock::Callback), + base::BindOnce(&CompletionCallbackMock::Callback, runloop.QuitClosure())); runloop.Run(); } @@ -2648,9 +2647,9 @@ { // This call succeeds. base::RunLoop runloop; - update_client->Update(ids, base::BindOnce(&DataCallbackFake::Callback), + update_client->Update(ids, base::BindOnce(&DataCallbackMock::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, + base::BindOnce(&CompletionCallbackMock::Callback, runloop.QuitClosure())); runloop.Run(); } @@ -2665,7 +2664,7 @@ // the first component is not apply and the client responds with a // (SERVICE_ERROR, UPDATE_DISABLED) TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -2687,7 +2686,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::NONE, error); @@ -2695,12 +2694,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -2710,7 +2709,7 @@ bool enabled_component_updates, UpdateCheckCallback update_check_callback) override { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> @@ -2802,15 +2801,15 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { @@ -2837,24 +2836,24 @@ } base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadProgress, base::Unretained(this), result)); base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete, base::Unretained(this), true, result, download_metrics)); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto ping_data = FakePingManagerImpl::ping_data(); + ~MockPingManager() override { + const auto ping_data = MockPingManagerImpl::ping_data(); EXPECT_EQ(2u, ping_data.size()); EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id); EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version); @@ -2873,8 +2872,8 @@ config()->SetEnabledComponentUpdates(false); scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; { @@ -2913,8 +2912,8 @@ const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf", "ihfokbkgjpifnbbojhneepfflplebdkc"}; update_client->Update( - ids, base::BindOnce(&DataCallbackFake::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + ids, base::BindOnce(&DataCallbackMock::Callback), false, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -2923,7 +2922,7 @@ // Tests the scenario where the update check fails. TEST_F(UpdateClientTest, OneCrxUpdateCheckFails) { - class DataCallbackFake { + class DataCallbackMock { public: static void Callback(const std::vector<std::string>& ids, std::vector<CrxComponent>* components) { @@ -2936,7 +2935,7 @@ } }; - class CompletionCallbackFake { + class CompletionCallbackMock { public: static void Callback(base::OnceClosure quit_closure, Error error) { EXPECT_EQ(Error::UPDATE_CHECK_ERROR, error); @@ -2944,12 +2943,12 @@ } }; - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -2970,33 +2969,33 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { EXPECT_TRUE(ping_data().empty()); } + ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); } }; scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); MockObserver observer; InSequence seq; @@ -3016,8 +3015,8 @@ const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf"}; update_client->Update( - ids, base::BindOnce(&DataCallbackFake::Callback), false, - base::BindOnce(&CompletionCallbackFake::Callback, quit_closure())); + ids, base::BindOnce(&DataCallbackMock::Callback), false, + base::BindOnce(&CompletionCallbackMock::Callback, quit_closure())); RunThreads(); @@ -3028,12 +3027,12 @@ // Tests that a run action in invoked in the CRX install scenario. TEST_F(UpdateClientTest, ActionRun_Install) { - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -3043,7 +3042,7 @@ bool enabled_component_updates, UpdateCheckCallback update_check_callback) override { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> @@ -3095,15 +3094,15 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { @@ -3130,20 +3129,20 @@ } base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete, + FROM_HERE, base::BindOnce(&MockCrxDownloader::OnDownloadComplete, base::Unretained(this), true, result, download_metrics)); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto& events = FakePingManagerImpl::events(); + ~MockPingManager() override { + const auto& events = MockPingManagerImpl::events(); EXPECT_EQ(3u, events.size()); EXPECT_STREQ( "<event eventtype=\"14\" eventresult=\"1\" downloader=\"unknown\" " @@ -3165,8 +3164,8 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); // The action is a program which returns 1877345072 as a hardcoded value. update_client->Install( @@ -3193,12 +3192,12 @@ // Tests that a run action is invoked in an update scenario when there was // no update. TEST_F(UpdateClientTest, ActionRun_NoUpdate) { - class FakeUpdateChecker : public UpdateChecker { + class MockUpdateChecker : public UpdateChecker { public: static std::unique_ptr<UpdateChecker> Create( scoped_refptr<Configurator> config, PersistedData* metadata) { - return std::make_unique<FakeUpdateChecker>(); + return std::make_unique<MockUpdateChecker>(); } void CheckForUpdates(const std::string& session_id, @@ -3208,7 +3207,7 @@ bool enabled_component_updates, UpdateCheckCallback update_check_callback) override { /* - Fake the following response: + Mock the following response: <?xml version='1.0' encoding='UTF-8'?> <response protocol='3.1'> @@ -3241,28 +3240,28 @@ } }; - class FakeCrxDownloader : public CrxDownloader { + class MockCrxDownloader : public CrxDownloader { public: static std::unique_ptr<CrxDownloader> Create( bool is_background_download, scoped_refptr<net::URLRequestContextGetter> context_getter) { - return std::make_unique<FakeCrxDownloader>(); + return std::make_unique<MockCrxDownloader>(); } - FakeCrxDownloader() : CrxDownloader(nullptr) {} + MockCrxDownloader() : CrxDownloader(nullptr) {} private: void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } }; - class FakePingManager : public FakePingManagerImpl { + class MockPingManager : public MockPingManagerImpl { public: - explicit FakePingManager(scoped_refptr<Configurator> config) - : FakePingManagerImpl(config) {} + explicit MockPingManager(scoped_refptr<Configurator> config) + : MockPingManagerImpl(config) {} protected: - ~FakePingManager() override { - const auto& events = FakePingManagerImpl::events(); + ~MockPingManager() override { + const auto& events = MockPingManagerImpl::events(); EXPECT_EQ(1u, events.size()); EXPECT_STREQ( "<event eventtype=\"42\" eventresult=\"1\" " @@ -3309,8 +3308,8 @@ scoped_refptr<UpdateClient> update_client = base::MakeRefCounted<UpdateClientImpl>( - config(), base::MakeRefCounted<FakePingManager>(config()), - &FakeUpdateChecker::Create, &FakeCrxDownloader::Create); + config(), base::MakeRefCounted<MockPingManager>(config()), + &MockUpdateChecker::Create, &MockCrxDownloader::Create); // The action is a program which returns 1877345072 as a hardcoded value. const std::vector<std::string> ids = {"gjpmebpgbhcamgdgjcmnjfhggjpgcimm"};
diff --git a/components/viz/client/hit_test_data_provider_draw_quad.cc b/components/viz/client/hit_test_data_provider_draw_quad.cc index a44809b..f571fa89 100644 --- a/components/viz/client/hit_test_data_provider_draw_quad.cc +++ b/components/viz/client/hit_test_data_provider_draw_quad.cc
@@ -23,6 +23,14 @@ hit_test_region_list->bounds.set_size(compositor_frame.size_in_pixels()); for (const auto& render_pass : compositor_frame.render_pass_list) { + // Skip the render_pass if the transform is not invertible (i.e. it will not + // be able to receive events). + gfx::Transform transform_from_root_target; + if (!render_pass->transform_to_root_target.GetInverse( + &transform_from_root_target)) { + continue; + } + for (const DrawQuad* quad : render_pass->quad_list) { if (quad->material == DrawQuad::SURFACE_CONTENT) { // Skip the quad if the transform is not invertible (i.e. it will not @@ -44,7 +52,8 @@ if (should_ask_for_child_region_) hit_test_region->flags |= mojom::kHitTestAsk; hit_test_region->rect = surface_quad->rect; - hit_test_region->transform = target_to_quad_transform; + hit_test_region->transform = + target_to_quad_transform * transform_from_root_target; hit_test_region_list->regions.push_back(std::move(hit_test_region)); } }
diff --git a/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc b/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc index 85eea7f5..dc0d0d6 100644 --- a/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc +++ b/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
@@ -25,24 +25,32 @@ namespace { -CompositorFrame MakeCompositorFrameWithChildSurface( +SurfaceId CreateChildSurfaceId(uint32_t id) { + LocalSurfaceId child_local_surface_id(id, base::UnguessableToken::Create()); + FrameSinkId frame_sink_id(id, 0); + SurfaceId child_surface_id(frame_sink_id, child_local_surface_id); + return child_surface_id; +} + +std::unique_ptr<RenderPass> CreateRenderPassWithChildSurface( const SurfaceId& child_surface_id, const gfx::Rect& rect, const gfx::Rect& child_rect, - const gfx::Transform& transform) { + const gfx::Transform& render_pass_transform, + const gfx::Transform& shared_state_transform) { auto pass = RenderPass::Create(); - pass->SetNew(1, rect, rect, gfx::Transform()); + pass->SetNew(1, rect, rect, render_pass_transform); auto* shared_state = pass->CreateAndAppendSharedQuadState(); - shared_state->SetAll(transform, rect, rect, rect, false, false, 1, - SkBlendMode::kSrcOver, 0); + shared_state->SetAll(shared_state_transform, rect, rect, rect, false, false, + 1, SkBlendMode::kSrcOver, 0); auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>(); surface_quad->SetNew(pass->shared_quad_state_list.back(), child_rect, child_rect, child_surface_id, base::nullopt, SK_ColorWHITE, false); - return CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build(); + return pass; } } // namespace @@ -69,14 +77,18 @@ // Ensure that a CompositorFrame with a child surface only set kHitTestAsk // for its child surface. - LocalSurfaceId child_local_surface_id(2, base::UnguessableToken::Create()); - FrameSinkId frame_sink_id(2, 0); - SurfaceId child_surface_id(frame_sink_id, child_local_surface_id); + SurfaceId child_surface_id = CreateChildSurfaceId(2); gfx::Rect child_rect(200, 100); - gfx::Transform transform; - transform.Translate(-200, -100); - compositor_frame = MakeCompositorFrameWithChildSurface( - child_surface_id, kFrameRect, child_rect, transform); + gfx::Transform render_pass_transform; + render_pass_transform.Translate(-50, -100); + render_pass_transform.Skew(2, 3); + gfx::Transform shared_state_transform; + shared_state_transform.Translate(-200, -100); + auto pass = CreateRenderPassWithChildSurface( + child_surface_id, kFrameRect, child_rect, render_pass_transform, + shared_state_transform); + compositor_frame = + CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build(); hit_test_region_list = hit_test_data_provider->GetHitTestData(compositor_frame); @@ -92,9 +104,70 @@ mojom::kHitTestChildSurface | mojom::kHitTestAsk, hit_test_region_list->regions[0]->flags); EXPECT_EQ(child_rect, hit_test_region_list->regions[0]->rect); - gfx::Transform transform_inverse; - EXPECT_TRUE(transform.GetInverse(&transform_inverse)); - EXPECT_EQ(transform_inverse, hit_test_region_list->regions[0]->transform); + gfx::Transform render_pass_transform_inverse; + EXPECT_TRUE(render_pass_transform.GetInverse(&render_pass_transform_inverse)); + gfx::Transform shared_state_transform_inverse; + EXPECT_TRUE( + shared_state_transform.GetInverse(&shared_state_transform_inverse)); + EXPECT_EQ(shared_state_transform_inverse * render_pass_transform_inverse, + hit_test_region_list->regions[0]->transform); +} + +// Test to ensure that we skip regions with a non-invertible transform when +// preparing hit-test data. +TEST(HitTestDataProviderDrawQuad, HitTestDataInvertibleTransform) { + std::unique_ptr<HitTestDataProvider> hit_test_data_provider = + std::make_unique<HitTestDataProviderDrawQuad>( + true /* should_ask_for_child_region */); + + constexpr gfx::Rect kFrameRect(0, 0, 1024, 768); + gfx::Rect child_rect(200, 100); + + // A degenerate matrix of all zeros is not invertible. + gfx::Transform not_invertible_transform; + not_invertible_transform.matrix().set(0, 0, 0.f); + not_invertible_transform.matrix().set(1, 1, 0.f); + not_invertible_transform.matrix().set(2, 2, 0.f); + not_invertible_transform.matrix().set(3, 3, 0.f); + + gfx::Transform invertible_transform; + invertible_transform.Translate(-200, -100); + + RenderPassList pass_list; + + // A render pass that has non-invertible transform. + SurfaceId child_surface_id1 = CreateChildSurfaceId(2); + auto pass1 = CreateRenderPassWithChildSurface( + child_surface_id1, kFrameRect, child_rect, not_invertible_transform, + invertible_transform); + pass_list.push_back(std::move(pass1)); + + // A render pass with a draw quad that has non-invertible transform. + SurfaceId child_surface_id2 = CreateChildSurfaceId(3); + auto pass2 = CreateRenderPassWithChildSurface( + child_surface_id2, kFrameRect, child_rect, invertible_transform, + not_invertible_transform); + pass_list.push_back(std::move(pass2)); + + // A render pass and its draw quad both have invertible transforms + SurfaceId child_surface_id3 = CreateChildSurfaceId(4); + auto pass3 = CreateRenderPassWithChildSurface( + child_surface_id3, kFrameRect, child_rect, invertible_transform, + invertible_transform); + pass_list.push_back(std::move(pass3)); + + auto compositor_frame = + CompositorFrameBuilder().SetRenderPassList(std::move(pass_list)).Build(); + mojom::HitTestRegionListPtr hit_test_region_list = + hit_test_data_provider->GetHitTestData(compositor_frame); + + // Only pass3 should have a hit-test region that corresponds to + // child_surface_id3. + EXPECT_EQ(1u, hit_test_region_list->regions.size()); + EXPECT_EQ(child_surface_id3.frame_sink_id(), + hit_test_region_list->regions[0]->frame_sink_id); + EXPECT_EQ(child_surface_id3.local_surface_id(), + hit_test_region_list->regions[0]->local_surface_id); } } // namespace viz
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc index facfe98..7fa21dd 100644 --- a/components/viz/service/display/renderer_pixeltest.cc +++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -1449,13 +1449,10 @@ ::testing::tuple<bool, HighbitTexture>> { public: void SetSupportHighbitTexture(HighbitTexture texture) { - cc::TestInProcessContextProvider* context_provider = - GetTestInProcessContextProvider(); switch (texture) { case HighbitTexture::Y8: break; case HighbitTexture::R16_EXT: - context_provider->SetSupportTextureNorm16(true); video_resource_updater_->SetUseR16ForTesting(true); break; }
diff --git a/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc b/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc index 72cc46c..1749f07c 100644 --- a/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc +++ b/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
@@ -198,6 +198,14 @@ hit_test_region_list->bounds.set_size(frame.size_in_pixels()); for (const auto& render_pass : frame.render_pass_list) { + // Skip the render_pass if the transform is not invertible (i.e. it will not + // be able to receive events). + gfx::Transform transform_from_root_target; + if (!render_pass->transform_to_root_target.GetInverse( + &transform_from_root_target)) { + continue; + } + for (const DrawQuad* quad : render_pass->quad_list) { if (quad->material == DrawQuad::SURFACE_CONTENT) { // Skip the quad if the transform is not invertible (i.e. it will not @@ -217,7 +225,8 @@ hit_test_region->flags = mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestChildSurface; hit_test_region->rect = surface_quad->rect; - hit_test_region->transform = target_to_quad_transform; + hit_test_region->transform = + target_to_quad_transform * transform_from_root_target; hit_test_region_list->regions.push_back(std::move(hit_test_region)); } }
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index ce6a321..fcf413b 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -374,21 +374,6 @@ MSVC_DISABLE_OPTIMIZE() MSVC_PUSH_DISABLE_WARNING(4748) -#if defined(OS_ANDROID) -NOINLINE void ResetThread_PROCESS_LAUNCHER( - std::unique_ptr<BrowserProcessSubThread> thread) { - volatile int inhibit_comdat = __LINE__; - ALLOW_UNUSED_LOCAL(inhibit_comdat); - thread.reset(); -} -#else // defined(OS_ANDROID) -NOINLINE void ResetThread_PROCESS_LAUNCHER() { - volatile int inhibit_comdat = __LINE__; - ALLOW_UNUSED_LOCAL(inhibit_comdat); - BrowserThreadImpl::StopRedirectionOfThreadID(BrowserThread::PROCESS_LAUNCHER); -} -#endif // defined(OS_ANDROID) - NOINLINE void ResetThread_IO(std::unique_ptr<BrowserProcessSubThread> thread) { volatile int inhibit_comdat = __LINE__; ALLOW_UNUSED_LOCAL(inhibit_comdat); @@ -1022,37 +1007,6 @@ *task_scheduler_init_params.get()); } - TRACE_EVENT_BEGIN1("startup", "BrowserMainLoop::CreateThreads:start", - "Thread", "BrowserThread::PROCESS_LAUNCHER"); - -#if defined(OS_ANDROID) - // Android specializes Launcher thread so it is accessible in java. - // Note Android never does clean shutdown, so shutdown use-after-free - // concerns are not a problem in practice. - base::MessageLoop* message_loop = android::LauncherThread::GetMessageLoop(); - DCHECK(message_loop); - // This BrowserThread will use this message loop instead of creating a new - // thread. Note that means this/ thread will not be joined on shutdown, and - // may cause use-after-free if anything tries to access objects deleted by - // AtExitManager, such as non-leaky LazyInstance. - process_launcher_thread_.reset(new BrowserProcessSubThread( - BrowserThread::PROCESS_LAUNCHER, message_loop)); -#else // defined(OS_ANDROID) - // This thread ID will be backed by a SingleThreadTaskRunner using - // |task_traits|. - // TODO(gab): WithBaseSyncPrimitives() is likely not required here. - base::TaskTraits task_traits = {base::MayBlock(), - base::WithBaseSyncPrimitives(), - base::TaskPriority::USER_BLOCKING, - base::TaskShutdownBehavior::BLOCK_SHUTDOWN}; - scoped_refptr<base::SingleThreadTaskRunner> redirection_task_runner = - base::CreateSingleThreadTaskRunnerWithTraits( - task_traits, base::SingleThreadTaskRunnerThreadMode::DEDICATED); - DCHECK(redirection_task_runner); - BrowserThreadImpl::RedirectThreadIDToTaskRunner( - BrowserThread::PROCESS_LAUNCHER, std::move(redirection_task_runner)); -#endif // defined(OS_ANDROID) - // |io_thread_| is created by |PostMainMessageLoopStart()|, but its // full initialization is deferred until this point because it requires // several dependencies we don't want to depend on so early in startup. @@ -1205,39 +1159,9 @@ { base::ThreadRestrictions::ScopedAllowWait allow_wait_for_join; - - // Must be size_t so we can subtract from it. - for (size_t thread_id = BrowserThread::ID_COUNT - 1; - thread_id >= (BrowserThread::UI + 1); --thread_id) { - // Find the thread object we want to stop. Looping over all valid - // BrowserThread IDs and DCHECKing on a missing case in the switch - // statement helps avoid a mismatch between this code and the - // BrowserThread::ID enumeration. - // - // The destruction order is the reverse order of occurrence in the - // BrowserThread::ID list. The rationale for the order is that he - // PROCESS_LAUNCHER thread must be stopped after IO in case the IO thread - // posted a task to terminate a process on the process launcher thread. - switch (thread_id) { - case BrowserThread::PROCESS_LAUNCHER: { - TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:LauncherThread"); -#if defined(OS_ANDROID) - ResetThread_PROCESS_LAUNCHER(std::move(process_launcher_thread_)); -#else // defined(OS_ANDROID) - ResetThread_PROCESS_LAUNCHER(); -#endif // defined(OS_ANDROID) - break; - } - case BrowserThread::IO: { - TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread"); - ResetThread_IO(std::move(io_thread_)); - break; - } - case BrowserThread::UI: - case BrowserThread::ID_COUNT: - NOTREACHED(); - break; - } + { + TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread"); + ResetThread_IO(std::move(io_thread_)); } {
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index 13a96b3..25bdb6e 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h
@@ -339,11 +339,7 @@ // Only the IO thread is a real thread by default, other BrowserThreads are // redirected to TaskScheduler under the hood. std::unique_ptr<BrowserProcessSubThread> io_thread_; -#if defined(OS_ANDROID) - // On Android, the PROCESS_LAUNCHER thread is handled by Java, - // |process_launcher_thread_| is merely a proxy to the real message loop. - std::unique_ptr<BrowserProcessSubThread> process_launcher_thread_; -#elif defined(OS_WIN) +#if defined(OS_WIN) // TaskScheduler doesn't support async I/O on Windows as CACHE thread is // the only user and this use case is going away in // https://codereview.chromium.org/2216583003/.
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc index 566b0f7..c78abe0 100644 --- a/content/browser/browser_thread_impl.cc +++ b/content/browser/browser_thread_impl.cc
@@ -32,7 +32,6 @@ // Friendly names for the well-known threads. static const char* const g_browser_thread_names[BrowserThread::ID_COUNT] = { "", // UI (name assembled in browser_main.cc). - "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER "Chrome_IOThread", // IO }; @@ -202,12 +201,6 @@ DCHECK(globals.task_runners[identifier_]->RunsTasksInCurrentSequence()); } #endif // DCHECK_IS_ON() - - if (identifier_ == BrowserThread::PROCESS_LAUNCHER) { - // Nesting and task observers are not allowed on redirected threads. - base::RunLoop::DisallowNestingOnCurrentThread(); - message_loop()->DisallowTaskObservers(); - } } // We disable optimizations for this block of functions so the compiler doesn't @@ -221,13 +214,6 @@ CHECK_GT(line_number, 0); } -NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun( - base::RunLoop* run_loop) { - volatile int line_number = __LINE__; - Thread::Run(run_loop); - CHECK_GT(line_number, 0); -} - NOINLINE void BrowserThreadImpl::IOThreadRun(base::RunLoop* run_loop) { volatile int line_number = __LINE__; Thread::Run(run_loop); @@ -254,8 +240,6 @@ switch (identifier_) { case BrowserThread::UI: return UIThreadRun(run_loop); - case BrowserThread::PROCESS_LAUNCHER: - return ProcessLauncherThreadRun(run_loop); case BrowserThread::IO: return IOThreadRun(run_loop); case BrowserThread::ID_COUNT:
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index 8da5fe2..c78c0766 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/process/launch.h" #include "build/build_config.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/common/result_codes.h" #include "content/public/common/sandboxed_process_launcher_delegate.h" @@ -62,8 +63,8 @@ const ChildProcessLauncherPriority& priority) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::Process to_pass = process_.process.Duplicate(); - BrowserThread::PostTask( - BrowserThread::PROCESS_LAUNCHER, FROM_HERE, + GetProcessLauncherTaskRunner()->PostTask( + FROM_HERE, base::BindOnce( &ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread, helper_, std::move(to_pass), priority));
diff --git a/content/browser/child_process_launcher_helper.cc b/content/browser/child_process_launcher_helper.cc index 7ee3df4..e924b12d 100644 --- a/content/browser/child_process_launcher_helper.cc +++ b/content/browser/child_process_launcher_helper.cc
@@ -6,18 +6,28 @@ #include "base/command_line.h" #include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" +#include "base/single_thread_task_runner.h" +#include "base/task_scheduler/post_task.h" +#include "base/task_scheduler/single_thread_task_runner_thread_mode.h" +#include "base/task_scheduler/task_traits.h" #include "content/browser/child_process_launcher.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/common/content_switches.h" #include "content/public/common/sandboxed_process_launcher_delegate.h" #include "mojo/edk/embedder/platform_channel_pair.h" +#if defined(OS_ANDROID) +#include "content/browser/android/launcher_thread.h" +#endif + namespace content { namespace internal { namespace { void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); // Log the launch time, separating out the first one (which will likely be // slower due to the rest of the browser initializing at the same time). static bool done_first_launch = false; @@ -85,14 +95,14 @@ mojo_client_handle_ = channel_pair.PassClientHandle(); } - BrowserThread::PostTask( - BrowserThread::PROCESS_LAUNCHER, FROM_HERE, + GetProcessLauncherTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&ChildProcessLauncherHelper::LaunchOnLauncherThread, this)); } void ChildProcessLauncherHelper::LaunchOnLauncherThread() { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); begin_launch_time_ = base::TimeTicks::Now(); @@ -167,18 +177,52 @@ // static void ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync( ChildProcessLauncherHelper::Process process) { - if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) { + if (CurrentlyOnProcessLauncherTaskRunner()) { ForceNormalProcessTerminationSync(std::move(process)); return; } // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! // So don't do this on the UI/IO threads. - BrowserThread::PostTask( - BrowserThread::PROCESS_LAUNCHER, FROM_HERE, + GetProcessLauncherTaskRunner()->PostTask( + FROM_HERE, base::BindOnce( &ChildProcessLauncherHelper::ForceNormalProcessTerminationSync, std::move(process))); } } // namespace internal + +// static +base::SingleThreadTaskRunner* GetProcessLauncherTaskRunner() { +#if defined(OS_ANDROID) + // Android specializes Launcher thread so it is accessible in java. + // Note Android never does clean shutdown, so shutdown use-after-free + // concerns are not a problem in practice. + // This process launcher thread will use the Java-side process-launching + // thread, instead of creating its own separate thread on C++ side. Note + // that means this thread will not be joined on shutdown, and may cause + // use-after-free if anything tries to access objects deleted by + // AtExitManager, such as non-leaky LazyInstance. + static base::NoDestructor<scoped_refptr<base::SingleThreadTaskRunner>> + launcher_task_runner( + android::LauncherThread::GetMessageLoop()->task_runner()); +#else // defined(OS_ANDROID) + constexpr base::TaskTraits task_traits = { + base::MayBlock(), base::WithBaseSyncPrimitives(), + base::TaskPriority::USER_BLOCKING, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}; + // TODO(wez): Investigates whether we could use SequencedTaskRunner on + // platforms other than Windows. http://crbug.com/820200. + static base::NoDestructor<scoped_refptr<base::SingleThreadTaskRunner>> + launcher_task_runner(base::CreateSingleThreadTaskRunnerWithTraits( + task_traits, base::SingleThreadTaskRunnerThreadMode::DEDICATED)); +#endif // defined(OS_ANDROID) + return (*launcher_task_runner).get(); +} + +// static +bool CurrentlyOnProcessLauncherTaskRunner() { + return GetProcessLauncherTaskRunner()->RunsTasksInCurrentSequence(); +} + } // namespace content
diff --git a/content/browser/child_process_launcher_helper_android.cc b/content/browser/child_process_launcher_helper_android.cc index 3867bf3..2c86dba 100644 --- a/content/browser/child_process_launcher_helper_android.cc +++ b/content/browser/child_process_launcher_helper_android.cc
@@ -15,6 +15,7 @@ #include "content/browser/posix_file_descriptor_info_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/content_descriptors.h" #include "content/public/common/content_switches.h" @@ -32,7 +33,7 @@ // Stops a child process based on the handle returned from StartChildProcess. void StopChildProcess(base::ProcessHandle handle) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); JNIEnv* env = AttachCurrentThread(); DCHECK(env); Java_ChildProcessLauncherHelper_stop(env, static_cast<jint>(handle)); @@ -64,7 +65,7 @@ std::unique_ptr<PosixFileDescriptorInfo> ChildProcessLauncherHelper::GetFilesToMap() { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); // Android WebView runs in single process, ensure that we never get here when // running in single process mode. @@ -162,15 +163,15 @@ // static bool ChildProcessLauncherHelper::TerminateProcess(const base::Process& process, int exit_code) { - BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, - base::Bind(&StopChildProcess, process.Handle())); + GetProcessLauncherTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&StopChildProcess, process.Handle())); return true; } // static void ChildProcessLauncherHelper::ForceNormalProcessTerminationSync( ChildProcessLauncherHelper::Process process) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); VLOG(1) << "ChromeProcess: Stopping process with handle " << process.process.Handle(); StopChildProcess(process.process.Handle()); @@ -211,7 +212,7 @@ JNIEnv*, const base::android::JavaParamRef<jobject>& obj, jint handle) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); scoped_refptr<ChildProcessLauncherHelper> ref(this); Release(); // Balances with LaunchProcessOnLauncherThread.
diff --git a/content/browser/child_process_launcher_helper_fuchsia.cc b/content/browser/child_process_launcher_helper_fuchsia.cc index 8be1b0e4..281f4609 100644 --- a/content/browser/child_process_launcher_helper_fuchsia.cc +++ b/content/browser/child_process_launcher_helper_fuchsia.cc
@@ -8,6 +8,7 @@ #include "base/process/launch.h" #include "content/browser/child_process_launcher.h" #include "content/common/sandbox_policy_fuchsia.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/common/sandboxed_process_launcher_delegate.h" #include "mojo/edk/embedder/platform_channel_pair.h" @@ -17,7 +18,7 @@ void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread( base::Process process, const ChildProcessLauncherPriority& priority) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); // TODO(fuchsia): Implement this. (crbug.com/707031) NOTIMPLEMENTED(); } @@ -64,14 +65,14 @@ std::unique_ptr<FileMappedForLaunch> ChildProcessLauncherHelper::GetFilesToMap() { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); return std::unique_ptr<FileMappedForLaunch>(); } bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread( const PosixFileDescriptorInfo& files_to_register, base::LaunchOptions* options) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); mojo::edk::PlatformChannelPair::PrepareToPassHandleToChildProcess( mojo_client_handle(), command_line(), &options->handles_to_transfer); @@ -87,7 +88,7 @@ std::unique_ptr<FileMappedForLaunch> files_to_register, bool* is_synchronous_launch, int* launch_result) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); DCHECK(mojo_client_handle().is_valid()); // TODO(750938): Implement sandboxed/isolated subprocess launching. @@ -99,7 +100,7 @@ void ChildProcessLauncherHelper::AfterLaunchOnLauncherThread( const ChildProcessLauncherHelper::Process& process, const base::LaunchOptions& options) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); if (process.process.IsValid()) { // |mojo_client_handle_| has already been transferred to the child process @@ -112,7 +113,7 @@ // static void ChildProcessLauncherHelper::ForceNormalProcessTerminationSync( ChildProcessLauncherHelper::Process process) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); process.process.Terminate(RESULT_CODE_NORMAL_EXIT, true); }
diff --git a/content/browser/child_process_launcher_helper_linux.cc b/content/browser/child_process_launcher_helper_linux.cc index 64957aa..ee4dd38 100644 --- a/content/browser/child_process_launcher_helper_linux.cc +++ b/content/browser/child_process_launcher_helper_linux.cc
@@ -11,6 +11,7 @@ #include "content/browser/sandbox_host_linux.h" #include "content/browser/zygote_host/zygote_communication_linux.h" #include "content/browser/zygote_host/zygote_host_impl_linux.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/browser/content_browser_client.h" #include "content/public/common/common_sandbox_support_linux.h" #include "content/public/common/content_client.h" @@ -36,7 +37,7 @@ std::unique_ptr<FileMappedForLaunch> ChildProcessLauncherHelper::GetFilesToMap() { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); return CreateDefaultPosixFilesToMap(child_process_id(), mojo_client_handle(), true /* include_service_required_files */, GetProcessType(), command_line()); @@ -154,7 +155,7 @@ void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread( base::Process process, const ChildProcessLauncherPriority& priority) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); if (process.CanBackgroundProcesses()) process.SetProcessBackgrounded(priority.background); }
diff --git a/content/browser/child_process_launcher_helper_mac.cc b/content/browser/child_process_launcher_helper_mac.cc index 3dd188d..ad6ff62 100644 --- a/content/browser/child_process_launcher_helper_mac.cc +++ b/content/browser/child_process_launcher_helper_mac.cc
@@ -13,6 +13,7 @@ #include "content/browser/mach_broker_mac.h" #include "content/browser/sandbox_parameters_mac.h" #include "content/grit/content_resources.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/browser/content_browser_client.h" #include "content/public/common/content_features.h" #include "content/public/common/content_paths.h" @@ -47,7 +48,7 @@ std::unique_ptr<PosixFileDescriptorInfo> ChildProcessLauncherHelper::GetFilesToMap() { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); return CreateDefaultPosixFilesToMap( child_process_id(), mojo_client_handle(), false /* include_service_required_files */, GetProcessType(), @@ -81,7 +82,6 @@ case service_manager::SANDBOX_TYPE_NACL_LOADER: case service_manager::SANDBOX_TYPE_PDF_COMPOSITOR: case service_manager::SANDBOX_TYPE_PROFILING: - case service_manager::SANDBOX_TYPE_GPU: v2_process = true; break; default: @@ -242,7 +242,7 @@ // static void ChildProcessLauncherHelper::ForceNormalProcessTerminationSync( ChildProcessLauncherHelper::Process process) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); // Client has gone away, so just kill the process. Using exit code 0 means // that UMA won't treat this as a crash. process.process.Terminate(RESULT_CODE_NORMAL_EXIT, false);
diff --git a/content/browser/child_process_launcher_helper_win.cc b/content/browser/child_process_launcher_helper_win.cc index bf9836e..ca73f60 100644 --- a/content/browser/child_process_launcher_helper_win.cc +++ b/content/browser/child_process_launcher_helper_win.cc
@@ -10,6 +10,7 @@ #include "base/win/win_util.h" #include "content/browser/child_process_launcher.h" #include "content/browser/child_process_launcher_helper.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/common/result_codes.h" #include "content/public/common/sandbox_init.h" #include "content/public/common/sandboxed_process_launcher_delegate.h" @@ -46,7 +47,7 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread( const FileMappedForLaunch& files_to_register, base::LaunchOptions* options) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); return true; } @@ -56,7 +57,7 @@ std::unique_ptr<FileMappedForLaunch> files_to_register, bool* is_synchronous_launch, int* launch_result) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); *is_synchronous_launch = true; if (delegate_->ShouldLaunchElevated()) { // When establishing a Mojo connection, the pipe path has already been added @@ -85,7 +86,7 @@ void ChildProcessLauncherHelper::AfterLaunchOnLauncherThread( const ChildProcessLauncherHelper::Process& process, const base::LaunchOptions& options) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); } base::TerminationStatus ChildProcessLauncherHelper::GetTerminationStatus( @@ -103,7 +104,7 @@ void ChildProcessLauncherHelper::ForceNormalProcessTerminationSync( ChildProcessLauncherHelper::Process process) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); // Client has gone away, so just kill the process. Using exit code 0 means // that UMA won't treat this as a crash. process.process.Terminate(RESULT_CODE_NORMAL_EXIT, false); @@ -112,7 +113,7 @@ void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread( base::Process process, const ChildProcessLauncherPriority& priority) { - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); + DCHECK(CurrentlyOnProcessLauncherTaskRunner()); if (process.CanBackgroundProcesses()) process.SetProcessBackgrounded(priority.background); }
diff --git a/content/browser/download/byte_stream_input_stream.cc b/content/browser/download/byte_stream_input_stream.cc index 3d53718..247821957 100644 --- a/content/browser/download/byte_stream_input_stream.cc +++ b/content/browser/download/byte_stream_input_stream.cc
@@ -56,9 +56,4 @@ return completion_status_; } -void ByteStreamInputStream::OnResponseCompleted( - download::DownloadInterruptReason status) { - completion_status_ = status; -} - } // namespace content
diff --git a/content/browser/download/byte_stream_input_stream.h b/content/browser/download/byte_stream_input_stream.h index 469839c..1deaeb4b 100644 --- a/content/browser/download/byte_stream_input_stream.h +++ b/content/browser/download/byte_stream_input_stream.h
@@ -27,7 +27,6 @@ download::InputStream::StreamState Read(scoped_refptr<net::IOBuffer>* data, size_t* length) override; download::DownloadInterruptReason GetCompletionStatus() override; - void OnResponseCompleted(download::DownloadInterruptReason status) override; private: // ByteStreamReader to read from.
diff --git a/content/browser/download/download_file_impl.cc b/content/browser/download/download_file_impl.cc index 896cff2..6dac814 100644 --- a/content/browser/download/download_file_impl.cc +++ b/content/browser/download/download_file_impl.cc
@@ -102,11 +102,6 @@ input_stream_->ClearDataReadyCallback(); } -void DownloadFileImpl::SourceStream::OnResponseCompleted( - download::DownloadInterruptReason reason) { - input_stream_->OnResponseCompleted(reason); -} - download::DownloadInterruptReason DownloadFileImpl::SourceStream::GetCompletionStatus() const { return input_stream_->GetCompletionStatus();
diff --git a/content/browser/download/download_file_impl.h b/content/browser/download/download_file_impl.h index 6b90a907..9f67af26 100644 --- a/content/browser/download/download_file_impl.h +++ b/content/browser/download/download_file_impl.h
@@ -95,9 +95,6 @@ void Initialize(); - // Called when response is completed. - void OnResponseCompleted(download::DownloadInterruptReason reason); - // Called after successfully writing a buffer to disk. void OnWriteBytesToDisk(int64_t bytes_write);
diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc index 8ae1ac9..0c5124568 100644 --- a/content/browser/download/download_file_unittest.cc +++ b/content/browser/download/download_file_unittest.cc
@@ -23,9 +23,8 @@ #include "components/download/public/common/download_create_info.h" #include "components/download/public/common/download_destination_observer.h" #include "components/download/public/common/download_interrupt_reasons.h" -#include "content/browser/byte_stream.h" -#include "content/browser/download/byte_stream_input_stream.h" #include "content/browser/download/download_file_impl.h" +#include "content/browser/download/mock_input_stream.h" #include "content/public/browser/download_manager.h" #include "content/public/test/mock_download_manager.h" #include "net/base/file_stream.h" @@ -70,18 +69,6 @@ return base::HexEncode(&hash_value.front(), hash_value.size()); } -class MockByteStreamReader : public ByteStreamReader { - public: - MockByteStreamReader() {} - ~MockByteStreamReader() {} - - // ByteStream functions - MOCK_METHOD2(Read, ByteStreamReader::StreamState( - scoped_refptr<net::IOBuffer>*, size_t*)); - MOCK_CONST_METHOD0(GetStatus, int()); - MOCK_METHOD1(RegisterCallback, void(const base::Closure&)); -}; - class MockDownloadDestinationObserver : public download::DownloadDestinationObserver { public: @@ -115,8 +102,6 @@ MOCK_METHOD2(CurrentUpdateStatus, void(int64_t, int64_t)); }; -MATCHER(IsNullCallback, "") { return (arg.is_null()); } - enum DownloadFileRenameMethodType { RENAME_AND_UNIQUIFY, RENAME_AND_ANNOTATE }; // This is a test DownloadFileImpl that has no retry delay and, on Posix, @@ -174,7 +159,7 @@ observer_factory_(observer_.get()), input_stream_(nullptr), additional_streams_( - std::vector<StrictMock<MockByteStreamReader>*>{nullptr, nullptr}), + std::vector<StrictMock<MockInputStream>*>{nullptr, nullptr}), bytes_(-1), bytes_per_sec_(-1) {} @@ -202,10 +187,13 @@ } // Mock calls to this function are forwarded here. - void RegisterCallback(const base::Closure& sink_callback) { + void RegisterCallback( + const mojo::SimpleWatcher::ReadyCallback& sink_callback) { sink_callback_ = sink_callback; } + void ClearCallback() { sink_callback_.Reset(); } + void SetInterruptReasonCallback(const base::Closure& closure, download::DownloadInterruptReason* reason_p, download::DownloadInterruptReason reason, @@ -227,11 +215,11 @@ // There can be only one. DCHECK(!download_file_.get()); - input_stream_ = new StrictMock<MockByteStreamReader>(); + input_stream_ = new StrictMock<MockInputStream>(); // TODO: Need to actually create a function that'll set the variables // based on the inputs from the callback. - EXPECT_CALL(*input_stream_, RegisterCallback(_)) + EXPECT_CALL(*input_stream_, RegisterDataReadyCallback(_)) .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback)) .RetiresOnSaturation(); @@ -242,12 +230,11 @@ download_file_.reset(new TestDownloadFileImpl( std::move(save_info), download_dir_.GetPath(), - std::make_unique<ByteStreamInputStream>( - std::unique_ptr<ByteStreamReader>(input_stream_)), + std::unique_ptr<MockInputStream>(input_stream_), download::DownloadItem::kInvalidId, observer_factory_.GetWeakPtr())); EXPECT_CALL(*input_stream_, Read(_, _)) - .WillOnce(Return(ByteStreamReader::STREAM_EMPTY)) + .WillOnce(Return(download::InputStream::EMPTY)) .RetiresOnSaturation(); base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this); @@ -285,20 +272,20 @@ // Don't actually trigger the callback or do verifications. void SetupDataAppend(const char** data_chunks, size_t num_chunks, - MockByteStreamReader* stream_reader, + MockInputStream* input_stream, ::testing::Sequence s, int64_t offset = -1) { - DCHECK(stream_reader); + DCHECK(input_stream); size_t current_pos = static_cast<size_t>(offset); for (size_t i = 0; i < num_chunks; i++) { const char *source_data = data_chunks[i]; size_t length = strlen(source_data); scoped_refptr<net::IOBuffer> data = new net::IOBuffer(length); memcpy(data->data(), source_data, length); - EXPECT_CALL(*stream_reader, Read(_, _)) + EXPECT_CALL(*input_stream, Read(_, _)) .InSequence(s) .WillOnce(DoAll(SetArgPointee<0>(data), SetArgPointee<1>(length), - Return(ByteStreamReader::STREAM_HAS_DATA))) + Return(download::InputStream::HAS_DATA))) .RetiresOnSaturation(); if (offset < 0) { @@ -329,24 +316,24 @@ SetupDataAppend(data_chunks, num_chunks, input_stream_, s1); EXPECT_CALL(*input_stream_, Read(_, _)) .InSequence(s1) - .WillOnce(Return(ByteStreamReader::STREAM_EMPTY)) + .WillOnce(Return(download::InputStream::EMPTY)) .RetiresOnSaturation(); - sink_callback_.Run(); + sink_callback_.Run(MOJO_RESULT_OK); VerifyStreamAndSize(); } void SetupFinishStream(download::DownloadInterruptReason interrupt_reason, - MockByteStreamReader* stream_reader, + MockInputStream* input_stream, ::testing::Sequence s) { - EXPECT_CALL(*stream_reader, Read(_, _)) + EXPECT_CALL(*input_stream, Read(_, _)) .InSequence(s) - .WillOnce(Return(ByteStreamReader::STREAM_COMPLETE)) + .WillOnce(Return(download::InputStream::COMPLETE)) .RetiresOnSaturation(); - EXPECT_CALL(*stream_reader, GetStatus()) + EXPECT_CALL(*input_stream, GetCompletionStatus()) .InSequence(s) .WillOnce(Return(interrupt_reason)) .RetiresOnSaturation(); - EXPECT_CALL(*stream_reader, RegisterCallback(_)).RetiresOnSaturation(); + EXPECT_CALL(*input_stream, ClearDataReadyCallback()).RetiresOnSaturation(); } void FinishStream(download::DownloadInterruptReason interrupt_reason, @@ -354,7 +341,7 @@ const std::string& expected_hash) { ::testing::Sequence s1; SetupFinishStream(interrupt_reason, input_stream_, s1); - sink_callback_.Run(); + sink_callback_.Run(MOJO_RESULT_OK); VerifyStreamAndSize(); if (check_observer) { EXPECT_CALL(*(observer_.get()), @@ -430,16 +417,16 @@ } // Prepare a byte stream to write to the file sink. - void PrepareStream(StrictMock<MockByteStreamReader>** stream, + void PrepareStream(StrictMock<MockInputStream>** stream, int64_t offset, bool create_stream, bool will_finish, const char** buffers, size_t num_buffer) { if (create_stream) - *stream = new StrictMock<MockByteStreamReader>(); + *stream = new StrictMock<MockInputStream>(); - // Expectation on MockByteStreamReader for MultipleStreams tests: + // Expectation on MockInputStream for MultipleStreams tests: // 1. RegisterCallback: Must called twice. One to set the callback, the // other to release the stream. // 2. Read: If filled with N buffer, called (N+1) times, where the last Read @@ -483,13 +470,13 @@ // Stream for sending data into the download file. // Owned by download_file_; will be alive for lifetime of download_file_. - StrictMock<MockByteStreamReader>* input_stream_; + StrictMock<MockInputStream>* input_stream_; // Additional streams to test multiple stream write. - std::vector<StrictMock<MockByteStreamReader>*> additional_streams_; + std::vector<StrictMock<MockInputStream>*> additional_streams_; // Sink callback data for stream. - base::Closure sink_callback_; + mojo::SimpleWatcher::ReadyCallback sink_callback_; base::ScopedTempDir download_dir_; @@ -729,7 +716,7 @@ ASSERT_TRUE(base::MakeFileUnwritable(target_dir)); // Expect nulling out of further processing. - EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback())); + EXPECT_CALL(*input_stream_, ClearDataReadyCallback()); ExpectPermissionError(InvokeSelectedRenameMethod(target_path, nullptr)); EXPECT_FALSE(base::PathExists(target_path_suffixed)); } @@ -890,7 +877,7 @@ SetupFinishStream(download::DOWNLOAD_INTERRUPT_REASON_NONE, input_stream_, s1); EXPECT_CALL(*(observer_.get()), MockDestinationCompleted(_, _)); - sink_callback_.Run(); + sink_callback_.Run(MOJO_RESULT_OK); VerifyStreamAndSize(); base::RunLoop().RunUntilIdle(); DestroyDownloadFile(0); @@ -922,7 +909,7 @@ EXPECT_CALL(*(observer_.get()), CurrentUpdateStatus(strlen(kTestData1) + strlen(kTestData2), _)); - sink_callback_.Run(); + sink_callback_.Run(MOJO_RESULT_OK); base::RunLoop().RunUntilIdle(); VerifyStreamAndSize(); DestroyDownloadFile(0); @@ -942,16 +929,15 @@ PrepareStream(&additional_streams_[0], stream_0_length, true, true, kTestData7, 2); - EXPECT_CALL(*additional_streams_[0], RegisterCallback(_)) + EXPECT_CALL(*additional_streams_[0], RegisterDataReadyCallback(_)) .RetiresOnSaturation(); EXPECT_CALL(*(observer_.get()), MockDestinationCompleted(_, _)); // Activate the streams. download_file_->AddInputStream( - std::make_unique<ByteStreamInputStream>( - std::unique_ptr<ByteStreamReader>(additional_streams_[0])), - stream_0_length, download::DownloadSaveInfo::kLengthFullContent); - sink_callback_.Run(); + std::unique_ptr<MockInputStream>(additional_streams_[0]), stream_0_length, + download::DownloadSaveInfo::kLengthFullContent); + sink_callback_.Run(MOJO_RESULT_OK); base::RunLoop().RunUntilIdle(); SourceStreamTestData stream_data_0(0, stream_0_length, true); @@ -984,26 +970,28 @@ PrepareStream(&additional_streams_[1], stream_0_length + stream_1_length, true, true, kTestData6, 2); - EXPECT_CALL(*additional_streams_[0], RegisterCallback(_)) - .Times(2) + EXPECT_CALL(*additional_streams_[0], RegisterDataReadyCallback(_)) + .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*additional_streams_[1], RegisterCallback(_)) + EXPECT_CALL(*additional_streams_[0], ClearDataReadyCallback()) + .Times(1) + .RetiresOnSaturation(); + + EXPECT_CALL(*additional_streams_[1], RegisterDataReadyCallback(_)) .RetiresOnSaturation(); EXPECT_CALL(*(observer_.get()), MockDestinationCompleted(_, _)); // Activate all the streams. download_file_->AddInputStream( - std::make_unique<ByteStreamInputStream>( - std::unique_ptr<ByteStreamReader>(additional_streams_[0])), - stream_0_length, stream_1_length); + std::unique_ptr<MockInputStream>(additional_streams_[0]), stream_0_length, + stream_1_length); download_file_->AddInputStream( - std::make_unique<ByteStreamInputStream>( - std::unique_ptr<ByteStreamReader>(additional_streams_[1])), + std::unique_ptr<MockInputStream>(additional_streams_[1]), stream_0_length + stream_1_length, download::DownloadSaveInfo::kLengthFullContent); - sink_callback_.Run(); + sink_callback_.Run(MOJO_RESULT_OK); base::RunLoop().RunUntilIdle(); SourceStreamTestData stream_data_0(0, stream_0_length, true); @@ -1034,17 +1022,16 @@ EXPECT_CALL(*(observer_.get()), MockDestinationCompleted(_, _)); - sink_callback_.Run(); + sink_callback_.Run(MOJO_RESULT_OK); base::RunLoop().RunUntilIdle(); // Add another stream, the file is already closed, so nothing should be // called. EXPECT_FALSE(download_file_->InProgress()); - additional_streams_[0] = new StrictMock<MockByteStreamReader>(); + additional_streams_[0] = new StrictMock<MockInputStream>(); download_file_->AddInputStream( - std::make_unique<ByteStreamInputStream>( - std::unique_ptr<ByteStreamReader>(additional_streams_[0])), + std::unique_ptr<MockInputStream>(additional_streams_[0]), stream_0_length - 1, download::DownloadSaveInfo::kLengthFullContent); base::RunLoop().RunUntilIdle(); @@ -1069,23 +1056,25 @@ EXPECT_CALL(*input_stream_, Read(_, _)) .InSequence(seq) - .WillOnce(Return(ByteStreamReader::STREAM_EMPTY)) + .WillOnce(Return(download::InputStream::EMPTY)) .RetiresOnSaturation(); - sink_callback_.Run(); + sink_callback_.Run(MOJO_RESULT_OK); base::RunLoop().RunUntilIdle(); - additional_streams_[0] = new StrictMock<MockByteStreamReader>(); - EXPECT_CALL(*additional_streams_[0], RegisterCallback(_)) + additional_streams_[0] = new StrictMock<MockInputStream>(); + EXPECT_CALL(*additional_streams_[0], RegisterDataReadyCallback(_)) .WillRepeatedly(Invoke(this, &DownloadFileTest::RegisterCallback)) .RetiresOnSaturation(); + EXPECT_CALL(*additional_streams_[0], ClearDataReadyCallback()) + .WillRepeatedly(Invoke(this, &DownloadFileTest::ClearCallback)) + .RetiresOnSaturation(); EXPECT_CALL(*additional_streams_[0], Read(_, _)) - .WillOnce(Return(ByteStreamReader::STREAM_EMPTY)) + .WillOnce(Return(download::InputStream::EMPTY)) .RetiresOnSaturation(); download_file_->AddInputStream( - std::make_unique<ByteStreamInputStream>( - std::unique_ptr<ByteStreamReader>(additional_streams_[0])), - 0, download::DownloadSaveInfo::kLengthFullContent); + std::unique_ptr<MockInputStream>(additional_streams_[0]), 0, + download::DownloadSaveInfo::kLengthFullContent); // The stream should get terminated and reset the callback. EXPECT_TRUE(sink_callback_.is_null());
diff --git a/content/browser/download/download_job.h b/content/browser/download/download_job.h index 376a757..bc92618 100644 --- a/content/browser/download/download_job.h +++ b/content/browser/download/download_job.h
@@ -10,7 +10,6 @@ #include "base/time/time.h" #include "components/download/public/common/download_interrupt_reasons.h" #include "components/download/public/common/download_request_handle_interface.h" -#include "content/browser/byte_stream.h" #include "content/browser/download/download_file.h" #include "content/common/content_export.h"
diff --git a/content/browser/download/mock_input_stream.cc b/content/browser/download/mock_input_stream.cc new file mode 100644 index 0000000..ad3eaa3 --- /dev/null +++ b/content/browser/download/mock_input_stream.cc
@@ -0,0 +1,13 @@ +// Copyright 2018 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/download/mock_input_stream.h" + +namespace content { + +MockInputStream::MockInputStream() = default; + +MockInputStream::~MockInputStream() = default; + +} // namespace content
diff --git a/content/browser/download/mock_input_stream.h b/content/browser/download/mock_input_stream.h new file mode 100644 index 0000000..fb0743d9 --- /dev/null +++ b/content/browser/download/mock_input_stream.h
@@ -0,0 +1,31 @@ +// Copyright 2018 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_DOWNLOAD_MOCK_INPUT_STREAM_H_ +#define CONTENT_BROWSER_DOWNLOAD_MOCK_INPUT_STREAM_H_ + +#include "components/download/public/common/input_stream.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace content { + +class MockInputStream : public download::InputStream { + public: + MockInputStream(); + ~MockInputStream() override; + + // download::InputStream functions + MOCK_METHOD0(IsEmpty, bool()); + MOCK_METHOD1(RegisterDataReadyCallback, + void(const mojo::SimpleWatcher::ReadyCallback&)); + MOCK_METHOD0(ClearDataReadyCallback, void()); + MOCK_METHOD2(Read, + download::InputStream::StreamState(scoped_refptr<net::IOBuffer>*, + size_t*)); + MOCK_METHOD0(GetCompletionStatus, download::DownloadInterruptReason()); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_DOWNLOAD_MOCK_INPUT_STREAM_H_
diff --git a/content/browser/download/parallel_download_job_unittest.cc b/content/browser/download/parallel_download_job_unittest.cc index a52a5d1c..2a50005 100644 --- a/content/browser/download/parallel_download_job_unittest.cc +++ b/content/browser/download/parallel_download_job_unittest.cc
@@ -13,10 +13,10 @@ #include "base/test/scoped_task_environment.h" #include "components/download/public/common/download_destination_observer.h" #include "components/download/public/common/download_task_runner.h" -#include "content/browser/download/byte_stream_input_stream.h" #include "content/browser/download/download_file_impl.h" #include "content/browser/download/download_item_impl_delegate.h" #include "content/browser/download/mock_download_item_impl.h" +#include "content/browser/download/mock_input_stream.h" #include "content/browser/download/parallel_download_utils.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gmock/include/gmock/gmock.h" @@ -57,15 +57,6 @@ MOCK_METHOD2(CurrentUpdateStatus, void(int64_t, int64_t)); }; -class MockByteStreamReader : public ByteStreamReader { - public: - MOCK_METHOD2(Read, - ByteStreamReader::StreamState(scoped_refptr<net::IOBuffer>*, - size_t*)); - MOCK_CONST_METHOD0(GetStatus, int()); - MOCK_METHOD1(RegisterCallback, void(const base::Closure&)); -}; - } // namespace class ParallelDownloadJobForTest : public ParallelDownloadJob { @@ -182,9 +173,7 @@ std::make_unique<download::DownloadCreateInfo>(); create_info->request_handle = std::move(request_handle); delegate->OnUrlDownloadStarted( - std::move(create_info), - std::make_unique<ByteStreamInputStream>( - std::make_unique<MockByteStreamReader>()), + std::move(create_info), std::make_unique<MockInputStream>(), download::DownloadUrlParameters::OnStartedCallback()); } @@ -486,16 +475,14 @@ // Test that parallel request is not created until download file is initialized. TEST_F(ParallelDownloadJobTest, ParallelRequestNotCreatedUntilFileInitialized) { auto save_info = std::make_unique<download::DownloadSaveInfo>(); - StrictMock<MockByteStreamReader>* input_stream = - new StrictMock<MockByteStreamReader>(); + StrictMock<MockInputStream>* input_stream = new StrictMock<MockInputStream>(); auto observer = std::make_unique<StrictMock<MockDownloadDestinationObserver>>(); base::WeakPtrFactory<download::DownloadDestinationObserver> observer_factory( observer.get()); auto download_file = std::make_unique<DownloadFileImpl>( std::move(save_info), base::FilePath(), - std::make_unique<ByteStreamInputStream>( - std::unique_ptr<ByteStreamReader>(input_stream)), + std::unique_ptr<MockInputStream>(input_stream), download::DownloadItem::kInvalidId, observer_factory.GetWeakPtr()); CreateParallelJob(0, 100, download::DownloadItem::ReceivedSlices(), 2, 0, 0); job_->Start(download_file.get(), @@ -504,7 +491,7 @@ download::DownloadItem::ReceivedSlices()); EXPECT_FALSE(file_initialized_); EXPECT_EQ(0u, job_->workers().size()); - EXPECT_CALL(*input_stream, RegisterCallback(_)); + EXPECT_CALL(*input_stream, RegisterDataReadyCallback(_)); EXPECT_CALL(*input_stream, Read(_, _)); EXPECT_CALL(*(observer.get()), DestinationUpdate(_, _, _)); task_environment_.RunUntilIdle();
diff --git a/content/browser/download/parallel_download_utils_unittest.cc b/content/browser/download/parallel_download_utils_unittest.cc index 53ac459d..8589dbda 100644 --- a/content/browser/download/parallel_download_utils_unittest.cc +++ b/content/browser/download/parallel_download_utils_unittest.cc
@@ -11,47 +11,44 @@ #include "base/test/scoped_feature_list.h" #include "components/download/public/common/download_features.h" #include "components/download/public/common/download_save_info.h" -#include "content/browser/byte_stream.h" -#include "content/browser/download/byte_stream_input_stream.h" +#include "content/browser/download/mock_input_stream.h" #include "content/public/browser/download_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using ::testing::Return; +using ::testing::StrictMock; + namespace content { namespace { const int kErrorStreamOffset = 100; -class MockByteStreamReader : public ByteStreamReader { - public: - MockByteStreamReader() {} - ~MockByteStreamReader() override {} - - // ByteStream functions - MOCK_METHOD2(Read, - ByteStreamReader::StreamState(scoped_refptr<net::IOBuffer>*, - size_t*)); - MOCK_CONST_METHOD0(GetStatus, int()); - MOCK_METHOD1(RegisterCallback, void(const base::Closure&)); -}; - -// Creates a source stream to test. -std::unique_ptr<DownloadFileImpl::SourceStream> CreateSourceStream( - int64_t offset, - int64_t length) { - auto input_stream = std::make_unique<ByteStreamInputStream>( - std::make_unique<MockByteStreamReader>()); - return std::make_unique<DownloadFileImpl::SourceStream>( - offset, length, std::move(input_stream)); -} - } // namespace class ParallelDownloadUtilsTest : public testing::Test {}; class ParallelDownloadUtilsRecoverErrorTest - : public ::testing::TestWithParam<int64_t> {}; + : public ::testing::TestWithParam<int64_t> { + public: + ParallelDownloadUtilsRecoverErrorTest() : input_stream_(nullptr) {} + + // Creates a source stream to test. + std::unique_ptr<DownloadFileImpl::SourceStream> CreateSourceStream( + int64_t offset, + int64_t length) { + input_stream_ = new StrictMock<MockInputStream>(); + EXPECT_CALL(*input_stream_, GetCompletionStatus()) + .WillRepeatedly(Return(download::DOWNLOAD_INTERRUPT_REASON_NONE)); + return std::make_unique<DownloadFileImpl::SourceStream>( + offset, length, std::unique_ptr<MockInputStream>(input_stream_)); + } + + protected: + // Stream for sending data into the SourceStream. + StrictMock<MockInputStream>* input_stream_; +}; TEST_F(ParallelDownloadUtilsTest, FindSlicesToDownload) { std::vector<download::DownloadItem::ReceivedSlice> downloaded_slices; @@ -265,6 +262,7 @@ RecoverErrorForHalfOpenErrorStream) { // Create a stream that will work on byte range "100-". const int kErrorStreamOffset = 100; + auto error_stream = CreateSourceStream( kErrorStreamOffset, download::DownloadSaveInfo::kLengthFullContent); error_stream->set_finished(true); @@ -287,8 +285,9 @@ // Half open finished preceding stream with error, should be treated as // failed. - preceding_stream->OnResponseCompleted( - download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE); + EXPECT_CALL(*input_stream_, GetCompletionStatus()) + .WillRepeatedly( + Return(download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE)); EXPECT_FALSE(CanRecoverFromError(error_stream.get(), preceding_stream.get())); // Even if it has written some data. @@ -308,8 +307,9 @@ // Inject an error results in failure, even if data written exceeds the first // byte of error stream. - preceding_stream->OnResponseCompleted( - download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE); + EXPECT_CALL(*input_stream_, GetCompletionStatus()) + .WillRepeatedly( + Return(download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE)); preceding_stream->OnWriteBytesToDisk(1000u); EXPECT_FALSE(CanRecoverFromError(error_stream.get(), preceding_stream.get())); @@ -383,8 +383,9 @@ // Even if inject an error, since data written has cover the upper bound of // the error stream, it should succeed. - preceding_stream->OnResponseCompleted( - download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE); + EXPECT_CALL(*input_stream_, GetCompletionStatus()) + .WillRepeatedly( + Return(download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE)); EXPECT_TRUE(CanRecoverFromError(error_stream.get(), preceding_stream.get())); // Preceding stream that never download data won't recover the error stream.
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc index 0df805d1..eae2d0c 100644 --- a/content/browser/isolated_origin_browsertest.cc +++ b/content/browser/isolated_origin_browsertest.cc
@@ -1174,4 +1174,52 @@ EXPECT_NE(subframe1->GetSiteInstance(), subframe2->GetSiteInstance()); } +// Ensure that --disable-site-isolation-trials disables field trials. +class IsolatedOriginTrialOverrideTest : public IsolatedOriginFieldTrialTest { + public: + IsolatedOriginTrialOverrideTest() {} + + ~IsolatedOriginTrialOverrideTest() override {} + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch(switches::kDisableSiteIsolationTrials); + } + + private: + DISALLOW_COPY_AND_ASSIGN(IsolatedOriginTrialOverrideTest); +}; + +IN_PROC_BROWSER_TEST_F(IsolatedOriginTrialOverrideTest, Test) { + if (AreAllSitesIsolatedForTesting()) + return; + auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); + EXPECT_FALSE(policy->IsIsolatedOrigin( + url::Origin::Create(GURL("https://field.trial.com/")))); + EXPECT_FALSE( + policy->IsIsolatedOrigin(url::Origin::Create(GURL("https://bar.com/")))); +} + +// Ensure that --disable-site-isolation-trials does not override the flag. +class IsolatedOriginNoFlagOverrideTest : public IsolatedOriginTest { + public: + IsolatedOriginNoFlagOverrideTest() {} + + ~IsolatedOriginNoFlagOverrideTest() override {} + + void SetUpCommandLine(base::CommandLine* command_line) override { + IsolatedOriginTest::SetUpCommandLine(command_line); + command_line->AppendSwitch(switches::kDisableSiteIsolationTrials); + } + + private: + DISALLOW_COPY_AND_ASSIGN(IsolatedOriginNoFlagOverrideTest); +}; + +IN_PROC_BROWSER_TEST_F(IsolatedOriginNoFlagOverrideTest, Test) { + GURL isolated_url( + embedded_test_server()->GetURL("isolated.foo.com", "/title2.html")); + auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); + EXPECT_TRUE(policy->IsIsolatedOrigin(url::Origin::Create(isolated_url))); +} + } // namespace content
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc index 19531ae..fbb803a 100644 --- a/content/browser/renderer_host/render_process_host_browsertest.cc +++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -11,6 +11,7 @@ #include "build/build_config.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/public/browser/child_process_launcher_utils.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host_observer.h" @@ -356,8 +357,8 @@ base::WaitableEvent launcher_thread_done( base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); - BrowserThread::PostTask( - BrowserThread::PROCESS_LAUNCHER, FROM_HERE, + GetProcessLauncherTaskRunner()->PostTask( + FROM_HERE, base::BindOnce([](base::WaitableEvent* done) { done->Signal(); }, base::Unretained(&launcher_thread_done))); ASSERT_TRUE(launcher_thread_done.TimedWait(TestTimeouts::action_timeout()));
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index f7dfced4..2e9574b 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/unguessable_token.h" #include "build/build_config.h" +#include "components/viz/host/host_frame_sink_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface_hittest.h" #include "content/browser/accessibility/browser_accessibility_manager.h" @@ -169,6 +170,15 @@ std::move(callback).Run(SkBitmap()); } +viz::mojom::FrameSinkVideoCapturerPtr +RenderWidgetHostViewBase::CreateVideoCapturer() { + viz::mojom::FrameSinkVideoCapturerPtr video_capturer; + GetHostFrameSinkManager()->CreateVideoCapturer( + mojo::MakeRequest(&video_capturer)); + video_capturer->ChangeTarget(GetFrameSinkId()); + return video_capturer; +} + base::string16 RenderWidgetHostViewBase::GetSelectedText() { if (!GetTextInputManager()) return base::string16();
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index e40361b6..543ce74f 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -119,6 +119,7 @@ const gfx::Rect& src_rect, const gfx::Size& output_size, base::OnceCallback<void(const SkBitmap&)> callback) override; + viz::mojom::FrameSinkVideoCapturerPtr CreateVideoCapturer() override; void FocusedNodeTouched(bool editable) override; void GetScreenInfo(ScreenInfo* screen_info) const override; float GetDeviceScaleFactor() const final;
diff --git a/content/browser/service_worker/service_worker_handle_unittest.cc b/content/browser/service_worker/service_worker_handle_unittest.cc index e90991b..884959f 100644 --- a/content/browser/service_worker/service_worker_handle_unittest.cc +++ b/content/browser/service_worker/service_worker_handle_unittest.cc
@@ -325,7 +325,9 @@ EXPECT_EQ(remaining_time, version_->remaining_timeout()); } -TEST_F(ServiceWorkerHandleTest, DispatchExtendableMessageEvent_FromClient) { +// Constantly fails on Android/Linux CFI builder. http://crbug.com/820620 +TEST_F(ServiceWorkerHandleTest, + DISABLED_DispatchExtendableMessageEvent_FromClient) { const int64_t kProviderId = 99; const GURL pattern("https://www.example.com/"); const GURL script_url("https://www.example.com/service_worker.js"); @@ -381,7 +383,8 @@ events[0]->source_info_for_client->client_type); } -TEST_F(ServiceWorkerHandleTest, DispatchExtendableMessageEvent_Fail) { +// Constantly fails on Android/Linux CFI builder. http://crbug.com/820620 +TEST_F(ServiceWorkerHandleTest, DISABLED_DispatchExtendableMessageEvent_Fail) { const int64_t kProviderId = 99; const GURL pattern("https://www.example.com/"); const GURL script_url("https://www.example.com/service_worker.js");
diff --git a/content/browser/site_isolation_policy.cc b/content/browser/site_isolation_policy.cc index 509c394..6f5cd31 100644 --- a/content/browser/site_isolation_policy.cc +++ b/content/browser/site_isolation_policy.cc
@@ -28,7 +28,9 @@ bool SiteIsolationPolicy::UseDedicatedProcessesForAllSites() { return base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kSitePerProcess) || - base::FeatureList::IsEnabled(features::kSitePerProcess); + (base::FeatureList::IsEnabled(features::kSitePerProcess) && + !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableSiteIsolationTrials)); } // static @@ -59,7 +61,9 @@ bool SiteIsolationPolicy::AreIsolatedOriginsEnabled() { return base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kIsolateOrigins) || - base::FeatureList::IsEnabled(features::kIsolateOrigins); + (base::FeatureList::IsEnabled(features::kIsolateOrigins) && + !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableSiteIsolationTrials)); } // static @@ -76,7 +80,9 @@ return cmdline_origins; } - if (base::FeatureList::IsEnabled(features::kIsolateOrigins)) { + if (base::FeatureList::IsEnabled(features::kIsolateOrigins) && + !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableSiteIsolationTrials)) { std::string field_trial_arg = base::GetFieldTrialParamValueByFeature( features::kIsolateOrigins, features::kIsolateOriginsFieldTrialParamName);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index b1b10828..04ca34e 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1677,6 +1677,10 @@ observer.NavigationStopped(); } +void WebContentsImpl::FreezePage() { + SendPageMessage(new PageMsg_FreezePage(MSG_ROUTING_NONE)); +} + WebContents* WebContentsImpl::Clone() { // We use our current SiteInstance since the cloned entry will use it anyway. // We pass our own opener so that the cloned page can access it if it was set
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 4cb3b5df..d0da3b51 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -374,6 +374,7 @@ RenderFrameHost* outer_contents_frame) override; void DidChangeVisibleSecurityState() override; void Stop() override; + void FreezePage() override; WebContents* Clone() override; void ReloadFocusedFrame(bool bypass_cache) override; void Undo() override;
diff --git a/content/common/page_messages.h b/content/common/page_messages.h index 423a9f1..ca7f0b6e 100644 --- a/content/common/page_messages.h +++ b/content/common/page_messages.h
@@ -50,6 +50,10 @@ IPC_MESSAGE_ROUTED1(PageMsg_UpdateScreenInfo, content::ScreenInfo /* screen_info */) +// Sent to all renderers, instructing them to freeze all frames that belongs to +// this page. +IPC_MESSAGE_ROUTED0(PageMsg_FreezePage) + // ----------------------------------------------------------------------------- // Messages sent from the renderer to the browser.
diff --git a/content/public/android/java/src/org/chromium/content/browser/LauncherThread.java b/content/public/android/java/src/org/chromium/content/browser/LauncherThread.java index e3e6ffd91..dd98f13 100644 --- a/content/public/android/java/src/org/chromium/content/browser/LauncherThread.java +++ b/content/public/android/java/src/org/chromium/content/browser/LauncherThread.java
@@ -12,7 +12,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; -/** This is BrowserThread::PROCESS_LAUNCHER. It is available before native library is loaded. */ +/** This is the process launcher thread. It is available before native library is loaded. */ @JNINamespace("content::android") public final class LauncherThread { private static final JavaHandlerThread sThread =
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index c5defd4..cd6941d 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -84,6 +84,7 @@ "cdm_registry.h", "certificate_request_result_type.h", "child_process_data.h", + "child_process_launcher_utils.h", "child_process_security_policy.h", "client_certificate_delegate.h", "color_chooser.h",
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h index a4bdf19..a9d6b08 100644 --- a/content/public/browser/browser_thread.h +++ b/content/public/browser/browser_thread.h
@@ -67,9 +67,6 @@ // The main thread in the browser. UI, - // Used to launch and terminate Chrome processes. - PROCESS_LAUNCHER, - // This is the thread that processes non-blocking IO, i.e. IPC and network. // Blocking IO should happen in TaskScheduler. IO,
diff --git a/content/public/browser/child_process_launcher_utils.h b/content/public/browser/child_process_launcher_utils.h new file mode 100644 index 0000000..1b9d4545 --- /dev/null +++ b/content/public/browser/child_process_launcher_utils.h
@@ -0,0 +1,24 @@ +// Copyright 2018 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_PUBLIC_BROWSER_CHILD_PROCESS_LAUNCHER_UTILS_H_ +#define CONTENT_PUBLIC_BROWSER_CHILD_PROCESS_LAUNCHER_UTILS_H_ + +#include "content/common/content_export.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace content { + +// The caller must take a reference to the returned TaskRunner pointer if it +// wants to use the pointer directly. +CONTENT_EXPORT base::SingleThreadTaskRunner* GetProcessLauncherTaskRunner(); + +CONTENT_EXPORT bool CurrentlyOnProcessLauncherTaskRunner(); + +} // namespace content + +#endif // CONTENT_PUBLIC_BROWSER_CHILD_PROCESS_LAUNCHER_UTILES_H_
diff --git a/content/public/browser/render_widget_host_view.h b/content/public/browser/render_widget_host_view.h index ffcf44f..f2edd26 100644 --- a/content/public/browser/render_widget_host_view.h +++ b/content/public/browser/render_widget_host_view.h
@@ -22,10 +22,22 @@ class Size; } +namespace mojo { +template <class T> +class InterfacePtr; +} + namespace ui { class TextInputClient; } +namespace viz { +namespace mojom { +class FrameSinkVideoCapturer; +using FrameSinkVideoCapturerPtr = mojo::InterfacePtr<FrameSinkVideoCapturer>; +} // namespace mojom +} // namespace viz + namespace content { class RenderWidgetHost; @@ -167,7 +179,7 @@ // Copies the given subset of the view's surface, optionally scales it, and // returns the result as a bitmap via the provided callback. This is meant for // one-off snapshots. For continuous video capture of the surface, please use - // viz::FrameSinkManager::CreateVideoCapturer() instead. + // CreateVideoCapturer() instead. // // |src_rect| is either the subset of the view's surface, in view coordinates, // or empty to indicate that all of it should be copied. This is NOT the same @@ -190,6 +202,12 @@ const gfx::Size& output_size, base::OnceCallback<void(const SkBitmap&)> callback) = 0; + // Creates a video capturer, which will allow the caller to receive a stream + // of media::VideoFrames captured from this view. The capturer is configured + // to target this view, so there is no need to call ChangeTarget() before + // Start(). See viz.mojom.FrameSinkVideoCapturer for documentation. + virtual viz::mojom::FrameSinkVideoCapturerPtr CreateVideoCapturer() = 0; + // Notification that a node was touched. // The |editable| parameter indicates if the node is editable, for e.g. // an input field, etc.
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index 9c6643a..b74438d7 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -480,6 +480,9 @@ // Stop any pending navigation. virtual void Stop() = 0; + // Freeze the current page. + virtual void FreezePage() = 0; + // Creates a new WebContents with the same state as this one. The returned // heap-allocated pointer is owned by the caller. virtual WebContents* Clone() = 0;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index fcfaebc..63bcb877 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -247,10 +247,6 @@ const base::Feature kPassiveEventListenersDueToFling{ "PassiveEventListenersDueToFling", base::FEATURE_ENABLED_BY_DEFAULT}; -// Whether PDF files should be rendered in diffent processes based on origin. -const base::Feature kPdfIsolation = {"PdfIsolation", - base::FEATURE_DISABLED_BY_DEFAULT}; - // If Pepper 3D Image Chromium is allowed, this feature controls whether it is // enabled. const base::Feature kPepper3DImageChromium {
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index a36d645..5f9db31 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -66,7 +66,6 @@ CONTENT_EXPORT extern const base::Feature kOriginTrials; CONTENT_EXPORT extern const base::Feature kPassiveDocumentEventListeners; CONTENT_EXPORT extern const base::Feature kPassiveEventListenersDueToFling; -CONTENT_EXPORT extern const base::Feature kPdfIsolation; CONTENT_EXPORT extern const base::Feature kPepper3DImageChromium; CONTENT_EXPORT extern const base::Feature kPurgeAndSuspend; CONTENT_EXPORT extern const base::Feature kPWAFullCodeCache;
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 30188c1..4f1dc51 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -772,6 +772,9 @@ // process consolidation, not isolation). You probably want this one. const char kSitePerProcess[] = "site-per-process"; +// Disables enabling site isolation (i.e., --site-per-process) via field trial. +const char kDisableSiteIsolationTrials[] = "disable-site-isolation-trials"; + // Specifies if the browser should start in fullscreen mode, like if the user // had pressed F11 right after startup. const char kStartFullscreen[] = "start-fullscreen";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 855329f..b48a297 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -214,6 +214,7 @@ extern const char kShowPaintRects[]; CONTENT_EXPORT extern const char kSingleProcess[]; CONTENT_EXPORT extern const char kSitePerProcess[]; +CONTENT_EXPORT extern const char kDisableSiteIsolationTrials[]; CONTENT_EXPORT extern const char kStartFullscreen[]; CONTENT_EXPORT extern const char kStatsCollectionController[]; CONTENT_EXPORT extern const char kTestType[];
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc index 4566c564..4569941 100644 --- a/content/public/renderer/content_renderer_client.cc +++ b/content/public/renderer/content_renderer_client.cc
@@ -173,11 +173,6 @@ return false; } -bool ContentRendererClient::IsOriginIsolatedPepperPlugin( - const base::FilePath& plugin_path) { - return false; -} - bool ContentRendererClient::AllowPepperMediaStreamAPI(const GURL& url) { return false; }
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h index f663393a..c5da6a40 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h
@@ -13,7 +13,6 @@ #include <vector> #include "base/callback_forward.h" -#include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "base/strings/string16.h" #include "base/task_scheduler/task_scheduler.h" @@ -262,12 +261,6 @@ // startup steps). virtual bool IsExternalPepperPlugin(const std::string& module_name); - // Returns true if the given Pepper plugin should process content from - // different origins in different PPAPI processes. This is generally a - // worthwhile precaution when the plugin provides an active scripting - // language. - virtual bool IsOriginIsolatedPepperPlugin(const base::FilePath& plugin_path); - // Returns true if the page at |url| can use Pepper MediaStream APIs. virtual bool AllowPepperMediaStreamAPI(const GURL& url);
diff --git a/content/public/test/test_browser_thread_bundle.cc b/content/public/test/test_browser_thread_bundle.cc index 05b943db..8dfb2e4 100644 --- a/content/public/test/test_browser_thread_bundle.cc +++ b/content/public/test/test_browser_thread_bundle.cc
@@ -39,8 +39,6 @@ base::RunLoop().RunUntilIdle(); io_thread_->Stop(); base::RunLoop().RunUntilIdle(); - process_launcher_thread_->Stop(); - base::RunLoop().RunUntilIdle(); ui_thread_->Stop(); base::RunLoop().RunUntilIdle(); @@ -116,9 +114,6 @@ void TestBrowserThreadBundle::CreateBrowserThreads() { CHECK(!threads_created_); - process_launcher_thread_ = std::make_unique<TestBrowserThread>( - BrowserThread::PROCESS_LAUNCHER, base::MessageLoop::current()); - if (options_ & REAL_IO_THREAD) { io_thread_ = std::make_unique<TestBrowserThread>(BrowserThread::IO); io_thread_->StartIOThread();
diff --git a/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc index d88e5fe..ad87e7a 100644 --- a/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc +++ b/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc
@@ -40,7 +40,7 @@ return it; }; -MockMediaStream::MockMediaStream(const std::string& label) : label_(label) {} +MockMediaStream::MockMediaStream(const std::string& id) : id_(id) {} bool MockMediaStream::AddTrack(AudioTrackInterface* track) { audio_track_vector_.push_back(track); @@ -74,8 +74,8 @@ return true; } -std::string MockMediaStream::label() const { - return label_; +std::string MockMediaStream::id() const { + return id_; } AudioTrackVector MockMediaStream::GetAudioTracks() {
diff --git a/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h b/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h index 7a59178..0d1724d 100644 --- a/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h +++ b/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h
@@ -86,13 +86,13 @@ class MockMediaStream : public webrtc::MediaStreamInterface { public: - explicit MockMediaStream(const std::string& label); + explicit MockMediaStream(const std::string& id); bool AddTrack(webrtc::AudioTrackInterface* track) override; bool AddTrack(webrtc::VideoTrackInterface* track) override; bool RemoveTrack(webrtc::AudioTrackInterface* track) override; bool RemoveTrack(webrtc::VideoTrackInterface* track) override; - std::string label() const override; + std::string id() const override; webrtc::AudioTrackVector GetAudioTracks() override; webrtc::VideoTrackVector GetVideoTracks() override; rtc::scoped_refptr<webrtc::AudioTrackInterface> FindAudioTrack( @@ -108,7 +108,7 @@ private: void NotifyObservers(); - std::string label_; + std::string id_; webrtc::AudioTrackVector audio_track_vector_; webrtc::VideoTrackVector video_track_vector_;
diff --git a/content/renderer/media/webrtc/mock_peer_connection_impl.cc b/content/renderer/media/webrtc/mock_peer_connection_impl.cc index 87fb40a..ab80a8a0 100644 --- a/content/renderer/media/webrtc/mock_peer_connection_impl.cc +++ b/content/renderer/media/webrtc/mock_peer_connection_impl.cc
@@ -31,9 +31,9 @@ public: size_t count() override { return streams_.size(); } MediaStreamInterface* at(size_t index) override { return streams_[index]; } - MediaStreamInterface* find(const std::string& label) override { + MediaStreamInterface* find(const std::string& id) override { for (size_t i = 0; i < streams_.size(); ++i) { - if (streams_[i]->label() == label) + if (streams_[i]->id() == id) return streams_[i]; } return nullptr; @@ -277,8 +277,8 @@ return nullptr; } for (auto* stream : streams) { - if (!local_streams_->find(stream->label())) { - stream_label_ = stream->label(); + if (!local_streams_->find(stream->id())) { + stream_label_ = stream->id(); local_streams_->AddStream(stream); } }
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index f87af36..49db083 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -2854,11 +2854,8 @@ this, delegate->GetWeakPtr()); } + // TODO(tsepez): extract origin to lock from WebPluginParams url. base::Optional<url::Origin> origin_lock; - if (base::FeatureList::IsEnabled(features::kPdfIsolation) && - GetContentClient()->renderer()->IsOriginIsolatedPepperPlugin(info.path)) { - origin_lock = url::Origin::Create(GURL(params.url)); - } bool pepper_plugin_was_registered = false; scoped_refptr<PluginModule> pepper_module(PluginModule::Create(
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 02d0c37..55120e6 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1133,6 +1133,7 @@ OnSetHistoryOffsetAndLength) IPC_MESSAGE_HANDLER(PageMsg_AudioStateChanged, OnAudioStateChanged) IPC_MESSAGE_HANDLER(PageMsg_UpdateScreenInfo, OnUpdateScreenInfo) + IPC_MESSAGE_HANDLER(PageMsg_FreezePage, OnFreezePage) #if defined(OS_MACOSX) IPC_MESSAGE_HANDLER(ViewMsg_GetRenderedText, @@ -2187,6 +2188,12 @@ screen_info_ = screen_info; } +void RenderViewImpl::OnFreezePage() { + if (webview()) { + webview()->FreezePage(); + } +} + GURL RenderViewImpl::GetURLForGraphicsContext3D() { DCHECK(webview()); WebFrame* main_frame = webview()->MainFrame();
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 0199552..0e1fb3c 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -552,6 +552,7 @@ void OnPageWasHidden(); void OnPageWasShown(); void OnUpdateScreenInfo(const ScreenInfo& screen_info); + void OnFreezePage(); // Adding a new message handler? Please add it in alphabetical order above // and put it in the same position in the .cc file.
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 1708eeb0..45360f9 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -50,6 +50,8 @@ "../browser/download/mock_download_item_impl.h", "../browser/download/mock_download_job.cc", "../browser/download/mock_download_job.h", + "../browser/download/mock_input_stream.cc", + "../browser/download/mock_input_stream.h", "../browser/media/session/mock_media_session_observer.cc", "../browser/media/session/mock_media_session_observer.h", "../browser/service_worker/embedded_worker_test_helper.cc",
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index eec4730..3db0800 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -243,6 +243,8 @@ # Win / Intel self.Fail('conformance/rendering/rendering-stencil-large-viewport.html', ['win', 'intel', 'd3d11'], bug=782317) + self.Fail('conformance2/textures/misc/angle-stuck-depth-textures.html', + ['win', 'intel', 'd3d11'], bug=820419) # Seems to cause the harness to fail immediately afterward self.Skip('conformance2/textures/video/tex-2d-rgba16f-rgba-half_float.html', @@ -412,6 +414,9 @@ ['mac', 'nvidia', 'intel'], bug=630800) self.Fail('deqp/functional/gles3/fbocompleteness.html', ['mac', 'nvidia', 'intel'], bug=630800) + self.Fail('deqp/functional/gles3/negativeshaderapi.html', + ['mac', 'amd', 'intel'], bug=811614) + # Mac Retina NVIDIA self.Fail('deqp/functional/gles3/shaderindexing/mat_01.html',
diff --git a/device/vr/oculus/oculus_render_loop.cc b/device/vr/oculus/oculus_render_loop.cc index e820f05..51e47a2 100644 --- a/device/vr/oculus/oculus_render_loop.cc +++ b/device/vr/oculus/oculus_render_loop.cc
@@ -5,6 +5,7 @@ #include "device/vr/oculus/oculus_render_loop.h" #include "device/vr/oculus/oculus_type_converters.h" +#include "third_party/libovr/src/Include/Extras/OVR_Math.h" #include "third_party/libovr/src/Include/OVR_CAPI.h" #include "third_party/libovr/src/Include/OVR_CAPI_D3D.h" #include "ui/gfx/geometry/angle_conversions.h" @@ -14,6 +15,32 @@ #endif namespace device { + +namespace { + +// How far the index trigger needs to be pushed to be considered "pressed". +const float kTriggerPressedThreshold = 0.6f; + +// WebXR reports a pointer pose separate from the grip pose, which represents a +// pointer ray emerging from the tip of the controller. Oculus does not report +// anything like that, but the pose they report matches WebXR's idea of the +// pointer pose more than grip. For consistency with other WebXR backends we +// apply a rotation and slight translation to the reported pose to get the grip +// pose. Experimentally determined, should roughly place the grip pose origin at +// the center of the Oculus Touch handle. +const float kGripRotationXDelta = 45.0f; +const float kGripOffsetZMeters = 0.025f; + +gfx::Transform PoseToTransform(const ovrPosef& pose) { + OVR::Matrix4f mat(pose); + return gfx::Transform(mat.M[0][0], mat.M[0][1], mat.M[0][2], mat.M[0][3], + mat.M[1][0], mat.M[1][1], mat.M[1][2], mat.M[1][3], + mat.M[2][0], mat.M[2][1], mat.M[2][2], mat.M[2][3], + mat.M[3][0], mat.M[3][1], mat.M[3][2], mat.M[3][3]); +} + +} // namespace + OculusRenderLoop::OculusRenderLoop(ovrSession session, ovrGraphicsLuid luid) : base::Thread("OculusRenderLoop"), main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), @@ -177,6 +204,8 @@ // able to safely ignore ones that our implementation doesn't care about. transport_options->wait_for_transfer_notification = true; + report_webxr_input_ = present_options->webxr_input; + main_thread_task_runner_->PostTask( FROM_HERE, base::BindOnce(std::move(callback), true, std::move(transport_options))); @@ -195,8 +224,12 @@ void OculusRenderLoop::GetVSync( mojom::VRPresentationProvider::GetVSyncCallback callback) { - int16_t frame = next_frame_id_++; DCHECK(is_presenting_); + int16_t frame = next_frame_id_; + next_frame_id_ += 1; + if (next_frame_id_ < 0) { + next_frame_id_ = 0; + } auto predicted_time = ovr_GetPredictedDisplayTime(session_, ovr_frame_index_ + 1); @@ -206,10 +239,124 @@ mojo::ConvertTo<mojom::VRPosePtr>(state.HeadPose.ThePose); last_render_pose_ = state.HeadPose.ThePose; + if (pose && report_webxr_input_) { + pose->input_state = GetInputState(state); + } + base::TimeDelta time = base::TimeDelta::FromSecondsD(predicted_time); std::move(callback).Run(std::move(pose), time, frame, mojom::VRPresentationProvider::VSyncStatus::SUCCESS); } +std::vector<mojom::XRInputSourceStatePtr> OculusRenderLoop::GetInputState( + const ovrTrackingState& tracking_state) { + std::vector<mojom::XRInputSourceStatePtr> input_states; + + ovrInputState input_state; + + // Get the state of the active controllers. + if ((OVR_SUCCESS(ovr_GetInputState(session_, ovrControllerType_Active, + &input_state)))) { + // Report whichever touch controllers are currently active. + if (input_state.ControllerType & ovrControllerType_LTouch) { + input_states.push_back(GetTouchData( + ovrControllerType_LTouch, tracking_state.HandPoses[ovrHand_Left], + input_state, ovrHand_Left)); + } else { + primary_input_pressed[ovrControllerType_LTouch] = false; + } + + if (input_state.ControllerType & ovrControllerType_RTouch) { + input_states.push_back(GetTouchData( + ovrControllerType_RTouch, tracking_state.HandPoses[ovrHand_Right], + input_state, ovrHand_Right)); + } else { + primary_input_pressed[ovrControllerType_RTouch] = false; + } + + // If an oculus remote is active, report a gaze controller. + if (input_state.ControllerType & ovrControllerType_Remote) { + device::mojom::XRInputSourceStatePtr state = + device::mojom::XRInputSourceState::New(); + + state->source_id = ovrControllerType_Remote; + state->primary_input_pressed = + (input_state.Buttons & ovrButton_Enter) != 0; + + if (!state->primary_input_pressed && + primary_input_pressed[ovrControllerType_Remote]) { + state->primary_input_clicked = true; + } + + primary_input_pressed[ovrControllerType_Remote] = + state->primary_input_pressed; + + input_states.push_back(std::move(state)); + } else { + primary_input_pressed[ovrControllerType_Remote] = false; + } + } + + return input_states; +} + +device::mojom::XRInputSourceStatePtr OculusRenderLoop::GetTouchData( + ovrControllerType type, + const ovrPoseStatef& pose, + const ovrInputState& input_state, + ovrHandType hand) { + device::mojom::XRInputSourceStatePtr state = + device::mojom::XRInputSourceState::New(); + + state->source_id = type; + state->primary_input_pressed = + (input_state.IndexTrigger[hand] > kTriggerPressedThreshold); + + // If the input has gone from pressed to not pressed since the last poll + // report it as clicked. + if (!state->primary_input_pressed && primary_input_pressed[type]) + state->primary_input_clicked = true; + + primary_input_pressed[type] = state->primary_input_pressed; + + device::mojom::XRInputSourceDescriptionPtr desc = + device::mojom::XRInputSourceDescription::New(); + + // It's a handheld pointing device. + desc->pointer_origin = device::mojom::XRPointerOrigin::HAND; + + // Set handedness. + switch (hand) { + case ovrHand_Left: + desc->handedness = device::mojom::XRHandedness::LEFT; + break; + case ovrHand_Right: + desc->handedness = device::mojom::XRHandedness::RIGHT; + break; + default: + desc->handedness = device::mojom::XRHandedness::NONE; + break; + } + + // Touch controller are fully 6DoF. + desc->emulated_position = false; + + // The grip pose will be rotated and translated back a bit from the pointer + // pose, which is what the Oculus API returns. + state->grip = PoseToTransform(pose.ThePose); + state->grip->RotateAboutXAxis(kGripRotationXDelta); + state->grip->Translate3d(0, 0, kGripOffsetZMeters); + + // Need to apply the inverse transform from above to put the pointer back in + // the right orientation relative to the grip. + desc->pointer_offset = gfx::Transform(); + desc->pointer_offset->Translate3d(0, 0, -kGripOffsetZMeters); + desc->pointer_offset->RotateAboutXAxis(-kGripRotationXDelta); + + state->description = std::move(desc); + + return state; +} + } // namespace device
diff --git a/device/vr/oculus/oculus_render_loop.h b/device/vr/oculus/oculus_render_loop.h index 93ff7422..47af6a69 100644 --- a/device/vr/oculus/oculus_render_loop.h +++ b/device/vr/oculus/oculus_render_loop.h
@@ -20,6 +20,8 @@ namespace device { +const int kMaxOculusRenderLoopInputId = (ovrControllerType_Remote + 1); + class OculusRenderLoop : public base::Thread, mojom::VRPresentationProvider { public: OculusRenderLoop(ovrSession session, ovrGraphicsLuid luid); @@ -52,6 +54,15 @@ mojom::VRPosePtr GetPose(); + std::vector<mojom::XRInputSourceStatePtr> GetInputState( + const ovrTrackingState& tracking_state); + + device::mojom::XRInputSourceStatePtr GetTouchData( + ovrControllerType type, + const ovrPoseStatef& pose, + const ovrInputState& input_state, + ovrHandType hand); + #if defined(OS_WIN) D3D11TextureHelper texture_helper_; #endif @@ -70,6 +81,9 @@ ovrTextureSwapChain texture_swap_chain_ = 0; double sensor_time_; mojo::Binding<mojom::VRPresentationProvider> binding_; + bool report_webxr_input_ = false; + bool primary_input_pressed[kMaxOculusRenderLoopInputId]; + base::WeakPtrFactory<OculusRenderLoop> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(OculusRenderLoop);
diff --git a/device/vr/openvr/openvr_render_loop.cc b/device/vr/openvr/openvr_render_loop.cc index f379ca73f..337eac3 100644 --- a/device/vr/openvr/openvr_render_loop.cc +++ b/device/vr/openvr/openvr_render_loop.cc
@@ -169,8 +169,12 @@ void OpenVRRenderLoop::GetVSync( mojom::VRPresentationProvider::GetVSyncCallback callback) { - int16_t frame = next_frame_id_++; DCHECK(is_presenting_); + int16_t frame = next_frame_id_; + next_frame_id_ += 1; + if (next_frame_id_ < 0) { + next_frame_id_ = 0; + } mojom::VRPosePtr pose = GetPose();
diff --git a/device/vr/orientation/orientation_device.cc b/device/vr/orientation/orientation_device.cc index 67f93f9..5c826c2 100644 --- a/device/vr/orientation/orientation_device.cc +++ b/device/vr/orientation/orientation_device.cc
@@ -54,8 +54,11 @@ mojom::SensorProviderPtr* sensor_provider, base::OnceClosure ready_callback) : ready_callback_(std::move(ready_callback)), binding_(this) { + // Use RELATIVE_ORIENTATION_QUATERNION rather than + // ABSOLUTE_ORIENTATION_QUATERNION because compass readings can be innacurate + // when used indoors. (*sensor_provider) - ->GetSensor(SensorType::ABSOLUTE_ORIENTATION_QUATERNION, + ->GetSensor(SensorType::RELATIVE_ORIENTATION_QUATERNION, base::BindOnce(&VROrientationDevice::SensorReady, base::Unretained(this)));
diff --git a/device/vr/orientation/orientation_device_provider_unittest.cc b/device/vr/orientation/orientation_device_provider_unittest.cc index e4db0d5..14757b5 100644 --- a/device/vr/orientation/orientation_device_provider_unittest.cc +++ b/device/vr/orientation/orientation_device_provider_unittest.cc
@@ -70,7 +70,7 @@ auto init_params = mojom::SensorInitParams::New(); init_params->sensor = std::move(sensor_ptr_); init_params->default_configuration = PlatformSensorConfiguration( - SensorTraits<mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION>:: + SensorTraits<mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION>:: kDefaultFrequency); init_params->client_request = mojo::MakeRequest(&sensor_client_ptr_); @@ -79,7 +79,7 @@ mojo::SharedBufferHandle::AccessMode::READ_ONLY); init_params->buffer_offset = SensorReadingSharedBuffer::GetOffset( - mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION); + mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION); return init_params; }
diff --git a/device/vr/orientation/orientation_device_unittest.cc b/device/vr/orientation/orientation_device_unittest.cc index 1643bb7..d360d89d 100644 --- a/device/vr/orientation/orientation_device_unittest.cc +++ b/device/vr/orientation/orientation_device_unittest.cc
@@ -97,7 +97,7 @@ double GetBufferOffset() { return SensorReadingSharedBuffer::GetOffset( - mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION); + mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION); } void InitializeDevice(mojom::SensorInitParamsPtr params) { @@ -150,7 +150,7 @@ auto init_params = mojom::SensorInitParams::New(); init_params->sensor = std::move(sensor_ptr_); init_params->default_configuration = PlatformSensorConfiguration( - SensorTraits<mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION>:: + SensorTraits<mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION>:: kDefaultFrequency); init_params->client_request = mojo::MakeRequest(&sensor_client_ptr_);
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn index a071e57..bf9ba62 100644 --- a/extensions/BUILD.gn +++ b/extensions/BUILD.gn
@@ -223,7 +223,6 @@ "//extensions/common:unit_tests", "//extensions/renderer:unit_tests", "//extensions/shell:unit_tests", - "//extensions/utility:unit_tests", "//services/data_decoder:lib", "//services/service_manager/public/cpp/test:test_support", "//ui/gl:test_support",
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn index 28da43b..8dc8564 100644 --- a/extensions/browser/BUILD.gn +++ b/extensions/browser/BUILD.gn
@@ -615,6 +615,8 @@ "//components/pref_registry:pref_registry", "//components/prefs:test_support", "//components/sync_preferences:test_support", + "//components/unzip_service:lib", + "//components/unzip_service/public/cpp:test_support", "//components/update_client", "//components/url_matcher", "//components/user_prefs", @@ -629,8 +631,10 @@ "//extensions/strings", "//ipc:test_support", "//net:test_support", + "//services/data_decoder:lib", "//services/data_decoder/public/cpp:test_support", "//services/device/public/mojom", + "//services/service_manager/public/cpp/test:test_support", "//storage/browser:test_support", "//third_party/leveldatabase", "//third_party/zlib/google:zip",
diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS index 3d5d48d..5d4816a 100644 --- a/extensions/browser/DEPS +++ b/extensions/browser/DEPS
@@ -8,6 +8,7 @@ "+components/sync", "+components/sync_preferences", "+components/update_client", + "+components/unzip_service/public", "+components/variations", "+components/version_info", "+components/web_cache", @@ -56,4 +57,8 @@ "+chrome/test/base/testing_profile.h", "+chrome/test/base/ui_test_utils.h", ], + "sandboxed_unpacker_unittest.cc": [ + "+components/unzip_service", + "+services/data_decoder", + ], }
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc index afec71d..54ee0ebc 100644 --- a/extensions/browser/sandboxed_unpacker.cc +++ b/extensions/browser/sandboxed_unpacker.cc
@@ -25,15 +25,16 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "components/crx_file/crx_verifier.h" +#include "components/unzip_service/public/cpp/unzip.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/declarative_net_request/utils.h" #include "extensions/browser/extension_file_task_runner.h" +#include "extensions/browser/zipfile_installer.h" #include "extensions/common/api/declarative_net_request/dnr_manifest_data.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/extension_l10n_util.h" #include "extensions/common/extension_resource_path_normalizer.h" -#include "extensions/common/extension_unpacker.mojom.h" #include "extensions/common/extension_utility_types.h" #include "extensions/common/extensions_client.h" #include "extensions/common/features/feature_channel.h" @@ -233,6 +234,9 @@ CHECK_GT(location, Manifest::INVALID_LOCATION); CHECK_LT(location, Manifest::NUM_LOCATIONS); + // The connector should not be bound to any thread yet. + DCHECK(!connector_->IsBound()); + // Use a random instance ID to guarantee the connection is to a new data // decoder service (running in its own process). data_decoder_identity_ = service_manager::Identity( @@ -323,9 +327,20 @@ PATH_LENGTH_HISTOGRAM("Extensions.SandboxUnpackLinkFreeCrxPathLength", link_free_crx_path); - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::BindOnce(&SandboxedUnpacker::Unzip, this, link_free_crx_path)); + // Make sure to create the directory where the extension will be unzipped, as + // the unzipper service requires it. + base::FilePath unzipped_dir = + link_free_crx_path.DirName().AppendASCII(kTempExtensionName); + base::File::Error error; + if (!base::CreateDirectoryAndGetError(unzipped_dir, &error)) { + LOG(ERROR) << "Failed to created directory " << unzipped_dir.value() + << " with error " << error; + ReportFailure(UNZIP_FAILED, + l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR)); + return; + } + + Unzip(link_free_crx_path, unzipped_dir); } void SandboxedUnpacker::StartWithDirectory(const std::string& extension_id, @@ -348,8 +363,8 @@ return; } - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, + unpacker_io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&SandboxedUnpacker::Unpack, this, extension_root_)); } @@ -373,63 +388,23 @@ unpacker_io_task_runner_->DeleteSoon(FROM_HERE, std::move(connector_)); } -void SandboxedUnpacker::StartUtilityProcessIfNeeded() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - if (utility_process_mojo_client_) - return; - - utility_process_mojo_client_ = std::make_unique< - content::UtilityProcessMojoClient<mojom::ExtensionUnpacker>>( - l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME)); - utility_process_mojo_client_->set_error_callback( - base::Bind(&SandboxedUnpacker::UtilityProcessCrashed, this)); - - utility_process_mojo_client_->set_exposed_directory(temp_dir_.GetPath()); - - utility_process_mojo_client_->Start(); -} - -void SandboxedUnpacker::UtilityProcessCrashed() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - utility_process_mojo_client_.reset(); - - unpacker_io_task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &SandboxedUnpacker::ReportFailure, this, - UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, - l10n_util::GetStringFUTF16( - IDS_EXTENSION_PACKAGE_INSTALL_ERROR, - ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL")) + - ASCIIToUTF16(". ") + - l10n_util::GetStringUTF16( - IDS_EXTENSION_INSTALL_PROCESS_CRASHED))); -} - -void SandboxedUnpacker::Unzip(const base::FilePath& crx_path) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - StartUtilityProcessIfNeeded(); +void SandboxedUnpacker::Unzip(const base::FilePath& crx_path, + const base::FilePath& unzipped_dir) { + DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); DCHECK(crx_path.DirName() == temp_dir_.GetPath()); - base::FilePath unzipped_dir = - crx_path.DirName().AppendASCII(kTempExtensionName); - utility_process_mojo_client_->service()->Unzip( - crx_path, unzipped_dir, - base::BindOnce(&SandboxedUnpacker::UnzipDone, this, unzipped_dir)); + ZipFileInstaller::Create(connector_.get(), + base::BindOnce(&SandboxedUnpacker::UnzipDone, this)) + ->LoadFromZipFileInDir(crx_path, unzipped_dir); } -void SandboxedUnpacker::UnzipDone(const base::FilePath& directory, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); +void SandboxedUnpacker::UnzipDone(const base::FilePath& zip_file, + const base::FilePath& unzip_dir, + const std::string& error) { + DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); - utility_process_mojo_client_.reset(); - - if (!success) { - utility_process_mojo_client_.reset(); + if (!error.empty()) { unpacker_io_task_runner_->PostTask( FROM_HERE, base::BindOnce( @@ -438,22 +413,18 @@ return; } - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::BindOnce(&SandboxedUnpacker::Unpack, this, directory)); + Unpack(unzip_dir); } void SandboxedUnpacker::Unpack(const base::FilePath& directory) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); DCHECK(directory.DirName() == temp_dir_.GetPath()); base::FilePath manifest_path = extension_root_.Append(kManifestFilename); - unpacker_io_task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &SandboxedUnpacker::ParseJsonFile, this, manifest_path, - base::BindOnce(&SandboxedUnpacker::ReadManifestDone, this))); + + ParseJsonFile(manifest_path, + base::BindOnce(&SandboxedUnpacker::ReadManifestDone, this)); } void SandboxedUnpacker::ReadManifestDone( @@ -607,6 +578,12 @@ l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE")); break; + case ImageSanitizer::Status::kServiceError: + failure_reason = UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL; + error = l10n_util::GetStringFUTF16( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("ERROR_UTILITY_PROCESS_CRASH")); + break; default: NOTREACHED(); break; @@ -786,7 +763,6 @@ void SandboxedUnpacker::UnpackExtensionFailed(const base::string16& error) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); - ReportFailure( UNPACKER_CLIENT_FAILED, l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error));
diff --git a/extensions/browser/sandboxed_unpacker.h b/extensions/browser/sandboxed_unpacker.h index 9ec05ce..24ea37f 100644 --- a/extensions/browser/sandboxed_unpacker.h +++ b/extensions/browser/sandboxed_unpacker.h
@@ -16,7 +16,6 @@ #include "base/optional.h" #include "base/strings/string_piece.h" #include "base/time/time.h" -#include "content/public/browser/utility_process_mojo_client.h" #include "extensions/browser/crx_file_info.h" #include "extensions/browser/image_sanitizer.h" #include "extensions/browser/install/crx_install_error.h" @@ -40,10 +39,6 @@ namespace extensions { class Extension; -namespace mojom { -class ExtensionUnpacker; -} - class SandboxedUnpackerClient : public base::RefCountedDeleteOnSequence<SandboxedUnpackerClient> { public: @@ -85,9 +80,8 @@ // SandboxedUnpacker does work to optionally unpack and then validate/sanitize // an extension, either starting from a crx file, or else an already unzipped -// directory (eg., from a differential update). This is done in a sandboxed -// subprocess to protect the browser process from parsing complex data formats -// like JPEG or JSON from untrusted sources. +// directory (eg., from a differential update). The parsing of complex data +// formats like JPEG or JSON is performed in specific, sandboxed services. // // Unpacking an extension using this class makes changes to its source, such as // transcoding all images to PNG, parsing all message catalogs, and rewriting @@ -96,8 +90,7 @@ // // Lifetime management: // -// This class is ref-counted by each call it makes to itself on another thread, -// and by UtilityProcessMojoClient. +// This class is ref-counted by each call it makes to itself on another thread. // // Additionally, we hold a reference to our own client so that the client lives // long enough to receive the result of unpacking. @@ -229,15 +222,12 @@ bool ValidateSignature(const base::FilePath& crx_path, const std::string& expected_hash); - // Ensures the utility process is created. - void StartUtilityProcessIfNeeded(); - - // Utility process crashed or failed while trying to install. - void UtilityProcessCrashed(); - // Unzips the extension into directory. - void Unzip(const base::FilePath& crx_path); - void UnzipDone(const base::FilePath& directory, bool success); + void Unzip(const base::FilePath& crx_path, + const base::FilePath& unzipped_dir); + void UnzipDone(const base::FilePath& zip_file, + const base::FilePath& unzip_dir, + const std::string& error); // Unpacks the extension in directory and returns the manifest. void Unpack(const base::FilePath& directory); @@ -342,10 +332,6 @@ // Sequenced task runner where file I/O operations will be performed. scoped_refptr<base::SequencedTaskRunner> unpacker_io_task_runner_; - // Utility client used for sending tasks to the utility process. - std::unique_ptr<content::UtilityProcessMojoClient<mojom::ExtensionUnpacker>> - utility_process_mojo_client_; - // The normalized path of the install icon path, retrieved from the manifest. base::FilePath install_icon_path_;
diff --git a/extensions/browser/sandboxed_unpacker_unittest.cc b/extensions/browser/sandboxed_unpacker_unittest.cc index a61be79..a378d30 100644 --- a/extensions/browser/sandboxed_unpacker_unittest.cc +++ b/extensions/browser/sandboxed_unpacker_unittest.cc
@@ -17,6 +17,8 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" #include "components/crx_file/id_util.h" +#include "components/unzip_service/public/cpp/test_unzip_service.h" +#include "components/unzip_service/unzip_service.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" @@ -28,8 +30,10 @@ #include "extensions/common/switches.h" #include "extensions/strings/grit/extensions_strings.h" #include "extensions/test/test_extensions_client.h" +#include "services/data_decoder/data_decoder_service.h" #include "services/data_decoder/public/cpp/test_data_decoder_service.h" #include "services/service_manager/public/cpp/connector.h" +#include "services/service_manager/public/cpp/test/test_connector_factory.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/zlib/google/zip.h" @@ -128,10 +132,30 @@ // It will delete itself. client_ = new MockSandboxedUnpackerClient; - sandboxed_unpacker_ = new SandboxedUnpacker( - test_data_decoder_service_.connector()->Clone(), Manifest::INTERNAL, - Extension::NO_FLAGS, extensions_dir_.GetPath(), - base::ThreadTaskRunnerHandle::Get(), client_); + InitSanboxedUnpacker(/*data_decode_service=*/nullptr, + /*unzip_service=*/nullptr); + } + + void InitSanboxedUnpacker( + std::unique_ptr<service_manager::Service> data_decode_service, + std::unique_ptr<service_manager::Service> unzip_service) { + service_manager::TestConnectorFactory::NameToServiceMap services; + if (!data_decode_service) + data_decode_service = data_decoder::DataDecoderService::Create(); + if (!unzip_service) + unzip_service = unzip::UnzipService::CreateService(); + services.insert( + std::make_pair("data_decoder", std::move(data_decode_service))); + services.insert(std::make_pair("unzip_service", std::move(unzip_service))); + test_connector_factory_ = + service_manager::TestConnectorFactory::CreateForServices( + std::move(services)); + connector_ = test_connector_factory_->CreateConnector(); + + sandboxed_unpacker_ = + new SandboxedUnpacker(connector_->Clone(), Manifest::INTERNAL, + Extension::NO_FLAGS, extensions_dir_.GetPath(), + base::ThreadTaskRunnerHandle::Get(), client_); } void TearDown() override { @@ -178,20 +202,6 @@ client_->WaitForUnpack(); } - void SimulateUtilityProcessCrash() { - sandboxed_unpacker_->CreateTempDirectory(); - - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&SandboxedUnpacker::StartUtilityProcessIfNeeded, - sandboxed_unpacker_)); - - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&SandboxedUnpacker::UtilityProcessCrashed, - sandboxed_unpacker_)); - } - bool InstallSucceeded() const { return !client_->temp_dir().empty(); } base::FilePath GetInstallPath() const { @@ -222,12 +232,14 @@ } protected: - data_decoder::TestDataDecoderService test_data_decoder_service_; base::ScopedTempDir extensions_dir_; MockSandboxedUnpackerClient* client_; scoped_refptr<SandboxedUnpacker> sandboxed_unpacker_; std::unique_ptr<content::InProcessUtilityThreadHelper> in_process_utility_thread_helper_; + std::unique_ptr<service_manager::TestConnectorFactory> + test_connector_factory_; + std::unique_ptr<service_manager::Connector> connector_; }; TEST_F(SandboxedUnpackerTest, EmptyDefaultLocale) { @@ -353,6 +365,34 @@ EXPECT_EQ(base::string16(), GetInstallError()); } +// The following tests simulate the utility services failling. +TEST_F(SandboxedUnpackerTest, UnzipperServiceFails) { + InitSanboxedUnpacker( + /*data_decoder_service=*/nullptr, + std::make_unique<unzip::CrashyUnzipService>()); + SetupUnpacker("good_package.crx", ""); + EXPECT_FALSE(InstallSucceeded()); + EXPECT_FALSE(GetInstallError().empty()); +} + +TEST_F(SandboxedUnpackerTest, JsonParserFails) { + InitSanboxedUnpacker(std::make_unique<data_decoder::CrashyDataDecoderService>( + /*crash_json=*/true, /*crash_image=*/false), + /*unzip_service=*/nullptr); + SetupUnpacker("good_package.crx", ""); + EXPECT_FALSE(InstallSucceeded()); + EXPECT_FALSE(GetInstallError().empty()); +} + +TEST_F(SandboxedUnpackerTest, ImageDecoderFails) { + InitSanboxedUnpacker(std::make_unique<data_decoder::CrashyDataDecoderService>( + /*crash_json=*/false, /*crash_image=*/true), + /*unzip_service=*/nullptr); + SetupUnpacker("good_package.crx", ""); + EXPECT_FALSE(InstallSucceeded()); + EXPECT_FALSE(GetInstallError().empty()); +} + // SandboxedUnpacker is ref counted and is reference by callbacks and // InterfacePtrs. This tests that it gets deleted as expected (so that no extra // refs are left). @@ -364,25 +404,4 @@ TestSandboxedUnpackerDeleted("bad_image.crx", /*expect_success=*/false); } -class SandboxedUnpackerTestWithRealIOThread : public SandboxedUnpackerTest { - public: - SandboxedUnpackerTestWithRealIOThread() - : SandboxedUnpackerTest( - content::TestBrowserThreadBundle::REAL_IO_THREAD) {} - - void TearDown() override { - // The utility process task could still be running. Ensure it is fully - // finished before ending the test. - content::RunAllPendingInMessageLoop(content::BrowserThread::IO); - SandboxedUnpackerTest::TearDown(); - } -}; - -TEST_F(SandboxedUnpackerTestWithRealIOThread, UtilityProcessCrash) { - SimulateUtilityProcessCrash(); - client_->WaitForUnpack(); - // Check that there is an error message. - EXPECT_NE(base::string16(), GetInstallError()); -} - } // namespace extensions
diff --git a/extensions/browser/zipfile_installer.cc b/extensions/browser/zipfile_installer.cc index b24bbab..b18e9588 100644 --- a/extensions/browser/zipfile_installer.cc +++ b/extensions/browser/zipfile_installer.cc
@@ -6,19 +6,33 @@ #include "base/files/file_util.h" #include "base/path_service.h" +#include "base/task_runner_util.h" #include "base/task_scheduler/post_task.h" +#include "components/unzip_service/public/cpp/unzip.h" +#include "components/unzip_service/public/interfaces/unzipper.mojom.h" #include "extensions/browser/extension_file_task_runner.h" -#include "extensions/common/extension_unpacker.mojom.h" +#include "extensions/common/constants.h" +#include "extensions/common/manifest.h" #include "extensions/strings/grit/extensions_strings.h" +#include "services/data_decoder/public/cpp/safe_json_parser.h" +#include "services/service_manager/public/cpp/connector.h" #include "ui/base/l10n/l10n_util.h" +namespace extensions { + namespace { -const char kExtensionHandlerTempDirError[] = +constexpr char kExtensionHandlerTempDirError[] = "Could not create temporary directory for zipped extension."; -const char kExtensionHandlerFileUnzipError[] = +constexpr char kExtensionHandlerFileUnzipError[] = "Could not unzip extension for install."; +constexpr const base::FilePath::CharType* kAllowedThemeFiletypes[] = { + FILE_PATH_LITERAL(".bmp"), FILE_PATH_LITERAL(".gif"), + FILE_PATH_LITERAL(".jpeg"), FILE_PATH_LITERAL(".jpg"), + FILE_PATH_LITERAL(".json"), FILE_PATH_LITERAL(".png"), + FILE_PATH_LITERAL(".webp")}; + base::Optional<base::FilePath> PrepareAndGetUnzipDir( const base::FilePath& zip_file) { base::AssertBlockingAllowed(); @@ -36,31 +50,59 @@ return unzip_dir; } -} // namespace +base::Optional<std::string> ReadFileContent(const base::FilePath& path) { + base::AssertBlockingAllowed(); -namespace extensions { + std::string content; + return base::ReadFileToString(path, &content) ? content + : base::Optional<std::string>(); +} + +} // namespace // static scoped_refptr<ZipFileInstaller> ZipFileInstaller::Create( + service_manager::Connector* connector, DoneCallback done_callback) { + DCHECK(connector); DCHECK(done_callback); - return base::WrapRefCounted(new ZipFileInstaller(std::move(done_callback))); + return base::WrapRefCounted( + new ZipFileInstaller(connector, std::move(done_callback))); } void ZipFileInstaller::LoadFromZipFile(const base::FilePath& zip_file) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + LoadFromZipFileImpl(zip_file, base::FilePath()); +} + +void ZipFileInstaller::LoadFromZipFileInDir(const base::FilePath& zip_file, + const base::FilePath& unzip_dir) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!unzip_dir.empty()); + LoadFromZipFileImpl(zip_file, unzip_dir); +} + +void ZipFileInstaller::LoadFromZipFileImpl(const base::FilePath& zip_file, + const base::FilePath& unzip_dir) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!zip_file.empty()); zip_file_ = zip_file; + if (!unzip_dir.empty()) { + Unzip(unzip_dir); + return; + } + base::PostTaskAndReplyWithResult( GetExtensionFileTaskRunner().get(), FROM_HERE, base::BindOnce(&PrepareAndGetUnzipDir, zip_file), base::BindOnce(&ZipFileInstaller::Unzip, this)); } -ZipFileInstaller::ZipFileInstaller(DoneCallback done_callback) - : done_callback_(std::move(done_callback)) {} +ZipFileInstaller::ZipFileInstaller(service_manager::Connector* connector, + DoneCallback done_callback) + : done_callback_(std::move(done_callback)), connector_(connector) {} ZipFileInstaller::~ZipFileInstaller() = default; @@ -71,29 +113,76 @@ ReportFailure(std::string(kExtensionHandlerTempDirError)); return; } - DCHECK(!utility_process_mojo_client_); - utility_process_mojo_client_ = std::make_unique< - content::UtilityProcessMojoClient<mojom::ExtensionUnpacker>>( - l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_ZIP_FILE_INSTALLER_NAME)); - utility_process_mojo_client_->set_error_callback( - base::Bind(&ZipFileInstaller::UnzipDone, this, *unzip_dir, false)); + unzip::UnzipWithFilter( + connector_->Clone(), zip_file_, *unzip_dir, + base::BindRepeating(&ZipFileInstaller::IsManifestFile), + base::BindOnce(&ZipFileInstaller::ManifestUnzipped, this, *unzip_dir)); +} - utility_process_mojo_client_->set_exposed_directory(*unzip_dir); +void ZipFileInstaller::ManifestUnzipped(const base::FilePath& unzip_dir, + bool success) { + if (!success) { + ReportFailure(kExtensionHandlerFileUnzipError); + return; + } - utility_process_mojo_client_->Start(); + base::PostTaskAndReplyWithResult( + GetExtensionFileTaskRunner().get(), FROM_HERE, + base::BindOnce(&ReadFileContent, unzip_dir.Append(kManifestFilename)), + base::BindOnce(&ZipFileInstaller::ManifestRead, this, unzip_dir)); +} - utility_process_mojo_client_->service()->Unzip( - zip_file_, *unzip_dir, - base::BindOnce(&ZipFileInstaller::UnzipDone, this, *unzip_dir)); +void ZipFileInstaller::ManifestRead( + const base::FilePath& unzip_dir, + base::Optional<std::string> manifest_content) { + if (!manifest_content) { + ReportFailure(std::string(kExtensionHandlerFileUnzipError)); + return; + } + + data_decoder::SafeJsonParser::Parse( + connector_, *manifest_content, + base::Bind(&ZipFileInstaller::ManifestParsed, this, unzip_dir), + base::Bind(&ZipFileInstaller::ManifestParsingFailed, this)); +} + +void ZipFileInstaller::ManifestParsingFailed(const std::string& error) { + ReportFailure(std::string(kExtensionHandlerFileUnzipError)); +} + +void ZipFileInstaller::ManifestParsed( + const base::FilePath& unzip_dir, + std::unique_ptr<base::Value> manifest_value) { + std::unique_ptr<base::DictionaryValue> manifest_dictionary = + base::DictionaryValue::From(std::move(manifest_value)); + if (!manifest_dictionary) { + ReportFailure(std::string(kExtensionHandlerFileUnzipError)); + return; + } + + Manifest manifest(Manifest::INTERNAL, std::move(manifest_dictionary)); + + unzip::UnzipFilterCallback filter = base::BindRepeating( + [](bool is_theme, const base::FilePath& file_path) -> bool { + // Note that we ignore the manifest as it has already been extracted and + // would cause the unzipping to fail. + return ZipFileInstaller::ShouldExtractFile(is_theme, file_path) && + !ZipFileInstaller::IsManifestFile(file_path); + }, + manifest.is_theme()); + + // TODO(crbug.com/645263): This silently ignores blocked file types. + // Add install warnings. + unzip::UnzipWithFilter( + connector_->Clone(), zip_file_, unzip_dir, filter, + base::BindOnce(&ZipFileInstaller::UnzipDone, this, unzip_dir)); } void ZipFileInstaller::UnzipDone(const base::FilePath& unzip_dir, bool success) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - utility_process_mojo_client_.reset(); - if (!success) { ReportFailure(kExtensionHandlerFileUnzipError); return; @@ -108,4 +197,26 @@ std::move(done_callback_).Run(zip_file_, base::FilePath(), error); } +// static +bool ZipFileInstaller::ShouldExtractFile(bool is_theme, + const base::FilePath& file_path) { + if (is_theme) { + const base::FilePath::StringType extension = + base::ToLowerASCII(file_path.FinalExtension()); + // Allow filenames with no extension. + if (extension.empty()) + return true; + return base::ContainsValue(kAllowedThemeFiletypes, extension); + } + return !base::FilePath::CompareEqualIgnoreCase(file_path.FinalExtension(), + FILE_PATH_LITERAL(".exe")); +} + +// static +bool ZipFileInstaller::IsManifestFile(const base::FilePath& file_path) { + CHECK(!file_path.IsAbsolute()); + return base::FilePath::CompareEqualIgnoreCase(file_path.value(), + kManifestFilename); +} + } // namespace extensions
diff --git a/extensions/browser/zipfile_installer.h b/extensions/browser/zipfile_installer.h index 944e99a..9d44b5f 100644 --- a/extensions/browser/zipfile_installer.h +++ b/extensions/browser/zipfile_installer.h
@@ -8,20 +8,24 @@ #include <memory> #include <string> +#include "base/callback.h" #include "base/files/file_path.h" +#include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "base/sequence_checker.h" -#include "content/public/browser/utility_process_mojo_client.h" +#include "base/values.h" + +namespace service_manager { +class Connector; +} namespace extensions { -namespace mojom { -class ExtensionUnpacker; -} - -// ZipFileInstaller unzips an extension in a utility process. +// ZipFileInstaller unzips an extension safely using the Unzipper and +// SafeJSONParser services. // This class is not thread-safe: it is bound to the sequence it is created on. class ZipFileInstaller : public base::RefCountedThreadSafe<ZipFileInstaller> { public: @@ -34,18 +38,38 @@ const std::string& error)>; // Creates a ZipFileInstaller that invokes |done_callback| when done. - static scoped_refptr<ZipFileInstaller> Create(DoneCallback done_callback); + static scoped_refptr<ZipFileInstaller> Create( + service_manager::Connector* connector, + DoneCallback done_callback); + // Creates a temporary directory and unzips the extension in it. void LoadFromZipFile(const base::FilePath& zip_file); + // Unzips the extension in |unzip_dir|. + void LoadFromZipFileInDir(const base::FilePath& zip_file, + const base::FilePath& unzip_dir); + private: friend class base::RefCountedThreadSafe<ZipFileInstaller>; + FRIEND_TEST_ALL_PREFIXES(ZipFileInstallerTest, NonTheme_FileExtractionFilter); + FRIEND_TEST_ALL_PREFIXES(ZipFileInstallerTest, Theme_FileExtractionFilter); + FRIEND_TEST_ALL_PREFIXES(ZipFileInstallerTest, ManifestExtractionFilter); - explicit ZipFileInstaller(DoneCallback done_callback); + ZipFileInstaller(service_manager::Connector* connector, + DoneCallback done_callback); ~ZipFileInstaller(); + void LoadFromZipFileImpl(const base::FilePath& zip_file, + const base::FilePath& unzip_dir); + // Unzip an extension into |unzip_dir| and load it with an UnpackedInstaller. void Unzip(base::Optional<base::FilePath> unzip_dir); + void ManifestUnzipped(const base::FilePath& unzip_dir, bool success); + void ManifestRead(const base::FilePath& unzip_dir, + base::Optional<std::string> manifest_content); + void ManifestParsingFailed(const std::string& error); + void ManifestParsed(const base::FilePath& unzip_dir, + std::unique_ptr<base::Value> manifest); void UnzipDone(const base::FilePath& unzip_dir, bool success); // On failure, report the |error| reason. @@ -54,12 +78,18 @@ // Callback invoked when unzipping has finished. DoneCallback done_callback_; + // Whether a file should be extracted as part of installing an + // extension/theme. Protects against unused or potentially hamrful files. + static bool ShouldExtractFile(bool is_theme, const base::FilePath& file_path); + + // Returns true if |file_path| points to an extension manifest. + static bool IsManifestFile(const base::FilePath& file_path); + // File containing the extension to unzip. base::FilePath zip_file_; - // Utility process used to perform the unzip. - std::unique_ptr<content::UtilityProcessMojoClient<mojom::ExtensionUnpacker>> - utility_process_mojo_client_; + // Connector to the ServiceManager. Bound to the UI thread. + service_manager::Connector* connector_; SEQUENCE_CHECKER(sequence_checker_);
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn index 0450e04..eb30402e 100644 --- a/extensions/common/BUILD.gn +++ b/extensions/common/BUILD.gn
@@ -23,7 +23,6 @@ if (enable_extensions) { mojom("mojo") { sources = [ - "extension_unpacker.mojom", "mojo/app_window.mojom", "mojo/guest_view.mojom", "mojo/keep_alive.mojom", @@ -35,7 +34,6 @@ public_deps = [ "//content/public/common:interfaces", - "//mojo/common:common_custom_types", "//ui/gfx/geometry/mojo", "//url/mojom:url_mojom_gurl", ]
diff --git a/extensions/common/api/_manifest_features.json b/extensions/common/api/_manifest_features.json index 54301371..8b0d4c7 100644 --- a/extensions/common/api/_manifest_features.json +++ b/extensions/common/api/_manifest_features.json
@@ -231,6 +231,7 @@ "extension_types": [ "extension", "legacy_packaged_app", "platform_app" ], "whitelist": [ "787000072C6FBB934AF5A42275CDE73FC977D995", // browser_tests + "2FC374607C2DF285634B67C64A2E356C607091C3", // QuickOffice "CBCC42ABED43A4B58FE3810E62AFFA010EB0349F" // PDF ] },
diff --git a/extensions/common/extension_unpacker.mojom b/extensions/common/extension_unpacker.mojom deleted file mode 100644 index f29ce63..0000000 --- a/extensions/common/extension_unpacker.mojom +++ /dev/null
@@ -1,16 +0,0 @@ -// 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. - -// Safe chrome extension unpacker service provided by the utility process -// and exposed by mojo policy to the chrome browser process. - -module extensions.mojom; - -import "mojo/common/file_path.mojom"; - -interface ExtensionUnpacker { - // Unzip |file| into the directory |path|. - Unzip(mojo.common.mojom.FilePath file, - mojo.common.mojom.FilePath path) => (bool success); -};
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn index b5ddbfab..5b493a18 100644 --- a/extensions/shell/BUILD.gn +++ b/extensions/shell/BUILD.gn
@@ -65,7 +65,6 @@ "//extensions/shell/common/api", "//extensions/shell/common/api:api_registration", "//extensions/shell/common/api:extensions_features", - "//extensions/utility", "//skia", "//third_party/WebKit/public:blink", "//third_party/cld_3/src/src:cld_3", @@ -95,6 +94,8 @@ "browser/api/feedback_private/shell_feedback_private_delegate.h", "browser/api/identity/identity_api.cc", "browser/api/identity/identity_api.h", + "browser/api/runtime/shell_runtime_api_delegate.cc", + "browser/api/runtime/shell_runtime_api_delegate.h", "browser/default_shell_browser_main_delegate.cc", "browser/default_shell_browser_main_delegate.h", "browser/delegates/shell_kiosk_delegate.cc", @@ -161,8 +162,6 @@ "browser/shell_oauth2_token_service_delegate.h", "browser/shell_prefs.cc", "browser/shell_prefs.h", - "browser/shell_runtime_api_delegate.cc", - "browser/shell_runtime_api_delegate.h", "browser/shell_special_storage_policy.cc", "browser/shell_special_storage_policy.h", "browser/shell_speech_recognition_manager_delegate.cc", @@ -183,8 +182,6 @@ "renderer/shell_content_renderer_client.h", "renderer/shell_extensions_renderer_client.cc", "renderer/shell_extensions_renderer_client.h", - "utility/shell_content_utility_client.cc", - "utility/shell_content_utility_client.h", ] if (use_aura) { @@ -456,6 +453,7 @@ source_set("browser_tests") { testonly = true sources = [ + "browser/api/runtime/runtime_apitest.cc", "browser/geolocation/geolocation_apitest.cc", "browser/shell_browsertest.cc", "test/shell_apitest.cc", @@ -473,15 +471,18 @@ ":app_shell_lib", "//base", "//base/test:test_support", + "//components/keep_alive_registry", "//components/version_info", "//content/shell:content_shell_lib", "//content/test:test_support", "//extensions:test_support", "//extensions/browser", + "//extensions/browser:test_support", "//extensions/common", ] if (use_aura) { + sources += [ "browser/shell_desktop_controller_aura_browsertest.cc" ] deps += [ "//ui/aura" ] } }
diff --git a/extensions/shell/app/DEPS b/extensions/shell/app/DEPS index 5b7cd97..a92aad2 100644 --- a/extensions/shell/app/DEPS +++ b/extensions/shell/app/DEPS
@@ -4,5 +4,6 @@ "+components/nacl", "+content/public/app", "+content/public/browser", + "+content/public/utility", "+sandbox", ]
diff --git a/extensions/shell/app/shell_main_delegate.cc b/extensions/shell/app/shell_main_delegate.cc index 823dbfc5..42c0f22 100644 --- a/extensions/shell/app/shell_main_delegate.cc +++ b/extensions/shell/app/shell_main_delegate.cc
@@ -12,13 +12,13 @@ #include "components/nacl/common/buildflags.h" #include "content/public/browser/browser_main_runner.h" #include "content/public/common/content_switches.h" +#include "content/public/utility/content_utility_client.h" #include "content/shell/common/shell_switches.h" #include "extensions/common/extension_paths.h" #include "extensions/shell/browser/default_shell_browser_main_delegate.h" #include "extensions/shell/browser/shell_content_browser_client.h" #include "extensions/shell/common/shell_content_client.h" #include "extensions/shell/renderer/shell_content_renderer_client.h" -#include "extensions/shell/utility/shell_content_utility_client.h" #include "ui/base/resource/resource_bundle.h" #if defined(OS_CHROMEOS) @@ -168,11 +168,6 @@ return renderer_client_.get(); } -content::ContentUtilityClient* ShellMainDelegate::CreateContentUtilityClient() { - utility_client_.reset(CreateShellContentUtilityClient()); - return utility_client_.get(); -} - void ShellMainDelegate::ProcessExiting(const std::string& process_type) { logging::CloseLogFile(); } @@ -202,7 +197,7 @@ content::ContentUtilityClient* ShellMainDelegate::CreateShellContentUtilityClient() { - return new ShellContentUtilityClient(); + return new content::ContentUtilityClient(); } void ShellMainDelegate::InitializeResourceBundle() {
diff --git a/extensions/shell/app/shell_main_delegate.h b/extensions/shell/app/shell_main_delegate.h index 1f005c6..c43f620 100644 --- a/extensions/shell/app/shell_main_delegate.h +++ b/extensions/shell/app/shell_main_delegate.h
@@ -31,7 +31,6 @@ void PreSandboxStartup() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentRendererClient* CreateContentRendererClient() override; - content::ContentUtilityClient* CreateContentUtilityClient() override; void ProcessExiting(const std::string& process_type) override; #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) void ZygoteStarting(std::vector<std::unique_ptr<content::ZygoteForkDelegate>>*
diff --git a/extensions/shell/browser/api/runtime/runtime_apitest.cc b/extensions/shell/browser/api/runtime/runtime_apitest.cc new file mode 100644 index 0000000..c1f0507 --- /dev/null +++ b/extensions/shell/browser/api/runtime/runtime_apitest.cc
@@ -0,0 +1,80 @@ +// Copyright 2018 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 "extensions/browser/browsertest_util.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/test_extension_registry_observer.h" +#include "extensions/common/extension_id.h" +#include "extensions/shell/browser/shell_extension_system.h" +#include "extensions/shell/test/shell_apitest.h" +#include "extensions/test/result_catcher.h" + +namespace extensions { + +using ShellRuntimeApiTest = ShellApiTest; + +IN_PROC_BROWSER_TEST_F(ShellRuntimeApiTest, RuntimeReload) { + const Extension* extension = nullptr; + + // Load the extension and wait for it to be ready. + { + ResultCatcher catcher; + ASSERT_TRUE(extension = LoadExtension("extension")); + ASSERT_TRUE(catcher.GetNextResult()); + } + + const ExtensionId extension_id = extension->id(); + ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context()); + + // Reload the extension and wait for a pair of + // ExtensionRegistry::OnExtensionUnloaded()/Loaded() calls. + TestExtensionRegistryObserver registry_observer(registry, extension_id); + ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait( + browser_context(), extension_id, "chrome.runtime.reload();")); + ASSERT_EQ(extension, registry_observer.WaitForExtensionUnloaded()); + EXPECT_TRUE(registry->disabled_extensions().Contains(extension_id)); + ASSERT_TRUE(extension = registry_observer.WaitForExtensionLoaded()); + ASSERT_EQ(extension->id(), extension_id); + EXPECT_TRUE(registry->enabled_extensions().Contains(extension_id)); + + // Wait for the background page to load. + { + ResultCatcher catcher; + ASSERT_TRUE(catcher.GetNextResult()); + } +} + +IN_PROC_BROWSER_TEST_F(ShellRuntimeApiTest, RuntimeReloadApp) { + const Extension* extension = nullptr; + + // Load and launch the app and wait for it to create a window. + { + ResultCatcher catcher; + extension = LoadApp("platform_app"); + ASSERT_TRUE(catcher.GetNextResult()); + } + + const ExtensionId extension_id = extension->id(); + ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context()); + + // Reload the extension and wait for a pair of + // ExtensionRegistry::OnExtensionUnloaded()/Loaded() calls. + TestExtensionRegistryObserver registry_observer(registry, extension_id); + ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait( + browser_context(), extension_id, "chrome.runtime.reload();")); + ASSERT_EQ(extension, registry_observer.WaitForExtensionUnloaded()); + EXPECT_TRUE(registry->disabled_extensions().Contains(extension_id)); + ASSERT_TRUE(extension = registry_observer.WaitForExtensionLoaded()); + ASSERT_EQ(extension->id(), extension_id); + EXPECT_TRUE(registry->enabled_extensions().Contains(extension_id)); + + // Reloading the app should launch it again automatically. + // Wait for the app to create a new window. + { + ResultCatcher catcher; + ASSERT_TRUE(catcher.GetNextResult()); + } +} + +} // namespace extensions
diff --git a/extensions/shell/browser/shell_runtime_api_delegate.cc b/extensions/shell/browser/api/runtime/shell_runtime_api_delegate.cc similarity index 75% rename from extensions/shell/browser/shell_runtime_api_delegate.cc rename to extensions/shell/browser/api/runtime/shell_runtime_api_delegate.cc index 9824e0f..d6e61de 100644 --- a/extensions/shell/browser/shell_runtime_api_delegate.cc +++ b/extensions/shell/browser/api/runtime/shell_runtime_api_delegate.cc
@@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "extensions/shell/browser/shell_runtime_api_delegate.h" +#include "extensions/shell/browser/api/runtime/shell_runtime_api_delegate.h" #include "build/build_config.h" #include "extensions/common/api/runtime.h" +#include "extensions/shell/browser/shell_extension_system.h" #if defined(OS_CHROMEOS) #include "chromeos/dbus/dbus_thread_manager.h" @@ -17,19 +18,21 @@ namespace extensions { -ShellRuntimeAPIDelegate::ShellRuntimeAPIDelegate() { +ShellRuntimeAPIDelegate::ShellRuntimeAPIDelegate( + content::BrowserContext* browser_context) + : browser_context_(browser_context) { + DCHECK(browser_context_); } -ShellRuntimeAPIDelegate::~ShellRuntimeAPIDelegate() { -} +ShellRuntimeAPIDelegate::~ShellRuntimeAPIDelegate() = default; -void ShellRuntimeAPIDelegate::AddUpdateObserver(UpdateObserver* observer) { -} +void ShellRuntimeAPIDelegate::AddUpdateObserver(UpdateObserver* observer) {} -void ShellRuntimeAPIDelegate::RemoveUpdateObserver(UpdateObserver* observer) { -} +void ShellRuntimeAPIDelegate::RemoveUpdateObserver(UpdateObserver* observer) {} void ShellRuntimeAPIDelegate::ReloadExtension(const std::string& extension_id) { + static_cast<ShellExtensionSystem*>(ExtensionSystem::Get(browser_context_)) + ->ReloadExtension(extension_id); } bool ShellRuntimeAPIDelegate::CheckForUpdates( @@ -38,8 +41,7 @@ return false; } -void ShellRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) { -} +void ShellRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) {} bool ShellRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) { #if defined(OS_CHROMEOS)
diff --git a/extensions/shell/browser/shell_runtime_api_delegate.h b/extensions/shell/browser/api/runtime/shell_runtime_api_delegate.h similarity index 70% rename from extensions/shell/browser/shell_runtime_api_delegate.h rename to extensions/shell/browser/api/runtime/shell_runtime_api_delegate.h index 92a5c3cd..1691ce34 100644 --- a/extensions/shell/browser/shell_runtime_api_delegate.h +++ b/extensions/shell/browser/api/runtime/shell_runtime_api_delegate.h
@@ -2,17 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ -#define EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ +#ifndef EXTENSIONS_SHELL_BROWSER_API_RUNTIME_SHELL_RUNTIME_API_DELEGATE_H_ +#define EXTENSIONS_SHELL_BROWSER_API_RUNTIME_SHELL_RUNTIME_API_DELEGATE_H_ #include "base/macros.h" #include "extensions/browser/api/runtime/runtime_api_delegate.h" +namespace content { +class BrowserContext; +} // namespace content + namespace extensions { class ShellRuntimeAPIDelegate : public RuntimeAPIDelegate { public: - ShellRuntimeAPIDelegate(); + explicit ShellRuntimeAPIDelegate(content::BrowserContext* browser_context); ~ShellRuntimeAPIDelegate() override; // RuntimeAPIDelegate implementation. @@ -26,9 +30,11 @@ bool RestartDevice(std::string* error_message) override; private: + content::BrowserContext* browser_context_; + DISALLOW_COPY_AND_ASSIGN(ShellRuntimeAPIDelegate); }; } // namespace extensions -#endif // EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ +#endif // EXTENSIONS_SHELL_BROWSER_API_RUNTIME_SHELL_RUNTIME_API_DELEGATE_H_
diff --git a/extensions/shell/browser/shell_browsertest.cc b/extensions/shell/browser/shell_browsertest.cc index 2a82867..cbd127e 100644 --- a/extensions/shell/browser/shell_browsertest.cc +++ b/extensions/shell/browser/shell_browsertest.cc
@@ -2,10 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/logging.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/web_contents.h" -#include "content/public/test/test_utils.h" #include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/app_window_registry.h" #include "extensions/browser/notification_types.h"
diff --git a/extensions/shell/browser/shell_desktop_controller_aura.cc b/extensions/shell/browser/shell_desktop_controller_aura.cc index 21fb9f3..934ae5e8 100644 --- a/extensions/shell/browser/shell_desktop_controller_aura.cc +++ b/extensions/shell/browser/shell_desktop_controller_aura.cc
@@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" +#include "components/keep_alive_registry/keep_alive_registry.h" #include "extensions/shell/browser/shell_app_window_client.h" #include "ui/aura/client/cursor_client.h" #include "ui/aura/window.h" @@ -161,10 +162,15 @@ } void ShellDesktopControllerAura::Run() { + KeepAliveRegistry::GetInstance()->AddObserver(this); + base::RunLoop run_loop; run_loop_ = &run_loop; run_loop.Run(); run_loop_ = nullptr; + + KeepAliveRegistry::GetInstance()->SetIsShuttingDown(true); + KeepAliveRegistry::GetInstance()->RemoveObserver(this); } void ShellDesktopControllerAura::AddAppWindow(AppWindow* app_window, @@ -198,9 +204,7 @@ TearDownRootWindowController(it->second.get()); root_window_controllers_.erase(it); - // run_loop_ may be null in tests. - if (run_loop_ && root_window_controllers_.empty()) - run_loop_->QuitWhenIdle(); + MaybeQuit(); } #if defined(OS_CHROMEOS) @@ -234,6 +238,15 @@ return GetPrimaryHost()->DispatchKeyEventPostIME(key_event); } +void ShellDesktopControllerAura::OnKeepAliveStateChanged( + bool is_keeping_alive) { + if (!is_keeping_alive) + MaybeQuit(); +} + +void ShellDesktopControllerAura::OnKeepAliveRestartStateChanged( + bool can_restart) {} + aura::WindowTreeHost* ShellDesktopControllerAura::GetPrimaryHost() { if (root_window_controllers_.empty()) return nullptr; @@ -337,6 +350,19 @@ root->host()->window()->RemovePreTargetHandler(focus_controller_.get()); } +void ShellDesktopControllerAura::MaybeQuit() { + // run_loop_ may be null in tests. + if (!run_loop_) + return; + + // Quit if there are no app windows open and no keep-alives waiting for apps + // to relaunch. + if (root_window_controllers_.empty() && + !KeepAliveRegistry::GetInstance()->IsKeepingAlive()) { + run_loop_->QuitWhenIdle(); + } +} + #if defined(OS_CHROMEOS) gfx::Size ShellDesktopControllerAura::GetStartingWindowSize() { gfx::Size size;
diff --git a/extensions/shell/browser/shell_desktop_controller_aura.h b/extensions/shell/browser/shell_desktop_controller_aura.h index bc6abf7b..34718f20 100644 --- a/extensions/shell/browser/shell_desktop_controller_aura.h +++ b/extensions/shell/browser/shell_desktop_controller_aura.h
@@ -11,6 +11,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "build/build_config.h" +#include "components/keep_alive_registry/keep_alive_state_observer.h" #include "extensions/shell/browser/desktop_controller.h" #include "extensions/shell/browser/root_window_controller.h" #include "ui/aura/window.h" @@ -69,7 +70,8 @@ public chromeos::PowerManagerClient::Observer, public display::DisplayConfigurator::Observer, #endif - public ui::internal::InputMethodDelegate { + public ui::internal::InputMethodDelegate, + public KeepAliveStateObserver { public: explicit ShellDesktopControllerAura(content::BrowserContext* browser_context); ~ShellDesktopControllerAura() override; @@ -84,19 +86,23 @@ RootWindowController* root_window_controller) override; #if defined(OS_CHROMEOS) - // chromeos::PowerManagerClient::Observer overrides: + // chromeos::PowerManagerClient::Observer: void PowerButtonEventReceived(bool down, const base::TimeTicks& timestamp) override; - // display::DisplayConfigurator::Observer overrides. + // display::DisplayConfigurator::Observer: void OnDisplayModeChanged( const display::DisplayConfigurator::DisplayStateList& displays) override; #endif - // ui::internal::InputMethodDelegate overrides: + // ui::internal::InputMethodDelegate: ui::EventDispatchDetails DispatchKeyEventPostIME( ui::KeyEvent* key_event) override; + // KeepAliveStateObserver: + void OnKeepAliveStateChanged(bool is_keeping_alive) override; + void OnKeepAliveRestartStateChanged(bool can_restart) override; + // Returns the WindowTreeHost for the primary display. aura::WindowTreeHost* GetPrimaryHost(); @@ -119,6 +125,10 @@ // Removes handlers from the RootWindowController so it can be destroyed. void TearDownRootWindowController(RootWindowController* root); + // Quits if there are no app windows, and no keep-alives waiting for apps to + // relaunch. + void MaybeQuit(); + #if defined(OS_CHROMEOS) // Returns the desired dimensions of the RootWindowController from the command // line, or falls back to a default size.
diff --git a/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc b/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc new file mode 100644 index 0000000..96637946 --- /dev/null +++ b/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc
@@ -0,0 +1,178 @@ +// Copyright 2018 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 "extensions/shell/browser/shell_desktop_controller_aura.h" + +#include "base/macros.h" +#include "base/task_scheduler/post_task.h" +#include "base/test/bind_test_util.h" +#include "base/time/time.h" +#include "components/keep_alive_registry/keep_alive_registry.h" +#include "extensions/browser/app_window/app_window.h" +#include "extensions/browser/app_window/app_window_registry.h" +#include "extensions/browser/browsertest_util.h" +#include "extensions/shell/browser/desktop_controller.h" +#include "extensions/shell/test/shell_apitest.h" +#include "extensions/test/result_catcher.h" + +namespace extensions { + +// Tests that spin up the ShellDesktopControllerAura and run async tasks like +// launching and reloading apps. +class ShellDesktopControllerAuraBrowserTest : public ShellApiTest { + public: + ShellDesktopControllerAuraBrowserTest() = default; + ~ShellDesktopControllerAuraBrowserTest() override = default; + + // Loads and launches a platform app that opens an app window. + void LoadAndLaunchApp() { + ASSERT_FALSE(app_); + app_ = LoadApp("platform_app"); + ASSERT_TRUE(app_); + + // Wait for app window to load. + ResultCatcher catcher; + EXPECT_TRUE(catcher.GetNextResult()); + + // A window was created. + EXPECT_EQ(1u, + AppWindowRegistry::Get(browser_context())->app_windows().size()); + } + + protected: + // Returns an open app window. + AppWindow* GetAppWindow() { + EXPECT_GT(AppWindowRegistry::Get(browser_context())->app_windows().size(), + 0u); + return AppWindowRegistry::Get(browser_context())->app_windows().front(); + } + + // ShellApiTest: + void SetUpOnMainThread() override { + ShellApiTest::SetUpOnMainThread(); + desktop_controller_ = + static_cast<ShellDesktopControllerAura*>(DesktopController::instance()); + ASSERT_TRUE(desktop_controller_); + } + + void TearDownOnMainThread() override { + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); + ShellApiTest::TearDownOnMainThread(); + } + + ShellDesktopControllerAura* desktop_controller_ = nullptr; + scoped_refptr<const Extension> app_; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellDesktopControllerAuraBrowserTest); +}; + +// Test that closing the app window stops the DesktopController. +IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, CloseAppWindow) { + bool test_succeeded = false; + + // Post a task so everything runs after the DesktopController starts. + base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply( + FROM_HERE, + // Asynchronously launch the app. + base::BindOnce(&ShellDesktopControllerAuraBrowserTest::LoadAndLaunchApp, + base::Unretained(this)), + + // Once the app launches, run the test. + base::BindLambdaForTesting([this, &test_succeeded]() { + // Close the app window so DesktopController quits. + GetAppWindow()->OnNativeClose(); + test_succeeded = true; + })); + + // Start DesktopController. It should run until the last app window closes. + desktop_controller_->Run(); + EXPECT_TRUE(test_succeeded) + << "DesktopController quit before test completed."; +} + +// Test that the DesktopController runs until all app windows close. +IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, TwoAppWindows) { + bool test_succeeded = false; + + // Post a task so everything runs after the DesktopController starts. + base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply( + FROM_HERE, + // Asynchronously launch the app. + base::BindOnce(&ShellDesktopControllerAuraBrowserTest::LoadAndLaunchApp, + base::Unretained(this)), + + // Once the app launches, run the test. + base::BindLambdaForTesting([this, &test_succeeded]() { + // Create a second app window. + ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait( + browser_context(), app_->id(), + "chrome.app.window.create('/hello.html');")); + ResultCatcher catcher; + catcher.GetNextResult(); + + // Close the first app window. + GetAppWindow()->OnNativeClose(); + + // One window is still open, so the DesktopController should still be + // running. Post a task to close the last window. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::BindLambdaForTesting([this, &test_succeeded]() { + GetAppWindow()->OnNativeClose(); + test_succeeded = true; + }), + // A regression might cause DesktopController to quit before the + // last window closes. To ensure we catch this, wait a while before + // closing the last window. If DesktopController::Run() finishes + // before we close the last window and update |test_succeeded|, the + // test fails. + base::TimeDelta::FromMilliseconds(500)); + })); + + desktop_controller_->Run(); + EXPECT_TRUE(test_succeeded) + << "DesktopController quit before test completed."; +} + +// Test that the DesktopController stays open while an app reloads, even though +// the app window closes. +IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, ReloadApp) { + bool test_succeeded = false; + + // Post a task so everything runs after the DesktopController starts. + base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply( + FROM_HERE, + // Asynchronously launch the app. + base::BindOnce(&ShellDesktopControllerAuraBrowserTest::LoadAndLaunchApp, + base::Unretained(this)), + + // Once the app launches, run the test. + base::BindLambdaForTesting([this, &test_succeeded]() { + // Reload the app. + ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait( + browser_context(), app_->id(), "chrome.runtime.reload();")); + + // Wait for the app window to re-open. + ResultCatcher catcher; + ASSERT_TRUE(catcher.GetNextResult()); + + // Close the new window after a delay. DesktopController should remain + // open until the window closes. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::BindLambdaForTesting([this, &test_succeeded]() { + AppWindow* app_window = AppWindowRegistry::Get(browser_context()) + ->app_windows() + .front(); + app_window->OnNativeClose(); + test_succeeded = true; + }), + base::TimeDelta::FromMilliseconds(500)); + })); + + desktop_controller_->Run(); + EXPECT_TRUE(test_succeeded) + << "DesktopController quit before test completed."; +} + +} // namespace extensions
diff --git a/extensions/shell/browser/shell_extension_loader_unittest.cc b/extensions/shell/browser/shell_extension_loader_unittest.cc index a28a6eb..92f1fe1 100644 --- a/extensions/shell/browser/shell_extension_loader_unittest.cc +++ b/extensions/shell/browser/shell_extension_loader_unittest.cc
@@ -12,7 +12,6 @@ #include "base/path_service.h" #include "components/crx_file/id_util.h" #include "components/keep_alive_registry/keep_alive_registry.h" -#include "components/prefs/testing_pref_service.h" #include "components/user_prefs/user_prefs.h" #include "content/public/browser/browser_context.h" #include "content/public/test/test_utils.h" @@ -95,7 +94,9 @@ ExtensionsTest::SetUp(); extensions_browser_client()->set_extension_system_factory(&factory_); - user_prefs::UserPrefs::Set(browser_context(), &testing_pref_service_); + // ExtensionsTest sets up the ExtensionPrefs, but we still need to attach + // the PrefService to the browser context. + user_prefs::UserPrefs::Set(browser_context(), pref_service()); event_router_ = CreateAndUseTestEventRouter(browser_context()); } @@ -135,7 +136,6 @@ private: MockExtensionSystemFactory<TestExtensionSystem> factory_; - TestingPrefServiceSimple testing_pref_service_; TestEventRouter* event_router_ = nullptr; // Created in SetUp().
diff --git a/extensions/shell/browser/shell_extension_system.cc b/extensions/shell/browser/shell_extension_system.cc index 3bdb3b3..5a176319a 100644 --- a/extensions/shell/browser/shell_extension_system.cc +++ b/extensions/shell/browser/shell_extension_system.cc
@@ -70,6 +70,10 @@ apps::LaunchPlatformApp(browser_context_, extension, SOURCE_UNTRACKED); } +void ShellExtensionSystem::ReloadExtension(const ExtensionId& extension_id) { + extension_loader_->ReloadExtension(extension_id); +} + void ShellExtensionSystem::Shutdown() { extension_loader_.reset(); }
diff --git a/extensions/shell/browser/shell_extension_system.h b/extensions/shell/browser/shell_extension_system.h index b25e58b..b69a1a3c 100644 --- a/extensions/shell/browser/shell_extension_system.h +++ b/extensions/shell/browser/shell_extension_system.h
@@ -52,6 +52,9 @@ // Launch the app with id |extension_id|. void LaunchApp(const ExtensionId& extension_id); + // Reloads the extension with id |extension_id|. + void ReloadExtension(const ExtensionId& extension_id); + // KeyedService implementation: void Shutdown() override;
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc index f21f331..587f57b 100644 --- a/extensions/shell/browser/shell_extensions_browser_client.cc +++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -23,13 +23,13 @@ #include "extensions/browser/url_request_util.h" #include "extensions/common/features/feature_channel.h" #include "extensions/shell/browser/api/generated_api_registration.h" +#include "extensions/shell/browser/api/runtime/shell_runtime_api_delegate.h" #include "extensions/shell/browser/delegates/shell_kiosk_delegate.h" #include "extensions/shell/browser/shell_extension_host_delegate.h" #include "extensions/shell/browser/shell_extension_system_factory.h" #include "extensions/shell/browser/shell_extension_web_contents_observer.h" #include "extensions/shell/browser/shell_extensions_api_client.h" #include "extensions/shell/browser/shell_navigation_ui_data.h" -#include "extensions/shell/browser/shell_runtime_api_delegate.h" #if defined(OS_CHROMEOS) #include "chromeos/login/login_state.h" @@ -229,7 +229,7 @@ std::unique_ptr<RuntimeAPIDelegate> ShellExtensionsBrowserClient::CreateRuntimeAPIDelegate( content::BrowserContext* context) const { - return std::make_unique<ShellRuntimeAPIDelegate>(); + return std::make_unique<ShellRuntimeAPIDelegate>(context); } const ComponentExtensionResourceManager*
diff --git a/extensions/shell/utility/DEPS b/extensions/shell/utility/DEPS deleted file mode 100644 index 8ad521e..0000000 --- a/extensions/shell/utility/DEPS +++ /dev/null
@@ -1,3 +0,0 @@ -include_rules = [ - "+content/public/utility", -]
diff --git a/extensions/shell/utility/shell_content_utility_client.cc b/extensions/shell/utility/shell_content_utility_client.cc deleted file mode 100644 index 75d72622..0000000 --- a/extensions/shell/utility/shell_content_utility_client.cc +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "extensions/shell/utility/shell_content_utility_client.h" - -namespace extensions { - -ShellContentUtilityClient::ShellContentUtilityClient() = default; - -ShellContentUtilityClient::~ShellContentUtilityClient() = default; - -void ShellContentUtilityClient::UtilityThreadStarted() { - utility_handler::UtilityThreadStarted(); -} - -} // namespace extensions
diff --git a/extensions/shell/utility/shell_content_utility_client.h b/extensions/shell/utility/shell_content_utility_client.h deleted file mode 100644 index 4baaf17..0000000 --- a/extensions/shell/utility/shell_content_utility_client.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef EXTENSIONS_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_ -#define EXTENSIONS_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_ - -#include "content/public/utility/content_utility_client.h" -#include "extensions/utility/utility_handler.h" - -namespace extensions { - -class ShellContentUtilityClient : public content::ContentUtilityClient { - public: - ShellContentUtilityClient(); - ~ShellContentUtilityClient() override; - - // content::ContentUtilityClient: - void UtilityThreadStarted() override; -}; - -} // namespace extensions - -#endif // EXTENSIONS_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_
diff --git a/extensions/strings/extensions_strings.grd b/extensions/strings/extensions_strings.grd index f3ea305..0fe77a51d 100644 --- a/extensions/strings/extensions_strings.grd +++ b/extensions/strings/extensions_strings.grd
@@ -385,17 +385,6 @@ Shaped windows are not supported. </message> </if> - - <!-- Utility process names. Please keep alphabetized. --> - <message name="IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME" desc="The name of the utility process used for unpacking extensions."> - Extension Unpacker - </message> - <message name="IDS_UTILITY_PROCESS_MANIFEST_PARSER_NAME" desc="The name of the utility process used for parsing extension manifests."> - Extension Manifest Parser - </message> - <message name="IDS_UTILITY_PROCESS_ZIP_FILE_INSTALLER_NAME" desc="The name of the utility process used for unpacking zip files."> - Zip File Installer - </message> </messages> </release> </grit>
diff --git a/extensions/test/test_content_utility_client.cc b/extensions/test/test_content_utility_client.cc index 10c2c16..69895ce 100644 --- a/extensions/test/test_content_utility_client.cc +++ b/extensions/test/test_content_utility_client.cc
@@ -17,10 +17,7 @@ TestContentUtilityClient::~TestContentUtilityClient() = default; void TestContentUtilityClient::UtilityThreadStarted() { - utility_handler::UtilityThreadStarted(); - auto registry = std::make_unique<service_manager::BinderRegistry>(); - utility_handler::ExposeInterfacesToBrowser(registry.get(), false); content::ChildThread::Get() ->GetServiceManagerConnection() ->AddConnectionFilter(std::make_unique<content::SimpleConnectionFilter>(
diff --git a/extensions/test/test_content_utility_client.h b/extensions/test/test_content_utility_client.h index 18531eb..b2edbd6b 100644 --- a/extensions/test/test_content_utility_client.h +++ b/extensions/test/test_content_utility_client.h
@@ -6,7 +6,6 @@ #define EXTENSIONS_TEST_TEST_CONTENT_UTILITY_CLIENT_H_ #include "content/public/utility/content_utility_client.h" -#include "extensions/utility/utility_handler.h" namespace extensions {
diff --git a/extensions/utility/BUILD.gn b/extensions/utility/BUILD.gn deleted file mode 100644 index de71ac1..0000000 --- a/extensions/utility/BUILD.gn +++ /dev/null
@@ -1,42 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build/config/features.gni") -import("//extensions/buildflags/buildflags.gni") - -assert(enable_extensions) - -source_set("utility") { - sources = [ - "utility_handler.cc", - "utility_handler.h", - ] - - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - - deps = [ - "//content/public/common", - "//content/public/utility", - "//extensions/common", - "//skia", - ] -} - -source_set("unit_tests") { - testonly = true - sources = [ - "utility_handler_unittest.cc", - ] - deps = [ - ":utility", - "//base", - "//extensions:test_support", - "//extensions/common", - "//extensions/strings", - "//testing/gtest", - "//third_party/zlib/google:zip", - "//ui/base", - ] -}
diff --git a/extensions/utility/DEPS b/extensions/utility/DEPS deleted file mode 100644 index 48d2f8d..0000000 --- a/extensions/utility/DEPS +++ /dev/null
@@ -1,6 +0,0 @@ -include_rules = [ - "+content/public/utility", - "+content/public/child", - "+net", - "+third_party/zlib/google", -]
diff --git a/extensions/utility/utility_handler.cc b/extensions/utility/utility_handler.cc deleted file mode 100644 index 40d7116e..0000000 --- a/extensions/utility/utility_handler.cc +++ /dev/null
@@ -1,182 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "extensions/utility/utility_handler.h" - -#include <memory> -#include <string> -#include <utility> - -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/json/json_file_value_serializer.h" -#include "base/location.h" -#include "base/task_scheduler/post_task.h" -#include "content/public/utility/utility_thread.h" -#include "extensions/common/constants.h" -#include "extensions/common/extension_l10n_util.h" -#include "extensions/common/extension_unpacker.mojom.h" -#include "extensions/common/extensions_client.h" -#include "extensions/common/features/feature_channel.h" -#include "extensions/common/features/feature_session_type.h" -#include "extensions/common/manifest.h" -#include "extensions/common/manifest_constants.h" -#include "extensions/strings/grit/extensions_strings.h" -#include "mojo/public/cpp/bindings/strong_binding.h" -#include "third_party/zlib/google/zip.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/ui_base_switches.h" - -namespace extensions { - -namespace { - -constexpr const base::FilePath::CharType* kAllowedThemeFiletypes[] = { - FILE_PATH_LITERAL(".bmp"), FILE_PATH_LITERAL(".gif"), - FILE_PATH_LITERAL(".jpeg"), FILE_PATH_LITERAL(".jpg"), - FILE_PATH_LITERAL(".json"), FILE_PATH_LITERAL(".png"), - FILE_PATH_LITERAL(".webp")}; - -std::unique_ptr<base::DictionaryValue> ReadManifest( - const base::FilePath& extension_dir, - std::string* error) { - DCHECK(error); - base::FilePath manifest_path = extension_dir.Append(kManifestFilename); - if (!base::PathExists(manifest_path)) { - *error = manifest_errors::kInvalidManifest; - return nullptr; - } - - JSONFileValueDeserializer deserializer(manifest_path); - std::unique_ptr<base::Value> root = deserializer.Deserialize(NULL, error); - if (!root) { - return nullptr; - } - - if (!root->is_dict()) { - *error = manifest_errors::kInvalidManifest; - return nullptr; - } - - return base::DictionaryValue::From(std::move(root)); -} - -class ExtensionUnpackerImpl : public extensions::mojom::ExtensionUnpacker { - public: - ExtensionUnpackerImpl() = default; - ~ExtensionUnpackerImpl() override = default; - - static void Create(extensions::mojom::ExtensionUnpackerRequest request) { - mojo::MakeStrongBinding(std::make_unique<ExtensionUnpackerImpl>(), - std::move(request)); - } - - private: - // extensions::mojom::ExtensionUnpacker: - void Unzip(const base::FilePath& file, - const base::FilePath& path, - UnzipCallback callback) override { - // Move unzip operation to background thread to avoid blocking the main - // utility thread for extended amont of time. For example, this prevents - // extension unzipping block receipt of the connection complete - // notification for the utility process channel to the browser process, - // which could cause the utility process to terminate itself due to browser - // process being considered unreachable. - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, - {base::TaskPriority::USER_BLOCKING, base::MayBlock(), - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, - base::BindOnce(&ExtensionUnpackerImpl::UnzipOnBackgroundTaskRunner, - file, path), - std::move(callback)); - } - - static bool UnzipFileManifestIntoPath( - const base::FilePath& file, - const base::FilePath& path, - std::unique_ptr<base::DictionaryValue>* manifest) { - if (zip::UnzipWithFilterCallback( - file, path, base::BindRepeating(&utility_handler::IsManifestFile), - false)) { - std::string error; - *manifest = ReadManifest(path, &error); - return error.empty() && manifest->get(); - } - - return false; - } - - static bool UnzipFileIntoPath( - const base::FilePath& file, - const base::FilePath& path, - std::unique_ptr<base::DictionaryValue> manifest) { - Manifest internal(Manifest::INTERNAL, std::move(manifest)); - // TODO(crbug.com/645263): This silently ignores blocked file types. - // Add install warnings. - return zip::UnzipWithFilterCallback( - file, path, - base::BindRepeating(&utility_handler::ShouldExtractFile, - internal.is_theme()), - true /* log_skipped_files */); - } - - // Unzips the extension from |file| to |path|. - // Returns whether the unzip operation succeeded. - static bool UnzipOnBackgroundTaskRunner(const base::FilePath& file, - const base::FilePath& path) { - std::unique_ptr<base::DictionaryValue> manifest; - if (!UnzipFileManifestIntoPath(file, path, &manifest)) - return false; - - return UnzipFileIntoPath(file, path, std::move(manifest)); - } - - DISALLOW_COPY_AND_ASSIGN(ExtensionUnpackerImpl); -}; - -} // namespace - -namespace utility_handler { - -void UtilityThreadStarted() { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - std::string lang = command_line->GetSwitchValueASCII(switches::kLang); - if (!lang.empty()) - extension_l10n_util::SetProcessLocale(lang); -} - -void ExposeInterfacesToBrowser(service_manager::BinderRegistry* registry, - bool running_elevated) { - // If our process runs with elevated privileges, only add elevated Mojo - // interfaces to the interface registry. - if (running_elevated) - return; - - registry->AddInterface(base::Bind(&ExtensionUnpackerImpl::Create), - base::ThreadTaskRunnerHandle::Get()); -} - -bool ShouldExtractFile(bool is_theme, const base::FilePath& file_path) { - if (is_theme) { - const base::FilePath::StringType extension = - base::ToLowerASCII(file_path.FinalExtension()); - // Allow filenames with no extension. - if (extension.empty()) - return true; - return base::ContainsValue(kAllowedThemeFiletypes, extension); - } - return !base::FilePath::CompareEqualIgnoreCase(file_path.FinalExtension(), - FILE_PATH_LITERAL(".exe")); -} - -bool IsManifestFile(const base::FilePath& file_path) { - CHECK(!file_path.IsAbsolute()); - return base::FilePath::CompareEqualIgnoreCase(file_path.value(), - kManifestFilename); -} - -} // namespace utility_handler - -} // namespace extensions
diff --git a/extensions/utility/utility_handler.h b/extensions/utility/utility_handler.h deleted file mode 100644 index 7a361d9..0000000 --- a/extensions/utility/utility_handler.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef EXTENSIONS_UTILITY_UTILITY_HANDLER_H_ -#define EXTENSIONS_UTILITY_UTILITY_HANDLER_H_ - -#include "services/service_manager/public/cpp/binder_registry.h" - -namespace base { -class FilePath; -} - -namespace extensions { - -namespace utility_handler { - -void UtilityThreadStarted(); - -void ExposeInterfacesToBrowser(service_manager::BinderRegistry* registry, - bool running_elevated); - -bool ShouldExtractFile(bool is_theme, const base::FilePath& file_path); - -bool IsManifestFile(const base::FilePath& file_path); - -} // namespace utility_handler - -} // namespace extensions - -#endif // EXTENSIONS_UTILITY_UTILITY_HANDLER_H_
diff --git a/extensions/utility/utility_handler_unittest.cc b/extensions/utility/utility_handler_unittest.cc deleted file mode 100644 index db2c0293..0000000 --- a/extensions/utility/utility_handler_unittest.cc +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2018 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 <vector> - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "extensions/utility/utility_handler.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace extensions { - -using UtilityHandlerTest = testing::Test; - -struct UnzipFileFilterTestCase { - const base::FilePath::CharType* input; - const bool should_unzip; -}; - -void RunZipFileFilterTest( - const std::vector<UnzipFileFilterTestCase>& cases, - base::RepeatingCallback<bool(const base::FilePath&)>& filter) { - for (size_t i = 0; i < cases.size(); ++i) { - base::FilePath input(cases[i].input); - bool observed = filter.Run(input); - EXPECT_EQ(cases[i].should_unzip, observed) - << "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(UtilityHandlerTest, NonTheme_FileExtractionFilter) { - const std::vector<UnzipFileFilterTestCase> cases = { - {FILE_PATH_LITERAL("foo"), true}, - {FILE_PATH_LITERAL("foo.nexe"), true}, - {FILE_PATH_LITERAL("foo.dll"), true}, - {FILE_PATH_LITERAL("foo.jpg.exe"), false}, - {FILE_PATH_LITERAL("foo.exe"), false}, - {FILE_PATH_LITERAL("foo.EXE"), false}, - {FILE_PATH_LITERAL("file_without_extension"), true}, - }; - base::RepeatingCallback<bool(const base::FilePath&)> filter = - base::BindRepeating(&utility_handler::ShouldExtractFile, false); - RunZipFileFilterTest(cases, filter); -} - -TEST_F(UtilityHandlerTest, Theme_FileExtractionFilter) { - const std::vector<UnzipFileFilterTestCase> cases = { - {FILE_PATH_LITERAL("image.jpg"), true}, - {FILE_PATH_LITERAL("IMAGE.JPEG"), true}, - {FILE_PATH_LITERAL("test/image.bmp"), true}, - {FILE_PATH_LITERAL("test/IMAGE.gif"), true}, - {FILE_PATH_LITERAL("test/image.WEBP"), true}, - {FILE_PATH_LITERAL("test/dir/file.image.png"), true}, - {FILE_PATH_LITERAL("manifest.json"), true}, - {FILE_PATH_LITERAL("other.html"), false}, - {FILE_PATH_LITERAL("file_without_extension"), true}, - }; - base::RepeatingCallback<bool(const base::FilePath&)> filter = - base::BindRepeating(&utility_handler::ShouldExtractFile, true); - RunZipFileFilterTest(cases, filter); -} - -TEST_F(UtilityHandlerTest, ManifestExtractionFilter) { - const std::vector<UnzipFileFilterTestCase> cases = { - {FILE_PATH_LITERAL("manifest.json"), true}, - {FILE_PATH_LITERAL("MANIFEST.JSON"), true}, - {FILE_PATH_LITERAL("test/manifest.json"), false}, - {FILE_PATH_LITERAL("manifest.json/test"), false}, - {FILE_PATH_LITERAL("other.file"), false}, - }; - base::RepeatingCallback<bool(const base::FilePath&)> filter = - base::BindRepeating(&utility_handler::IsManifestFile); - RunZipFileFilterTest(cases, filter); -} - -} // namespace extensions
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc index bbe2c33a..5908c49e 100644 --- a/gpu/command_buffer/service/buffer_manager.cc +++ b/gpu/command_buffer/service/buffer_manager.cc
@@ -129,6 +129,8 @@ size_(0), deleted_(false), is_client_side_array_(false), + binding_count_(0), + transform_feedback_binding_count_(0), service_id_(service_id), initial_target_(0), usage_(GL_STATIC_DRAW) { @@ -427,12 +429,19 @@ return; } + if (buffer->IsBoundForTransformFeedbackAndOther()) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, "glBufferData", + "buffer is bound for transform feedback and other use simultaneously"); + return; + } + DoBufferData(error_state, buffer, target, size, usage, data); if (context_state->bound_transform_feedback.get()) { // buffer size might have changed, and on Desktop GL lower than 4.2, // we might need to reset transform feedback buffer range. - context_state->bound_transform_feedback->OnBufferData(target, buffer); + context_state->bound_transform_feedback->OnBufferData(buffer); } } @@ -478,8 +487,8 @@ void BufferManager::ValidateAndDoBufferSubData( ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data) { - Buffer* buffer = RequestBufferAccess( - context_state, target, offset, size, "glBufferSubData"); + Buffer* buffer = RequestBufferAccess(context_state, target, offset, size, + "glBufferSubData"); if (!buffer) { return; } @@ -500,12 +509,12 @@ ContextState* context_state, GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size) { const char* func_name = "glCopyBufferSubData"; - Buffer* readbuffer = RequestBufferAccess( - context_state, readtarget, readoffset, size, func_name); + Buffer* readbuffer = RequestBufferAccess(context_state, readtarget, + readoffset, size, func_name); if (!readbuffer) return; - Buffer* writebuffer = RequestBufferAccess( - context_state, writetarget, writeoffset, size, func_name); + Buffer* writebuffer = RequestBufferAccess(context_state, writetarget, + writeoffset, size, func_name); if (!writebuffer) return; @@ -619,10 +628,6 @@ // After being bound to non ELEMENT_ARRAY_BUFFER target, a buffer cannot // be bound to ELEMENT_ARRAY_BUFFER target. - // Note that we don't force the WebGL 2 rule that a buffer bound to - // TRANSFORM_FEEDBACK_BUFFER target should not be bound to any other - // targets, because that is not a security threat, so we only enforce it - // in the WebGL2RenderingContextBase. switch (buffer->initial_target()) { case GL_ELEMENT_ARRAY_BUFFER: switch (target) { @@ -771,8 +776,8 @@ if (!buffer->CheckRange(offset, size)) { std::string msg = base::StringPrintf( "bound to target 0x%04x : offset/size out of range", target); - ERRORSTATE_SET_GL_ERROR( - error_state, GL_INVALID_VALUE, func_name, msg.c_str()); + ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, + msg.c_str()); return nullptr; } return buffer; @@ -785,15 +790,17 @@ ErrorState* error_state = context_state->GetErrorState(); Buffer* buffer = GetBufferInfoForTarget(context_state, target); - return RequestBufferAccess( - error_state, buffer, func_name, - "bound to target 0x%04x", target) ? buffer : nullptr; + return RequestBufferAccess(error_state, buffer, func_name, + "bound to target 0x%04x", target) + ? buffer + : nullptr; } bool BufferManager::RequestBufferAccess(ErrorState* error_state, Buffer* buffer, const char* func_name, - const char* error_message_format, ...) { + const char* error_message_format, + ...) { DCHECK(error_state); va_list varargs; @@ -832,6 +839,7 @@ const char* message_tag) { DCHECK(error_state); DCHECK(bindings); + for (size_t ii = 0; ii < variable_sizes.size(); ++ii) { if (variable_sizes[ii] == 0) continue; @@ -850,13 +858,22 @@ error_state, GL_INVALID_OPERATION, func_name, msg.c_str()); return false; } + if (buffer->IsBoundForTransformFeedbackAndOther()) { + std::string msg = base::StringPrintf( + "%s : buffer at index %zu is bound for transform feedback and other " + "use simultaneously", + message_tag, ii); + ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, + msg.c_str()); + return false; + } GLsizeiptr size = bindings->GetEffectiveBufferSize(ii); base::CheckedNumeric<GLsizeiptr> required_size = variable_sizes[ii]; required_size *= count; if (size < required_size.ValueOrDefault( std::numeric_limits<GLsizeiptr>::max())) { std::string msg = base::StringPrintf( - "%s : buffer or buffer range not large enough at index %zu", + "%s : buffer or buffer range at index %zu not large enough", message_tag, ii); ERRORSTATE_SET_GL_ERROR( error_state, GL_INVALID_OPERATION, func_name, msg.c_str()); @@ -888,6 +905,16 @@ msg.c_str()); return false; } + if (buffer->IsBoundForTransformFeedbackAndOther()) { + std::string message_tag = base::StringPrintV(error_message_format, varargs); + std::string msg = base::StringPrintf( + "%s : buffer is bound for transform feedback and other use " + "simultaneously", + message_tag.c_str()); + ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, + msg.c_str()); + return false; + } return true; }
diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h index 7b754cf..6efb10f3 100644 --- a/gpu/command_buffer/service/buffer_manager.h +++ b/gpu/command_buffer/service/buffer_manager.h
@@ -14,6 +14,7 @@ #include <vector> #include "base/containers/hash_tables.h" +#include "base/debug/stack_trace.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -103,6 +104,27 @@ return mapped_range_.get(); } + void OnBind(GLenum target) { + ++binding_count_; + if (target == GL_TRANSFORM_FEEDBACK_BUFFER) { + ++transform_feedback_binding_count_; + } + } + + void OnUnbind(GLenum target) { + --binding_count_; + if (target == GL_TRANSFORM_FEEDBACK_BUFFER) { + --transform_feedback_binding_count_; + } + DCHECK(binding_count_ >= 0); + DCHECK(transform_feedback_binding_count_ >= 0); + } + + bool IsBoundForTransformFeedbackAndOther() const { + return transform_feedback_binding_count_ > 0 && + transform_feedback_binding_count_ != binding_count_; + } + private: friend class BufferManager; friend class BufferManagerTestBase; @@ -192,6 +214,13 @@ // sitting in local memory. bool is_client_side_array_; + // Keeps track of whether this buffer is currently bound for transform + // feedback in a WebGL context. Used as an optimization when validating WebGL + // draw calls for compliance with binding restrictions. + // http://crbug.com/696345 + int binding_count_; + int transform_feedback_binding_count_; + // Service side buffer id. GLuint service_id_; @@ -320,7 +349,8 @@ bool RequestBufferAccess(ErrorState* error_state, Buffer* buffer, const char* func_name, - const char* error_message_format, ...); + const char* error_message_format, + ...); // Generates INVALID_OPERATION if offset + size is out of range. bool RequestBufferAccess(ErrorState* error_state, Buffer* buffer, @@ -331,13 +361,12 @@ // Returns false and generates INVALID_OPERATION if buffer at binding |ii| // doesn't exist, is mapped, or smaller than |variable_sizes[ii]| * |count|. // Return true otherwise. - bool RequestBuffersAccess( - ErrorState* error_state, - const IndexedBufferBindingHost* bindings, - const std::vector<GLsizeiptr>& variable_sizes, - GLsizei count, - const char* func_name, - const char* message_tag); + bool RequestBuffersAccess(ErrorState* error_state, + const IndexedBufferBindingHost* bindings, + const std::vector<GLsizeiptr>& variable_sizes, + GLsizei count, + const char* func_name, + const char* message_tag); private: friend class Buffer;
diff --git a/gpu/command_buffer/service/context_state.cc b/gpu/command_buffer/service/context_state.cc index 324f461..d022fb9 100644 --- a/gpu/command_buffer/service/context_state.cc +++ b/gpu/command_buffer/service/context_state.cc
@@ -401,7 +401,8 @@ : 0); if (flag) { if (bound_transform_feedback.get()) { - bound_transform_feedback->DoBindTransformFeedback(GL_TRANSFORM_FEEDBACK); + bound_transform_feedback->DoBindTransformFeedback( + GL_TRANSFORM_FEEDBACK, bound_transform_feedback.get()); } else { api()->glBindTransformFeedbackFn(GL_TRANSFORM_FEEDBACK, 0); } @@ -645,32 +646,61 @@ } void ContextState::SetBoundBuffer(GLenum target, Buffer* buffer) { + bool do_refcounting = feature_info_->IsWebGL2OrES3Context(); switch (target) { case GL_ARRAY_BUFFER: + if (do_refcounting && bound_array_buffer) + bound_array_buffer->OnUnbind(target); bound_array_buffer = buffer; + if (do_refcounting && buffer) + buffer->OnBind(target); break; case GL_ELEMENT_ARRAY_BUFFER: vertex_attrib_manager->SetElementArrayBuffer(buffer); break; case GL_COPY_READ_BUFFER: + if (do_refcounting && bound_copy_read_buffer) + bound_copy_read_buffer->OnUnbind(target); bound_copy_read_buffer = buffer; + if (do_refcounting && buffer) + buffer->OnBind(target); break; case GL_COPY_WRITE_BUFFER: + if (do_refcounting && bound_copy_write_buffer) + bound_copy_write_buffer->OnUnbind(target); bound_copy_write_buffer = buffer; + if (do_refcounting && buffer) + buffer->OnBind(target); break; case GL_PIXEL_PACK_BUFFER: + if (do_refcounting && bound_pixel_pack_buffer) + bound_pixel_pack_buffer->OnUnbind(target); bound_pixel_pack_buffer = buffer; + if (do_refcounting && buffer) + buffer->OnBind(target); UpdatePackParameters(); break; case GL_PIXEL_UNPACK_BUFFER: + if (do_refcounting && bound_pixel_unpack_buffer) + bound_pixel_unpack_buffer->OnUnbind(target); bound_pixel_unpack_buffer = buffer; + if (do_refcounting && buffer) + buffer->OnBind(target); UpdateUnpackParameters(); break; case GL_TRANSFORM_FEEDBACK_BUFFER: + if (do_refcounting && bound_transform_feedback_buffer) + bound_transform_feedback_buffer->OnUnbind(target); bound_transform_feedback_buffer = buffer; + if (do_refcounting && buffer) + buffer->OnBind(target); break; case GL_UNIFORM_BUFFER: + if (do_refcounting && bound_uniform_buffer) + bound_uniform_buffer->OnUnbind(target); bound_uniform_buffer = buffer; + if (do_refcounting && buffer) + buffer->OnBind(target); break; default: NOTREACHED(); @@ -680,32 +710,47 @@ void ContextState::RemoveBoundBuffer(Buffer* buffer) { DCHECK(buffer); + bool do_refcounting = feature_info_->IsWebGL2OrES3Context(); vertex_attrib_manager->Unbind(buffer); if (bound_array_buffer.get() == buffer) { bound_array_buffer = nullptr; + if (do_refcounting && buffer) + buffer->OnUnbind(GL_ARRAY_BUFFER); } if (bound_copy_read_buffer.get() == buffer) { bound_copy_read_buffer = nullptr; + if (do_refcounting && buffer) + buffer->OnUnbind(GL_COPY_READ_BUFFER); } if (bound_copy_write_buffer.get() == buffer) { bound_copy_write_buffer = nullptr; + if (do_refcounting && buffer) + buffer->OnUnbind(GL_COPY_WRITE_BUFFER); } if (bound_pixel_pack_buffer.get() == buffer) { bound_pixel_pack_buffer = nullptr; + if (do_refcounting && buffer) + buffer->OnUnbind(GL_PIXEL_PACK_BUFFER); UpdatePackParameters(); } if (bound_pixel_unpack_buffer.get() == buffer) { bound_pixel_unpack_buffer = nullptr; + if (do_refcounting && buffer) + buffer->OnUnbind(GL_PIXEL_UNPACK_BUFFER); UpdateUnpackParameters(); } if (bound_transform_feedback_buffer.get() == buffer) { bound_transform_feedback_buffer = nullptr; + if (do_refcounting && buffer) + buffer->OnUnbind(GL_TRANSFORM_FEEDBACK_BUFFER); } if (bound_transform_feedback.get()) { bound_transform_feedback->RemoveBoundBuffer(buffer); } if (bound_uniform_buffer.get() == buffer) { bound_uniform_buffer = nullptr; + if (do_refcounting && buffer) + buffer->OnUnbind(GL_UNIFORM_BUFFER); } }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 81b51b8..c17eb07f 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1280,7 +1280,8 @@ GLuint service_id, bool client_visible) { return vertex_array_manager()->CreateVertexAttribManager( - client_id, service_id, group_->max_vertex_attribs(), client_visible); + client_id, service_id, group_->max_vertex_attribs(), client_visible, + feature_info_->IsWebGL2OrES3Context()); } void DoBindAttribLocation(GLuint client_id, @@ -3416,9 +3417,12 @@ api()->glBindTransformFeedbackFn(GL_TRANSFORM_FEEDBACK, default_transform_feedback); state_.bound_transform_feedback = state_.default_transform_feedback.get(); + state_.bound_transform_feedback->SetIsBound(true); } - state_.indexed_uniform_buffer_bindings = new IndexedBufferBindingHost( - group_->max_uniform_buffer_bindings(), needs_emulation); + state_.indexed_uniform_buffer_bindings = + new IndexedBufferBindingHost(group_->max_uniform_buffer_bindings(), + GL_UNIFORM_BUFFER, needs_emulation); + state_.indexed_uniform_buffer_bindings->SetIsBound(true); state_.InitGenericAttribs(group_->max_vertex_attribs()); vertex_array_manager_.reset(new VertexArrayManager()); @@ -4517,7 +4521,7 @@ // Bind to the default transform feedback. DCHECK(state_.default_transform_feedback.get()); state_.default_transform_feedback->DoBindTransformFeedback( - GL_TRANSFORM_FEEDBACK); + GL_TRANSFORM_FEEDBACK, state_.bound_transform_feedback.get()); state_.bound_transform_feedback = state_.default_transform_feedback.get(); } @@ -5817,10 +5821,10 @@ DCHECK(bindings); switch (function_type) { case kBindBufferBase: - bindings->DoBindBufferBase(target, index, buffer); + bindings->DoBindBufferBase(index, buffer); break; case kBindBufferRange: - bindings->DoBindBufferRange(target, index, buffer, offset, size); + bindings->DoBindBufferRange(index, buffer, offset, size); break; default: NOTREACHED(); @@ -6255,7 +6259,8 @@ return; } LogClientServiceForInfo(transform_feedback, client_id, function_name); - transform_feedback->DoBindTransformFeedback(target); + transform_feedback->DoBindTransformFeedback( + target, state_.bound_transform_feedback.get()); state_.bound_transform_feedback = transform_feedback; } @@ -16926,7 +16931,11 @@ // Only set the VAO state if it's changed if (state_.vertex_attrib_manager.get() != vao) { + if (state_.vertex_attrib_manager) + state_.vertex_attrib_manager->SetIsBound(false); state_.vertex_attrib_manager = vao; + if (vao) + vao->SetIsBound(true); if (!features().native_vertex_array_object) { EmulateVertexArrayState(); } else {
diff --git a/gpu/command_buffer/service/indexed_buffer_binding_host.cc b/gpu/command_buffer/service/indexed_buffer_binding_host.cc index 967cb1cf..144f5c2 100644 --- a/gpu/command_buffer/service/indexed_buffer_binding_host.cc +++ b/gpu/command_buffer/service/indexed_buffer_binding_host.cc
@@ -75,40 +75,56 @@ effective_full_buffer_size = 0; } - -IndexedBufferBindingHost::IndexedBufferBindingHost( - uint32_t max_bindings, bool needs_emulation) +IndexedBufferBindingHost::IndexedBufferBindingHost(uint32_t max_bindings, + GLenum target, + bool needs_emulation) : needs_emulation_(needs_emulation), - max_non_null_binding_index_plus_one_(0u) { + is_bound_(false), + max_non_null_binding_index_plus_one_(0u), + target_(target) { DCHECK(needs_emulation); buffer_bindings_.resize(max_bindings); } -IndexedBufferBindingHost::~IndexedBufferBindingHost() = default; +IndexedBufferBindingHost::~IndexedBufferBindingHost() { + SetIsBound(false); +} -void IndexedBufferBindingHost::DoBindBufferBase( - GLenum target, GLuint index, Buffer* buffer) { +void IndexedBufferBindingHost::DoBindBufferBase(GLuint index, Buffer* buffer) { DCHECK_LT(index, buffer_bindings_.size()); GLuint service_id = buffer ? buffer->service_id() : 0; - glBindBufferBase(target, index, service_id); + glBindBufferBase(target_, index, service_id); + if (buffer_bindings_[index].buffer && is_bound_) { + buffer_bindings_[index].buffer->OnUnbind(target_); + } buffer_bindings_[index].SetBindBufferBase(buffer); + if (buffer && is_bound_) { + buffer->OnBind(target_); + } UpdateMaxNonNullBindingIndex(index); } -void IndexedBufferBindingHost::DoBindBufferRange( - GLenum target, GLuint index, Buffer* buffer, GLintptr offset, - GLsizeiptr size) { +void IndexedBufferBindingHost::DoBindBufferRange(GLuint index, + Buffer* buffer, + GLintptr offset, + GLsizeiptr size) { DCHECK_LT(index, buffer_bindings_.size()); GLuint service_id = buffer ? buffer->service_id() : 0; if (buffer && needs_emulation_) { - DoAdjustedBindBufferRange( - target, index, service_id, offset, size, buffer->size()); + DoAdjustedBindBufferRange(target_, index, service_id, offset, size, + buffer->size()); } else { - glBindBufferRange(target, index, service_id, offset, size); + glBindBufferRange(target_, index, service_id, offset, size); } + if (buffer_bindings_[index].buffer && is_bound_) { + buffer_bindings_[index].buffer->OnUnbind(target_); + } buffer_bindings_[index].SetBindBufferRange(buffer, offset, size); + if (buffer && is_bound_) { + buffer->OnBind(target_); + } UpdateMaxNonNullBindingIndex(index); } @@ -140,24 +156,7 @@ glBindBufferRange(target, index, service_id, offset, adjusted_size); } -void IndexedBufferBindingHost::OnBindHost(GLenum target) { - if (needs_emulation_) { - // If some bound buffers change size since last time the transformfeedback - // is bound, we might need to reset the ranges. - for (size_t ii = 0; ii < buffer_bindings_.size(); ++ii) { - Buffer* buffer = buffer_bindings_[ii].buffer.get(); - if (buffer && buffer_bindings_[ii].type == kBindBufferRange && - buffer_bindings_[ii].effective_full_buffer_size != buffer->size()) { - DoAdjustedBindBufferRange( - target, ii, buffer->service_id(), buffer_bindings_[ii].offset, - buffer_bindings_[ii].size, buffer->size()); - buffer_bindings_[ii].effective_full_buffer_size = buffer->size(); - } - } - } -} - -void IndexedBufferBindingHost::OnBufferData(GLenum target, Buffer* buffer) { +void IndexedBufferBindingHost::OnBufferData(Buffer* buffer) { DCHECK(buffer); if (needs_emulation_) { // If some bound buffers change size since last time the transformfeedback @@ -167,9 +166,9 @@ continue; if (buffer_bindings_[ii].type == kBindBufferRange && buffer_bindings_[ii].effective_full_buffer_size != buffer->size()) { - DoAdjustedBindBufferRange( - target, ii, buffer->service_id(), buffer_bindings_[ii].offset, - buffer_bindings_[ii].size, buffer->size()); + DoAdjustedBindBufferRange(target_, ii, buffer->service_id(), + buffer_bindings_[ii].offset, + buffer_bindings_[ii].size, buffer->size()); buffer_bindings_[ii].effective_full_buffer_size = buffer->size(); } } @@ -185,6 +184,36 @@ } } +void IndexedBufferBindingHost::SetIsBound(bool is_bound) { + if (is_bound && needs_emulation_) { + // If some bound buffers change size since last time the transformfeedback + // is bound, we might need to reset the ranges. + for (size_t ii = 0; ii < buffer_bindings_.size(); ++ii) { + Buffer* buffer = buffer_bindings_[ii].buffer.get(); + if (buffer && buffer_bindings_[ii].type == kBindBufferRange && + buffer_bindings_[ii].effective_full_buffer_size != buffer->size()) { + DoAdjustedBindBufferRange(target_, ii, buffer->service_id(), + buffer_bindings_[ii].offset, + buffer_bindings_[ii].size, buffer->size()); + buffer_bindings_[ii].effective_full_buffer_size = buffer->size(); + } + } + } + + if (is_bound != is_bound_) { + is_bound_ = is_bound; + for (auto& bb : buffer_bindings_) { + if (bb.buffer) { + if (is_bound_) { + bb.buffer->OnBind(target_); + } else { + bb.buffer->OnUnbind(target_); + } + } + } + } +} + Buffer* IndexedBufferBindingHost::GetBufferBinding(GLuint index) const { DCHECK_LT(index, buffer_bindings_.size()); return buffer_bindings_[index].buffer.get(); @@ -222,6 +251,8 @@ void IndexedBufferBindingHost::RestoreBindings( IndexedBufferBindingHost* prev) { + // This is used only for UNIFORM_BUFFER bindings in context switching. + DCHECK(target_ == GL_UNIFORM_BUFFER && (!prev || prev->target_ == target_)); size_t limit = max_non_null_binding_index_plus_one_; if (prev && prev->max_non_null_binding_index_plus_one_ > limit) { limit = prev->max_non_null_binding_index_plus_one_; @@ -233,13 +264,12 @@ switch (buffer_bindings_[ii].type) { case kBindBufferBase: case kBindBufferNone: - DoBindBufferBase( - GL_UNIFORM_BUFFER, ii, buffer_bindings_[ii].buffer.get()); + DoBindBufferBase(ii, buffer_bindings_[ii].buffer.get()); break; case kBindBufferRange: - DoBindBufferRange( - GL_UNIFORM_BUFFER, ii, buffer_bindings_[ii].buffer.get(), - buffer_bindings_[ii].offset, buffer_bindings_[ii].size); + DoBindBufferRange(ii, buffer_bindings_[ii].buffer.get(), + buffer_bindings_[ii].offset, + buffer_bindings_[ii].size); break; } }
diff --git a/gpu/command_buffer/service/indexed_buffer_binding_host.h b/gpu/command_buffer/service/indexed_buffer_binding_host.h index 86c78ffd..4e9993b 100644 --- a/gpu/command_buffer/service/indexed_buffer_binding_host.h +++ b/gpu/command_buffer/service/indexed_buffer_binding_host.h
@@ -25,25 +25,27 @@ // In theory |needs_emulation| needs to be true on Desktop GL 4.1 or lower. // However, we set it to true everywhere, not to trust drivers to handle // out-of-bounds buffer accesses. - IndexedBufferBindingHost(uint32_t max_bindings, bool needs_emulation); + IndexedBufferBindingHost(uint32_t max_bindings, + GLenum target, + bool needs_emulation); // The following two functions do state update and call the underlying GL // function. All validations have been done already and the GL function is // guaranteed to succeed. - void DoBindBufferBase(GLenum target, GLuint index, Buffer* buffer); - void DoBindBufferRange( - GLenum target, GLuint index, Buffer* buffer, GLintptr offset, - GLsizeiptr size); + void DoBindBufferBase(GLuint index, Buffer* buffer); + void DoBindBufferRange(GLuint index, + Buffer* buffer, + GLintptr offset, + GLsizeiptr size); // This is called on the active host when glBufferData is called and buffer // size might change. - void OnBufferData(GLenum target, Buffer* buffer); - - // This is called when the host become active. - void OnBindHost(GLenum target); + void OnBufferData(Buffer* buffer); void RemoveBoundBuffer(Buffer* buffer); + void SetIsBound(bool bound); + Buffer* GetBufferBinding(GLuint index) const; // Returns |size| set by glBindBufferRange; 0 if set by glBindBufferBase. GLsizeiptr GetBufferSize(GLuint index) const; @@ -107,8 +109,20 @@ bool needs_emulation_; + // Whether this object is currently bound into the context. + bool is_bound_; + + // Whether or not to call Buffer::OnBind/OnUnbind whenever bindings change. + // This is only necessary for WebGL contexts to implement + // https://crbug.com/696345 + bool do_buffer_refcounting_; + // This is used for optimization purpose in context switching. size_t max_non_null_binding_index_plus_one_; + + // The GL binding point that this host manages + // (e.g. GL_TRANSFORM_FEEDBACK_BUFFER). + GLenum target_; }; } // namespace gles2
diff --git a/gpu/command_buffer/service/indexed_buffer_binding_host_unittest.cc b/gpu/command_buffer/service/indexed_buffer_binding_host_unittest.cc index 6d126f48..7e5237b 100644 --- a/gpu/command_buffer/service/indexed_buffer_binding_host_unittest.cc +++ b/gpu/command_buffer/service/indexed_buffer_binding_host_unittest.cc
@@ -19,7 +19,12 @@ class IndexedBufferBindingHostTest : public GpuServiceTest { public: IndexedBufferBindingHostTest() - : host_(new IndexedBufferBindingHost(kMaxBindings, true)), + : uniform_host_(new IndexedBufferBindingHost(kMaxBindings, + GL_UNIFORM_BUFFER, + true)), + tf_host_(new IndexedBufferBindingHost(kMaxBindings, + GL_TRANSFORM_FEEDBACK_BUFFER, + true)), buffer_manager_(new BufferManager(nullptr, nullptr)) { buffer_manager_->CreateBuffer(kBufferClientId, kBufferServiceId); buffer_ = buffer_manager_->GetBuffer(kBufferClientId); @@ -34,7 +39,8 @@ } void TearDown() override { - host_->RemoveBoundBuffer(buffer_.get()); + uniform_host_->RemoveBoundBuffer(buffer_.get()); + tf_host_->RemoveBoundBuffer(buffer_.get()); buffer_ = nullptr; buffer_manager_->MarkContextLost(); buffer_manager_->Destroy(); @@ -47,7 +53,8 @@ buffer_.get(), target, size, GL_STATIC_DRAW, false); } - scoped_refptr<IndexedBufferBindingHost> host_; + scoped_refptr<IndexedBufferBindingHost> uniform_host_; + scoped_refptr<IndexedBufferBindingHost> tf_host_; std::unique_ptr<BufferManager> buffer_manager_; scoped_refptr<Buffer> buffer_; }; @@ -62,15 +69,15 @@ .Times(1) .RetiresOnSaturation(); - host_->DoBindBufferRange(kTarget, kIndex, buffer_.get(), kOffset, kSize); + tf_host_->DoBindBufferRange(kIndex, buffer_.get(), kOffset, kSize); for (uint32_t index = 0; index < kMaxBindings; ++index) { if (index != kIndex) { - EXPECT_EQ(nullptr, host_->GetBufferBinding(index)); + EXPECT_EQ(nullptr, tf_host_->GetBufferBinding(index)); } else { - EXPECT_EQ(buffer_.get(), host_->GetBufferBinding(index)); - EXPECT_EQ(kSize, host_->GetBufferSize(index)); - EXPECT_EQ(kOffset, host_->GetBufferStart(index)); + EXPECT_EQ(buffer_.get(), tf_host_->GetBufferBinding(index)); + EXPECT_EQ(kSize, tf_host_->GetBufferSize(index)); + EXPECT_EQ(kOffset, tf_host_->GetBufferStart(index)); } } } @@ -91,15 +98,15 @@ .Times(1) .RetiresOnSaturation(); - host_->DoBindBufferRange(kTarget, kIndex, buffer_.get(), kOffset, kSize); + tf_host_->DoBindBufferRange(kIndex, buffer_.get(), kOffset, kSize); for (uint32_t index = 0; index < kMaxBindings; ++index) { if (index != kIndex) { - EXPECT_EQ(nullptr, host_->GetBufferBinding(index)); + EXPECT_EQ(nullptr, tf_host_->GetBufferBinding(index)); } else { - EXPECT_EQ(buffer_.get(), host_->GetBufferBinding(index)); - EXPECT_EQ(kSize, host_->GetBufferSize(index)); - EXPECT_EQ(kOffset, host_->GetBufferStart(index)); + EXPECT_EQ(buffer_.get(), tf_host_->GetBufferBinding(index)); + EXPECT_EQ(kSize, tf_host_->GetBufferSize(index)); + EXPECT_EQ(kOffset, tf_host_->GetBufferStart(index)); } } @@ -110,7 +117,7 @@ .RetiresOnSaturation(); SetBufferSize(kTarget, kOffset + kSize); - host_->OnBufferData(kTarget, buffer_.get()); + tf_host_->OnBufferData(buffer_.get()); } TEST_F(IndexedBufferBindingHostTest, RestoreBindings) { @@ -128,29 +135,29 @@ EXPECT_CALL(*gl_, BindBufferBase(kTarget, kIndex, kBufferServiceId)) .Times(1) .RetiresOnSaturation(); - host_->DoBindBufferBase(kTarget, kIndex, buffer_.get()); + uniform_host_->DoBindBufferBase(kIndex, buffer_.get()); // Set up the second host scoped_refptr<IndexedBufferBindingHost> other = - new IndexedBufferBindingHost(kMaxBindings, true); + new IndexedBufferBindingHost(kMaxBindings, GL_UNIFORM_BUFFER, true); EXPECT_CALL(*gl_, BindBufferRange(kTarget, kOtherIndex, kBufferServiceId, kOffset, clamped_size)) .Times(1) .RetiresOnSaturation(); - other->DoBindBufferRange(kTarget, kOtherIndex, buffer_.get(), kOffset, kSize); + other->DoBindBufferRange(kOtherIndex, buffer_.get(), kOffset, kSize); { - // Switching from |other| to |host_|. + // Switching from |other| to |uniform_host_|. EXPECT_CALL(*gl_, BindBufferBase(kTarget, kIndex, kBufferServiceId)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl_, BindBufferBase(kTarget, kOtherIndex, 0)) .Times(1) .RetiresOnSaturation(); - host_->RestoreBindings(other.get()); + uniform_host_->RestoreBindings(other.get()); } { - // Switching from |host_| to |other|. + // Switching from |uniform_host_| to |other|. EXPECT_CALL(*gl_, BindBufferBase(kTarget, kIndex, 0)) .Times(1) .RetiresOnSaturation(); @@ -158,7 +165,7 @@ kOffset, clamped_size)) .Times(1) .RetiresOnSaturation(); - other->RestoreBindings(host_.get()); + other->RestoreBindings(uniform_host_.get()); } }
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 36fccf08..cfa7f8d 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc
@@ -2616,6 +2616,12 @@ "pixel unpack buffer should not be mapped to client memory"); return false; } + if (buffer->IsBoundForTransformFeedbackAndOther()) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "pixel unpack buffer is simultaneously bound for transform feedback"); + return error::kNoError; + } base::CheckedNumeric<uint32_t> size = args.pixels_size; GLuint offset = ToGLuint(args.pixels); size += offset; @@ -2912,6 +2918,12 @@ "pixel unpack buffer should not be mapped to client memory"); return false; } + if (buffer->IsBoundForTransformFeedbackAndOther()) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "pixel unpack buffer is simultaneously bound for transform feedback"); + return error::kNoError; + } base::CheckedNumeric<uint32_t> size = args.pixels_size; GLuint offset = ToGLuint(args.pixels); size += offset;
diff --git a/gpu/command_buffer/service/transform_feedback_manager.cc b/gpu/command_buffer/service/transform_feedback_manager.cc index 7f20e973..1cde26b 100644 --- a/gpu/command_buffer/service/transform_feedback_manager.cc +++ b/gpu/command_buffer/service/transform_feedback_manager.cc
@@ -15,6 +15,7 @@ GLuint service_id) : IndexedBufferBindingHost( manager->max_transform_feedback_separate_attribs(), + GL_TRANSFORM_FEEDBACK_BUFFER, manager->needs_emulation()), manager_(manager), client_id_(client_id), @@ -35,17 +36,24 @@ } } -void TransformFeedback::DoBindTransformFeedback(GLenum target) { +void TransformFeedback::DoBindTransformFeedback( + GLenum target, + TransformFeedback* last_bound_transform_feedback) { DCHECK_LT(0u, service_id_); glBindTransformFeedback(target, service_id_); has_been_bound_ = true; - OnBindHost(target); if (active_ && !paused_) { // This could only happen during virtual context switching. // Otherwise the validation should generate a GL error without calling // into this function. glResumeTransformFeedback(); } + if (last_bound_transform_feedback != this) { + if (last_bound_transform_feedback) { + last_bound_transform_feedback->SetIsBound(false); + } + SetIsBound(true); + } } void TransformFeedback::DoBeginTransformFeedback(GLenum primitive_mode) { @@ -77,9 +85,9 @@ paused_ = false; } - TransformFeedbackManager::TransformFeedbackManager( - GLuint max_transform_feedback_separate_attribs, bool needs_emulation) + GLuint max_transform_feedback_separate_attribs, + bool needs_emulation) : max_transform_feedback_separate_attribs_( max_transform_feedback_separate_attribs), needs_emulation_(needs_emulation),
diff --git a/gpu/command_buffer/service/transform_feedback_manager.h b/gpu/command_buffer/service/transform_feedback_manager.h index 09c370e4..d589fa7 100644 --- a/gpu/command_buffer/service/transform_feedback_manager.h +++ b/gpu/command_buffer/service/transform_feedback_manager.h
@@ -22,13 +22,16 @@ // Info about TransformFeedbacks currently in the system. class GPU_GLES2_EXPORT TransformFeedback : public IndexedBufferBindingHost { public: - TransformFeedback( - TransformFeedbackManager* manager, GLuint client_id, GLuint service_id); + TransformFeedback(TransformFeedbackManager* manager, + GLuint client_id, + GLuint service_id); // All the following functions do state update and call the underlying GL // function. All validations have been done already and the GL function is // guaranteed to succeed. - void DoBindTransformFeedback(GLenum target); + void DoBindTransformFeedback( + GLenum target, + TransformFeedback* last_bound_transform_feedback); void DoBeginTransformFeedback(GLenum primitive_mode); void DoEndTransformFeedback(); void DoPauseTransformFeedback();
diff --git a/gpu/command_buffer/service/vertex_array_manager.cc b/gpu/command_buffer/service/vertex_array_manager.cc index a2f2e1ae..c3f5400 100644 --- a/gpu/command_buffer/service/vertex_array_manager.cc +++ b/gpu/command_buffer/service/vertex_array_manager.cc
@@ -37,9 +37,11 @@ VertexArrayManager::CreateVertexAttribManager(GLuint client_id, GLuint service_id, uint32_t num_vertex_attribs, - bool client_visible) { + bool client_visible, + bool do_buffer_refcounting) { scoped_refptr<VertexAttribManager> vertex_attrib_manager( - new VertexAttribManager(this, service_id, num_vertex_attribs)); + new VertexAttribManager(this, service_id, num_vertex_attribs, + do_buffer_refcounting)); if (client_visible) { std::pair<VertexAttribManagerMap::iterator, bool> result =
diff --git a/gpu/command_buffer/service/vertex_array_manager.h b/gpu/command_buffer/service/vertex_array_manager.h index 5ff5649..a3ab420f 100644 --- a/gpu/command_buffer/service/vertex_array_manager.h +++ b/gpu/command_buffer/service/vertex_array_manager.h
@@ -35,7 +35,8 @@ GLuint client_id, GLuint service_id, uint32_t num_vertex_attribs, - bool client_visible); + bool client_visible, + bool do_buffer_refcounting); // Gets the vertex attrib manager for the given vertex array. VertexAttribManager* GetVertexAttribManager(GLuint client_id);
diff --git a/gpu/command_buffer/service/vertex_array_manager_unittest.cc b/gpu/command_buffer/service/vertex_array_manager_unittest.cc index ac645c8..daa37434 100644 --- a/gpu/command_buffer/service/vertex_array_manager_unittest.cc +++ b/gpu/command_buffer/service/vertex_array_manager_unittest.cc
@@ -54,8 +54,8 @@ const GLuint kClient2Id = 2; // Check we can create - manager_->CreateVertexAttribManager( - kClient1Id, kService1Id, kNumVertexAttribs, true); + manager_->CreateVertexAttribManager(kClient1Id, kService1Id, + kNumVertexAttribs, true, false); // Check creation success VertexAttribManager* info1 = manager_->GetVertexAttribManager(kClient1Id); ASSERT_TRUE(info1 != NULL); @@ -81,8 +81,8 @@ const GLuint kService1Id = 11; VertexArrayManager manager; // Check we can create - manager.CreateVertexAttribManager( - kClient1Id, kService1Id, kNumVertexAttribs, true); + manager.CreateVertexAttribManager(kClient1Id, kService1Id, kNumVertexAttribs, + true, false); // Check creation success VertexAttribManager* info1 = manager.GetVertexAttribManager(kClient1Id); ASSERT_TRUE(info1 != NULL);
diff --git a/gpu/command_buffer/service/vertex_attrib_manager.cc b/gpu/command_buffer/service/vertex_attrib_manager.cc index bc61abd..673f36b3 100644 --- a/gpu/command_buffer/service/vertex_attrib_manager.cc +++ b/gpu/command_buffer/service/vertex_attrib_manager.cc
@@ -65,12 +65,6 @@ integer_ = integer; } -void VertexAttrib::Unbind(Buffer* buffer) { - if (buffer_.get() == buffer) { - buffer_ = NULL; - } -} - bool VertexAttrib::CanAccess(GLuint index) const { if (!enabled_) { return true; @@ -90,21 +84,25 @@ return index < num_elements; } -VertexAttribManager::VertexAttribManager() +VertexAttribManager::VertexAttribManager(bool do_buffer_refcounting) : num_fixed_attribs_(0), element_array_buffer_(NULL), manager_(NULL), deleted_(false), - service_id_(0) { -} + is_bound_(false), + do_buffer_refcounting_(do_buffer_refcounting), + service_id_(0) {} VertexAttribManager::VertexAttribManager(VertexArrayManager* manager, GLuint service_id, - uint32_t num_vertex_attribs) + uint32_t num_vertex_attribs, + bool do_buffer_refcounting) : num_fixed_attribs_(0), element_array_buffer_(NULL), manager_(manager), deleted_(false), + is_bound_(false), + do_buffer_refcounting_(do_buffer_refcounting), service_id_(service_id) { manager_->StartTracking(this); Initialize(num_vertex_attribs, false); @@ -144,7 +142,11 @@ } void VertexAttribManager::SetElementArrayBuffer(Buffer* buffer) { + if (do_buffer_refcounting_ && is_bound_ && element_array_buffer_) + element_array_buffer_->OnUnbind(GL_ELEMENT_ARRAY_BUFFER); element_array_buffer_ = buffer; + if (do_buffer_refcounting_ && is_bound_ && buffer) + buffer->OnBind(GL_ELEMENT_ARRAY_BUFFER); } bool VertexAttribManager::Enable(GLuint index, bool enable) { @@ -167,11 +169,42 @@ } void VertexAttribManager::Unbind(Buffer* buffer) { + if (!buffer) + return; if (element_array_buffer_.get() == buffer) { - element_array_buffer_ = NULL; + if (do_buffer_refcounting_ && is_bound_) + buffer->OnUnbind(GL_ELEMENT_ARRAY_BUFFER); + element_array_buffer_ = nullptr; } for (uint32_t vv = 0; vv < vertex_attribs_.size(); ++vv) { - vertex_attribs_[vv].Unbind(buffer); + if (vertex_attribs_[vv].buffer_ == buffer) { + if (do_buffer_refcounting_ && is_bound_) + buffer->OnUnbind(GL_ARRAY_BUFFER); + vertex_attribs_[vv].buffer_ = nullptr; + } + } +} + +void VertexAttribManager::SetIsBound(bool is_bound) { + if (is_bound == is_bound_) + return; + is_bound_ = is_bound; + if (do_buffer_refcounting_) { + if (element_array_buffer_) { + if (is_bound) + element_array_buffer_->OnBind(GL_ELEMENT_ARRAY_BUFFER); + else + element_array_buffer_->OnUnbind(GL_ELEMENT_ARRAY_BUFFER); + } + for (const auto& va : vertex_attribs_) { + if (va.buffer_) { + if (is_bound) { + va.buffer_->OnBind(GL_ARRAY_BUFFER); + } else { + va.buffer_->OnUnbind(GL_ARRAY_BUFFER); + } + } + } } } @@ -201,10 +234,9 @@ it != enabled_vertex_attribs_.end(); ++it) { VertexAttrib* attrib = *it; Buffer* buffer = attrib->buffer(); - if (!buffer_manager->RequestBufferAccess( - error_state, buffer, function_name, - "attached to enabled attrib %u", - attrib->index())) { + if (!buffer_manager->RequestBufferAccess(error_state, buffer, function_name, + "attached to enabled attrib %u", + attrib->index())) { return false; } const Program::VertexAttrib* attrib_info =
diff --git a/gpu/command_buffer/service/vertex_attrib_manager.h b/gpu/command_buffer/service/vertex_attrib_manager.h index ff54986..f60539f 100644 --- a/gpu/command_buffer/service/vertex_attrib_manager.h +++ b/gpu/command_buffer/service/vertex_attrib_manager.h
@@ -130,8 +130,6 @@ divisor_ = divisor; } - void Unbind(Buffer* buffer); - // The index of this attrib. GLuint index_; @@ -185,7 +183,7 @@ public: typedef std::list<VertexAttrib*> VertexAttribList; - VertexAttribManager(); + explicit VertexAttribManager(bool do_buffer_refcounting); void Initialize(uint32_t num_vertex_attribs, bool init_attribs); @@ -256,8 +254,12 @@ if (type == GL_FIXED) { ++num_fixed_attribs_; } + if (do_buffer_refcounting_ && is_bound_ && attrib->buffer_) + attrib->buffer_->OnUnbind(GL_ARRAY_BUFFER); attrib->SetInfo(buffer, size, type, normalized, gl_stride, real_stride, offset, integer); + if (do_buffer_refcounting_ && is_bound_ && buffer) + buffer->OnBind(GL_ARRAY_BUFFER); } } @@ -300,6 +302,8 @@ bool instanced, GLsizei primcount); + void SetIsBound(bool is_bound); + private: friend class VertexArrayManager; friend class VertexArrayManagerTest; @@ -308,7 +312,8 @@ // Used when creating from a VertexArrayManager VertexAttribManager(VertexArrayManager* manager, GLuint service_id, - uint32_t num_vertex_attribs); + uint32_t num_vertex_attribs, + bool do_buffer_refcounting); ~VertexAttribManager(); @@ -346,6 +351,14 @@ // True if deleted. bool deleted_; + // True if this is the currently bound VAO. + bool is_bound_; + + // Whether or not to call Buffer::OnBind/OnUnbind whenever bindings change. + // This is only necessary for WebGL contexts to implement + // https://crbug.com/696345 + bool do_buffer_refcounting_; + // Service side vertex array object id. GLuint service_id_; };
diff --git a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc index 83dd567..c894c6a 100644 --- a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc +++ b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
@@ -38,7 +38,7 @@ .RetiresOnSaturation(); } - manager_ = new VertexAttribManager(); + manager_ = new VertexAttribManager(false); manager_->Initialize(kNumVertexAttribs, true); }
diff --git a/gpu/command_buffer/tests/gl_map_buffer_range_unittest.cc b/gpu/command_buffer/tests/gl_map_buffer_range_unittest.cc index 9b74792..be58ee3 100644 --- a/gpu/command_buffer/tests/gl_map_buffer_range_unittest.cc +++ b/gpu/command_buffer/tests/gl_map_buffer_range_unittest.cc
@@ -459,7 +459,6 @@ glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, 6, GL_MAP_READ_BIT); EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); - glDrawArrays(GL_TRIANGLES, 0, 6); glEndTransformFeedback(); GLTestHelper::CheckGLError("no errors", __LINE__);
diff --git a/gpu/config/gpu_test_config.cc b/gpu/config/gpu_test_config.cc index fb7a835..6d4fd89 100644 --- a/gpu/config/gpu_test_config.cc +++ b/gpu/config/gpu_test_config.cc
@@ -147,6 +147,8 @@ build_type_ != kBuildTypeUnknown && (build_type_ & config.build_type_) == 0) return false; + if (config.api() != kAPIUnknown && api_ != kAPIUnknown && api_ != config.api_) + return false; return true; }
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg index 4a10929..1a1fc28 100644 --- a/infra/config/global/cr-buildbucket.cfg +++ b/infra/config/global/cr-buildbucket.cfg
@@ -115,6 +115,31 @@ } builder_mixins { + name: "android-angle-try" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-14.04" + mixins: "angle-try" +} + +builder_mixins { + name: "android-gpu-fyi-ci" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-14.04" + mixins: "gpu-fyi-ci" +} + +builder_mixins { + name: "android-optional-gpu-try" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-14.04" + mixins: "gpu-optional-try" + mixins: "android-try" +} + +builder_mixins { name: "angle-try" service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com" recipe { @@ -329,6 +354,51 @@ } builders { + name: "Android FYI 32 Vk Release (Nexus 5X)" + mixins: "android-gpu-fyi-ci" + } + + builders { + name: "Android FYI 64 Vk Release (Nexus 5X)" + mixins: "android-gpu-fyi-ci" + } + + builders { + name: "Android FYI dEQP Release (Nexus 5X)" + mixins: "android-gpu-fyi-ci" + } + + builders { + name: "Android FYI Release (Nexus 5)" + mixins: "android-gpu-fyi-ci" + } + + builders { + name: "Android FYI Release (Nexus 5X)" + mixins: "android-gpu-fyi-ci" + } + + builders { + name: "Android FYI Release (Nexus 6)" + mixins: "android-gpu-fyi-ci" + } + + builders { + name: "Android FYI Release (Nexus 6P)" + mixins: "android-gpu-fyi-ci" + } + + builders { + name: "Android FYI Release (Nexus 9)" + mixins: "android-gpu-fyi-ci" + } + + builders { + name: "Android FYI Release (NVIDIA Shield TV)" + mixins: "android-gpu-fyi-ci" + } + + builders { name: "Android x64 Builder (dbg)" mixins: "android-ci" dimensions: "os:Ubuntu-14.04" @@ -802,6 +872,8 @@ } # Keep builders sorted by OS, then name. + builders { mixins: "android-angle-try" name: "android_angle_rel_ng" } + builders { mixins: "android-angle-try" name: "android_angle_deqp_rel_ng" } builders { mixins: "android-try" name: "android_arm64_dbg_recipe" @@ -814,6 +886,7 @@ dimensions: "os:Ubuntu-14.04" dimensions: "cores:8" } + builders { mixins: "android-optional-gpu-try" name: "android_optional_gpu_tests_rel" } builders { mixins: "linux-try" name: "cast_shell_audio_linux" } builders { mixins: "linux-try" name: "cast_shell_linux" }
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg index 80995c6..54a1798 100644 --- a/infra/config/global/luci-milo.cfg +++ b/infra/config/global/luci-milo.cfg
@@ -1647,6 +1647,98 @@ short_name: "(ಥ_ಥ)" } + # GPU FYI Android bots, prefixed with GPU FYI|Android + builders: { + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 5)" + category: "GPU FYI|Android|L32|N5" + short_name: "ci" + } + builders: { + name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 5)" + category: "GPU FYI|Android|L32|N5" + short_name: "bb" + } + builders: { + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 6)" + category: "GPU FYI|Android|L32|N6" + short_name: "ci" + } + builders: { + name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 6)" + category: "GPU FYI|Android|L32|N6" + short_name: "bb" + } + builders: { + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 5X)" + category: "GPU FYI|Android|M64|QCOM|N5X" + short_name: "ci" + } + builders: { + name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 5X)" + category: "GPU FYI|Android|M64|QCOM|N5X" + short_name: "bb" + } + builders: { + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 6P)" + category: "GPU FYI|Android|M64|QCOM|N6P" + short_name: "ci" + } + builders: { + name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 6P)" + category: "GPU FYI|Android|M64|QCOM|N6P" + short_name: "bb" + } + builders: { + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 9)" + category: "GPU FYI|Android|M64|NVDA|N9" + short_name: "ci" + } + builders: { + name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 9)" + category: "GPU FYI|Android|M64|NVDA|N9" + short_name: "bb" + } + builders: { + name: "buildbucket/luci.chromium.ci/Android FYI Release (NVIDIA Shield TV)" + category: "GPU FYI|Android|N64|NVDA|STV" + short_name: "ci" + } + builders: { + name: "buildbot/chromium.gpu.fyi/Android FYI Release (NVIDIA Shield TV)" + category: "GPU FYI|Android|N64|NVDA|STV" + short_name: "bb" + } + builders: { + name: "buildbucket/luci.chromium.ci/Android FYI dEQP Release (Nexus 5X)" + category: "GPU FYI|Android|dqp|M64|N5X" + short_name: "ci" + } + builders: { + name: "buildbot/chromium.gpu.fyi/Android FYI dEQP Release (Nexus 5X)" + category: "GPU FYI|Android|dqp|M64|N5X" + short_name: "bb" + } + builders: { + name: "buildbucket/luci.chromium.ci/Android FYI 32 Vk Release (Nexus 5X)" + category: "GPU FYI|Android|vk|O32|N5X" + short_name: "ci" + } + builders: { + name: "buildbot/chromium.gpu.fyi/Android FYI 32 Vk Release (Nexus 5X)" + category: "GPU FYI|Android|vk|O32|N5X" + short_name: "bb" + } + builders: { + name: "buildbucket/luci.chromium.ci/Android FYI 64 Vk Release (Nexus 5X)" + category: "GPU FYI|Android|vk|O64|N5X" + short_name: "ci" + } + builders: { + name: "buildbot/chromium.gpu.fyi/Android FYI 64 Vk Release (Nexus 5X)" + category: "GPU FYI|Android|vk|O64|N5X" + short_name: "bb" + } + # GPU FYI Linux bots, prefixed with GPU FYI|Linux builders: { name: "buildbucket/luci.chromium.ci/GPU FYI Linux Builder" @@ -3464,46 +3556,55 @@ } builders: { name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 5)" + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 5)" category: "Android|L32" short_name: "N5" } builders: { name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 6)" + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 6)" category: "Android|L32" short_name: "N6" } builders: { name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 5X)" + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 5X)" category: "Android|M64|QCOM" short_name: "N5X" } builders: { name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 6P)" + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 6P)" category: "Android|M64|QCOM" short_name: "N6P" } builders: { name: "buildbot/chromium.gpu.fyi/Android FYI Release (Nexus 9)" + name: "buildbucket/luci.chromium.ci/Android FYI Release (Nexus 9)" category: "Android|M64|NVDA" short_name: "N9" } builders: { name: "buildbot/chromium.gpu.fyi/Android FYI Release (NVIDIA Shield TV)" + name: "buildbucket/luci.chromium.ci/Android FYI Release (NVIDIA Shield TV)" category: "Android|N64|NVDA" short_name: "STV" } builders: { name: "buildbot/chromium.gpu.fyi/Android FYI dEQP Release (Nexus 5X)" + name: "buildbucket/luci.chromium.ci/Android FYI dEQP Release (Nexus 5X)" category: "Android|dqp|M64" short_name: "N5X" } builders: { name: "buildbot/chromium.gpu.fyi/Android FYI 32 Vk Release (Nexus 5X)" + name: "buildbucket/luci.chromium.ci/Android FYI 32 Vk Release (Nexus 5X)" category: "Android|vk|O32" short_name: "N5X" } builders: { name: "buildbot/chromium.gpu.fyi/Android FYI 64 Vk Release (Nexus 5X)" + name: "buildbucket/luci.chromium.ci/Android FYI 64 Vk Release (Nexus 5X)" category: "Android|vk|O64" short_name: "N5X" } @@ -4963,6 +5064,9 @@ name: "buildbucket/luci.chromium.try/android_n5x_swarming_dbg" } builders: { + name: "buildbucket/luci.chromium.try/android_optional_gpu_tests_rel" + } + builders: { name: "buildbucket/luci.chromium.try/cast_shell_audio_linux" } builders: {
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg index 8eef5b5b..2d7f510 100644 --- a/infra/config/global/luci-scheduler.cfg +++ b/infra/config/global/luci-scheduler.cfg
@@ -53,8 +53,18 @@ # Android. Sorted alphabetically. triggers: "Android arm64 Builder (dbg)" + triggers: "Android FYI 32 Vk Release (Nexus 5X)" + triggers: "Android FYI 64 Vk Release (Nexus 5X)" + triggers: "Android FYI dEQP Release (Nexus 5X)" + triggers: "Android FYI Release (Nexus 5)" + triggers: "Android FYI Release (Nexus 5X)" + triggers: "Android FYI Release (Nexus 6)" + triggers: "Android FYI Release (Nexus 6P)" + triggers: "Android FYI Release (Nexus 9)" + triggers: "Android FYI Release (NVIDIA Shield TV)" triggers: "Android x64 Builder (dbg)" triggers: "Android x86 Builder (dbg)" + triggers: "Optional Android Release (Nexus 5X)" # Linux. Sorted alphabetically. triggers: "Cast Linux" @@ -110,6 +120,96 @@ } job { + id: "Android FYI 32 Vk Release (Nexus 5X)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Android FYI 32 Vk Release (Nexus 5X)" + } +} + +job { + id: "Android FYI 64 Vk Release (Nexus 5X)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Android FYI 64 Vk Release (Nexus 5X)" + } +} + +job { + id: "Android FYI dEQP Release (Nexus 5X)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Android FYI dEQP Release (Nexus 5X)" + } +} + +job { + id: "Android FYI Release (Nexus 5)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Android FYI Release (Nexus 5)" + } +} + +job { + id: "Android FYI Release (Nexus 5X)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Android FYI Release (Nexus 5X)" + } +} + +job { + id: "Android FYI Release (Nexus 6)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Android FYI Release (Nexus 6)" + } +} + +job { + id: "Android FYI Release (Nexus 6P)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Android FYI Release (Nexus 6P)" + } +} + +job { + id: "Android FYI Release (Nexus 9)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Android FYI Release (Nexus 9)" + } +} + +job { + id: "Android FYI Release (NVIDIA Shield TV)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Android FYI Release (NVIDIA Shield TV)" + } +} + +job { id: "Android WebView N (dbg)" # triggered by "Android arm64 Builder (dbg)" acl_sets: "triggered-by-parent-builders" @@ -193,6 +293,13 @@ } job { + id: "Optional Android Release (Nexus 5X)" + acl_sets: "default" + # This bot doesn't actually exist, so it's noop'ed out. crbug.com/819899 + noop: {} +} + +job { id: "Oreo Phone Tester" # triggered by "Android arm64 Builder (dbg)" acl_sets: "triggered-by-parent-builders"
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn index 303fc94..3650a8b 100644 --- a/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn +++ b/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn
@@ -33,6 +33,7 @@ "//base", "//components/browser_sync", "//components/sessions", + "//components/strings", "//components/sync", "//ios/chrome/app/strings", "//ios/chrome/app/theme",
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm index 0b58127..3d66bae 100644 --- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -9,10 +9,11 @@ #include "base/metrics/user_metrics_action.h" #include "base/strings/sys_string_conversions.h" #include "components/browser_sync/profile_sync_service.h" +#include "components/sessions/core/tab_restore_service.h" +#include "components/strings/grit/components_strings.h" #include "components/sync/driver/sync_service.h" #include "components/sync_sessions/open_tabs_ui_delegate.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/experimental_flags.h" #import "ios/chrome/browser/metrics/new_tab_page_uma.h" #include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.h" #include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios_factory.h" @@ -28,24 +29,16 @@ #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h" #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_handset_view_controller.h" #include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/header_of_collapsable_section_protocol.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/show_full_history_view.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_in_progress_view.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_on_no_sessions_view.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/spacers_view.h" #import "ios/chrome/browser/ui/settings/sync_utils/sync_presenter.h" #import "ios/chrome/browser/ui/signin_interaction/public/signin_presenter.h" +#import "ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h" +#import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h" +#import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h" #include "ios/chrome/browser/ui/ui_util.h" #import "ios/chrome/browser/ui/url_loader.h" -#import "ios/chrome/browser/ui/util/constraints_ui_util.h" #import "ios/chrome/browser/ui/util/top_view_controller.h" #include "ios/chrome/grit/ios_chromium_strings.h" #include "ios/chrome/grit/ios_strings.h" -#include "ios/web/public/referrer.h" #import "ios/web/public/web_state/context_menu_params.h" #include "ui/base/l10n/l10n_util.h" @@ -55,40 +48,34 @@ namespace { +typedef NS_ENUM(NSInteger, SectionIdentifier) { + SectionIdentifierRecentlyClosedTabs = kSectionIdentifierEnumZero, + SectionIdentifierOtherDevices, + // The first SessionsSectionIdentifier index. + kFirstSessionSectionIdentifier, +}; + +typedef NS_ENUM(NSInteger, ItemType) { + ItemTypeRecentlyClosedHeader = kItemTypeEnumZero, + ItemTypeRecentlyClosed, + ItemTypeOtherDevicesHeader, + ItemTypeOtherDevicesSyncOff, + ItemTypeOtherDevicesNoSessions, + ItemTypeOtherDevicesSigninPromo, + ItemTypeOtherDevicesSyncInProgress, + ItemTypeSessionHeader, + ItemTypeSessionTabData, + ItemTypeShowFullHistory, +}; + // Key for saving whether the Other Device section is collapsed. NSString* const kOtherDeviceCollapsedKey = @"OtherDevicesCollapsed"; - // Key for saving whether the Recently Closed section is collapsed. NSString* const kRecentlyClosedCollapsedKey = @"RecentlyClosedCollapsed"; - -// Tag to extract the section headers from the cells. -enum { kSectionHeader = 1 }; - -// Margin at the top of the sigin-in promo view. -const CGFloat kSigninPromoViewTopMargin = 24; - -// Types of sections. -enum SectionType { - SEPARATOR_SECTION, - CLOSED_TAB_SECTION, - OTHER_DEVICES_SECTION, - SESSION_SECTION, -}; - -// Types of cells. -enum CellType { - CELL_CLOSED_TAB_SECTION_HEADER, - CELL_CLOSED_TAB_DATA, - CELL_SHOW_FULL_HISTORY, - CELL_SEPARATOR, - CELL_OTHER_DEVICES_SECTION_HEADER, - CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF, - CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS, - CELL_OTHER_DEVICES_SIGNIN_PROMO, - CELL_OTHER_DEVICES_SYNC_IN_PROGRESS, - CELL_SESSION_SECTION_HEADER, - CELL_SESSION_TAB_DATA, -}; +// There are 2 static sections before the first SessionSection. +int const kNumberOfSectionsBeforeSessions = 2; +// Estimated Table Row height. +const CGFloat kEstimatedRowHeight = 56; } // namespace @@ -120,14 +107,9 @@ #pragma mark - Public Interface -- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState - loader:(id<UrlLoader>)loader - dispatcher:(id<ApplicationCommands>)dispatcher { +- (instancetype)init { self = [super initWithStyle:UITableViewStylePlain]; if (self) { - _dispatcher = dispatcher; - _loader = loader; - _browserState = browserState; _sessionState = SessionsSyncUserState::USER_SIGNED_OUT; _syncedSessions.reset(new synced_sessions::SyncedSessions()); } @@ -140,14 +122,14 @@ - (void)viewDidLoad { [super viewDidLoad]; + [self loadModel]; self.view.accessibilityIdentifier = kRecentTabsTableViewControllerAccessibilityIdentifier; - self.tableView.rowHeight = UITableViewAutomaticDimension; - self.tableView.estimatedRowHeight = - [SessionTabDataView desiredHeightInUITableViewCell]; - [self.tableView setSeparatorColor:[UIColor clearColor]]; - [self.tableView setDataSource:self]; [self.tableView setDelegate:self]; + self.tableView.estimatedRowHeight = kEstimatedRowHeight; + self.tableView.rowHeight = UITableViewAutomaticDimension; + self.tableView.estimatedSectionHeaderHeight = kEstimatedRowHeight; + self.tableView.sectionFooterHeight = 0.0; UILongPressGestureRecognizer* longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self @@ -156,91 +138,360 @@ [self.tableView addGestureRecognizer:longPress]; } -- (SectionType)sectionType:(NSInteger)section { - if (section == 0) { - return CLOSED_TAB_SECTION; - } - if (section == 1) { - return SEPARATOR_SECTION; - } - if (section < [self numberOfSectionsBeforeSessionOrOtherDevicesSections]) { - return CLOSED_TAB_SECTION; - } +#pragma mark - TableViewModel + +- (void)loadModel { + [super loadModel]; + [self addRecentlyClosedSection]; + + // The other Devices header section is always present regardless if it has any + // items or not. + [self addOtherDevicesSectionHeader]; if (self.sessionState == SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) { - return SESSION_SECTION; - } - // Other cases of recent_tabs::USER_SIGNED_IN_SYNC_OFF, - // recent_tabs::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS, and - // recent_tabs::USER_SIGNED_OUT falls through to here. - return OTHER_DEVICES_SECTION; -} - -- (CellType)cellType:(NSIndexPath*)indexPath { - SectionType sectionType = [self sectionType:indexPath.section]; - switch (sectionType) { - case CLOSED_TAB_SECTION: - if (indexPath.row == 0) { - return CELL_CLOSED_TAB_SECTION_HEADER; - } - // The last cell of the section is to access the history panel. - if (indexPath.row == - [self numberOfCellsInRecentlyClosedTabsSection] - 1) { - return CELL_SHOW_FULL_HISTORY; - } - return CELL_CLOSED_TAB_DATA; - case SEPARATOR_SECTION: - return CELL_SEPARATOR; - case SESSION_SECTION: - if (indexPath.row == 0) { - return CELL_SESSION_SECTION_HEADER; - } - return CELL_SESSION_TAB_DATA; - case OTHER_DEVICES_SECTION: - if (self.sessionState == - SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS) { - return CELL_OTHER_DEVICES_SYNC_IN_PROGRESS; - } - if (indexPath.row == 0) { - return CELL_OTHER_DEVICES_SECTION_HEADER; - } - switch (self.sessionState) { - case SessionsSyncUserState::USER_SIGNED_OUT: - return CELL_OTHER_DEVICES_SIGNIN_PROMO; - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF: - return CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF; - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS: - return CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS; - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS: - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS: - NOTREACHED(); - // These cases should never occur. Still, this method needs to - // return _something_, so it's returning the least wrong cell type. - return CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS; - } + [self addSessionSections]; + } else { + [self addOtherDevicesItemForState:self.sessionState]; } } -- (NSInteger)sectionIndexForSectionType:(SectionType)sectionType { - NSUInteger sectionCount = [self numberOfSectionsInTableView:self.tableView]; - for (NSUInteger sectionIndex = 0; sectionIndex < sectionCount; - ++sectionIndex) { - if ([self sectionType:sectionIndex] == sectionType) - return sectionIndex; +#pragma mark Recently Closed Section + +- (void)addRecentlyClosedSection { + TableViewModel* model = self.tableViewModel; + + // Recently Closed Section. + [model addSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs]; + TableViewTextHeaderFooterItem* header = [[TableViewTextHeaderFooterItem alloc] + initWithType:ItemTypeRecentlyClosedHeader]; + header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_RECENTLY_CLOSED); + [model setHeader:header + forSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs]; + + // Add Recently Closed Tabs Cells. + [self addRecentlyClosedTabItems]; + + // Add show full history item last. + TableViewURLItem* historyItem = + [[TableViewURLItem alloc] initWithType:ItemTypeShowFullHistory]; + historyItem.title = l10n_util::GetNSString(IDS_HISTORY_SHOWFULLHISTORY_LINK); + historyItem.favicon = [UIImage imageNamed:@"ntp_opentabs_clock"]; + [model addItem:historyItem + toSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs]; +} + +- (void)addRecentlyClosedTabItems { + if (!self.tabRestoreService) + return; + + // Note that std:list<> can only be accessed sequentially, which is + // suboptimal when using Cocoa table APIs. This list doesn't appear + // to get very long, so it probably won't matter for perf. + for (auto iter = self.tabRestoreService->entries().begin(); + iter != self.tabRestoreService->entries().end(); ++iter) { + DCHECK(iter->get()); + const sessions::TabRestoreService::Entry* entry = iter->get(); + DCHECK(entry); + // Use the page's title for the label, or its URL if title is empty. + NSString* entryTitle; + NSString* entryURL = @""; + GURL entryGURL; + switch (entry->type) { + case sessions::TabRestoreService::TAB: { + const sessions::TabRestoreService::Tab* tab = + static_cast<const sessions::TabRestoreService::Tab*>(entry); + const sessions::SerializedNavigationEntry& entry = + tab->navigations[tab->current_navigation_index]; + // Use the page's title for the label, or its URL if title is empty. + if (entry.title().size()) { + entryTitle = base::SysUTF16ToNSString(entry.title()); + entryURL = base::SysUTF8ToNSString(entry.virtual_url().spec()); + } else { + entryTitle = base::SysUTF8ToNSString(entry.virtual_url().spec()); + } + entryGURL = entry.virtual_url(); + break; + } + case sessions::TabRestoreService::WINDOW: { + // Only TAB type is handled. + entryTitle = @"Window type - NOTIMPLEMENTED"; + break; + } + } + + // Configure and add the Item. + TableViewURLItem* recentlyClosedTab = + [[TableViewURLItem alloc] initWithType:ItemTypeRecentlyClosed]; + recentlyClosedTab.favicon = [UIImage imageNamed:@"default_favicon"]; + recentlyClosedTab.title = entryTitle; + recentlyClosedTab.URL = entryURL; + [self.tableViewModel addItem:recentlyClosedTab + toSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs]; } - return NSNotFound; } -- (NSInteger)numberOfSectionsBeforeSessionOrOtherDevicesSections { - // The 2 sections are CLOSED_TAB_SECTION and SEPARATOR_SECTION. - return 2; +#pragma mark Sessions Section + +// Cleans up the model in order to update the Session sections. Needs to be +// called inside a [UITableView beginUpdates] block on iOS10, or +// performBatchUpdates on iOS11+. +- (void)updateSessionSections { + SessionsSyncUserState previousState = self.sessionState; + if (previousState != + SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) { + // The previous state was one of the OtherDevices states, remove it to clean + // it up and re-add just the header. + [self.tableViewModel + removeSectionWithIdentifier:SectionIdentifierOtherDevices]; + [self addOtherDevicesSectionHeader]; + // Reload the TableViews section. + [self.tableView reloadSections:[self otherDevicesSectionIndexSet] + withRowAnimation:UITableViewRowAnimationNone]; + } + + // Clean up any previously added SessionSections. + [self removeSessionSections]; + + // Re-Add the session sections to |self.tableViewModel| and insert them into + // |self.tableView|. + [self addSessionSections]; + [self.tableView insertSections:[self sessionSectionIndexSet] + withRowAnimation:UITableViewRowAnimationNone]; } -- (void)dismissModals { - [self.contextMenuCoordinator stop]; +// Adds all the Remote Sessions sections with its respective items. +- (void)addSessionSections { + TableViewModel* model = self.tableViewModel; + for (NSUInteger i = 0; i < [self numberOfSessions]; i++) { + synced_sessions::DistantSession const* session = + _syncedSessions->GetSession(i); + NSInteger sessionIdentifier = [self sectionIdentifierForSession:session]; + [model addSectionWithIdentifier:sessionIdentifier]; + TableViewTextHeaderFooterItem* header = + [[TableViewTextHeaderFooterItem alloc] + initWithType:ItemTypeSessionHeader]; + header.text = base::SysUTF8ToNSString(session->name); + [model setHeader:header forSectionWithIdentifier:sessionIdentifier]; + [self addItemsForSession:session]; + } } -#pragma mark - Recently closed tab helpers +- (void)addItemsForSession:(synced_sessions::DistantSession const*)session { + TableViewModel* model = self.tableViewModel; + NSInteger numberOfTabs = static_cast<NSInteger>(session->tabs.size()); + for (int i = 0; i < numberOfTabs; i++) { + synced_sessions::DistantTab const* sessionTab = session->tabs[i].get(); + NSString* title = base::SysUTF16ToNSString(sessionTab->title); + GURL url = sessionTab->virtual_url; + + TableViewURLItem* sessionTabItem = + [[TableViewURLItem alloc] initWithType:ItemTypeSessionTabData]; + sessionTabItem.favicon = [UIImage imageNamed:@"default_favicon"]; + sessionTabItem.title = title; + sessionTabItem.URL = base::SysUTF8ToNSString(url.host()); + [model addItem:sessionTabItem + toSectionWithIdentifier:[self sectionIdentifierForSession:session]]; + } +} + +// Remove all SessionSections from |self.tableViewModel| and |self.tableView| +// Needs to be called inside a [UITableView beginUpdates] block on iOS10, or +// performBatchUpdates on iOS11+. +- (void)removeSessionSections { + // Get the numberOfSessionSections from |self.tableViewModel|, since + // |_syncedSessions| has been updated by now. + int numberOfSessionSections = + [self.tableViewModel numberOfSections] - kNumberOfSectionsBeforeSessions; + for (int i = 0; i < numberOfSessionSections; i++) { + [self.tableView + deleteSections:[NSIndexSet + indexSetWithIndex:i + + kNumberOfSectionsBeforeSessions] + withRowAnimation:UITableViewRowAnimationNone]; + [self.tableViewModel + removeSectionWithIdentifier:i + kFirstSessionSectionIdentifier]; + } +} + +#pragma mark Other Devices Section + +// Cleans up the model in order to update the Other devices section. Needs to be +// called inside a [UITableView beginUpdates] block on iOS10, or +// performBatchUpdates on iOS11+. +- (void)updateOtherDevicesSectionForState:(SessionsSyncUserState)newState { + TableViewModel* model = self.tableViewModel; + SessionsSyncUserState previousState = self.sessionState; + switch (previousState) { + case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF: + case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS: + case SessionsSyncUserState::USER_SIGNED_OUT: + case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS: + // The OtherDevices section will be updated, remove it in order to clean + // it up. After the clean up add just the header. + [model removeSectionWithIdentifier:SectionIdentifierOtherDevices]; + [self addOtherDevicesSectionHeader]; + break; + case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS: + // The Sessions Section exists, remove it. + [self removeSessionSections]; + break; + } + // Add updated OtherDevices Item. + [self addOtherDevicesItemForState:newState]; + + // Update OtherDevices TableView Section. + [self.tableView reloadSections:[self otherDevicesSectionIndexSet] + withRowAnimation:UITableViewRowAnimationNone]; +} + +// Adds Other Devices Section and its header. +- (void)addOtherDevicesSectionHeader { + TableViewModel* model = self.tableViewModel; + [model addSectionWithIdentifier:SectionIdentifierOtherDevices]; + TableViewTextHeaderFooterItem* header = [[TableViewTextHeaderFooterItem alloc] + initWithType:ItemTypeRecentlyClosedHeader]; + header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OTHER_DEVICES); + [model setHeader:header + forSectionWithIdentifier:SectionIdentifierOtherDevices]; +} + +// Adds Other Devices item for |state|. +- (void)addOtherDevicesItemForState:(SessionsSyncUserState)state { + // Add item depending on |state|. + TableViewTextItem* dummyCell = nil; + switch (state) { + case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS: + NOTREACHED(); + return; + case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF: + dummyCell = + [[TableViewTextItem alloc] initWithType:ItemTypeOtherDevicesSyncOff]; + dummyCell.text = + l10n_util::GetNSString(IDS_IOS_OPEN_TABS_ENABLE_SYNC_MOBILE); + break; + case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS: + dummyCell = [[TableViewTextItem alloc] + initWithType:ItemTypeOtherDevicesNoSessions]; + dummyCell.text = + l10n_util::GetNSString(IDS_IOS_OPEN_TABS_NO_SESSION_INSTRUCTIONS); + break; + case SessionsSyncUserState::USER_SIGNED_OUT: + dummyCell = [[TableViewTextItem alloc] + initWithType:ItemTypeOtherDevicesSigninPromo]; + dummyCell.text = l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_RECENT_TABS); + break; + case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS: + dummyCell = [[TableViewTextItem alloc] + initWithType:ItemTypeOtherDevicesSyncInProgress]; + dummyCell.text = @"Sync in progress"; + } + [self.tableViewModel addItem:dummyCell + toSectionWithIdentifier:SectionIdentifierOtherDevices]; +} + +#pragma mark - TableViewModel Helpers + +// Ordered array of all section identifiers. +- (NSArray*)allSessionSectionIdentifiers { + NSMutableArray* allSessionSectionIdentifiers = [[NSMutableArray alloc] init]; + for (NSUInteger i = 0; i < [self numberOfSessions]; i++) { + [allSessionSectionIdentifiers + addObject:@(i + kFirstSessionSectionIdentifier)]; + } + return allSessionSectionIdentifiers; +} + +// Returns the TableViewModel SectionIdentifier for |distantSession|. Returns -1 +// if |distantSession| doesn't exists. +- (NSInteger)sectionIdentifierForSession: + (synced_sessions::DistantSession const*)distantSession { + for (NSUInteger i = 0; i < [self numberOfSessions]; i++) { + synced_sessions::DistantSession const* session = + _syncedSessions->GetSession(i); + if (session->tag == distantSession->tag) + return i + kFirstSessionSectionIdentifier; + } + NOTREACHED(); + return -1; +} + +// Returns an IndexSet containing the Other Devices Section. +- (NSIndexSet*)otherDevicesSectionIndexSet { + NSUInteger otherDevicesSection = [self.tableViewModel + sectionForSectionIdentifier:SectionIdentifierOtherDevices]; + return [NSIndexSet indexSetWithIndex:otherDevicesSection]; +} + +// Returns an IndexSet containing the all the Session Sections. +- (NSIndexSet*)sessionSectionIndexSet { + // Create a range of all Session Sections. + NSRange rangeOfSessionSections = + NSMakeRange(kNumberOfSectionsBeforeSessions, [self numberOfSessions]); + NSIndexSet* sessionSectionIndexes = + [NSIndexSet indexSetWithIndexesInRange:rangeOfSessionSections]; + return sessionSectionIndexes; +} + +// Returns YES if |sectionIdentifier| is a Sessions sectionIdentifier. +- (BOOL)isSessionSectionIdentifier:(NSInteger)sectionIdentifier { + NSArray* sessionSectionIdentifiers = [self allSessionSectionIdentifiers]; + NSNumber* sectionIdentifierObject = @(sectionIdentifier); + return [sessionSectionIdentifiers containsObject:sectionIdentifierObject]; +} + +#pragma mark - Consumer Protocol + +- (void)refreshUserState:(SessionsSyncUserState)newSessionState { + if ((newSessionState == self.sessionState && + self.sessionState != + SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) || + self.signinPromoViewMediator.isSigninInProgress) { + // No need to refresh the sections since all states other than + // USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS only have static content. This means + // that if the previous State is the same as the new one the static content + // won't change. + return; + } + syncer::SyncService* syncService = + IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState); + _syncedSessions.reset(new synced_sessions::SyncedSessions(syncService)); + + // Update the TableView and TableViewModel sections to match the new + // sessionState. + // Turn Off animations since UITableViewRowAnimationNone still animates. + [UIView setAnimationsEnabled:NO]; + // If iOS11+ use performBatchUpdates: instead of begin/endUpdates. + if (@available(iOS 11, *)) { + if (newSessionState == + SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) { + [self.tableView performBatchUpdates:^{ + [self updateSessionSections]; + } + completion:nil]; + } else { + [self.tableView performBatchUpdates:^{ + [self updateOtherDevicesSectionForState:newSessionState]; + } + completion:nil]; + } + } else { + [self.tableView beginUpdates]; + if (newSessionState == + SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) { + [self updateSessionSections]; + } else { + [self updateOtherDevicesSectionForState:newSessionState]; + } + [self.tableView endUpdates]; + } + [UIView setAnimationsEnabled:YES]; + + self.sessionState = newSessionState; + if (self.sessionState != SessionsSyncUserState::USER_SIGNED_OUT) { + [self.signinPromoViewMediator signinPromoViewRemoved]; + self.signinPromoViewMediator = nil; + } +} - (void)refreshRecentlyClosedTabs { [self.tableView reloadData]; @@ -250,22 +501,54 @@ _tabRestoreService = tabRestoreService; } -- (NSInteger)numberOfCellsInRecentlyClosedTabsSection { - // + 2 because of the section header, and the "Show full history" cell. - return [self numberOfRecentlyClosedTabs] + 2; +- (void)dismissModals { + [self.contextMenuCoordinator stop]; } +#pragma mark - UITableViewDelegate + +- (void)tableView:(UITableView*)tableView + didSelectRowAtIndexPath:(NSIndexPath*)indexPath { + DCHECK_EQ(tableView, self.tableView); + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + NSInteger itemTypeSelected = + [self.tableViewModel itemTypeForIndexPath:indexPath]; + switch (itemTypeSelected) { + case ItemTypeRecentlyClosed: + [self + openTabWithTabRestoreEntry:[self + tabRestoreEntryAtIndexPath:indexPath]]; + break; + case ItemTypeSessionTabData: + [self + openTabWithContentOfDistantTab:[self + distantTabAtIndexPath:indexPath]]; + break; + case ItemTypeShowFullHistory: + [tableView deselectRowAtIndexPath:indexPath animated:NO]; + [self showFullHistory]; + break; + case ItemTypeOtherDevicesSyncOff: + case ItemTypeOtherDevicesNoSessions: + case ItemTypeOtherDevicesSigninPromo: + case ItemTypeOtherDevicesSyncInProgress: + break; + } +} + +#pragma mark - Recently closed tab helpers + - (NSInteger)numberOfRecentlyClosedTabs { if (!self.tabRestoreService) return 0; return static_cast<NSInteger>(self.tabRestoreService->entries().size()); } -- (const sessions::TabRestoreService::Entry*)tabRestoreEntryAtIndex: +- (const sessions::TabRestoreService::Entry*)tabRestoreEntryAtIndexPath: (NSIndexPath*)indexPath { - DCHECK_EQ([self sectionType:indexPath.section], CLOSED_TAB_SECTION); - // "- 1" because of the section header. - NSInteger index = indexPath.row - 1; + DCHECK_EQ([self.tableViewModel sectionIdentifierForSection:indexPath.section], + SectionIdentifierRecentlyClosedTabs); + NSInteger index = indexPath.row; DCHECK_LE(index, [self numberOfRecentlyClosedTabs]); if (!self.tabRestoreService) return nullptr; @@ -281,7 +564,52 @@ return iter->get(); } -#pragma mark - Helpers to open tabs, or show the full history view. +// TO IMPLEMENT. Remove this depending on which TableStyle we'll use. +- (CGFloat)tableView:(UITableView*)tableView + heightForFooterInSection:(NSInteger)section { + return 1.0; +} + +#pragma mark - Distant Sessions helpers + +- (NSUInteger)numberOfSessions { + if (!_syncedSessions) + return 0; + return _syncedSessions->GetSessionCount(); +} + +// Returns the Session Index for a given Session Tab |indexPath|. +- (size_t)indexOfSessionForTabAtIndexPath:(NSIndexPath*)indexPath { + DCHECK_EQ([self.tableViewModel itemTypeForIndexPath:indexPath], + ItemTypeSessionTabData); + // Get the sectionIdentifier for |indexPath|, + NSNumber* sectionIdentifierForIndexPath = + @([self.tableViewModel sectionIdentifierForSection:indexPath.section]); + // Get the index of this sectionIdentifier. + size_t indexOfSession = [[self allSessionSectionIdentifiers] + indexOfObject:sectionIdentifierForIndexPath]; + DCHECK_LT(indexOfSession, _syncedSessions->GetSessionCount()); + return indexOfSession; +} + +- (synced_sessions::DistantSession const*)sessionForTabAtIndexPath: + (NSIndexPath*)indexPath { + return _syncedSessions->GetSession( + [self indexOfSessionForTabAtIndexPath:indexPath]); +} + +- (synced_sessions::DistantTab const*)distantTabAtIndexPath: + (NSIndexPath*)indexPath { + DCHECK_EQ([self.tableViewModel itemTypeForIndexPath:indexPath], + ItemTypeSessionTabData); + size_t indexOfDistantTab = indexPath.row; + synced_sessions::DistantSession const* session = + [self sessionForTabAtIndexPath:indexPath]; + DCHECK_LT(indexOfDistantTab, session->tabs.size()); + return session->tabs[indexOfDistantTab].get(); +} + +#pragma mark - Navigation helpers - (void)dismissRecentTabsModal { [self.handsetCommandHandler dismissRecentTabsWithCompletion:nil]; @@ -309,7 +637,7 @@ DCHECK(entry); if (!entry) return; - // We only handle the TAB type. + // Only TAB type is handled. if (entry->type != sessions::TabRestoreService::TAB) return; TabRestoreServiceDelegateImplIOS* delegate = @@ -324,16 +652,6 @@ WindowOpenDisposition::CURRENT_TAB); } -- (void)openTabWithURL:(const GURL&)url { - if (url.is_valid()) { - [self dismissRecentTabsModal]; - [self.loader loadURL:url - referrer:web::Referrer() - transition:ui::PAGE_TRANSITION_TYPED - rendererInitiated:NO]; - } -} - - (void)showFullHistory { __weak RecentTabsTableViewController* weakSelf = self; ProceduralBlock openHistory = ^{ @@ -343,79 +661,10 @@ [self.handsetCommandHandler dismissRecentTabsWithCompletion:openHistory]; } -#pragma mark - Handling of the collapsed sections. +#pragma mark - Collapse sections - (void)toggleExpansionOfSection:(NSInteger)sectionIndex { - NSString* sectionCollapseKey = nil; - int cellCount = 0; - - SectionType section = [self sectionType:sectionIndex]; - - switch (section) { - case CLOSED_TAB_SECTION: - sectionCollapseKey = kRecentlyClosedCollapsedKey; - // - 1 because the header does not count. - cellCount = [self numberOfCellsInRecentlyClosedTabsSection] - 1; - break; - case SEPARATOR_SECTION: - NOTREACHED(); - return; - case OTHER_DEVICES_SECTION: - cellCount = 1; - sectionCollapseKey = kOtherDeviceCollapsedKey; - break; - case SESSION_SECTION: { - size_t indexOfSession = - sectionIndex - - [self numberOfSectionsBeforeSessionOrOtherDevicesSections]; - DCHECK_LT(indexOfSession, _syncedSessions->GetSessionCount()); - synced_sessions::DistantSession const* distantSession = - _syncedSessions->GetSession(indexOfSession); - cellCount = distantSession->tabs.size(); - sectionCollapseKey = [self keyForDistantSession:distantSession]; - break; - } - } - DCHECK(sectionCollapseKey); - BOOL collapsed = ![self sectionIsCollapsed:sectionCollapseKey]; - [self setSection:sectionCollapseKey collapsed:collapsed]; - - // Builds an array indexing all the cells needing to be removed or inserted to - // collapse/expand the section. - NSMutableArray* cellIndexPathsToDeleteOrInsert = [NSMutableArray array]; - for (int i = 1; i <= cellCount; i++) { - NSIndexPath* tabIndexPath = - [NSIndexPath indexPathForRow:i inSection:sectionIndex]; - [cellIndexPathsToDeleteOrInsert addObject:tabIndexPath]; - } - - // Update the table view. - [self.tableView beginUpdates]; - if (collapsed) { - [self.tableView deleteRowsAtIndexPaths:cellIndexPathsToDeleteOrInsert - withRowAnimation:UITableViewRowAnimationFade]; - } else { - [self.tableView insertRowsAtIndexPaths:cellIndexPathsToDeleteOrInsert - withRowAnimation:UITableViewRowAnimationFade]; - } - [self.tableView endUpdates]; - - // Rotate disclosure icon. - NSIndexPath* sectionCellIndexPath = - [NSIndexPath indexPathForRow:0 inSection:sectionIndex]; - UITableViewCell* sectionCell = - [self.tableView cellForRowAtIndexPath:sectionCellIndexPath]; - UIView* subview = [sectionCell viewWithTag:kSectionHeader]; - DCHECK([subview - conformsToProtocol:@protocol(HeaderOfCollapsableSectionProtocol)]); - id<HeaderOfCollapsableSectionProtocol> headerView = - static_cast<id<HeaderOfCollapsableSectionProtocol>>(subview); - [headerView setSectionIsCollapsed:collapsed animated:YES]; -} - -- (NSString*)keyForDistantSession: - (synced_sessions::DistantSession const*)distantSession { - return base::SysUTF8ToNSString(distantSession->tag); + // TO IMPLEMENT! } - (void)setSection:(NSString*)sectionKey collapsed:(BOOL)collapsed { @@ -442,95 +691,6 @@ return [value boolValue]; } -#pragma mark - Distant Sessions helpers - -- (void)refreshUserState:(SessionsSyncUserState)newSessionState { - if ((newSessionState == self.sessionState && - self.sessionState != - SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) || - self.signinPromoViewMediator.isSigninInProgress) { - // No need to refresh the sections. - return; - } - - [self.tableView beginUpdates]; - NSIndexSet* indexesToBeDeleted = [self sessionOrOtherDevicesSectionsIndexes]; - [self.tableView deleteSections:indexesToBeDeleted - withRowAnimation:UITableViewRowAnimationFade]; - syncer::SyncService* syncService = - IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState); - _syncedSessions.reset(new synced_sessions::SyncedSessions(syncService)); - self.sessionState = newSessionState; - - if (self.sessionState == - SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS) { - // Expand the "Other Device" section once sync is finished. - [self setSection:kOtherDeviceCollapsedKey collapsed:NO]; - } - - NSIndexSet* indexesToBeInserted = [self sessionOrOtherDevicesSectionsIndexes]; - [self.tableView insertSections:indexesToBeInserted - withRowAnimation:UITableViewRowAnimationFade]; - [self.tableView endUpdates]; - - if (self.sessionState != SessionsSyncUserState::USER_SIGNED_OUT) { - [self.signinPromoViewMediator signinPromoViewRemoved]; - self.signinPromoViewMediator = nil; - } -} - -- (NSInteger)numberOfSessionSections { - DCHECK(self.sessionState == - SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS); - return _syncedSessions->GetSessionCount(); -} - -- (NSIndexSet*)sessionOrOtherDevicesSectionsIndexes { - NSInteger sectionCount = 0; - switch (self.sessionState) { - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS: - sectionCount = [self numberOfSessionSections]; - break; - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF: - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS: - case SessionsSyncUserState::USER_SIGNED_OUT: - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS: - sectionCount = 1; - break; - } - NSRange rangeOfSessionSections = NSMakeRange( - [self numberOfSectionsBeforeSessionOrOtherDevicesSections], sectionCount); - NSIndexSet* sessionSectionsIndexes = - [NSIndexSet indexSetWithIndexesInRange:rangeOfSessionSections]; - return sessionSectionsIndexes; -} - -- (size_t)indexOfSessionAtIndexPath:(NSIndexPath*)indexPath { - DCHECK_EQ([self sectionType:indexPath.section], SESSION_SECTION); - size_t indexOfSession = - indexPath.section - - [self numberOfSectionsBeforeSessionOrOtherDevicesSections]; - DCHECK_LT(indexOfSession, _syncedSessions->GetSessionCount()); - return indexOfSession; -} - -- (synced_sessions::DistantSession const*)sessionAtIndexPath: - (NSIndexPath*)indexPath { - return _syncedSessions->GetSession( - [self indexOfSessionAtIndexPath:indexPath]); -} - -- (synced_sessions::DistantTab const*)distantTabAtIndex: - (NSIndexPath*)indexPath { - DCHECK_EQ([self sectionType:indexPath.section], SESSION_SECTION); - // "- 1" because of the section header. - size_t indexOfDistantTab = indexPath.row - 1; - synced_sessions::DistantSession const* session = - [self sessionAtIndexPath:indexPath]; - DCHECK_LT(indexOfDistantTab, session->tabs.size()); - return session->tabs[indexOfDistantTab].get(); -} - #pragma mark - Long press and context menus - (void)handleLongPress:(UILongPressGestureRecognizer*)longPressGesture { @@ -543,8 +703,8 @@ DCHECK_LE(indexPath.section, [self numberOfSectionsInTableView:self.tableView]); - CellType cellType = [self cellType:indexPath]; - if (cellType != CELL_SESSION_SECTION_HEADER) { + NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath]; + if ([self isSessionSectionIdentifier:itemType]) { NOTREACHED(); return; } @@ -590,8 +750,10 @@ } - (void)openTabsFromSessionAtIndexPath:(NSIndexPath*)indexPath { + // TO-ADAPT. + return; synced_sessions::DistantSession const* session = - [self sessionAtIndexPath:indexPath]; + [self sessionForTabAtIndexPath:indexPath]; [self dismissRecentTabsModal]; for (auto const& tab : session->tabs) { [self.loader webPageOrderedOpen:tab->virtual_url @@ -602,15 +764,20 @@ } - (void)removeSessionAtIndexPath:(NSIndexPath*)indexPath { - DCHECK_EQ([self cellType:indexPath], CELL_SESSION_SECTION_HEADER); + // TO-ADAPT. + return; + DCHECK([self + isSessionSectionIdentifier: + [self.tableViewModel sectionIdentifierForSection:indexPath.section]]); synced_sessions::DistantSession const* session = - [self sessionAtIndexPath:indexPath]; + [self sessionForTabAtIndexPath:indexPath]; std::string sessionTagCopy = session->tag; syncer::SyncService* syncService = IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState); sync_sessions::OpenTabsUIDelegate* openTabs = syncService->GetOpenTabsUIDelegate(); - _syncedSessions->EraseSession([self indexOfSessionAtIndexPath:indexPath]); + _syncedSessions->EraseSession( + [self indexOfSessionForTabAtIndexPath:indexPath]); [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationLeft]; @@ -625,298 +792,18 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { CGPoint point = [gestureRecognizer locationInView:self.tableView]; - NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:point]; - if (!indexPath) - return NO; - CellType cellType = [self cellType:indexPath]; - // Context menus can be opened on a section header for tabs. - return cellType == CELL_SESSION_SECTION_HEADER; -} - -#pragma mark - UITableViewDataSource - -- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView { - switch (self.sessionState) { - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS: - return [self numberOfSectionsBeforeSessionOrOtherDevicesSections] + - [self numberOfSessionSections]; - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF: - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS: - case SessionsSyncUserState::USER_SIGNED_OUT: - case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS: - return [self numberOfSectionsBeforeSessionOrOtherDevicesSections] + 1; - } -} - -- (NSInteger)tableView:(UITableView*)tableView - numberOfRowsInSection:(NSInteger)section { - switch ([self sectionType:section]) { - case CLOSED_TAB_SECTION: - if ([self sectionIsCollapsed:kRecentlyClosedCollapsedKey]) - return 1; - else - return [self numberOfCellsInRecentlyClosedTabsSection]; - case SEPARATOR_SECTION: - return 1; - case OTHER_DEVICES_SECTION: - if (self.sessionState == - SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS) - return 1; - if ([self sectionIsCollapsed:kOtherDeviceCollapsedKey]) - return 1; - else - return 2; - case SESSION_SECTION: { - DCHECK(self.sessionState == - SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS); - size_t sessionIndex = - section - [self numberOfSectionsBeforeSessionOrOtherDevicesSections]; - DCHECK_LT(sessionIndex, _syncedSessions->GetSessionCount()); - synced_sessions::DistantSession const* distantSession = - _syncedSessions->GetSession(sessionIndex); - NSString* key = [self keyForDistantSession:distantSession]; - if ([self sectionIsCollapsed:key]) - return 1; - else - return distantSession->tabs.size() + 1; + // Context menus can be opened on a Session section header. + for (NSInteger section = 0; section < [self.tableViewModel numberOfSections]; + section++) { + NSInteger itemType = + [self.tableViewModel sectionIdentifierForSection:section]; + if (CGRectContainsPoint([self.tableView rectForHeaderInSection:section], + point) && + [self isSessionSectionIdentifier:itemType]) { + return YES; } } -} - -- (UITableViewCell*)tableView:(UITableView*)tableView - cellForRowAtIndexPath:(NSIndexPath*)indexPath { - UITableViewCell* cell = - [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault - reuseIdentifier:nil]; - UIView* contentView = cell.contentView; - CGFloat contentViewTopMargin = 0; - - UIView* subview; - CellType cellType = [self cellType:indexPath]; - switch (cellType) { - case CELL_CLOSED_TAB_SECTION_HEADER: { - BOOL collapsed = [self sectionIsCollapsed:kRecentlyClosedCollapsedKey]; - subview = [[GenericSectionHeaderView alloc] - initWithType:recent_tabs::RECENTLY_CLOSED_TABS_SECTION_HEADER - sectionIsCollapsed:collapsed]; - [subview setTag:kSectionHeader]; - break; - } - case CELL_CLOSED_TAB_DATA: { - SessionTabDataView* genericTabData = - [[SessionTabDataView alloc] initWithFrame:CGRectZero]; - [genericTabData - updateWithTabRestoreEntry:[self tabRestoreEntryAtIndex:indexPath] - browserState:self.browserState]; - subview = genericTabData; - break; - } - case CELL_SHOW_FULL_HISTORY: - subview = [[ShowFullHistoryView alloc] initWithFrame:CGRectZero]; - break; - case CELL_SEPARATOR: - subview = [[RecentlyClosedSectionFooter alloc] initWithFrame:CGRectZero]; - [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; - break; - case CELL_OTHER_DEVICES_SECTION_HEADER: { - BOOL collapsed = [self sectionIsCollapsed:kOtherDeviceCollapsedKey]; - subview = [[GenericSectionHeaderView alloc] - initWithType:recent_tabs::OTHER_DEVICES_SECTION_HEADER - sectionIsCollapsed:collapsed]; - [subview setTag:kSectionHeader]; - break; - } - case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF: - subview = [[SignedInSyncOffView alloc] initWithFrame:CGRectZero - browserState:self.browserState - presenter:self]; - [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; - break; - case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS: - subview = [[SignedInSyncOnNoSessionsView alloc] initWithFrame:CGRectZero]; - [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; - break; - case CELL_OTHER_DEVICES_SIGNIN_PROMO: { - if (!self.signinPromoViewMediator) { - self.signinPromoViewMediator = [[SigninPromoViewMediator alloc] - initWithBrowserState:self.browserState - accessPoint:signin_metrics::AccessPoint:: - ACCESS_POINT_RECENT_TABS - presenter:self /* id<SigninPresenter> */]; - self.signinPromoViewMediator.consumer = self; - } - contentViewTopMargin = kSigninPromoViewTopMargin; - SigninPromoView* signinPromoView = - [[SigninPromoView alloc] initWithFrame:CGRectZero]; - signinPromoView.delegate = self.signinPromoViewMediator; - signinPromoView.textLabel.text = - l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_RECENT_TABS); - signinPromoView.textLabel.preferredMaxLayoutWidth = - CGRectGetWidth(self.tableView.bounds) - - 2 * signinPromoView.horizontalPadding; - SigninPromoViewConfigurator* configurator = - [self.signinPromoViewMediator createConfigurator]; - [configurator configureSigninPromoView:signinPromoView]; - subview = signinPromoView; - [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; - [self.signinPromoViewMediator signinPromoViewVisible]; - break; - } - case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS: - subview = [[SignedInSyncInProgressView alloc] initWithFrame:CGRectZero]; - [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; - break; - case CELL_SESSION_SECTION_HEADER: { - synced_sessions::DistantSession const* distantSession = - [self sessionAtIndexPath:indexPath]; - NSString* key = [self keyForDistantSession:distantSession]; - BOOL collapsed = [self sectionIsCollapsed:key]; - SessionSectionHeaderView* sessionSectionHeader = - [[SessionSectionHeaderView alloc] initWithFrame:CGRectZero - sectionIsCollapsed:collapsed]; - [sessionSectionHeader updateWithSession:distantSession]; - subview = sessionSectionHeader; - [subview setTag:kSectionHeader]; - break; - } - case CELL_SESSION_TAB_DATA: { - SessionTabDataView* genericTabData = - [[SessionTabDataView alloc] initWithFrame:CGRectZero]; - [genericTabData updateWithDistantTab:[self distantTabAtIndex:indexPath] - browserState:self.browserState]; - subview = genericTabData; - break; - } - } - - DCHECK(subview); - [contentView addSubview:subview]; - - // Sets constraints on the subview. - [subview setTranslatesAutoresizingMaskIntoConstraints:NO]; - - NSDictionary* viewsDictionary = @{@"view" : subview}; - // This set of constraints should match the constraints set on the - // RecentlyClosedSectionFooter. - // clang-format off - NSArray* constraints = @[ - @"V:|-(TopMargin)-[view]-0-|", - @"H:|-(>=0)-[view(<=548)]-(>=0)-|", - @"H:[view(==548@500)]" - ]; - // clang-format on - [contentView addConstraint:[NSLayoutConstraint - constraintWithItem:subview - attribute:NSLayoutAttributeCenterX - relatedBy:NSLayoutRelationEqual - toItem:contentView - attribute:NSLayoutAttributeCenterX - multiplier:1 - constant:0]]; - NSDictionary* metrics = @{ @"TopMargin" : @(contentViewTopMargin) }; - ApplyVisualConstraintsWithMetrics(constraints, viewsDictionary, metrics); - return cell; -} - -#pragma mark - UITableViewDelegate - -- (NSIndexPath*)tableView:(UITableView*)tableView - willSelectRowAtIndexPath:(NSIndexPath*)indexPath { - DCHECK_EQ(tableView, self.tableView); - CellType cellType = [self cellType:indexPath]; - switch (cellType) { - case CELL_CLOSED_TAB_SECTION_HEADER: - case CELL_OTHER_DEVICES_SECTION_HEADER: - case CELL_SESSION_SECTION_HEADER: - case CELL_CLOSED_TAB_DATA: - case CELL_SESSION_TAB_DATA: - case CELL_SHOW_FULL_HISTORY: - return indexPath; - case CELL_SEPARATOR: - case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF: - case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS: - case CELL_OTHER_DEVICES_SIGNIN_PROMO: - case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS: - return nil; - } -} - -- (void)tableView:(UITableView*)tableView - didSelectRowAtIndexPath:(NSIndexPath*)indexPath { - DCHECK_EQ(tableView, self.tableView); - CellType cellType = [self cellType:indexPath]; - switch (cellType) { - case CELL_CLOSED_TAB_SECTION_HEADER: - case CELL_OTHER_DEVICES_SECTION_HEADER: - case CELL_SESSION_SECTION_HEADER: - // Collapse or uncollapse section. - [tableView deselectRowAtIndexPath:indexPath animated:NO]; - [self toggleExpansionOfSection:indexPath.section]; - break; - case CELL_CLOSED_TAB_DATA: - // Open new tab. - [self openTabWithTabRestoreEntry:[self tabRestoreEntryAtIndex:indexPath]]; - break; - case CELL_SESSION_TAB_DATA: - // Open new tab. - [self openTabWithContentOfDistantTab:[self distantTabAtIndex:indexPath]]; - break; - case CELL_SHOW_FULL_HISTORY: - [tableView deselectRowAtIndexPath:indexPath animated:NO]; - [self showFullHistory]; - break; - case CELL_SEPARATOR: - case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF: - case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS: - case CELL_OTHER_DEVICES_SIGNIN_PROMO: - case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS: - NOTREACHED(); - break; - } -} - -- (CGFloat)tableView:(UITableView*)tableView - heightForRowAtIndexPath:(NSIndexPath*)indexPath { - DCHECK_EQ(self.tableView, tableView); - CellType cellType = [self cellType:indexPath]; - switch (cellType) { - case CELL_SHOW_FULL_HISTORY: - return [ShowFullHistoryView desiredHeightInUITableViewCell]; - case CELL_SEPARATOR: - return [RecentlyClosedSectionFooter desiredHeightInUITableViewCell]; - case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF: - return [SignedInSyncOffView desiredHeightInUITableViewCell]; - case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS: - return [SignedInSyncOnNoSessionsView desiredHeightInUITableViewCell]; - case CELL_OTHER_DEVICES_SIGNIN_PROMO: - return UITableViewAutomaticDimension; - case CELL_SESSION_SECTION_HEADER: - return [SessionSectionHeaderView desiredHeightInUITableViewCell]; - case CELL_CLOSED_TAB_DATA: - case CELL_SESSION_TAB_DATA: - return [SessionTabDataView desiredHeightInUITableViewCell]; - case CELL_CLOSED_TAB_SECTION_HEADER: - case CELL_OTHER_DEVICES_SECTION_HEADER: - return [GenericSectionHeaderView desiredHeightInUITableViewCell]; - case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS: - return [SignedInSyncInProgressView desiredHeightInUITableViewCell]; - } -} - -- (UIView*)tableView:(UITableView*)tableView - viewForHeaderInSection:(NSInteger)section { - if ([self sectionType:section] == CLOSED_TAB_SECTION) { - return [[RecentlyTabsTopSpacingHeader alloc] initWithFrame:CGRectZero]; - } - return nil; -} - -- (CGFloat)tableView:(UITableView*)tableView - heightForHeaderInSection:(NSInteger)section { - if ([self sectionType:section] == CLOSED_TAB_SECTION) { - return [RecentlyTabsTopSpacingHeader desiredHeightInUITableViewCell]; - } - return 0; + return NO; } #pragma mark - SigninPromoViewConsumer @@ -927,11 +814,9 @@ DCHECK(self.signinPromoViewMediator); if ([self sectionIsCollapsed:kOtherDeviceCollapsedKey]) return; - NSInteger sectionIndex = - [self sectionIndexForSectionType:OTHER_DEVICES_SECTION]; - DCHECK(sectionIndex != NSNotFound); NSIndexPath* indexPath = - [NSIndexPath indexPathForRow:1 inSection:sectionIndex]; + [self.tableViewModel indexPathForItemType:ItemTypeOtherDevicesSigninPromo + sectionIdentifier:SectionIdentifierOtherDevices]; if (identityChanged) { [self.tableView reloadRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationNone];
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm index 6bdbbf7..8a67452 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
@@ -31,6 +31,10 @@ TableViewTextHeaderFooterView* header = base::mac::ObjCCastStrict<TableViewTextHeaderFooterView>(headerFooter); header.textLabel.text = self.text; + // Set the contentView backgroundColor, not the header's. + header.contentView.backgroundColor = [UIColor whiteColor]; + header.textLabel.font = + [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; } @end @@ -46,7 +50,6 @@ // Text Label, set font sizes using dynamic type. _textLabel = [[UILabel alloc] init]; _textLabel.translatesAutoresizingMaskIntoConstraints = NO; - _textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; // Container View. UIView* containerView = [[UIView alloc] init];
diff --git a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm index d08cd7d2..d97b528 100644 --- a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm +++ b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm
@@ -21,6 +21,15 @@ _tableViewModel = [[TableViewModel alloc] init]; } +#pragma mark - ViewLifeCycle + +- (void)viewDidLoad { + [super viewDidLoad]; + [self.tableView setBackgroundColor:[UIColor whiteColor]]; + [self.tableView setSeparatorColor:[UIColor grayColor]]; + [self.tableView setSeparatorInset:UIEdgeInsetsMake(0, 56, 0, 0)]; +} + #pragma mark - UITableViewDataSource - (UITableViewCell*)tableView:(UITableView*)tableView @@ -54,7 +63,7 @@ TableViewHeaderFooterItem* item = [self.tableViewModel headerForSection:section]; if (!item) - return [super tableView:self.tableView viewForHeaderInSection:section]; + return [[UIView alloc] initWithFrame:CGRectZero]; Class headerFooterClass = [item cellClass]; NSString* reuseIdentifier = NSStringFromClass(headerFooterClass); [self.tableView registerClass:headerFooterClass @@ -70,7 +79,7 @@ TableViewHeaderFooterItem* item = [self.tableViewModel footerForSection:section]; if (!item) - return [super tableView:self.tableView viewForHeaderInSection:section]; + return [[UIView alloc] initWithFrame:CGRectZero]; Class headerFooterClass = [item cellClass]; NSString* reuseIdentifier = NSStringFromClass(headerFooterClass); [self.tableView registerClass:headerFooterClass
diff --git a/ipc/ipc_mojo_bootstrap_unittest.cc b/ipc/ipc_mojo_bootstrap_unittest.cc index 46dca0e..5bc2422 100644 --- a/ipc/ipc_mojo_bootstrap_unittest.cc +++ b/ipc/ipc_mojo_bootstrap_unittest.cc
@@ -65,7 +65,11 @@ : binding_(this, std::move(request)), on_peer_pid_set_(on_peer_pid_set), message_expectation_(message_expectation) {} - ~PeerPidReceiver() override {} + ~PeerPidReceiver() override { + bool expected_message = + message_expectation_ != MessageExpectation::kNotExpected; + EXPECT_EQ(expected_message, received_message_); + } // mojom::Channel: void SetPeerPid(int32_t pid) override { @@ -77,6 +81,7 @@ base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles) override { ASSERT_NE(MessageExpectation::kNotExpected, message_expectation_); + received_message_ = true; IPC::Message message(reinterpret_cast<const char*>(data.data()), static_cast<uint32_t>(data.size())); @@ -97,6 +102,8 @@ MessageExpectation message_expectation_; int32_t peer_pid_ = -1; + bool received_message_ = false; + DISALLOW_COPY_AND_ASSIGN(PeerPidReceiver); };
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc index 8c6198da..bba15221 100644 --- a/media/video/gpu_memory_buffer_video_frame_pool.cc +++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -16,6 +16,7 @@ #include "base/barrier_closure.h" #include "base/bind.h" +#include "base/containers/circular_deque.h" #include "base/containers/stack_container.h" #include "base/location.h" #include "base/macros.h" @@ -117,25 +118,35 @@ base::TimeTicks last_use_time_; }; + // Struct to keep track of requested videoframe copies. + struct VideoFrameCopyRequest { + VideoFrameCopyRequest(scoped_refptr<VideoFrame> video_frame, + FrameReadyCB frame_ready_cb) + : video_frame(video_frame), frame_ready_cb(std::move(frame_ready_cb)) {} + scoped_refptr<VideoFrame> video_frame; + FrameReadyCB frame_ready_cb; + }; + + // Start the copy of a video_frame on the worker_task_runner_. + // It assumes there are currently no in-flight copies. + void StartCopy(const scoped_refptr<VideoFrame>& video_frame); + // Copy |video_frame| data into |frame_resources| and calls |frame_ready_cb| // when done. void CopyVideoFrameToGpuMemoryBuffers( const scoped_refptr<VideoFrame>& video_frame, - FrameResources* frame_resources, - FrameReadyCB frame_ready_cb); + FrameResources* frame_resources); // Called when all the data has been copied. void OnCopiesDone(const scoped_refptr<VideoFrame>& video_frame, - FrameResources* frame_resources, - FrameReadyCB frame_ready_cb); + FrameResources* frame_resources); // Prepares GL resources, mailboxes and calls |frame_ready_cb| with the new // VideoFrame. This has to be run on |media_task_runner_| where - // |frame_ready_cb| will also be run. + // |frame_ready_cb| associated with video_frame will also be run. void BindAndCreateMailboxesHardwareFrameResources( const scoped_refptr<VideoFrame>& video_frame, - FrameResources* frame_resources, - FrameReadyCB frame_ready_cb); + FrameResources* frame_resources); // Return true if |resources| can be used to represent a frame for // specific |format| and |size|. @@ -179,6 +190,9 @@ // |tick_clock_| is always a DefaultTickClock outside of testing. base::TickClock* tick_clock_; + // Queued up video frames for copies. The front is the currently + // in-flight copy, new copies are added at the end. + base::circular_deque<VideoFrameCopyRequest> frame_copy_requests_; bool in_shutdown_; DISALLOW_COPY_AND_ASSIGN(PoolImpl); @@ -563,19 +577,9 @@ return; } - const gfx::Size coded_size = CodedSize(video_frame, output_format_); - // Acquire resources. Incompatible ones will be dropped from the pool. - FrameResources* frame_resources = - GetOrCreateFrameResources(coded_size, output_format_); - if (!frame_resources) { - std::move(frame_ready_cb).Run(video_frame); - return; - } - - worker_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, - this, video_frame, frame_resources, - base::Passed(&frame_ready_cb))); + frame_copy_requests_.emplace_back(video_frame, std::move(frame_ready_cb)); + if (frame_copy_requests_.size() == 1u) + StartCopy(video_frame); } bool GpuMemoryBufferVideoFramePool::PoolImpl::OnMemoryDump( @@ -623,8 +627,7 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone( const scoped_refptr<VideoFrame>& video_frame, - FrameResources* frame_resources, - FrameReadyCB frame_ready_cb) { + FrameResources* frame_resources) { for (const auto& plane_resource : frame_resources->plane_resources) { if (plane_resource.gpu_memory_buffer) { plane_resource.gpu_memory_buffer->Unmap(); @@ -639,8 +642,27 @@ media_task_runner_->PostTask( FROM_HERE, base::BindOnce(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources, - this, video_frame, frame_resources, - base::Passed(&frame_ready_cb))); + this, video_frame, frame_resources)); +} + +void GpuMemoryBufferVideoFramePool::PoolImpl::StartCopy( + const scoped_refptr<VideoFrame>& video_frame) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(!frame_copy_requests_.empty()); + + const gfx::Size coded_size = CodedSize(video_frame, output_format_); + // Acquire resources. Incompatible ones will be dropped from the pool. + FrameResources* frame_resources = + GetOrCreateFrameResources(coded_size, output_format_); + if (!frame_resources) { + std::move(frame_copy_requests_.front().frame_ready_cb).Run(video_frame); + frame_copy_requests_.pop_front(); + return; + } + + worker_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, + this, video_frame, frame_resources)); } // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks @@ -648,8 +670,7 @@ // After the barrier is passed OnCopiesDone will be called. void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( const scoped_refptr<VideoFrame>& video_frame, - FrameResources* frame_resources, - FrameReadyCB frame_ready_cb) { + FrameResources* frame_resources) { // Compute the number of tasks to post and create the barrier. const size_t num_planes = VideoFrame::NumPlanes(VideoFormat(output_format_)); const size_t planes_per_copy = PlanesPerCopy(output_format_); @@ -666,8 +687,7 @@ } const base::Closure copies_done = - base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, - base::Passed(&frame_ready_cb)); + base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources); const base::RepeatingClosure barrier = base::BarrierClosure(copies, copies_done); @@ -763,13 +783,13 @@ void GpuMemoryBufferVideoFramePool::PoolImpl:: BindAndCreateMailboxesHardwareFrameResources( const scoped_refptr<VideoFrame>& video_frame, - FrameResources* frame_resources, - FrameReadyCB frame_ready_cb) { + FrameResources* frame_resources) { std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock( gpu_factories_->GetGLContextLock()); if (!lock) { frame_resources->MarkUnused(tick_clock_->NowTicks()); - std::move(frame_ready_cb).Run(video_frame); + std::move(frame_copy_requests_.front().frame_ready_cb).Run(video_frame); + frame_copy_requests_.pop_front(); return; } gpu::gles2::GLES2Interface* gles2 = lock->ContextGL(); @@ -824,7 +844,8 @@ if (!frame) { frame_resources->MarkUnused(tick_clock_->NowTicks()); release_mailbox_callback.Run(gpu::SyncToken()); - std::move(frame_ready_cb).Run(video_frame); + std::move(frame_copy_requests_.front().frame_ready_cb).Run(video_frame); + frame_copy_requests_.pop_front(); return; } @@ -864,7 +885,15 @@ frame->metadata()->SetBoolean(VideoFrameMetadata::READ_LOCK_FENCES_ENABLED, true); - std::move(frame_ready_cb).Run(frame); + lock.reset(); // Release the lock to avoid deadlocks. + DCHECK(!frame_copy_requests_.empty()); + std::move(frame_copy_requests_.front().frame_ready_cb).Run(frame); + frame_copy_requests_.pop_front(); + + if (!frame_copy_requests_.empty()) { + VideoFrameCopyRequest& copy_request = frame_copy_requests_.front(); + StartCopy(copy_request.video_frame); + } } // Destroy all the resources posting one task per FrameResources @@ -899,7 +928,6 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( const gfx::Size& size, GpuVideoAcceleratorFactories::OutputFormat format) { - DCHECK(!in_shutdown_); auto it = resources_pool_.begin(); while (it != resources_pool_.end()) {
diff --git a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc index 397f938b..e734fb6 100644 --- a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc +++ b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
@@ -414,4 +414,30 @@ EXPECT_EQ(3u, gles2_->deleted_textures_count()); } +// Test when we request two copies in a row, there should be at most one frame +// copy in flight at any time. +TEST_F(GpuMemoryBufferVideoFramePoolTest, AtMostOneCopyInFlight) { + mock_gpu_factories_->SetVideoFrameOutputFormat( + media::GpuVideoAcceleratorFactories::OutputFormat::UYVY); + + scoped_refptr<VideoFrame> software_frame_1 = CreateTestYUVVideoFrame(10); + scoped_refptr<VideoFrame> frame_1; + gpu_memory_buffer_pool_->MaybeCreateHardwareFrame( + software_frame_1, + base::BindOnce(MaybeCreateHardwareFrameCallback, &frame_1)); + + scoped_refptr<VideoFrame> software_frame_2 = CreateTestYUVVideoFrame(10); + scoped_refptr<VideoFrame> frame_2; + gpu_memory_buffer_pool_->MaybeCreateHardwareFrame( + software_frame_2, + base::BindOnce(MaybeCreateHardwareFrameCallback, &frame_2)); + + media_task_runner_->RunUntilIdle(); + EXPECT_EQ(1u, copy_task_runner_->NumPendingTasks()); + copy_task_runner_->RunUntilIdle(); + media_task_runner_->RunUntilIdle(); + EXPECT_EQ(1u, copy_task_runner_->NumPendingTasks()); + RunUntilIdle(); +} + } // namespace media
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn index a8f9c48d..55b7ba7c 100644 --- a/mojo/public/cpp/bindings/BUILD.gn +++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -88,6 +88,7 @@ defines = [ "IS_MOJO_CPP_BINDINGS_BASE_IMPL" ] public_deps = [ + ":mojo_features", "//base", "//mojo/public/cpp/system", ] @@ -160,7 +161,6 @@ public_deps = [ ":bindings_base", - ":mojo_features", ":struct_traits", "//base", "//ipc:message_support",
diff --git a/net/base/network_interfaces_fuchsia.cc b/net/base/network_interfaces_fuchsia.cc index 61c9e80..65ef4f8 100644 --- a/net/base/network_interfaces_fuchsia.cc +++ b/net/base/network_interfaces_fuchsia.cc
@@ -18,37 +18,38 @@ return false; } - netc_get_if_info_t netconfig; - int size = ioctl_netc_get_if_info(s, &netconfig); - PCHECK(close(s) == 0); - - if (size < 0) { - PLOG(ERROR) << "ioctl_netc_get_if_info"; + uint32_t num_ifs = 0; + if (ioctl_netc_get_num_ifs(s, &num_ifs) < 0) { + PLOG(ERROR) << "ioctl_netc_get_num_ifs"; + PCHECK(close(s) == 0); return false; } - networks->clear(); + for (uint32_t i = 0; i < num_ifs; ++i) { + netc_if_info_t interface; - for (size_t i = 0; i < netconfig.n_info; ++i) { - netc_if_info_t* interface = netconfig.info + i; + if (ioctl_netc_get_if_info_at(s, &i, &interface) < 0) { + PLOG(WARNING) << "ioctl_netc_get_if_info_at"; + continue; + } // Skip loopback addresses. if (internal::IsLoopbackOrUnspecifiedAddress( - reinterpret_cast<sockaddr*>(&(interface->addr)))) { + reinterpret_cast<sockaddr*>(&(interface.addr)))) { continue; } IPEndPoint address; - if (!address.FromSockAddr(reinterpret_cast<sockaddr*>(&(interface->addr)), - sizeof(interface->addr))) { + if (!address.FromSockAddr(reinterpret_cast<sockaddr*>(&(interface.addr)), + sizeof(interface.addr))) { DLOG(WARNING) << "ioctl_netc_get_if_info returned invalid address."; continue; } int prefix_length = 0; IPEndPoint netmask; - if (netmask.FromSockAddr(reinterpret_cast<sockaddr*>(&(interface->netmask)), - sizeof(interface->netmask))) { + if (netmask.FromSockAddr(reinterpret_cast<sockaddr*>(&(interface.netmask)), + sizeof(interface.netmask))) { prefix_length = MaskPrefixLength(netmask.address()); } @@ -58,11 +59,13 @@ int attributes = 0; networks->push_back( - NetworkInterface(interface->name, interface->name, interface->index, + NetworkInterface(interface.name, interface.name, interface.index, NetworkChangeNotifier::CONNECTION_UNKNOWN, address.address(), prefix_length, attributes)); } + PCHECK(close(s) == 0); + return true; }
diff --git a/net/quic/core/quic_ietf_framer_test.cc b/net/quic/core/quic_ietf_framer_test.cc index 42d84f8..a24e414 100644 --- a/net/quic/core/quic_ietf_framer_test.cc +++ b/net/quic/core/quic_ietf_framer_test.cc
@@ -832,9 +832,11 @@ } TEST_F(QuicIetfFramerTest, PathChallengeFrame) { - QuicPathFrameBuffer buffer0 = {0, 0, 0, 0, 0, 0, 0, 0}; - QuicPathFrameBuffer buffer1 = {0x80, 0x91, 0xa2, 0xb3, - 0xc4, 0xd5, 0xe5, 0xf7}; + // Double-braces needed on some platforms due to + // https://bugs.llvm.org/show_bug.cgi?id=21629 + QuicPathFrameBuffer buffer0 = {{0, 0, 0, 0, 0, 0, 0, 0}}; + QuicPathFrameBuffer buffer1 = { + {0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe5, 0xf7}}; char packet_buffer[kNormalPacketBufferSize]; EXPECT_TRUE( TryPathChallengeFrame(packet_buffer, sizeof(packet_buffer), buffer0)); @@ -843,9 +845,11 @@ } TEST_F(QuicIetfFramerTest, PathResponseFrame) { - QuicPathFrameBuffer buffer0 = {0, 0, 0, 0, 0, 0, 0, 0}; - QuicPathFrameBuffer buffer1 = {0x80, 0x91, 0xa2, 0xb3, - 0xc4, 0xd5, 0xe5, 0xf7}; + // Double-braces needed on some platforms due to + // https://bugs.llvm.org/show_bug.cgi?id=21629 + QuicPathFrameBuffer buffer0 = {{0, 0, 0, 0, 0, 0, 0, 0}}; + QuicPathFrameBuffer buffer1 = { + {0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe5, 0xf7}}; char packet_buffer[kNormalPacketBufferSize]; EXPECT_TRUE( TryPathResponseFrame(packet_buffer, sizeof(packet_buffer), buffer0));
diff --git a/net/socket/udp_socket_posix.cc b/net/socket/udp_socket_posix.cc index 7732ecc4..9bc55d7 100644 --- a/net/socket/udp_socket_posix.cc +++ b/net/socket/udp_socket_posix.cc
@@ -94,14 +94,19 @@ return MapSystemError(errno); result = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr); #elif defined(OS_FUCHSIA) - netc_get_if_info_t netconfig; - int size = ioctl_netc_get_if_info(socket, &netconfig); - if (size < 0) + uint32_t num_ifs = 0; + if (ioctl_netc_get_num_ifs(socket, &num_ifs) < 0) { + PLOG(ERROR) << "ioctl_netc_get_num_ifs"; return MapSystemError(errno); - for (size_t i = 0; i < netconfig.n_info; ++i) { - netc_if_info_t* interface = netconfig.info + i; - if (interface->index == index && interface->addr.ss_family == AF_INET) { - result = reinterpret_cast<sockaddr_in*>(&(interface->addr)); + } + for (uint32_t i = 0; i < num_ifs; ++i) { + netc_if_info_t interface; + if (ioctl_netc_get_if_info_at(socket, &i, &interface) < 0) { + PLOG(WARNING) << "ioctl_netc_get_if_info_at"; + continue; + } + if (interface.index == index && interface.addr.ss_family == AF_INET) { + result = reinterpret_cast<sockaddr_in*>(&(interface.addr)); break; } }
diff --git a/printing/printed_document.cc b/printing/printed_document.cc index 05987fcf..bc5aecc 100644 --- a/printing/printed_document.cc +++ b/printing/printed_document.cc
@@ -131,6 +131,11 @@ PrintedDocument::~PrintedDocument() = default; #if defined(OS_WIN) +void PrintedDocument::SetConvertingPdf() { + base::AutoLock lock(lock_); + mutable_.converting_pdf_ = true; +} + void PrintedDocument::SetPage(int page_number, std::unique_ptr<MetafilePlayer> metafile, float shrink, @@ -195,6 +200,9 @@ if (!mutable_.page_count_) return false; #if defined(OS_WIN) + if (mutable_.converting_pdf_) + return true; + PageNumber page(immutable_.settings_, mutable_.page_count_); if (page == PageNumber::npos()) return false;
diff --git a/printing/printed_document.h b/printing/printed_document.h index 9a52abb..08d9946 100644 --- a/printing/printed_document.h +++ b/printing/printed_document.h
@@ -43,6 +43,11 @@ int cookie); #if defined(OS_WIN) + // Indicates that the PDF has been generated and the document is waiting for + // conversion for printing. This is needed on Windows so that the print job + // is not cancelled if the web contents dies before PDF conversion finishes. + void SetConvertingPdf(); + // Sets a page's data. 0-based. Note: locks for a short amount of time. void SetPage(int page_number, std::unique_ptr<MetafilePlayer> metafile, @@ -78,7 +83,7 @@ // Returns true if all the necessary pages for the settings are already // rendered. - // Note: locks while parsing the whole tree. + // Note: This function always locks and may parse the whole tree. bool IsComplete() const; // Sets the number of pages in the document to be rendered. Can only be set @@ -153,6 +158,9 @@ // Contains the pages' representation. This is a collection of PrintedPage. // Warning: Lock must be held when accessing this member. PrintedPages pages_; + + // Whether the PDF is being converted for printing. + bool converting_pdf_ = false; #else std::unique_ptr<MetafilePlayer> metafile_; #endif
diff --git a/remoting/ios/app/client_connection_view_controller.mm b/remoting/ios/app/client_connection_view_controller.mm index 98355de..e651af3b 100644 --- a/remoting/ios/app/client_connection_view_controller.mm +++ b/remoting/ios/app/client_connection_view_controller.mm
@@ -43,8 +43,6 @@ static const CGFloat kPadding = 20.f; static const CGFloat kMargin = 20.f; -static const CGFloat kBarHeight = 58.f; - static const CGFloat kKeyboardAnimationTime = 0.3; static NSString* const kConnectionErrorFeedbackContext = @@ -108,13 +106,13 @@ _navBar.translatesAutoresizingMaskIntoConstraints = NO; // Attach navBar to the top of the view. + UILayoutGuide* layoutGuide = + remoting::SafeAreaLayoutGuideForView(self.view); [NSLayoutConstraint activateConstraints:@[ - [[_navBar topAnchor] constraintEqualToAnchor:[self.view topAnchor]], - [[_navBar leadingAnchor] - constraintEqualToAnchor:[self.view leadingAnchor]], - [[_navBar trailingAnchor] - constraintEqualToAnchor:[self.view trailingAnchor]], - [[_navBar heightAnchor] constraintEqualToConstant:kBarHeight], + [_navBar.topAnchor constraintEqualToAnchor:layoutGuide.topAnchor], + [_navBar.leadingAnchor constraintEqualToAnchor:layoutGuide.leadingAnchor], + [_navBar.trailingAnchor + constraintEqualToAnchor:layoutGuide.trailingAnchor], ]]; } return self;
diff --git a/remoting/protocol/webrtc_connection_to_host.cc b/remoting/protocol/webrtc_connection_to_host.cc index bfc5c2c..37c795e0 100644 --- a/remoting/protocol/webrtc_connection_to_host.cc +++ b/remoting/protocol/webrtc_connection_to_host.cc
@@ -151,7 +151,7 @@ void WebrtcConnectionToHost::OnWebrtcTransportMediaStreamAdded( scoped_refptr<webrtc::MediaStreamInterface> stream) { if (stream->GetVideoTracks().size() > 0) { - GetOrCreateVideoAdapter(stream->label())->SetMediaStream(stream); + GetOrCreateVideoAdapter(stream->id())->SetMediaStream(stream); } else if (stream->GetAudioTracks().size() > 0) { audio_adapter_.reset(new WebrtcAudioSinkAdapter(stream, audio_consumer_)); } else { @@ -161,7 +161,7 @@ void WebrtcConnectionToHost::OnWebrtcTransportMediaStreamRemoved( scoped_refptr<webrtc::MediaStreamInterface> stream) { - if (video_adapter_ && video_adapter_->label() == stream->label()) + if (video_adapter_ && video_adapter_->label() == stream->id()) video_adapter_.reset(); }
diff --git a/remoting/protocol/webrtc_video_renderer_adapter.cc b/remoting/protocol/webrtc_video_renderer_adapter.cc index 56e7701..dd30ced 100644 --- a/remoting/protocol/webrtc_video_renderer_adapter.cc +++ b/remoting/protocol/webrtc_video_renderer_adapter.cc
@@ -73,7 +73,7 @@ void WebrtcVideoRendererAdapter::SetMediaStream( scoped_refptr<webrtc::MediaStreamInterface> media_stream) { - DCHECK_EQ(media_stream->label(), label()); + DCHECK_EQ(media_stream->id(), label()); media_stream_ = std::move(media_stream);
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc index 2bc1700..e3a37d0 100644 --- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc +++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc
@@ -200,7 +200,7 @@ dump->platform_private_footprint->rss_anon_bytes = rss_anon_bytes; dump->platform_private_footprint->vm_swap_bytes = vm_swap_bytes; - dump->resident_set_kb = process_metrics->GetRSS() / 1024; + dump->resident_set_kb = process_metrics->GetResidentSetSize() / 1024; return true; }
diff --git a/services/ui/service.cc b/services/ui/service.cc index dafa492e..c69ea7d 100644 --- a/services/ui/service.cc +++ b/services/ui/service.cc
@@ -267,48 +267,52 @@ window_server_->SetGpuHost(std::move(gpu_host)); registry_.AddInterface<mojom::Gpu>( - base::Bind(&Service::BindGpuRequest, base::Unretained(this))); + base::BindRepeating(&Service::BindGpuRequest, base::Unretained(this))); #if defined(OS_CHROMEOS) registry_.AddInterface<mojom::Arc>( - base::Bind(&Service::BindArcRequest, base::Unretained(this))); + base::BindRepeating(&Service::BindArcRequest, base::Unretained(this))); #endif // defined(OS_CHROMEOS) } - registry_.AddInterface<mojom::VideoDetector>( - base::Bind(&Service::BindVideoDetectorRequest, base::Unretained(this))); + registry_.AddInterface<mojom::VideoDetector>(base::BindRepeating( + &Service::BindVideoDetectorRequest, base::Unretained(this))); ime_driver_.Init(context()->connector(), test_config_); registry_with_source_info_.AddInterface<mojom::AccessibilityManager>( - base::Bind(&Service::BindAccessibilityManagerRequest, - base::Unretained(this))); - registry_with_source_info_.AddInterface<mojom::Clipboard>( - base::Bind(&Service::BindClipboardRequest, base::Unretained(this))); + base::BindRepeating(&Service::BindAccessibilityManagerRequest, + base::Unretained(this))); + registry_with_source_info_.AddInterface<mojom::Clipboard>(base::BindRepeating( + &Service::BindClipboardRequest, base::Unretained(this))); registry_with_source_info_.AddInterface<mojom::DisplayManager>( - base::Bind(&Service::BindDisplayManagerRequest, base::Unretained(this))); - registry_.AddInterface<mojom::IMERegistrar>( - base::Bind(&Service::BindIMERegistrarRequest, base::Unretained(this))); - registry_.AddInterface<mojom::IMEDriver>( - base::Bind(&Service::BindIMEDriverRequest, base::Unretained(this))); + base::BindRepeating(&Service::BindDisplayManagerRequest, + base::Unretained(this))); + registry_.AddInterface<mojom::IMERegistrar>(base::BindRepeating( + &Service::BindIMERegistrarRequest, base::Unretained(this))); + registry_.AddInterface<mojom::IMEDriver>(base::BindRepeating( + &Service::BindIMEDriverRequest, base::Unretained(this))); registry_with_source_info_.AddInterface<mojom::UserActivityMonitor>( - base::Bind(&Service::BindUserActivityMonitorRequest, - base::Unretained(this))); - registry_with_source_info_.AddInterface<WindowTreeHostFactory>(base::Bind( - &Service::BindWindowTreeHostFactoryRequest, base::Unretained(this))); + base::BindRepeating(&Service::BindUserActivityMonitorRequest, + base::Unretained(this))); + registry_with_source_info_.AddInterface<WindowTreeHostFactory>( + base::BindRepeating(&Service::BindWindowTreeHostFactoryRequest, + base::Unretained(this))); registry_with_source_info_ - .AddInterface<mojom::WindowManagerWindowTreeFactory>( - base::Bind(&Service::BindWindowManagerWindowTreeFactoryRequest, - base::Unretained(this))); - registry_with_source_info_.AddInterface<mojom::WindowTreeFactory>(base::Bind( - &Service::BindWindowTreeFactoryRequest, base::Unretained(this))); + .AddInterface<mojom::WindowManagerWindowTreeFactory>(base::BindRepeating( + &Service::BindWindowManagerWindowTreeFactoryRequest, + base::Unretained(this))); + registry_with_source_info_.AddInterface<mojom::WindowTreeFactory>( + base::BindRepeating(&Service::BindWindowTreeFactoryRequest, + base::Unretained(this))); registry_with_source_info_ .AddInterface<discardable_memory::mojom::DiscardableSharedMemoryManager>( - base::Bind(&Service::BindDiscardableSharedMemoryManagerRequest, - base::Unretained(this))); + base::BindRepeating( + &Service::BindDiscardableSharedMemoryManagerRequest, + base::Unretained(this))); if (test_config_) { - registry_.AddInterface<WindowServerTest>(base::Bind( + registry_.AddInterface<WindowServerTest>(base::BindRepeating( &Service::BindWindowServerTestRequest, base::Unretained(this))); } - registry_.AddInterface<mojom::RemoteEventDispatcher>(base::Bind( + registry_.AddInterface<mojom::RemoteEventDispatcher>(base::BindRepeating( &Service::BindRemoteEventDispatcherRequest, base::Unretained(this))); // On non-Linux platforms there will be no DeviceDataManager instance and no
diff --git a/skia/BUILD.gn b/skia/BUILD.gn index 1d12fbf..76eff548 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn
@@ -351,7 +351,6 @@ # Remove unused util sources. sources -= [ "//third_party/skia/src/utils/SkCamera.cpp", - "//third_party/skia/src/utils/SkDumpCanvas.cpp", "//third_party/skia/src/utils/SkFrontBufferedStream.cpp", "//third_party/skia/src/utils/SkInterpolator.cpp", "//third_party/skia/src/utils/SkOSPath.cpp",
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json index 0d3a3a3..6323effb 100644 --- a/testing/buildbot/chromium.perf.fyi.json +++ b/testing/buildbot/chromium.perf.fyi.json
@@ -400,6 +400,50 @@ } ] }, + "Mac 10.12 Laptop Low End": { + "isolated_scripts": [ + { + "args": [ + "-v", + "--xvfb", + "--browser=release_x64" + ], + "isolate_name": "performance_test_suite", + "merge": { + "args": [ + "--service-account-file", + "/creds/service_accounts/service-account-chromium-perf-histograms.json" + ], + "script": "//tools/perf/process_perf_results.py" + }, + "name": "performance_test_suite", + "override_compile_targets": [ + "performance_test_suite" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "pool": "Chrome-perf-fyi" + } + ], + "expiration": 36000, + "hard_timeout": 36000, + "ignore_task_failure": false, + "io_timeout": 3600, + "shards": 26, + "upload_test_results": true + }, + "trigger_script": { + "args": [ + "--multiple-trigger-configs", + "[{\"id\": \"build195-a9\"}, {\"id\": \"build196-a9\"}, {\"id\": \"build197-a9\"}, {\"id\": \"build198-a9\"}, {\"id\": \"build199-a9\"}, {\"id\": \"build200-a9\"}, {\"id\": \"build201-a9\"}, {\"id\": \"build202-a9\"}, {\"id\": \"build203-a9\"}, {\"id\": \"build204-a9\"}, {\"id\": \"build205-a9\"}, {\"id\": \"build206-a9\"}, {\"id\": \"build207-a9\"}, {\"id\": \"build208-a9\"}, {\"id\": \"build209-a9\"}, {\"id\": \"build210-a9\"}, {\"id\": \"build211-a9\"}, {\"id\": \"build212-a9\"}, {\"id\": \"build213-a9\"}, {\"id\": \"build214-a9\"}, {\"id\": \"build215-a9\"}, {\"id\": \"build216-a9\"}, {\"id\": \"build217-a9\"}, {\"id\": \"build218-a9\"}, {\"id\": \"build219-a9\"}, {\"id\": \"build220-a9\"}]" + ], + "script": "//testing/trigger_scripts/perf_device_trigger.py" + } + } + ] + }, "Mojo Linux Perf": { "isolated_scripts": [ { @@ -477,49 +521,6 @@ ], "script": "//testing/trigger_scripts/perf_device_trigger.py" } - }, - { - "args": [ - "-v", - "--xvfb", - "--browser=reference", - "--testing=true" - ], - "isolate_name": "performance_test_suite", - "merge": { - "args": [ - "--configuration-name", - "buildbot-test", - "--service-account-file", - "/creds/service_accounts/service-account-chromium-perf-histograms.json" - ], - "script": "//tools/perf/process_perf_results.py" - }, - "name": "performance_test_suite", - "override_compile_targets": [ - "performance_test_suite" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 36000, - "ignore_task_failure": false, - "io_timeout": 3600, - "shards": 1, - "upload_test_results": true - }, - "trigger_script": { - "args": [ - "--multiple-trigger-configs", - "[{\"id\": \"swarm823-c4\"}]" - ], - "script": "//testing/trigger_scripts/perf_device_trigger.py" - } } ] }
diff --git a/testing/buildbot/filters/mash.ash_unittests.filter b/testing/buildbot/filters/mash.ash_unittests.filter index ab0af2ac..092a3cb 100644 --- a/testing/buildbot/filters/mash.ash_unittests.filter +++ b/testing/buildbot/filters/mash.ash_unittests.filter
@@ -150,6 +150,7 @@ -MultiWindowResizeControllerTest.IsOverWindows -MultiWindowResizeControllerTest.Three -MultiWindowResizeControllerTest.TwoSnappedWindows +-MultiWindowResizeControllerTest.WindowStateChange -NativeCursorManagerAshTest.FractionalScale -NativeCursorManagerAshTest.LockCursor -NativeCursorManagerAshTest.SetCursor
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter index 86b11fc6..32ecb793 100644 --- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter +++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -76,6 +76,8 @@ -WebViewTests/WebViewTest.WebViewInBackgroundPage/1 # Need support for blocking cookies via content settings: # https://crbug.com/803452. +-ClientHintsBrowserTest.ClientHintsLifetimeNotAttachedCookiesBlocked +-ClientHintsBrowserTest.ClientHintsNoLifetimeCookiesNotAllowed -ContentSettingsTest.AllowCookiesForASessionUsingExceptions -ContentSettingsTest.RedirectCrossOrigin -ContentSettingsTest.RedirectLoopCookies @@ -90,10 +92,6 @@ -DnsProbeBrowserTest.NoInternetProbeResultWithSlowBrokenCorrections # crbug.com/776589 Intercepting requests with net::URLRequestFilter. --ClientHintsBrowserTest.ClientHintsHttpsSubresourceDifferentOrigin --ClientHintsBrowserTest.ClientHintsLifetimeNotAttachedCookiesBlocked --ClientHintsBrowserTest.ClientHintsNoLifetimeCookiesNotAllowed --ClientHintsBrowserTest.ClientHintsNoLifetimeScriptNotAllowed -ContinueWhereILeftOffTest.CookiesClearedOnExit -DevToolsSanityTest.TestNetworkPushTime -DownloadExtensionTest.DownloadExtensionTest_Download_FileSystemURL
diff --git a/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter index d1b598c..29e4a6bf 100644 --- a/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter +++ b/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter
@@ -1,14 +1,21 @@ +#### Dev Tools # content::DevToolsProtocolTest::WaitForResponse times out # http://crbug.com/784941 -CaptureScreenshotTest.* +#### ui::LatencyInfo # Fails to receive histogram updates http://crbug.com/786151 -ScrollLatencyBrowserTest.* -# Need to handle lost context. https://crbug.com/776050 +# OnGpuSwapBuffersCompletedInternal not called. http://crbug.com/791557 +-MouseLatencyBrowserTest.CoalescedMouseMovesCorrectlyTerminated + +#### GPU +# GPU Shutdown https://crbug.com/781714 -WebRtcCaptureFromElementBrowserTest.CaptureFromCanvas2DHandlesContextLoss -WebRtcCaptureFromElementBrowserTest.CaptureFromOpaqueCanvas2DHandlesContextLoss +#### WaitForChildFrameSurfaceReady # WaitForChildFrameSurfaceReady doesn't work http://crbug.com/763452 -PointerLockBrowserTest.* -SitePerProcessGestureHitTestBrowserTest.* @@ -17,11 +24,6 @@ -SitePerProcessMouseWheelHitTestBrowserTest.* -TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.* -# Waiting for CompositorFrames times out http://crbug.com/787941 --SitePerProcessBrowserTest.CompositorFrameSwapped --SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFrames --SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFramesAfterNavigation - # Further WaitForChildFrameSurfaceReady doesn't work http://crbug.com/787945 -SitePerProcessBrowserTest.CompositorViewportPixelSizeTest -SitePerProcessBrowserTest.GestureFlingStartEventsBubble @@ -39,13 +41,13 @@ -SitePerProcessHitTestBrowserTest.CrossProcessMouseCapture* -SitePerProcessHitTestBrowserTest.CrossProcessMouseEnterAndLeaveTest* -SitePerProcessHitTestBrowserTest.CursorUpdateReceivedFromCrossSiteIframe* +-SitePerProcessHitTestBrowserTest.HitTestLayerSquashing* +-SitePerProcessHitTestBrowserTest.HitTestNestedFrames* +-SitePerProcessHitTestBrowserTest.HitTestWatermark* -SitePerProcessHitTestBrowserTest.InputEventRouterGesturePreventDefaultTargetMapTest* -SitePerProcessHitTestBrowserTest.InputEventRouterGestureTargetMapTest* -SitePerProcessHitTestBrowserTest.InputEventRouterTouchpadGestureTargetTest* -SitePerProcessHitTestBrowserTest.InputEventRouterWheelCoalesceTest* --SitePerProcessHitTestBrowserTest.HitTestLayerSquashing* --SitePerProcessHitTestBrowserTest.HitTestNestedFrames* --SitePerProcessHitTestBrowserTest.HitTestWatermark* -SitePerProcessHitTestBrowserTest.NestedSurfaceHitTestTest* -SitePerProcessHitTestBrowserTest.OverlapSurfaceHitTestTest* -SitePerProcessHitTestBrowserTest.PopupMenuTest* @@ -54,33 +56,45 @@ -SitePerProcessHitTestBrowserTest.SubframeTouchEventRouting* -SitePerProcessHitTestBrowserTest.SurfaceHitTestPointerEventsNone* -SitePerProcessHitTestBrowserTest.SurfaceHitTestTest* --SitePerProcessMacBrowserTest.InputEventRouterTouchpadGestureTargetTest -SitePerProcessNonIntegerScaleFactorHitTestBrowserTest.NestedSurfaceHitTestTest* -# Copy Surface timing out http://crbug.com/785257 --GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTest.* --GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestHiDPI.* --GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCapture.* --GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI.* - -# No ContextProvider http://crbug.com/785268 --ImageTransportFactoryTearDownBrowserTest.* --ImageTransportFactoryBrowserTest.TestLostContext - -# GetSnapshotFromBrowser doesn't return snapshots http://crbug.com/785308 --SnapshotBrowserTest.* +#### Compositor Frame Submission +# Waiting for CompositorFrames times out http://crbug.com/787941 +-SitePerProcessBrowserTest.CompositorFrameSwapped +-SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFrames +-SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFramesAfterNavigation # Touch selection information is not provided to the browser # http://crbug.com/777882 -TouchSelectionControllerClientAuraScaleFactorTest.* -TouchSelectionControllerClientAuraTest.* +#### Tab Capture +# Copy Surface timing out http://crbug.com/785257 +-GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestHiDPI.* +-GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCapture.* +-GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI.* + +# GetSnapshotFromBrowser doesn't return snapshots http://crbug.com/785308 +-SnapshotBrowserTest.* + +#### VizProcessTransportFactory +# No ContextProvider http://crbug.com/785268 +-ImageTransportFactoryTearDownBrowserTest.* +-ImageTransportFactoryBrowserTest.TestLostContext + +#### Surface Invariants +# Surface Invariants Failure on Mac http://crbug.com/817827 +-NavigationControllerBrowserTest.FrameNavigationEntry_RecreatedSubframeBackForward + +#### GL Renderer +# GL Renderer Check Failure on Mac https://crbug.com/817830 +-WebContentsVideoCaptureDeviceBrowserTestP.CapturesContentChanges/* + +#### Unknown Flakes # TODO: investigate flaky failure http://crbug.com/783434 -GpuProcessHostBrowserTest.Shutdown -# OnGpuSwapBuffersCompletedInternal not called. http://crbug.com/791557 --MouseLatencyBrowserTest.CoalescedMouseMovesCorrectlyTerminated - # TODO: investigate flaky failure http://crbug.com/790683 -SitePerProcessBrowserTest.CrossSiteIframeBlockedByXFrameOptionsOrCSP @@ -91,9 +105,3 @@ # Flaky Result on Windows-7 http://crbug.com/883463 -MainThreadEventQueueBrowserTest.MouseMove - -# Surface Invariants Failure on Mac http://crbug.com/817827 --NavigationControllerBrowserTest.FrameNavigationEntry_RecreatedSubframeBackForward - -# GL Renderer Check Failure on Mac https://crbug.com/817830 --WebContentsVideoCaptureDeviceBrowserTestP.CapturesContentChanges/*
diff --git a/testing/buildbot/filters/viz.browser_tests.filter b/testing/buildbot/filters/viz.browser_tests.filter index 12e6e6e..8ed9070e 100644 --- a/testing/buildbot/filters/viz.browser_tests.filter +++ b/testing/buildbot/filters/viz.browser_tests.filter
@@ -1,3 +1,4 @@ +#### HostFrameSinkManager Crashes # HostFrameSinkManager::CreateRootCompositorFrameSink Crash crbug.com/796575 -AppWindowApiTest.OnBoundsChangedEvent -ForceMaximizeOnFirstRunTest.*TwoRuns @@ -7,48 +8,35 @@ -ShelfAppBrowserTest.LaunchAppFromDisplayWithoutFocus0 -ShelfAppBrowserTest.LaunchAppFromDisplayWithoutFocus1 -# viz::HostFrameSinkManager::CreateCompositorFrameSinkSupport crash. +#### HostFrameSinkManager::CreateCompositorFrameSinkSupport crash. # http://crbug.com/807465 -ArcAccessibilityHelperBridgeBrowserTest.PreferenceChange -# PictureLayerTilingSet::ComputeSkewport crash crbug.com/796594 --LoginFeedbackTest.Basic - -# RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedderImpl crash -# crbug.com/797801 --HostedAppProcessModelTest.IframeNavigationsInsideHostedApp/1 - +# Tab Capture Errors # Tab Capture is still in development: crbug.com/754864 --CastStreamingApiTestWithPixelOutput.EndToEnd --ChromeScreenshotGrabberBrowserTest.TakeScreenshot --PluginPowerSaverBrowserTest.PosterTests --PluginPowerSaverBrowserTest.SmallCrossOrigin --PluginPowerSaverBrowserTest.SmallerThanPlayIcon --TabCaptureApiPixelTest.EndToEndThroughWebRTC --TabCaptureApiPixelTest.EndToEndWithoutRemoting -TabCaptureApiPixelTest.OffscreenTabEndToEnd -TabCaptureApiPixelTest.OffscreenTabEvilTests -ThumbnailTest.ShouldCaptureOnNavigatingAwayExplicitWait -ThumbnailTest.ShouldCaptureOnNavigatingAwaySlowPageLoad -# Tab Capture on Viz fails FeedbackTest: crbug.com/810389 +# Tab Capture on Viz fails at CopyOutputRequest: crbug.com/810389 -FeedbackTest.* +-LoginFeedbackTest.Basic +#### Compositor Frame Observation Timeouts # WaitForChildFrameSurfaceReady crashes crbug.com/787945 -PDFExtensionTest.ContextMenuCoordinates -SitePerProcessDevToolsSanityTest.InputDispatchEventsToOOPIF -WebViewTests/WebViewTest.InterstitialPageFocusedWidget/1 -WebViewTests/WebViewTest.ReloadAfterCrash/1 -# Flaky timeouts. http://crbug.com/807773 --PDFExtensionClipboardTest.* - # WebViewBrowserTest::ScrollWaiter Doesn't Work in Viz crbug.com/796336 -WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/0 -WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/1 -WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/2 -WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/3 +#### FrameSinkManager Crashes # FrameSinkManagerImpl::RegisterFrameSinkHierarchy Crash crbug.com/796344 # Linux and Windows failures -WebViewTests/WebViewTest.Shim_TestAssignSrcAfterCrash/0 @@ -56,16 +44,11 @@ -WebViewTests/WebViewTest.Shim_TestReloadAfterTerminate/0 -WebViewTests/WebViewTest.Shim_TestTerminateAfterExit/0 +#### Hit Testing # Incorrect Focus State crbug.com/818205 -WebViewTests/WebViewFocusTest.TouchFocusesEmbedder/0 -# Windows only failures --ExtensionApiTabTest.TabsOnUpdated - -# Individual test failure, Windows only --CloudPrintPolicyTest.NormalPassedFlag --PolicyMakeDefaultBrowserTest.MakeDefaultDisabled - +#### Surface Invariants # Surface Invariants Failure on Mac http://crbug.com/817827 -ActivityLogApiTest.TriggerEvent -AllUrlsApiTest.WhitelistedExtension @@ -86,6 +69,7 @@ -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.ServiceWorkerSuspensionOnExtensionUnload/0 -TabManagerTest.DiscardTabsWithMinimizedAndOccludedWindows +#### GL Renderer # GL Renderer Check Failure on Mac https://crbug.com/817830 -DeclarativeNetRequestBrowserTest.BlockRequests_UrlFilter/0 -DeclarativeNetRequestBrowserTest.BlockRequests_UrlFilter/1 @@ -113,3 +97,7 @@ -SSLUIWorkerFetchTest.MixedContentSubFrame/1 -ThumbnailTest.ShouldContainProperContentIfCapturedOnNavigatingAway -ThumbnailTest.ShouldContainProperContentIfCapturedOnTabSwitch + +# Unknown Flakes +# Flaky timeouts. http://crbug.com/807773 +-PDFExtensionClipboardTest.*
diff --git a/testing/buildbot/filters/viz.content_browsertests.filter b/testing/buildbot/filters/viz.content_browsertests.filter index 3b0a143f..931a2052 100644 --- a/testing/buildbot/filters/viz.content_browsertests.filter +++ b/testing/buildbot/filters/viz.content_browsertests.filter
@@ -1,21 +1,21 @@ +#### Dev Tools # content::DevToolsProtocolTest::WaitForResponse times out # http://crbug.com/784941 -CaptureScreenshotTest.* -# FrameWatcher::WaitFrames times out http://crbug.com/785013 --NonBlockingEventBrowserTest.* --TouchActionBrowserTest.* - +#### ui::LatencyInfo # Fails to receive histogram updates http://crbug.com/786151 -ScrollLatencyBrowserTest.* -# Flaky timeout while waiting for scoll update http://crbug.com/786132 --WheelScrollLatchingBrowserTest.WheelScrollingRelatchWhenLatchedScrollerRemoved +# OnGpuSwapBuffersCompletedInternal not called. http://crbug.com/791557 +-MouseLatencyBrowserTest.CoalescedMouseMovesCorrectlyTerminated -# Need to handle lost context. https://crbug.com/776050 +#### GPU +# GPU Shutdown https://crbug.com/781714 -WebRtcCaptureFromElementBrowserTest.CaptureFromCanvas2DHandlesContextLoss -WebRtcCaptureFromElementBrowserTest.CaptureFromOpaqueCanvas2DHandlesContextLoss +#### WaitForChildFrameSurfaceReady # WaitForChildFrameSurfaceReady doesn't work http://crbug.com/763452 -PointerLockBrowserTest.* -SitePerProcessGestureHitTestBrowserTest.* @@ -24,16 +24,12 @@ -SitePerProcessMouseWheelHitTestBrowserTest.* -TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.* -# Waiting for CompositorFrames times out http://crbug.com/787941 --SitePerProcessBrowserTest.CompositorFrameSwapped --SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFrames --SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFramesAfterNavigation - # Further WaitForChildFrameSurfaceReady doesn't work http://crbug.com/787945 -SitePerProcessBrowserTest.CompositorViewportPixelSizeTest -SitePerProcessBrowserTest.GestureFlingStartEventsBubble -SitePerProcessBrowserTest.NavigateCrashedSubframeToSameSite -SitePerProcessBrowserTest.OOPIFDetachDuringAnimation +-SitePerProcessBrowserTest.PhysicalBackingSizeTest -SitePerProcessBrowserTest.ScrollBubblingFromNestedOOPIFTest -SitePerProcessBrowserTest.ScrollBubblingFromOOPIFTest -SitePerProcessBrowserTest.ScrollBubblingFromOOPIFWithBodyOverflowHidden @@ -46,13 +42,13 @@ -SitePerProcessHitTestBrowserTest.CrossProcessMouseCapture* -SitePerProcessHitTestBrowserTest.CrossProcessMouseEnterAndLeaveTest* -SitePerProcessHitTestBrowserTest.CursorUpdateReceivedFromCrossSiteIframe* +-SitePerProcessHitTestBrowserTest.HitTestLayerSquashing* +-SitePerProcessHitTestBrowserTest.HitTestNestedFrames* +-SitePerProcessHitTestBrowserTest.HitTestWatermark* -SitePerProcessHitTestBrowserTest.InputEventRouterGesturePreventDefaultTargetMapTest* -SitePerProcessHitTestBrowserTest.InputEventRouterGestureTargetMapTest* -SitePerProcessHitTestBrowserTest.InputEventRouterTouchpadGestureTargetTest* -SitePerProcessHitTestBrowserTest.InputEventRouterWheelCoalesceTest* --SitePerProcessHitTestBrowserTest.HitTestLayerSquashing* --SitePerProcessHitTestBrowserTest.HitTestNestedFrames* --SitePerProcessHitTestBrowserTest.HitTestWatermark* -SitePerProcessHitTestBrowserTest.NestedSurfaceHitTestTest* -SitePerProcessHitTestBrowserTest.OverlapSurfaceHitTestTest* -SitePerProcessHitTestBrowserTest.PopupMenuTest* @@ -63,30 +59,43 @@ -SitePerProcessHitTestBrowserTest.SurfaceHitTestTest* -SitePerProcessNonIntegerScaleFactorHitTestBrowserTest.NestedSurfaceHitTestTest* -# Copy Surface timing out http://crbug.com/785257 --GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTest.* --GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestHiDPI.* --GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCapture.* --GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI.* - -# No ContextProvider http://crbug.com/785268 --ImageTransportFactoryTearDownBrowserTest.* --ImageTransportFactoryBrowserTest.TestLostContext - -# GetSnapshotFromBrowser doesn't return snapshots http://crbug.com/785308 --SnapshotBrowserTest.* +#### Compositor Frame Submission +# Waiting for CompositorFrames times out http://crbug.com/787941 +-SitePerProcessBrowserTest.CompositorFrameSwapped +-SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFrames +-SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFramesAfterNavigation # Touch selection information is not provided to the browser # http://crbug.com/777882 -TouchSelectionControllerClientAuraScaleFactorTest.* -TouchSelectionControllerClientAuraTest.* +#### Tab Capture +# Copy Surface timing out http://crbug.com/785257 +-GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestHiDPI.* +-GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCapture.* +-GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI.* + +# GetSnapshotFromBrowser doesn't return snapshots http://crbug.com/785308 +-SnapshotBrowserTest.* + +#### VizProcessTransportFactory +# No ContextProvider http://crbug.com/785268 +-ImageTransportFactoryTearDownBrowserTest.* +-ImageTransportFactoryBrowserTest.TestLostContext + +#### Surface Invariants +# Surface Invariants Failure on Mac http://crbug.com/817827 +-NavigationControllerBrowserTest.FrameNavigationEntry_RecreatedSubframeBackForward + +#### GL Renderer +# GL Renderer Check Failure on Mac https://crbug.com/817830 +-WebContentsVideoCaptureDeviceBrowserTestP.CapturesContentChanges/* + +#### Unknown Flakes # TODO: investigate flaky failure http://crbug.com/783434 -GpuProcessHostBrowserTest.Shutdown -# OnGpuSwapBuffersCompletedInternal not called. http://crbug.com/791557 --MouseLatencyBrowserTest.CoalescedMouseMovesCorrectlyTerminated - # TODO: investigate flaky failure http://crbug.com/790683 -SitePerProcessBrowserTest.CrossSiteIframeBlockedByXFrameOptionsOrCSP @@ -95,13 +104,5 @@ -IsolatedOriginTest.ProcessLimit -SitePerProcessBrowserTest.RFPHDestruction -# Tests failures related to surface sync. http://crbug.com/793302 --RenderWidgetInitialSizeTest.InitialSize --RenderWidgetTest.OnResize - # Flaky Result on Windows-7 http://crbug.com/883463 -MainThreadEventQueueBrowserTest.MouseMove - -# Still work TODO to trigger render process kills on either surface invariant -# violations or copy request permission violations. http://crbug.com/771354 --RenderWidgetHostBrowserTest.ProhibitsCopyRequestsFromRenderer
diff --git a/testing/buildbot/filters/viz.content_unittests.filter b/testing/buildbot/filters/viz.content_unittests.filter index 5cba3a36..b890bf3 100644 --- a/testing/buildbot/filters/viz.content_unittests.filter +++ b/testing/buildbot/filters/viz.content_unittests.filter
@@ -1,5 +1,4 @@ --RenderWidgetHostInputEventRouterTest.DoNotCoalesceGestureEvents --RenderWidgetHostInputEventRouterTest.DoNotCoalesceTouchEvents +# Legacy SubmitCompositorFrame tests -RenderWidgetHostViewAuraSurfaceSynchronizationTest.CompositorFrameSinkChange -RenderWidgetHostViewAuraSurfaceSynchronizationTest.DiscardDelegatedFrames -RenderWidgetHostViewAuraSurfaceSynchronizationTest.DropFallbackWhenHidden @@ -10,13 +9,18 @@ -RenderWidgetHostViewAuraTest.ForwardsBeginFrameAcks -RenderWidgetHostViewAuraTest.HitTestRegionListSubmitted -RenderWidgetHostViewAuraTest.OutputSurfaceIdChange --RenderWidgetHostViewAuraTest.TwoOutputSurfaces --RenderWidgetHostViewChildFrameTest.FrameEviction -RenderWidgetHostViewChildFrameTest.SwapCompositorFrame -RenderWidgetHostViewGuestSurfaceTest.TestGuestSurface +# Legacy using TestImageTransportFactory::GetFrameSinkManager +-RenderWidgetHostViewAuraTest.ForwardsBeginFrameAcks +-RenderWidgetHostViewAuraTest.TwoOutputSurfaces +-RenderWidgetHostViewChildFrameTest.FrameEviction + # Not finding the correct target crbug.com/796605 -RenderWidgetHostInputEventRouterTest.DoNotChangeTargetViewDuringTouchScrollGesture +-RenderWidgetHostInputEventRouterTest.DoNotCoalesceGestureEvents +-RenderWidgetHostInputEventRouterTest.DoNotCoalesceTouchEvents # TODO(crbug.com/601869): Reflector needs to be rewritten for viz. -ReflectorImplTest.*
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 55ef2ca..890b7fb 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3034,17 +3034,6 @@ "bg_sub_limit": "4" }, "enable_features": [ - "ReportRendererPeakMemoryStats", - "ResourceLoadScheduler" - ] - }, - { - "name": "Enabled_bg_limit_8", - "params": { - "bg_limit": "8" - }, - "enable_features": [ - "ReportRendererPeakMemoryStats", "ResourceLoadScheduler" ] }
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process index 064b67b..ab6815d 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process +++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -9,8 +9,9 @@ crbug.com/794631 virtual/unified-autoplay/external/wpt/feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html [ Failure ] crbug.com/794631 virtual/unified-autoplay/external/wpt/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html [ Failure ] -# https://crbug.com/793127: Crash related to frame consolidation CL. +# https://crbug.com/793127: NOTREACHED() from clamy@ tickled by frame consolidation CL? crbug.com/793127 http/tests/security/upgrade-insecure-requests/iframe-upgrade.https.html [ Crash ] +crbug.com/793127 external/wpt/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html [ Crash ] # https://crbug.com/769502: PlzNavigate-related, not-yet-investigated timeout. crbug.com/769502 fast/loader/recursive-before-unload-crash.html [ Timeout ] @@ -134,43 +135,15 @@ # TODO(lukasza, alexmos): Triage these failures. Bug(none) external/wpt/IndexedDB/interleaved-cursors.html [ Timeout ] Bug(none) external/wpt/xhr/xmlhttprequest-sync-default-feature-policy.sub.html [ Timeout ] -Bug(none) external/wpt/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-star-allow.html [ Timeout ] Bug(none) external/wpt/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html [ Timeout ] -Bug(none) external/wpt/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html [ Crash ] -Bug(none) external/wpt/credential-management/credentialscontainer-create-basics.https.html [ Crash ] Bug(none) external/wpt/css-fonts/font-display/font-display.html [ Crash ] -Bug(none) external/wpt/dom/nodes/Element-matches.html [ Failure ] -Bug(none) external/wpt/encrypted-media/encrypted-media-default-feature-policy.https.sub.html [ Timeout ] -Bug(none) external/wpt/feature-policy/payment-allowed-by-feature-policy.https.sub.html [ Timeout ] -Bug(none) external/wpt/feature-policy/payment-disabled-by-feature-policy.https.sub.html [ Timeout ] Bug(none) external/wpt/fetch/api/basic/keepalive.html [ Timeout ] Bug(none) external/wpt/fullscreen/api/element-ready-check-allowed-cross-origin-manual.sub.html [ Failure ] Bug(none) external/wpt/fullscreen/api/element-ready-check-not-allowed-cross-origin-manual.sub.html [ Failure ] Bug(none) external/wpt/html/browsers/browsing-the-web/navigating-across-documents/004.html [ Timeout ] -Bug(none) external/wpt/html/browsers/history/the-location-interface/location-origin-idna.sub.window.html [ Timeout ] -Bug(none) external/wpt/html/semantics/embedded-content/media-elements/error-codes/error.html [ Timeout ] -Bug(none) external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay.html [ Timeout ] -Bug(none) external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html [ Timeout ] Bug(none) external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub.html [ Failure ] -Bug(none) external/wpt/preload/dynamic-adding-preload-nonce.html [ Failure ] -Bug(none) external/wpt/preload/dynamic-adding-preload.html [ Failure ] -Bug(none) external/wpt/preload/link-header-on-subresource.html [ Failure ] -Bug(none) external/wpt/preload/link-header-preload-delay-onload.html [ Failure ] -Bug(none) external/wpt/preload/link-header-preload-nonce.html [ Failure ] -Bug(none) external/wpt/preload/link-header-preload.html [ Failure ] -Bug(none) external/wpt/preload/onerror-event.html [ Failure ] -Bug(none) external/wpt/preload/onload-event.html [ Failure ] -Bug(none) external/wpt/preload/preload-with-type.html [ Failure ] -Bug(none) external/wpt/preload/single-download-late-used-preload.html [ Failure ] -Bug(none) external/wpt/preload/single-download-preload.html [ Failure ] -Bug(none) external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html [ Failure ] -Bug(none) external/wpt/upgrade-insecure-requests/iframe-upgrade.https.html [ Crash Timeout ] Bug(none) external/wpt/webmessaging/event.origin.sub.htm [ Failure ] Bug(none) external/wpt/webmessaging/postMessage_asterisk_xorigin.sub.htm [ Failure ] -Bug(none) external/wpt/webmessaging/with-ports/021.html [ Failure ] -Bug(none) external/wpt/webmessaging/without-ports/020.html [ Failure ] -Bug(none) external/wpt/webusb/usb-disabled-by-feature-policy.https.sub.html [ Timeout ] -Bug(none) external/wpt/webvr/webvr-enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html [ Timeout ] Bug(none) storage/indexeddb/blob-valid-before-commit.html [ Failure ] Bug(none) virtual/outofblink-cors/external/wpt/fetch/api/basic/keepalive.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests index ef453e9b..0b5bea9 100644 --- a/third_party/WebKit/LayoutTests/NeverFixTests +++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -45,8 +45,8 @@ [ Win Linux ] fast/dom/partial-layout-overlay-scrollbars.html [ WontFix ] # Tests trak table support / letter spacing specific to Mac system font -# Only maintain this for latest Mac OS -[ Win Linux Android Mac10.10 Mac10.11 Mac10.12 ] fast/text/mac-system-ui-trak.html [ WontFix ] +# Only maintain this for the latest macOS (and Retina is currently 10.12). +[ Win Linux Android Mac10.10 Mac10.11 Mac10.12 Retina ] fast/text/mac-system-ui-trak.html [ WontFix ] # Mac's popup behavior is different. [ Mac ] fast/forms/select/menulist-onchange-fired-with-key-up-down.html [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index e3ca497..eaee435 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1319,9 +1319,9 @@ crbug.com/736319 [ Linux Mac ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-006a.html [ Failure Pass ] crbug.com/736319 [ Linux Mac ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-007.html [ Failure Pass ] -crbug.com/752449 [ Mac10.12 Mac10.13 ] external/wpt/css/css-fonts/matching/fixed-stretch-style-over-weight.html [ Failure ] -crbug.com/752449 [ Mac10.12 Mac10.13 ] external/wpt/css/css-fonts/matching/stretch-distance-over-weight-distance.html [ Failure ] -crbug.com/752449 [ Mac10.12 ] external/wpt/css/css-fonts/matching/style-ranges-over-weight-direction.html [ Failure ] +crbug.com/752449 [ Mac10.12 Mac10.13 Retina ] external/wpt/css/css-fonts/matching/fixed-stretch-style-over-weight.html [ Failure ] +crbug.com/752449 [ Mac10.12 Retina ] external/wpt/css/css-fonts/matching/stretch-distance-over-weight-distance.html [ Failure ] +crbug.com/752449 [ Mac10.12 Retina ] external/wpt/css/css-fonts/matching/style-ranges-over-weight-direction.html [ Failure ] crbug.com/796619 [ Win10 ] external/wpt/css/css-fonts/matching/fixed-stretch-style-over-weight.html [ Failure ] crbug.com/796619 [ Win10 ] external/wpt/css/css-fonts/matching/stretch-distance-over-weight-distance.html [ Failure ] crbug.com/796619 [ Win10 ] external/wpt/css/css-fonts/matching/style-ranges-over-weight-direction.html [ Failure ] @@ -1671,8 +1671,6 @@ crbug.com/803200 external/wpt/websockets/cookies/006.html?wss [ Failure ] crbug.com/803200 external/wpt/websockets/opening-handshake/005.html?wss [ Pass Failure ] -crbug.com/805463 external/wpt/acid/acid3/numbered-tests.html [ Skip ] - # ====== New tests from wpt-importer added here ====== crbug.com/626703 [ Mac10.11 ] external/wpt/payment-handler/can-make-payment-event-constructor.https.worker.html [ Timeout ] crbug.com/626703 [ Linux Win ] external/wpt/css/css-text/letter-spacing/letter-spacing-control-chars-001.html [ Failure ] @@ -3410,9 +3408,6 @@ # Sheriff 2018-03-07 crbug.com/819591 virtual/threaded/animations/hit-testing/composited-with-hit-testing.html [ Failure Pass ] -crbug.com/819683 [ Linux ] paint/invalidation/background/obscured-background-no-repaint.html [ Crash ] -crbug.com/819851 [ Mac ] paint/invalidation/forms/checkbox-focus-by-mouse-then-keydown.html [ Skip ] -crbug.com/819851 [ Mac ] paint/invalidation/forms/radio-focus-by-mouse-then-keydown.html [ Skip ] crbug.com/819778 [ Linux ] external/wpt/css/cssom-view/interfaces.html [ Pass Timeout ] # Sheriff 2018-03-08
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-expected.txt index 2677032f..36067da 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-expected.txt
@@ -595,7 +595,8 @@ "backendNodeId": "<number>", "childNodeIndexes": [ 53 - ] + ], + "shadowRootType": "open" }, { "nodeType": 3, @@ -625,7 +626,8 @@ "value": "font-family: ahem;" } ], - "layoutNodeIndex": 28 + "layoutNodeIndex": 28, + "shadowRootType": "open" }, { "nodeType": 1, @@ -635,7 +637,8 @@ "childNodeIndexes": [ 57 ], - "layoutNodeIndex": 29 + "layoutNodeIndex": 29, + "shadowRootType": "open" }, { "nodeType": 3,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-input-value-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-input-value-expected.txt index 30e63cf..eae4313 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-input-value-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-input-value-expected.txt
@@ -119,7 +119,8 @@ "name": "name", "value": "user-agent-custom-assign-slot" } - ] + ], + "shadowRootType": "user-agent" }, { "nodeType": 1, @@ -205,6 +206,7 @@ 16 ], "layoutNodeIndex": 7, + "shadowRootType": "user-agent", "isClickable": true }, { @@ -418,6 +420,7 @@ 31 ], "layoutNodeIndex": 22, + "shadowRootType": "user-agent", "isClickable": true }, {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/animated-row-background.html b/third_party/WebKit/LayoutTests/paint/invalidation/table/animated-row-background.html index b74fa63..b8faff44 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/table/animated-row-background.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/animated-row-background.html
@@ -12,6 +12,9 @@ <img id="image"> <script src="../resources/text-based-repaint.js"></script> <script> +// The occasional under-invalidation of svg animation as background is harmless. +if (window.internals) + internals.runtimeFlags.paintUnderInvalidationCheckingEnabled = false; window.testIsAsync = true; function repaintTest() { if (window.internals)
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counter-04-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counter-04-b-expected.png deleted file mode 100644 index 7aa97bf..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counter-04-b-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counter-04-b-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counter-04-b-expected.txt deleted file mode 100644 index ed6cb91..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counter-04-b-expected.txt +++ /dev/null
@@ -1,99 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x103 - LayoutBlockFlow {HTML} at (0,0) size 800x103 - LayoutBlockFlow {BODY} at (8,16) size 784x79 - LayoutBlockFlow {P} at (0,0) size 784x18 - LayoutText {#text} at (0,0) size 237x18 - text run at (0,0) width 237: "The following two lines should look " - LayoutInline {EM} at (0,0) size 93x18 - LayoutText {#text} at (236,0) size 93x18 - text run at (236,0) width 93: "approximately" - LayoutText {#text} at (328,0) size 66x18 - text run at (328,0) width 66: " the same:" - LayoutBlockFlow {DIV} at (0,34) size 784x19 - LayoutInline {SPAN} at (0,0) size 9x18 - LayoutInline {<pseudo:before>} at (0,0) size 9x18 - LayoutCounter (anonymous) at (0,1) size 9x18 - text run at (0,1) width 9: "\x{25A0}" - LayoutText {#text} at (8,1) size 5x18 - text run at (8,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 10x18 - LayoutInline {<pseudo:before>} at (0,0) size 10x18 - LayoutCounter (anonymous) at (12,1) size 10x18 - text run at (12,1) width 10: "\x{25A0}" - LayoutText {#text} at (21,1) size 5x18 - text run at (21,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 10x18 - LayoutInline {<pseudo:before>} at (0,0) size 10x18 - LayoutCounter (anonymous) at (25,1) size 10x18 - text run at (25,1) width 10: "\x{25A0}" - LayoutText {#text} at (34,1) size 5x18 - text run at (34,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 9x18 - LayoutInline {<pseudo:before>} at (0,0) size 9x18 - LayoutCounter (anonymous) at (38,1) size 9x18 - text run at (38,1) width 9: "\x{25A0}" - LayoutText {#text} at (46,1) size 5x18 - text run at (46,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 10x18 - LayoutInline {<pseudo:before>} at (0,0) size 10x18 - LayoutCounter (anonymous) at (50,1) size 10x18 - text run at (50,1) width 10: "\x{25A0}" - LayoutText {#text} at (59,1) size 5x18 - text run at (59,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 10x18 - LayoutInline {<pseudo:before>} at (0,0) size 10x18 - LayoutCounter (anonymous) at (63,1) size 10x18 - text run at (63,1) width 10: "\x{25A0}" - LayoutText {#text} at (72,1) size 5x18 - text run at (72,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 9x18 - LayoutInline {<pseudo:before>} at (0,0) size 9x18 - LayoutCounter (anonymous) at (76,1) size 9x18 - text run at (76,1) width 9: "\x{25A0}" - LayoutText {#text} at (84,1) size 5x18 - text run at (84,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 10x18 - LayoutInline {<pseudo:before>} at (0,0) size 10x18 - LayoutCounter (anonymous) at (88,1) size 10x18 - text run at (88,1) width 10: "\x{25A0}" - LayoutText {#text} at (97,1) size 5x18 - text run at (97,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 10x18 - LayoutInline {<pseudo:before>} at (0,0) size 10x18 - LayoutCounter (anonymous) at (101,1) size 10x18 - text run at (101,1) width 10: "\x{25A0}" - LayoutText {#text} at (110,1) size 5x18 - text run at (110,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 9x18 - LayoutInline {<pseudo:before>} at (0,0) size 9x18 - LayoutCounter (anonymous) at (114,1) size 9x18 - text run at (114,1) width 9: "\x{25A0}" - LayoutText {#text} at (122,1) size 5x18 - text run at (122,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 10x18 - LayoutInline {<pseudo:before>} at (0,0) size 10x18 - LayoutCounter (anonymous) at (126,1) size 10x18 - text run at (126,1) width 10: "\x{25A0}" - LayoutText {#text} at (135,1) size 5x18 - text run at (135,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 10x18 - LayoutInline {<pseudo:before>} at (0,0) size 10x18 - LayoutCounter (anonymous) at (139,1) size 10x18 - text run at (139,1) width 10: "\x{25A0}" - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,53) size 784x26 - LayoutText {#text} at (0,6) size 236x18 - text run at (0,6) width 20: "\x{25FE} " - text run at (20,6) width 20: "\x{25FE} " - text run at (40,6) width 20: "\x{25FE} " - text run at (60,6) width 20: "\x{25FE} " - text run at (80,6) width 20: "\x{25FE} " - text run at (100,6) width 20: "\x{25FE} " - text run at (120,6) width 20: "\x{25FE} " - text run at (140,6) width 20: "\x{25FE} " - text run at (160,6) width 20: "\x{25FE} " - text run at (180,6) width 20: "\x{25FE} " - text run at (200,6) width 20: "\x{25FE} " - text run at (220,6) width 16: "\x{25FE}"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counters-04-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counters-04-b-expected.png deleted file mode 100644 index b5be8c9e..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counters-04-b-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counters-04-b-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counters-04-b-expected.txt deleted file mode 100644 index 978769db..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/css2.1/t1202-counters-04-b-expected.txt +++ /dev/null
@@ -1,99 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x103 - LayoutBlockFlow {HTML} at (0,0) size 800x103 - LayoutBlockFlow {BODY} at (8,16) size 784x79 - LayoutBlockFlow {P} at (0,0) size 784x18 - LayoutText {#text} at (0,0) size 237x18 - text run at (0,0) width 237: "The following two lines should look " - LayoutInline {EM} at (0,0) size 93x18 - LayoutText {#text} at (236,0) size 93x18 - text run at (236,0) width 93: "approximately" - LayoutText {#text} at (328,0) size 66x18 - text run at (328,0) width 66: " the same:" - LayoutBlockFlow {DIV} at (0,34) size 784x19 - LayoutInline {SPAN} at (0,0) size 22x18 - LayoutInline {<pseudo:before>} at (0,0) size 22x18 - LayoutCounter (anonymous) at (0,1) size 22x18 - text run at (0,1) width 22: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (21,1) size 5x18 - text run at (21,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 22x18 - LayoutInline {<pseudo:before>} at (0,0) size 22x18 - LayoutCounter (anonymous) at (25,1) size 22x18 - text run at (25,1) width 22: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (46,1) size 5x18 - text run at (46,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 23x18 - LayoutInline {<pseudo:before>} at (0,0) size 23x18 - LayoutCounter (anonymous) at (50,1) size 23x18 - text run at (50,1) width 23: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (72,1) size 5x18 - text run at (72,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 22x18 - LayoutInline {<pseudo:before>} at (0,0) size 22x18 - LayoutCounter (anonymous) at (76,1) size 22x18 - text run at (76,1) width 22: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (97,1) size 5x18 - text run at (97,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 22x18 - LayoutInline {<pseudo:before>} at (0,0) size 22x18 - LayoutCounter (anonymous) at (101,1) size 22x18 - text run at (101,1) width 22: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (122,1) size 5x18 - text run at (122,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 23x18 - LayoutInline {<pseudo:before>} at (0,0) size 23x18 - LayoutCounter (anonymous) at (126,1) size 23x18 - text run at (126,1) width 23: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (148,1) size 5x18 - text run at (148,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 22x18 - LayoutInline {<pseudo:before>} at (0,0) size 22x18 - LayoutCounter (anonymous) at (152,1) size 22x18 - text run at (152,1) width 22: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (173,1) size 5x18 - text run at (173,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 22x18 - LayoutInline {<pseudo:before>} at (0,0) size 22x18 - LayoutCounter (anonymous) at (177,1) size 22x18 - text run at (177,1) width 22: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (198,1) size 5x18 - text run at (198,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 23x18 - LayoutInline {<pseudo:before>} at (0,0) size 23x18 - LayoutCounter (anonymous) at (202,1) size 23x18 - text run at (202,1) width 23: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (224,1) size 5x18 - text run at (224,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 22x18 - LayoutInline {<pseudo:before>} at (0,0) size 22x18 - LayoutCounter (anonymous) at (228,1) size 22x18 - text run at (228,1) width 22: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (249,1) size 5x18 - text run at (249,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 22x18 - LayoutInline {<pseudo:before>} at (0,0) size 22x18 - LayoutCounter (anonymous) at (253,1) size 22x18 - text run at (253,1) width 22: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (274,1) size 5x18 - text run at (274,1) width 5: " " - LayoutInline {SPAN} at (0,0) size 23x18 - LayoutInline {<pseudo:before>} at (0,0) size 23x18 - LayoutCounter (anonymous) at (278,1) size 23x18 - text run at (278,1) width 23: "\x{25A0}.\x{25A0}" - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,53) size 784x26 - LayoutText {#text} at (0,6) size 476x18 - text run at (0,6) width 40: "\x{25FE}.\x{25FE} " - text run at (40,6) width 40: "\x{25FE}.\x{25FE} " - text run at (80,6) width 40: "\x{25FE}.\x{25FE} " - text run at (120,6) width 40: "\x{25FE}.\x{25FE} " - text run at (160,6) width 40: "\x{25FE}.\x{25FE} " - text run at (200,6) width 40: "\x{25FE}.\x{25FE} " - text run at (240,6) width 40: "\x{25FE}.\x{25FE} " - text run at (280,6) width 40: "\x{25FE}.\x{25FE} " - text run at (320,6) width 40: "\x{25FE}.\x{25FE} " - text run at (360,6) width 40: "\x{25FE}.\x{25FE} " - text run at (400,6) width 40: "\x{25FE}.\x{25FE} " - text run at (440,6) width 36: "\x{25FE}.\x{25FE}"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/editing/deleting/delete-line-006-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/editing/deleting/delete-line-006-expected.png deleted file mode 100644 index 4bc44f34..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/editing/deleting/delete-line-006-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/battery-status/battery-full-manual.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/battery-status/battery-full-manual.https-expected.txt deleted file mode 100644 index 0f4003d..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/battery-status/battery-full-manual.https-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL Battery Test: battery full, charger plugged in assert_equals: chargingTime must be set to 0 expected 0 but got Infinity -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/block/positioning/047-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/block/positioning/047-expected.png deleted file mode 100644 index f8ca3a3..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/block/positioning/047-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/datetimelocal/datetimelocal-appearance-l10n-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/datetimelocal/datetimelocal-appearance-l10n-expected.png deleted file mode 100644 index 64a5f017..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/datetimelocal/datetimelocal-appearance-l10n-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/formmove3-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/formmove3-expected.png deleted file mode 100644 index 93f5e17e..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/formmove3-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/month/month-appearance-l10n-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/month/month-appearance-l10n-expected.png deleted file mode 100644 index 0545e8c..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/month/month-appearance-l10n-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/number/number-appearance-spinbutton-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/number/number-appearance-spinbutton-layer-expected.png deleted file mode 100644 index 519c89cc..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/number/number-appearance-spinbutton-layer-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/search/search-display-none-cancel-button-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/search/search-display-none-cancel-button-expected.png deleted file mode 100644 index 59184aed..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/search/search-display-none-cancel-button-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/search/search-display-none-cancel-button-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/search/search-display-none-cancel-button-expected.txt deleted file mode 100644 index 732e3be..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/search/search-display-none-cancel-button-expected.txt +++ /dev/null
@@ -1,16 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutBlockFlow {HTML} at (0,0) size 800x600 - LayoutBlockFlow {BODY} at (8,8) size 784x584 - LayoutText {#text} at (0,0) size 510x18 - text run at (0,0) width 510: "This tests that the display:none style will work on a search field's cancel button." - LayoutBR {BR} at (509,14) size 1x0 - LayoutTextControl {INPUT} at (0,18) size 133x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] - LayoutFlexibleBox {DIV} at (4,3) size 125x13 - LayoutBlockFlow {DIV} at (0,0) size 125x13 - LayoutText {#text} at (0,0) size 0x0 -layer at (12,29) size 125x13 - LayoutBlockFlow {DIV} at (0,0) size 125x13 - LayoutText {#text} at (0,0) size 20x13 - text run at (0,0) width 20: "test"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/003-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/003-expected.png deleted file mode 100644 index 06ffd8f..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/003-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/select-background-none-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/select-background-none-expected.png deleted file mode 100644 index 479595c..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/select-background-none-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png deleted file mode 100644 index 60343011..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/text/input-spaces-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/text/input-spaces-expected.png deleted file mode 100644 index 33b9d6b6..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/text/input-spaces-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/text/textfield-overflow-by-value-update-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/text/textfield-overflow-by-value-update-expected.png deleted file mode 100644 index 6a5adf5..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/text/textfield-overflow-by-value-update-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/invalid/014-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/invalid/014-expected.png deleted file mode 100644 index 6cbaa21..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/invalid/014-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/replaced/replaced-breaking-mixture-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/replaced/replaced-breaking-mixture-expected.png deleted file mode 100644 index c169fca64..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/replaced/replaced-breaking-mixture-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/color-emoji-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/color-emoji-expected.png deleted file mode 100644 index 6759624..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/color-emoji-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/complex-preferred-logical-widths-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/complex-preferred-logical-widths-expected.png deleted file mode 100644 index fa2211a..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/complex-preferred-logical-widths-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/emoticons-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/emoticons-expected.png deleted file mode 100644 index dba363d..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/emoticons-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/flexbox-selection-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/flexbox-selection-expected.png new file mode 100644 index 0000000..30bd61f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/flexbox-selection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/flexbox-selection-nested-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/flexbox-selection-nested-expected.png new file mode 100644 index 0000000..5103b0c --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/flexbox-selection-nested-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/unicode-fallback-font-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/unicode-fallback-font-expected.png deleted file mode 100644 index 62b09ba..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/unicode-fallback-font-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/writing-mode/text-combine-various-fonts-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/writing-mode/text-combine-various-fonts-expected.png deleted file mode 100644 index 129f53f..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/writing-mode/text-combine-various-fonts-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fonts/sans-serif-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fonts/sans-serif-expected.png deleted file mode 100644 index 9b223cd..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fonts/sans-serif-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/misc/bad-charset-alias-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/misc/bad-charset-alias-expected.txt deleted file mode 100644 index 88c213f6..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/misc/bad-charset-alias-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -Test that iso-8859-1 aliases that aren't known to Firefox and IE aren't supported (we should fall back to parent frame charset). - -SUCCESS - -
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/inspector-protocol/layout-fonts/ogham-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/inspector-protocol/layout-fonts/ogham-expected.txt deleted file mode 100644 index f56d468..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/inspector-protocol/layout-fonts/ogham-expected.txt +++ /dev/null
@@ -1,10 +0,0 @@ - ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜ -#oghammonofont: -"Noto Sans Ogham" : 29 - - ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜ -#oghamdefaultfont: -"Noto Sans Ogham" : 29 - -There should be two lines of Ogham above. -
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/inspector-protocol/layout-fonts/tifinagh-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/inspector-protocol/layout-fonts/tifinagh-expected.txt deleted file mode 100644 index 4793163..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/inspector-protocol/layout-fonts/tifinagh-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -ⵉⵎⴷⴰⵏⴻⵏ, ⴰⴽⴽⴻⵏ ⵎⴰ ⵍⵍⴰⵏ ⵜⵜⵍⴰⵍⴻⵏ ⴷ ⵉⵍⴻⵍⵍⵉⵢⴻⵏ ⵎⵙⴰⵡⴰⵏ ⴷⵉ ⵍⵃⵡⴻⵕⵎⴰ ⴷ ⵢⵉⵣⴻⵔⴼⴰⵏ-ⵖⵓⵔ ⵙⴻⵏ ⵜⴰⵎⵙⴰⴽⵡⵉⵜ ⴷ ⵍⴰⵇⵓⴻⵍ ⵓ ⵢⴻⵙⵙⴻⴼⴽ ⴰⴷ-ⵜⵉⵍⵉ ⵜⴻⴳⵎⴰⵜⵜ ⴳⴰⵔ ⴰⵙⴻⵏ -#tifinagh_text: -"Noto Sans Tifinagh" : 109, -"Times" : 23 - -
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png deleted file mode 100644 index d144fd2..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/coords-units-03-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/coords-units-03-b-expected.png deleted file mode 100644 index e8ebf3a..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/coords-units-03-b-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/painting-marker-06-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/painting-marker-06-f-expected.png deleted file mode 100644 index d8f72d75..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/painting-marker-06-f-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/text-intro-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/text-intro-02-b-expected.png deleted file mode 100644 index 270060a..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/text-intro-02-b-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/text-intro-09-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/text-intro-09-b-expected.png deleted file mode 100644 index 8c95a97..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1-SE/text-intro-09-b-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1/struct-use-05-b-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1/struct-use-05-b-expected.txt deleted file mode 100644 index e111d5c..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1/struct-use-05-b-expected.txt +++ /dev/null
@@ -1,29 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutSVGRoot {svg} at (0,0) size 800x600 - LayoutSVGContainer {g} at (0,0) size 0x0 - LayoutSVGHiddenContainer {defs} at (0,0) size 0x0 - LayoutSVGResourceLinearGradient {linearGradient} [id="linearGrad1"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,1)] - LayoutSVGGradientStop {stop} [offset=0.00] [color=#4169E1] - LayoutSVGGradientStop {stop} [offset=0.33] [color=#FFFFFF] - LayoutSVGGradientStop {stop} [offset=0.50] [color=#00008B] - LayoutSVGGradientStop {stop} [offset=0.66] [color=#FFFFFF] - LayoutSVGGradientStop {stop} [offset=1.00] [color=#4169E1] - LayoutSVGResourceRadialGradient {radialGradient} [id="radialGrad1"] [gradientUnits=objectBoundingBox] [center=(0.50,0.50)] [focal=(0.15,0.15)] [radius=0.50] [focalRadius=0.00] - LayoutSVGGradientStop {stop} [offset=0.00] [color=#4169E1] - LayoutSVGGradientStop {stop} [offset=0.33] [color=#FFFFFF] - LayoutSVGGradientStop {stop} [offset=0.50] [color=#00008B] - LayoutSVGGradientStop {stop} [offset=0.66] [color=#FFFFFF] - LayoutSVGGradientStop {stop} [offset=1.00] [color=#4169E1] - LayoutSVGContainer {use} at (0,0) size 0x0 - LayoutSVGContainer {use} at (0,0) size 0x0 - LayoutSVGContainer {use} at (0,0) size 0x0 - LayoutSVGContainer {use} at (0,0) size 0x0 - LayoutSVGText {text} at (42.75,13.39) size 394.47x27.59 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (42.75,13.39) size 394.47x27.59 - chunk 1 (middle anchor) text run 1 at (42.76,35.00) startOffset 0 endOffset 39 width 394.48: "External references and computed values" - LayoutSVGText {text} at (10,304) size 263.31x46.19 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (10,304) size 263.31x46.19 - chunk 1 text run 1 at (10.00,340.00) startOffset 0 endOffset 16 width 263.31: "$Revision: 1.6 $" - LayoutSVGRect {rect} at (1,1) size 478x358 [stroke={[type=SOLID] [color=#000000]}] [x=1.00] [y=1.00] [width=478.00] [height=358.00]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1/text-fonts-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1/text-fonts-01-t-expected.png deleted file mode 100644 index 47db25f..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/W3C-SVG-1.1/text-fonts-01-t-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/text/text-selection-fonts-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/text/text-selection-fonts-01-t-expected.png deleted file mode 100644 index 77e4510..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/text/text-selection-fonts-01-t-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla/bugs/bug194024-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla/bugs/bug194024-expected.png deleted file mode 100644 index fb45699..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla/bugs/bug194024-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla/bugs/bug28928-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla/bugs/bug28928-expected.png deleted file mode 100644 index 9be97bc9..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla/bugs/bug28928-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla/other/move_row-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla/other/move_row-expected.png deleted file mode 100644 index af44f4b..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla/other/move_row-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png deleted file mode 100644 index 5d54f98..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers-expected.png index 2d26010..40840209 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers-expected.png Binary files differ
diff --git a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp index 893cce3..609f99cd 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
@@ -945,6 +945,15 @@ DCHECK(RuntimeEnabledFeatures::CSSMatchesEnabled()); feature = WebFeature::kCSSSelectorPseudoMatches; break; + case CSSSelector::kPseudoFocusVisible: + DCHECK(RuntimeEnabledFeatures::CSSFocusVisibleEnabled()); + if (context_->Mode() != kUASheetMode) + feature = WebFeature::kCSSSelectorPseudoFocusVisible; + break; + case CSSSelector::kPseudoFocus: + if (context_->Mode() != kUASheetMode) + feature = WebFeature::kCSSSelectorPseudoFocus; + break; case CSSSelector::kPseudoAnyLink: feature = WebFeature::kCSSSelectorPseudoAnyLink; break;
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.h b/third_party/WebKit/Source/core/dom/ExecutionContext.h index 236d525d..edf072fa 100644 --- a/third_party/WebKit/Source/core/dom/ExecutionContext.h +++ b/third_party/WebKit/Source/core/dom/ExecutionContext.h
@@ -176,7 +176,7 @@ bool IsWindowInteractionAllowed() const; // Decides whether this context is privileged, as described in - // https://w3c.github.io/webappsec/specs/powerfulfeatures/#settings-privileged. + // https://w3c.github.io/webappsec-secure-contexts/#is-settings-object-contextually-secure. virtual bool IsSecureContext(String& error_message) const = 0; virtual bool IsSecureContext() const;
diff --git a/third_party/WebKit/Source/core/exported/WebViewImpl.cpp b/third_party/WebKit/Source/core/exported/WebViewImpl.cpp index 494a9bc..d52b3a9 100644 --- a/third_party/WebKit/Source/core/exported/WebViewImpl.cpp +++ b/third_party/WebKit/Source/core/exported/WebViewImpl.cpp
@@ -3855,4 +3855,8 @@ return ime_accept_events_ ? FocusedLocalFrameInWidget() : nullptr; } +void WebViewImpl::FreezePage() { + Scheduler()->SetPageFrozen(true); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebViewImpl.h b/third_party/WebKit/Source/core/exported/WebViewImpl.h index 4e820e77..b27c3f1 100644 --- a/third_party/WebKit/Source/core/exported/WebViewImpl.h +++ b/third_party/WebKit/Source/core/exported/WebViewImpl.h
@@ -236,6 +236,7 @@ void SetShowFPSCounter(bool) override; void SetShowScrollBottleneckRects(bool) override; void AcceptLanguagesChanged() override; + void FreezePage() override; // WebScheduler::InterventionReporter implementation: void ReportIntervention(const WebString& message) override;
diff --git a/third_party/WebKit/Source/core/frame/UseCounterTest.cpp b/third_party/WebKit/Source/core/frame/UseCounterTest.cpp index 22029bd..9d619f2 100644 --- a/third_party/WebKit/Source/core/frame/UseCounterTest.cpp +++ b/third_party/WebKit/Source/core/frame/UseCounterTest.cpp
@@ -249,47 +249,6 @@ [&](LocalFrame* frame) { use_counter.DidCommitLoad(frame); }, kSvgUrl); } -TEST_F(UseCounterTest, CSSSelectorPseudoAnyLink) { - std::unique_ptr<DummyPageHolder> dummy_page_holder = - DummyPageHolder::Create(IntSize(800, 600)); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kCSSSelectorPseudoAnyLink; - EXPECT_FALSE(UseCounter::IsCounted(document, feature)); - document.documentElement()->SetInnerHTMLFromString( - "<style>:any-link { color: red; }</style>"); - EXPECT_TRUE(UseCounter::IsCounted(document, feature)); -} - -TEST_F(UseCounterTest, CSSSelectorPseudoWebkitAnyLink) { - std::unique_ptr<DummyPageHolder> dummy_page_holder = - DummyPageHolder::Create(IntSize(800, 600)); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kCSSSelectorPseudoWebkitAnyLink; - EXPECT_FALSE(UseCounter::IsCounted(document, feature)); - document.documentElement()->SetInnerHTMLFromString( - "<style>:-webkit-any-link { color: red; }</style>"); - EXPECT_TRUE(UseCounter::IsCounted(document, feature)); -} - -TEST_F(UseCounterTest, CSSTypedOMStylePropertyMap) { - UseCounter use_counter; - WebFeature feature = WebFeature::kCSSTypedOMStylePropertyMap; - EXPECT_FALSE(use_counter.IsCounted(GetDocument(), feature)); - use_counter.Count(GetDocument(), feature); - EXPECT_TRUE(use_counter.IsCounted(GetDocument(), feature)); -} - -TEST_F(UseCounterTest, CSSSelectorPseudoMatches) { - std::unique_ptr<DummyPageHolder> dummy_page_holder = - DummyPageHolder::Create(IntSize(800, 600)); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kCSSSelectorPseudoMatches; - EXPECT_FALSE(UseCounter::IsCounted(document, feature)); - document.documentElement()->SetInnerHTMLFromString( - "<style>.a+:matches(.b, .c+.d) { color: red; }</style>"); - EXPECT_TRUE(UseCounter::IsCounted(document, feature)); -} - TEST_F(UseCounterTest, InspectorDisablesMeasurement) { UseCounter use_counter; @@ -336,6 +295,58 @@ UseCounter::MapCSSPropertyIdToCSSSampleIdForHistogram(property), 1); } +/* + * Counter-specific tests + * + * NOTE: Most individual UseCounters don't need dedicated test cases. They are + * "tested" by analyzing the data they generate including on some known pages. + * Feel free to add tests for counters where the triggering logic is + * non-trivial, but it's not required. Manual analysis is necessary to trust the + * data anyway, real-world pages are full of edge-cases and surprises that you + * won't find in unit testing anyway. + */ + +TEST_F(UseCounterTest, CSSSelectorPseudoAnyLink) { + std::unique_ptr<DummyPageHolder> dummy_page_holder = + DummyPageHolder::Create(IntSize(800, 600)); + Document& document = dummy_page_holder->GetDocument(); + WebFeature feature = WebFeature::kCSSSelectorPseudoAnyLink; + EXPECT_FALSE(UseCounter::IsCounted(document, feature)); + document.documentElement()->SetInnerHTMLFromString( + "<style>:any-link { color: red; }</style>"); + EXPECT_TRUE(UseCounter::IsCounted(document, feature)); +} + +TEST_F(UseCounterTest, CSSSelectorPseudoWebkitAnyLink) { + std::unique_ptr<DummyPageHolder> dummy_page_holder = + DummyPageHolder::Create(IntSize(800, 600)); + Document& document = dummy_page_holder->GetDocument(); + WebFeature feature = WebFeature::kCSSSelectorPseudoWebkitAnyLink; + EXPECT_FALSE(UseCounter::IsCounted(document, feature)); + document.documentElement()->SetInnerHTMLFromString( + "<style>:-webkit-any-link { color: red; }</style>"); + EXPECT_TRUE(UseCounter::IsCounted(document, feature)); +} + +TEST_F(UseCounterTest, CSSTypedOMStylePropertyMap) { + UseCounter use_counter; + WebFeature feature = WebFeature::kCSSTypedOMStylePropertyMap; + EXPECT_FALSE(use_counter.IsCounted(GetDocument(), feature)); + use_counter.Count(GetDocument(), feature); + EXPECT_TRUE(use_counter.IsCounted(GetDocument(), feature)); +} + +TEST_F(UseCounterTest, CSSSelectorPseudoMatches) { + std::unique_ptr<DummyPageHolder> dummy_page_holder = + DummyPageHolder::Create(IntSize(800, 600)); + Document& document = dummy_page_holder->GetDocument(); + WebFeature feature = WebFeature::kCSSSelectorPseudoMatches; + EXPECT_FALSE(UseCounter::IsCounted(document, feature)); + document.documentElement()->SetInnerHTMLFromString( + "<style>.a+:matches(.b, .c+.d) { color: red; }</style>"); + EXPECT_TRUE(UseCounter::IsCounted(document, feature)); +} + TEST_F(UseCounterTest, DropMeasurementOnViewSourcePages) { UseCounter use_counter; SetIsViewSource();
diff --git a/third_party/WebKit/Source/core/frame/Window.idl b/third_party/WebKit/Source/core/frame/Window.idl index 777ad74..d24b0f4a 100644 --- a/third_party/WebKit/Source/core/frame/Window.idl +++ b/third_party/WebKit/Source/core/frame/Window.idl
@@ -213,7 +213,7 @@ attribute EventHandler onwebkitanimationstart; attribute EventHandler onwebkittransitionend; - // https://w3c.github.io/webappsec/specs/powerfulfeatures/#monkey-patching-global-object + // https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object readonly attribute boolean isSecureContext; attribute DOMMatrixConstructor WebKitCSSMatrix;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMSnapshotAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMSnapshotAgent.cpp index 7478ca9..16111e73 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDOMSnapshotAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorDOMSnapshotAgent.cpp
@@ -279,7 +279,8 @@ DocumentType* doc_type = ToDocumentType(node); value->setPublicId(doc_type->publicId()); value->setSystemId(doc_type->systemId()); - } else if (node->IsInShadowTree()) { + } + if (node->IsInShadowTree()) { value->setShadowRootType( InspectorDOMAgent::GetShadowRootType(node->ContainingShadowRoot())); }
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp index d52c6920..124d9c3b 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -112,7 +112,8 @@ // because we always paint using the latest data (buffered ranges, current // time and duration) which may be different from the cached data, and for // delayed-invalidation object because it may change before it's actually - // invalidated. + // invalidated. Note that we still report harmless under-invalidation of + // non-delayed-invalidation animated background, which should be ignored. if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() && (style.Appearance() == kMediaSliderPart || layout_box_.FullPaintInvalidationReason() ==
diff --git a/third_party/WebKit/Source/core/paint/ImagePainter.cpp b/third_party/WebKit/Source/core/paint/ImagePainter.cpp index bbd8df0..35f57f6 100644 --- a/third_party/WebKit/Source/core/paint/ImagePainter.cpp +++ b/third_party/WebKit/Source/core/paint/ImagePainter.cpp
@@ -109,12 +109,12 @@ paint_info.phase)) return; - // Disable cache in under-invalidation checking mode for delayed-invalidation - // image because it may change before it's actually invalidated. + // Disable cache in under-invalidation checking mode for animated image + // because it may change before it's actually invalidated. Optional<DisplayItemCacheSkipper> cache_skipper; if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() && - layout_image_.FullPaintInvalidationReason() == - PaintInvalidationReason::kDelayedFull) + layout_image_.ImageResource() && + layout_image_.ImageResource()->MaybeAnimated()) cache_skipper.emplace(context); LayoutRect content_rect(paint_offset + layout_image_.ContentBoxOffset(),
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js b/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js index 704966b..41bf1f8 100644 --- a/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js +++ b/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js
@@ -273,7 +273,7 @@ * @param {boolean} encoded * @this {Workspace.UISourceCode} */ - function contentLoaded(updatedContent, encoded) { + async function contentLoaded(updatedContent, encoded) { this._checkingContent = false; if (updatedContent === null) { const workingCopy = this.workingCopy(); @@ -290,14 +290,19 @@ } if (!this.isDirty() || this._workingCopy === updatedContent) { - this._contentCommitted(updatedContent, false); + this._contentCommitted(/** @type {string} */ (updatedContent), false); return; } + await Common.Revealer.reveal(this); + + // Make sure we are in the next frame before stopping the world with confirm + await new Promise(resolve => setTimeout(resolve, 0)); + const shouldUpdate = window.confirm(Common.UIString('This file was changed externally. Would you like to reload it?')); if (shouldUpdate) - this._contentCommitted(updatedContent, false); + this._contentCommitted(/** @type {string} */ (updatedContent), false); else this._lastAcceptedContent = updatedContent; }
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp index 3be6906c..dea30a43 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
@@ -1819,6 +1819,10 @@ return const_cast<AXObject*>(this); } +int AXObject::ChildCount() const { + return static_cast<int>(Children().size()); +} + const AXObject::AXObjectVector& AXObject::Children() const { return const_cast<AXObject*>(this)->Children(); } @@ -1829,6 +1833,36 @@ return children_; } +AXObject* AXObject::FirstChild() const { + return ChildCount() ? *Children().begin() : nullptr; +} + +AXObject* AXObject::LastChild() const { + return ChildCount() ? *(Children().end() - 1) : nullptr; +} + +AXObject* AXObject::DeepestFirstChild() const { + if (!ChildCount()) + return nullptr; + + AXObject* deepest_child = FirstChild(); + while (deepest_child->ChildCount()) + deepest_child = deepest_child->FirstChild(); + + return deepest_child; +} + +AXObject* AXObject::DeepestLastChild() const { + if (!ChildCount()) + return nullptr; + + AXObject* deepest_child = LastChild(); + while (deepest_child->ChildCount()) + deepest_child = deepest_child->LastChild(); + + return deepest_child; +} + bool AXObject::IsAncestorOf(const AXObject& descendant) const { return descendant.IsDescendantOf(*this); } @@ -1840,6 +1874,59 @@ return !!parent; } +AXObject* AXObject::NextSibling() const { + AXObject* parent = ParentObjectUnignored(); + if (!parent) + return nullptr; + + if (IndexInParent() < parent->ChildCount() - 1) + return *(parent->Children().begin() + IndexInParent() + 1); + + return nullptr; +} + +AXObject* AXObject::PreviousSibling() const { + AXObject* parent = ParentObjectUnignored(); + if (!parent) + return nullptr; + + if (IndexInParent() > 0) + return *(parent->Children().begin() + IndexInParent() - 1); + + return nullptr; +} + +AXObject* AXObject::NextInTreeObject(bool can_wrap_to_first_element) const { + if (ChildCount()) + return FirstChild(); + + if (NextSibling()) + return NextSibling(); + AXObject* current_object = const_cast<AXObject*>(this); + while (current_object->ParentObjectUnignored()) { + current_object = current_object->ParentObjectUnignored(); + AXObject* sibling = current_object->NextSibling(); + if (sibling) + return sibling; + } + + return can_wrap_to_first_element ? current_object : nullptr; +} + +AXObject* AXObject::PreviousInTreeObject(bool can_wrap_to_last_element) const { + AXObject* sibling = PreviousSibling(); + if (!sibling) { + if (ParentObjectUnignored()) + return ParentObjectUnignored(); + return can_wrap_to_last_element ? DeepestLastChild() : nullptr; + } + + if (sibling->ChildCount()) + return sibling->DeepestLastChild(); + + return sibling; +} + AXObject* AXObject::ParentObject() const { if (IsDetached()) return nullptr;
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.h b/third_party/WebKit/Source/modules/accessibility/AXObject.h index 1fdd009..8dc2266 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObject.h +++ b/third_party/WebKit/Source/modules/accessibility/AXObject.h
@@ -635,10 +635,21 @@ // High-level accessibility tree access. Other modules should only use these // functions. + int ChildCount() const; const AXObjectVector& Children() const; const AXObjectVector& Children(); + AXObject* FirstChild() const; + AXObject* LastChild() const; + AXObject* DeepestFirstChild() const; + AXObject* DeepestLastChild() const; bool IsAncestorOf(const AXObject&) const; bool IsDescendantOf(const AXObject&) const; + AXObject* NextSibling() const; + AXObject* PreviousSibling() const; + // Next object in tree using depth-first pre-order traversal. + AXObject* NextInTreeObject(bool can_wrap_to_first_element = false) const; + // Previous object in tree using depth-first pre-order traversal. + AXObject* PreviousInTreeObject(bool can_wrap_to_last_element = false) const; AXObject* ParentObject() const; AXObject* ParentObjectIfExists() const; virtual AXObject* ComputeParent() const = 0;
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectTest.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectTest.cpp index debe051..c4701f5 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObjectTest.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXObjectTest.cpp
@@ -36,4 +36,46 @@ EXPECT_FALSE(button->IsAncestorOf(*root)); } +TEST_F(AccessibilityTest, SimpleTreeNavigation) { + SetBodyInnerHTML(R"HTML(<input id='input' type='text' value='value'>" + R"<p id='paragraph'>hello<br id='br'>there</p>" + R"<button id='button'>button</button>)HTML"); + + const AXObject* root = GetAXRootObject(); + ASSERT_NE(nullptr, root); + const AXObject* input = GetAXObjectByElementId("input"); + ASSERT_NE(nullptr, input); + const AXObject* paragraph = GetAXObjectByElementId("paragraph"); + ASSERT_NE(nullptr, paragraph); + const AXObject* br = GetAXObjectByElementId("br"); + ASSERT_NE(nullptr, br); + const AXObject* button = GetAXObjectByElementId("button"); + ASSERT_NE(nullptr, button); + + EXPECT_EQ(input, root->FirstChild()); + EXPECT_EQ(button, root->LastChild()); + EXPECT_EQ(button, root->DeepestLastChild()); + + ASSERT_NE(nullptr, paragraph->FirstChild()); + EXPECT_EQ(AccessibilityRole::kStaticTextRole, + paragraph->FirstChild()->RoleValue()); + ASSERT_NE(nullptr, paragraph->LastChild()); + EXPECT_EQ(AccessibilityRole::kStaticTextRole, + paragraph->LastChild()->RoleValue()); + ASSERT_NE(nullptr, paragraph->DeepestFirstChild()); + EXPECT_EQ(AccessibilityRole::kStaticTextRole, + paragraph->DeepestFirstChild()->RoleValue()); + ASSERT_NE(nullptr, paragraph->DeepestLastChild()); + EXPECT_EQ(AccessibilityRole::kStaticTextRole, + paragraph->DeepestLastChild()->RoleValue()); + + // There is a static text element in between the input and the paragraph. + EXPECT_EQ(paragraph->PreviousSibling(), input->NextSibling()); + ASSERT_NE(nullptr, br->NextSibling()); + EXPECT_EQ(AccessibilityRole::kStaticTextRole, br->NextSibling()->RoleValue()); + ASSERT_NE(nullptr, br->PreviousSibling()); + EXPECT_EQ(AccessibilityRole::kStaticTextRole, + br->PreviousSibling()->RoleValue()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp index 8f063805b..4e9435c5 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
@@ -183,7 +183,7 @@ execution_context->GetSecurityOrigin(); String error_message; // Restrict to secure origins: - // https://w3c.github.io/webappsec/specs/powerfulfeatures/#settings-privileged + // https://w3c.github.io/webappsec-secure-contexts/#is-settings-object-contextually-secure if (!execution_context->IsSecureContext(error_message)) { callbacks->OnError(WebServiceWorkerError( mojom::blink::ServiceWorkerErrorType::kSecurity, error_message));
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp index 2377614..ba3a62e8 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -4268,6 +4268,13 @@ return; } + if (transform_feedback_binding_->active() && + !transform_feedback_binding_->paused()) { + SynthesizeGLError(GL_INVALID_OPERATION, "bindTransformFeedback", + "transform feedback is active and not paused"); + return; + } + WebGLTransformFeedback* feedback_to_be_bound; if (feedback) { feedback_to_be_bound = feedback; @@ -4287,22 +4294,50 @@ if (!ValidateTransformFeedbackPrimitiveMode("beginTransformFeedback", primitive_mode)) return; + if (!current_program_) { + SynthesizeGLError(GL_INVALID_OPERATION, "beginTransformFeedback", + "no program object is active"); + return; + } + if (transform_feedback_binding_->active()) { + SynthesizeGLError(GL_INVALID_OPERATION, "beginTransformFeedback", + "transform feedback is already active"); + return; + } + int required_buffer_count = + current_program_->GetRequiredTransformFeedbackBufferCount(this); + if (required_buffer_count == 0) { + SynthesizeGLError(GL_INVALID_OPERATION, "beginTransformFeedback", + "current active program does not specify any transform " + "feedback varyings to record"); + return; + } + if (!transform_feedback_binding_->HasEnoughBuffers(required_buffer_count)) { + SynthesizeGLError(GL_INVALID_OPERATION, "beginTransformFeedback", + "not enough transform feedback buffers bound"); + return; + } ContextGL()->BeginTransformFeedback(primitive_mode); - - if (current_program_) - current_program_->IncreaseActiveTransformFeedbackCount(); - - if (transform_feedback_binding_) - transform_feedback_binding_->SetProgram(current_program_); + current_program_->IncreaseActiveTransformFeedbackCount(); + transform_feedback_binding_->SetProgram(current_program_); + transform_feedback_binding_->SetActive(true); + transform_feedback_binding_->SetPaused(false); } void WebGL2RenderingContextBase::endTransformFeedback() { if (isContextLost()) return; + if (!transform_feedback_binding_->active()) { + SynthesizeGLError(GL_INVALID_OPERATION, "endTransformFeedback", + "transform feedback is not active"); + return; + } ContextGL()->EndTransformFeedback(); + transform_feedback_binding_->SetPaused(false); + transform_feedback_binding_->SetActive(false); if (current_program_) current_program_->DecreaseActiveTransformFeedbackCount(); } @@ -4340,6 +4375,9 @@ varying_strings.push_back(keep_alive.back().data()); } + program->SetRequiredTransformFeedbackBufferCount( + buffer_mode == GL_INTERLEAVED_ATTRIBS ? 1 : varyings.size()); + ContextGL()->TransformFeedbackVaryings(ObjectOrZero(program), varyings.size(), varying_strings.data(), buffer_mode); } @@ -4391,6 +4429,18 @@ if (isContextLost()) return; + if (!transform_feedback_binding_->active()) { + SynthesizeGLError(GL_INVALID_OPERATION, "pauseTransformFeedback", + "transform feedback is not active"); + return; + } + if (transform_feedback_binding_->paused()) { + SynthesizeGLError(GL_INVALID_OPERATION, "pauseTransformFeedback", + "transform feedback is already paused"); + return; + } + + transform_feedback_binding_->SetPaused(true); ContextGL()->PauseTransformFeedback(); } @@ -4398,13 +4448,21 @@ if (isContextLost()) return; - if (transform_feedback_binding_ && - transform_feedback_binding_->GetProgram() != current_program_) { + if (!transform_feedback_binding_->ValidateProgramForResume( + current_program_)) { SynthesizeGLError(GL_INVALID_OPERATION, "resumeTransformFeedback", - "the program object is not active"); + "the current program is not the same as when " + "beginTransformFeedback was called"); + return; + } + if (!transform_feedback_binding_->active() || + !transform_feedback_binding_->paused()) { + SynthesizeGLError(GL_INVALID_OPERATION, "resumeTransformFeedback", + "transform feedback is not active or not paused"); return; } + transform_feedback_binding_->SetPaused(false); ContextGL()->ResumeTransformFeedback(); } @@ -4436,6 +4494,12 @@ "attempt to bind a deleted buffer"); return; } + if (target == GL_TRANSFORM_FEEDBACK_BUFFER && + transform_feedback_binding_->active()) { + SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferBase", + "transform feedback is active"); + return; + } if (!ValidateAndUpdateBufferBindBaseTarget("bindBufferBase", target, index, buffer)) return; @@ -4458,6 +4522,12 @@ "attempt to bind a deleted buffer"); return; } + if (target == GL_TRANSFORM_FEEDBACK_BUFFER && + transform_feedback_binding_->active()) { + SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferBase", + "transform feedback is active"); + return; + } if (!ValidateValueFitNonNegInt32("bindBufferRange", "offset", offset) || !ValidateValueFitNonNegInt32("bindBufferRange", "size", size)) { return; @@ -5039,32 +5109,6 @@ } } -bool WebGL2RenderingContextBase::IsBufferBoundToTransformFeedback( - WebGLBuffer* buffer) { - DCHECK(buffer); - return transform_feedback_binding_->IsBufferBoundToTransformFeedback(buffer); -} - -bool WebGL2RenderingContextBase::IsBufferBoundToNonTransformFeedback( - WebGLBuffer* buffer) { - DCHECK(buffer); - - if (bound_array_buffer_ == buffer || - bound_vertex_array_object_->BoundElementArrayBuffer() == buffer || - bound_copy_read_buffer_ == buffer || bound_copy_write_buffer_ == buffer || - bound_pixel_pack_buffer_ == buffer || - bound_pixel_unpack_buffer_ == buffer || bound_uniform_buffer_ == buffer) { - return true; - } - - for (size_t i = 0; i <= max_bound_uniform_buffer_index_; ++i) { - if (bound_indexed_uniform_buffers_[i] == buffer) - return true; - } - - return false; -} - bool WebGL2RenderingContextBase::ValidateBufferTargetCompatibility( const char* function_name, GLenum target, @@ -5106,20 +5150,6 @@ break; } - if (target == GL_TRANSFORM_FEEDBACK_BUFFER) { - if (IsBufferBoundToNonTransformFeedback(buffer)) { - SynthesizeGLError(GL_INVALID_OPERATION, function_name, - "a buffer bound to TRANSFORM_FEEDBACK_BUFFER can not " - "be bound to any other targets"); - return false; - } - } else if (IsBufferBoundToTransformFeedback(buffer)) { - SynthesizeGLError(GL_INVALID_OPERATION, function_name, - "a buffer bound to TRANSFORM_FEEDBACK_BUFFER can not be " - "bound to any other targets"); - return false; - } - return true; } @@ -5814,6 +5844,16 @@ bindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer_binding_.Get()); } +void WebGL2RenderingContextBase::useProgram(WebGLProgram* program) { + if (transform_feedback_binding_->active() && + !transform_feedback_binding_->paused()) { + SynthesizeGLError(GL_INVALID_OPERATION, "useProgram", + "transform feedback is active and not paused"); + return; + } + WebGLRenderingContextBase::useProgram(program); +} + GLint WebGL2RenderingContextBase::GetMaxTransformFeedbackSeparateAttribs() const { return max_transform_feedback_separate_attribs_;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h index a5c6b42..ccbdfb3 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
@@ -971,6 +971,7 @@ GLenum type, MaybeShared<DOMArrayBufferView> pixels) override; void RestoreCurrentFramebuffer() override; + void useProgram(WebGLProgram*) override; /* Helpers */ GLint GetMaxTransformFeedbackSeparateAttribs() const;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLProgram.cpp b/third_party/WebKit/Source/modules/webgl/WebGLProgram.cpp index 92c4042..b1e572d 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLProgram.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLProgram.cpp
@@ -40,7 +40,9 @@ link_status_(false), link_count_(0), active_transform_feedback_count_(0), - info_valid_(true) { + info_valid_(true), + required_transform_feedback_buffer_count_(0), + required_transform_feedback_buffer_count_after_next_link_(0) { SetObject(ctx->ContextGL()->CreateProgram()); } @@ -138,6 +140,10 @@ gpu::gles2::GLES2Interface* gl = context->ContextGL(); link_status_ = 0; gl->GetProgramiv(object_, GL_LINK_STATUS, &link_status_); + if (link_status_ == GL_TRUE) { + required_transform_feedback_buffer_count_ = + required_transform_feedback_buffer_count_after_next_link_; + } info_valid_ = true; }
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLProgram.h b/third_party/WebKit/Source/modules/webgl/WebGLProgram.h index 4edd3193..ed146a9 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLProgram.h +++ b/third_party/WebKit/Source/modules/webgl/WebGLProgram.h
@@ -57,6 +57,15 @@ void IncreaseActiveTransformFeedbackCount(); void DecreaseActiveTransformFeedbackCount(); + void SetRequiredTransformFeedbackBufferCount(int count) { + required_transform_feedback_buffer_count_after_next_link_ = count; + } + int GetRequiredTransformFeedbackBufferCount( + WebGLRenderingContextBase* context) { + CacheInfoIfNeeded(context); + return required_transform_feedback_buffer_count_; + } + WebGLShader* GetAttachedShader(GLenum); bool AttachShader(WebGLShader*); bool DetachShader(WebGLShader*); @@ -88,6 +97,10 @@ TraceWrapperMember<WebGLShader> fragment_shader_; bool info_valid_; + + // The number of transform feedback buffers this program will write to. + int required_transform_feedback_buffer_count_; + int required_transform_feedback_buffer_count_after_next_link_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h index 5af4eb1..ff5878f 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -496,7 +496,7 @@ GLboolean transpose, Vector<GLfloat>& value); - void useProgram(WebGLProgram*); + virtual void useProgram(WebGLProgram*); void validateProgram(WebGLProgram*); void vertexAttrib1f(GLuint index, GLfloat x);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.cpp b/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.cpp index 7e7c6c1..d2b1c6dc 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.cpp
@@ -21,7 +21,9 @@ object_(0), type_(type), target_(0), - program_(nullptr) { + program_(nullptr), + active_(false), + paused_(false) { GLint max_attribs = ctx->GetMaxTransformFeedbackSeparateAttribs(); DCHECK_GE(max_attribs, 0); bound_indexed_transform_feedback_buffers_.resize(max_attribs); @@ -80,6 +82,13 @@ void WebGLTransformFeedback::SetProgram(WebGLProgram* program) { program_ = program; + program_link_count_ = program->LinkCount(); +} + +bool WebGLTransformFeedback::ValidateProgramForResume( + WebGLProgram* program) const { + return program && program_ == program && + program->LinkCount() == program_link_count_; } void WebGLTransformFeedback::SetBoundTransformFeedbackBuffer( @@ -121,6 +130,16 @@ return true; } +bool WebGLTransformFeedback::HasEnoughBuffers(GLuint num_required) const { + if (num_required > bound_indexed_transform_feedback_buffers_.size()) + return false; + for (GLuint i = 0; i < num_required; i++) { + if (!bound_indexed_transform_feedback_buffers_[i]) + return false; + } + return true; +} + bool WebGLTransformFeedback::IsBufferBoundToTransformFeedback( WebGLBuffer* buffer) { if (bound_transform_feedback_buffer_ == buffer)
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.h b/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.h index c751bbf..0272b48 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.h +++ b/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.h
@@ -49,6 +49,7 @@ bool SetBoundIndexedTransformFeedbackBuffer(GLuint index, WebGLBuffer*); bool GetBoundIndexedTransformFeedbackBuffer(GLuint index, WebGLBuffer** outBuffer) const; + bool HasEnoughBuffers(GLuint num_required) const; bool IsBufferBoundToTransformFeedback(WebGLBuffer*); @@ -57,6 +58,20 @@ virtual void Trace(blink::Visitor*); virtual void TraceWrappers(const ScriptWrappableVisitor*) const; + bool active() const { return active_; } + bool paused() const { return paused_; } + + void SetActive(bool active) { + active_ = active; + DCHECK(active_ || !paused_); + } + void SetPaused(bool paused) { + paused_ = paused; + DCHECK(active_ || !paused_); + } + + bool ValidateProgramForResume(WebGLProgram*) const; + protected: explicit WebGLTransformFeedback(WebGL2RenderingContextBase*, TFType); @@ -75,6 +90,9 @@ bound_indexed_transform_feedback_buffers_; Member<WebGLProgram> program_; + unsigned program_link_count_; + bool active_; + bool paused_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index 4f256d0d..e6202e9 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1053,6 +1053,8 @@ "graphics/VideoFrameSubmitter.h", "graphics/WebGraphicsContext3DProviderWrapper.cpp", "graphics/WebGraphicsContext3DProviderWrapper.h", + "graphics/compositing/ChunkToLayerMapper.cpp", + "graphics/compositing/ChunkToLayerMapper.h", "graphics/compositing/CompositedLayerRasterInvalidator.cpp", "graphics/compositing/CompositedLayerRasterInvalidator.h", "graphics/compositing/ContentLayerClientImpl.cpp", @@ -1856,6 +1858,7 @@ "graphics/PlaceholderImageTest.cpp", "graphics/StaticBitmapImageTest.cpp", "graphics/VideoFrameSubmitterTest.cpp", + "graphics/compositing/ChunkToLayerMapperTest.cpp", "graphics/compositing/CompositedLayerRasterInvalidatorTest.cpp", "graphics/compositing/PaintArtifactCompositorTest.cpp", "graphics/compositing/PaintChunksToCcLayerTest.cpp",
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/ChunkToLayerMapper.cpp b/third_party/WebKit/Source/platform/graphics/compositing/ChunkToLayerMapper.cpp new file mode 100644 index 0000000..22ea570 --- /dev/null +++ b/third_party/WebKit/Source/platform/graphics/compositing/ChunkToLayerMapper.cpp
@@ -0,0 +1,107 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/graphics/compositing/ChunkToLayerMapper.h" + +#include "platform/graphics/paint/GeometryMapper.h" +#include "platform/graphics/paint/PaintChunk.h" + +namespace blink { + +void ChunkToLayerMapper::SwitchToChunk(const PaintChunk& chunk) { + outset_for_raster_effects_ = chunk.outset_for_raster_effects; + + const auto& new_chunk_state = + chunk.properties.property_tree_state.GetPropertyTreeState(); + if (new_chunk_state == chunk_state_) + return; + + if (new_chunk_state == layer_state_) { + has_filter_that_moves_pixels_ = false; + transform_ = TransformationMatrix().Translate(-layer_offset_.x(), + -layer_offset_.y()); + clip_rect_ = FloatClipRect(); + chunk_state_ = new_chunk_state; + return; + } + + if (new_chunk_state.Transform() != chunk_state_.Transform()) { + transform_ = GeometryMapper::SourceToDestinationProjection( + new_chunk_state.Transform(), layer_state_.Transform()); + transform_.PostTranslate(-layer_offset_.x(), -layer_offset_.y()); + } + + bool new_has_filter_that_moves_pixels = has_filter_that_moves_pixels_; + if (new_chunk_state.Effect() != chunk_state_.Effect()) { + new_has_filter_that_moves_pixels = false; + for (const auto* effect = new_chunk_state.Effect(); + effect && effect != layer_state_.Effect(); effect = effect->Parent()) { + if (effect->HasFilterThatMovesPixels()) { + new_has_filter_that_moves_pixels = true; + break; + } + } + } + + bool needs_clip_recalculation = + new_has_filter_that_moves_pixels != has_filter_that_moves_pixels_ || + new_chunk_state.Clip() != chunk_state_.Clip(); + if (needs_clip_recalculation) { + clip_rect_ = + GeometryMapper::LocalToAncestorClipRect(new_chunk_state, layer_state_); + if (!clip_rect_.IsInfinite()) + clip_rect_.MoveBy(FloatPoint(-layer_offset_.x(), -layer_offset_.y())); + } + + chunk_state_ = new_chunk_state; + has_filter_that_moves_pixels_ = new_has_filter_that_moves_pixels; +} + +IntRect ChunkToLayerMapper::MapVisualRect(const FloatRect& rect) const { + if (rect.IsEmpty()) + return IntRect(); + + if (UNLIKELY(has_filter_that_moves_pixels_)) + return MapUsingGeometryMapper(rect); + + FloatRect mapped_rect = transform_.MapRect(rect); + if (!mapped_rect.IsEmpty() && !clip_rect_.IsInfinite()) + mapped_rect.Intersect(clip_rect_.Rect()); + + if (mapped_rect.IsEmpty()) { + DCHECK_EQ(IntRect(), MapUsingGeometryMapper(rect)); + return IntRect(); + } + + mapped_rect.Inflate(outset_for_raster_effects_); + auto result = EnclosingIntRect(mapped_rect); +#if DCHECK_IS_ON() + auto slow_result = MapUsingGeometryMapper(rect); + if (result != slow_result) { + // Not a DCHECK because this may result from a floating point error. + LOG(WARNING) << "ChunkToLayerMapper::MapVisualRect: Different results from" + << "fast path (" << result << ") and slow path (" + << slow_result << ")"; + } +#endif + return result; +} + +// This is called when the fast path doesn't apply if there is any filter that +// moves pixels. GeometryMapper::LocalToAncestorVisualRect() will apply the +// visual effects of the filters, though slowly. +IntRect ChunkToLayerMapper::MapUsingGeometryMapper( + const FloatRect& rect) const { + FloatClipRect visual_rect(rect); + GeometryMapper::LocalToAncestorVisualRect(chunk_state_, layer_state_, + visual_rect); + if (visual_rect.Rect().IsEmpty()) + return IntRect(); + + visual_rect.Rect().Move(-layer_offset_.x(), -layer_offset_.y()); + visual_rect.Rect().Inflate(outset_for_raster_effects_); + return EnclosingIntRect(visual_rect.Rect()); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/ChunkToLayerMapper.h b/third_party/WebKit/Source/platform/graphics/compositing/ChunkToLayerMapper.h new file mode 100644 index 0000000..5ac3d0f2 --- /dev/null +++ b/third_party/WebKit/Source/platform/graphics/compositing/ChunkToLayerMapper.h
@@ -0,0 +1,64 @@ +// Copyright 2018 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 ChunkToLayerMapper_h +#define ChunkToLayerMapper_h + +#include "platform/graphics/paint/FloatClipRect.h" +#include "platform/graphics/paint/PropertyTreeState.h" + +namespace blink { + +struct PaintChunk; + +// Maps geometry from PaintChunks to the containing composited layer. +// It provides higher performance than GeometryMapper by reusing computed +// transforms and clips for unchanged states within or across paint chunks. +class PLATFORM_EXPORT ChunkToLayerMapper { + DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + + public: + ChunkToLayerMapper(const PropertyTreeState& layer_state, + const gfx::Vector2dF& layer_offset) + : layer_state_(layer_state), + layer_offset_(layer_offset), + chunk_state_(nullptr, nullptr, nullptr) {} + + // This class can map from multiple chunks. Before mapping from a chunk, this + // method must be called to prepare for the chunk. + void SwitchToChunk(const PaintChunk&); + + // Maps a visual rectangle in the current chunk space into the layer space. + IntRect MapVisualRect(const FloatRect&) const; + + // Returns the combined transform from the current chunk to the layer. + const TransformationMatrix& Transform() const { return transform_; } + + // Returns the combined clip from the current chunk to the layer if it can + // be calculated (there is no filter that moves pixels), or infinite loose + // clip rect otherwise. + const FloatClipRect& ClipRect() const { return clip_rect_; } + + private: + friend class ChunkToLayerMapperTest; + + IntRect MapUsingGeometryMapper(const FloatRect&) const; + + const PropertyTreeState layer_state_; + const gfx::Vector2dF layer_offset_; + + // The following fields are chunk-specific which are updated in + // SwitchToChunk(). + PropertyTreeState chunk_state_; + float outset_for_raster_effects_ = 0.f; + TransformationMatrix transform_; + FloatClipRect clip_rect_; + // True if there is any pixel-moving filter between chunk state and layer + // state, and we will call GeometryMapper for each mapping. + bool has_filter_that_moves_pixels_ = false; +}; + +} // namespace blink + +#endif // PaintArtifactCompositor_h
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/ChunkToLayerMapperTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/ChunkToLayerMapperTest.cpp new file mode 100644 index 0000000..6cb686a9 --- /dev/null +++ b/third_party/WebKit/Source/platform/graphics/compositing/ChunkToLayerMapperTest.cpp
@@ -0,0 +1,234 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/graphics/compositing/ChunkToLayerMapper.h" + +#include "platform/graphics/paint/DisplayItem.h" +#include "platform/graphics/paint/PaintChunk.h" +#include "platform/testing/FakeDisplayItemClient.h" +#include "platform/wtf/Optional.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +class ChunkToLayerMapperTest : public ::testing::Test { + protected: + static PaintChunk Chunk(const PropertyTreeState& state) { + DEFINE_STATIC_LOCAL(FakeDisplayItemClient, fake_client, ()); + DEFINE_STATIC_LOCAL( + Optional<PaintChunk::Id>, id, + (PaintChunk::Id(fake_client, DisplayItem::kDrawingFirst))); + PaintChunk chunk(0, 0, *id, PaintChunkProperties(state)); + return chunk; + } + + // A state containing arbitrary values which should not affect test results + // if the state is used as a layer state. + PropertyTreeState LayerState() { + DEFINE_STATIC_REF( + TransformPaintPropertyNode, transform, + TransformPaintPropertyNode::Create( + TransformPaintPropertyNode::Root(), + TransformationMatrix().Translate(123, 456), FloatPoint3D(1, 2, 3))); + DEFINE_STATIC_REF( + ClipPaintPropertyNode, clip, + ClipPaintPropertyNode::Create(ClipPaintPropertyNode::Root(), transform, + FloatRoundedRect(12, 34, 56, 78))); + DEFINE_STATIC_REF( + EffectPaintPropertyNode, effect, + EffectPaintPropertyNode::Create( + EffectPaintPropertyNode::Root(), transform, clip, + kColorFilterLuminanceToAlpha, CompositorFilterOperations(), 0.789f, + SkBlendMode::kSrcIn)); + return PropertyTreeState(transform, clip, effect); + } + + bool HasFilterThatMovesPixels(const ChunkToLayerMapper& mapper) { + return mapper.has_filter_that_moves_pixels_; + } +}; + +TEST_F(ChunkToLayerMapperTest, OneChunkUsingLayerState) { + ChunkToLayerMapper mapper(LayerState(), gfx::Vector2dF(10, 20)); + auto chunk = Chunk(LayerState()); + mapper.SwitchToChunk(chunk); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20), mapper.Transform()); + EXPECT_EQ(FloatClipRect(), mapper.ClipRect()); + EXPECT_EQ(IntRect(20, 10, 88, 99), + mapper.MapVisualRect(FloatRect(30, 30, 88, 99))); + EXPECT_EQ(IntRect(20, 10, 88, 99), + mapper.MapVisualRect(FloatRect(30.2f, 30.7f, 87.3f, 98.1f))); + EXPECT_EQ(IntRect(), mapper.MapVisualRect(FloatRect())); +} + +TEST_F(ChunkToLayerMapperTest, TwoChunkUsingLayerState) { + ChunkToLayerMapper mapper(LayerState(), gfx::Vector2dF(10, 20)); + auto chunk1 = Chunk(LayerState()); + auto chunk2 = Chunk(LayerState()); + + mapper.SwitchToChunk(chunk1); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20), mapper.Transform()); + EXPECT_EQ(FloatClipRect(), mapper.ClipRect()); + EXPECT_EQ(IntRect(20, 10, 88, 99), + mapper.MapVisualRect(FloatRect(30, 30, 88, 99))); + EXPECT_EQ(IntRect(20, 10, 88, 99), + mapper.MapVisualRect(FloatRect(30.2f, 30.7f, 87.3f, 98.1f))); + EXPECT_EQ(IntRect(), mapper.MapVisualRect(FloatRect())); + + mapper.SwitchToChunk(chunk2); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20), mapper.Transform()); + EXPECT_EQ(FloatClipRect(), mapper.ClipRect()); + EXPECT_EQ(IntRect(20, 10, 88, 99), + mapper.MapVisualRect(FloatRect(30, 30, 88, 99))); + EXPECT_EQ(IntRect(20, 10, 88, 99), + mapper.MapVisualRect(FloatRect(30.2f, 30.7f, 87.3f, 98.1f))); + EXPECT_EQ(IntRect(), mapper.MapVisualRect(FloatRect())); +} + +TEST_F(ChunkToLayerMapperTest, TwoChunkSameState) { + ChunkToLayerMapper mapper(LayerState(), gfx::Vector2dF(10, 20)); + auto transform = TransformPaintPropertyNode::Create( + LayerState().Transform(), TransformationMatrix().Scale(2), + FloatPoint3D()); + auto clip = ClipPaintPropertyNode::Create(LayerState().Clip(), + LayerState().Transform(), + FloatRoundedRect(10, 10, 100, 100)); + auto effect = LayerState().Effect(); + auto chunk1 = Chunk(PropertyTreeState(transform.get(), clip.get(), effect)); + auto chunk2 = Chunk(PropertyTreeState(transform.get(), clip.get(), effect)); + + mapper.SwitchToChunk(chunk1); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20).Scale(2), + mapper.Transform()); + EXPECT_EQ(FloatRect(0, -10, 100, 100), mapper.ClipRect().Rect()); + EXPECT_TRUE(mapper.ClipRect().IsTight()); + EXPECT_EQ(IntRect(50, 40, 50, 50), + mapper.MapVisualRect(FloatRect(30, 30, 88, 99))); + EXPECT_EQ(IntRect(), mapper.MapVisualRect(FloatRect())); + + mapper.SwitchToChunk(chunk2); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20).Scale(2), + mapper.Transform()); + EXPECT_EQ(FloatRect(0, -10, 100, 100), mapper.ClipRect().Rect()); + EXPECT_TRUE(mapper.ClipRect().IsTight()); + EXPECT_EQ(IntRect(50, 40, 50, 50), + mapper.MapVisualRect(FloatRect(30, 30, 88, 99))); + EXPECT_EQ(IntRect(), mapper.MapVisualRect(FloatRect())); +} + +TEST_F(ChunkToLayerMapperTest, TwoChunkDifferentState) { + ChunkToLayerMapper mapper(LayerState(), gfx::Vector2dF(10, 20)); + auto transform1 = TransformPaintPropertyNode::Create( + LayerState().Transform(), TransformationMatrix().Scale(2), + FloatPoint3D()); + auto clip1 = ClipPaintPropertyNode::Create( + LayerState().Clip(), LayerState().Transform(), + FloatRoundedRect(10, 10, 100, 100)); + auto effect = LayerState().Effect(); + auto chunk1 = Chunk(PropertyTreeState(transform1.get(), clip1.get(), effect)); + + auto transform2 = TransformPaintPropertyNode::Create( + transform1, TransformationMatrix().Translate(20, 30), FloatPoint3D()); + auto clip2 = ClipPaintPropertyNode::Create(LayerState().Clip(), transform2, + FloatRoundedRect(0, 0, 20, 20)); + auto chunk2 = Chunk(PropertyTreeState(transform2.get(), clip2.get(), effect)); + + mapper.SwitchToChunk(chunk1); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20).Scale(2), + mapper.Transform()); + EXPECT_EQ(FloatRect(0, -10, 100, 100), mapper.ClipRect().Rect()); + EXPECT_TRUE(mapper.ClipRect().IsTight()); + EXPECT_EQ(IntRect(50, 40, 50, 50), + mapper.MapVisualRect(FloatRect(30, 30, 88, 99))); + EXPECT_EQ(IntRect(), mapper.MapVisualRect(FloatRect())); + + mapper.SwitchToChunk(chunk2); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ( + TransformationMatrix().Translate(-10, -20).Scale(2).Translate(20, 30), + mapper.Transform()); + EXPECT_EQ(FloatRect(30, 40, 40, 40), mapper.ClipRect().Rect()); + EXPECT_FALSE(mapper.ClipRect().IsTight()); + EXPECT_EQ(IntRect(30, 40, 40, 40), + mapper.MapVisualRect(FloatRect(0, 0, 200, 200))); + EXPECT_EQ(IntRect(), mapper.MapVisualRect(FloatRect())); +} + +TEST_F(ChunkToLayerMapperTest, SlowPath) { + ChunkToLayerMapper mapper(LayerState(), gfx::Vector2dF(10, 20)); + auto chunk1 = Chunk(LayerState()); + + // Chunk2 has a blur filter. Should use the slow path. + CompositorFilterOperations filter2; + filter2.AppendBlurFilter(20); + auto effect2 = EffectPaintPropertyNode::Create( + EffectPaintPropertyNode::Root(), LayerState().Transform(), + LayerState().Clip(), kColorFilterNone, filter2, 1.f, SkBlendMode::kDstIn); + auto chunk2 = Chunk(PropertyTreeState(LayerState().Transform(), + LayerState().Clip(), effect2.get())); + + // Chunk3 has a different effect which inherits from chunk2's effect. + // Should use the slow path. + auto effect3 = EffectPaintPropertyNode::Create( + effect2.get(), LayerState().Transform(), LayerState().Clip(), + kColorFilterNone, CompositorFilterOperations(), 1.f, SkBlendMode::kDstIn); + auto chunk3 = Chunk(PropertyTreeState(LayerState().Transform(), + LayerState().Clip(), effect3.get())); + + // Chunk4 has an opacity filter effect which inherits from the layer's effect. + // Should use the fast path. + CompositorFilterOperations filter4; + filter4.AppendOpacityFilter(0.5); + auto effect4 = EffectPaintPropertyNode::Create( + LayerState().Effect(), LayerState().Transform(), LayerState().Clip(), + kColorFilterNone, CompositorFilterOperations(), 1.f, SkBlendMode::kDstIn); + auto chunk4 = Chunk(PropertyTreeState(LayerState().Transform(), + LayerState().Clip(), effect4.get())); + + // Chunk5 goes back to the layer state. + auto chunk5 = Chunk(LayerState()); + + mapper.SwitchToChunk(chunk1); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20), mapper.Transform()); + EXPECT_EQ(FloatClipRect(), mapper.ClipRect()); + + mapper.SwitchToChunk(chunk2); + EXPECT_TRUE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20), mapper.Transform()); + EXPECT_TRUE(mapper.ClipRect().IsInfinite()); + EXPECT_EQ(IntRect(-40, -50, 208, 219), + mapper.MapVisualRect(FloatRect(30, 30, 88, 99))); + EXPECT_EQ(IntRect(-40, -50, 208, 219), + mapper.MapVisualRect(FloatRect(30.2f, 30.7f, 87.3f, 98.1f))); + EXPECT_EQ(IntRect(), mapper.MapVisualRect(FloatRect())); + + mapper.SwitchToChunk(chunk3); + EXPECT_TRUE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20), mapper.Transform()); + EXPECT_TRUE(mapper.ClipRect().IsInfinite()); + EXPECT_EQ(IntRect(-40, -50, 208, 219), + mapper.MapVisualRect(FloatRect(30, 30, 88, 99))); + EXPECT_EQ(IntRect(-40, -50, 208, 219), + mapper.MapVisualRect(FloatRect(30.2f, 30.7f, 87.3f, 98.1f))); + EXPECT_EQ(IntRect(), mapper.MapVisualRect(FloatRect())); + + mapper.SwitchToChunk(chunk4); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20), mapper.Transform()); + EXPECT_EQ(FloatClipRect(), mapper.ClipRect()); + + mapper.SwitchToChunk(chunk5); + EXPECT_FALSE(HasFilterThatMovesPixels(mapper)); + EXPECT_EQ(TransformationMatrix().Translate(-10, -20), mapper.Transform()); + EXPECT_EQ(FloatClipRect(), mapper.ClipRect()); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidator.cpp b/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidator.cpp index a11f22e..aad465d 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidator.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidator.cpp
@@ -30,44 +30,6 @@ } } -IntRect CompositedLayerRasterInvalidator::MapRectFromChunkToLayer( - const FloatRect& r, - const PaintChunk& chunk, - const PropertyTreeState& layer_state) const { - return ClipByLayerBounds(PaintChunksToCcLayer::MapRectFromChunkToLayer( - r, chunk, layer_state, layer_bounds_.OffsetFromOrigin())); -} - -TransformationMatrix CompositedLayerRasterInvalidator::ChunkToLayerTransform( - const PaintChunk& chunk, - const PropertyTreeState& layer_state) const { - auto matrix = GeometryMapper::SourceToDestinationProjection( - chunk.properties.property_tree_state.Transform(), - layer_state.Transform()); - matrix.Translate(-layer_bounds_.x(), -layer_bounds_.y()); - return matrix; -} - -// Returns the clip rect when we know it is precise (no radius, no complex -// transform, no pixel moving filter, etc.) -FloatClipRect CompositedLayerRasterInvalidator::ChunkToLayerClip( - const PaintChunk& chunk, - const PropertyTreeState& layer_state) const { - FloatClipRect clip_rect; - if (chunk.properties.property_tree_state.Effect() != layer_state.Effect()) { - // Don't bother GeometryMapper because we don't need the rect when it's not - // tight because of the effect nodes. - clip_rect.ClearIsTight(); - } else { - clip_rect = GeometryMapper::LocalToAncestorClipRect( - chunk.properties.property_tree_state.GetPropertyTreeState(), - layer_state); - if (clip_rect.IsTight()) - clip_rect.MoveBy(FloatPoint(-layer_bounds_.x(), -layer_bounds_.y())); - } - return clip_rect; -} - size_t CompositedLayerRasterInvalidator::MatchNewChunkToOldChunk( const PaintChunk& new_chunk, size_t old_index) { @@ -141,15 +103,18 @@ // is slightly larger than O(n). void CompositedLayerRasterInvalidator::GenerateRasterInvalidations( const Vector<const PaintChunk*>& new_chunks, - const Vector<PaintChunkInfo>& new_chunks_info, - const PropertyTreeState& layer_state) { + const PropertyTreeState& layer_state, + Vector<PaintChunkInfo>& new_chunks_info) { + ChunkToLayerMapper mapper(layer_state, layer_bounds_.OffsetFromOrigin()); Vector<bool> old_chunks_matched; old_chunks_matched.resize(paint_chunks_info_.size()); size_t old_index = 0; size_t max_matched_old_index = 0; for (size_t new_index = 0; new_index < new_chunks.size(); ++new_index) { const auto& new_chunk = *new_chunks[new_index]; - const auto& new_chunk_info = new_chunks_info[new_index]; + mapper.SwitchToChunk(new_chunk); + const auto& new_chunk_info = + new_chunks_info.emplace_back(*this, mapper, new_chunk); if (!new_chunk.is_cacheable) { FullyInvalidateNewChunk(new_chunk_info, @@ -191,7 +156,7 @@ IncrementallyInvalidateChunk(old_chunk_info, new_chunk_info); // Add the raster invalidations found by PaintController within the chunk. - AddDisplayItemRasterInvalidations(new_chunk, layer_state); + AddDisplayItemRasterInvalidations(new_chunk, mapper); } old_index = matched_old_index + 1; @@ -213,14 +178,17 @@ void CompositedLayerRasterInvalidator::AddDisplayItemRasterInvalidations( const PaintChunk& chunk, - const PropertyTreeState& layer_state) { + const ChunkToLayerMapper& mapper) { DCHECK(chunk.raster_invalidation_tracking.IsEmpty() || chunk.raster_invalidation_rects.size() == chunk.raster_invalidation_tracking.size()); + if (chunk.raster_invalidation_rects.IsEmpty()) + return; + for (size_t i = 0; i < chunk.raster_invalidation_rects.size(); ++i) { - auto rect = MapRectFromChunkToLayer(chunk.raster_invalidation_rects[i], - chunk, layer_state); + auto rect = ClipByLayerBounds( + mapper.MapVisualRect(chunk.raster_invalidation_rects[i])); if (rect.IsEmpty()) continue; raster_invalidation_function_(rect); @@ -300,26 +268,34 @@ if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) EnsureTracking(); - bool layer_bounds_was_empty = layer_bounds_.IsEmpty(); - layer_bounds_ = layer_bounds; - - Vector<PaintChunkInfo> new_chunks_info; - new_chunks_info.ReserveCapacity(paint_chunks.size()); - for (const auto* chunk : paint_chunks) { - new_chunks_info.push_back(PaintChunkInfo( - MapRectFromChunkToLayer(chunk->bounds, *chunk, layer_state), - ChunkToLayerTransform(*chunk, layer_state), - ChunkToLayerClip(*chunk, layer_state), *chunk)); - if (tracking_info_) { + if (tracking_info_) { + for (const auto* chunk : paint_chunks) { tracking_info_->new_client_debug_names.insert( &chunk->id.client, chunk->id.client.DebugName()); } } - if (!layer_bounds_was_empty && !layer_bounds_.IsEmpty()) - GenerateRasterInvalidations(paint_chunks, new_chunks_info, layer_state); + bool layer_bounds_was_empty = layer_bounds_.IsEmpty(); + layer_bounds_ = layer_bounds; + + Vector<PaintChunkInfo> new_chunks_info; + new_chunks_info.ReserveCapacity(paint_chunks.size()); + + if (layer_bounds_was_empty || layer_bounds_.IsEmpty()) { + // No raster invalidation is needed if either the old bounds or the new + // bounds is empty, but we still need to update new_chunks_info for the + // next cycle. + ChunkToLayerMapper mapper(layer_state, layer_bounds.OffsetFromOrigin()); + for (const auto* chunk : paint_chunks) { + mapper.SwitchToChunk(*chunk); + new_chunks_info.emplace_back(*this, mapper, *chunk); + } + } else { + GenerateRasterInvalidations(paint_chunks, layer_state, new_chunks_info); + } paint_chunks_info_ = std::move(new_chunks_info); + if (tracking_info_) { tracking_info_->old_client_debug_names = std::move(tracking_info_->new_client_debug_names);
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidator.h b/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidator.h index 240b39aa..75b5f1c 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidator.h +++ b/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidator.h
@@ -5,6 +5,7 @@ #ifndef CompositedLayerRasterInvalidator_h #define CompositedLayerRasterInvalidator_h +#include "platform/graphics/compositing/ChunkToLayerMapper.h" #include "platform/graphics/paint/FloatClipRect.h" #include "platform/graphics/paint/PaintChunk.h" #include "platform/graphics/paint/RasterInvalidationTracking.h" @@ -48,13 +49,13 @@ friend class CompositedLayerRasterInvalidatorTest; struct PaintChunkInfo { - PaintChunkInfo(const IntRect& bounds, - const TransformationMatrix& chunk_to_layer_transform, - const FloatClipRect& chunk_to_layer_clip, + PaintChunkInfo(const CompositedLayerRasterInvalidator& invalidator, + const ChunkToLayerMapper& mapper, const PaintChunk& chunk) - : bounds_in_layer(bounds), - chunk_to_layer_transform(chunk_to_layer_transform), - chunk_to_layer_clip(chunk_to_layer_clip), + : bounds_in_layer(invalidator.ClipByLayerBounds( + mapper.MapVisualRect(chunk.bounds))), + chunk_to_layer_transform(mapper.Transform()), + chunk_to_layer_clip(mapper.ClipRect()), id(chunk.id), is_cacheable(chunk.is_cacheable), properties(chunk.properties) {} @@ -71,22 +72,12 @@ PaintChunkProperties properties; }; - IntRect MapRectFromChunkToLayer(const FloatRect&, - const PaintChunk&, - const PropertyTreeState& layer_state) const; - TransformationMatrix ChunkToLayerTransform( - const PaintChunk&, - const PropertyTreeState& layer_state) const; - FloatClipRect ChunkToLayerClip(const PaintChunk&, - const PropertyTreeState& layer_state) const; - - void GenerateRasterInvalidations( - const Vector<const PaintChunk*>& new_chunks, - const Vector<PaintChunkInfo>& new_chunks_info, - const PropertyTreeState& layer_state); + void GenerateRasterInvalidations(const Vector<const PaintChunk*>& new_chunks, + const PropertyTreeState& layer_state, + Vector<PaintChunkInfo>& new_chunks_info); size_t MatchNewChunkToOldChunk(const PaintChunk& new_chunk, size_t old_index); void AddDisplayItemRasterInvalidations(const PaintChunk&, - const PropertyTreeState& layer_state); + const ChunkToLayerMapper&); void IncrementallyInvalidateChunk(const PaintChunkInfo& old_chunk, const PaintChunkInfo& new_chunk); void FullyInvalidateChunk(const PaintChunkInfo& old_chunk,
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidatorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidatorTest.cpp index 7624036..8927dca 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidatorTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/CompositedLayerRasterInvalidatorTest.cpp
@@ -294,10 +294,8 @@ EXPECT_TRUE(TrackedRasterInvalidations(invalidator).IsEmpty()); // Change both clip0 and clip2. - LOG(ERROR) << "22222222222222222222222222222222222222222222"; CHUNKS(new_chunks, Chunk(0), Chunk(1), Chunk(2)); FloatRoundedRect new_clip_rect(FloatRect(-2000, -2000, 4000, 4000), radii); - LOG(ERROR) << "new_clip_rect: " << new_clip_rect.ToString(); clip0->Update(clip0->Parent(), clip0->LocalTransformSpace(), new_clip_rect); clip2->Update(clip2->Parent(), clip2->LocalTransformSpace(), new_clip_rect); new_chunks_array[0].properties = chunks[0]->properties; @@ -314,7 +312,6 @@ PaintInvalidationReason::kPaintProperty); invalidator.SetTracksRasterInvalidations(false); clip2->ClearChangedToRoot(); - LOG(ERROR) << "333333333333333333333333333333333333333333333"; // Change chunk1's properties to use a different property tree state. CHUNKS(new_chunks1, Chunk(0), Chunk(1), Chunk(2));
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp index 7f939b5..fd78bd0 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
@@ -8,6 +8,7 @@ #include "cc/paint/paint_op_buffer.h" #include "cc/paint/render_surface_filters.h" #include "platform/graphics/GraphicsContext.h" +#include "platform/graphics/compositing/ChunkToLayerMapper.h" #include "platform/graphics/paint/DisplayItemList.h" #include "platform/graphics/paint/DrawingDisplayItem.h" #include "platform/graphics/paint/GeometryMapper.h" @@ -424,6 +425,8 @@ translated = true; }; + ChunkToLayerMapper mapper(layer_state_, layer_offset_); + for (auto chunk_it = paint_chunks.begin(); chunk_it != paint_chunks.end(); chunk_it++) { const PaintChunk& chunk = **chunk_it; @@ -450,6 +453,8 @@ properties_adjusted = true; }; + mapper.SwitchToChunk(chunk); + for (const auto& item : display_items.ItemsInPaintChunk(chunk)) { DCHECK(item.IsDrawing()); auto record = @@ -469,8 +474,7 @@ cc_list_.StartPaint(); if (record && record->size() != 0) cc_list_.push<cc::DrawRecordOp>(std::move(record)); - cc_list_.EndPaintOfUnpaired(PaintChunksToCcLayer::MapRectFromChunkToLayer( - item.VisualRect(), chunk, layer_state_, layer_offset_)); + cc_list_.EndPaintOfUnpaired(mapper.MapVisualRect(item.VisualRect())); } if (transformed) AppendRestore(1); @@ -528,23 +532,4 @@ return cc_list; } -IntRect PaintChunksToCcLayer::MapRectFromChunkToLayer( - const FloatRect& r, - const PaintChunk& chunk, - const PropertyTreeState& layer_state, - const gfx::Vector2dF& layer_offset) { - FloatClipRect rect(r); - GeometryMapper::LocalToAncestorVisualRect( - chunk.properties.property_tree_state.GetPropertyTreeState(), layer_state, - rect); - if (rect.Rect().IsEmpty()) - return IntRect(); - - // Now rect is in the space of the containing transform node of layer, - // so need to subtract off the layer offset. - rect.Rect().Move(-layer_offset.x(), -layer_offset.y()); - rect.Rect().Inflate(chunk.outset_for_raster_effects); - return EnclosingIntRect(rect.Rect()); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h index cc29ae0..4c56db6 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h
@@ -69,11 +69,6 @@ const DisplayItemList&, cc::DisplayItemList::UsageHint, RasterUnderInvalidationCheckingParams* = nullptr); - - static IntRect MapRectFromChunkToLayer(const FloatRect&, - const PaintChunk&, - const PropertyTreeState& layer_state, - const gfx::Vector2dF& layer_offset); }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp index 82b4f80..34d3d37 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp
@@ -250,6 +250,11 @@ local_state.Clip(), ancestor_state.Clip(), ancestor_state.Transform(), clip_behavior, success); DCHECK(success); + + // Many effects (e.g. filters, clip-paths) can make a clip rect not tight. + if (local_state.Effect() != ancestor_state.Effect()) + result.ClearIsTight(); + return result; }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp index a7c4195..8a4db2c 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp
@@ -649,6 +649,7 @@ expected_visual_rect = FloatClipRect(output); expected_visual_rect.ClearIsTight(); expected_clip = FloatClipRect(FloatRect(50, 60, 90, 90)); + expected_clip.ClearIsTight(); CHECK_MAPPINGS(); }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp index d31d8ca..cfcb00f 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -6,15 +6,12 @@ #include <memory> #include "platform/graphics/GraphicsLayer.h" +#include "platform/graphics/LoggingCanvas.h" #include "platform/graphics/paint/DrawingDisplayItem.h" #include "platform/instrumentation/tracing/TraceEvent.h" #include "platform/wtf/AutoReset.h" #include "platform/wtf/text/StringBuilder.h" -#ifndef NDEBUG -#include "platform/graphics/LoggingCanvas.h" -#endif - namespace blink { void PaintController::SetTracksRasterInvalidations(bool value) { @@ -1019,12 +1016,8 @@ LOG(ERROR) << "New display item: " << new_item.AsDebugString(); LOG(ERROR) << "Old display item: " << (old_item ? old_item->AsDebugString() : "None"); -#else - LOG(ERROR) << "Run a build with DCHECK on to get more details."; -#endif LOG(ERROR) << "See http://crbug.com/619103."; -#ifndef NDEBUG const PaintRecord* new_record = nullptr; if (new_item.IsDrawing()) { new_record = @@ -1044,7 +1037,10 @@ : "None"); ShowDebugData(); -#endif // NDEBUG +#else + LOG(ERROR) << "Run a build with DCHECK on to get more details."; + LOG(ERROR) << "See http://crbug.com/619103."; +#endif } void PaintController::ShowSequenceUnderInvalidationError(
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc index deea3d1..cf60ad2 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc
@@ -96,6 +96,10 @@ DURATION_PER_QUEUE_TYPE_METRIC_NAME ".HiddenMusic"), per_frame_status_duration_reporter(DURATION_PER_FRAME_TYPE_METRIC_NAME), per_task_type_duration_reporter(DURATION_PER_TASK_TYPE_METRIC_NAME), + foreground_per_task_type_duration_reporter( + DURATION_PER_TASK_TYPE_METRIC_NAME ".Foreground"), + background_per_task_type_duration_reporter( + DURATION_PER_TASK_TYPE_METRIC_NAME ".Background"), main_thread_task_load_state(MainThreadTaskLoadState::kUnknown) { main_thread_load_tracker.Resume(now); if (renderer_backgrounded) { @@ -230,6 +234,9 @@ per_queue_type_task_duration_reporter.RecordTask(queue_type, duration); + TaskType task_type = static_cast<TaskType>(task.task_type()); + per_task_type_duration_reporter.RecordTask(task_type, duration); + if (renderer_scheduler_->main_thread_only().renderer_backgrounded) { background_per_queue_type_task_duration_reporter.RecordTask(queue_type, duration); @@ -276,6 +283,8 @@ backgrounded_at + base::TimeDelta::FromMinutes(5), std::max(backgrounded_at + base::TimeDelta::FromMinutes(5), end_time))); + + background_per_task_type_duration_reporter.RecordTask(task_type, duration); } else { foreground_per_queue_type_task_duration_reporter.RecordTask(queue_type, duration); @@ -310,6 +319,8 @@ foregrounded_at + base::TimeDelta::FromMinutes(3), std::max(foregrounded_at + base::TimeDelta::FromMinutes(3), end_time))); + + foreground_per_task_type_duration_reporter.RecordTask(task_type, duration); } if (renderer_scheduler_->main_thread_only().renderer_hidden) { @@ -354,9 +365,6 @@ UMA_HISTOGRAM_ENUMERATION(COUNT_PER_FRAME_METRIC_NAME ".LongerThan1s", frame_status, FrameStatus::kCount); } - - per_task_type_duration_reporter.RecordTask( - static_cast<TaskType>(task.task_type()), duration); } void RendererMetricsHelper::RecordMainThreadTaskLoad(base::TimeTicks time,
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.h index d5f057e..49c7ac3 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.h +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.h
@@ -119,6 +119,10 @@ using TaskDurationPerTaskTypeMetricReporter = TaskDurationMetricReporter<TaskType>; TaskDurationPerTaskTypeMetricReporter per_task_type_duration_reporter; + TaskDurationPerTaskTypeMetricReporter + foreground_per_task_type_duration_reporter; + TaskDurationPerTaskTypeMetricReporter + background_per_task_type_duration_reporter; MainThreadTaskLoadState main_thread_task_load_state;
diff --git a/third_party/WebKit/Source/platform/testing/FakeDisplayItemClient.h b/third_party/WebKit/Source/platform/testing/FakeDisplayItemClient.h index 3742758..d67d5fe 100644 --- a/third_party/WebKit/Source/platform/testing/FakeDisplayItemClient.h +++ b/third_party/WebKit/Source/platform/testing/FakeDisplayItemClient.h
@@ -6,6 +6,7 @@ #define FakeDisplayItemClient_h #include "platform/geometry/LayoutRect.h" +#include "platform/graphics/paint/DisplayItemClient.h" #include "platform/wtf/Forward.h" namespace blink {
diff --git a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h index d77dc0c..5be4efa 100644 --- a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h +++ b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h
@@ -144,7 +144,7 @@ PolicyAreas = kPolicyAreaAll); // Schemes which bypass Secure Context checks defined in - // https://w3c.github.io/webappsec/specs/powerfulfeatures/#is-origin-trustworthy. + // https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy static void RegisterURLSchemeBypassingSecureContextCheck( const String& scheme); static bool SchemeShouldBypassSecureContextCheck(const String& scheme);
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h index bc1179d..3640e65 100644 --- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h +++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
@@ -123,7 +123,7 @@ // Returns true if the origin loads resources either from the local // machine or over the network from a // cryptographically-authenticated origin, as described in - // https://w3c.github.io/webappsec/specs/powerfulfeatures/#is-origin-trustworthy. + // https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy bool IsPotentiallyTrustworthy() const; // Returns a human-readable error message describing that a non-secure
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/platform_info.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/platform_info.py index cb3b427c..dab67d1 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/platform_info.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/platform_info.py
@@ -74,7 +74,7 @@ if self.is_mac(): output = self._executive.run_command(['system_profiler', 'SPDisplaysDataType'], error_handler=self._executive.ignore_error) - if output and 'Retina: Yes' in output: + if output and re.search(r'Resolution:.*Retina$', output, re.MULTILINE): return True return False
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/mac.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/mac.py index 8ca5a7d..819c953 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/mac.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/mac.py
@@ -40,12 +40,12 @@ SUPPORTED_VERSIONS = ('mac10.10', 'mac10.11', 'mac10.12', 'mac10.13', 'retina') port_name = 'mac' - # FIXME: We treat Retina (High-DPI) devices as if they are running - # a different operating system version. This is lame and should be fixed. - # Note that the retina versions fallback to the non-retina versions and so no - # baselines are shared between retina versions; this keeps the fallback graph as a tree - # and maximizes the number of baselines we can share that way. - # We also currently only support Retina on 10.11. + # FIXME: We treat Retina (High-DPI) devices as if they are running a + # different operating system version. This is lame and should be fixed. + # Note that the retina versions fallback to the non-retina versions and so + # no baselines are shared between retina versions; this keeps the fallback + # graph as a tree and maximizes the number of baselines we can share that + # way. We also currently only support Retina on 10.12. FALLBACK_PATHS = {} @@ -53,7 +53,7 @@ FALLBACK_PATHS['mac10.12'] = ['mac-mac10.12'] + FALLBACK_PATHS['mac10.13'] FALLBACK_PATHS['mac10.11'] = ['mac-mac10.11'] + FALLBACK_PATHS['mac10.12'] FALLBACK_PATHS['mac10.10'] = ['mac-mac10.10'] + FALLBACK_PATHS['mac10.11'] - FALLBACK_PATHS['retina'] = ['mac-retina'] + FALLBACK_PATHS['mac10.11'] + FALLBACK_PATHS['retina'] = ['mac-retina'] + FALLBACK_PATHS['mac10.12'] CONTENT_SHELL_NAME = 'Content Shell'
diff --git a/third_party/WebKit/public/platform/WebSecurityOrigin.h b/third_party/WebKit/public/platform/WebSecurityOrigin.h index 798ade33..6bbf812 100644 --- a/third_party/WebKit/public/platform/WebSecurityOrigin.h +++ b/third_party/WebKit/public/platform/WebSecurityOrigin.h
@@ -92,7 +92,7 @@ // Returns true if the origin loads resources either from the local // machine or over the network from a // cryptographically-authenticated origin, as described in - // https://w3c.github.io/webappsec/specs/powerfulfeatures/#is-origin-trustworthy. + // https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy. BLINK_PLATFORM_EXPORT bool IsPotentiallyTrustworthy() const; // Returns a string representation of the WebSecurityOrigin. The empty
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom index 716b0536..4476c4b6 100644 --- a/third_party/WebKit/public/platform/web_feature.mojom +++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1876,6 +1876,8 @@ kRtcPeerConnectionId = 2384, kV8PaintWorkletGlobalScope_RegisterPaint_Method = 2385, kV8PaintWorkletGlobalScope_DevicePixelRatio_AttributeGetter = 2386, + kCSSSelectorPseudoFocus = 2387, + kCSSSelectorPseudoFocusVisible = 2388, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/public/web/WebView.h b/third_party/WebKit/public/web/WebView.h index 8fc376c..69a9beca 100644 --- a/third_party/WebKit/public/web/WebView.h +++ b/third_party/WebKit/public/web/WebView.h
@@ -428,6 +428,11 @@ // to call the WebViewClient::acceptLanguages(). virtual void AcceptLanguagesChanged() = 0; + // Lifecycle state ------------------------------------------------------ + + // Freeze the page and all the local frames. + virtual void FreezePage() = 0; + // Testing functionality for TestRunner --------------------------------- // Force the webgl context to fail so that webglcontextcreationerror
diff --git a/third_party/webrtc_overrides/DEPS b/third_party/webrtc_overrides/DEPS index 529c21d..a191f6d 100644 --- a/third_party/webrtc_overrides/DEPS +++ b/third_party/webrtc_overrides/DEPS
@@ -1,5 +1,6 @@ include_rules = [ '+base', + '+build', '+net/base', '+third_party/webrtc', '+third_party/webrtc_overrides',
diff --git a/third_party/webrtc_overrides/rtc_base/task_queue.cc b/third_party/webrtc_overrides/rtc_base/task_queue.cc index fd811b6..74f16803 100644 --- a/third_party/webrtc_overrides/rtc_base/task_queue.cc +++ b/third_party/webrtc_overrides/rtc_base/task_queue.cc
@@ -13,104 +13,191 @@ #include "base/bind.h" #include "base/lazy_instance.h" #include "base/memory/ref_counted.h" -#include "base/threading/thread.h" +#include "base/synchronization/waitable_event.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/thread_local.h" +#include "build/build_config.h" #include "third_party/webrtc/rtc_base/refcount.h" #include "third_party/webrtc/rtc_base/refcountedobject.h" -// Intentionally outside of the "namespace rtc { ... }" block, because -// here, scoped_refptr should *not* be resolved as rtc::scoped_refptr. -namespace { - -void RunTask(std::unique_ptr<rtc::QueuedTask> task) { - if (!task->Run()) - task.release(); -} - -class PostAndReplyTask : public rtc::QueuedTask { - public: - PostAndReplyTask( - std::unique_ptr<rtc::QueuedTask> task, - std::unique_ptr<rtc::QueuedTask> reply, - const scoped_refptr<base::SingleThreadTaskRunner>& reply_task_runner) - : task_(std::move(task)), - reply_(std::move(reply)), - reply_task_runner_(reply_task_runner) {} - - ~PostAndReplyTask() override {} - - private: - bool Run() override { - if (!task_->Run()) - task_.release(); - - reply_task_runner_->PostTask(FROM_HERE, - base::Bind(&RunTask, base::Passed(&reply_))); - return true; - } - - std::unique_ptr<rtc::QueuedTask> task_; - std::unique_ptr<rtc::QueuedTask> reply_; - scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner_; -}; - -// A lazily created thread local storage for quick access to a TaskQueue. -base::LazyInstance<base::ThreadLocalPointer<rtc::TaskQueue>>::Leaky - lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER; - -} // namespace +using base::WaitableEvent; namespace rtc { +namespace { + +// A lazily created thread local storage for quick access to a TaskQueue. +base::LazyInstance<base::ThreadLocalPointer<TaskQueue>>::Leaky lazy_tls_ptr = + LAZY_INSTANCE_INITIALIZER; + +base::TaskTraits TaskQueuePriority2Traits(TaskQueue::Priority priority) { + // The content/renderer/media/webrtc/rtc_video_encoder.* code + // employs a PostTask/Wait pattern that uses TQ in a way that makes it + // blocking and synchronous, which is why we allow WithBaseSyncPrimitives() + // for OS_ANDROID. + switch (priority) { + case TaskQueue::Priority::HIGH: +#if defined(OS_ANDROID) + return {base::WithBaseSyncPrimitives(), base::TaskPriority::HIGHEST}; +#else + return {base::TaskPriority::HIGHEST}; +#endif + break; + case TaskQueue::Priority::LOW: + return {base::MayBlock(), base::TaskPriority::BACKGROUND}; + case TaskQueue::Priority::NORMAL: + default: +#if defined(OS_ANDROID) + return {base::WithBaseSyncPrimitives()}; +#else + return {}; +#endif + } +} + +} // namespace bool TaskQueue::IsCurrent() const { return Current() == this; } -class TaskQueue::Impl : public RefCountInterface, public base::Thread { +class TaskQueue::Impl : public RefCountInterface { public: - Impl(const char* queue_name, TaskQueue* queue); + Impl(const char* queue_name, + TaskQueue* queue, + const base::TaskTraits& traits); ~Impl() override; + // To maintain functional compatibility with WebRTC's TaskQueue, we flush + // and deactivate the task queue here, synchronously. + // This has some drawbacks and will likely change in the future, but for now + // is necessary. + void Stop(); + + void PostTask(std::unique_ptr<QueuedTask> task); + void PostDelayedTask(std::unique_ptr<QueuedTask> task, uint32_t milliseconds); + void PostTaskAndReply(std::unique_ptr<QueuedTask> task, + std::unique_ptr<QueuedTask> reply, + TaskQueue* reply_queue); + void PostTaskAndReply(std::unique_ptr<QueuedTask> task, + std::unique_ptr<QueuedTask> reply); + private: - virtual void Init() override; + void RunTask(std::unique_ptr<QueuedTask> task); + void Deactivate(WaitableEvent* event); + + class PostAndReplyTask : public QueuedTask { + public: + PostAndReplyTask(std::unique_ptr<QueuedTask> task, + ::scoped_refptr<TaskQueue::Impl> target_queue, + std::unique_ptr<QueuedTask> reply, + ::scoped_refptr<TaskQueue::Impl> reply_queue) + : task_(std::move(task)), + target_queue_(std::move(target_queue)), + reply_(std::move(reply)), + reply_queue_(std::move(reply_queue)) {} + + ~PostAndReplyTask() override {} + + private: + bool Run() override { + if (task_) { + target_queue_->RunTask(std::move(task_)); + std::unique_ptr<QueuedTask> t = std::unique_ptr<QueuedTask>(this); + reply_queue_->PostTask(std::move(t)); + return false; // Don't delete, ownership lies with reply_queue_. + } + + reply_queue_->RunTask(std::move(reply_)); + + return true; // OK to delete. + } + + std::unique_ptr<QueuedTask> task_; + ::scoped_refptr<TaskQueue::Impl> target_queue_; + std::unique_ptr<QueuedTask> reply_; + ::scoped_refptr<TaskQueue::Impl> reply_queue_; + }; TaskQueue* const queue_; + const ::scoped_refptr<base::SequencedTaskRunner> task_runner_; + bool is_active_ = true; // Checked and set on |task_runner_|. }; -TaskQueue::Impl::Impl(const char* queue_name, TaskQueue* queue) - : base::Thread(queue_name), queue_(queue) {} +// TaskQueue::Impl. -void TaskQueue::Impl::Init() { +TaskQueue::Impl::Impl(const char* queue_name, + TaskQueue* queue, + const base::TaskTraits& traits) + : queue_(queue), + task_runner_(base::CreateSequencedTaskRunnerWithTraits(traits)) { + DCHECK(task_runner_); +} + +TaskQueue::Impl::~Impl() {} + +void TaskQueue::Impl::Stop() { + WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, + WaitableEvent::InitialState::NOT_SIGNALED); + task_runner_->PostTask( + FROM_HERE, base::BindOnce(&TaskQueue::Impl::Deactivate, this, &event)); + event.Wait(); +} + +void TaskQueue::Impl::PostTask(std::unique_ptr<QueuedTask> task) { + task_runner_->PostTask(FROM_HERE, base::BindOnce(&TaskQueue::Impl::RunTask, + this, base::Passed(&task))); +} + +void TaskQueue::Impl::PostDelayedTask(std::unique_ptr<QueuedTask> task, + uint32_t milliseconds) { + task_runner_->PostDelayedTask( + FROM_HERE, + base::BindOnce(&TaskQueue::Impl::RunTask, this, base::Passed(&task)), + base::TimeDelta::FromMilliseconds(milliseconds)); +} + +void TaskQueue::Impl::PostTaskAndReply(std::unique_ptr<QueuedTask> task, + std::unique_ptr<QueuedTask> reply, + TaskQueue* reply_queue) { + std::unique_ptr<QueuedTask> t = + std::unique_ptr<QueuedTask>(new PostAndReplyTask( + std::move(task), this, std::move(reply), reply_queue->impl_.get())); + PostTask(std::move(t)); +} + +void TaskQueue::Impl::PostTaskAndReply(std::unique_ptr<QueuedTask> task, + std::unique_ptr<QueuedTask> reply) { + PostTaskAndReply(std::move(task), std::move(reply), queue_); +} + +void TaskQueue::Impl::RunTask(std::unique_ptr<QueuedTask> task) { + if (!is_active_) + return; + + auto* prev = lazy_tls_ptr.Pointer()->Get(); lazy_tls_ptr.Pointer()->Set(queue_); + if (!task->Run()) + task.release(); + lazy_tls_ptr.Pointer()->Set(prev); } -TaskQueue::Impl::~Impl() { - DCHECK(!Thread::IsRunning()); +void TaskQueue::Impl::Deactivate(WaitableEvent* event) { + is_active_ = false; + event->Signal(); } +// TaskQueue. + TaskQueue::TaskQueue(const char* queue_name, Priority priority /*= Priority::NORMAL*/) - : impl_(new RefCountedObject<Impl>(queue_name, this)) { + : impl_(new RefCountedObject<Impl>(queue_name, + this, + TaskQueuePriority2Traits(priority))) { DCHECK(queue_name); - base::Thread::Options options; - switch (priority) { - case Priority::HIGH: - options.priority = base::ThreadPriority::REALTIME_AUDIO; - break; - case Priority::LOW: - options.priority = base::ThreadPriority::BACKGROUND; - break; - case Priority::NORMAL: - default: - options.priority = base::ThreadPriority::NORMAL; - break; - } - CHECK(impl_->StartWithOptions(options)); } TaskQueue::~TaskQueue() { DCHECK(!IsCurrent()); - impl_->Stop(); } // static @@ -119,29 +206,23 @@ } void TaskQueue::PostTask(std::unique_ptr<QueuedTask> task) { - impl_->task_runner()->PostTask(FROM_HERE, - base::Bind(&RunTask, base::Passed(&task))); + impl_->PostTask(std::move(task)); } void TaskQueue::PostDelayedTask(std::unique_ptr<QueuedTask> task, uint32_t milliseconds) { - impl_->task_runner()->PostDelayedTask( - FROM_HERE, base::Bind(&RunTask, base::Passed(&task)), - base::TimeDelta::FromMilliseconds(milliseconds)); + impl_->PostDelayedTask(std::move(task), milliseconds); } void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task, std::unique_ptr<QueuedTask> reply, TaskQueue* reply_queue) { - PostTask(std::unique_ptr<QueuedTask>(new PostAndReplyTask( - std::move(task), std::move(reply), reply_queue->impl_->task_runner()))); + impl_->PostTaskAndReply(std::move(task), std::move(reply), reply_queue); } void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task, std::unique_ptr<QueuedTask> reply) { - impl_->task_runner()->PostTaskAndReply( - FROM_HERE, base::Bind(&RunTask, base::Passed(&task)), - base::Bind(&RunTask, base::Passed(&reply))); + impl_->PostTaskAndReply(std::move(task), std::move(reply)); } } // namespace rtc
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 9a61624..8890c4a6 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -7743,9 +7743,22 @@ <int value="50" label="0.5: Slowest"/> <int value="75" label="0.75: Slow"/> <int value="100" label="1.0: Normal"/> - <int value="125" label="1.25: Fast"/> - <int value="150" label="1.5: Faster"/> - <int value="200" label="2.0: Fastest"/> + <int value="125" label="1.25"/> + <int value="150" label="1.5"/> + <int value="175" label="1.75"/> + <int value="200" label="2.0"/> + <int value="225" label="2.25"/> + <int value="250" label="2.5"/> + <int value="275" label="2.75"/> + <int value="300" label="3.0"/> + <int value="325" label="3.25"/> + <int value="350" label="3.5"/> + <int value="375" label="3.75"/> + <int value="400" label="4.0"/> + <int value="425" label="4.25"/> + <int value="450" label="4.5"/> + <int value="475" label="4.75"/> + <int value="500" label="5.0: Fastest"/> </enum> <enum name="CrosSelectToSpeakStartSpeechMethod"> @@ -17943,6 +17956,8 @@ <int value="2385" label="V8PaintWorkletGlobalScope_RegisterPaint_Method"/> <int value="2386" label="V8PaintWorkletGlobalScope_DevicePixelRatio_AttributeGetter"/> + <int value="2387" label="CSSSelectorPseudoFocus"/> + <int value="2388" label="CSSSelectorPseudoFocusVisible"/> </enum> <enum name="FeedbackSource"> @@ -26743,6 +26758,7 @@ <int value="665409384" label="AutofillToolkitViewsCreditCardDialogsMac:enabled"/> <int value="679931272" label="DcheckIsFatal:enabled"/> + <int value="682549212" label="ash-enable-cursor-motion-blur"/> <int value="684806628" label="TranslateLanguageByULP:disabled"/> <int value="685916283" label="enable-zip-archiver-on-file-manager"/> <int value="687838135" label="ThirdPartyDoodles:disabled"/> @@ -26906,7 +26922,9 @@ <int value="1075637651" label="disable-tablet-splitview"/> <int value="1079032226" label="ParallelDownloading:enabled"/> <int value="1081546525" label="ash-enable-docked-windows"/> + <int value="1082054180" label="PersistentWindowBounds:disabled"/> <int value="1082405724" label="AutofillUpstreamUseGooglePayBranding:enabled"/> + <int value="1083201516" label="PersistentWindowBounds:enabled"/> <int value="1087235172" label="file-manager-enable-new-audio-player"/> <int value="1090377940" label="enable-quic-https"/> <int value="1092896354" label="EnableFullscreenAppList:disabled"/> @@ -27097,6 +27115,7 @@ <int value="1497924954" label="js-flags"/> <int value="1499163193" label="PostScriptPrinting:disabled"/> <int value="1505194447" label="disable-transition-compositing"/> + <int value="1508761653" label="disable-site-isolation-trials"/> <int value="1509901380" label="disable-drive-search-in-app-launcher"/> <int value="1510476448" label="disable-prefixed-encrypted-media"/> <int value="1510659184" label="MacMDDownloadShelf:enabled"/> @@ -27857,9 +27876,9 @@ <int value="175" label="webkit-appearance"/> <int value="176" label="webkit-aspect-ratio"/> <int value="177" label="alias-webkit-backface-visibility"/> - <int value="178" label="webkit-background-clip"/> + <int value="178" label="alias-webkit-background-clip"/> <int value="179" label="webkit-background-composite"/> - <int value="180" label="webkit-background-origin"/> + <int value="180" label="alias-webkit-background-origin"/> <int value="181" label="alias-webkit-background-size"/> <int value="182" label="webkit-border-after"/> <int value="183" label="webkit-border-after-color"/> @@ -28270,6 +28289,8 @@ <int value="588" label="font-variant-east-asian"/> <int value="589" label="text-decoration-skip-ink"/> <int value="590" label="scroll-customization"/> + <int value="591" label="row-gap"/> + <int value="592" label="gap"/> </enum> <enum name="MappedEditingCommands">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 1ee4d94f..d30877e 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -112719,6 +112719,7 @@ <suffix name="Background"/> <suffix name="Foreground"/> <affected-histogram name="RendererScheduler.TaskCPUDurationPerThreadType"/> + <affected-histogram name="RendererScheduler.TaskDurationPerTaskType"/> <affected-histogram name="RendererScheduler.TaskDurationPerThreadType"/> </histogram_suffixes>
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py index 052caca..b66677e 100755 --- a/tools/perf/process_perf_results.py +++ b/tools/perf/process_perf_results.py
@@ -22,6 +22,9 @@ build_properties, oauth_file, tmp_dir): """Upload the contents of result JSON(s) to the perf dashboard.""" build_properties = json.loads(build_properties) + if not configuration_name: + # we are deprecating perf-id crbug.com/817823 + configuration_name = build_properties['buildername'], args = [ '--tmp-dir', tmp_dir, '--buildername', build_properties['buildername'],
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn index 2c4586d..0a8a1f8 100644 --- a/ui/app_list/BUILD.gn +++ b/ui/app_list/BUILD.gn
@@ -51,6 +51,10 @@ "views/folder_header_view.cc", "views/folder_header_view.h", "views/folder_header_view_delegate.h", + "views/horizontal_page.cc", + "views/horizontal_page.h", + "views/horizontal_page_container.cc", + "views/horizontal_page_container.h", "views/image_shadow_animator.cc", "views/image_shadow_animator.h", "views/indicator_chip_view.cc",
diff --git a/ui/app_list/views/app_list_folder_view.cc b/ui/app_list/views/app_list_folder_view.cc index d47d243..bbaff79 100644 --- a/ui/app_list/views/app_list_folder_view.cc +++ b/ui/app_list/views/app_list_folder_view.cc
@@ -15,7 +15,6 @@ #include "ui/app_list/app_list_util.h" #include "ui/app_list/pagination_model.h" #include "ui/app_list/views/app_list_item_view.h" -#include "ui/app_list/views/app_list_main_view.h" #include "ui/app_list/views/apps_container_view.h" #include "ui/app_list/views/apps_grid_view.h" #include "ui/app_list/views/contents_view.h" @@ -411,9 +410,9 @@ AppListFolderView::AppListFolderView(AppsContainerView* container_view, AppListModel* model, - AppListMainView* app_list_main_view) + ContentsView* contents_view) : container_view_(container_view), - app_list_main_view_(app_list_main_view), + contents_view_(contents_view), background_view_(new views::View), contents_container_(new views::View), folder_header_view_(new FolderHeaderView(this)), @@ -434,8 +433,7 @@ AddChildView(contents_container_); view_model_->Add(contents_container_, kIndexContentsContainer); - items_grid_view_ = - new AppsGridView(app_list_main_view_->contents_view(), this); + items_grid_view_ = new AppsGridView(contents_view_, this); items_grid_view_->SetModel(model); contents_container_->AddChildView(items_grid_view_); view_model_->Add(items_grid_view_, kIndexChildItems); @@ -732,7 +730,7 @@ } void AppListFolderView::GiveBackFocusToSearchBox() { - app_list_main_view_->search_box_view()->search_box()->RequestFocus(); + contents_view_->GetSearchBoxView()->search_box()->RequestFocus(); } void AppListFolderView::SetItemName(AppListFolderItem* item,
diff --git a/ui/app_list/views/app_list_folder_view.h b/ui/app_list/views/app_list_folder_view.h index 939fab6e..7594acf 100644 --- a/ui/app_list/views/app_list_folder_view.h +++ b/ui/app_list/views/app_list_folder_view.h
@@ -27,7 +27,6 @@ class AppsGridView; class AppListFolderItem; class AppListItemView; -class AppListMainView; class AppListModel; class FolderHeaderView; class PageSwitcher; @@ -39,7 +38,7 @@ public: AppListFolderView(AppsContainerView* container_view, AppListModel* model, - AppListMainView* app_list_main_view); + ContentsView* contents_view); ~AppListFolderView() override; // An interface for the folder opening and closing animations. @@ -132,7 +131,7 @@ // Views below are not owned by views hierarchy. AppsContainerView* container_view_; - AppListMainView* app_list_main_view_; + ContentsView* contents_view_; // The view is used to draw a background with corner radius. views::View* background_view_; // Owned by views hierarchy.
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc index c3c7d7c..944cf27 100644 --- a/ui/app_list/views/app_list_main_view.cc +++ b/ui/app_list/views/app_list_main_view.cc
@@ -73,7 +73,7 @@ void AppListMainView::AddContentsViews() { DCHECK(search_box_view_); - contents_view_ = new ContentsView(this, app_list_view_); + contents_view_ = new ContentsView(app_list_view_); contents_view_->Init(model_); AddChildView(contents_view_); @@ -93,7 +93,7 @@ void AppListMainView::ResetForShow() { contents_view_->SetActiveState(ash::AppListState::kStateStart); - contents_view_->apps_container_view()->ResetForShowApps(); + contents_view_->GetAppsContainerView()->ResetForShowApps(); // We clear the search when hiding so when app list appears it is not showing // search results. search_box_view_->ClearSearch(); @@ -121,7 +121,7 @@ } PaginationModel* AppListMainView::GetAppsPaginationModel() { - return contents_view_->apps_container_view() + return contents_view_->GetAppsContainerView() ->apps_grid_view() ->pagination_model(); } @@ -153,7 +153,7 @@ } void AppListMainView::CancelDragInActiveFolder() { - contents_view_->apps_container_view() + contents_view_->GetAppsContainerView() ->app_list_folder_view() ->items_grid_view() ->EndDrag(true);
diff --git a/ui/app_list/views/app_list_main_view_unittest.cc b/ui/app_list/views/app_list_main_view_unittest.cc index 5c90a8a4..89cfc730 100644 --- a/ui/app_list/views/app_list_main_view_unittest.cc +++ b/ui/app_list/views/app_list_main_view_unittest.cc
@@ -176,11 +176,11 @@ ContentsView* GetContentsView() { return main_view_->contents_view(); } AppsGridView* RootGridView() { - return GetContentsView()->apps_container_view()->apps_grid_view(); + return GetContentsView()->GetAppsContainerView()->apps_grid_view(); } AppListFolderView* FolderView() { - return GetContentsView()->apps_container_view()->app_list_folder_view(); + return GetContentsView()->GetAppsContainerView()->app_list_folder_view(); } AppsGridView* FolderGridView() { return FolderView()->items_grid_view(); } @@ -376,7 +376,7 @@ // Ensure keyboard selection works on the root grid view after a reparent. // This is a regression test for https://crbug.com/466058. ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, ui::EF_NONE); - GetContentsView()->apps_container_view()->OnKeyPressed(key_event); + GetContentsView()->GetAppsContainerView()->OnKeyPressed(key_event); EXPECT_TRUE(RootGridView()->has_selected_view()); EXPECT_FALSE(FolderGridView()->has_selected_view());
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc index 9b76e9f..ad9d0a6 100644 --- a/ui/app_list/views/app_list_view.cc +++ b/ui/app_list/views/app_list_view.cc
@@ -568,13 +568,6 @@ } void AppListView::UpdateDrag(const gfx::Point& location) { - if (initial_drag_point_ == gfx::Point()) { - // When the app grid view redirects the event to the app list view, we - // detect this by seeing that StartDrag was not called. This sets up the - // drag. - StartDrag(location); - return; - } // Update the widget bounds based on the initial widget bounds and drag delta. gfx::Point location_in_screen_coordinates = location; ConvertPointToScreen(this, &location_in_screen_coordinates); @@ -803,7 +796,7 @@ } AppsContainerView* AppListView::GetAppsContainerView() { - return app_list_main_view_->contents_view()->apps_container_view(); + return app_list_main_view_->contents_view()->GetAppsContainerView(); } AppsGridView* AppListView::GetRootAppsGridView() {
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc index 2d85247a..2e3caf1 100644 --- a/ui/app_list/views/app_list_view_unittest.cc +++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -426,14 +426,14 @@ AppsGridView* apps_grid_view() { return main_view() ->contents_view() - ->apps_container_view() + ->GetAppsContainerView() ->apps_grid_view(); } AppListFolderView* app_list_folder_view() { return main_view() ->contents_view() - ->apps_container_view() + ->GetAppsContainerView() ->app_list_folder_view(); } @@ -599,7 +599,7 @@ SetAppListState(AppListViewState::FULLSCREEN_ALL_APPS); folder_item_view()->RequestFocus(); SimulateKeyPress(ui::VKEY_RETURN, false); - EXPECT_TRUE(contents_view()->apps_container_view()->IsInFolderView()); + EXPECT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); std::vector<views::View*> forward_view_list; forward_view_list.push_back(search_box_view()->search_box()); @@ -746,7 +746,7 @@ SetAppListState(AppListViewState::FULLSCREEN_ALL_APPS); folder_item_view()->RequestFocus(); SimulateKeyPress(ui::VKEY_RETURN, false); - EXPECT_TRUE(contents_view()->apps_container_view()->IsInFolderView()); + EXPECT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); std::vector<views::View*> forward_view_list; forward_view_list.push_back(search_box_view()->search_box()); @@ -784,7 +784,7 @@ SetAppListState(AppListViewState::FULLSCREEN_ALL_APPS); folder_item_view()->RequestFocus(); SimulateKeyPress(ui::VKEY_RETURN, false); - EXPECT_TRUE(contents_view()->apps_container_view()->IsInFolderView()); + EXPECT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); // Select the second page. app_list_folder_view()->items_grid_view()->pagination_model()->SelectPage( @@ -850,7 +850,7 @@ // Move focus to first suggestion app, then open the folder. folder_item_view()->RequestFocus(); SimulateKeyPress(ui::VKEY_RETURN, false); - EXPECT_TRUE(contents_view()->apps_container_view()->IsInFolderView()); + EXPECT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); EXPECT_EQ(search_box_view()->search_box(), focused_view()); // Move focus to the first app, then transition to PEEKING state. @@ -1516,19 +1516,19 @@ Show(); AppsGridViewTestApi test_api(view_->app_list_main_view() ->contents_view() - ->apps_container_view() + ->GetAppsContainerView() ->apps_grid_view()); test_api.PressItemAt(0); EXPECT_TRUE(view_->app_list_main_view() ->contents_view() - ->apps_container_view() + ->GetAppsContainerView() ->IsInFolderView()); view_->SetState(AppListViewState::PEEKING); EXPECT_FALSE(view_->app_list_main_view() ->contents_view() - ->apps_container_view() + ->GetAppsContainerView() ->IsInFolderView()); } @@ -1542,7 +1542,7 @@ view_->SetState(AppListViewState::FULLSCREEN_ALL_APPS); EXPECT_EQ(AppListViewState::FULLSCREEN_ALL_APPS, view_->app_list_state()); ContentsView* contents_view = view_->app_list_main_view()->contents_view(); - AppsContainerView* container_view = contents_view->apps_container_view(); + AppsContainerView* container_view = contents_view->GetAppsContainerView(); const gfx::Rect grid_view_bounds = container_view->apps_grid_view()->GetBoundsInScreen(); gfx::Point target_point = grid_view_bounds.origin();
diff --git a/ui/app_list/views/apps_container_view.cc b/ui/app_list/views/apps_container_view.cc index c23bfa7..4375f474 100644 --- a/ui/app_list/views/apps_container_view.cc +++ b/ui/app_list/views/apps_container_view.cc
@@ -28,19 +28,10 @@ namespace app_list { -// Initial search box top padding in shelf mode. -constexpr int kSearchBoxInitalTopPadding = 12; - -// Top padding of search box in peeking state. -constexpr int kSearchBoxPeekingTopPadding = 24; - -// Minimum top padding of search box in fullscreen state. -constexpr int kSearchBoxMinimumTopPadding = 24; - -AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view, - AppListModel* model) { - apps_grid_view_ = - new AppsGridView(app_list_main_view->contents_view(), nullptr); +AppsContainerView::AppsContainerView(ContentsView* contents_view, + AppListModel* model) + : contents_view_(contents_view) { + apps_grid_view_ = new AppsGridView(contents_view_, nullptr); apps_grid_view_->SetLayout(kPreferredCols, kPreferredRows); AddChildView(apps_grid_view_); @@ -49,8 +40,7 @@ true /* vertical */); AddChildView(page_switcher_); - app_list_folder_view_ = - new AppListFolderView(this, model, app_list_main_view); + app_list_folder_view_ = new AppListFolderView(this, model, contents_view_); // The folder view is initially hidden. app_list_folder_view_->SetVisible(false); folder_background_view_ = new FolderBackgroundView(app_list_folder_view_); @@ -80,7 +70,7 @@ // Disable all the items behind the folder so that they will not be reached // during focus traversal. - contents_view()->GetSearchBoxView()->search_box()->RequestFocus(); + contents_view_->GetSearchBoxView()->search_box()->RequestFocus(); apps_grid_view_->DisableFocusForShowingActiveFolder(true); } @@ -133,7 +123,7 @@ // Updates the opacity of page switcher buttons. The same rule as all apps in // AppsGridView. - AppListView* app_list_view = contents_view()->app_list_view(); + AppListView* app_list_view = contents_view_->app_list_view(); bool should_restore_opacity = !app_list_view->is_in_drag() && (app_list_view->app_list_state() != AppListViewState::CLOSED); @@ -201,11 +191,6 @@ return "AppsContainerView"; } -void AppsContainerView::OnWillBeShown() { - apps_grid_view()->ClearAnySelectedView(); - app_list_folder_view()->items_grid_view()->ClearAnySelectedView(); -} - void AppsContainerView::OnWillBeHidden() { if (show_state_ == SHOW_APPS || show_state_ == SHOW_ITEM_REPARENT) apps_grid_view_->EndDrag(true); @@ -213,96 +198,6 @@ app_list_folder_view_->CloseFolderPage(); } -gfx::Rect AppsContainerView::GetSearchBoxBounds() const { - return GetSearchBoxBoundsForState(contents_view()->GetActiveState()); -} - -gfx::Rect AppsContainerView::GetSearchBoxBoundsForState( - ash::AppListState state) const { - gfx::Rect search_box_bounds(contents_view()->GetDefaultSearchBoxBounds()); - bool is_in_drag = false; - if (contents_view()->app_list_view()) - is_in_drag = contents_view()->app_list_view()->is_in_drag(); - if (is_in_drag) { - search_box_bounds.set_y(GetSearchBoxTopPaddingDuringDragging()); - } else { - if (state == ash::AppListState::kStateStart) - search_box_bounds.set_y(kSearchBoxPeekingTopPadding); - else - search_box_bounds.set_y(GetSearchBoxFinalTopPadding()); - } - - return search_box_bounds; -} - -gfx::Rect AppsContainerView::GetPageBoundsForState( - ash::AppListState state) const { - gfx::Rect onscreen_bounds = GetDefaultContentsBounds(); - - // Both STATE_START and STATE_APPS are AppsContainerView page. - if (state == ash::AppListState::kStateApps || - state == ash::AppListState::kStateStart) { - int y = GetSearchBoxBoundsForState(state).bottom(); - if (state == ash::AppListState::kStateStart) - y -= (kSearchBoxBottomPadding - kSearchBoxPeekingBottomPadding); - onscreen_bounds.set_y(y); - return onscreen_bounds; - } - - return GetBelowContentsOffscreenBounds(onscreen_bounds.size()); -} - -gfx::Rect AppsContainerView::GetPageBoundsDuringDragging( - ash::AppListState state) const { - float app_list_y_position_in_screen = - contents_view()->app_list_view()->app_list_y_position_in_screen(); - float drag_amount = - std::max(0.f, contents_view()->app_list_view()->GetScreenBottom() - - kShelfSize - app_list_y_position_in_screen); - - float y = 0; - float peeking_final_y = - kSearchBoxPeekingTopPadding + search_box::kSearchBoxPreferredHeight + - kSearchBoxPeekingBottomPadding - kSearchBoxBottomPadding; - if (drag_amount <= (kPeekingAppListHeight - kShelfSize)) { - // App list is dragged from collapsed to peeking, which moved up at most - // |kPeekingAppListHeight - kShelfSize| (272px). The top padding of apps - // container view changes from |-kSearchBoxFullscreenBottomPadding| to - // |kSearchBoxPeekingTopPadding + kSearchBoxPreferredHeight + - // kSearchBoxPeekingBottomPadding - kSearchBoxFullscreenBottomPadding|. - y = std::ceil(((peeking_final_y + kSearchBoxBottomPadding) * drag_amount) / - (kPeekingAppListHeight - kShelfSize) - - kSearchBoxBottomPadding); - } else { - // App list is dragged from peeking to fullscreen, which moved up at most - // |peeking_to_fullscreen_height|. The top padding of apps container view - // changes from |peeking_final_y| to |final_y|. - float final_y = - GetSearchBoxFinalTopPadding() + search_box::kSearchBoxPreferredHeight; - float peeking_to_fullscreen_height = - contents_view()->GetDisplayHeight() - kPeekingAppListHeight; - y = std::ceil((final_y - peeking_final_y) * - (drag_amount - (kPeekingAppListHeight - kShelfSize)) / - peeking_to_fullscreen_height + - peeking_final_y); - y = std::max(std::min(final_y, y), peeking_final_y); - } - - gfx::Rect onscreen_bounds = GetPageBoundsForState(state); - // Both STATE_START and STATE_APPS are AppsContainerView page. - if (state == ash::AppListState::kStateApps || - state == ash::AppListState::kStateStart) - onscreen_bounds.set_y(y); - - return onscreen_bounds; -} - -views::View* AppsContainerView::GetSelectedView() const { - return IsInFolderView() - ? app_list_folder_view_->items_grid_view()->GetSelectedView() - : apps_grid_view_->GetSelectedView(); -} - views::View* AppsContainerView::GetFirstFocusableView() { if (IsInFolderView()) { // The pagination inside a folder is set horizontally, so focus should be @@ -315,11 +210,6 @@ this, GetWidget(), false /* reverse */, false /* dont_loop */); } -views::View* AppsContainerView::GetLastFocusableView() { - return GetFocusManager()->GetNextFocusableView( - this, GetWidget(), true /* reverse */, false /* dont_loop */); -} - void AppsContainerView::SetShowState(ShowState show_state, bool show_apps_with_animation) { if (show_state_ == show_state) @@ -353,50 +243,4 @@ } } -int AppsContainerView::GetSearchBoxFinalTopPadding() const { - gfx::Rect search_box_bounds(contents_view()->GetDefaultSearchBoxBounds()); - const int total_height = - GetDefaultContentsBounds().bottom() - search_box_bounds.y(); - - // Makes search box and content vertically centered in contents_view. - int y = std::max(search_box_bounds.y(), - (contents_view()->GetDisplayHeight() - total_height) / 2); - - // Top padding of the searchbox should not be smaller than - // |kSearchBoxMinimumTopPadding| - return std::max(y, kSearchBoxMinimumTopPadding); -} - -int AppsContainerView::GetSearchBoxTopPaddingDuringDragging() const { - float searchbox_final_y = GetSearchBoxFinalTopPadding(); - float peeking_to_fullscreen_height = - contents_view()->GetDisplayHeight() - kPeekingAppListHeight; - float drag_amount = std::max( - 0, contents_view()->app_list_view()->GetScreenBottom() - kShelfSize - - contents_view()->app_list_view()->app_list_y_position_in_screen()); - - if (drag_amount <= (kPeekingAppListHeight - kShelfSize)) { - // App list is dragged from collapsed to peeking, which moved up at most - // |kPeekingAppListHeight - kShelfSize| (272px). The top padding of search - // box changes from |kSearchBoxInitalTopPadding| to - // |kSearchBoxPeekingTopPadding|, - return std::ceil( - (kSearchBoxPeekingTopPadding - kSearchBoxInitalTopPadding) + - ((kSearchBoxPeekingTopPadding - kSearchBoxInitalTopPadding) * - drag_amount) / - (kPeekingAppListHeight - kShelfSize)); - } else { - // App list is dragged from peeking to fullscreen, which moved up at most - // |peeking_to_fullscreen_height|. The top padding of search box changes - // from |kSearchBoxPeekingTopPadding| to |searchbox_final_y|. - int y = (kSearchBoxPeekingTopPadding + - std::ceil((searchbox_final_y - kSearchBoxPeekingTopPadding) * - (drag_amount - (kPeekingAppListHeight - kShelfSize)) / - peeking_to_fullscreen_height)); - y = std::max(kSearchBoxPeekingTopPadding, - std::min<int>(searchbox_final_y, y)); - return y; - } -} - } // namespace app_list
diff --git a/ui/app_list/views/apps_container_view.h b/ui/app_list/views/apps_container_view.h index a9f5624..a101a511cb 100644 --- a/ui/app_list/views/apps_container_view.h +++ b/ui/app_list/views/apps_container_view.h
@@ -11,11 +11,7 @@ #include "ash/app_list/model/app_list_folder_item.h" #include "base/macros.h" -#include "ui/app_list/views/app_list_page.h" - -namespace gfx { -class Rect; -} +#include "ui/app_list/views/horizontal_page.h" namespace app_list { @@ -23,17 +19,17 @@ class ApplicationDragAndDropHost; class AppListFolderItem; class AppListFolderView; -class AppListMainView; class AppListModel; +class ContentsView; class FolderBackgroundView; class PageSwitcher; // AppsContainerView contains a root level AppsGridView to render the root level // app items, and a AppListFolderView to render the app items inside the // active folder. Only one if them is visible to user at any time. -class APP_LIST_EXPORT AppsContainerView : public AppListPage { +class APP_LIST_EXPORT AppsContainerView : public HorizontalPage { public: - AppsContainerView(AppListMainView* app_list_main_view, AppListModel* model); + AppsContainerView(ContentsView* contents_view, AppListModel* model); ~AppsContainerView() override; // Shows the active folder content specified by |folder_item|. @@ -78,16 +74,9 @@ bool OnKeyPressed(const ui::KeyEvent& event) override; const char* GetClassName() const override; - // AppListPage overrides: - void OnWillBeShown() override; + // HorizontalPage overrides: void OnWillBeHidden() override; - gfx::Rect GetSearchBoxBounds() const override; - gfx::Rect GetSearchBoxBoundsForState(ash::AppListState state) const override; - gfx::Rect GetPageBoundsForState(ash::AppListState state) const override; - gfx::Rect GetPageBoundsDuringDragging(ash::AppListState state) const override; - views::View* GetSelectedView() const override; views::View* GetFirstFocusableView() override; - views::View* GetLastFocusableView() override; AppsGridView* apps_grid_view() { return apps_grid_view_; } FolderBackgroundView* folder_background_view() { @@ -105,11 +94,7 @@ void SetShowState(ShowState show_state, bool show_apps_with_animation); - // Gets the final top padding of search box. - int GetSearchBoxFinalTopPadding() const; - - // Gets the top padding of search box during dragging. - int GetSearchBoxTopPaddingDuringDragging() const; + ContentsView* contents_view_; // Not owned. // The views below are owned by views hierarchy. AppsGridView* apps_grid_view_ = nullptr;
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc index 2f35065..8554dd23 100644 --- a/ui/app_list/views/apps_grid_view.cc +++ b/ui/app_list/views/apps_grid_view.cc
@@ -635,7 +635,7 @@ // An EndDrag can be received during a reparent via a model change. This // is always a cancel and needs to be forwarded to the folder. DCHECK(cancel); - contents_view_->app_list_main_view()->CancelDragInActiveFolder(); + contents_view_->GetAppListMainView()->CancelDragInActiveFolder(); return; } @@ -720,7 +720,7 @@ // folder's grid view. AppListItemView* view = new AppListItemView( this, original_drag_view->item(), - contents_view_->app_list_main_view()->view_delegate()); + contents_view_->GetAppListMainView()->view_delegate()); AddChildView(view); drag_view_ = view; drag_view_->SetPaintToLayer(); @@ -966,7 +966,7 @@ void AppsGridView::UpdateSuggestions() { if (!suggestions_container_) return; - suggestions_container_->SetResults(contents_view_->app_list_main_view() + suggestions_container_->SetResults(contents_view_->GetAppListMainView() ->view_delegate() ->GetSearchModel() ->results()); @@ -1029,7 +1029,7 @@ DCHECK_LE(index, item_list_->item_count()); AppListItemView* view = new AppListItemView( this, item_list_->item_at(index), - contents_view_->app_list_main_view()->view_delegate()); + contents_view_->GetAppListMainView()->view_delegate()); view->SetPaintToLayer(); view->layer()->SetFillsBoundsOpaquely(false); return view; @@ -1554,7 +1554,7 @@ if (arrow_up) { contents_view_->GetSearchBoxView()->search_box()->RequestFocus(); } else { - contents_view_->apps_container_view() + contents_view_->GetAppsContainerView() ->app_list_folder_view() ->folder_header_view() ->SetTextFocus(); @@ -2225,7 +2225,7 @@ else activated_folder_item_view_ = nullptr; } - contents_view_->app_list_main_view()->ActivateApp(pressed_item_view->item(), + contents_view_->GetAppListMainView()->ActivateApp(pressed_item_view->item(), event.flags()); }
diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc index 9339ed9d..ac3625a 100644 --- a/ui/app_list/views/apps_grid_view_unittest.cc +++ b/ui/app_list/views/apps_grid_view_unittest.cc
@@ -132,7 +132,7 @@ params.parent = parent; app_list_view_->Initialize(params); contents_view_ = app_list_view_->app_list_main_view()->contents_view(); - apps_grid_view_ = contents_view_->apps_container_view()->apps_grid_view(); + apps_grid_view_ = contents_view_->GetAppsContainerView()->apps_grid_view(); app_list_view_->GetWidget()->Show(); model_ = delegate_->GetTestModel(); @@ -181,7 +181,7 @@ } AppListFolderView* app_list_folder_view() const { - return contents_view_->apps_container_view()->app_list_folder_view(); + return contents_view_->GetAppsContainerView()->app_list_folder_view(); } // Points are in |apps_grid_view_|'s coordinates, and fixed for RTL. @@ -750,7 +750,7 @@ model_->PopulateApps(5); // Select the first suggested app and launch it. - contents_view_->app_list_main_view()->ActivateApp(GetItemViewAt(0)->item(), + contents_view_->GetAppListMainView()->ActivateApp(GetItemViewAt(0)->item(), 0); // Test that histograms recorded that a regular app launched. @@ -862,7 +862,7 @@ TEST_F(AppsGridViewTest, CloseFolderByClickingBackground) { AppsContainerView* apps_container_view = - contents_view_->apps_container_view(); + contents_view_->GetAppsContainerView(); const size_t kTotalItems = kMaxFolderItemsPerPage; model_->CreateAndPopulateFolderWithApps(kTotalItems);
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc index c532c165..5145cdd 100644 --- a/ui/app_list/views/contents_view.cc +++ b/ui/app_list/views/contents_view.cc
@@ -17,6 +17,7 @@ #include "ui/app_list/views/app_list_view.h" #include "ui/app_list/views/apps_container_view.h" #include "ui/app_list/views/apps_grid_view.h" +#include "ui/app_list/views/horizontal_page_container.h" #include "ui/app_list/views/search_box_view.h" #include "ui/app_list/views/search_result_answer_card_view.h" #include "ui/app_list/views/search_result_list_view.h" @@ -46,9 +47,8 @@ } // namespace -ContentsView::ContentsView(AppListMainView* app_list_main_view, - AppListView* app_list_view) - : app_list_main_view_(app_list_main_view), app_list_view_(app_list_view) { +ContentsView::ContentsView(AppListView* app_list_view) + : app_list_view_(app_list_view) { pagination_model_.SetTransitionDurations(kPageTransitionDurationInMs, kOverscrollPageTransitionDurationMs); pagination_model_.AddObserver(this); @@ -62,13 +62,13 @@ DCHECK(model); model_ = model; - AppListViewDelegate* view_delegate = app_list_main_view_->view_delegate(); + AppListViewDelegate* view_delegate = GetAppListMainView()->view_delegate(); - apps_container_view_ = new AppsContainerView(app_list_main_view_, model); + horizontal_page_container_ = new HorizontalPageContainer(this, model); - // Add |apps_container_view_| as STATE_START corresponding page for + // Add |horizontal_page_container_| as STATE_START corresponding page for // fullscreen app list. - AddLauncherPage(apps_container_view_, ash::AppListState::kStateStart); + AddLauncherPage(horizontal_page_container_, ash::AppListState::kStateStart); // Search results UI. search_results_page_view_ = new SearchResultPageView(); @@ -91,14 +91,14 @@ results, search_result_tile_item_list_view_); search_result_list_view_ = - new SearchResultListView(app_list_main_view_, view_delegate); + new SearchResultListView(GetAppListMainView(), view_delegate); search_results_page_view_->AddSearchResultContainerView( results, search_result_list_view_); AddLauncherPage(search_results_page_view_, ash::AppListState::kStateSearchResults); - AddLauncherPage(apps_container_view_, ash::AppListState::kStateApps); + AddLauncherPage(horizontal_page_container_, ash::AppListState::kStateApps); int initial_page_index = GetPageIndexForState(ash::AppListState::kStateStart); DCHECK_GE(initial_page_index, 0); @@ -118,19 +118,21 @@ } void ContentsView::CancelDrag() { - if (apps_container_view_->apps_grid_view()->has_dragged_view()) - apps_container_view_->apps_grid_view()->EndDrag(true); - if (apps_container_view_->app_list_folder_view() + if (GetAppsContainerView()->apps_grid_view()->has_dragged_view()) + GetAppsContainerView()->apps_grid_view()->EndDrag(true); + if (GetAppsContainerView() + ->app_list_folder_view() ->items_grid_view() ->has_dragged_view()) { - apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag( + GetAppsContainerView()->app_list_folder_view()->items_grid_view()->EndDrag( true); } } void ContentsView::SetDragAndDropHostOfCurrentAppList( ApplicationDragAndDropHost* drag_and_drop_host) { - apps_container_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); + GetAppsContainerView()->SetDragAndDropHostOfCurrentAppList( + drag_and_drop_host); } void ContentsView::SetActiveState(ash::AppListState state) { @@ -182,6 +184,10 @@ return pagination_model_.total_pages(); } +AppsContainerView* ContentsView::GetAppsContainerView() { + return horizontal_page_container_->apps_container_view(); +} + void ContentsView::SetActiveStateInternal(int page_index, bool show_search_results, bool animate) { @@ -211,7 +217,7 @@ app_list_pages_[GetActivePageIndex()]->OnWillBeShown(); - app_list_main_view_->model()->SetState(state); + GetAppListMainView()->model()->SetState(state); } void ContentsView::ShowSearchResults(bool show) { @@ -284,11 +290,11 @@ } PaginationModel* ContentsView::GetAppsPaginationModel() { - return apps_container_view_->apps_grid_view()->pagination_model(); + return GetAppsContainerView()->apps_grid_view()->pagination_model(); } void ContentsView::ShowFolderContent(AppListFolderItem* item) { - apps_container_view_->ShowActiveFolder(item); + GetAppsContainerView()->ShowActiveFolder(item); } AppListPage* ContentsView::GetPageView(int index) const { @@ -297,7 +303,11 @@ } SearchBoxView* ContentsView::GetSearchBoxView() const { - return app_list_main_view_->search_box_view(); + return GetAppListMainView()->search_box_view(); +} + +AppListMainView* ContentsView::GetAppListMainView() const { + return app_list_view_->app_list_main_view(); } int ContentsView::AddLauncherPage(AppListPage* view) { @@ -359,8 +369,8 @@ // Close the app list when Back() is called from the start page. return false; case ash::AppListState::kStateApps: - if (apps_container_view_->IsInFolderView()) { - apps_container_view_->app_list_folder_view()->CloseFolderPage(); + if (GetAppsContainerView()->IsInFolderView()) { + GetAppsContainerView()->app_list_folder_view()->CloseFolderPage(); } else { app_list_view_->Dismiss(); } @@ -379,7 +389,7 @@ } gfx::Size ContentsView::GetDefaultContentsSize() const { - return apps_container_view_->GetPreferredSize(); + return horizontal_page_container_->GetPreferredSize(); } gfx::Size ContentsView::CalculatePreferredSize() const {
diff --git a/ui/app_list/views/contents_view.h b/ui/app_list/views/contents_view.h index dfa8082..a2d1d72d2 100644 --- a/ui/app_list/views/contents_view.h +++ b/ui/app_list/views/contents_view.h
@@ -33,6 +33,7 @@ class AppListMainView; class AppsContainerView; class AppsGridView; +class HorizontalPageContainer; class PaginationModel; class SearchBoxView; class SearchResultAnswerCardView; @@ -48,7 +49,7 @@ class APP_LIST_EXPORT ContentsView : public views::View, public PaginationModelObserver { public: - ContentsView(AppListMainView* app_list_main_view, AppListView* app_list_view); + explicit ContentsView(AppListView* app_list_view); ~ContentsView() override; // Initialize the pages of the launcher. Should be called after @@ -94,9 +95,8 @@ int NumLauncherPages() const; - AppsContainerView* apps_container_view() const { - return apps_container_view_; - } + AppsContainerView* GetAppsContainerView(); + SearchResultPageView* search_results_page_view() const { return search_results_page_view_; } @@ -114,7 +114,7 @@ SearchBoxView* GetSearchBoxView() const; - AppListMainView* app_list_main_view() const { return app_list_main_view_; } + AppListMainView* GetAppListMainView() const; AppListView* app_list_view() const { return app_list_view_; } @@ -203,7 +203,7 @@ AppListModel* model_ = nullptr; // Sub-views of the ContentsView. All owned by the views hierarchy. - AppsContainerView* apps_container_view_ = nullptr; + HorizontalPageContainer* horizontal_page_container_ = nullptr; SearchResultPageView* search_results_page_view_ = nullptr; SearchResultAnswerCardView* search_result_answer_card_view_ = nullptr; SearchResultTileItemListView* search_result_tile_item_list_view_ = nullptr; @@ -212,9 +212,6 @@ // The child page views. Owned by the views hierarchy. std::vector<AppListPage*> app_list_pages_; - // Parent view. Owned by the views hierarchy. - AppListMainView* app_list_main_view_; - // Owned by the views hierarchy. AppListView* const app_list_view_;
diff --git a/ui/app_list/views/horizontal_page.cc b/ui/app_list/views/horizontal_page.cc new file mode 100644 index 0000000..16de048 --- /dev/null +++ b/ui/app_list/views/horizontal_page.cc
@@ -0,0 +1,27 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/app_list/views/horizontal_page.h" + +#include "ui/views/focus/focus_manager.h" + +namespace app_list { + +void HorizontalPage::OnWillBeHidden() {} + +views::View* HorizontalPage::GetFirstFocusableView() { + return GetFocusManager()->GetNextFocusableView( + this, GetWidget(), false /* reverse */, false /* dont_loop */); +} + +views::View* HorizontalPage::GetLastFocusableView() { + return GetFocusManager()->GetNextFocusableView( + this, GetWidget(), true /* reverse */, false /* dont_loop */); +} + +HorizontalPage::HorizontalPage() = default; + +HorizontalPage::~HorizontalPage() = default; + +} // namespace app_list
diff --git a/ui/app_list/views/horizontal_page.h b/ui/app_list/views/horizontal_page.h new file mode 100644 index 0000000..c107179 --- /dev/null +++ b/ui/app_list/views/horizontal_page.h
@@ -0,0 +1,37 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_APP_LIST_VIEWS_HORIZONTAL_PAGE_H_ +#define UI_APP_LIST_VIEWS_HORIZONTAL_PAGE_H_ + +#include "ash/app_list/model/app_list_model.h" +#include "base/macros.h" +#include "ui/app_list/app_list_export.h" +#include "ui/views/view.h" + +namespace app_list { + +// HorizontalPage is laid out horizontally in HorizontalPageContainer and its +// visibility is controlled by horizontal gesture scrolling. +class APP_LIST_EXPORT HorizontalPage : public views::View { + public: + // Triggered when the page is about to be hidden. + virtual void OnWillBeHidden(); + + // Gets the first and last focusable view in this page, this will be used in + // focus traversal. + virtual views::View* GetFirstFocusableView(); + virtual views::View* GetLastFocusableView(); + + protected: + HorizontalPage(); + ~HorizontalPage() override; + + private: + DISALLOW_COPY_AND_ASSIGN(HorizontalPage); +}; + +} // namespace app_list + +#endif // UI_APP_LIST_VIEWS_HORIZONTAL_PAGE_H_
diff --git a/ui/app_list/views/horizontal_page_container.cc b/ui/app_list/views/horizontal_page_container.cc new file mode 100644 index 0000000..959ea19 --- /dev/null +++ b/ui/app_list/views/horizontal_page_container.cc
@@ -0,0 +1,272 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/app_list/views/horizontal_page_container.h" + +#include "base/strings/utf_string_conversions.h" +#include "ui/app_list/app_list_constants.h" +#include "ui/app_list/pagination_controller.h" +#include "ui/app_list/views/app_list_view.h" +#include "ui/app_list/views/apps_container_view.h" +#include "ui/app_list/views/contents_view.h" +#include "ui/chromeos/search_box/search_box_constants.h" +#include "ui/views/controls/label.h" + +namespace app_list { + +// Initial search box top padding in shelf mode. +constexpr int kSearchBoxInitalTopPadding = 12; + +// Top padding of search box in peeking state. +constexpr int kSearchBoxPeekingTopPadding = 24; + +// Minimum top padding of search box in fullscreen state. +constexpr int kSearchBoxMinimumTopPadding = 24; + +HorizontalPageContainer::HorizontalPageContainer(ContentsView* contents_view, + AppListModel* model) + : contents_view_(contents_view) { + pagination_model_.SetTransitionDurations(kPageTransitionDurationInMs, + kOverscrollPageTransitionDurationMs); + pagination_model_.AddObserver(this); + pagination_controller_.reset(new PaginationController( + &pagination_model_, PaginationController::SCROLL_AXIS_HORIZONTAL)); + + apps_container_view_ = new AppsContainerView(contents_view_, model); + + // Add horizontal pages. + AddHorizontalPage(apps_container_view_); + pagination_model_.SetTotalPages(horizontal_pages_.size()); + + // By default select apps container page. + pagination_model_.SelectPage(GetIndexForPage(apps_container_view_), false); +} + +HorizontalPageContainer::~HorizontalPageContainer() { + pagination_model_.RemoveObserver(this); +} + +gfx::Size HorizontalPageContainer::CalculatePreferredSize() const { + return apps_container_view_->GetPreferredSize(); +} + +void HorizontalPageContainer::Layout() { + gfx::Rect content_bounds(GetContentsBounds()); + for (size_t i = 0; i < horizontal_pages_.size(); ++i) { + gfx::Rect page_bounds(content_bounds); + page_bounds.ClampToCenteredSize(horizontal_pages_[i]->GetPreferredSize()); + page_bounds.Offset(GetOffsetForPageIndex(i)); + horizontal_pages_[i]->SetBoundsRect(page_bounds); + } +} + +void HorizontalPageContainer::OnGestureEvent(ui::GestureEvent* event) { + if (pagination_controller_->OnGestureEvent(*event, GetContentsBounds())) + event->SetHandled(); +} + +void HorizontalPageContainer::OnWillBeHidden() { + GetSelectedPage()->OnWillBeHidden(); +} + +gfx::Rect HorizontalPageContainer::GetSearchBoxBounds() const { + return GetSearchBoxBoundsForState(contents_view_->GetActiveState()); +} + +gfx::Rect HorizontalPageContainer::GetSearchBoxBoundsForState( + ash::AppListState state) const { + gfx::Rect search_box_bounds(contents_view_->GetDefaultSearchBoxBounds()); + bool is_in_drag = false; + if (contents_view_->app_list_view()) + is_in_drag = contents_view_->app_list_view()->is_in_drag(); + if (is_in_drag) { + search_box_bounds.set_y(GetSearchBoxTopPaddingDuringDragging()); + } else { + if (state == ash::AppListState::kStateStart) + search_box_bounds.set_y(kSearchBoxPeekingTopPadding); + else + search_box_bounds.set_y(GetSearchBoxFinalTopPadding()); + } + + return search_box_bounds; +} + +gfx::Rect HorizontalPageContainer::GetPageBoundsForState( + ash::AppListState state) const { + gfx::Rect onscreen_bounds = GetDefaultContentsBounds(); + + // Both STATE_START and STATE_APPS are AppsContainerView page. + if (state == ash::AppListState::kStateApps || + state == ash::AppListState::kStateStart) { + int y = GetSearchBoxBoundsForState(state).bottom(); + if (state == ash::AppListState::kStateStart) + y -= (kSearchBoxBottomPadding - kSearchBoxPeekingBottomPadding); + onscreen_bounds.set_y(y); + return onscreen_bounds; + } + + return GetBelowContentsOffscreenBounds(onscreen_bounds.size()); +} + +gfx::Rect HorizontalPageContainer::GetPageBoundsDuringDragging( + ash::AppListState state) const { + float app_list_y_position_in_screen = + contents_view_->app_list_view()->app_list_y_position_in_screen(); + float drag_amount = + std::max(0.f, contents_view_->app_list_view()->GetScreenBottom() - + kShelfSize - app_list_y_position_in_screen); + + float y = 0; + float peeking_final_y = + kSearchBoxPeekingTopPadding + search_box::kSearchBoxPreferredHeight + + kSearchBoxPeekingBottomPadding - kSearchBoxBottomPadding; + if (drag_amount <= (kPeekingAppListHeight - kShelfSize)) { + // App list is dragged from collapsed to peeking, which moved up at most + // |kPeekingAppListHeight - kShelfSize| (272px). The top padding of apps + // container view changes from |-kSearchBoxFullscreenBottomPadding| to + // |kSearchBoxPeekingTopPadding + kSearchBoxPreferredHeight + + // kSearchBoxPeekingBottomPadding - kSearchBoxFullscreenBottomPadding|. + y = std::ceil(((peeking_final_y + kSearchBoxBottomPadding) * drag_amount) / + (kPeekingAppListHeight - kShelfSize) - + kSearchBoxBottomPadding); + } else { + // App list is dragged from peeking to fullscreen, which moved up at most + // |peeking_to_fullscreen_height|. The top padding of apps container view + // changes from |peeking_final_y| to |final_y|. + float final_y = + GetSearchBoxFinalTopPadding() + search_box::kSearchBoxPreferredHeight; + float peeking_to_fullscreen_height = + contents_view_->GetDisplayHeight() - kPeekingAppListHeight; + y = std::ceil((final_y - peeking_final_y) * + (drag_amount - (kPeekingAppListHeight - kShelfSize)) / + peeking_to_fullscreen_height + + peeking_final_y); + y = std::max(std::min(final_y, y), peeking_final_y); + } + + gfx::Rect onscreen_bounds = GetPageBoundsForState(state); + // Both STATE_START and STATE_APPS are AppsContainerView page. + if (state == ash::AppListState::kStateApps || + state == ash::AppListState::kStateStart) + onscreen_bounds.set_y(y); + + return onscreen_bounds; +} + +views::View* HorizontalPageContainer::GetFirstFocusableView() { + return GetSelectedPage()->GetFirstFocusableView(); +} + +views::View* HorizontalPageContainer::GetLastFocusableView() { + return GetSelectedPage()->GetLastFocusableView(); +} + +void HorizontalPageContainer::TotalPagesChanged() {} + +void HorizontalPageContainer::SelectedPageChanged(int old_selected, + int new_selected) { + Layout(); +} + +void HorizontalPageContainer::TransitionStarted() { + Layout(); +} + +void HorizontalPageContainer::TransitionChanged() { + Layout(); +} + +void HorizontalPageContainer::TransitionEnded() { + Layout(); +} + +int HorizontalPageContainer::AddHorizontalPage(HorizontalPage* view) { + AddChildView(view); + horizontal_pages_.emplace_back(view); + return horizontal_pages_.size() - 1; +} + +int HorizontalPageContainer::GetIndexForPage(HorizontalPage* view) const { + for (size_t i = 0; i < horizontal_pages_.size(); ++i) { + if (horizontal_pages_[i] == view) + return i; + } + return -1; +} + +HorizontalPage* HorizontalPageContainer::GetSelectedPage() { + const int current_page = pagination_model_.selected_page(); + DCHECK(pagination_model_.is_valid_page(current_page)); + return horizontal_pages_[current_page]; +} + +gfx::Vector2d HorizontalPageContainer::GetOffsetForPageIndex(int index) const { + const int current_page = pagination_model_.selected_page(); + DCHECK(pagination_model_.is_valid_page(current_page)); + const PaginationModel::Transition& transition = + pagination_model_.transition(); + const bool is_valid = pagination_model_.is_valid_page(transition.target_page); + const int dir = transition.target_page > current_page ? -1 : 1; + int x_offset = 0; + // TODO(https://crbug.com/820510): figure out the right pagination style. + if (index < current_page) + x_offset = -width(); + else if (index > current_page) + x_offset = width(); + + if (is_valid) { + if (index == current_page || index == transition.target_page) { + x_offset += transition.progress * width() * dir; + } + } + return gfx::Vector2d(x_offset, 0); +} + +int HorizontalPageContainer::GetSearchBoxFinalTopPadding() const { + gfx::Rect search_box_bounds(contents_view_->GetDefaultSearchBoxBounds()); + const int total_height = + GetDefaultContentsBounds().bottom() - search_box_bounds.y(); + + // Makes search box and content vertically centered in contents_view. + int y = std::max(search_box_bounds.y(), + (contents_view_->GetDisplayHeight() - total_height) / 2); + + // Top padding of the searchbox should not be smaller than + // |kSearchBoxMinimumTopPadding| + return std::max(y, kSearchBoxMinimumTopPadding); +} + +int HorizontalPageContainer::GetSearchBoxTopPaddingDuringDragging() const { + float searchbox_final_y = GetSearchBoxFinalTopPadding(); + float peeking_to_fullscreen_height = + contents_view_->GetDisplayHeight() - kPeekingAppListHeight; + float drag_amount = std::max( + 0, contents_view_->app_list_view()->GetScreenBottom() - kShelfSize - + contents_view_->app_list_view()->app_list_y_position_in_screen()); + + if (drag_amount <= (kPeekingAppListHeight - kShelfSize)) { + // App list is dragged from collapsed to peeking, which moved up at most + // |kPeekingAppListHeight - kShelfSize| (272px). The top padding of search + // box changes from |kSearchBoxInitalTopPadding| to + // |kSearchBoxPeekingTopPadding|, + return std::ceil( + (kSearchBoxPeekingTopPadding - kSearchBoxInitalTopPadding) + + ((kSearchBoxPeekingTopPadding - kSearchBoxInitalTopPadding) * + drag_amount) / + (kPeekingAppListHeight - kShelfSize)); + } else { + // App list is dragged from peeking to fullscreen, which moved up at most + // |peeking_to_fullscreen_height|. The top padding of search box changes + // from |kSearchBoxPeekingTopPadding| to |searchbox_final_y|. + int y = (kSearchBoxPeekingTopPadding + + std::ceil((searchbox_final_y - kSearchBoxPeekingTopPadding) * + (drag_amount - (kPeekingAppListHeight - kShelfSize)) / + peeking_to_fullscreen_height)); + y = std::max(kSearchBoxPeekingTopPadding, + std::min<int>(searchbox_final_y, y)); + return y; + } +} + +} // namespace app_list
diff --git a/ui/app_list/views/horizontal_page_container.h b/ui/app_list/views/horizontal_page_container.h new file mode 100644 index 0000000..3d428f6 --- /dev/null +++ b/ui/app_list/views/horizontal_page_container.h
@@ -0,0 +1,90 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_APP_LIST_VIEWS_HORIZONTAL_PAGE_CONTAINER_H_ +#define UI_APP_LIST_VIEWS_HORIZONTAL_PAGE_CONTAINER_H_ + +#include "base/macros.h" +#include "ui/app_list/app_list_export.h" +#include "ui/app_list/pagination_model.h" +#include "ui/app_list/pagination_model_observer.h" +#include "ui/app_list/views/app_list_page.h" + +namespace app_list { + +class AppsContainerView; +class PaginationController; +class HorizontalPage; + +// HorizontalPageContainer contains a list of HorizontalPage that are +// horizontally laid out. These pages can be switched with gesture scrolling. +class APP_LIST_EXPORT HorizontalPageContainer : public AppListPage, + public PaginationModelObserver { + public: + HorizontalPageContainer(ContentsView* contents_view, AppListModel* model); + ~HorizontalPageContainer() override; + + // views::View: + gfx::Size CalculatePreferredSize() const override; + void Layout() override; + void OnGestureEvent(ui::GestureEvent* event) override; + + // AppListPage overrides: + void OnWillBeHidden() override; + gfx::Rect GetSearchBoxBounds() const override; + gfx::Rect GetSearchBoxBoundsForState(ash::AppListState state) const override; + gfx::Rect GetPageBoundsForState(ash::AppListState state) const override; + gfx::Rect GetPageBoundsDuringDragging(ash::AppListState state) const override; + views::View* GetFirstFocusableView() override; + views::View* GetLastFocusableView() override; + + AppsContainerView* apps_container_view() { return apps_container_view_; } + + private: + // PaginationModelObserver: + void TotalPagesChanged() override; + void SelectedPageChanged(int old_selected, int new_selected) override; + void TransitionStarted() override; + void TransitionChanged() override; + void TransitionEnded() override; + + // Adds a horizontal page to this view. + int AddHorizontalPage(HorizontalPage* view); + + // Gets the index of a horizontal page in |horizontal_pages_|. Returns -1 if + // there is no such view. + int GetIndexForPage(HorizontalPage* view) const; + + // Gets the currently selected horizontal page. + HorizontalPage* GetSelectedPage(); + + // Gets the offset for the horizontal page with specified index. + gfx::Vector2d GetOffsetForPageIndex(int index) const; + + // Gets the final top padding of search box. + int GetSearchBoxFinalTopPadding() const; + + // Gets the top padding of search box during dragging. + int GetSearchBoxTopPaddingDuringDragging() const; + + // Manages the pagination for the horizontal pages. + PaginationModel pagination_model_; + + // Must appear after |pagination_model_|. + std::unique_ptr<PaginationController> pagination_controller_; + + ContentsView* contents_view_; // Not owned + + // Owned by view hierarchy: + AppsContainerView* apps_container_view_ = nullptr; + + // The child page views. Owned by the views hierarchy. + std::vector<HorizontalPage*> horizontal_pages_; + + DISALLOW_COPY_AND_ASSIGN(HorizontalPageContainer); +}; + +} // namespace app_list + +#endif // UI_APP_LIST_VIEWS_HORIZONTAL_PAGE_CONTAINER_H_
diff --git a/ui/app_list/views/suggestions_container_view.cc b/ui/app_list/views/suggestions_container_view.cc index 2259379..f41e92db 100644 --- a/ui/app_list/views/suggestions_container_view.cc +++ b/ui/app_list/views/suggestions_container_view.cc
@@ -24,7 +24,7 @@ layer()->SetFillsBoundsOpaquely(false); DCHECK(contents_view); - view_delegate_ = contents_view_->app_list_main_view()->view_delegate(); + view_delegate_ = contents_view_->GetAppListMainView()->view_delegate(); SetBackground(views::CreateSolidBackground(kLabelBackgroundColor)); CreateAppsGrid(kNumStartPageTiles);
diff --git a/ui/events/ozone/chromeos/cursor_controller.cc b/ui/events/ozone/chromeos/cursor_controller.cc index 7b84c6e..91273c6 100644 --- a/ui/events/ozone/chromeos/cursor_controller.cc +++ b/ui/events/ozone/chromeos/cursor_controller.cc
@@ -44,6 +44,16 @@ return base::Singleton<CursorController>::get(); } +void CursorController::AddCursorObserver(CursorObserver* observer) { + base::AutoLock lock(cursor_observers_lock_); + cursor_observers_.AddObserver(observer); +} + +void CursorController::RemoveCursorObserver(CursorObserver* observer) { + base::AutoLock lock(cursor_observers_lock_); + cursor_observers_.RemoveObserver(observer); +} + void CursorController::SetCursorConfigForWindow( gfx::AcceleratedWidget widget, display::Display::Rotation rotation, @@ -66,6 +76,12 @@ TransformCursorMove(it->second.rotation, it->second.scale, delta); } +void CursorController::SetCursorLocation(const gfx::PointF& location) { + base::AutoLock lock(cursor_observers_lock_); + for (auto& observer : cursor_observers_) + observer.OnCursorLocationChanged(location); +} + CursorController::CursorController() { }
diff --git a/ui/events/ozone/chromeos/cursor_controller.h b/ui/events/ozone/chromeos/cursor_controller.h index 554ca6f..073f4d573 100644 --- a/ui/events/ozone/chromeos/cursor_controller.h +++ b/ui/events/ozone/chromeos/cursor_controller.h
@@ -10,9 +10,11 @@ #include "base/event_types.h" #include "base/macros.h" #include "base/memory/singleton.h" +#include "base/observer_list.h" #include "base/synchronization/lock.h" #include "ui/display/display.h" #include "ui/events/ozone/events_ozone_export.h" +#include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/vector2d_f.h" #include "ui/gfx/native_widget_types.h" @@ -36,8 +38,20 @@ // TODO(spang): Don't worry, we have a plan to remove this. class EVENTS_OZONE_EXPORT CursorController { public: + class CursorObserver { + public: + // Called when cursor location changed. + virtual void OnCursorLocationChanged(const gfx::PointF& location) = 0; + + protected: + virtual ~CursorObserver() {} + }; + static CursorController* GetInstance(); + void AddCursorObserver(CursorObserver* observer); + void RemoveCursorObserver(CursorObserver* observer); + // Changes the rotation & scale applied for a window. void SetCursorConfigForWindow(gfx::AcceleratedWidget widget, display::Display::Rotation rotation, @@ -59,6 +73,9 @@ void ApplyCursorConfigForWindow(gfx::AcceleratedWidget widget, gfx::Vector2dF* delta) const; + // Notifies controller of new cursor location. + void SetCursorLocation(const gfx::PointF& location); + private: CursorController(); ~CursorController(); @@ -75,6 +92,9 @@ WindowToCursorConfigurationMap window_to_cursor_configuration_map_; mutable base::Lock window_to_cursor_configuration_map_lock_; + base::ObserverList<CursorObserver> cursor_observers_; + mutable base::Lock cursor_observers_lock_; + DISALLOW_COPY_AND_ASSIGN(CursorController); };
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc index f7597bb4..d4f5af78 100644 --- a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc +++ b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
@@ -211,14 +211,6 @@ hwstate.buttons_down |= GESTURES_BUTTON_FORWARD; } - // Check if this event has an MSC_TIMESTAMP field - if (EvdevBitIsSet(evdev->info.msc_bitmask, MSC_TIMESTAMP)) { - hwstate.msc_timestamp = static_cast<stime_t>(Event_Get_Timestamp(evdev)) / - base::Time::kMicrosecondsPerSecond; - } else { - hwstate.msc_timestamp = 0.0; - } - GestureInterpreterPushHardwareState(interpreter_, &hwstate); }
diff --git a/ui/events/platform/x11/BUILD.gn b/ui/events/platform/x11/BUILD.gn index d4c7462..31a20f0 100644 --- a/ui/events/platform/x11/BUILD.gn +++ b/ui/events/platform/x11/BUILD.gn
@@ -38,6 +38,10 @@ "//base", ] + if (is_chromeos) { + deps += [ "//ui/events/ozone:events_ozone" ] + } + if (use_glib) { sources += [ "x11_event_source_glib.cc",
diff --git a/ui/events/platform/x11/x11_event_source_libevent.cc b/ui/events/platform/x11/x11_event_source_libevent.cc index e583157..2183b35 100644 --- a/ui/events/platform/x11/x11_event_source_libevent.cc +++ b/ui/events/platform/x11/x11_event_source_libevent.cc
@@ -15,6 +15,10 @@ #include "ui/events/x/events_x_utils.h" #include "ui/gfx/x/x11.h" +#if defined(OS_CHROMEOS) +#include "ui/events/ozone/chromeos/cursor_controller.h" +#endif + namespace ui { namespace { @@ -177,6 +181,12 @@ void X11EventSourceLibevent::ProcessXEvent(XEvent* xevent) { std::unique_ptr<ui::Event> translated_event = TranslateXEventToEvent(*xevent); if (translated_event) { +#if defined(OS_CHROMEOS) + if (translated_event->IsLocatedEvent()) { + ui::CursorController::GetInstance()->SetCursorLocation( + translated_event->AsLocatedEvent()->location_f()); + } +#endif DispatchPlatformEvent(translated_event.get(), xevent); } else { // Only if we can't translate XEvent into ui::Event, try to dispatch XEvent
diff --git a/ui/ozone/platform/drm/host/drm_cursor.cc b/ui/ozone/platform/drm/host/drm_cursor.cc index 0042294..8ffc06b4 100644 --- a/ui/ozone/platform/drm/host/drm_cursor.cc +++ b/ui/ozone/platform/drm/host/drm_cursor.cc
@@ -226,6 +226,9 @@ gfx::PointF(confined_bounds_.right() - 1, confined_bounds_.bottom() - 1)); location_ = clamped_location; +#if defined(OS_CHROMEOS) + ui::CursorController::GetInstance()->SetCursorLocation(location_); +#endif } void DrmCursor::SendCursorShowLocked() {
diff --git a/ui/views/accessibility/native_view_accessibility_base.cc b/ui/views/accessibility/native_view_accessibility_base.cc index 62455b9a..02e2a37 100644 --- a/ui/views/accessibility/native_view_accessibility_base.cc +++ b/ui/views/accessibility/native_view_accessibility_base.cc
@@ -72,6 +72,31 @@ return ui::AXPlatformNode::FromNativeViewAccessible(native_view_accessible); } +ui::AXPlatformNode* PlatformNodeFromNodeID(int32_t id) { + // Note: For Views, node IDs and unique IDs are the same - but that isn't + // necessarily true for all AXPlatformNodes. + auto it = g_unique_id_to_ax_platform_node.Get().find(id); + + if (it == g_unique_id_to_ax_platform_node.Get().end()) + return nullptr; + + return it->second; +} + +void FireEvent(QueuedEvent event) { + ui::AXPlatformNode* node = PlatformNodeFromNodeID(event.node_id); + if (node) + node->NotifyAccessibilityEvent(event.type); +} + +void FlushQueue() { + DCHECK(g_is_queueing_events); + for (QueuedEvent event : g_event_queue.Get()) + FireEvent(event); + g_is_queueing_events = false; + g_event_queue.Get().clear(); +} + } // namespace // static @@ -101,31 +126,6 @@ return ax_node_->GetNativeViewAccessible(); } -ui::AXPlatformNode* PlatformNodeFromNodeID(int32_t id) { - // Note: For Views, node IDs and unique IDs are the same - but that isn't - // necessarily true for all AXPlatformNodes. - auto it = g_unique_id_to_ax_platform_node.Get().find(id); - - if (it == g_unique_id_to_ax_platform_node.Get().end()) - return nullptr; - - return it->second; -} - -void FireEvent(QueuedEvent event) { - ui::AXPlatformNode* node = PlatformNodeFromNodeID(event.node_id); - if (node) - node->NotifyAccessibilityEvent(event.type); -} - -void FlushQueue() { - DCHECK(g_is_queueing_events); - for (QueuedEvent event : g_event_queue.Get()) - FireEvent(event); - g_is_queueing_events = false; - g_event_queue.Get().clear(); -} - void NativeViewAccessibilityBase::NotifyAccessibilityEvent( ax::mojom::Event event_type) { if (g_is_queueing_events) { @@ -353,10 +353,6 @@ return ViewAccessibility::GetUniqueId(); } -gfx::RectF NativeViewAccessibilityBase::GetBoundsInScreen() const { - return gfx::RectF(view()->GetBoundsInScreen()); -} - void NativeViewAccessibilityBase::PopulateChildWidgetVector( std::vector<Widget*>* result_child_widgets) { // Only attach child widgets to the root view.
diff --git a/ui/views/accessibility/native_view_accessibility_base.h b/ui/views/accessibility/native_view_accessibility_base.h index 637708b2..cb3d15a 100644 --- a/ui/views/accessibility/native_view_accessibility_base.h +++ b/ui/views/accessibility/native_view_accessibility_base.h
@@ -67,9 +67,6 @@ protected: explicit NativeViewAccessibilityBase(View* view); - protected: - virtual gfx::RectF GetBoundsInScreen() const; - private: void PopulateChildWidgetVector(std::vector<Widget*>* result_child_widgets);
diff --git a/ui/views/accessibility/native_view_accessibility_win.cc b/ui/views/accessibility/native_view_accessibility_win.cc index 86cb139a..def94a1 100644 --- a/ui/views/accessibility/native_view_accessibility_win.cc +++ b/ui/views/accessibility/native_view_accessibility_win.cc
@@ -23,6 +23,7 @@ #include "ui/base/layout.h" #include "ui/base/win/accessibility_misc_utils.h" #include "ui/base/win/atl_module.h" +#include "ui/display/win/screen_win.h" #include "ui/views/controls/button/button.h" #include "ui/views/widget/widget.h" #include "ui/views/win/hwnd_util.h" @@ -100,12 +101,14 @@ return HWNDForView(view()); } -gfx::RectF NativeViewAccessibilityWin::GetBoundsInScreen() const { - gfx::RectF bounds = gfx::RectF(view()->GetBoundsInScreen()); - gfx::NativeView native_view = view()->GetWidget()->GetNativeView(); - float device_scale = ui::GetScaleFactorForNativeView(native_view); - bounds.Scale(device_scale); - return bounds; +gfx::Rect NativeViewAccessibilityWin::GetClippedScreenBoundsRect() const { + // We could optionally add clipping here if ever needed. + return GetUnclippedScreenBoundsRect(); +} + +gfx::Rect NativeViewAccessibilityWin::GetUnclippedScreenBoundsRect() const { + gfx::Rect bounds = view()->GetBoundsInScreen(); + return display::win::ScreenWin::DIPToScreenRect(HWNDForView(view()), bounds); } } // namespace views
diff --git a/ui/views/accessibility/native_view_accessibility_win.h b/ui/views/accessibility/native_view_accessibility_win.h index dde0c906..8f64f688 100644 --- a/ui/views/accessibility/native_view_accessibility_win.h +++ b/ui/views/accessibility/native_view_accessibility_win.h
@@ -19,7 +19,8 @@ // NativeViewAccessibilityBase: gfx::NativeViewAccessible GetParent() override; gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override; - gfx::RectF GetBoundsInScreen() const override; + gfx::Rect GetClippedScreenBoundsRect() const override; + gfx::Rect GetUnclippedScreenBoundsRect() const override; DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityWin); };
diff --git a/ui/views/animation/ink_drop_host_view.cc b/ui/views/animation/ink_drop_host_view.cc index 5a769f05..d27e0ed1 100644 --- a/ui/views/animation/ink_drop_host_view.cc +++ b/ui/views/animation/ink_drop_host_view.cc
@@ -168,6 +168,10 @@ gfx::RectF(GetMirroredRect(GetContentsBounds())).CenterPoint()); } +std::unique_ptr<views::InkDropMask> InkDropHostView::CreateInkDropMask() const { + return nullptr; +} + std::unique_ptr<InkDropRipple> InkDropHostView::CreateDefaultInkDropRipple( const gfx::Point& center_point, const gfx::Size& size) const { @@ -278,10 +282,6 @@ return gfx::kPlaceholderColor; } -std::unique_ptr<views::InkDropMask> InkDropHostView::CreateInkDropMask() const { - return nullptr; -} - bool InkDropHostView::HasInkDrop() const { return !!ink_drop_; }
diff --git a/ui/views/animation/ink_drop_host_view.h b/ui/views/animation/ink_drop_host_view.h index 34ea050d..81d0182 100644 --- a/ui/views/animation/ink_drop_host_view.h +++ b/ui/views/animation/ink_drop_host_view.h
@@ -45,6 +45,12 @@ std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override; std::unique_ptr<InkDropHighlight> CreateInkDropHighlight() const override; + // Subclasses can override to return a mask for the ink drop. By default, + // returns nullptr (i.e no mask). + // TODO(bruthig): InkDropMasks do not currently work on Windows. See + // https://crbug.com/713359. + virtual std::unique_ptr<views::InkDropMask> CreateInkDropMask() const; + // Toggle to enable/disable an InkDrop on this View. Descendants can override // CreateInkDropHighlight() and CreateInkDropRipple() to change the look/feel // of the InkDrop. @@ -107,12 +113,6 @@ // ink drop. virtual SkColor GetInkDropBaseColor() const; - // Subclasses can override to return a mask for the ink drop. By default, - // returns nullptr (i.e no mask). - // TODO(bruthig): InkDropMasks do not currently work on Windows. See - // crbug.com/713359. - virtual std::unique_ptr<views::InkDropMask> CreateInkDropMask() const; - // Called after a new InkDrop instance is created. virtual void OnInkDropCreated() {}
diff --git a/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js b/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js index 4cf3d472..d4d38a7 100644 --- a/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js +++ b/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js
@@ -5,7 +5,7 @@ /** * @fileoverview 'cr-toggle' is a component for showing an on/off switch. It * fires a 'change' event *only* when its state changes as a result of a user - * interaction. Besides just tapping the element, its state can be changed by + * interaction. Besides just clicking the element, its state can be changed by * dragging (pointerdown+pointermove) the element towards the desired direction. */ Polymer({ @@ -40,7 +40,7 @@ listeners: { 'pointerdown': 'onPointerDown_', 'pointerup': 'onPointerUp_', - 'tap': 'onTap_', + 'click': 'onTap_', 'keypress': 'onKeyPress_', 'focus': 'onFocus_', 'blur': 'onBlur_', @@ -58,7 +58,7 @@ /** * Whether the state of the toggle has already taken into account by - * |pointeremove| handlers. Used in the 'tap' handler. + * |pointeremove| handlers. Used in the 'click' handler. * @private {boolean} */ handledInPointerMove_: false, @@ -136,28 +136,29 @@ /** @private */ onTap_: function(e) { - // Prevent |tap| event from bubbling. It can cause parents of this elements - // to erroneously re-toggle this control. + // Prevent |click| event from bubbling. It can cause parents of this + // elements to erroneously re-toggle this control. e.stopPropagation(); + e.preventDefault(); // User gesture has already been taken care of inside |pointermove| // handlers, Do nothing here. if (this.handledInPointerMove_) return; - // If no pointermove event fired, then user just tapped on the + // If no pointermove event fired, then user just clicked on the // toggle button and therefore it should be toggled. this.toggleState_(false); }, /** - * Whether the host of this element should handle a 'tap' event it received, - * to be used when tapping on the parent is supposed to toggle the cr-toggle. + * Whether the host of this element should handle a 'click' event it received, + * to be used when clicking on the parent is supposed to toggle the cr-toggle. * * This is necessary to avoid a corner case when pointerdown is initiated * in cr-toggle, but pointerup happens outside the bounds of cr-toggle, which - * ends up firing a 'tap' event on the parent (see context at crbug.com/689158 - * and crbug.com/768555). + * ends up firing a 'click' event on the parent (see context at + * crbug.com/689158 and crbug.com/768555). * @param {!Event} e * @return {boolean} */