diff --git a/DEPS b/DEPS index 3b5cd12..211d474f 100644 --- a/DEPS +++ b/DEPS
@@ -105,11 +105,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '0098ccbab5d10040f021daab5bff7a38e718a309', + 'skia_revision': 'd37570b325e2a8c78aa232d13e502c8d24de7d46', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '8aa858e5115a8cdb376deb0c42561dea10c5d32a', + 'v8_revision': 'c5a1fcbf544dc5ca5d901e96e2228d1eb767251b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -117,7 +117,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '4ebd8f3d9999ca4cd1ec769fe4c4aaa2fceda431', + 'angle_revision': 'b36a4816a5460120249e89258af3c5741301de40', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -213,7 +213,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_tools_revision': '90a12b3d4d1d589b3d61c194f983eb9c22459226', + 'spv_tools_revision': '903514f95445267754e28f0cd8def22e9533ebe8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -313,7 +313,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '827c67034ba293e6e4676689979571e471ec5486', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'a9d14ef965d6e5e4852998b17a283e560990206e', 'condition': 'checkout_ios', }, @@ -954,7 +954,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'd963884232959c2de9b7b149530cbfea26fad6dc', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '2e5a2964784b33df48a0ad0827ed105e4fecfe3d', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', @@ -1106,7 +1106,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6d2f3f4cb8bac1f7c4a945c73d07a33df74f22f9', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'bacfd87b3be2a9d211560994b4e276a882188834', + Var('webrtc_git') + '/src.git' + '@' + 'a7af0218826cfed77664e6723470c77089e12db1', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1137,7 +1137,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d6b25c280cdc9cddda34ce091857f0fa6dd1cc83', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@be0a57bc9068ed15b2c91555ab9c5622baf18a36', 'condition': 'checkout_src_internal', },
diff --git a/ash/app_list/views/folder_header_view.cc b/ash/app_list/views/folder_header_view.cc index ef3aa40..fa92920 100644 --- a/ash/app_list/views/folder_header_view.cc +++ b/ash/app_list/views/folder_header_view.cc
@@ -201,7 +201,10 @@ folder_name_view_->GetInsets().width(); text_width = std::min(text_width, GetMaxFolderNameWidth()); text_bounds.set_x(rect.x() + (rect.width() - text_width) / 2); - text_bounds.set_width(text_width); + + // The width of the text field should always be maximum length, to prevent the + // touch target from resizing with the text. + text_bounds.set_width(GetMaxFolderNameWidth()); text_bounds.ClampToCenteredSize(gfx::Size( text_bounds.width(), folder_name_view_->GetPreferredSize().height())); folder_name_view_->SetBoundsRect(text_bounds);
diff --git a/ash/app_list/views/folder_header_view.h b/ash/app_list/views/folder_header_view.h index 65e92980..082726e 100644 --- a/ash/app_list/views/folder_header_view.h +++ b/ash/app_list/views/folder_header_view.h
@@ -23,7 +23,7 @@ class FolderHeaderViewTest; } -// FolderHeaderView contains a back button and an editable folder name field. +// FolderHeaderView contains an editable folder name field. class APP_LIST_EXPORT FolderHeaderView : public views::View, public views::TextfieldController, public AppListItemObserver {
diff --git a/ash/assistant/assistant_interaction_controller.cc b/ash/assistant/assistant_interaction_controller.cc index 57ff8892a3..a4017ee 100644 --- a/ash/assistant/assistant_interaction_controller.cc +++ b/ash/assistant/assistant_interaction_controller.cc
@@ -162,11 +162,10 @@ model_.SetInputModality(InputModality::kKeyboard); break; case AssistantVisibility::kVisible: - if (source == AssistantSource::kLauncherSearchBox) { + if (source == AssistantSource::kLauncherSearchBox || + source == AssistantSource::kLongPressLauncher) { if (IsTabletMode()) StartVoiceInteraction(); - } else if (source == AssistantSource::kLongPressLauncher) { - StartVoiceInteraction(); } else if (source == AssistantSource::kStylus) { model_.SetInputModality(InputModality::kStylus); }
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h index 9455fe3c..95611a5 100644 --- a/base/allocator/partition_allocator/partition_alloc.h +++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -337,6 +337,7 @@ internal::PartitionBucket* bucket = root->bucket_lookups[(order << kGenericNumBucketsPerOrderBits) + order_index + !!sub_order_index]; + CHECK(bucket); DCHECK(!bucket->slot_size || bucket->slot_size >= size); DCHECK(!(bucket->slot_size % kGenericSmallestBucket)); return bucket;
diff --git a/base/memory/platform_shared_memory_region_android.cc b/base/memory/platform_shared_memory_region_android.cc index a529725..c7dd5a9 100644 --- a/base/memory/platform_shared_memory_region_android.cc +++ b/base/memory/platform_shared_memory_region_android.cc
@@ -6,8 +6,10 @@ #include <sys/mman.h> +#include "base/bits.h" #include "base/memory/shared_memory_tracker.h" #include "base/posix/eintr_wrapper.h" +#include "base/process/process_metrics.h" #include "third_party/ashmem/ashmem.h" namespace base { @@ -159,7 +161,9 @@ if (size == 0) return {}; - if (size > static_cast<size_t>(std::numeric_limits<int>::max())) + // Align size as required by ashmem_create_region() API documentation. + size_t rounded_size = bits::Align(size, GetPageSize()); + if (rounded_size > static_cast<size_t>(std::numeric_limits<int>::max())) return {}; CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will " @@ -168,7 +172,7 @@ UnguessableToken guid = UnguessableToken::Create(); ScopedFD fd(ashmem_create_region( - SharedMemoryTracker::GetDumpNameForTracing(guid).c_str(), size)); + SharedMemoryTracker::GetDumpNameForTracing(guid).c_str(), rounded_size)); if (!fd.is_valid()) { DPLOG(ERROR) << "ashmem_create_region failed"; return {};
diff --git a/base/memory/shared_memory_android.cc b/base/memory/shared_memory_android.cc index c126767..e54e61a 100644 --- a/base/memory/shared_memory_android.cc +++ b/base/memory/shared_memory_android.cc
@@ -7,7 +7,9 @@ #include <stddef.h> #include <sys/mman.h> +#include "base/bits.h" #include "base/logging.h" +#include "base/process/process_metrics.h" #include "third_party/ashmem/ashmem.h" namespace base { @@ -20,13 +22,16 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { DCHECK(!shm_.IsValid()); - if (options.size > static_cast<size_t>(std::numeric_limits<int>::max())) + // Align size as required by ashmem_create_region() API documentation. + size_t rounded_size = bits::Align(options.size, GetPageSize()); + + if (rounded_size > static_cast<size_t>(std::numeric_limits<int>::max())) return false; // "name" is just a label in ashmem. It is visible in /proc/pid/maps. int fd = ashmem_create_region( options.name_deprecated ? options.name_deprecated->c_str() : "", - options.size); + rounded_size); shm_ = SharedMemoryHandle::ImportHandle(fd, options.size); if (!shm_.IsValid()) { DLOG(ERROR) << "Shared memory creation failed";
diff --git a/base/threading/scoped_blocking_call.h b/base/threading/scoped_blocking_call.h index 144480b9..516ac0a 100644 --- a/base/threading/scoped_blocking_call.h +++ b/base/threading/scoped_blocking_call.h
@@ -10,6 +10,12 @@ namespace base { +// A "blocking call" refers to any call that causes the calling thread to wait +// off-CPU. It includes but is not limited to calls that wait on synchronous +// file I/O operations: read or write a file from disk, interact with a pipe or +// a socket, rename or delete a file, enumerate files in a directory, etc. +// Acquiring a low contention lock is not considered a blocking call. + // BlockingType indicates the likelihood that a blocking call will actually // block. enum class BlockingType { @@ -46,14 +52,16 @@ } // namespace internal -// This class must be instantiated in every scope where a blocking call is made. -// When a ScopedBlockingCall is instantiated, it asserts that blocking calls are -// allowed in its scope with a call to base::AssertBlockingAllowed(). CPU usage -// should be minimal within that scope. //base APIs that block instantiate their -// own ScopedBlockingCall; it is not necessary to instantiate another -// ScopedBlockingCall in the scope where these APIs are used. Nested -// ScopedBlockingCalls are supported (mostly a no-op except for WILL_BLOCK -// nested within MAY_BLOCK which will result in immediate WILL_BLOCK semantics). +// This class must be instantiated in every scope where a blocking call is made +// and serves as a precise annotation of the scope that may/will block for the +// scheduler. When a ScopedBlockingCall is instantiated, it asserts that +// blocking calls are allowed in its scope with a call to +// base::AssertBlockingAllowed(). CPU usage should be minimal within that scope. +// //base APIs that block instantiate their own ScopedBlockingCall; it is not +// necessary to instantiate another ScopedBlockingCall in the scope where these +// APIs are used. Nested ScopedBlockingCalls are supported (mostly a no-op +// except for WILL_BLOCK nested within MAY_BLOCK which will result in immediate +// WILL_BLOCK semantics). // // Good: // Data data;
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 844dc792..b5a24d0 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -376,7 +376,7 @@ defines = [ "CC_IMPLEMENTATION=1" ] } -cc_static_library("test_support") { +cc_test_static_library("test_support") { testonly = true sources = [ "test/animation_test_common.cc",
diff --git a/cc/cc.gni b/cc/cc.gni index 44a5eebc5..51bbd51a 100644 --- a/cc/cc.gni +++ b/cc/cc.gni
@@ -6,24 +6,16 @@ import("//testing/test.gni") cc_remove_configs = [] -cc_add_configs = [ "//build/config:precompiled_headers" ] +cc_add_configs = [ + "//build/config:precompiled_headers", + "//build/config/compiler:wexit_time_destructors", +] if (!is_debug && (is_win || is_android)) { cc_remove_configs += [ "//build/config/compiler:default_optimization" ] cc_add_configs += [ "//build/config/compiler:optimize_max" ] } -template("cc_source_set") { - jumbo_source_set(target_name) { - forward_variables_from(invoker, "*", [ "configs" ]) - if (defined(invoker.configs)) { - configs += invoker.configs - } - configs -= cc_remove_configs - configs += cc_add_configs - } -} - template("cc_component") { jumbo_component(target_name) { forward_variables_from(invoker, "*", [ "configs" ]) @@ -35,7 +27,7 @@ } } -template("cc_static_library") { +template("cc_test_static_library") { jumbo_static_library(target_name) { forward_variables_from(invoker, "*", [ "configs" ]) if (defined(invoker.configs)) { @@ -43,6 +35,9 @@ } configs -= cc_remove_configs configs += cc_add_configs + + # Not needed in test code. + configs -= [ "//build/config/compiler:wexit_time_destructors" ] } } @@ -54,5 +49,8 @@ } configs -= cc_remove_configs configs += cc_add_configs + + # Not needed in test code. + configs -= [ "//build/config/compiler:wexit_time_destructors" ] } }
diff --git a/cc/input/main_thread_scrolling_reason.cc b/cc/input/main_thread_scrolling_reason.cc index 6653ac9..a85b60f 100644 --- a/cc/input/main_thread_scrolling_reason.cc +++ b/cc/input/main_thread_scrolling_reason.cc
@@ -71,6 +71,10 @@ traced_value.AppendString("Non-invertible transform"); if (reasons & kPageBasedScrolling) traced_value.AppendString("Page-based scrolling"); + if (reasons & kWheelEventHandlerRegion) + traced_value.AppendString("Wheel event handler region"); + if (reasons & kTouchEventHandlerRegion) + traced_value.AppendString("Touch event handler region"); traced_value.EndArray(); }
diff --git a/cc/input/main_thread_scrolling_reason.h b/cc/input/main_thread_scrolling_reason.h index b926c751..cf2deff 100644 --- a/cc/input/main_thread_scrolling_reason.h +++ b/cc/input/main_thread_scrolling_reason.h
@@ -60,12 +60,14 @@ kContinuingMainThreadScroll = 1 << 10, kNonInvertibleTransform = 1 << 11, kPageBasedScrolling = 1 << 12, + kWheelEventHandlerRegion = 1 << 23, + kTouchEventHandlerRegion = 1 << 24, // The maximum number of flags in this struct (excluding itself). // New flags should increment this number but it should never be decremented // because the values are used in UMA histograms. It should also be noted // that it excludes the kNotScrollingOnMain value. - kMainThreadScrollingReasonCount = 23, + kMainThreadScrollingReasonCount = 25, }; static const uint32_t kNonCompositedReasons = @@ -91,7 +93,8 @@ uint32_t reasons_set_by_compositor = kNonFastScrollableRegion | kFailedHitTest | kNoScrollingLayer | kNotScrollable | kContinuingMainThreadScroll | kNonInvertibleTransform | - kPageBasedScrolling; + kPageBasedScrolling | kWheelEventHandlerRegion | + kTouchEventHandlerRegion; return (reasons & reasons_set_by_compositor) == reasons; }
diff --git a/cc/input/main_thread_scrolling_reason_unittest.cc b/cc/input/main_thread_scrolling_reason_unittest.cc index ec49ff9..9f8e6b6 100644 --- a/cc/input/main_thread_scrolling_reason_unittest.cc +++ b/cc/input/main_thread_scrolling_reason_unittest.cc
@@ -31,7 +31,9 @@ "Not scrollable," "Continuing main thread scroll," "Non-invertible transform," - "Page-based scrolling", + "Page-based scrolling," + "Wheel event handler region," + "Touch event handler region", MainThreadScrollingReason::AsText(0xffffffffu)); }
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index d28e609..9b7809e3 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -13,6 +13,7 @@ #include <set> #include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" #include "base/time/time.h" #include "base/trace_event/trace_event_argument.h" #include "build/build_config.h" @@ -666,11 +667,11 @@ !layer_tree_impl()->SmoothnessTakesPriority(); } - static const Occlusion kEmptyOcclusion; + static const base::NoDestructor<Occlusion> kEmptyOcclusion; const Occlusion& occlusion_in_content_space = layer_tree_impl()->settings().use_occlusion_for_tile_prioritization ? draw_properties().occlusion_in_content_space - : kEmptyOcclusion; + : *kEmptyOcclusion; // Pass |occlusion_in_content_space| for |occlusion_in_layer_space| since // they are the same space in picture layer, as contents scale is always 1.
diff --git a/cc/paint/discardable_image_map.cc b/cc/paint/discardable_image_map.cc index 232dab6a..1c53bb9 100644 --- a/cc/paint/discardable_image_map.cc +++ b/cc/paint/discardable_image_map.cc
@@ -12,6 +12,7 @@ #include "base/auto_reset.h" #include "base/containers/adapters.h" #include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" #include "base/trace_event/trace_event.h" #include "cc/paint/paint_filter.h" #include "cc/paint/paint_op_buffer.h" @@ -456,9 +457,9 @@ const DiscardableImageMap::Rects& DiscardableImageMap::GetRectsForImage( PaintImage::Id image_id) const { - static const Rects kEmptyRects; + static const base::NoDestructor<Rects> kEmptyRects; auto it = image_id_to_rects_.find(image_id); - return it == image_id_to_rects_.end() ? kEmptyRects : it->second; + return it == image_id_to_rects_.end() ? *kEmptyRects : it->second; } void DiscardableImageMap::Reset() {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 93fbeb84..e53875b 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -1958,6 +1958,11 @@ metadata.min_page_scale_factor = active_tree_->min_page_scale_factor(); + metadata.top_controls_height = + browser_controls_offset_manager_->TopControlsHeight(); + metadata.top_controls_shown_ratio = + browser_controls_offset_manager_->TopControlsShownRatio(); + #if defined(OS_ANDROID) metadata.max_page_scale_factor = active_tree_->max_page_scale_factor(); metadata.root_layer_size = active_tree_->ScrollableSize(); @@ -1967,10 +1972,6 @@ !outer_viewport_scroll_node->user_scrollable_vertical; } - metadata.top_controls_height = - browser_controls_offset_manager_->TopControlsHeight(); - metadata.top_controls_shown_ratio = - browser_controls_offset_manager_->TopControlsShownRatio(); metadata.bottom_controls_height = browser_controls_offset_manager_->BottomControlsHeight(); metadata.bottom_controls_shown_ratio =
diff --git a/cc/trees/render_frame_metadata.h b/cc/trees/render_frame_metadata.h index bd261d6..8b6c45d 100644 --- a/cc/trees/render_frame_metadata.h +++ b/cc/trees/render_frame_metadata.h
@@ -66,8 +66,8 @@ float page_scale_factor = 1.f; - // Used to position the Android location top bar and page content, whose - // precise position is computed by the renderer compositor. + // Used to position the location top bar and page content, whose precise + // position is computed by the renderer compositor. float top_controls_height = 0.f; float top_controls_shown_ratio = 0.f;
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 85f66a45..e4aa553 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -391,6 +391,7 @@ "//chrome/browser/android/crash/crash_keys_android.h", "//chrome/browser/android/customtabs/detached_resource_request.h", "//chrome/browser/android/digital_asset_links/digital_asset_links_handler.h", + "//chrome/browser/android/explore_sites/explore_sites_feature.h", "//chrome/browser/android/feedback/connectivity_checker.cc", "//chrome/browser/android/policy/policy_auditor.cc", "//chrome/browser/android/shortcut_info.h",
diff --git a/chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml b/chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml index d456217..8ef6b6a 100644 --- a/chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml +++ b/chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml
@@ -15,7 +15,7 @@ <!-- Main icon/image --> <ImageView - android:id="@+id/explore_sites_category_tile_icon" + android:id="@+id/experimental_explore_sites_category_tile_icon" android:layout_gravity="center_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -23,7 +23,7 @@ <!-- Category title --> <TextView - android:id="@+id/explore_sites_category_tile_title" + android:id="@+id/experimental_explore_sites_category_tile_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal"
diff --git a/chrome/android/java/res/layout/experimental_explore_sites_section.xml b/chrome/android/java/res/layout/experimental_explore_sites_section.xml index 9969ef2..76586bb 100644 --- a/chrome/android/java/res/layout/experimental_explore_sites_section.xml +++ b/chrome/android/java/res/layout/experimental_explore_sites_section.xml
@@ -12,29 +12,29 @@ <TextView style="@style/BlackCaption" - android:id="@+id/explore_sites_title" + android:id="@+id/experimental_explore_sites_title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/explore_sites_spacing" + android:layout_marginTop="@dimen/experimental_explore_sites_spacing" android:gravity="center" android:text="@string/explore_sites_title" /> <LinearLayout - android:id="@+id/explore_sites_tiles" + android:id="@+id/experimental_explore_sites_tiles" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/explore_sites_spacing" - android:paddingHorizontal="@dimen/explore_sites_padding" + android:layout_marginTop="@dimen/experimental_explore_sites_spacing" + android:paddingHorizontal="@dimen/experimental_explore_sites_padding" android:orientation="horizontal" /> <Button - android:id="@+id/explore_sites_more_button" + android:id="@+id/experimental_explore_sites_more_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" - android:layout_marginTop="@dimen/explore_sites_spacing" - android:layout_marginHorizontal="@dimen/explore_sites_margin" - android:layout_marginBottom="@dimen/explore_sites_spacing" + android:layout_marginTop="@dimen/experimental_explore_sites_spacing" + android:layout_marginHorizontal="@dimen/experimental_explore_sites_margin" + android:layout_marginBottom="@dimen/experimental_explore_sites_spacing" android:text="@string/ntp_explore_sites_more" /> </LinearLayout>
diff --git a/chrome/android/java/res/layout/explore_sites_category_tile_view.xml b/chrome/android/java/res/layout/explore_sites_category_tile_view.xml new file mode 100644 index 0000000..258f178b --- /dev/null +++ b/chrome/android/java/res/layout/explore_sites_category_tile_view.xml
@@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. --> + +<org.chromium.chrome.browser.explore_sites.ExploreSitesCategoryTileView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="@dimen/tile_view_width" + android:layout_height="wrap_content" + android:paddingStart="@dimen/tile_view_padding" + android:paddingEnd="@dimen/tile_view_padding" > + <include + android:layout_width="match_parent" + android:layout_height="match_parent" + layout="@layout/tile_view_modern" /> +</org.chromium.chrome.browser.explore_sites.ExploreSitesCategoryTileView>
diff --git a/chrome/android/java/res/layout/explore_sites_category_tile_view_condensed.xml b/chrome/android/java/res/layout/explore_sites_category_tile_view_condensed.xml new file mode 100644 index 0000000..86ad1c5 --- /dev/null +++ b/chrome/android/java/res/layout/explore_sites_category_tile_view_condensed.xml
@@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. --> + +<org.chromium.chrome.browser.explore_sites.ExploreSitesCategoryTileView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="@dimen/tile_view_width_condensed" + android:layout_height="wrap_content" + android:paddingStart="@dimen/tile_view_padding" + android:paddingEnd="@dimen/tile_view_padding" > + <include + android:layout_width="match_parent" + android:layout_height="match_parent" + layout="@layout/tile_view_modern_condensed" /> +</org.chromium.chrome.browser.explore_sites.ExploreSitesCategoryTileView>
diff --git a/chrome/android/java/res/layout/explore_sites_section.xml b/chrome/android/java/res/layout/explore_sites_section.xml new file mode 100644 index 0000000..f5f341e --- /dev/null +++ b/chrome/android/java/res/layout/explore_sites_section.xml
@@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. --> + +<org.chromium.chrome.browser.suggestions.TileGridLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="top" + android:gravity="center_horizontal" />
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml index 6a994f78..7c0158c 100644 --- a/chrome/android/java/res/layout/new_tab_page_layout.xml +++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -85,7 +85,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:inflatedId="@+id/explore_sites" - android:layout="@layout/experimental_explore_sites_section" /> + android:layout_marginBottom="16dp" + android:layout="@layout/explore_sites_section" /> <!-- Site suggestion tile grid placeholder --> <ViewStub
diff --git a/chrome/android/java/res/layout/suggestions_tile_view.xml b/chrome/android/java/res/layout/suggestions_tile_view.xml index e92c7dd..ba00700 100644 --- a/chrome/android/java/res/layout/suggestions_tile_view.xml +++ b/chrome/android/java/res/layout/suggestions_tile_view.xml
@@ -10,8 +10,8 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="@dimen/tile_view_width" android:layout_height="wrap_content" - android:paddingStart="4dp" - android:paddingEnd="4dp" > + android:paddingStart="@dimen/tile_view_padding" + android:paddingEnd="@dimen/tile_view_padding" > <include android:layout_width="match_parent" android:layout_height="match_parent"
diff --git a/chrome/android/java/res/layout/suggestions_tile_view_condensed.xml b/chrome/android/java/res/layout/suggestions_tile_view_condensed.xml index 2097270..820b0c5 100644 --- a/chrome/android/java/res/layout/suggestions_tile_view_condensed.xml +++ b/chrome/android/java/res/layout/suggestions_tile_view_condensed.xml
@@ -10,8 +10,8 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="@dimen/tile_view_width_condensed" android:layout_height="wrap_content" - android:paddingStart="4dp" - android:paddingEnd="4dp" > + android:paddingStart="@dimen/tile_view_padding" + android:paddingEnd="@dimen/tile_view_padding" > <include android:layout_width="match_parent" android:layout_height="match_parent"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 15e2537..80d4f70 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -223,8 +223,6 @@ <dimen name="control_container_height">56dp</dimen> <dimen name="bottom_toolbar_height">@dimen/min_touch_target_size</dimen> <dimen name="bottom_control_container_peek_height">48dp</dimen> - <dimen name="bottom_control_container_slim_peek_height">40dp</dimen> - <dimen name="bottom_control_container_slim_expanded_height">56dp</dimen> <dimen name="custom_tabs_control_container_height">56dp</dimen> <dimen name="fullscreen_activity_control_container_height">0dp</dimen> @@ -315,15 +313,16 @@ <dimen name="tile_view_offline_badge_margin_end_modern">9dp</dimen> <dimen name="tile_view_offline_badge_margin_top_modern_condensed">6dp</dimen> <dimen name="tile_view_offline_badge_margin_end_modern_condensed">7dp</dimen> + <dimen name="tile_view_padding">4dp</dimen> <dimen name="tile_view_title_margin_top_modern">61dp</dimen> <dimen name="ntp_logo_height">100dp</dimen> <dimen name="duet_ntp_logo_top_margin">-16dp</dimen> <dimen name="ntp_search_box_height">48dp</dimen> <dimen name="ntp_search_box_transition_length">16dp</dimen> - <dimen name="explore_sites_radius">8dp</dimen> - <dimen name="explore_sites_padding">8dp</dimen> - <dimen name="explore_sites_margin">16dp</dimen> - <dimen name="explore_sites_spacing">12dp</dimen> + <dimen name="experimental_explore_sites_radius">8dp</dimen> + <dimen name="experimental_explore_sites_padding">8dp</dimen> + <dimen name="experimental_explore_sites_margin">16dp</dimen> + <dimen name="experimental_explore_sites_spacing">12dp</dimen> <!-- Negative vertical inset added to the search box bounds when modern is enabled. 4dp is added to both the top and bottom bounds to bring the 48dp modern_toolbar_background_size to 56dp (matches toolbar_height_no_shadow). -->
diff --git a/chrome/android/java/res/xml/sync_and_services_preferences.xml b/chrome/android/java/res/xml/sync_and_services_preferences.xml index 2205043..8b2cdc20 100644 --- a/chrome/android/java/res/xml/sync_and_services_preferences.xml +++ b/chrome/android/java/res/xml/sync_and_services_preferences.xml
@@ -8,7 +8,7 @@ android:key="sign_in" android:title="@string/sign_in_to_chrome"/> - <org.chromium.chrome.browser.preferences.SyncErrorCardPreference + <Preference android:key="sync_error_card" android:icon="@drawable/sync_error" android:title="@string/sync_error_card_title"/>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java index 4abdb98b..4cece6b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
@@ -296,7 +296,7 @@ /** * @return The fullscreen width. */ - private float getFullscreenWidth() { + public float getFullscreenWidth() { return mLayoutWidth; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java index 920bfa9..6e83f950 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
@@ -134,6 +134,7 @@ ContextualSearchPanel.CLOSE_ICON_DRAWABLE_ID, R.drawable.progress_bar_background, R.drawable.progress_bar_foreground, searchPromoViewId, R.drawable.contextual_search_promo_ripple, searchBarBannerTextViewId, mDpToPx, + panel.getFullscreenWidth() * mDpToPx, panel.getTabHeight() * mDpToPx, panel.getBasePageBrightness(), panel.getBasePageY() * mDpToPx, panelWebContents, searchPromoVisible, searchPromoHeightPx, searchPromoOpacity, searchBarBannerVisible, searchBarBannerHeightPx, searchBarBannerPaddingPx, searchBarBannerRippleWidthPx, @@ -203,14 +204,15 @@ int searchProviderIconResourceId, int quickActionIconResourceId, int arrowUpResourceId, int closeIconResourceId, int progressBarBackgroundResourceId, int progressBarResourceId, int searchPromoResourceId, int barBannerRippleResourceId, int barBannerTextResourceId, - float dpToPx, float basePageBrightness, float basePageYOffset, WebContents webContents, - boolean searchPromoVisible, float searchPromoHeight, float searchPromoOpacity, - boolean searchBarBannerVisible, float searchBarBannerHeight, - float searchBarBannerPaddingPx, float searchBarBannerRippleWidth, - float searchBarBannerRippleOpacity, float searchBarBannerTextOpacity, - float searchPanelX, float searchPanelY, float searchPanelWidth, float searchPanelHeight, - float searchBarMarginSide, float searchBarHeight, float searchContextOpacity, - float searchTextLayerMinHeight, float searchTermOpacity, float searchTermCaptionSpacing, + float dpToPx, float layoutWidth, float layoutHeight, float basePageBrightness, + float basePageYOffset, WebContents webContents, boolean searchPromoVisible, + float searchPromoHeight, float searchPromoOpacity, boolean searchBarBannerVisible, + float searchBarBannerHeight, float searchBarBannerPaddingPx, + float searchBarBannerRippleWidth, float searchBarBannerRippleOpacity, + float searchBarBannerTextOpacity, float searchPanelX, float searchPanelY, + float searchPanelWidth, float searchPanelHeight, float searchBarMarginSide, + float searchBarHeight, float searchContextOpacity, float searchTextLayerMinHeight, + float searchTermOpacity, float searchTermCaptionSpacing, float searchCaptionAnimationPercentage, boolean searchCaptionVisible, boolean searchBarBorderVisible, float searchBarBorderHeight, boolean searchBarShadowVisible, float searchBarShadowOpacity,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java index 41fa3ea4..c889edf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java
@@ -62,11 +62,6 @@ } @Override - public boolean useSlimPeek() { - return false; - } - - @Override public int getSheetContentDescriptionStringId() { return R.string.contextual_suggestions_button_description; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java index 60bf266..3532786 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
@@ -45,17 +45,19 @@ @Override public void onFinishInflate() { super.onFinishInflate(); - mTitleView = findViewById(R.id.explore_sites_category_tile_title); - mIconView = findViewById(R.id.explore_sites_category_tile_icon); + mTitleView = findViewById(R.id.experimental_explore_sites_category_tile_title); + mIconView = findViewById(R.id.experimental_explore_sites_category_tile_icon); } public void initialize(ExploreSitesCategoryTile category, int widthPx) { mCategoryData = category; - mIconWidthPx = - widthPx - (2 * mResources.getDimensionPixelSize(R.dimen.explore_sites_padding)); + mIconWidthPx = widthPx + - (2 + * mResources.getDimensionPixelSize( + R.dimen.experimental_explore_sites_padding)); mIconHeightPx = mIconWidthPx * 2 / 3; mIconGenerator = new RoundedIconGenerator(mIconWidthPx, mIconHeightPx, - mResources.getDimensionPixelSize(R.dimen.explore_sites_radius), + mResources.getDimensionPixelSize(R.dimen.experimental_explore_sites_radius), ApiCompatibilityUtils.getColor( mResources, R.color.default_favicon_background_color), mResources.getDimensionPixelSize(R.dimen.headline_size_medium)); @@ -71,7 +73,7 @@ } else { drawable = ViewUtils.createRoundedBitmapDrawable( Bitmap.createScaledBitmap(bitmap, mIconWidthPx, mIconHeightPx, false), - mResources.getDimensionPixelSize(R.dimen.explore_sites_radius)); + mResources.getDimensionPixelSize(R.dimen.experimental_explore_sites_radius)); } mCategoryData.setIconDrawable(drawable); mIconView.setImageDrawable(drawable);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java index 9969fc8..2afa2755 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
@@ -42,10 +42,11 @@ } private void initialize() { - mCategorySection = mExploreSection.findViewById(R.id.explore_sites_tiles); + mCategorySection = mExploreSection.findViewById(R.id.experimental_explore_sites_tiles); ExploreSitesBridgeExperimental.getNtpCategories(mProfile, this::initializeTiles); - View moreCategoriesButton = mExploreSection.findViewById(R.id.explore_sites_more_button); + View moreCategoriesButton = + mExploreSection.findViewById(R.id.experimental_explore_sites_more_button); moreCategoriesButton.setOnClickListener( (View v) -> mNavigationDelegate.openUrl(WindowOpenDisposition.CURRENT_TAB,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java index b9eb85a..e98ed46 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
@@ -37,6 +37,15 @@ finishedCallback.onResult(null); } + /** + * Gets the current Finch variation that is configured by flag or experiment. + */ + @ExploreSitesVariation + public static int getVariation() { + return nativeGetVariation(); + } + + static native int nativeGetVariation(); private static native void nativeGetEspCatalog(Profile profile, List<ExploreSitesCategory> result, Callback<List<ExploreSitesCategory>> callback); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategory.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategory.java index b20322b..ad8f5c7c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategory.java
@@ -7,6 +7,7 @@ import android.graphics.Bitmap; import org.chromium.base.annotations.CalledByNative; +import org.chromium.chrome.browser.UrlConstants; import java.util.ArrayList; import java.util.List; @@ -53,6 +54,10 @@ return mSites; } + public String getUrl() { + return UrlConstants.EXPLORE_URL + "#" + getId(); + } + // Creates a new category and appends to the given list. Also returns the created category to // easily append sites to the category. @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java new file mode 100644 index 0000000..d38ccde --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java
@@ -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. + +package org.chromium.chrome.browser.explore_sites; + +import android.content.Context; +import android.graphics.drawable.BitmapDrawable; +import android.util.AttributeSet; + +import org.chromium.chrome.browser.ntp.TitleUtil; +import org.chromium.chrome.browser.widget.tile.TileWithTextView; + +/** + * A category tile for ExploreSites, containing an icon that is a composition of sites' favicons + * within the category. Alternatively, a MORE button. + */ +public class ExploreSitesCategoryTileView extends TileWithTextView { + private static final int TITLE_LINES = 1; + private static final boolean SUPPORTED_OFFLINE = false; + + /** The data currently associated to this tile. */ + private ExploreSitesCategory mCategory; + + /** + * Constructor for inflating from XML. + */ + public ExploreSitesCategoryTileView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + /** + * Initializes the view using the data held by {@code tile}. This should be called immediately + * after inflation. + * @param category The object that holds the data to populate this view. + */ + public void initialize(ExploreSitesCategory category) { + super.initialize(TitleUtil.getTitleForDisplay(category.getTitle(), category.getUrl()), + SUPPORTED_OFFLINE, new BitmapDrawable(category.getIcon()), TITLE_LINES); + mCategory = category; + } + + /** Retrieves url associated with this view. */ + public String getUrl() { + return mCategory.getUrl(); + } + + /** Renders icon based on tile data. */ + public void renderIcon(ExploreSitesCategory category) { + mCategory = category; + setIconDrawable(new BitmapDrawable(getResources(), category.getIcon())); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java new file mode 100644 index 0000000..2e1925e --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
@@ -0,0 +1,86 @@ +// 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. + +package org.chromium.chrome.browser.explore_sites; + +import android.view.LayoutInflater; +import android.view.View; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.suggestions.SuggestionsConfig.TileStyle; +import org.chromium.chrome.browser.suggestions.TileGridLayout; +import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.ui.base.PageTransition; +import org.chromium.ui.mojom.WindowOpenDisposition; + +import java.util.List; + +/** + * Describes a portion of UI responsible for rendering a group of categories. + * It abstracts general tasks related to initializing and fetching data for the UI. + */ +public class ExploreSitesSection { + private static final int MAX_TILES = 4; + + @TileStyle + private int mStyle; + private Profile mProfile; + private NativePageNavigationDelegate mNavigationDelegate; + private TileGridLayout mExploreSection; + + public ExploreSitesSection(View view, Profile profile, + NativePageNavigationDelegate navigationDelegate, @TileStyle int style) { + mProfile = profile; + mStyle = style; + mExploreSection = (TileGridLayout) view; + mExploreSection.setMaxRows(1); + mExploreSection.setMaxColumns(MAX_TILES); + mNavigationDelegate = navigationDelegate; + initialize(); + } + + private void initialize() { + ExploreSitesBridge.getEspCatalog(mProfile, this ::initializeCategoryTiles); + } + + private void initializeCategoryTiles(List<ExploreSitesCategory> categoryList) { + if (categoryList == null) return; + if (categoryList.size() == 0) { + // TODO(dewittj): Remove this once the fetcher works. + categoryList.add(new ExploreSitesCategory(1, "this")); + categoryList.add(new ExploreSitesCategory(1, "this")); + categoryList.add(new ExploreSitesCategory(1, "this")); + categoryList.add(new ExploreSitesCategory(1, "More")); + } + + int tileCount = 0; + for (final ExploreSitesCategory category : categoryList) { + tileCount++; + if (tileCount > MAX_TILES) break; + ExploreSitesCategoryTileView tileView; + if (mStyle == TileStyle.MODERN_CONDENSED) { + tileView = (ExploreSitesCategoryTileView) LayoutInflater + .from(mExploreSection.getContext()) + .inflate(R.layout.explore_sites_category_tile_view_condensed, + mExploreSection, false); + } else { + tileView = (ExploreSitesCategoryTileView) LayoutInflater + .from(mExploreSection.getContext()) + .inflate(R.layout.explore_sites_category_tile_view, + mExploreSection, false); + } + + tileView.initialize(category); + mExploreSection.addView(tileView); + tileView.setOnClickListener((View v) -> onClicked(category, v)); + } + } + + private void onClicked(ExploreSitesCategory category, View v) { + mNavigationDelegate.openUrl(WindowOpenDisposition.CURRENT_TAB, + new LoadUrlParams(category.getUrl(), PageTransition.AUTO_BOOKMARK)); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java index c1e8520..f277d6a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java
@@ -30,9 +30,8 @@ } public void initialize(ExploreSitesSite site) { - super.initialize(site.getTitle(), site.getUrl(), /* showOfflineBadge = */ false, - getDrawableForBitmap(site.getIcon(), site.getTitle()), TITLE_LINES, - TileWithTextView.Style.MODERN); + super.initialize(site.getTitle(), /* showOfflineBadge = */ false, + getDrawableForBitmap(site.getIcon(), site.getTitle()), TITLE_LINES); } public void updateIcon(Bitmap iconImage, String text) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java index 2877e609..8a15338 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -29,6 +29,9 @@ import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider; import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection; +import org.chromium.chrome.browser.explore_sites.ExploreSitesBridge; +import org.chromium.chrome.browser.explore_sites.ExploreSitesSection; +import org.chromium.chrome.browser.explore_sites.ExploreSitesVariation; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.native_page.ContextMenuManager; import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener; @@ -86,7 +89,7 @@ @Nullable private View mExploreSectionView; // View is null if explore flag is disabled. @Nullable - private ExperimentalExploreSitesSection mExploreSection; // Null when explore sites disabled. + private Object mExploreSection; // Null when explore sites disabled. private OnSearchBoxScrollListener mSearchBoxScrollListener; @@ -185,8 +188,12 @@ mSearchProviderLogoView = findViewById(R.id.search_provider_logo); mSearchBoxView = findViewById(R.id.search_box); insertSiteSectionView(); - if (ChromeFeatureList.isEnabled(ChromeFeatureList.EXPLORE_SITES)) { + + if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.ENABLED) { + mExploreSectionView = ((ViewStub) findViewById(R.id.explore_sites_stub)).inflate(); + } else if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.EXPERIMENT) { ViewStub exploreStub = findViewById(R.id.explore_sites_stub); + exploreStub.setLayoutResource(R.layout.experimental_explore_sites_section); mExploreSectionView = exploreStub.inflate(); } @@ -233,7 +240,10 @@ mSiteSectionViewHolder = SiteSection.createViewHolder(getSiteSectionView(), mUiConfig); mSiteSectionViewHolder.bindDataSource(mTileGroup, tileRenderer); - if (ChromeFeatureList.isEnabled(ChromeFeatureList.EXPLORE_SITES)) { + if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.ENABLED) { + mExploreSection = new ExploreSitesSection(mExploreSectionView, profile, + mManager.getNavigationDelegate(), SuggestionsConfig.getTileStyle(mUiConfig)); + } else if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.EXPERIMENT) { mExploreSection = new ExperimentalExploreSitesSection( mExploreSectionView, profile, mManager.getNavigationDelegate()); } @@ -422,6 +432,12 @@ mSiteSectionView = SiteSection.inflateSiteSection(this); ViewGroup.LayoutParams layoutParams = mSiteSectionView.getLayoutParams(); layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT; + // If the explore sites section exists, then space it more closely. + if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.ENABLED) { + ((MarginLayoutParams) layoutParams).bottomMargin = + getResources().getDimensionPixelOffset( + R.dimen.tile_grid_layout_vertical_spacing); + } mSiteSectionView.setLayoutParams(layoutParams); int insertionPoint = indexOfChild(mMiddleSpacer) + 1; @@ -878,6 +894,11 @@ measureExactly(mSearchBoxView, width, mSearchBoxView.getMeasuredHeight()); measureExactly(mSearchProviderLogoView, width, mSearchProviderLogoView.getMeasuredHeight()); + + if (mExploreSectionView != null) { + measureExactly(mExploreSectionView, mSiteSectionView.getMeasuredWidth(), + mExploreSectionView.getMeasuredHeight()); + } } else if (mExploreSectionView != null) { final int exploreWidth = mExploreSectionView.getMeasuredWidth() - mTileGridLayoutBleed; measureExactly(mSearchBoxView, exploreWidth, mSearchBoxView.getMeasuredHeight());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java index 3628209..2f3e1401 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.suggestions; import android.content.res.Resources; +import android.support.annotation.IntDef; import android.text.TextUtils; import org.chromium.base.ApiCompatibilityUtils; @@ -12,12 +13,21 @@ import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.util.AccessibilityUtil; import org.chromium.chrome.browser.widget.displaystyle.UiConfig; -import org.chromium.chrome.browser.widget.tile.TileWithTextView; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * Provides configuration details for suggestions. */ public final class SuggestionsConfig { + @IntDef({TileStyle.MODERN, TileStyle.MODERN_CONDENSED}) + @Retention(RetentionPolicy.SOURCE) + public @interface TileStyle { + int MODERN = 1; + int MODERN_CONDENSED = 2; + } + /** * Field trial parameter for referrer URL. * It must be kept in sync with //components/ntp_suggestions/features.cc @@ -55,10 +65,10 @@ /** * Returns the current tile style, that depends on the enabled features and the screen size. */ - @TileWithTextView.Style + @TileStyle public static int getTileStyle(UiConfig uiConfig) { - return uiConfig.getCurrentDisplayStyle().isSmall() ? TileWithTextView.Style.MODERN_CONDENSED - : TileWithTextView.Style.MODERN; + return uiConfig.getCurrentDisplayStyle().isSmall() ? TileStyle.MODERN_CONDENSED + : TileStyle.MODERN; } private static boolean useCondensedTileLayout(boolean isScreenSmall) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsTileView.java index c007526d..ecefd83 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsTileView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsTileView.java
@@ -11,7 +11,6 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ntp.TitleUtil; import org.chromium.chrome.browser.widget.tile.TileWithTextView; -import org.chromium.chrome.browser.widget.tile.TileWithTextView.Style; /** * The view for a site suggestion tile. Displays the title of the site beneath a large icon. If a @@ -33,11 +32,10 @@ * after inflation. * @param tile The tile that holds the data to populate this view. * @param titleLines The number of text lines to use for the tile title. - * @param tileStyle The visual style of the tile. */ - public void initialize(Tile tile, int titleLines, @Style int tileStyle) { + public void initialize(Tile tile, int titleLines) { super.initialize(TitleUtil.getTitleForDisplay(tile.getTitle(), tile.getUrl()), - tile.getUrl(), tile.isOfflineAvailable(), tile.getIcon(), titleLines, tileStyle); + tile.isOfflineAvailable(), tile.getIcon(), titleLines); mData = tile.getData(); setIconViewLayoutParams(tile); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java index 3251907..b1c60e4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java
@@ -24,9 +24,9 @@ import org.chromium.chrome.browser.favicon.LargeIconBridge; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.suggestions.SuggestionsConfig.TileStyle; import org.chromium.chrome.browser.util.ViewUtils; import org.chromium.chrome.browser.widget.RoundedIconGenerator; -import org.chromium.chrome.browser.widget.tile.TileWithTextView; import org.chromium.components.feature_engagement.EventConstants; import org.chromium.components.feature_engagement.Tracker; @@ -49,7 +49,7 @@ private final ImageFetcher mImageFetcher; private final RoundedIconGenerator mIconGenerator; - @TileWithTextView.Style + @TileStyle private final int mStyle; private final int mTitleLinesCount; private final int mDesiredIconSize; @@ -58,8 +58,8 @@ @LayoutRes private final int mLayout; - public TileRenderer(Context context, @TileWithTextView.Style int style, int titleLines, - ImageFetcher imageFetcher) { + public TileRenderer( + Context context, @TileStyle int style, int titleLines, ImageFetcher imageFetcher) { mImageFetcher = imageFetcher; mStyle = style; mTitleLinesCount = titleLines; @@ -133,7 +133,7 @@ SuggestionsTileView tileView = (SuggestionsTileView) LayoutInflater.from(parentView.getContext()) .inflate(mLayout, parentView, false); - tileView.initialize(tile, mTitleLinesCount, mStyle); + tileView.initialize(tile, mTitleLinesCount); // Note: It is important that the callbacks below don't keep a reference to the tile or // modify them as there is no guarantee that the same tile would be used to update the view. @@ -206,9 +206,9 @@ @LayoutRes private int getLayout() { switch (mStyle) { - case TileWithTextView.Style.MODERN: + case TileStyle.MODERN: return R.layout.suggestions_tile_view; - case TileWithTextView.Style.MODERN_CONDENSED: + case TileStyle.MODERN_CONDENSED: return R.layout.suggestions_tile_view_condensed; } assert false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index af08a45..0019d5b5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -148,6 +148,9 @@ private static final ActionEvent ACCELERATOR_BUTTON_TAP_ACTION = new ActionEvent("MobileToolbarOmniboxAcceleratorTap"); + /** The amount of time to show the Duet help bubble for. */ + private static final int DUET_IPH_BUBBLE_SHOW_DURATION_MS = 6000; + /** * The number of ms to wait before reporting to UMA omnibox interaction metrics. */ @@ -947,7 +950,7 @@ R.string.iph_duet_icons_moved, R.string.iph_duet_icons_moved, true, new ViewRectProvider(mToolbar)); } - bubble.setDismissOnTouchInteraction(true); + bubble.setAutoDismissTimeout(DUET_IPH_BUBBLE_SHOW_DURATION_MS); bubble.addOnDismissListener( () -> tracker.dismissed(FeatureConstants.CHROME_DUET_FEATURE)); bubble.show();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java index 396dab2..dab6166 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -261,9 +261,6 @@ /** Whether or not scroll events are currently being blocked for the 'velocity' swipe logic. */ private boolean mVelocityLogicBlockSwipe; - /** Whether or not the slim peek UI should be used for the current sheet content. */ - private boolean mUseSlimPeek; - /** * An interface defining content that can be displayed inside of the bottom sheet for Chrome * Home. @@ -312,11 +309,6 @@ boolean isPeekStateEnabled(); /** - * @return Whether a slimmer peek UI should be used for this content. - */ - boolean useSlimPeek(); - - /** * @return The resource id of the content description for the bottom sheet. This is * generally the name of the feature/content that is showing. 'Swipe down to close.' * will be automatically appended after the content description. @@ -802,9 +794,6 @@ // If the desired content is already showing, do nothing. if (mSheetContent == content) return; - // TODO(twellington): Handle updates to the peek UI while the sheet is showing? - if (content != null && mUseSlimPeek != content.useSlimPeek()) updatePeekUI(content); - List<Animator> animators = new ArrayList<>(); mContentSwapAnimatorSet = new AnimatorSet(); mContentSwapAnimatorSet.addListener(new AnimatorListenerAdapter() { @@ -875,24 +864,6 @@ } /** - * Updates the peek UI for the current BottomSheetcontent. - * @param content The current {@link BottomSheetContent} - */ - private void updatePeekUI(BottomSheetContent content) { - mUseSlimPeek = content.useSlimPeek(); - - int peekHeightId = mUseSlimPeek ? R.dimen.bottom_control_container_slim_expanded_height - : R.dimen.bottom_control_container_peek_height; - mDefaultToolbarView.getLayoutParams().height = - getResources().getDimensionPixelSize(peekHeightId); - - int toolbarHeightId = mUseSlimPeek ? R.dimen.bottom_control_container_slim_peek_height - : R.dimen.bottom_control_container_peek_height; - mToolbarHeight = getResources().getDimensionPixelSize(toolbarHeightId); - updateSheetStateRatios(); - } - - /** * Called when the animation to swap BottomSheetContent ends. * @param content The BottomSheetContent showing at the end of the animation. */ @@ -1022,8 +993,12 @@ mPersistentControlsToken); for (BottomSheetObserver o : mObservers) o.onSheetClosed(reason); - announceForAccessibility(getResources().getString( - getCurrentSheetContent().getSheetClosedAccessibilityStringId())); + // If the sheet contents are cleared out before #onSheetClosed is called, do not try to + // retrieve the accessibility string. + if (getCurrentSheetContent() != null) { + announceForAccessibility(getResources().getString( + getCurrentSheetContent().getSheetClosedAccessibilityStringId())); + } clearFocus(); mActivity.removeViewObscuringAllTabs(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java index d6fea41..83d50f5c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java
@@ -6,7 +6,6 @@ import android.content.Context; import android.graphics.drawable.Drawable; -import android.support.annotation.IntDef; import android.util.AttributeSet; import android.widget.FrameLayout; import android.widget.ImageView; @@ -14,22 +13,12 @@ import org.chromium.chrome.R; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - /** * The view for a tile with icon and text. * * Displays the title of the site beneath a large icon. */ public class TileWithTextView extends FrameLayout { - @IntDef({Style.MODERN, Style.MODERN_CONDENSED}) - @Retention(RetentionPolicy.SOURCE) - public @interface Style { - int MODERN = 1; - int MODERN_CONDENSED = 2; - } - private TextView mTitleView; private ImageView mBadgeView; protected ImageView mIconView; @@ -54,14 +43,11 @@ * Initializes the view. This should be called immediately after inflation. * * @param title The title of the tile. - * @param url The url of the tile. * @param showOfflineBadge Whether to show the offline badge. * @param icon The icon to display on the tile. * @param titleLines The number of text lines to use for the tile title. - * @param tileStyle The visual style of the tile. */ - public void initialize(String title, String url, boolean showOfflineBadge, Drawable icon, - int titleLines, @Style int tileStyle) { + public void initialize(String title, boolean showOfflineBadge, Drawable icon, int titleLines) { mTitleView.setLines(titleLines); mTitleView.setText(title); setOfflineBadgeVisibility(showOfflineBadge);
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 7197758..458f0a4 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -567,8 +567,10 @@ "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java", "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardViewHolderFactory.java", "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTile.java", + "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java", "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java", "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageLayout.java", + "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java", "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSite.java", "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java", "java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java index 42443ef3..3f3c8cb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java
@@ -83,11 +83,6 @@ } @Override - public boolean useSlimPeek() { - return false; - } - - @Override public int getSheetContentDescriptionStringId() { return R.string.contextual_suggestions_button_description; }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java index 9c6e4f4a..740e0fd 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java
@@ -46,8 +46,8 @@ import org.chromium.chrome.browser.native_page.ContextMenuManager; import org.chromium.chrome.browser.ntp.cards.CardsVariationParameters; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; +import org.chromium.chrome.browser.suggestions.SuggestionsConfig.TileStyle; import org.chromium.chrome.browser.widget.displaystyle.UiConfig; -import org.chromium.chrome.browser.widget.tile.TileWithTextView.Style; import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.suggestions.FakeMostVisitedSites; @@ -84,7 +84,7 @@ mImageFetcher = new FakeImageFetcher(); mTileRenderer = new TileRenderer( - RuntimeEnvironment.application, Style.MODERN, TILE_TITLE_LINES, mImageFetcher); + RuntimeEnvironment.application, TileStyle.MODERN, TILE_TITLE_LINES, mImageFetcher); mMostVisitedSites = new FakeMostVisitedSites(); doAnswer(invocation -> {
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index b4875eb..aee74e1 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -4145,7 +4145,7 @@ Place your finger </message> <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION" desc="The label that explains the location of the fingerprint sensor on the device."> - Touch the sensor with your index finger. It's on the top left of your Chromebook. + Touch the sensor with your finger. It's on the edge of your Chromebook. </message> <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_ENROLLMENT_PROGRESS_TITLE" desc="The title of the dialog that shows where the fingerprint sensor is."> Lift, then touch again @@ -4184,7 +4184,7 @@ Finger 3 </message> <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER" desc="Text in the fingerprint setup screen telling users what to move finger to capture the different parts of fingerprint."> - Move your index finger slightly to add the different parts of your fingerprint. + Move your finger slightly to add the different parts of your fingerprint. </message> <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_TRY_AGAIN" desc="Text in the fingerprint setup screen telling users what to scan their finger again."> Try again.
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1 index 5830e6f7..4e1bc54 100644 --- a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1 +++ b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1
@@ -1 +1 @@ -53b1e6993c638b4395accfbf4fb34a0d5cb943d2 \ No newline at end of file +0aa420cbdd6f271aa13288688e3fe83347f649b2 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1 index a6df5e7..4e1bc54 100644 --- a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1 +++ b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1
@@ -1 +1 @@ -9d151e643bd4a4a6c1ff3ef6fb84b0ad6da02fc8 \ No newline at end of file +0aa420cbdd6f271aa13288688e3fe83347f649b2 \ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 59fe934..49e9cf3 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -4793,7 +4793,7 @@ <message name="IDS_NTP_CONFIRM_MSG_RESTORE_DEFAULTS" desc="The text label of the restore default shortcuts button when editing a custom link. (On the New Tab Page)"> Restore default shortcuts </message> - <message name="IDS_NTP_CUSTOM_BG_CUSTOMIZE_BACKGROUND" desc="The title for the tooltip for background customization. (On the New Tab Page)"> + <message name="IDS_NTP_CUSTOM_BG_CUSTOMIZE_BACKGROUND" desc="The title and aria-label for the tooltip for background customization. (On the New Tab Page)"> Customize this page </message> <message name="IDS_NTP_CUSTOM_BG_GOOGLE_PHOTOS" desc="The text label of the Google Photos option for background customization. (On the New Tab Page)">
diff --git a/chrome/app/nibs/Toolbar.xib b/chrome/app/nibs/Toolbar.xib index 5e2eb5d..bc6c940 100644 --- a/chrome/app/nibs/Toolbar.xib +++ b/chrome/app/nibs/Toolbar.xib
@@ -76,10 +76,10 @@ <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="155"/> </connections> </button> - <textField focusRingType="exterior" verticalHuggingPriority="750" tag="33004" id="4" customClass="AutocompleteTextField"> + <textField focusRingType="exterior" verticalHuggingPriority="750" tag="33004" id="4"> <rect key="frame" x="119" y="4" width="454" height="29"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="exterior" alignment="left" drawsBackground="YES" id="13" customClass="AutocompleteTextFieldCell"> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="exterior" alignment="left" drawsBackground="YES" id="13"> <font key="font" metaFont="system"/> <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
diff --git a/chrome/app/theme/default_100_percent/legacy/download_animation_begin.png b/chrome/app/theme/default_100_percent/legacy/download_animation_begin.png deleted file mode 100644 index 0343b14..0000000 --- a/chrome/app/theme/default_100_percent/legacy/download_animation_begin.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/legacy/download_animation_begin.png b/chrome/app/theme/default_200_percent/legacy/download_animation_begin.png deleted file mode 100644 index 91ea7595..0000000 --- a/chrome/app/theme/default_200_percent/legacy/download_animation_begin.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 048ce1c..d01bf93 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -96,9 +96,6 @@ <structure type="chrome_scaled_image" name="IDR_DEVICE_DISABLED" file="cros/device_disabled.png" /> </if> <structure type="chrome_scaled_image" name="IDR_DOWNLOADS_FAVICON" file="common/favicon_downloads.png" /> - <if expr="is_macosx"> - <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_ANIMATION_BEGIN" file="legacy/download_animation_begin.png" /> - </if> <if expr="chromeos"> <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_ANNOTATE" file="cros/downloads/annotate.png" /> <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_CANCEL" file="cros/downloads/cancel.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 854dc50..baf8b49 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1319,6 +1319,8 @@ "resource_coordinator/browser_child_process_watcher.h", "resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc", "resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h", + "resource_coordinator/discard_before_unload_helper.cc", + "resource_coordinator/discard_before_unload_helper.h", "resource_coordinator/exponential_moving_average.cc", "resource_coordinator/exponential_moving_average.h", "resource_coordinator/page_signal_receiver.cc", @@ -1538,6 +1540,8 @@ "sync/model_type_store_service_factory.h", "sync/profile_sync_service_factory.cc", "sync/profile_sync_service_factory.h", + "sync/session_sync_service_factory.cc", + "sync/session_sync_service_factory.h", "sync/sessions/sync_sessions_router_tab_helper.cc", "sync/sessions/sync_sessions_router_tab_helper.h", "sync/sessions/sync_sessions_web_contents_router.cc",
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc index cf8af34..a305a01 100644 --- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc +++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -21,6 +21,7 @@ #include "ui/android/resources/resource_manager_impl.h" #include "ui/android/view_android.h" #include "ui/gfx/android/java_bitmap.h" +#include "ui/gfx/geometry/size_conversions.h" using base::android::JavaParamRef; using base::android::JavaRef; @@ -33,12 +34,18 @@ : SceneLayer(env, jobj), env_(env), object_(jobj), - base_page_brightness_(1.0f), + color_overlay_(cc::SolidColorLayer::Create()), content_container_(cc::Layer::Create()) { // Responsible for moving the base page without modifying the layer itself. content_container_->SetIsDrawable(true); content_container_->SetPosition(gfx::PointF(0.0f, 0.0f)); layer()->AddChild(content_container_); + + color_overlay_->SetIsDrawable(true); + color_overlay_->SetOpacity(0.0f); + color_overlay_->SetBackgroundColor(SK_ColorBLACK); + color_overlay_->SetPosition(gfx::PointF(0.f, 0.f)); + layer()->AddChild(color_overlay_); } void ContextualSearchSceneLayer::CreateContextualSearchLayer( @@ -76,6 +83,8 @@ jint bar_banner_ripple_resource_id, jint bar_banner_text_resource_id, jfloat dp_to_px, + jfloat layout_width, + jfloat layout_height, jfloat base_page_brightness, jfloat base_page_offset, const JavaParamRef<jobject>& jweb_contents, @@ -143,15 +152,9 @@ web_contents ? web_contents->GetNativeView()->GetLayer() : nullptr; // Fade the base page out. - if (base_page_brightness_ != base_page_brightness) { - base_page_brightness_ = base_page_brightness; - cc::FilterOperations filters; - if (base_page_brightness < 1.f) { - filters.Append( - cc::FilterOperation::CreateBrightnessFilter(base_page_brightness)); - } - content_container_->SetFilters(filters); - } + color_overlay_->SetOpacity(1.f - base_page_brightness); + color_overlay_->SetBounds( + gfx::ToCeiledSize(gfx::SizeF(layout_width, layout_height))); // Move the base page contents up. content_container_->SetPosition(gfx::PointF(0.0f, base_page_offset)); @@ -236,9 +239,7 @@ contextual_search_layer_->layer()->SetHideLayerAndSubtree(true); } // Reset base page brightness. - cc::FilterOperations filters; - filters.Append(cc::FilterOperation::CreateBrightnessFilter(1.0f)); - content_container_->SetFilters(filters); + color_overlay_->SetOpacity(0.f); // Reset base page offset. content_container_->SetPosition(gfx::PointF(0.0f, 0.0f)); }
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h index b1ead56b..0d0ec1b1 100644 --- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h +++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
@@ -17,6 +17,7 @@ namespace cc { class Layer; +class SolidColorLayer; } namespace android { @@ -53,6 +54,8 @@ jint bar_banner_ripple_resource_id, jint bar_banner_text_resource_id, jfloat dp_to_px, + jfloat layout_width, + jfloat layout_height, jfloat base_page_brightness, jfloat base_page_offset, const base::android::JavaParamRef<jobject>& jweb_contents, @@ -122,11 +125,12 @@ JNIEnv* env_; base::android::ScopedJavaGlobalRef<jobject> object_; - float base_page_brightness_; std::string thumbnail_url_; std::unique_ptr<BitmapFetcher> fetcher_; scoped_refptr<ContextualSearchLayer> contextual_search_layer_; + // Responsible for fading the base page content. + scoped_refptr<cc::SolidColorLayer> color_overlay_; scoped_refptr<cc::Layer> content_container_; DISALLOW_COPY_AND_ASSIGN(ContextualSearchSceneLayer);
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc index 89c947e1..ec5af60 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
@@ -36,7 +36,8 @@ #include "content/public/browser/web_contents.h" #include "net/base/escape.h" #include "net/http/http_status_code.h" -#include "net/url_request/url_fetcher.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" #include "url/gurl.h" using content::RenderFrameHost; @@ -73,20 +74,19 @@ // The version of the Contextual Cards API that we want to invoke. const int kContextualCardsUrlActions = 3; -} // namespace +const int kResponseCodeUninitialized = -1; -// URLFetcher ID, only used for tests: we only have one kind of fetcher. -const int ContextualSearchDelegate::kContextualSearchURLFetcherID = 1; +} // namespace // Handles tasks for the ContextualSearchManager in a separable, testable way. ContextualSearchDelegate::ContextualSearchDelegate( - net::URLRequestContextGetter* url_request_context, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, TemplateURLService* template_url_service, const ContextualSearchDelegate::SearchTermResolutionCallback& search_term_callback, const ContextualSearchDelegate::SurroundingTextCallback& surrounding_text_callback) - : url_request_context_(url_request_context), + : url_loader_factory_(std::move(url_loader_factory)), template_url_service_(template_url_service), search_term_callback_(search_term_callback), surrounding_text_callback_(surrounding_text_callback) { @@ -132,7 +132,7 @@ // Immediately cancel any request that's in flight, since we're building a new // context (and the response disposes of any existing context). - search_term_fetcher_.reset(); + url_loader_.reset(); // Decide if the URL should be sent with the context. GURL page_url(web_contents->GetURL()); @@ -149,47 +149,47 @@ GURL request_url(BuildRequestUrl(context_->GetHomeCountry())); DCHECK(request_url.is_valid()); - // Reset will delete any previous fetcher, and we won't get any callback. - search_term_fetcher_.reset( - net::URLFetcher::Create(kContextualSearchURLFetcherID, request_url, - net::URLFetcher::GET, this).release()); - search_term_fetcher_->SetRequestContext(url_request_context_); + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = request_url; - // Add Chrome experiment state to the request headers. - net::HttpRequestHeaders headers; - variations::AppendVariationHeadersUnknownSignedIn( - search_term_fetcher_->GetOriginalURL(), - variations::InIncognito::kNo, // Impossible to be incognito at this - // point. - &headers); - search_term_fetcher_->SetExtraRequestHeaders(headers.ToString()); - - SetDiscourseContextAndAddToHeader(*context_); + // Populates the discourse context and adds it to the HTTP header of the + // search term resolution request. + resource_request->headers.AddHeadersFromString( + GetDiscourseContext(*context_)); // Disable cookies for this request. - search_term_fetcher_->SetAllowCredentials(false); + resource_request->allow_credentials = false; - search_term_fetcher_->Start(); + // Add Chrome experiment state to the request headers. + // Reset will delete any previous loader, and we won't get any callback. + url_loader_ = + variations::CreateSimpleURLLoaderWithVariationsHeadersUnknownSignedIn( + std::move(resource_request), + variations::InIncognito::kNo, // Impossible to be incognito at this + // point. + NO_TRAFFIC_ANNOTATION_YET); + + url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + url_loader_factory_.get(), + base::BindOnce(&ContextualSearchDelegate::OnUrlLoadComplete, + base::Unretained(this))); } -void ContextualSearchDelegate::OnURLFetchComplete( - const net::URLFetcher* source) { - if (context_ == nullptr) +void ContextualSearchDelegate::OnUrlLoadComplete( + std::unique_ptr<std::string> response_body) { + if (!context_) return; - DCHECK(source == search_term_fetcher_.get()); - int response_code = source->GetResponseCode(); + int response_code = kResponseCodeUninitialized; + if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) { + response_code = url_loader_->ResponseInfo()->headers->response_code(); + } std::unique_ptr<ResolvedSearchTerm> resolved_search_term( new ResolvedSearchTerm(response_code)); - if (source->GetStatus().is_success() && response_code == net::HTTP_OK) { - std::string response; - bool has_string_response = source->GetResponseAsString(&response); - DCHECK(has_string_response); - if (has_string_response && context_ != nullptr) { - resolved_search_term = - GetResolvedSearchTermFromJson(response_code, response); - } + if (response_body && response_code == net::HTTP_OK) { + resolved_search_term = + GetResolvedSearchTermFromJson(response_code, *response_body); } search_term_callback_.Run(*resolved_search_term); } @@ -234,7 +234,7 @@ end_adjust = mention_end - context_->GetEndOffset(); } } - bool is_invalid = response_code == net::URLFetcher::RESPONSE_CODE_INVALID; + bool is_invalid = response_code == kResponseCodeUninitialized; return std::unique_ptr<ResolvedSearchTerm>(new ResolvedSearchTerm( is_invalid, response_code, search_term, display_text, alternate_term, mid, prevent_preload == kDoPreventPreloadValue, start_adjust, end_adjust, @@ -325,11 +325,6 @@ selection_end); } -void ContextualSearchDelegate::SetDiscourseContextAndAddToHeader( - const ContextualSearchContext& context) { - search_term_fetcher_->AddExtraRequestHeader(GetDiscourseContext(context)); -} - std::string ContextualSearchDelegate::GetDiscourseContext( const ContextualSearchContext& context) { discourse_context::ClientDiscourseContext proto;
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.h b/chrome/browser/android/contextualsearch/contextual_search_delegate.h index f18bc89..55c2050 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.h +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
@@ -17,15 +17,15 @@ #include "base/values.h" #include "chrome/browser/android/contextualsearch/contextual_search_context.h" #include "chrome/browser/android/contextualsearch/resolved_search_term.h" -#include "net/url_request/url_fetcher_delegate.h" namespace content { class WebContents; } -namespace net { -class URLRequestContextGetter; -} // namespace net +namespace network { +class SharedURLLoaderFactory; +class SimpleURLLoader; +} // namespace network class Profile; class TemplateURLService; @@ -34,8 +34,7 @@ // Handles tasks for the ContextualSearchManager in a separable and testable // way, without the complication of being connected to a Java object. class ContextualSearchDelegate - : public net::URLFetcherDelegate, - public base::SupportsWeakPtr<ContextualSearchDelegate> { + : public base::SupportsWeakPtr<ContextualSearchDelegate> { public: // Provides the Resolved Search Term, called when the Resolve Request returns. typedef base::Callback<void(const ResolvedSearchTerm&)> @@ -45,17 +44,14 @@ void(const std::string&, const base::string16&, size_t, size_t)> SurroundingTextCallback; - // ID used in creating URLFetcher for Contextual Search results. - static const int kContextualSearchURLFetcherID; - // Constructs a delegate that will always call back to the given callbacks // when search term resolution or surrounding text responses are available. ContextualSearchDelegate( - net::URLRequestContextGetter* url_request_context, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, TemplateURLService* template_url_service, const SearchTermResolutionCallback& search_term_callback, const SurroundingTextCallback& surrounding_callback); - ~ContextualSearchDelegate() override; + virtual ~ContextualSearchDelegate(); // Gathers surrounding text and saves it locally in the given context. void GatherAndSaveSurroundingText( @@ -101,8 +97,7 @@ FRIEND_TEST_ALL_PREFIXES(ContextualSearchDelegateTest, DecodeSearchTermFromJsonResponse); - // net::URLFetcherDelegate: - void OnURLFetchComplete(const net::URLFetcher* source) override; + void OnUrlLoadComplete(std::unique_ptr<std::string> response_body); // Resolves the search term specified by the current context. // Only needed for tests. TODO(donnd): make private and friend? @@ -124,11 +119,6 @@ int start_offset, int end_offset); - // Populates the discourse context and adds it to the HTTP header of the - // search term resolution request. - void SetDiscourseContextAndAddToHeader( - const ContextualSearchContext& context); - // Populates and returns the discourse context. std::string GetDiscourseContext(const ContextualSearchContext& context); @@ -191,10 +181,10 @@ } // The current request in progress, or NULL. - std::unique_ptr<net::URLFetcher> search_term_fetcher_; + std::unique_ptr<network::SimpleURLLoader> url_loader_; - // Holds the URL request context. Not owned. - net::URLRequestContextGetter* url_request_context_; + // Holds the URL loader factory. + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; // Holds the TemplateURLService. Not owned. TemplateURLService* template_url_service_;
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc index 283c9d7..b405d9860 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
@@ -22,8 +22,8 @@ #include "chrome/common/chrome_switches.h" #include "components/search_engines/template_url_service.h" #include "net/base/escape.h" -#include "net/url_request/test_url_fetcher_factory.h" -#include "net/url_request/url_request_test_util.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" using base::ListValue; @@ -42,11 +42,12 @@ protected: void SetUp() override { - request_context_ = - new net::TestURLRequestContextGetter(io_message_loop_.task_runner()); + test_shared_url_loader_factory_ = + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_); template_url_service_.reset(CreateTemplateURLService()); delegate_.reset(new ContextualSearchDelegate( - request_context_.get(), template_url_service_.get(), + test_shared_url_loader_factory_, template_url_service_.get(), base::Bind( &ContextualSearchDelegateTest::recordSearchTermResolutionResponse, base::Unretained(this)), @@ -56,7 +57,6 @@ } void TearDown() override { - fetcher_ = NULL; is_invalid_ = true; response_code_ = -1; search_term_ = "invalid"; @@ -96,10 +96,7 @@ test_context_->SetSelectionSurroundings(start_offset, end_offset, surrounding_text); delegate_->ResolveSearchTermFromContext(); - fetcher_ = test_factory_.GetFetcherByID( - ContextualSearchDelegate::kContextualSearchURLFetcherID); - ASSERT_TRUE(fetcher_); - ASSERT_TRUE(fetcher()); + ASSERT_TRUE(test_url_loader_factory_.GetPendingRequest(0)); } // Allows using the vertical bar "|" as a quote character, which makes @@ -113,11 +110,9 @@ void CreateDefaultSearchWithAdditionalJsonData( const std::string additional_json_data) { CreateDefaultSearchContextAndRequestSearchTerm(); - fetcher()->set_response_code(200); std::string response = escapeBarQuoted("{|search_term|:|obama|" + additional_json_data + "}"); - fetcher()->SetResponseString(response); - fetcher()->delegate()->OnURLFetchComplete(fetcher()); + SimulateResponseReturned(response); EXPECT_FALSE(is_invalid()); EXPECT_EQ(200, response_code()); @@ -144,30 +139,29 @@ delegate_->OnTextSurroundingSelectionAvailable(base::string16(), 1, 2); } - // Call the OnURLFetchComplete to simulate the end of a Resolve request. - // Cannot be in an actual test because OnTextSurroundingSelectionAvailable - // is private. - void CallOnURLFetchComplete() { - delegate_->OnURLFetchComplete(delegate_->search_term_fetcher_.get()); - } - void CallResolveSearchTermFromContext() { delegate_->ResolveSearchTermFromContext(); } - void SetResponseStringAndFetch(const std::string& selected_text, - const std::string& mentions_start, - const std::string& mentions_end) { - fetcher()->set_response_code(200); - fetcher()->SetResponseString( - ")]}'\n" - "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\"," - "\"info_text\":\"44th U.S. President\"," - "\"display_text\":\"Barack Obama\"," - "\"mentions\":[" + mentions_start + ","+ mentions_end + "]," - "\"selected_text\":\"" + selected_text + "\"," - "\"resolved_term\":\"barack obama\"}"); - fetcher()->delegate()->OnURLFetchComplete(fetcher()); + void SetResponseStringAndSimulateResponse(const std::string& selected_text, + const std::string& mentions_start, + const std::string& mentions_end) { + std::string response = std::string( + ")]}'\n" + "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\"," + "\"info_text\":\"44th U.S. President\"," + "\"display_text\":\"Barack Obama\"," + "\"mentions\":[" + mentions_start + "," + mentions_end + "]," + "\"selected_text\":\"" + selected_text + "\"," + "\"resolved_term\":\"barack obama\"}"); + SimulateResponseReturned(response); + } + + void SimulateResponseReturned(const std::string& response) { + auto* pending_request = test_url_loader_factory_.GetPendingRequest(0); + test_url_loader_factory_.SimulateResponseForPendingRequest( + pending_request->request.url.spec(), response); + base::RunLoop().RunUntilIdle(); } void SetSurroundingContext(const base::string16& surrounding_text, @@ -184,13 +178,13 @@ // Gets the Client Discourse Context proto from the request header. discourse_context::ClientDiscourseContext GetDiscourseContextFromRequest() { discourse_context::ClientDiscourseContext cdc; - // Make sure we can get the actual raw headers from the fake fetcher. - net::HttpRequestHeaders fetch_headers; - fetcher()->GetExtraRequestHeaders(&fetch_headers); - if (fetch_headers.HasHeader(kDiscourseContextHeaderName)) { + // Make sure we can get the actual raw headers from the url loader. + auto* pending_request = test_url_loader_factory_.GetPendingRequest(0); + net::HttpRequestHeaders request_headers = pending_request->request.headers; + if (request_headers.HasHeader(kDiscourseContextHeaderName)) { std::string actual_header_value; - fetch_headers.GetHeader(kDiscourseContextHeaderName, - &actual_header_value); + request_headers.GetHeader(kDiscourseContextHeaderName, + &actual_header_value); // Unescape, since the server memoizer expects a web-safe encoding. std::string unescaped_header = actual_header_value; @@ -218,7 +212,6 @@ return result; } - net::TestURLFetcher* fetcher() { return fetcher_; } bool is_invalid() { return is_invalid_; } int response_code() { return response_code_; } std::string search_term() { return search_term_; } @@ -235,6 +228,8 @@ // The delegate under test. std::unique_ptr<ContextualSearchDelegate> delegate_; + network::TestURLLoaderFactory test_url_loader_factory_; + private: void recordSearchTermResolutionResponse( const ResolvedSearchTerm& resolved_search_term) { @@ -273,10 +268,9 @@ std::string context_language_; base::MessageLoopForIO io_message_loop_; - net::TestURLFetcherFactory test_factory_; - net::TestURLFetcher* fetcher_; std::unique_ptr<TemplateURLService> template_url_service_; - scoped_refptr<net::TestURLRequestContextGetter> request_context_; + scoped_refptr<network::SharedURLLoaderFactory> + test_shared_url_loader_factory_; // Will be owned by the delegate. ContextualSearchContext* test_context_; @@ -286,14 +280,13 @@ TEST_F(ContextualSearchDelegateTest, NormalFetchWithXssiEscape) { CreateDefaultSearchContextAndRequestSearchTerm(); - fetcher()->set_response_code(200); - fetcher()->SetResponseString( + std::string response( ")]}'\n" "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\"," "\"info_text\":\"44th U.S. President\"," "\"display_text\":\"Barack Obama\", \"mentions\":[0,15]," "\"selected_text\":\"obama\", \"resolved_term\":\"barack obama\"}"); - fetcher()->delegate()->OnURLFetchComplete(fetcher()); + SimulateResponseReturned(response); EXPECT_FALSE(is_invalid()); EXPECT_EQ(200, response_code()); @@ -305,13 +298,12 @@ TEST_F(ContextualSearchDelegateTest, NormalFetchWithoutXssiEscape) { CreateDefaultSearchContextAndRequestSearchTerm(); - fetcher()->set_response_code(200); - fetcher()->SetResponseString( + std::string response( "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\"," "\"info_text\":\"44th U.S. President\"," "\"display_text\":\"Barack Obama\", \"mentions\":[0,15]," "\"selected_text\":\"obama\", \"resolved_term\":\"barack obama\"}"); - fetcher()->delegate()->OnURLFetchComplete(fetcher()); + SimulateResponseReturned(response); EXPECT_FALSE(is_invalid()); EXPECT_EQ(200, response_code()); @@ -323,11 +315,10 @@ TEST_F(ContextualSearchDelegateTest, ResponseWithNoDisplayText) { CreateDefaultSearchContextAndRequestSearchTerm(); - fetcher()->set_response_code(200); - fetcher()->SetResponseString( + std::string response( "{\"mid\":\"/m/02mjmr\",\"search_term\":\"obama\"," "\"mentions\":[0,15]}"); - fetcher()->delegate()->OnURLFetchComplete(fetcher()); + SimulateResponseReturned(response); EXPECT_FALSE(is_invalid()); EXPECT_EQ(200, response_code()); @@ -339,11 +330,10 @@ TEST_F(ContextualSearchDelegateTest, ResponseWithPreventPreload) { CreateDefaultSearchContextAndRequestSearchTerm(); - fetcher()->set_response_code(200); - fetcher()->SetResponseString( + std::string response( "{\"mid\":\"/m/02mjmr\",\"search_term\":\"obama\"," "\"mentions\":[0,15],\"prevent_preload\":\"1\"}"); - fetcher()->delegate()->OnURLFetchComplete(fetcher()); + SimulateResponseReturned(response); EXPECT_FALSE(is_invalid()); EXPECT_EQ(200, response_code()); @@ -355,9 +345,8 @@ TEST_F(ContextualSearchDelegateTest, NonJsonResponse) { CreateDefaultSearchContextAndRequestSearchTerm(); - fetcher()->set_response_code(200); - fetcher()->SetResponseString("Non-JSON Response"); - fetcher()->delegate()->OnURLFetchComplete(fetcher()); + std::string response("Non-JSON Response"); + SimulateResponseReturned(response); EXPECT_FALSE(is_invalid()); EXPECT_EQ(200, response_code()); @@ -369,8 +358,11 @@ TEST_F(ContextualSearchDelegateTest, InvalidResponse) { CreateDefaultSearchContextAndRequestSearchTerm(); - fetcher()->set_response_code(net::URLFetcher::RESPONSE_CODE_INVALID); - fetcher()->delegate()->OnURLFetchComplete(fetcher()); + auto* pending_request = test_url_loader_factory_.GetPendingRequest(0); + test_url_loader_factory_.SimulateResponseForPendingRequest( + pending_request->request.url, network::URLLoaderCompletionStatus(net::OK), + network::ResourceResponseHead(), std::string()); + base::RunLoop().RunUntilIdle(); EXPECT_FALSE(do_prevent_preload()); EXPECT_TRUE(is_invalid()); @@ -380,7 +372,7 @@ base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke."); std::string selected_text = "Barack"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 6); - SetResponseStringAndFetch(selected_text, "0", "12"); + SetResponseStringAndSimulateResponse(selected_text, "0", "12"); EXPECT_EQ(0, start_adjust()); EXPECT_EQ(6, end_adjust()); @@ -390,7 +382,7 @@ base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke."); std::string selected_text = "Obama"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 7, 12); - SetResponseStringAndFetch(selected_text, "0", "12"); + SetResponseStringAndSimulateResponse(selected_text, "0", "12"); EXPECT_EQ(-7, start_adjust()); EXPECT_EQ(0, end_adjust()); @@ -400,7 +392,7 @@ base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke."); std::string selected_text = "Ob"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 7, 9); - SetResponseStringAndFetch(selected_text, "0", "12"); + SetResponseStringAndSimulateResponse(selected_text, "0", "12"); EXPECT_EQ(-7, start_adjust()); EXPECT_EQ(3, end_adjust()); @@ -410,7 +402,7 @@ base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke."); std::string selected_text = "Ob"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 7, 9); - SetResponseStringAndFetch(selected_text, "0", "200"); + SetResponseStringAndSimulateResponse(selected_text, "0", "200"); EXPECT_EQ(0, start_adjust()); EXPECT_EQ(0, end_adjust()); @@ -421,7 +413,7 @@ std::string selected_text = "Ob"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0xffffffff, 0xffffffff - 2); - SetResponseStringAndFetch(selected_text, "0", "12"); + SetResponseStringAndSimulateResponse(selected_text, "0", "12"); EXPECT_EQ(0, start_adjust()); EXPECT_EQ(0, end_adjust()); @@ -431,7 +423,7 @@ base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke."); std::string selected_text = "Ob"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 12); - SetResponseStringAndFetch(selected_text, "12", "14"); + SetResponseStringAndSimulateResponse(selected_text, "12", "14"); EXPECT_EQ(0, start_adjust()); EXPECT_EQ(0, end_adjust()); @@ -442,7 +434,7 @@ std::string selected_text = "Ob"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0xffffffff, 0xffffffff - 2); - SetResponseStringAndFetch(selected_text, "0", "268435455"); + SetResponseStringAndSimulateResponse(selected_text, "0", "268435455"); EXPECT_EQ(0, start_adjust()); EXPECT_EQ(0, end_adjust()); @@ -453,7 +445,7 @@ std::string selected_text = "Ob"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 268435450, 268435455); - SetResponseStringAndFetch(selected_text, "268435440", "268435455"); + SetResponseStringAndSimulateResponse(selected_text, "268435440", "268435455"); EXPECT_EQ(-10, start_adjust()); EXPECT_EQ(0, end_adjust()); @@ -463,7 +455,7 @@ base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke."); std::string selected_text = "Barack Obama just"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 17); - SetResponseStringAndFetch(selected_text, "0", "12"); + SetResponseStringAndSimulateResponse(selected_text, "0", "12"); EXPECT_EQ(0, start_adjust()); EXPECT_EQ(-5, end_adjust()); @@ -473,7 +465,7 @@ base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke."); std::string selected_text = "Barack Obama just"; CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 17); - SetResponseStringAndFetch(selected_text, "5", "5"); + SetResponseStringAndSimulateResponse(selected_text, "5", "5"); EXPECT_EQ(0, start_adjust()); EXPECT_EQ(0, end_adjust()); @@ -568,12 +560,11 @@ TEST_F(ContextualSearchDelegateTest, ResponseWithLanguage) { CreateDefaultSearchContextAndRequestSearchTerm(); - fetcher()->set_response_code(200); - fetcher()->SetResponseString( + std::string response( "{\"mid\":\"/m/02mjmr\",\"search_term\":\"obama\"," "\"mentions\":[0,15],\"prevent_preload\":\"1\", " "\"lang\":\"de\"}"); - fetcher()->delegate()->OnURLFetchComplete(fetcher()); + SimulateResponseReturned(response); EXPECT_FALSE(is_invalid()); EXPECT_EQ(200, response_code()); @@ -616,7 +607,11 @@ CreateTestContext(); CallResolveSearchTermFromContext(); DestroyTestContext(); - CallOnURLFetchComplete(); + + std::string response("Any response as it does not matter here."); + SimulateResponseReturned(response); + + EXPECT_TRUE(is_invalid()); } // Test that we can destroy the context while gathering surrounding text.
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc index da9dd3d..1bc3e648 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -25,6 +25,7 @@ #include "content/public/browser/web_contents_observer.h" #include "jni/ContextualSearchManager_jni.h" #include "net/url_request/url_fetcher_impl.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/interface_provider.h" @@ -84,7 +85,7 @@ env, obj, reinterpret_cast<intptr_t>(this)); Profile* profile = ProfileManager::GetActiveUserProfile(); delegate_.reset(new ContextualSearchDelegate( - profile->GetRequestContext(), + profile->GetURLLoaderFactory(), TemplateURLServiceFactory::GetForProfile(profile), base::Bind(&ContextualSearchManager::OnSearchTermResolutionResponse, base::Unretained(this)),
diff --git a/chrome/browser/android/explore_sites/explore_sites_bridge.cc b/chrome/browser/android/explore_sites/explore_sites_bridge.cc index b259691..7da43f5 100644 --- a/chrome/browser/android/explore_sites/explore_sites_bridge.cc +++ b/chrome/browser/android/explore_sites/explore_sites_bridge.cc
@@ -9,6 +9,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" +#include "chrome/browser/android/explore_sites/explore_sites_feature.h" #include "chrome/browser/android/explore_sites/explore_sites_service.h" #include "chrome/browser/android/explore_sites/explore_sites_service_factory.h" #include "chrome/browser/android/explore_sites/explore_sites_types.h" @@ -75,4 +76,11 @@ ScopedJavaGlobalRef<jobject>(j_callback_obj))); } +// static +jint JNI_ExploreSitesBridge_GetVariation(JNIEnv* env, + const JavaParamRef<jclass>& j_caller) { + return static_cast<jint>( + chrome::android::explore_sites::GetExploreSitesVariation()); +} + } // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_feature.h b/chrome/browser/android/explore_sites/explore_sites_feature.h index 121815a4f..676f32c5 100644 --- a/chrome/browser/android/explore_sites/explore_sites_feature.h +++ b/chrome/browser/android/explore_sites/explore_sites_feature.h
@@ -13,6 +13,8 @@ extern const char kExploreSitesVariationExperimental[]; +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.explore_sites enum class ExploreSitesVariation { ENABLED, EXPERIMENT, DISABLED }; ExploreSitesVariation GetExploreSitesVariation();
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc index 5a75249a..f1b3952e 100644 --- a/chrome/browser/chromeos/arc/arc_util.cc +++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -20,7 +20,7 @@ #include "base/strings/string_util.h" #include "base/sys_info.h" #include "base/task/post_task.h" -#include "base/threading/thread_restrictions.h" +#include "base/threading/scoped_blocking_call.h" #include "chrome/browser/chromeos/arc/arc_session_manager.h" #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h" #include "chrome/browser/chromeos/login/demo_mode/demo_session.h" @@ -86,7 +86,7 @@ // Returns whether ARC can run on the filesystem mounted at |path|. // This function should run only on threads where IO operations are allowed. bool IsArcCompatibleFilesystem(const base::FilePath& path) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); // If it can be verified it is not on ecryptfs, then it is ok. struct statfs statfs_buf;
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc index 8ae48038..0f2c45c 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc +++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
@@ -11,7 +11,7 @@ #include "base/files/file.h" #include "base/task/post_task.h" -#include "base/threading/thread_restrictions.h" +#include "base/threading/scoped_blocking_call.h" #include "chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.h" #include "content/public/browser/browser_thread.h" #include "mojo/public/cpp/platform/platform_handle.h" @@ -32,7 +32,7 @@ // Seeks the file, returns 0 on success, or errno on an error. int SeekFile(base::File* file, size_t offset) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); // lseek() instead of |file|'s method for errno. off_t result = lseek(file->GetPlatformFile(), offset, SEEK_SET); return result < 0 ? errno : 0;
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc index e27c3623..6d4236c1 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc +++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -905,9 +905,9 @@ NOTREACHED(); return; } - linked_ptr<drive::FileChange> changes; + std::unique_ptr<drive::FileChange> changes; if (list) - changes.reset(new drive::FileChange(*list)); // Copy + changes = std::make_unique<drive::FileChange>(*list); // Copy for (size_t i = 0; i < extension_ids.size(); ++i) { std::string* extension_id = new std::string(extension_ids[i]); @@ -922,13 +922,13 @@ profile_, *extension_id, file_definition, base::BindOnce( &EventRouter::DispatchDirectoryChangeEventWithEntryDefinition, - weak_factory_.GetWeakPtr(), changes, base::Owned(extension_id), - got_error)); + weak_factory_.GetWeakPtr(), std::move(changes), + base::Owned(extension_id), got_error)); } } void EventRouter::DispatchDirectoryChangeEventWithEntryDefinition( - const linked_ptr<drive::FileChange> list, + std::unique_ptr<drive::FileChange> list, const std::string* extension_id, bool watcher_error, const EntryDefinition& entry_definition) { @@ -946,7 +946,7 @@ : file_manager_private::FILE_WATCH_EVENT_TYPE_CHANGED; // Detailed information is available. - if (list.get()) { + if (list) { event.changed_files = std::make_unique<std::vector<file_manager_private::FileChange>>();
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h index ab63ed2d..f18b2e7 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router.h +++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -180,7 +180,7 @@ // Sends directory change event, after converting the file definition to entry // definition. void DispatchDirectoryChangeEventWithEntryDefinition( - const linked_ptr<drive::FileChange> list, + std::unique_ptr<drive::FileChange> list, const std::string* extension_id, bool watcher_error, const EntryDefinition& entry_definition);
diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc index 2f33cbb..f44699b 100644 --- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc +++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
@@ -9,7 +9,6 @@ #include <memory> #include <utility> -#include "base/memory/ptr_util.h" #include "base/threading/thread_task_runner_handle.h" #include "components/services/filesystem/public/interfaces/types.mojom.h" #include "net/base/io_buffer.h" @@ -73,7 +72,7 @@ metadata->mime_type.reset(new std::string(mime_type)); entries_[entry_path] = - make_linked_ptr(new FakeEntry(std::move(metadata), contents)); + std::make_unique<FakeEntry>(std::move(metadata), contents); } const FakeEntry* FakeProvidedFileSystem::GetEntry( @@ -98,10 +97,8 @@ const Entries::const_iterator entry_it = entries_.find(entry_path); if (entry_it == entries_.end()) { - return PostAbortableTask( - base::BindOnce(std::move(callback), - base::Passed(base::WrapUnique<EntryMetadata>(NULL)), - base::File::FILE_ERROR_NOT_FOUND)); + return PostAbortableTask(base::BindOnce(std::move(callback), nullptr, + base::File::FILE_ERROR_NOT_FOUND)); } std::unique_ptr<EntryMetadata> metadata(new EntryMetadata);
diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h index 4d6921bc..70df78ae 100644 --- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h +++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h
@@ -8,13 +8,13 @@ #include <stdint.h> #include <map> +#include <memory> #include <string> #include <vector> #include "base/callback.h" #include "base/files/file.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/task/cancelable_task_tracker.h" @@ -163,7 +163,7 @@ base::WeakPtr<ProvidedFileSystemInterface> GetWeakPtr() override; private: - typedef std::map<base::FilePath, linked_ptr<FakeEntry>> Entries; + using Entries = std::map<base::FilePath, std::unique_ptr<FakeEntry>>; // Utility function for posting a task which can be aborted by calling the // returned callback.
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc index cc3c959d..42e5e3c 100644 --- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc +++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -393,10 +393,11 @@ UserImageManagerMap::iterator ui = user_image_managers_.find(account_id); if (ui != user_image_managers_.end()) return ui->second.get(); - linked_ptr<UserImageManagerImpl> mgr( - new UserImageManagerImpl(account_id.GetUserEmail(), this)); - user_image_managers_[account_id] = mgr; - return mgr.get(); + auto mgr = + std::make_unique<UserImageManagerImpl>(account_id.GetUserEmail(), this); + UserImageManagerImpl* mgr_raw = mgr.get(); + user_image_managers_[account_id] = std::move(mgr); + return mgr_raw; } SupervisedUserManager* ChromeUserManagerImpl::GetSupervisedUserManager() {
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h index 99929993..dbee25b 100644 --- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h +++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
@@ -12,7 +12,6 @@ #include <vector> #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/synchronization/lock.h" @@ -197,7 +196,8 @@ friend class WallpaperManager; friend class WallpaperManagerTest; - using UserImageManagerMap = std::map<AccountId, linked_ptr<UserImageManager>>; + using UserImageManagerMap = + std::map<AccountId, std::unique_ptr<UserImageManager>>; ChromeUserManagerImpl();
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 26296978..7773c32 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -1350,7 +1350,8 @@ return; // First remember how far have we reached so that we can resume if needed. - if (is_out_of_box_ && IsResumableScreen(current_screen_->screen_id())) { + if (is_out_of_box_ && !demo_setup_controller_ && + IsResumableScreen(current_screen_->screen_id())) { StartupUtils::SaveOobePendingScreen( GetOobeScreenName(current_screen_->screen_id())); }
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h index 834ab41..474fb71 100644 --- a/chrome/browser/chromeos/login/wizard_controller.h +++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -12,7 +12,6 @@ #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/optional.h"
diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc index 8b26041..7bd39fd 100644 --- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc +++ b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc
@@ -9,7 +9,6 @@ #include "base/containers/queue.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/run_loop.h" #include "base/test/scoped_path_override.h" #include "base/values.h" @@ -50,10 +49,10 @@ return; while (!set_requests_.empty()) { - SetRequest request = set_requests_.front(); + SetRequest request = std::move(set_requests_.front()); set_requests_.pop(); const base::Value* value = provider_->Get(request.first); - ASSERT_TRUE(request.second->Equals(value)); + ASSERT_EQ(request.second, *value); } loop_.Quit(); } @@ -61,8 +60,7 @@ bool Set(const std::string& setting, const base::Value& value) { if (!service_->Set(setting, value)) return false; - set_requests_.push( - SetRequest(setting, linked_ptr<base::Value>(value.DeepCopy()))); + set_requests_.push(SetRequest(setting, value.Clone())); return true; } @@ -73,7 +71,7 @@ DeviceSettingsProvider* provider_; base::RunLoop loop_; - using SetRequest = std::pair<std::string, linked_ptr<base::Value>>; + using SetRequest = std::pair<std::string, base::Value>; base::queue<SetRequest> set_requests_; DISALLOW_COPY_AND_ASSIGN(PrefsChecker);
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc index e7e57b2..02974f7 100644 --- a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc +++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
@@ -741,7 +741,7 @@ } void PlatformKeysService::StartOrQueueTask(std::unique_ptr<Task> task) { - tasks_.push(make_linked_ptr(task.release())); + tasks_.push(std::move(task)); if (tasks_.size() == 1) tasks_.front()->Start(); }
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.h b/chrome/browser/chromeos/platform_keys/platform_keys_service.h index b77be3d..17045fa 100644 --- a/chrome/browser/chromeos/platform_keys/platform_keys_service.h +++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
@@ -12,7 +12,6 @@ #include "base/callback_forward.h" #include "base/containers/queue.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/platform_keys/key_permissions.h" #include "chrome/browser/chromeos/platform_keys/platform_keys.h" @@ -205,7 +204,7 @@ content::BrowserContext* browser_context_; KeyPermissions key_permissions_; std::unique_ptr<SelectDelegate> select_delegate_; - base::queue<linked_ptr<Task>> tasks_; + base::queue<std::unique_ptr<Task>> tasks_; base::WeakPtrFactory<PlatformKeysService> weak_factory_; DISALLOW_COPY_AND_ASSIGN(PlatformKeysService);
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc index 778e91c..eb831deb 100644 --- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc +++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc
@@ -176,10 +176,8 @@ ProfilePolicyConnector* policy_connector = ProfilePolicyConnectorFactory::GetForBrowserContext(profile); - logged_in_user_observers_[user_id] = make_linked_ptr( - new PolicyServiceObserver(this, - user_id, - policy_connector->policy_service())); + logged_in_user_observers_[user_id] = std::make_unique<PolicyServiceObserver>( + this, user_id, policy_connector->policy_service()); } void CloudExternalDataPolicyObserver::OnPolicyUpdated( @@ -282,7 +280,7 @@ delegate_->OnExternalDataSet(policy_, user_id); - linked_ptr<WeakPtrFactory>& weak_ptr_factory = fetch_weak_ptrs_[user_id]; + std::unique_ptr<WeakPtrFactory>& weak_ptr_factory = fetch_weak_ptrs_[user_id]; weak_ptr_factory.reset(new WeakPtrFactory(this)); if (entry->external_data_fetcher) { entry->external_data_fetcher->Fetch(base::Bind(
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h index aef0b8d5..ef4467b8 100644 --- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h +++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h
@@ -11,7 +11,6 @@ #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h" #include "chrome/browser/chromeos/settings/cros_settings.h" @@ -100,8 +99,8 @@ // A map from each logged-in user to the helper that observes |policy_| in the // user's PolicyService. - typedef std::map<std::string, linked_ptr<PolicyServiceObserver>> - LoggedInUserObserverMap; + using LoggedInUserObserverMap = + std::map<std::string, std::unique_ptr<PolicyServiceObserver>>; LoggedInUserObserverMap logged_in_user_observers_; chromeos::CrosSettings* cros_settings_; @@ -120,7 +119,8 @@ // currently in progress. This allows fetches to be effectively be canceled by // invalidating the pointers. using WeakPtrFactory = base::WeakPtrFactory<CloudExternalDataPolicyObserver>; - using FetchWeakPtrMap = std::map<std::string, linked_ptr<WeakPtrFactory>>; + using FetchWeakPtrMap = + std::map<std::string, std::unique_ptr<WeakPtrFactory>>; FetchWeakPtrMap fetch_weak_ptrs_; base::WeakPtrFactory<CloudExternalDataPolicyObserver> weak_factory_;
diff --git a/chrome/browser/chromeos/settings/device_settings_service.cc b/chrome/browser/chromeos/settings/device_settings_service.cc index 4e2229e..278656b 100644 --- a/chrome/browser/chromeos/settings/device_settings_service.cc +++ b/chrome/browser/chromeos/settings/device_settings_service.cc
@@ -143,10 +143,10 @@ const base::Closure& callback) { // On Active Directory managed devices policy is written only by authpolicyd. CHECK(device_mode_ != policy::DEVICE_MODE_ENTERPRISE_AD); - Enqueue(linked_ptr<SessionManagerOperation>(new StoreSettingsOperation( + Enqueue(std::make_unique<StoreSettingsOperation>( base::Bind(&DeviceSettingsService::HandleCompletedAsyncOperation, weak_factory_.GetWeakPtr(), callback), - std::move(policy)))); + std::move(policy))); } DeviceSettingsService::OwnershipStatus @@ -243,9 +243,10 @@ } void DeviceSettingsService::Enqueue( - const linked_ptr<SessionManagerOperation>& operation) { - pending_operations_.push_back(operation); - if (pending_operations_.front().get() == operation.get()) + std::unique_ptr<SessionManagerOperation> operation) { + const bool was_empty = pending_operations_.empty(); + pending_operations_.push_back(std::move(operation)); + if (was_empty) StartNextOperation(); } @@ -255,11 +256,10 @@ request_key_load = false; cloud_validations = false; } - linked_ptr<SessionManagerOperation> operation(new LoadSettingsOperation( + Enqueue(std::make_unique<LoadSettingsOperation>( request_key_load, cloud_validations, false /*force_immediate_load*/, base::Bind(&DeviceSettingsService::HandleCompletedAsyncOperation, weak_factory_.GetWeakPtr(), base::Closure()))); - Enqueue(operation); } void DeviceSettingsService::EnsureReload(bool request_key_load) {
diff --git a/chrome/browser/chromeos/settings/device_settings_service.h b/chrome/browser/chromeos/settings/device_settings_service.h index 2718b9d..9ee38b14 100644 --- a/chrome/browser/chromeos/settings/device_settings_service.h +++ b/chrome/browser/chromeos/settings/device_settings_service.h
@@ -13,7 +13,6 @@ #include "base/compiler_specific.h" #include "base/containers/circular_deque.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "chromeos/dbus/session_manager_client.h" @@ -210,7 +209,7 @@ // Enqueues a new operation. Takes ownership of |operation| and starts it // right away if there is no active operation currently. - void Enqueue(const linked_ptr<SessionManagerOperation>& operation); + void Enqueue(std::unique_ptr<SessionManagerOperation> operation); // Enqueues a load operation. void EnqueueLoad(bool request_key_load); @@ -263,7 +262,8 @@ // The queue of pending operations. The first operation on the queue is // currently active; it gets removed and destroyed once it completes. - base::circular_deque<linked_ptr<SessionManagerOperation>> pending_operations_; + base::circular_deque<std::unique_ptr<SessionManagerOperation>> + pending_operations_; base::ObserverList<Observer>::Unchecked observers_;
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.h b/chrome/browser/chromeos/smb_client/smb_file_system.h index 7050839..528c5df 100644 --- a/chrome/browser/chromeos/smb_client/smb_file_system.h +++ b/chrome/browser/chromeos/smb_client/smb_file_system.h
@@ -14,7 +14,6 @@ #include "base/callback.h" #include "base/files/file.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/timer/elapsed_timer.h"
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc index b78a02e..643c19c 100644 --- a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc +++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
@@ -305,3 +305,11 @@ } remote_locations_.swap(remote_locations); } + +void ChromeDevToolsManagerDelegate::ResetAndroidDeviceManagerForTesting() { + device_manager_.reset(); + + // We also need |device_discovery_| to go away because there may be a pending + // task using a raw pointer to the DeviceManager we just deleted. + device_discovery_.reset(); +}
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.h b/chrome/browser/devtools/chrome_devtools_manager_delegate.h index f5ac9d7b..3f490b4 100644 --- a/chrome/browser/devtools/chrome_devtools_manager_delegate.h +++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
@@ -46,6 +46,9 @@ static bool AllowInspection(Profile* profile, const extensions::Extension* extension); + // Resets |device_manager_|. + void ResetAndroidDeviceManagerForTesting(); + private: friend class DevToolsManagerDelegateTest;
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.cc b/chrome/browser/devtools/device/devtools_android_bridge.cc index 9007e47..db3f446 100644 --- a/chrome/browser/devtools/device/devtools_android_bridge.cc +++ b/chrome/browser/devtools/device/devtools_android_bridge.cc
@@ -98,6 +98,11 @@ return new DevToolsAndroidBridge(profile); } +void DevToolsAndroidBridge::Shutdown() { + // Needed for Chrome_DevToolsADBThread to shut down gracefully in tests. + device_manager_.reset(); +} + scoped_refptr<content::DevToolsAgentHost> DevToolsAndroidBridge::GetBrowserAgentHost( scoped_refptr<RemoteBrowser> browser) {
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.h b/chrome/browser/devtools/device/devtools_android_bridge.h index 2b737b74..b59161c 100644 --- a/chrome/browser/devtools/device/devtools_android_bridge.h +++ b/chrome/browser/devtools/device/devtools_android_bridge.h
@@ -134,6 +134,8 @@ base::Callback<void(scoped_refptr<TCPDeviceProvider>)>; void set_tcp_provider_callback_for_test(TCPProviderCallback callback); + void Shutdown() override; + private: friend struct content::BrowserThread::DeleteOnThread< content::BrowserThread::UI>; @@ -162,7 +164,7 @@ } Profile* const profile_; - const std::unique_ptr<AndroidDeviceManager> device_manager_; + std::unique_ptr<AndroidDeviceManager> device_manager_; using DeviceMap = std::map<std::string, scoped_refptr<AndroidDeviceManager::Device> >;
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc index b916faf..0e28dbe1 100644 --- a/chrome/browser/devtools/devtools_sanity_browsertest.cc +++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -2237,6 +2237,8 @@ base::StringPrintf("while testing URL: %s", pair.first.c_str())); EXPECT_EQ(opened_url, pair.second); } + + CloseDevToolsWindow(); } IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, LoadNetworkResourceForFrontend) {
diff --git a/chrome/browser/devtools/devtools_window_testing.cc b/chrome/browser/devtools/devtools_window_testing.cc index 50e0095..c0c99ff 100644 --- a/chrome/browser/devtools/devtools_window_testing.cc +++ b/chrome/browser/devtools/devtools_window_testing.cc
@@ -6,6 +6,7 @@ #include "base/lazy_instance.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/devtools/chrome_devtools_manager_delegate.h" #include "chrome/browser/devtools/devtools_window.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" @@ -43,6 +44,10 @@ close_callback_.Run(); close_callback_ = base::Closure(); } + + // Needed for Chrome_DevToolsADBThread to shut down gracefully in tests. + ChromeDevToolsManagerDelegate::GetInstance() + ->ResetAndroidDeviceManagerForTesting(); } // static
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc index 13bdd29e..1f674f0 100644 --- a/chrome/browser/download/download_browsertest.cc +++ b/chrome/browser/download/download_browsertest.cc
@@ -3730,19 +3730,19 @@ fake_metadata.download_request().SerializeAsString()); std::string ping_response( fake_metadata.download_response().SerializeAsString()); - safe_browsing::SafeBrowsingService* sb_service = - g_browser_process->safe_browsing_service(); - safe_browsing::DownloadProtectionService* download_protection_service = - sb_service->download_protection_service(); - download_protection_service->feedback_service()->MaybeStorePingsForDownload( + safe_browsing::DownloadFeedbackService::MaybeStorePingsForDownload( safe_browsing::DownloadCheckResult::UNCOMMON, true /* upload_requested */, downloads[0], ping_request, ping_response); ASSERT_TRUE(safe_browsing::DownloadFeedbackService::IsEnabledForDownload( *(downloads[0]))); // Begin feedback and check that the file is "stolen". - download_protection_service->feedback_service()->BeginFeedbackForDownload( - downloads[0], DownloadCommands::DISCARD); + safe_browsing::SafeBrowsingService* sb_service = + g_browser_process->safe_browsing_service(); + safe_browsing::DownloadProtectionService* download_protection_service = + sb_service->download_protection_service(); + download_protection_service->MaybeBeginFeedbackForDownload( + browser()->profile(), downloads[0], DownloadCommands::DISCARD); std::vector<DownloadItem*> updated_downloads; GetDownloads(browser(), &updated_downloads); ASSERT_TRUE(updated_downloads.empty()); @@ -3789,19 +3789,19 @@ fake_metadata.download_request().SerializeAsString()); std::string ping_response( fake_metadata.download_response().SerializeAsString()); - safe_browsing::SafeBrowsingService* sb_service = - g_browser_process->safe_browsing_service(); - safe_browsing::DownloadProtectionService* download_protection_service = - sb_service->download_protection_service(); - download_protection_service->feedback_service()->MaybeStorePingsForDownload( + safe_browsing::DownloadFeedbackService::MaybeStorePingsForDownload( safe_browsing::DownloadCheckResult::UNCOMMON, true /* upload_requested */, downloads[0], ping_request, ping_response); ASSERT_TRUE(safe_browsing::DownloadFeedbackService::IsEnabledForDownload( *(downloads[0]))); // Begin feedback and check that file is still there. - download_protection_service->feedback_service()->BeginFeedbackForDownload( - downloads[0], DownloadCommands::KEEP); + safe_browsing::SafeBrowsingService* sb_service = + g_browser_process->safe_browsing_service(); + safe_browsing::DownloadProtectionService* download_protection_service = + sb_service->download_protection_service(); + download_protection_service->MaybeBeginFeedbackForDownload( + browser()->profile(), downloads[0], DownloadCommands::KEEP); completion_observer->WaitForFinished(); std::vector<DownloadItem*> updated_downloads;
diff --git a/chrome/browser/download/download_started_animation.h b/chrome/browser/download/download_started_animation.h index 250302b..fe31baf 100644 --- a/chrome/browser/download/download_started_animation.h +++ b/chrome/browser/download/download_started_animation.h
@@ -6,7 +6,6 @@ #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_STARTED_ANIMATION_H_ #include "base/macros.h" -#include "build/build_config.h" namespace content { class WebContents; @@ -15,11 +14,6 @@ class DownloadStartedAnimation { public: static void Show(content::WebContents* web_contents); -#if defined(OS_MACOSX) - // Temporary shim for Polychrome. See bottom of first comment in - // https://crbug.com/804950 for details - static void ShowCocoa(content::WebContents* web_contents); -#endif private: DownloadStartedAnimation() { }
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc index 7c7a602..a7c4849 100644 --- a/chrome/browser/extensions/api/debugger/debugger_api.cc +++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -369,9 +369,8 @@ const GURL& site_instance_url = render_frame_host->GetSiteInstance()->GetSiteURL(); - if (site_instance_url.is_empty()) { - // |site_instance_url| is empty for about:blank. Allow the extension to - // attach. + if (site_instance_url.is_empty() || site_instance_url == "about:") { + // Allow the extension to attach to about:blank. return true; }
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc index ea51782..e50a7b2 100644 --- a/chrome/browser/extensions/api/sessions/sessions_apitest.cc +++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/sync/chrome_sync_client.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/sync/profile_sync_test_util.h" +#include "chrome/browser/sync/session_sync_service_factory.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/in_process_browser_test.h" @@ -35,6 +36,7 @@ #include "components/sync/model/data_type_activation_request.h" #include "components/sync/test/engine/mock_model_type_worker.h" #include "components/sync_sessions/session_store.h" +#include "components/sync_sessions/session_sync_service.h" #include "extensions/browser/api_test_utils.h" #include "extensions/common/extension_builder.h" @@ -268,8 +270,8 @@ std::unique_ptr<syncer::DataTypeActivationResponse> activation_response; base::RunLoop loop; - ProfileSyncServiceFactory::GetForProfile(browser_->profile()) - ->GetSessionSyncControllerDelegate() + SessionSyncServiceFactory::GetForProfile(browser_->profile()) + ->GetControllerDelegate() ->OnSyncStarting( request, base::BindLambdaForTesting( [&](std::unique_ptr<syncer::DataTypeActivationResponse>
diff --git a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc index 71928f9f..ff1a5e0 100644 --- a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc +++ b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
@@ -33,7 +33,6 @@ #include "extensions/browser/extension_prefs.h" #include "extensions/browser/install_flag.h" #include "extensions/common/extension_builder.h" -#include "extensions/common/manifest_constants.h" #include "extensions/common/value_builder.h" #include "ppapi/buildflags/buildflags.h" @@ -121,7 +120,7 @@ const std::string& version, const base::FilePath& path) { return ExtensionBuilder("test") - .SetManifestKey(manifest_keys::kVersion, version) + .SetVersion(version) .SetID(id) .SetPath(path) .SetLocation(Manifest::INTERNAL)
diff --git a/chrome/browser/extensions/extension_loading_browsertest.cc b/chrome/browser/extensions/extension_loading_browsertest.cc index f782779..22d79dd 100644 --- a/chrome/browser/extensions/extension_loading_browsertest.cc +++ b/chrome/browser/extensions/extension_loading_browsertest.cc
@@ -9,6 +9,8 @@ #include "base/strings/stringprintf.h" #include "base/version.h" #include "build/build_config.h" +#include "chrome/browser/devtools/devtools_window.h" +#include "chrome/browser/devtools/devtools_window_testing.h" #include "chrome/browser/extensions/devtools_util.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_service.h" @@ -304,6 +306,11 @@ ASSERT_TRUE(content::ExecuteScriptAndExtractBool( bg_contents, "domAutomationController.send(is_valid);", &is_valid)); EXPECT_TRUE(is_valid); + + // Tidy up. + DevToolsWindowTesting::CloseDevToolsWindowSync( + DevToolsWindow::FindDevToolsWindow( + content::DevToolsAgentHost::GetOrCreateFor(bg_contents).get())); } } // namespace
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc index d1a1a77..15b701f 100644 --- a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc +++ b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
@@ -25,7 +25,7 @@ #include "base/strings/string_util.h" #include "base/task/post_task.h" #include "base/task/task_traits.h" -#include "base/threading/thread_restrictions.h" +#include "base/threading/scoped_blocking_call.h" #include "chrome/browser/media_galleries/chromeos/mtp_device_task_helper_map_service.h" #include "chrome/browser/media_galleries/chromeos/snapshot_file_details.h" #include "components/services/filesystem/public/interfaces/types.mojom.h" @@ -356,7 +356,7 @@ std::pair<int, base::File::Error> OpenFileDescriptor( const base::FilePath& file_path, const int flags) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); if (base::DirectoryExists(file_path)) return std::make_pair(-1, base::File::FILE_ERROR_NOT_A_FILE); @@ -370,7 +370,7 @@ // Closes |file_descriptor| on a background task runner. void CloseFileDescriptor(const int file_descriptor) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); IGNORE_EINTR(close(file_descriptor)); }
diff --git a/chrome/browser/media_galleries/chromeos/mtp_read_file_worker.cc b/chrome/browser/media_galleries/chromeos/mtp_read_file_worker.cc index a1bb63c..37c1f20 100644 --- a/chrome/browser/media_galleries/chromeos/mtp_read_file_worker.cc +++ b/chrome/browser/media_galleries/chromeos/mtp_read_file_worker.cc
@@ -12,7 +12,6 @@ #include "base/numerics/safe_conversions.h" #include "base/task/post_task.h" #include "base/task/task_traits.h" -#include "base/threading/thread_restrictions.h" #include "chrome/browser/media_galleries/chromeos/snapshot_file_details.h" #include "components/storage_monitor/storage_monitor.h" #include "content/public/browser/browser_task_traits.h" @@ -30,7 +29,6 @@ uint32_t WriteDataChunkIntoSnapshotFileOnFileThread( const base::FilePath& snapshot_file_path, const std::string& data) { - base::AssertBlockingAllowed(); return base::AppendToFile(snapshot_file_path, data.c_str(), data.size()) ? base::checked_cast<uint32_t>(data.size()) : 0;
diff --git a/chrome/browser/media_galleries/gallery_watch_manager.cc b/chrome/browser/media_galleries/gallery_watch_manager.cc index ddb55c7..42b81de 100644 --- a/chrome/browser/media_galleries/gallery_watch_manager.cc +++ b/chrome/browser/media_galleries/gallery_watch_manager.cc
@@ -15,7 +15,7 @@ #include "base/stl_util.h" #include "base/task/post_task.h" #include "base/task/task_traits.h" -#include "base/threading/thread_restrictions.h" +#include "base/threading/scoped_blocking_call.h" #include "base/time/time.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/media_galleries/gallery_watch_manager_observer.h" @@ -118,7 +118,7 @@ const base::FilePath& path, const base::Callback<void(bool)>& callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); // This can occur if the GalleryWatchManager attempts to watch the same path // again before recieving the callback. It's benign. @@ -144,7 +144,6 @@ void GalleryWatchManager::FileWatchManager::RemoveFileWatch( const base::FilePath& path) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - base::AssertBlockingAllowed(); size_t erased = watchers_.erase(path); DCHECK_EQ(erased, 1u); @@ -159,7 +158,6 @@ const base::FilePath& path, bool error) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - base::AssertBlockingAllowed(); if (error) RemoveFileWatch(path);
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc index 98713b0..c79f0b2 100644 --- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc +++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -23,7 +23,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" #include "base/task_runner_util.h" -#include "base/threading/thread_restrictions.h" +#include "base/threading/scoped_blocking_call.h" #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h" #include "chrome/browser/media_galleries/win/mtp_device_object_entry.h" #include "chrome/browser/media_galleries/win/mtp_device_object_enumerator.h" @@ -70,7 +70,6 @@ base::string16 GetFileObjectIdFromPathOnBlockingPoolThread( const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info, const base::FilePath& file_path) { - base::AssertBlockingAllowed(); DCHECK(!file_path.empty()); IPortableDevice* device = PortableDeviceMapService::GetInstance()->GetPortableDevice( @@ -108,7 +107,6 @@ CreateFileEnumeratorOnBlockingPoolThread( const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info, const base::FilePath& root) { - base::AssertBlockingAllowed(); DCHECK(!device_info.registered_device_path.empty()); DCHECK(!root.empty()); IPortableDevice* device = @@ -139,7 +137,6 @@ bool OpenDeviceOnBlockingPoolThread( const base::string16& pnp_device_id, const base::string16& registered_device_path) { - base::AssertBlockingAllowed(); DCHECK(!pnp_device_id.empty()); DCHECK(!registered_device_path.empty()); Microsoft::WRL::ComPtr<IPortableDevice> device = @@ -160,7 +157,6 @@ const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info, const base::FilePath& file_path, base::File::Info* file_info) { - base::AssertBlockingAllowed(); DCHECK(!device_info.registered_device_path.empty()); DCHECK(!file_path.empty()); DCHECK(file_info); @@ -186,7 +182,7 @@ const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info, const base::FilePath& root, storage::AsyncFileUtil::EntryList* entries) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(!root.empty()); DCHECK(entries); base::File::Info file_info; @@ -221,7 +217,6 @@ base::File::Error GetFileStreamOnBlockingPoolThread( const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info, SnapshotFileDetails* file_details) { - base::AssertBlockingAllowed(); DCHECK(file_details); DCHECK(!file_details->request_info().device_file_path.empty()); DCHECK(!file_details->request_info().snapshot_file_path.empty()); @@ -278,7 +273,6 @@ // files, or 0 on failure. For empty files, just return 0. DWORD WriteDataChunkIntoSnapshotFileOnBlockingPoolThread( const SnapshotFileDetails& file_details) { - base::AssertBlockingAllowed(); if (file_details.file_info().size == 0) return 0; return media_transfer_protocol::CopyDataChunkToLocalFile( @@ -289,7 +283,6 @@ void DeletePortableDeviceOnBlockingPoolThread( const base::string16& registered_device_path) { - base::AssertBlockingAllowed(); PortableDeviceMapService::GetInstance()->RemovePortableDevice( registered_device_path); }
diff --git a/chrome/browser/media_galleries/win/mtp_device_object_enumerator.cc b/chrome/browser/media_galleries/win/mtp_device_object_enumerator.cc index 5052e62..52e5154 100644 --- a/chrome/browser/media_galleries/win/mtp_device_object_enumerator.cc +++ b/chrome/browser/media_galleries/win/mtp_device_object_enumerator.cc
@@ -7,15 +7,10 @@ #include "chrome/browser/media_galleries/win/mtp_device_object_enumerator.h" #include "base/logging.h" -#include "base/threading/thread_restrictions.h" MTPDeviceObjectEnumerator::MTPDeviceObjectEnumerator( const MTPDeviceObjectEntries& entries) - : object_entries_(entries), - index_(0U), - is_index_ready_(false) { - base::AssertBlockingAllowed(); -} + : object_entries_(entries), index_(0U), is_index_ready_(false) {} MTPDeviceObjectEnumerator::~MTPDeviceObjectEnumerator() { DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chrome/browser/media_galleries/win/mtp_device_operations_util.cc b/chrome/browser/media_galleries/win/mtp_device_operations_util.cc index 99861c5..f9ee8f3 100644 --- a/chrome/browser/media_galleries/win/mtp_device_operations_util.cc +++ b/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
@@ -17,7 +17,7 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/strings/string_util.h" -#include "base/threading/thread_restrictions.h" +#include "base/threading/scoped_blocking_call.h" #include "base/time/time.h" #include "base/win/scoped_co_mem.h" #include "base/win/scoped_propvariant.h" @@ -32,7 +32,7 @@ // application that communicates with the device. bool GetClientInformation( Microsoft::WRL::ComPtr<IPortableDeviceValues>* client_info) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(client_info); HRESULT hr = ::CoCreateInstance(__uuidof(PortableDeviceValues), NULL, CLSCTX_INPROC_SERVER, @@ -58,7 +58,7 @@ // the IPortableDeviceContent interface. On failure, returns NULL. Microsoft::WRL::ComPtr<IPortableDeviceContent> GetDeviceContent( IPortableDevice* device) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(device); Microsoft::WRL::ComPtr<IPortableDeviceContent> content; if (SUCCEEDED(device->Content(content.GetAddressOf()))) @@ -72,7 +72,7 @@ Microsoft::WRL::ComPtr<IEnumPortableDeviceObjectIDs> GetDeviceObjectEnumerator( IPortableDevice* device, const base::string16& parent_id) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(device); DCHECK(!parent_id.empty()); Microsoft::WRL::ComPtr<IPortableDeviceContent> content = @@ -175,7 +175,7 @@ bool* is_directory, int64_t* size, base::Time* last_modified_time) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(device); DCHECK(!object_id.empty()); DCHECK(name); @@ -241,7 +241,7 @@ // On success, returns true and fills in |entry|. MTPDeviceObjectEntry GetMTPDeviceObjectEntry(IPortableDevice* device, const base::string16& object_id) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(device); DCHECK(!object_id.empty()); base::string16 name; @@ -265,7 +265,7 @@ const base::string16& directory_object_id, const base::string16& object_name, MTPDeviceObjectEntries* object_entries) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(device); DCHECK(!directory_object_id.empty()); DCHECK(object_entries); @@ -306,7 +306,7 @@ Microsoft::WRL::ComPtr<IPortableDevice> OpenDevice( const base::string16& pnp_device_id) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(!pnp_device_id.empty()); Microsoft::WRL::ComPtr<IPortableDeviceValues> client_info; if (!GetClientInformation(&client_info)) @@ -356,7 +356,7 @@ const base::string16& file_object_id, IStream** file_stream, DWORD* optimal_transfer_size) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(device); DCHECK(!file_object_id.empty()); Microsoft::WRL::ComPtr<IPortableDeviceContent> content = @@ -376,7 +376,7 @@ DWORD CopyDataChunkToLocalFile(IStream* stream, const base::FilePath& local_path, size_t optimal_transfer_size) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); DCHECK(stream); DCHECK(!local_path.empty()); if (optimal_transfer_size == 0U)
diff --git a/chrome/browser/media_galleries/win/portable_device_map_service.cc b/chrome/browser/media_galleries/win/portable_device_map_service.cc index 6020503..e5a16fb1 100644 --- a/chrome/browser/media_galleries/win/portable_device_map_service.cc +++ b/chrome/browser/media_galleries/win/portable_device_map_service.cc
@@ -6,7 +6,6 @@ #include "base/logging.h" #include "base/stl_util.h" -#include "base/threading/thread_restrictions.h" #include "content/public/browser/browser_thread.h" namespace { @@ -24,7 +23,6 @@ void PortableDeviceMapService::AddPortableDevice( const base::string16& device_location, IPortableDevice* device) { - base::AssertBlockingAllowed(); DCHECK(!device_location.empty()); DCHECK(device); base::AutoLock lock(lock_); @@ -43,7 +41,6 @@ void PortableDeviceMapService::RemovePortableDevice( const base::string16& device_location) { - base::AssertBlockingAllowed(); DCHECK(!device_location.empty()); base::AutoLock lock(lock_); PortableDeviceMap::const_iterator it = device_map_.find(device_location); @@ -53,7 +50,6 @@ IPortableDevice* PortableDeviceMapService::GetPortableDevice( const base::string16& device_location) { - base::AssertBlockingAllowed(); DCHECK(!device_location.empty()); base::AutoLock lock(lock_); PortableDeviceMap::const_iterator it = device_map_.find(device_location);
diff --git a/chrome/browser/notifications/OWNERS b/chrome/browser/notifications/OWNERS index 82f60d8f..8d106f95 100644 --- a/chrome/browser/notifications/OWNERS +++ b/chrome/browser/notifications/OWNERS
@@ -9,6 +9,7 @@ per-file *_mac*=rsesek@chromium.org # Windows files +per-file *_win*=chengx@chromium.org per-file *_win*=finnur@chromium.org per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc index b642c8a..9a9cd9a 100644 --- a/chrome/browser/notifications/notification_platform_bridge_win.cc +++ b/chrome/browser/notifications/notification_platform_bridge_win.cc
@@ -155,14 +155,11 @@ // NotificationTemplateBuilder). This function is only used when displaying // notification in production code, which explains why the UMA metrics record // within are classified with the display path. - HRESULT GetToastNotification( + mswr::ComPtr<winui::Notifications::IToastNotification> GetToastNotification( const message_center::Notification& notification, const NotificationTemplateBuilder& notification_template_builder, const std::string& profile_id, - bool incognito, - winui::Notifications::IToastNotification** toast_notification) { - *toast_notification = nullptr; - + bool incognito) { ScopedHString ref_class_name = ScopedHString::Create(RuntimeClass_Windows_Data_Xml_Dom_XmlDocument); mswr::ComPtr<IInspectable> inspectable; @@ -171,7 +168,7 @@ if (FAILED(hr)) { LogDisplayHistogram(DisplayStatus::RO_ACTIVATE_FAILED); DLOG(ERROR) << "Unable to activate the XML Document " << std::hex << hr; - return hr; + return nullptr; } mswr::ComPtr<winxml::Dom::IXmlDocumentIO> document_io; @@ -181,7 +178,7 @@ DisplayStatus::CONVERSION_FAILED_INSPECTABLE_TO_XML_IO); DLOG(ERROR) << "Failed to get XmlDocument as IXmlDocumentIO " << std::hex << hr; - return hr; + return nullptr; } base::string16 notification_template = @@ -192,7 +189,7 @@ LogDisplayHistogram(DisplayStatus::LOAD_XML_FAILED); DLOG(ERROR) << "Unable to load the template's XML into the document " << std::hex << hr; - return hr; + return nullptr; } mswr::ComPtr<winxml::Dom::IXmlDocument> document; @@ -200,7 +197,7 @@ if (FAILED(hr)) { LogDisplayHistogram(DisplayStatus::CONVERSION_FAILED_XML_IO_TO_XML); DLOG(ERROR) << "Unable to get as XMLDocument " << std::hex << hr; - return hr; + return nullptr; } mswr::ComPtr<winui::Notifications::IToastNotificationFactory> @@ -212,25 +209,26 @@ LogDisplayHistogram(DisplayStatus::CREATE_FACTORY_FAILED); DLOG(ERROR) << "Unable to create the IToastNotificationFactory " << std::hex << hr; - return hr; + return nullptr; } + mswr::ComPtr<winui::Notifications::IToastNotification> toast_notification; hr = toast_notification_factory->CreateToastNotification( - document.Get(), toast_notification); + document.Get(), toast_notification.GetAddressOf()); if (FAILED(hr)) { LogDisplayHistogram(DisplayStatus::CREATE_TOAST_NOTIFICATION_FAILED); DLOG(ERROR) << "Unable to create the IToastNotification " << std::hex << hr; - return hr; + return nullptr; } mswr::ComPtr<winui::Notifications::IToastNotification2> toast2; - hr = (*toast_notification)->QueryInterface(IID_PPV_ARGS(&toast2)); + hr = toast_notification->QueryInterface(IID_PPV_ARGS(&toast2)); if (FAILED(hr)) { LogDisplayHistogram(DisplayStatus::CREATE_TOAST_NOTIFICATION2_FAILED); DLOG(ERROR) << "Failed to get IToastNotification2 object " << std::hex << hr; - return hr; + return nullptr; } // Set the Group and Tag values for the notification, in order to support @@ -249,14 +247,14 @@ if (FAILED(hr)) { LogDisplayHistogram(DisplayStatus::SETTING_GROUP_FAILED); DLOG(ERROR) << "Failed to set Group " << std::hex << hr; - return hr; + return nullptr; } hr = toast2->put_Tag(tag.get()); if (FAILED(hr)) { LogDisplayHistogram(DisplayStatus::SETTING_TAG_FAILED); DLOG(ERROR) << "Failed to set Tag " << std::hex << hr; - return hr; + return nullptr; } // By default, Windows 10 will always show the notification on screen. @@ -278,7 +276,7 @@ if (FAILED(hr)) { LogDisplayHistogram(DisplayStatus::GET_GROUP_FAILED); DLOG(ERROR) << "Failed to get group value " << std::hex << hr; - return hr; + return nullptr; } ScopedHString scoped_group(hstring_group); @@ -287,7 +285,7 @@ if (FAILED(hr)) { LogDisplayHistogram(DisplayStatus::GET_TAG_FAILED); DLOG(ERROR) << "Failed to get tag value " << std::hex << hr; - return hr; + return nullptr; } ScopedHString scoped_tag(hstring_tag); @@ -298,12 +296,12 @@ if (FAILED(hr)) { LogDisplayHistogram(DisplayStatus::SUPPRESS_POPUP_FAILED); DLOG(ERROR) << "Failed to set suppress value " << std::hex << hr; - return hr; + return nullptr; } } } - return S_OK; + return toast_notification; } void Display(NotificationHandler::Type notification_type, @@ -360,14 +358,11 @@ std::unique_ptr<NotificationTemplateBuilder> notification_template = NotificationTemplateBuilder::Build( image_retainer_->AsWeakPtr(), launch_id, profile_id, *notification); - mswr::ComPtr<winui::Notifications::IToastNotification> toast; - hr = GetToastNotification(*notification, *notification_template, profile_id, - incognito, &toast); - if (FAILED(hr)) { - // A histogram should have already been logged for this failure. - DLOG(ERROR) << "Unable to get a toast notification " << std::hex << hr; + mswr::ComPtr<winui::Notifications::IToastNotification> toast = + GetToastNotification(*notification, *notification_template, profile_id, + incognito); + if (!toast) return; - } // Activation via user interaction with the toast is handled in // HandleActivation() by way of the notification_helper. @@ -408,8 +403,9 @@ const std::string& notification_id) { DCHECK(notification_task_runner_->RunsTasksInCurrentSequence()); - mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history; - if (!GetIToastNotificationHistory(&history)) { + mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history = + GetIToastNotificationHistory(); + if (!history) { LogCloseHistogram(CloseStatus::GET_TOAST_HISTORY_FAILED); DLOG(ERROR) << "Failed to get IToastNotificationHistory"; return; @@ -431,9 +427,8 @@ } } - bool GetIToastNotificationHistory( - winui::Notifications::IToastNotificationHistory** notification_history) - const WARN_UNUSED_RESULT { + mswr::ComPtr<winui::Notifications::IToastNotificationHistory> + GetIToastNotificationHistory() const WARN_UNUSED_RESULT { mswr::ComPtr<winui::Notifications::IToastNotificationManagerStatics> toast_manager; HRESULT hr = CreateActivationFactory( @@ -444,7 +439,7 @@ HistoryStatus::CREATE_TOAST_NOTIFICATION_MANAGER_FAILED); DLOG(ERROR) << "Unable to create the ToastNotificationManager " << std::hex << hr; - return false; + return nullptr; } mswr::ComPtr<winui::Notifications::IToastNotificationManagerStatics2> @@ -457,26 +452,30 @@ HistoryStatus::QUERY_TOAST_MANAGER_STATISTICS2_FAILED); DLOG(ERROR) << "Failed to get IToastNotificationManagerStatics2 " << std::hex << hr; - return false; + return nullptr; } - hr = toast_manager2->get_History(notification_history); + mswr::ComPtr<winui::Notifications::IToastNotificationHistory> + notification_history; + hr = toast_manager2->get_History(notification_history.GetAddressOf()); if (FAILED(hr)) { LogHistoryHistogram(HistoryStatus::GET_TOAST_HISTORY_FAILED); DLOG(ERROR) << "Failed to get IToastNotificationHistory " << std::hex << hr; - return false; + return nullptr; } LogHistoryHistogram(HistoryStatus::SUCCESS); - return true; + + return notification_history; } std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>> GetDisplayedFromActionCenter(const std::string& profile_id, bool incognito) const { - mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history; - if (!GetIToastNotificationHistory(&history)) { + mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history = + GetIToastNotificationHistory(); + if (!history) { LogGetDisplayedStatus(GetDisplayedStatus::GET_TOAST_HISTORY_FAILED); DLOG(ERROR) << "Failed to get IToastNotificationHistory"; return {}; @@ -920,13 +919,12 @@ NotificationPlatformBridgeWinImpl::notifier_for_testing_ = notifier; } -HRESULT NotificationPlatformBridgeWin::GetToastNotificationForTesting( +mswr::ComPtr<winui::Notifications::IToastNotification> +NotificationPlatformBridgeWin::GetToastNotificationForTesting( const message_center::Notification& notification, const NotificationTemplateBuilder& notification_template_builder, const std::string& profile_id, - bool incognito, - winui::Notifications::IToastNotification** toast_notification) { - return impl_->GetToastNotification(notification, - notification_template_builder, profile_id, - incognito, toast_notification); + bool incognito) { + return impl_->GetToastNotification( + notification, notification_template_builder, profile_id, incognito); }
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.h b/chrome/browser/notifications/notification_platform_bridge_win.h index 7e4f489..315718e 100644 --- a/chrome/browser/notifications/notification_platform_bridge_win.h +++ b/chrome/browser/notifications/notification_platform_bridge_win.h
@@ -82,12 +82,12 @@ // Obtain an IToastNotification interface from a given XML (provided by the // NotificationTemplateBuilder). For testing use only. - HRESULT GetToastNotificationForTesting( + Microsoft::WRL::ComPtr<ABI::Windows::UI::Notifications::IToastNotification> + GetToastNotificationForTesting( const message_center::Notification& notification, const NotificationTemplateBuilder& notification_template_builder, const std::string& profile_id, - bool incognito, - ABI::Windows::UI::Notifications::IToastNotification** toast_notification); + bool incognito); scoped_refptr<NotificationPlatformBridgeWinImpl> impl_;
diff --git a/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc b/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc index ddb5175a..597ee09 100644 --- a/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc +++ b/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
@@ -54,12 +54,11 @@ std::make_unique<NotificationPlatformBridgeWin>()) {} ~NotificationPlatformBridgeWinTest() override = default; - HRESULT GetToast( + mswr::ComPtr<winui::Notifications::IToastNotification2> GetToast( const NotificationLaunchId& launch_id, bool renotify, const std::string& profile_id, - bool incognito, - mswr::ComPtr<winui::Notifications::IToastNotification2>* toast2) { + bool incognito) { GURL origin(kOrigin); auto notification = std::make_unique<message_center::Notification>( message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, L"title", @@ -72,22 +71,22 @@ NotificationTemplateBuilder::Build( image_retainer->AsWeakPtr(), launch_id, profile_id, *notification); - mswr::ComPtr<winui::Notifications::IToastNotification> toast; - HRESULT hr = + mswr::ComPtr<winui::Notifications::IToastNotification> toast = notification_platform_bridge_win_->GetToastNotificationForTesting( - *notification, *builder, profile_id, incognito, &toast); - if (FAILED(hr)) { + *notification, *builder, profile_id, incognito); + if (!toast) { LOG(ERROR) << "GetToastNotificationForTesting failed"; - return hr; + return nullptr; } - hr = toast.As<winui::Notifications::IToastNotification2>(toast2); + mswr::ComPtr<winui::Notifications::IToastNotification2> toast2; + HRESULT hr = toast.As<winui::Notifications::IToastNotification2>(&toast2); if (FAILED(hr)) { LOG(ERROR) << "Converting to IToastNotification2 failed"; - return hr; + return nullptr; } - return S_OK; + return toast2; } protected: @@ -111,9 +110,10 @@ NotificationLaunchId launch_id(kLaunchId); ASSERT_TRUE(launch_id.is_valid()); - mswr::ComPtr<winui::Notifications::IToastNotification2> toast2; - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, kProfileId, - /*incognito=*/false, &toast2)); + mswr::ComPtr<winui::Notifications::IToastNotification2> toast2 = + GetToast(launch_id, /*renotify=*/false, kProfileId, + /*incognito=*/false); + ASSERT_TRUE(toast2); HSTRING hstring_group; ASSERT_HRESULT_SUCCEEDED(toast2->get_Group(&hstring_group)); @@ -149,10 +149,13 @@ // Different profiles, same incognito status -> Unique tags. { - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1", - /*incognito=*/true, &toastA)); - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile2", - /*incognito=*/true, &toastB)); + toastA = GetToast(launch_id, /*renotify=*/false, "Profile1", + /*incognito=*/true); + toastB = GetToast(launch_id, /*renotify=*/false, "Profile2", + /*incognito=*/true); + + ASSERT_TRUE(toastA); + ASSERT_TRUE(toastB); ASSERT_HRESULT_SUCCEEDED(toastA->get_Tag(&hstring_tagA)); base::win::ScopedHString tagA(hstring_tagA); @@ -165,10 +168,13 @@ // Same profile, different incognito status -> Unique tags. { - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1", - /*incognito=*/true, &toastA)); - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1", - /*incognito=*/false, &toastB)); + toastA = GetToast(launch_id, /*renotify=*/false, "Profile1", + /*incognito=*/true); + toastB = GetToast(launch_id, /*renotify=*/false, "Profile1", + /*incognito=*/false); + + ASSERT_TRUE(toastA); + ASSERT_TRUE(toastB); ASSERT_HRESULT_SUCCEEDED(toastA->get_Tag(&hstring_tagA)); base::win::ScopedHString tagA(hstring_tagA); @@ -181,10 +187,13 @@ // Same profile, same incognito status -> Identical tags. { - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1", - /*incognito=*/true, &toastA)); - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1", - /*incognito=*/true, &toastB)); + toastA = GetToast(launch_id, /*renotify=*/false, "Profile1", + /*incognito=*/true); + toastB = GetToast(launch_id, /*renotify=*/false, "Profile1", + /*incognito=*/true); + + ASSERT_TRUE(toastA); + ASSERT_TRUE(toastB); ASSERT_HRESULT_SUCCEEDED(toastA->get_Tag(&hstring_tagA)); base::win::ScopedHString tagA(hstring_tagA); @@ -218,10 +227,12 @@ // Make sure this works a toast is not suppressed when no notifications are // registered. - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, kProfileId, - /*incognito=*/false, &toast2)); + toast2 = GetToast(launch_id, /*renotify=*/false, kProfileId, + /*incognito=*/false); + ASSERT_TRUE(toast2); ASSERT_HRESULT_SUCCEEDED(toast2->get_SuppressPopup(&suppress)); ASSERT_FALSE(suppress); + toast2.Reset(); // Register a single notification with a specific tag. std::string tag_data = std::string(kNotificationId) + "|" + kProfileId + "|0"; @@ -232,16 +243,20 @@ L"<toast launch=\"0|0|Default|0|https://foo.com/|id\"></toast>", tag)); // Request this notification with renotify true (should not be suppressed). - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/true, kProfileId, - /*incognito=*/false, &toast2)); + toast2 = GetToast(launch_id, /*renotify=*/true, kProfileId, + /*incognito=*/false); + ASSERT_TRUE(toast2); ASSERT_HRESULT_SUCCEEDED(toast2->get_SuppressPopup(&suppress)); ASSERT_FALSE(suppress); + toast2.Reset(); // Request this notification with renotify false (should be suppressed). - ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, kProfileId, - /*incognito=*/false, &toast2)); + toast2 = GetToast(launch_id, /*renotify=*/false, kProfileId, + /*incognito=*/false); + ASSERT_TRUE(toast2); ASSERT_HRESULT_SUCCEEDED(toast2->get_SuppressPopup(&suppress)); ASSERT_TRUE(suppress); + toast2.Reset(); notification_platform_bridge_win_->SetDisplayedNotificationsForTesting( nullptr);
diff --git a/chrome/browser/notifications/win/OWNERS b/chrome/browser/notifications/win/OWNERS index 118c023..1c89641 100644 --- a/chrome/browser/notifications/win/OWNERS +++ b/chrome/browser/notifications/win/OWNERS
@@ -1,3 +1,4 @@ +chengx@chromium.org finnur@chromium.org per-file notification_helper*=file://chrome/notification_helper/OWNERS
diff --git a/chrome/browser/notifications/win/notification_image_retainer.cc b/chrome/browser/notifications/win/notification_image_retainer.cc index d627e639..a8f3abb 100644 --- a/chrome/browser/notifications/win/notification_image_retainer.cc +++ b/chrome/browser/notifications/win/notification_image_retainer.cc
@@ -6,12 +6,11 @@ #include "base/files/file_util.h" #include "base/hash.h" +#include "base/memory/ref_counted_memory.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" #include "base/threading/thread_restrictions.h" -#include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "chrome/common/chrome_paths.h" #include "ui/gfx/image/image.h" @@ -28,25 +27,34 @@ // notifications that can be shown on-screen at once (1). constexpr base::TimeDelta kDeletionDelay = base::TimeDelta::FromSeconds(12); -// Writes |data| to a new temporary file and returns the path to the new file, -// or an empty path if the function fails. -base::FilePath WriteDataToTmpFile( - const base::FilePath& file_path, - const base::string16& subdirectory, - const scoped_refptr<base::RefCountedMemory>& data) { - int data_len = data->size(); - if (data_len == 0) - return base::FilePath(); +// Returns the temporary directory within the user data directory. The regular +// temporary directory is not used to minimize the risk of files getting deleted +// by accident. It is also not profile-bound because the notification bridge +// handles images for multiple profiles and the separation is handled by +// RegisterTemporaryImage. +base::FilePath DetermineImageDirectory() { + base::FilePath data_dir; + bool success = base::PathService::Get(chrome::DIR_USER_DATA, &data_dir); + DCHECK(success); + return data_dir.Append(kImageRoot); +} - base::FilePath new_temp = file_path.Append(subdirectory); - if (!base::CreateDirectoryAndGetError(new_temp, nullptr)) +// Writes |data| to a new temporary file at |dir_path| and returns the path to +// the new file, or an empty path if the function fails. +base::FilePath WriteDataToTmpFile( + const base::FilePath& dir_path, + const scoped_refptr<base::RefCountedMemory>& data) { + if (!base::CreateDirectoryAndGetError(dir_path, nullptr)) return base::FilePath(); base::FilePath temp_file; - if (!base::CreateTemporaryFileInDir(new_temp, &temp_file)) + if (!base::CreateTemporaryFileInDir(dir_path, &temp_file)) return base::FilePath(); + + int data_len = data->size(); if (base::WriteFile(temp_file, data->front_as<char>(), data_len) != data_len) return base::FilePath(); + return temp_file; } @@ -68,6 +76,11 @@ const std::string& profile_id, const GURL& origin) { base::AssertBlockingAllowed(); + + scoped_refptr<base::RefCountedMemory> image_data = image.As1xPNGBytes(); + if (image_data->size() == 0) + return base::FilePath(); + if (!initialized_) { image_directory_ = DetermineImageDirectory(); // Delete the old image directory. @@ -84,7 +97,7 @@ base::string16 directory = base::UintToString16(base::Hash(profile_id + origin.spec())); base::FilePath temp_file = - WriteDataToTmpFile(image_directory_, directory, image.As1xPNGBytes()); + WriteDataToTmpFile(image_directory_.Append(directory), image_data); // Add a future task to try to delete the file. It is OK to fail, the file // will get deleted later. @@ -105,10 +118,3 @@ bool override_file_destruction) { override_file_destruction_ = override_file_destruction; } - -base::FilePath NotificationImageRetainer::DetermineImageDirectory() { - base::FilePath data_dir; - bool success = base::PathService::Get(chrome::DIR_USER_DATA, &data_dir); - DCHECK(success); - return data_dir.Append(kImageRoot); -}
diff --git a/chrome/browser/notifications/win/notification_image_retainer.h b/chrome/browser/notifications/win/notification_image_retainer.h index 96c3603f..4516a3f 100644 --- a/chrome/browser/notifications/win/notification_image_retainer.h +++ b/chrome/browser/notifications/win/notification_image_retainer.h
@@ -8,6 +8,7 @@ #include <string> #include "base/files/file_path.h" +#include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner.h" @@ -51,13 +52,6 @@ bool override_file_destruction); private: - // Returns the temporary directory within the user data directory. The - // regular temporary directory is not used to minimize the risk of files - // getting deleted by accident. It is also not profile-bound because the - // notification bridge handles images for multiple profiles and the separation - // is handled by RegisterTemporaryImage. - base::FilePath DetermineImageDirectory(); - // The path to where to store the temporary files. base::FilePath image_directory_;
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc index 0452fd49..e30d22b 100644 --- a/chrome/browser/password_manager/password_store_factory.cc +++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -289,8 +289,7 @@ ps->PreparePasswordHashData(GetSyncUsername(profile)); #endif - password_manager_util::DeleteBlacklistedDuplicates(ps.get(), - profile->GetPrefs(), 60); + password_manager_util::RemoveUselessCredentials(ps, profile->GetPrefs(), 60); auto network_context_getter = base::BindRepeating( [](Profile* profile) -> network::mojom::NetworkContext* { if (!g_browser_process->profile_manager()->IsValidProfile(profile))
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index 4d313b0..b825908e 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -40,7 +40,6 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/ui_test_utils.h" -#include "chrome/test/views/scoped_macviews_browser_mode.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/download/public/common/download_item.h" #include "components/viz/common/features.h" @@ -380,10 +379,6 @@ } base::test::ScopedFeatureList feature_list_; - -#if defined(OS_MACOSX) - test::ScopedMacViewsBrowserMode cocoa_browser_mode_{false}; -#endif }; // Disabled because it's flaky.
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc index 83cb9551..297fb69d 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -1174,15 +1174,10 @@ #if !defined(OS_ANDROID) -// TODO(mlamouri): enable this tests on other platforms when aspect ratio is -// implemented. -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) - // Tests that when a new surface id is sent to the Picture-in-Picture window, it // doesn't move back to its default position. -// TODO(https://crbug.com/862505): test is currently flaky. IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest, - DISABLED_SurfaceIdChangeDoesNotMoveWindow) { + SurfaceIdChangeDoesNotMoveWindow) { LoadTabAndEnterPictureInPicture(browser()); content::WebContents* active_web_contents = @@ -1208,7 +1203,8 @@ content::TitleWatcher(active_web_contents, expected_title) .WaitAndGetTitle()); - // Simulate a new surface layer and a change in aspect ratio and wait for ack. + // Simulate a new surface layer and a change in aspect ratio then wait for + // ack. { WidgetBoundsChangeWaiter waiter(overlay_window); @@ -1228,8 +1224,6 @@ EXPECT_LT(overlay_window->GetBounds().y(), 100); } -#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) - // Tests that the Picture-in-Picture state is properly updated when the window // is closed at a system level. IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest, @@ -1444,8 +1438,8 @@ .WaitAndGetTitle()); // Attaching devtools triggers the change in timing that leads to the crash. - DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), - true /*is_docked=*/); + DevToolsWindow* window = DevToolsWindowTesting::OpenDevToolsWindowSync( + browser(), true /*is_docked=*/); { bool result = false; @@ -1468,6 +1462,10 @@ content::WebContentsDestroyedWatcher destroyed_watcher(active_web_contents); browser()->tab_strip_model()->CloseWebContentsAt(0, 0); destroyed_watcher.Wait(); + + // Make sure the window and therefore Chrome_DevToolsADBThread shutdown + // gracefully. + DevToolsWindowTesting::CloseDevToolsWindowSync(window); } #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 7d4305b..2aa2cbd 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -117,6 +117,7 @@ #include "components/subresource_filter/content/browser/ruleset_service.h" #include "components/sync/base/sync_prefs.h" #include "components/sync_preferences/pref_service_syncable.h" +#include "components/sync_sessions/session_sync_prefs.h" #include "components/translate/core/browser/translate_prefs.h" #include "components/update_client/update_client.h" #include "components/variations/service/variations_service.h" @@ -590,6 +591,7 @@ secure_origin_whitelist::RegisterProfilePrefs(registry); SafeBrowsingTriggeredPopupBlocker::RegisterProfilePrefs(registry); SessionStartupPref::RegisterProfilePrefs(registry); + sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry); syncer::SyncPrefs::RegisterProfilePrefs(registry); syncer::PerUserTopicRegistrationManager::RegisterProfilePrefs(registry); TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/resource_coordinator/discard_before_unload_helper.cc b/chrome/browser/resource_coordinator/discard_before_unload_helper.cc new file mode 100644 index 0000000..23510df --- /dev/null +++ b/chrome/browser/resource_coordinator/discard_before_unload_helper.cc
@@ -0,0 +1,120 @@ +// 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/resource_coordinator/discard_before_unload_helper.h" + +#include "base/bind.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" + +namespace resource_coordinator { + +namespace { + +// This is a helper class that determines whether or not there is a beforeunload +// handler associated with a given WebContents, and if so, whether or not it +// indicates that the page contains unsaved state. +// +// This is done by actually running the beforeunload handler if there is one. If +// the beforeunload handler returns a non-empty string then a javascript dialog +// request is made, in which case it is intercepted before it is displayed and +// implicitly canceled. +// +// The beforeunload is initiated via WebContents::DispatchBeforeUnload, and the +// outcome of the beforeunload is monitored via +// WebContentsObserver::BeforeUnloadFired and ::BeforeUnloadDialogCanceled. +// +// Note that the callback is guaranteed to be invoked; in the worst case +// scenario it will be invoked when the WebContents is destroyed, with a +// |proceed|=true value. +class DiscardBeforeUnloadHelper : public content::WebContentsObserver { + public: + static void HasBeforeUnloadHandler(content::WebContents* contents, + HasBeforeUnloadHandlerCallback&& callback); + + ~DiscardBeforeUnloadHelper() override; + + private: + // This is only meant to be called via "new", as the object takes ownership + // of itself. + DiscardBeforeUnloadHelper(content::WebContents* contents, + HasBeforeUnloadHandlerCallback&& callback); + + // WebContentsObserver: + void BeforeUnloadFired(bool proceed, + const base::TimeTicks& proceed_time) override; + void BeforeUnloadDialogCancelled() override; + void WebContentsDestroyed() override; + + // Responds by invoking the callback, and cleaning itself up. + void Respond(bool has_beforeunload_handler); + + // This object keeps itself alive while waiting for a callback, and cleans + // itself up when done. + std::unique_ptr<DiscardBeforeUnloadHelper> self_; + + HasBeforeUnloadHandlerCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(DiscardBeforeUnloadHelper); +}; + +void DiscardBeforeUnloadHelper::HasBeforeUnloadHandler( + content::WebContents* contents, + HasBeforeUnloadHandlerCallback&& callback) { + // Create this object and deliberately let go of it. It deletes itself after + // it has invoked the callback. + new DiscardBeforeUnloadHelper(contents, std::move(callback)); +} + +DiscardBeforeUnloadHelper::DiscardBeforeUnloadHelper( + content::WebContents* contents, + HasBeforeUnloadHandlerCallback&& callback) + : WebContentsObserver(contents), + self_(this), + callback_(std::move(callback)) { + DCHECK(!callback_.is_null()); + // NOTE: Ideally this would call NeedToFireBeforeUnload and entirely skip + // on the dispatch if there are no unload handlers installed. Unfortunately, + // NeedToFireBeforeUnload doesn't check the main frame, so this doesn't quite + // work. See this related bug for more information: crbug.com/869956 + web_contents()->DispatchBeforeUnload(true /* auto_cancel */); +} + +DiscardBeforeUnloadHelper::~DiscardBeforeUnloadHelper() = default; + +void DiscardBeforeUnloadHelper::BeforeUnloadFired( + bool proceed, + const base::TimeTicks& proceed_time) { + // |proceed = true| means no beforeunload handler and vice-versa. + Respond(!proceed /* has_beforeunload_handler */); +} + +void DiscardBeforeUnloadHelper::BeforeUnloadDialogCancelled() { + // Canceling a beforeunload dialog means that there was a beforeunload handler + // that was already running prior to our request, and more specifically that + // the user wants to stay on the page. + Respond(true /* has_beforeunload_handler */); +} + +void DiscardBeforeUnloadHelper::WebContentsDestroyed() { + // If a WebContents is destroyed while waiting for the beforeunload response + // this can be interpreted as |proceed| being true, as the page is no longer + // going to be around to be preserved. + Respond(false /* has_beforeunload_handler */); +} + +void DiscardBeforeUnloadHelper::Respond(bool has_beforeunload_handler) { + std::move(callback_).Run(has_beforeunload_handler); + self_.reset(); +} + +} // namespace + +void HasBeforeUnloadHandler(content::WebContents* contents, + HasBeforeUnloadHandlerCallback&& callback) { + DiscardBeforeUnloadHelper::HasBeforeUnloadHandler(contents, + std::move(callback)); +} + +} // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/discard_before_unload_helper.h b/chrome/browser/resource_coordinator/discard_before_unload_helper.h new file mode 100644 index 0000000..d2ae716 --- /dev/null +++ b/chrome/browser/resource_coordinator/discard_before_unload_helper.h
@@ -0,0 +1,30 @@ +// 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_RESOURCE_COORDINATOR_DISCARD_BEFORE_UNLOAD_HELPER_H_ +#define CHROME_BROWSER_RESOURCE_COORDINATOR_DISCARD_BEFORE_UNLOAD_HELPER_H_ + +#include "base/callback.h" + +namespace content { +class WebContents; +} // namespace content + +namespace resource_coordinator { + +using HasBeforeUnloadHandlerCallback = + base::OnceCallback<void(bool has_before_unload_handler)>; + +// Determines if the given WebContents has a beforeunload handler; if not, it is +// safe to discard. This works by calling WebContents::DispatchBeforeUnload with +// |auto_cancel = true|, which prevents a beforeunload dialog from being +// displayed to the user in the case that there is a beforeunload handler. This +// should only be called from the UI thread, and the callback will similarly +// be invoked from there. +void HasBeforeUnloadHandler(content::WebContents* contents, + HasBeforeUnloadHandlerCallback&& callback); + +} // namespace resource_coordinator + +#endif // CHROME_BROWSER_RESOURCE_COORDINATOR_DISCARD_BEFORE_UNLOAD_HELPER_H_
diff --git a/chrome/browser/resource_coordinator/discard_before_unload_helper_browsertest.cc b/chrome/browser/resource_coordinator/discard_before_unload_helper_browsertest.cc new file mode 100644 index 0000000..a0f2e0e --- /dev/null +++ b/chrome/browser/resource_coordinator/discard_before_unload_helper_browsertest.cc
@@ -0,0 +1,98 @@ +// 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/resource_coordinator/discard_before_unload_helper.h" + +#include "base/bind.h" +#include "base/run_loop.h" +#include "base/test/bind_test_util.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/app_modal/javascript_app_modal_dialog.h" +#include "components/app_modal/native_app_modal_dialog.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.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" + +namespace resource_coordinator { + +namespace { + +class HasBeforeUnloadHandlerTest : public InProcessBrowserTest { + protected: + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); + embedded_test_server()->ServeFilesFromSourceDirectory("chrome/test/data"); + embedded_test_server()->StartAcceptingConnections(); + } + + void TestDiscardBeforeUnloadHelper(const char* url, + bool has_beforeunload_helper) { + GURL gurl(embedded_test_server()->GetURL("a.com", url)); + ui_test_utils::NavigateToURL(browser(), gurl); + auto* wc = browser()->tab_strip_model()->GetActiveWebContents(); + content::PrepContentsForBeforeUnloadTest(wc); + + base::RunLoop run_loop; + bool callback_invoked = false; + bool response = false; + HasBeforeUnloadHandlerCallback callback = base::BindLambdaForTesting( + [&run_loop, &callback_invoked, &response](bool response_arg) { + run_loop.Quit(); + callback_invoked = true; + response = response_arg; + }); + + HasBeforeUnloadHandler(wc, std::move(callback)); + + // The callback should not be invoked synchronously. In a world where + // NeedToFireBeforeUnload works properly this expectation changes. + ASSERT_FALSE(callback_invoked); + + // Run the loop until we process the callback. + run_loop.Run(); + + EXPECT_TRUE(callback_invoked); + EXPECT_EQ(has_beforeunload_helper, response); + + // If we didn't expect to proceed, then that means there's an unload + // handler. Which means that when we try to exit the browser a dialog will + // be shown. Wait for it, and accept it to allow the browser to close and + // the test to complete. + browser()->tab_strip_model()->CloseAllTabs(); + if (has_beforeunload_helper) { + app_modal::JavaScriptAppModalDialog* alert = + ui_test_utils::WaitForAppModalDialog(); + ASSERT_TRUE(alert); + EXPECT_TRUE(alert->is_before_unload_dialog()); + alert->native_dialog()->AcceptAppModalDialog(); + } + } +}; + +} // namespace + +IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest, + NonEmptyBeforeUnloadDetected) { + TestDiscardBeforeUnloadHelper("/beforeunload.html", + true /* has_beforeunload_helper */); +} + +IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest, EmptyBeforeUnloadDetected) { + TestDiscardBeforeUnloadHelper("/emptybeforeunload.html", + false /* has_beforeunload_helper */); +} + +IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest, NoBeforeUnloadDetected) { + TestDiscardBeforeUnloadHelper("/empty.html", + false /* has_beforeunload_helper */); +} + +} // namespace resource_coordinator
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js index 8fc78677..f5b6985 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -432,11 +432,6 @@ AutomationPredicate.linkOrControl(node); }; - // Always try to give nodes selection. - if (start.defaultActionVerb == chrome.automation.DefaultActionVerb.SELECT) { - start.doDefault(); - } - // Next, try to focus the start or end node. if (!AutomationPredicate.structuralContainer(start) && start.state[StateType.FOCUSABLE]) {
diff --git a/chrome/browser/resources/local_ntp/custom_backgrounds.js b/chrome/browser/resources/local_ntp/custom_backgrounds.js index a042caa1..5c97d5c 100644 --- a/chrome/browser/resources/local_ntp/custom_backgrounds.js +++ b/chrome/browser/resources/local_ntp/custom_backgrounds.js
@@ -902,6 +902,9 @@ .setAttribute( 'aria-label', configData.translatedStrings.customizeThisPage); + $(customBackgrounds.IDS.EDIT_BG_GEAR) + .setAttribute('title', configData.translatedStrings.customizeBackground); + // Edit gear icon interaction events. let editBackgroundInteraction = function() { editDialog.showModal();
diff --git a/chrome/browser/resources/omnibox/omnibox.html b/chrome/browser/resources/omnibox/omnibox.html index ccaaa686..7360c58 100644 --- a/chrome/browser/resources/omnibox/omnibox.html +++ b/chrome/browser/resources/omnibox/omnibox.html
@@ -17,7 +17,6 @@ <p> Enter omnibox input text: <input id="input-text" type="text" size="40" autofocus> - <input type="submit"> </p> <p>Input parameters:</p> <p>
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js index 33cfac1..078ae73 100644 --- a/chrome/browser/resources/omnibox/omnibox.js +++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -22,7 +22,7 @@ * Register our event handlers. */ function initialize() { - $('omnibox-input-form').addEventListener('submit', startOmniboxQuery, false); + $('input-text').addEventListener('input', startOmniboxQuery, false); $('prevent-inline-autocomplete') .addEventListener('change', startOmniboxQuery); $('prefer-keyword').addEventListener('change', startOmniboxQuery);
diff --git a/chrome/browser/resources/print_preview/new/destination_dialog.html b/chrome/browser/resources/print_preview/new/destination_dialog.html index fe21ce5..efedf4d1b 100644 --- a/chrome/browser/resources/print_preview/new/destination_dialog.html +++ b/chrome/browser/resources/print_preview/new/destination_dialog.html
@@ -54,7 +54,7 @@ } .user-info { - font-size: calc(13/15 * 1em); + font-size: calc(13 / 15 * 1em); line-height: normal; margin-bottom: 14px; margin-top: 8px; @@ -77,7 +77,7 @@ /* Height = 3 * destination item (28px) + 10px padding + 1 line text */ #recentList { flex: 0; - min-height: calc(94px + 1rem); + min-height: calc(94px + 20 / 13 * 1rem); padding-bottom: 18px; } @@ -85,12 +85,12 @@ /* header (82px + 1 line) - button (64px) - 2px spinner - 2px extra */ #printList { flex: 1; - min-height: calc(94px + 1rem); + min-height: calc(94px + 20 / 13 * 1rem); padding-bottom: 0; } paper-button { - font-size: calc(12/13 * 1em); + font-size: calc(12 / 13 * 1em); } #dialog #promos { @@ -140,7 +140,7 @@ #invitationPromo invitation-details { color: var(--google-grey-refresh-700); - font-size: calc(10/13 * 1em); + font-size: calc(10 / 13 * 1em); font-weight: 500; } </style>
diff --git a/chrome/browser/resources/print_preview/new/destination_list.html b/chrome/browser/resources/print_preview/new/destination_list.html index 28a0125..0a74336 100644 --- a/chrome/browser/resources/print_preview/new/destination_list.html +++ b/chrome/browser/resources/print_preview/new/destination_list.html
@@ -26,6 +26,7 @@ #listContainer { flex: 1; + min-height: 0; } .title, @@ -39,7 +40,8 @@ border-bottom: 2px solid var(--google-grey-300); display: flex; flex: 0; - min-height: 1em; + margin-top: 2px; + min-height: calc(20/13 * 1em); padding-bottom: 8px; }
diff --git a/chrome/browser/resources/print_preview/new/link_container.html b/chrome/browser/resources/print_preview/new/link_container.html index 2a811fb..710b1c0 100644 --- a/chrome/browser/resources/print_preview/new/link_container.html +++ b/chrome/browser/resources/print_preview/new/link_container.html
@@ -9,6 +9,10 @@ <dom-module id="print-preview-link-container"> <template> <style include="print-preview-shared throbber cr-hidden-style"> + :host([disabled]) { + pointer-events: none; + } + .throbber { margin: 8px; min-height: 16px;
diff --git a/chrome/browser/resources/print_preview/new/pages_settings.html b/chrome/browser/resources/print_preview/new/pages_settings.html index 2d20d0ba..b6ec296 100644 --- a/chrome/browser/resources/print_preview/new/pages_settings.html +++ b/chrome/browser/resources/print_preview/new/pages_settings.html
@@ -31,6 +31,7 @@ #pageSettingsCustomInput { cursor: default; + height: 100%; } </style> <print-preview-settings-section
diff --git a/chrome/browser/resources/print_preview/new/pages_settings.js b/chrome/browser/resources/print_preview/new/pages_settings.js index 660c9e48..2db57211 100644 --- a/chrome/browser/resources/print_preview/new/pages_settings.js +++ b/chrome/browser/resources/print_preview/new/pages_settings.js
@@ -139,7 +139,14 @@ this.onRangeChange_(); return this.pagesToPrint_; } + const limits = range.split('-'); + if (limits.length > 2) { + this.errorState_ = PagesInputErrorState.INVALID_SYNTAX; + this.onRangeChange_(); + return this.pagesToPrint_; + } + let min = Number.parseInt(limits[0], 10); if ((limits[0].length > 0 && Number.isNaN(min)) || min < 1) { this.errorState_ = PagesInputErrorState.INVALID_SYNTAX;
diff --git a/chrome/browser/safe_browsing/download_protection/download_feedback.cc b/chrome/browser/safe_browsing/download_protection/download_feedback.cc index 3db44bb..421dcb5 100644 --- a/chrome/browser/safe_browsing/download_protection/download_feedback.cc +++ b/chrome/browser/safe_browsing/download_protection/download_feedback.cc
@@ -21,16 +21,16 @@ // This enum is used by histograms. Do not change the ordering or remove items. enum UploadResultType { - UPLOAD_SUCCESS, - UPLOAD_CANCELLED, - UPLOAD_METADATA_NET_ERROR, - UPLOAD_METADATA_RESPONSE_ERROR, - UPLOAD_FILE_NET_ERROR, - UPLOAD_FILE_RESPONSE_ERROR, - UPLOAD_COMPLETE_RESPONSE_ERROR, + UPLOAD_SUCCESS = 0, + UPLOAD_CANCELLED = 1, + UPLOAD_METADATA_NET_ERROR = 2, + UPLOAD_METADATA_RESPONSE_ERROR = 3, + UPLOAD_FILE_NET_ERROR = 4, + UPLOAD_FILE_RESPONSE_ERROR = 5, + UPLOAD_COMPLETE_RESPONSE_ERROR = 6, // Memory space for histograms is determined by the max. // ALWAYS ADD NEW VALUES BEFORE THIS ONE. - UPLOAD_RESULT_MAX + UPLOAD_RESULT_MAX = 7 }; // Handles the uploading of a single downloaded binary to the safebrowsing
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc index 89a6656..e9fdc24f1 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -507,4 +507,17 @@ username); } +bool DownloadProtectionService::MaybeBeginFeedbackForDownload( + Profile* profile, + download::DownloadItem* download, + DownloadCommands::Command download_command) { + PrefService* prefs = profile->GetPrefs(); + if (!profile->IsOffTheRecord() && ExtendedReportingPrefExists(*prefs) && + IsExtendedReportingEnabled(*prefs)) { + feedback_service_->BeginFeedbackForDownload(download, download_command); + return true; + } + return false; +} + } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.h b/chrome/browser/safe_browsing/download_protection/download_protection_service.h index 2b54a1c..dffff24 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_service.h +++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.h
@@ -23,6 +23,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/supports_user_data.h" +#include "chrome/browser/download/download_commands.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h" #include "chrome/browser/safe_browsing/ui_manager.h" @@ -121,9 +122,12 @@ return download_request_timeout_ms_; } - DownloadFeedbackService* feedback_service() { - return feedback_service_.get(); - } + // Checks the user permissions, and submits the downloaded file if + // appropriate. Returns whether the submission was successful. + bool MaybeBeginFeedbackForDownload( + Profile* profile, + download::DownloadItem* download, + DownloadCommands::Command download_command); // Registers a callback that will be run when a ClientDownloadRequest has // been formed.
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc index c14cc16..667767e 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -2639,6 +2639,22 @@ EXPECT_TRUE(IsResult(DownloadCheckResult::WHITELISTED_BY_POLICY)); } +TEST_F(DownloadProtectionServiceTest, CheckOffTheRecordDoesNotSendFeedback) { + NiceMockDownloadItem item; + EXPECT_FALSE(download_service_->MaybeBeginFeedbackForDownload( + profile_->GetOffTheRecordProfile(), &item, DownloadCommands::KEEP)); +} + +TEST_F(DownloadProtectionServiceTest, + CheckNotExtendedReportedDisabledDoesNotSendFeedback) { + PrefService* prefs = profile_->GetPrefs(); + prefs->SetBoolean(GetExtendedReportingPrefName(*prefs), false); + + NiceMockDownloadItem item; + EXPECT_FALSE(download_service_->MaybeBeginFeedbackForDownload( + profile_.get(), &item, DownloadCommands::KEEP)); +} + // ------------ class DownloadProtectionServiceFlagTest ---------------- class DownloadProtectionServiceFlagTest : public DownloadProtectionServiceTest { protected:
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc index 406066b..d0831ee 100644 --- a/chrome/browser/search/instant_service.cc +++ b/chrome/browser/search/instant_service.cc
@@ -85,23 +85,41 @@ return defaults; } -base::FilePath GetLocalFilePath() { +void CopyFileToProfilePath(const base::FilePath& from_path, + const base::FilePath& profile_path) { + base::CopyFile(from_path, + profile_path.AppendASCII( + chrome::kChromeSearchLocalNtpBackgroundFilename)); +} + +void RemoveLocalBackgroundImageCopy(const base::FilePath& profile_path) { + base::DeleteFile( + profile_path.AppendASCII(chrome::kChromeSearchLocalNtpBackgroundFilename), + false); +} + +// In some cases (Sync, upgrading versions) its necessary to check if the file +// actually exists and is in the correct location. +bool CheckLocalBackgroundImageExists(const base::FilePath& profile_path) { base::FilePath user_data_dir; base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); - return user_data_dir.AppendASCII( + base::FilePath profile_image = + profile_path.AppendASCII(chrome::kChromeSearchLocalNtpBackgroundFilename); + base::FilePath user_data_image = user_data_dir.AppendASCII( chrome::kChromeSearchLocalNtpBackgroundFilename); -} -void CopyFileToProfilePath(const base::FilePath& from_path) { - base::CopyFile(from_path, GetLocalFilePath()); -} + if (base::PathExists(profile_image)) + return true; -void RemoveLocalBackgroundImageCopy() { - base::DeleteFile(GetLocalFilePath(), false); -} + // The image was originally stored in the user data dir, it needs to be moved + // to the profile path if it's still there. + if (base::PathExists(user_data_image)) { + base::CopyFile(user_data_image, profile_image); + base::DeleteFile(user_data_image, false); + return true; + } -bool CheckLocalBackgroundImageExists() { - return base::PathExists(GetLocalFilePath()); + return false; } bool IsLocalFileUrl(GURL url) { @@ -366,9 +384,9 @@ const std::string& attribution_line_2, const GURL& action_url) { pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, false); - base::PostTaskWithTraits(FROM_HERE, - {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, - base::BindOnce(&RemoveLocalBackgroundImageCopy)); + base::PostTaskWithTraits( + FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, + base::BindOnce(&RemoveLocalBackgroundImageCopy, profile_->GetPath())); if (background_url.is_valid()) { base::DictionaryValue background_info = GetBackgroundInfoAsDict( @@ -395,7 +413,7 @@ void InstantService::SelectLocalBackgroundImage(const base::FilePath& path) { base::PostTaskWithTraitsAndReply( FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, - base::BindOnce(&CopyFileToProfilePath, path), + base::BindOnce(&CopyFileToProfilePath, path, profile_->GetPath()), base::BindOnce(&InstantService::SetBackgroundToLocalResource, weak_ptr_factory_.GetWeakPtr())); } @@ -644,7 +662,7 @@ background_local_to_device_pref->IsDefaultValue()) { base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, - base::BindOnce(&CheckLocalBackgroundImageExists), + base::BindOnce(&CheckLocalBackgroundImageExists, profile_->GetPath()), base::BindOnce( &InstantService::ApplyCustomBackgroundThemeInfoFromLocalFile, weak_ptr_factory_.GetWeakPtr())); @@ -717,9 +735,9 @@ void InstantService::ResetCustomBackgroundThemeInfo() { pref_service_->ClearPref(prefs::kNtpCustomBackgroundDict); pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, false); - base::PostTaskWithTraits(FROM_HERE, - {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, - base::BindOnce(&RemoveLocalBackgroundImageCopy)); + base::PostTaskWithTraits( + FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, + base::BindOnce(&RemoveLocalBackgroundImageCopy, profile_->GetPath())); FallbackToDefaultThemeInfo(); }
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc index 3c73e87..4e6112e 100644 --- a/chrome/browser/search/instant_service_unittest.cc +++ b/chrome/browser/search/instant_service_unittest.cc
@@ -188,10 +188,9 @@ LocalBackgroundImageCopyCreated) { const GURL kUrl("chrome-search://local-ntp/background.jpg"); - base::FilePath user_data_dir; - base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); - base::FilePath path(user_data_dir.AppendASCII("test_file")); - base::FilePath copy_path(user_data_dir.AppendASCII( + base::FilePath profile_path = profile()->GetPath(); + base::FilePath path(profile_path.AppendASCII("test_file")); + base::FilePath copy_path(profile_path.AppendASCII( chrome::kChromeSearchLocalNtpBackgroundFilename)); base::WriteFile(path, "background_image", 16); @@ -209,9 +208,8 @@ TEST_F(InstantServiceTestCustomBackgroundsEnabled, ChangingSearchProviderRemovesLocalBackgroundImageCopy) { - base::FilePath user_data_dir; - base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); - base::FilePath path(user_data_dir.AppendASCII( + base::FilePath profile_path = profile()->GetPath(); + base::FilePath path(profile_path.AppendASCII( chrome::kChromeSearchLocalNtpBackgroundFilename)); base::WriteFile(path, "background_image", 16); @@ -232,9 +230,8 @@ SettingUrlRemovesLocalBackgroundImageCopy) { const GURL kUrl("https://www.foo.com"); - base::FilePath user_data_dir; - base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); - base::FilePath path(user_data_dir.AppendASCII( + base::FilePath profile_path = profile()->GetPath(); + base::FilePath path(profile_path.AppendASCII( chrome::kChromeSearchLocalNtpBackgroundFilename)); base::WriteFile(path, "background_image", 16); @@ -334,9 +331,8 @@ sync_preferences::TestingPrefServiceSyncable* pref_service = profile()->GetTestingPrefService(); - base::FilePath user_data_dir; - base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); - base::FilePath path(user_data_dir.AppendASCII( + base::FilePath profile_path = profile()->GetPath(); + base::FilePath path(profile_path.AppendASCII( chrome::kChromeSearchLocalNtpBackgroundFilename)); base::WriteFile(path, "background_image", 16); base::TaskScheduler::GetInstance()->FlushForTesting(); @@ -368,3 +364,31 @@ ThemeBackgroundInfo* theme_info = instant_service_->GetThemeInfoForTesting(); EXPECT_EQ(kUrl, theme_info->custom_background_url); } + +TEST_F(InstantServiceTestCustomBackgroundsEnabled, + LocalFileCopiedToProfileDirectory) { + const GURL kUrl("chrome-search://local-ntp/background.jpg?123456789"); + + sync_preferences::TestingPrefServiceSyncable* pref_service = + profile()->GetTestingPrefService(); + + base::FilePath user_data_dir; + base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + base::FilePath old_path(user_data_dir.AppendASCII( + chrome::kChromeSearchLocalNtpBackgroundFilename)); + base::FilePath new_path(profile()->GetPath().AppendASCII( + chrome::kChromeSearchLocalNtpBackgroundFilename)); + base::WriteFile(old_path, "background_image", 16); + base::TaskScheduler::GetInstance()->FlushForTesting(); + + pref_service->SetUserPref( + prefs::kNtpCustomBackgroundDict, + std::make_unique<base::Value>(GetBackgroundInfoAsDict(kUrl))); + thread_bundle()->RunUntilIdle(); + + ThemeBackgroundInfo* theme_info = instant_service_->GetThemeInfoForTesting(); + EXPECT_EQ(kUrl, theme_info->custom_background_url); + + EXPECT_FALSE(base::PathExists(old_path)); + EXPECT_TRUE(base::PathExists(new_path)); +}
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc index 55fb3a2..f22d405 100644 --- a/chrome/browser/search/local_ntp_source.cc +++ b/chrome/browser/search/local_ntp_source.cc
@@ -267,13 +267,11 @@ SkColorGetB(background_color)); } -std::string ReadBackgroundImageData() { +std::string ReadBackgroundImageData(const base::FilePath& profile_path) { std::string data_string; - base::FilePath user_data_dir; - base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); - base::ReadFileToString(user_data_dir.AppendASCII( - chrome::kChromeSearchLocalNtpBackgroundFilename), - &data_string); + base::ReadFileToString( + profile_path.AppendASCII(chrome::kChromeSearchLocalNtpBackgroundFilename), + &data_string); return data_string; } @@ -718,7 +716,7 @@ if (stripped_path == chrome::kChromeSearchLocalNtpBackgroundFilename) { base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, - base::BindOnce(&ReadBackgroundImageData), + base::BindOnce(&ReadBackgroundImageData, profile_->GetPath()), base::BindOnce(&ServeBackgroundImageData, callback)); return; }
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index b1f67841..640ee8f 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -28,24 +28,20 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/sync/bookmark_sync_service_factory.h" -#include "chrome/browser/sync/glue/sync_start_util.h" #include "chrome/browser/sync/glue/theme_data_type_controller.h" #include "chrome/browser/sync/model_type_store_service_factory.h" #include "chrome/browser/sync/profile_sync_service_factory.h" -#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router.h" -#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h" +#include "chrome/browser/sync/session_sync_service_factory.h" #include "chrome/browser/sync/user_event_service_factory.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/themes/theme_syncable_service.h" -#include "chrome/browser/ui/sync/browser_synced_window_delegates_getter.h" #include "chrome/browser/undo/bookmark_undo_service_factory.h" #include "chrome/browser/web_data_service_factory.h" #include "chrome/common/buildflags.h" #include "chrome/common/channel_info.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" -#include "chrome/common/url_constants.h" #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h" @@ -70,7 +66,6 @@ #include "components/spellcheck/spellcheck_buildflags.h" #include "components/sync/base/pref_names.h" #include "components/sync/base/report_unrecoverable_error.h" -#include "components/sync/device_info/local_device_info_provider.h" #include "components/sync/driver/async_directory_type_controller.h" #include "components/sync/driver/sync_api_component_factory.h" #include "components/sync/driver/sync_util.h" @@ -81,8 +76,7 @@ #include "components/sync_bookmarks/bookmark_sync_service.h" #include "components/sync_preferences/pref_service_syncable.h" #include "components/sync_sessions/favicon_cache.h" -#include "components/sync_sessions/session_sync_bridge.h" -#include "components/sync_sessions/sync_sessions_client.h" +#include "components/sync_sessions/session_sync_service.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/storage/backend_task_runner.h" @@ -116,10 +110,6 @@ #include "chrome/browser/spellchecker/spellcheck_service.h" #endif // BUILDFLAG(ENABLE_SPELLCHECK) -#if defined(OS_ANDROID) -#include "chrome/browser/sync/glue/synced_window_delegates_getter_android.h" -#endif // defined(OS_ANDROID) - #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/printing/printers_sync_bridge.h" @@ -158,78 +148,7 @@ } // namespace -// Chrome implementation of SyncSessionsClient. Needs to be in a separate class -// due to possible multiple inheritance issues, wherein ChromeSyncClient might -// inherit from other interfaces with same methods. -class SyncSessionsClientImpl : public sync_sessions::SyncSessionsClient { - public: - explicit SyncSessionsClientImpl(Profile* profile) : profile_(profile) { - window_delegates_getter_.reset( -#if defined(OS_ANDROID) - // Android doesn't have multi-profile support, so no need to pass the - // profile in. - new SyncedWindowDelegatesGetterAndroid()); -#else // defined(OS_ANDROID) - new browser_sync::BrowserSyncedWindowDelegatesGetter(profile)); -#endif // defined(OS_ANDROID) - } - ~SyncSessionsClientImpl() override {} - - // SyncSessionsClient implementation. - favicon::FaviconService* GetFaviconService() override { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return FaviconServiceFactory::GetForProfile( - profile_, ServiceAccessType::IMPLICIT_ACCESS); - } - history::HistoryService* GetHistoryService() override { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return HistoryServiceFactory::GetForProfile( - profile_, ServiceAccessType::EXPLICIT_ACCESS); - } - const syncer::DeviceInfo* GetLocalDeviceInfo() override { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return ProfileSyncServiceFactory::GetForProfile(profile_) - ->GetLocalDeviceInfoProvider() - ->GetLocalDeviceInfo(); - } - bool ShouldSyncURL(const GURL& url) const override { - if (url == chrome::kChromeUIHistoryURL) { - // The history page is treated specially as we want it to trigger syncable - // events for UI purposes. - return true; - } - return url.is_valid() && !url.SchemeIs(content::kChromeUIScheme) && - !url.SchemeIs(chrome::kChromeNativeScheme) && !url.SchemeIsFile(); - } - - sync_sessions::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter() - override { - return window_delegates_getter_.get(); - } - - sync_sessions::LocalSessionEventRouter* GetLocalSessionEventRouter() - override { - syncer::SyncableService::StartSyncFlare flare( - sync_start_util::GetFlareForSyncableService(profile_->GetPath())); - sync_sessions::SyncSessionsWebContentsRouter* router = - sync_sessions::SyncSessionsWebContentsRouterFactory::GetForProfile( - profile_); - router->InjectStartSyncFlare(flare); - return router; - } - - private: - Profile* profile_; - std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter> - window_delegates_getter_; - - DISALLOW_COPY_AND_ASSIGN(SyncSessionsClientImpl); -}; - -ChromeSyncClient::ChromeSyncClient(Profile* profile) - : profile_(profile), - sync_sessions_client_(std::make_unique<SyncSessionsClientImpl>(profile)) { -} +ChromeSyncClient::ChromeSyncClient(Profile* profile) : profile_(profile) {} ChromeSyncClient::~ChromeSyncClient() { } @@ -333,6 +252,11 @@ profile_, ServiceAccessType::EXPLICIT_ACCESS); } +sync_sessions::SessionSyncService* ChromeSyncClient::GetSessionSyncService() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + return SessionSyncServiceFactory::GetForProfile(profile_); +} + bool ChromeSyncClient::HasPasswordStore() { return password_store_ != nullptr; } @@ -468,10 +392,6 @@ return extensions_activity_monitor_.GetExtensionsActivity(); } -sync_sessions::SyncSessionsClient* ChromeSyncClient::GetSyncSessionsClient() { - return sync_sessions_client_.get(); -} - base::WeakPtr<syncer::SyncableService> ChromeSyncClient::GetSyncableServiceForType(syncer::ModelType type) { if (!profile_) { // For tests. @@ -553,7 +473,7 @@ case syncer::FAVICON_IMAGES: case syncer::FAVICON_TRACKING: { sync_sessions::FaviconCache* favicons = - ProfileSyncServiceFactory::GetForProfile(profile_)->GetFaviconCache(); + SessionSyncServiceFactory::GetForProfile(profile_)->GetFaviconCache(); return favicons ? favicons->AsWeakPtr() : base::WeakPtr<syncer::SyncableService>(); } @@ -573,8 +493,9 @@ } #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) case syncer::SESSIONS: { - return ProfileSyncServiceFactory::GetForProfile(profile_)-> - GetSessionsSyncableService()->AsWeakPtr(); + return SessionSyncServiceFactory::GetForProfile(profile_) + ->GetSyncableService() + ->AsWeakPtr(); } case syncer::PASSWORDS: { return password_store_.get() @@ -624,10 +545,6 @@ ->GetSyncBridge() ->change_processor() ->GetControllerDelegate(); - case syncer::SESSIONS: { - return ProfileSyncServiceFactory::GetForProfile(profile_) - ->GetSessionSyncControllerDelegate(); - } // We don't exercise this function for certain datatypes, because their // controllers get the delegate elsewhere. @@ -636,6 +553,7 @@ case syncer::AUTOFILL_WALLET_DATA: case syncer::AUTOFILL_WALLET_METADATA: case syncer::BOOKMARKS: + case syncer::SESSIONS: case syncer::TYPED_URLS: NOTREACHED(); return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h index 1baeb45..66674be 100644 --- a/chrome/browser/sync/chrome_sync_client.h +++ b/chrome/browser/sync/chrome_sync_client.h
@@ -47,6 +47,7 @@ bookmarks::BookmarkModel* GetBookmarkModel() override; favicon::FaviconService* GetFaviconService() override; history::HistoryService* GetHistoryService() override; + sync_sessions::SessionSyncService* GetSessionSyncService() override; bool HasPasswordStore() override; base::Closure GetPasswordStateChangedCallback() override; syncer::DataTypeController::TypeVector CreateDataTypeControllers( @@ -55,7 +56,6 @@ invalidation::InvalidationService* GetInvalidationService() override; BookmarkUndoService* GetBookmarkUndoServiceIfExists() override; scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override; - sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override; base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType( syncer::ModelType type) override; base::WeakPtr<syncer::ModelTypeControllerDelegate> @@ -89,8 +89,6 @@ // The task runner for the |web_data_service_|, if any. scoped_refptr<base::SingleThreadTaskRunner> web_data_service_thread_; - std::unique_ptr<sync_sessions::SyncSessionsClient> sync_sessions_client_; - // Generates and monitors the ExtensionsActivity object used by sync. ExtensionsActivityMonitor extensions_activity_monitor_;
diff --git a/chrome/browser/sync/chrome_sync_client_unittest.cc b/chrome/browser/sync/chrome_sync_client_unittest.cc deleted file mode 100644 index fa48932..0000000 --- a/chrome/browser/sync/chrome_sync_client_unittest.cc +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/sync/chrome_sync_client.h" - -#include <memory> -#include <string> - -#include "chrome/common/url_constants.h" -#include "chrome/test/base/testing_profile.h" -#include "components/sync/driver/sync_api_component_factory.h" -#include "components/sync_sessions/sync_sessions_client.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -namespace browser_sync { - -namespace { - -const char kValidUrl[] = "http://www.example.com"; -const char kInvalidUrl[] = "invalid.url"; - -class ChromeSyncClientTest : public testing::Test { - public: - ChromeSyncClientTest() - : profile_(new TestingProfile()), - sync_client_(new ChromeSyncClient(profile_.get())) {} - ~ChromeSyncClientTest() override {} - - ChromeSyncClient* sync_client() { return sync_client_.get(); } - - private: - content::TestBrowserThreadBundle thread_bundle_; - std::unique_ptr<TestingProfile> profile_; - std::unique_ptr<ChromeSyncClient> sync_client_; -}; - -TEST_F(ChromeSyncClientTest, ShouldSyncURL) { - EXPECT_TRUE( - sync_client()->GetSyncSessionsClient()->ShouldSyncURL(GURL(kValidUrl))); - EXPECT_TRUE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL( - GURL("other://anything"))); - EXPECT_TRUE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL( - GURL("chrome-other://anything"))); - - EXPECT_FALSE( - sync_client()->GetSyncSessionsClient()->ShouldSyncURL(GURL(kInvalidUrl))); - EXPECT_FALSE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL( - GURL("file://anything"))); - EXPECT_FALSE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL( - GURL("chrome://anything"))); - EXPECT_FALSE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL( - GURL("chrome-native://anything"))); - - EXPECT_TRUE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL( - GURL(chrome::kChromeUIHistoryURL))); -} - -} // namespace - -} // namespace browser_sync
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc index 33f1f744..e93f595e 100644 --- a/chrome/browser/sync/profile_sync_service_android.cc +++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/sync/profile_sync_service_factory.h" +#include "chrome/browser/sync/session_sync_service_factory.h" #include "chrome/browser/sync/sync_ui_util.h" #include "chrome/common/channel_info.h" #include "chrome/grit/generated_resources.h" @@ -34,6 +35,7 @@ #include "components/sync/driver/sync_service_utils.h" #include "components/sync/engine/net/network_resources.h" #include "components/sync/syncable/read_transaction.h" +#include "components/sync_sessions/session_sync_service.h" #include "components/unified_consent/url_keyed_data_collection_consent_helper.h" #include "content/public/browser/browser_thread.h" #include "google/cacheinvalidation/types.pb.h" @@ -410,7 +412,8 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(profile_); std::string machine_tag = ConvertJavaStringToUTF8(env, tag); - sync_prefs_->SetSyncSessionsGUID(machine_tag); + SessionSyncServiceFactory::GetForProfile(profile_)->SetSyncSessionsGUID( + machine_tag); } jboolean ProfileSyncServiceAndroid::HasKeepEverythingSynced(
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc index 4e283fb..8e487773 100644 --- a/chrome/browser/sync/profile_sync_service_factory.cc +++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -34,7 +34,8 @@ #include "chrome/browser/spellchecker/spellcheck_factory.h" #include "chrome/browser/sync/bookmark_sync_service_factory.h" #include "chrome/browser/sync/chrome_sync_client.h" -#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h" +#include "chrome/browser/sync/model_type_store_service_factory.h" +#include "chrome/browser/sync/session_sync_service_factory.h" #include "chrome/browser/sync/user_event_service_factory.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/undo/bookmark_undo_service_factory.h" @@ -130,7 +131,8 @@ BrowserContextDependencyManager::GetInstance()) { // The ProfileSyncService depends on various SyncableServices being around // when it is shut down. Specify those dependencies here to build the proper - // destruction order. + // destruction order. Note that some of the dependencies are listed here but + // actually plumbed in ChromeSyncClient, which this factory constructs. DependsOn(AboutSigninInternalsFactory::GetInstance()); DependsOn(autofill::PersonalDataManagerFactory::GetInstance()); DependsOn(BookmarkModelFactory::GetInstance()); @@ -151,12 +153,13 @@ DependsOn(invalidation::DeprecatedProfileInvalidationProviderFactory:: GetInstance()); DependsOn(invalidation::ProfileInvalidationProviderFactory::GetInstance()); + DependsOn(ModelTypeStoreServiceFactory::GetInstance()); DependsOn(PasswordStoreFactory::GetInstance()); DependsOn(SpellcheckServiceFactory::GetInstance()); #if BUILDFLAG(ENABLE_SUPERVISED_USERS) DependsOn(SupervisedUserSettingsServiceFactory::GetInstance()); #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) - DependsOn(sync_sessions::SyncSessionsWebContentsRouterFactory::GetInstance()); + DependsOn(SessionSyncServiceFactory::GetInstance()); DependsOn(TemplateURLServiceFactory::GetInstance()); DependsOn(WebDataServiceFactory::GetInstance()); #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -167,12 +170,6 @@ DependsOn(chromeos::SyncedPrintersManagerFactory::GetInstance()); DependsOn(sync_wifi::WifiCredentialSyncableServiceFactory::GetInstance()); #endif // defined(OS_CHROMEOS) - - // The following have not been converted to KeyedServices yet, - // and for now they are explicitly destroyed after the - // BrowserContextDependencyManager is told to DestroyBrowserContextServices, - // so they will be around when the ProfileSyncService is destroyed. - } ProfileSyncServiceFactory::~ProfileSyncServiceFactory() {
diff --git a/chrome/browser/sync/session_sync_service_factory.cc b/chrome/browser/sync/session_sync_service_factory.cc new file mode 100644 index 0000000..f847412 --- /dev/null +++ b/chrome/browser/sync/session_sync_service_factory.cc
@@ -0,0 +1,169 @@ +// 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/sync/session_sync_service_factory.h" + +#include "base/memory/singleton.h" +#include "build/build_config.h" +#include "chrome/browser/favicon/favicon_service_factory.h" +#include "chrome/browser/history/history_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/glue/sync_start_util.h" +#include "chrome/browser/sync/model_type_store_service_factory.h" +#include "chrome/browser/sync/profile_sync_service_factory.h" +#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router.h" +#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h" +#include "chrome/browser/ui/sync/browser_synced_window_delegates_getter.h" +#include "chrome/common/channel_info.h" +#include "chrome/common/url_constants.h" +#include "components/browser_sync/profile_sync_service.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/sync/device_info/local_device_info_provider.h" +#include "components/sync/model/model_type_store_service.h" +#include "components/sync_sessions/session_sync_prefs.h" +#include "components/sync_sessions/session_sync_service.h" +#include "components/sync_sessions/sync_sessions_client.h" + +#if defined(OS_ANDROID) +#include "chrome/browser/sync/glue/synced_window_delegates_getter_android.h" +#endif // defined(OS_ANDROID) + +namespace { + +bool ShouldSyncURLImpl(const GURL& url) { + if (url == chrome::kChromeUIHistoryURL) { + // Whitelist the chrome history page, home for "Tabs from other devices", so + // it can trigger starting up the sync engine. + return true; + } + return url.is_valid() && !url.SchemeIs(content::kChromeUIScheme) && + !url.SchemeIs(chrome::kChromeNativeScheme) && !url.SchemeIsFile(); +} + +// Chrome implementation of SyncSessionsClient. +class SyncSessionsClientImpl : public sync_sessions::SyncSessionsClient { + public: + explicit SyncSessionsClientImpl(Profile* profile) + : profile_(profile), session_sync_prefs_(profile->GetPrefs()) { + window_delegates_getter_ = +#if defined(OS_ANDROID) + // Android doesn't have multi-profile support, so no need to pass the + // profile in. + std::make_unique<browser_sync::SyncedWindowDelegatesGetterAndroid>(); +#else // defined(OS_ANDROID) + std::make_unique<browser_sync::BrowserSyncedWindowDelegatesGetter>( + profile); +#endif // defined(OS_ANDROID) + } + + ~SyncSessionsClientImpl() override {} + + // SyncSessionsClient implementation. + favicon::FaviconService* GetFaviconService() override { + return FaviconServiceFactory::GetForProfile( + profile_, ServiceAccessType::IMPLICIT_ACCESS); + } + + history::HistoryService* GetHistoryService() override { + return HistoryServiceFactory::GetForProfile( + profile_, ServiceAccessType::EXPLICIT_ACCESS); + } + + sync_sessions::SessionSyncPrefs* GetSessionSyncPrefs() override { + return &session_sync_prefs_; + } + + syncer::RepeatingModelTypeStoreFactory GetStoreFactory() override { + return ModelTypeStoreServiceFactory::GetForProfile(profile_) + ->GetStoreFactory(); + } + + const syncer::DeviceInfo* GetLocalDeviceInfo() override { + // Avoid creating ProfileSyncService if there wasn't one, to avoid + // dependency cycles among keyed services. + if (!ProfileSyncServiceFactory::HasProfileSyncService(profile_)) { + return nullptr; + } + return ProfileSyncServiceFactory::GetForProfile(profile_) + ->GetLocalDeviceInfoProvider() + ->GetLocalDeviceInfo(); + } + + bool ShouldSyncURL(const GURL& url) const override { + return ShouldSyncURLImpl(url); + } + + sync_sessions::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter() + override { + return window_delegates_getter_.get(); + } + + sync_sessions::LocalSessionEventRouter* GetLocalSessionEventRouter() + override { + syncer::SyncableService::StartSyncFlare flare( + sync_start_util::GetFlareForSyncableService(profile_->GetPath())); + sync_sessions::SyncSessionsWebContentsRouter* router = + sync_sessions::SyncSessionsWebContentsRouterFactory::GetForProfile( + profile_); + // TODO(mastiz): Injecting a start flare as a side effect of what seems to + // be a getter is error-prone. In fact, we seem to call this function very + // early for the USS implementation. + router->InjectStartSyncFlare(flare); + return router; + } + + void NotifyForeignSessionUpdated() override { + if (!ProfileSyncServiceFactory::HasProfileSyncService(profile_)) { + return; + } + ProfileSyncServiceFactory::GetForProfile(profile_) + ->NotifyForeignSessionUpdated(); + } + + private: + Profile* const profile_; + std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter> + window_delegates_getter_; + sync_sessions::SessionSyncPrefs session_sync_prefs_; + + DISALLOW_COPY_AND_ASSIGN(SyncSessionsClientImpl); +}; + +} // namespace + +// static +sync_sessions::SessionSyncService* SessionSyncServiceFactory::GetForProfile( + Profile* profile) { + return static_cast<sync_sessions::SessionSyncService*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +SessionSyncServiceFactory* SessionSyncServiceFactory::GetInstance() { + return base::Singleton<SessionSyncServiceFactory>::get(); +} + +// static +bool SessionSyncServiceFactory::ShouldSyncURLForTesting(const GURL& url) { + return ShouldSyncURLImpl(url); +} + +SessionSyncServiceFactory::SessionSyncServiceFactory() + : BrowserContextKeyedServiceFactory( + "SessionSyncService", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(FaviconServiceFactory::GetInstance()); + DependsOn(HistoryServiceFactory::GetInstance()); + DependsOn(ModelTypeStoreServiceFactory::GetInstance()); + DependsOn(sync_sessions::SyncSessionsWebContentsRouterFactory::GetInstance()); +} + +SessionSyncServiceFactory::~SessionSyncServiceFactory() {} + +KeyedService* SessionSyncServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + Profile* profile = Profile::FromBrowserContext(context); + return new sync_sessions::SessionSyncService( + chrome::GetChannel(), std::make_unique<SyncSessionsClientImpl>(profile)); +}
diff --git a/chrome/browser/sync/session_sync_service_factory.h b/chrome/browser/sync/session_sync_service_factory.h new file mode 100644 index 0000000..e31389f --- /dev/null +++ b/chrome/browser/sync/session_sync_service_factory.h
@@ -0,0 +1,45 @@ +// 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_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_ + +#include <memory> + +#include "base/macros.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class GURL; +class Profile; + +namespace base { +template <typename T> +struct DefaultSingletonTraits; +} // namespace base + +namespace sync_sessions { +class SessionSyncService; +} // namespace sync_sessions + +class SessionSyncServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static sync_sessions::SessionSyncService* GetForProfile(Profile* profile); + static SessionSyncServiceFactory* GetInstance(); + + static bool ShouldSyncURLForTesting(const GURL& url); + + private: + friend struct base::DefaultSingletonTraits<SessionSyncServiceFactory>; + + SessionSyncServiceFactory(); + ~SessionSyncServiceFactory() override; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + + DISALLOW_COPY_AND_ASSIGN(SessionSyncServiceFactory); +}; + +#endif // CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_
diff --git a/chrome/browser/sync/session_sync_service_factory_unittest.cc b/chrome/browser/sync/session_sync_service_factory_unittest.cc new file mode 100644 index 0000000..e3a3f41a --- /dev/null +++ b/chrome/browser/sync/session_sync_service_factory_unittest.cc
@@ -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. + +#include "chrome/browser/sync/session_sync_service_factory.h" + +#include "chrome/common/url_constants.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace { + +const char kValidUrl[] = "http://www.example.com"; +const char kInvalidUrl[] = "invalid.url"; + +TEST(SessionSyncServiceFactoryTest, ShouldSyncURL) { + EXPECT_TRUE( + SessionSyncServiceFactory::ShouldSyncURLForTesting(GURL(kValidUrl))); + EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL("other://anything"))); + EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL("chrome-other://anything"))); + + EXPECT_FALSE( + SessionSyncServiceFactory::ShouldSyncURLForTesting(GURL(kInvalidUrl))); + EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL("file://anything"))); + EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL("chrome://anything"))); + EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL("chrome-native://anything"))); + + EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL(chrome::kChromeUIHistoryURL))); +} + +} // namespace
diff --git a/chrome/browser/sync/user_event_service_factory.cc b/chrome/browser/sync/user_event_service_factory.cc index cf817ba..901a6595 100644 --- a/chrome/browser/sync/user_event_service_factory.cc +++ b/chrome/browser/sync/user_event_service_factory.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/model_type_store_service_factory.h" #include "chrome/browser/sync/profile_sync_service_factory.h" +#include "chrome/browser/sync/session_sync_service_factory.h" #include "chrome/common/channel_info.h" #include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" @@ -21,6 +22,7 @@ #include "components/sync/user_events/no_op_user_event_service.h" #include "components/sync/user_events/user_event_service_impl.h" #include "components/sync/user_events/user_event_sync_bridge.h" +#include "components/sync_sessions/session_sync_service.h" namespace browser_sync { @@ -41,6 +43,7 @@ "UserEventService", BrowserContextDependencyManager::GetInstance()) { DependsOn(ModelTypeStoreServiceFactory::GetInstance()); + DependsOn(SessionSyncServiceFactory::GetInstance()); // TODO(vitaliii): This is missing // DependsOn(ProfileSyncServiceFactory::GetInstance()), which we can't // simply add because ProfileSyncServiceFactory itself depends on this @@ -70,7 +73,7 @@ chrome::GetChannel())); auto bridge = std::make_unique<syncer::UserEventSyncBridge>( std::move(store_factory), std::move(change_processor), - sync_service->GetGlobalIdMapper()); + SessionSyncServiceFactory::GetForProfile(profile)->GetGlobalIdMapper()); return new syncer::UserEventServiceImpl(sync_service, std::move(bridge)); }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 81a63654..0d17497 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -75,10 +75,6 @@ "cocoa/browser_window_utils.mm", "cocoa/bubble_anchor_helper.h", "cocoa/bubble_anchor_helper.mm", - "cocoa/bubble_combobox.h", - "cocoa/bubble_combobox.mm", - "cocoa/bubble_view.h", - "cocoa/bubble_view.mm", "cocoa/certificate_viewer_mac_cocoa.h", "cocoa/certificate_viewer_mac_cocoa.mm", "cocoa/chrome_browser_window.h", @@ -109,8 +105,6 @@ "cocoa/constrained_window/constrained_window_web_dialog_sheet.h", "cocoa/constrained_window/constrained_window_web_dialog_sheet.mm", "cocoa/create_native_web_modal_manager_cocoa.mm", - "cocoa/dev_tools_controller.h", - "cocoa/dev_tools_controller.mm", "cocoa/drag_util.h", "cocoa/drag_util.mm", "cocoa/extensions/extension_keybinding_registry_cocoa.h", @@ -148,14 +142,6 @@ "cocoa/image_button_cell.mm", "cocoa/javascript_app_modal_dialog_cocoa.h", "cocoa/javascript_app_modal_dialog_cocoa.mm", - "cocoa/location_bar/autocomplete_text_field.h", - "cocoa/location_bar/autocomplete_text_field.mm", - "cocoa/location_bar/autocomplete_text_field_cell.h", - "cocoa/location_bar/autocomplete_text_field_cell.mm", - "cocoa/location_bar/autocomplete_text_field_editor.h", - "cocoa/location_bar/autocomplete_text_field_editor.mm", - "cocoa/location_bar/location_bar_decoration.h", - "cocoa/location_bar/location_bar_decoration.mm", "cocoa/location_bar/location_bar_view_mac.h", "cocoa/location_bar/location_bar_view_mac.mm", "cocoa/main_menu_item.h", @@ -163,16 +149,6 @@ "cocoa/menu_button.mm", "cocoa/nsview_additions.h", "cocoa/nsview_additions.mm", - "cocoa/omnibox/omnibox_popup_cell.h", - "cocoa/omnibox/omnibox_popup_cell.mm", - "cocoa/omnibox/omnibox_popup_matrix.h", - "cocoa/omnibox/omnibox_popup_matrix.mm", - "cocoa/omnibox/omnibox_popup_separator_view.h", - "cocoa/omnibox/omnibox_popup_separator_view.mm", - "cocoa/omnibox/omnibox_popup_view_mac.h", - "cocoa/omnibox/omnibox_popup_view_mac.mm", - "cocoa/omnibox/omnibox_view_mac.h", - "cocoa/omnibox/omnibox_view_mac.mm", "cocoa/rect_path_utils.h", "cocoa/rect_path_utils.mm", "cocoa/restart_browser.h", @@ -188,8 +164,6 @@ "cocoa/ssl_client_certificate_selector_cocoa.h", "cocoa/ssl_client_certificate_selector_cocoa.mm", "cocoa/spinner_util.h", - "cocoa/status_bubble_mac.h", - "cocoa/status_bubble_mac.mm", "cocoa/styled_text_field.h", "cocoa/styled_text_field.mm", "cocoa/styled_text_field_cell.h", @@ -2153,7 +2127,6 @@ "cocoa/confirm_quit_panel_controller.mm", "cocoa/dock_icon.h", "cocoa/dock_icon.mm", - "cocoa/download/download_started_animation_mac.mm", "cocoa/first_run_dialog.h", "cocoa/first_run_dialog.mm", "cocoa/first_run_dialog_controller.h", @@ -2595,8 +2568,6 @@ "views/device_chooser_content_view.cc", "views/device_chooser_content_view.h", "views/download/download_danger_prompt_views.cc", - "views/download/download_feedback_dialog_view.cc", - "views/download/download_feedback_dialog_view.h", "views/download/download_in_progress_dialog_view.cc", "views/download/download_in_progress_dialog_view.h", "views/download/download_item_view.cc", @@ -3684,6 +3655,7 @@ "//chrome/browser/ui/webui/reset_password:mojo_bindings", "//chrome/common/safe_browsing:proto", "//components/safe_browsing:csd_proto", + "//components/safe_browsing/password_protection:password_protection_metrics_util", ] }
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 26b5d17..0605c54 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -1221,6 +1221,11 @@ return window_->GetTopControlsHeight(); } +bool Browser::DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const { + return window_->DoBrowserControlsShrinkRendererSize(contents); +} + void Browser::SetTopControlsGestureScrollInProgress(bool in_progress) { window_->SetTopControlsGestureScrollInProgress(in_progress); }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index b51c713aa..615e1a5 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -473,6 +473,8 @@ void SetTopControlsShownRatio(content::WebContents* web_contents, float ratio) override; int GetTopControlsHeight() const override; + bool DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const override; void SetTopControlsGestureScrollInProgress(bool in_progress) override; bool CanOverscrollContent() const override; bool ShouldPreserveAbortedURLs(content::WebContents* source) override;
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h index 43f07ff..25cf05ad 100644 --- a/chrome/browser/ui/browser_window.h +++ b/chrome/browser/ui/browser_window.h
@@ -120,6 +120,37 @@ virtual void SetTopControlsShownRatio(content::WebContents* web_contents, float ratio) = 0; + // Whether or not the renderer's viewport size should be shrunk by the height + // of the browser's top controls. + // As top-chrome is slided up or down, we don't actually resize the web + // contents (for perf reasons) but we have to do a bunch of adjustments on the + // renderer side to make it appear to the user like we're resizing things + // smoothly: + // + // 1) Expose content beyond the web contents rect by expanding the clip. + // 2) Push bottom-fixed elements around until we get a resize. As top-chrome + // hides, we push the fixed elements down by an equivalent amount so that + // they appear to stay fixed to the viewport bottom. + // + // Only when the user releases their finger to finish the scroll do we + // actually resize the web contents and clear these adjustments. So web + // contents has two possible sizes, viewport filling and shrunk by the top + // controls. + // + // The GetTopControlsHeight is a static number that never changes (as long as + // the top-chrome slide with gesture scrolls feature is enabled). To get the + // actual "showing" height as the user sees, you multiply this by the shown + // ratio. However, it's not enough to know this value, the renderer also needs + // to know which direction it should be doing the above-mentioned adjustments. + // That's what the DoBrowserControlsShrinkRendererSize bit is for. It tells + // the renderer whether it's currently in the "viewport filling" or the + // "shrunk by top controls" state. + // The returned value should never change while sliding top-chrome is in + // progress (either due to an in-progress gesture scroll, or due to a + // renderer-initiated animation of the top controls shown ratio). + virtual bool DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const = 0; + // Returns the height of the browser's top controls. This height doesn't // change with the current shown ratio above. Renderers will call this to // calculate the top-chrome shown ratio from the gesture scroll offset.
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h index d5c965e..74d67ac2 100644 --- a/chrome/browser/ui/cocoa/browser_window_cocoa.h +++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -54,6 +54,8 @@ gfx::NativeWindow GetNativeWindow() const override; void SetTopControlsShownRatio(content::WebContents* web_contents, float ratio) override; + bool DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const override; int GetTopControlsHeight() const override; void SetTopControlsGestureScrollInProgress(bool in_progress) override; StatusBubble* GetStatusBubble() override;
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm index b6ee3a8..2fb2747 100644 --- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -39,7 +39,6 @@ #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" #import "chrome/browser/ui/cocoa/nsmenuitem_additions.h" #include "chrome/browser/ui/cocoa/restart_browser.h" -#include "chrome/browser/ui/cocoa/status_bubble_mac.h" #include "chrome/browser/ui/cocoa/task_manager_mac.h" #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" @@ -247,6 +246,12 @@ NOTIMPLEMENTED(); } +bool BrowserWindowCocoa::DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const { + NOTIMPLEMENTED(); + return false; +} + int BrowserWindowCocoa::GetTopControlsHeight() const { NOTIMPLEMENTED(); return 0; @@ -258,7 +263,7 @@ } StatusBubble* BrowserWindowCocoa::GetStatusBubble() { - return [controller_ statusBubble]; + return nullptr; } void BrowserWindowCocoa::UpdateTitleBar() { @@ -409,7 +414,7 @@ } PageActionIconContainer* BrowserWindowCocoa::GetPageActionIconContainer() { - return [controller_ locationBarBridge]; + return nullptr; } LocationBar* BrowserWindowCocoa::GetLocationBar() const { @@ -417,7 +422,6 @@ } void BrowserWindowCocoa::SetFocusToLocationBar(bool select_all) { - [controller_ focusLocationBar:select_all ? YES : NO]; } void BrowserWindowCocoa::UpdateReloadStopState(bool is_loading, bool force) { @@ -541,10 +545,6 @@ void BrowserWindowCocoa::UserChangedTheme() { [controller_ userChangedTheme]; - LocationBarViewMac* locationBar = [controller_ locationBarBridge]; - if (locationBar) { - locationBar->OnThemeChanged(); - } } void BrowserWindowCocoa::ShowAppMenu() {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h index 7e0ab8f..3ffb675 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.h +++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -36,7 +36,6 @@ class BrowserWindowCocoa; @class BrowserWindowFullscreenTransition; @class BrowserWindowTouchBarController; -@class DevToolsController; class ExtensionKeybindingRegistryCocoa; class ExclusiveAccessController; class ExclusiveAccessContext; @@ -46,7 +45,6 @@ @class FullscreenWindow; class LocationBarViewMac; @class OverlayableContentsController; -class StatusBubbleMac; @class TabStripControllerCocoa; @class TabStripView; @class ToolbarController; @@ -74,7 +72,6 @@ std::unique_ptr<BrowserWindowCocoa> windowShim_; base::scoped_nsobject<ToolbarController> toolbarController_; base::scoped_nsobject<TabStripControllerCocoa> tabStripController_; - base::scoped_nsobject<DevToolsController> devToolsController_; base::scoped_nsobject<OverlayableContentsController> overlayableContentsController_; base::scoped_nsobject<FullscreenToolbarControllerCocoa> @@ -84,12 +81,6 @@ fullscreenTransition_; base::scoped_nsobject<BrowserWindowTouchBarController> touchBarController_; - // Strong. StatusBubble is a special case of a strong reference that - // we don't wrap in a scoped_ptr because it is acting the same - // as an NSWindowController in that it wraps a window that must - // be shut down before our destructors are called. - StatusBubbleMac* statusBubble_; - BOOL initializing_; // YES while we are currently in initWithBrowser: BOOL ownsBrowser_; // Only ever NO when testing @@ -203,9 +194,6 @@ // Return a weak pointer to the tab strip controller. - (TabStripControllerCocoa*)tabStripController; -// Access the C++ bridge object representing the status bubble for the window. -- (StatusBubbleMac*)statusBubble; - // Access the C++ bridge object representing the location bar. - (LocationBarViewMac*)locationBarBridge; @@ -273,8 +261,6 @@ // Returns YES if the bookmark bar is currently animating. - (BOOL)isBookmarkBarAnimating; -- (DevToolsController*)devToolsController; - // The user changed the theme. - (void)userChangedTheme; @@ -284,9 +270,6 @@ - (BOOL)handledByExtensionCommand:(NSEvent*)event priority:(ui::AcceleratorManager::HandlerPriority)priority; -// Delegate method for the status bubble to query its base frame. -- (NSRect)statusBubbleBaseFrame; - // Dismiss the permission bubble - (void)dismissPermissionBubble; @@ -353,11 +336,6 @@ // otherwise). (E.g., normal browser windows do, pop-ups do not.) - (BOOL)hasToolbar; -// Called to check whether or not this window has a location bar (YES if it -// does, NO otherwise). (E.g., normal browser windows do, pop-ups may or may -// not.) -- (BOOL)hasLocationBar; - // Called to check whether or not this window can have bookmark bar (YES if it // does, NO otherwise). (E.g., normal browser windows may, pop-ups may not.) - (BOOL)supportsBookmarkBar;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index bae55c6a..679f690e 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -47,7 +47,6 @@ #import "chrome/browser/ui/cocoa/browser_window_controller_private.h" #import "chrome/browser/ui/cocoa/browser_window_layout.h" #import "chrome/browser/ui/cocoa/browser_window_utils.h" -#import "chrome/browser/ui/cocoa/dev_tools_controller.h" #include "chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.h" #import "chrome/browser/ui/cocoa/fast_resize_view.h" #import "chrome/browser/ui/cocoa/framed_browser_window.h" @@ -56,9 +55,6 @@ #include "chrome/browser/ui/cocoa/fullscreen_placeholder_view.h" #import "chrome/browser/ui/cocoa/fullscreen_window.h" #include "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" -#import "chrome/browser/ui/cocoa/status_bubble_mac.h" #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" @@ -289,20 +285,11 @@ // of the toolbar/tabstrip is known. windowShim_->SetBounds(windowRect); - // Create a sub-controller for the docked devTools and add its view to the - // hierarchy. - devToolsController_.reset([[DevToolsController alloc] init]); - [[devToolsController_ view] setFrame:[[self tabContentArea] bounds]]; - [[self tabContentArea] addSubview:[devToolsController_ view]]; - // Create the overlayable contents controller. This provides the switch // view that TabStripControllerCocoa needs. overlayableContentsController_.reset( [[OverlayableContentsController alloc] init]); - [[overlayableContentsController_ view] - setFrame:[[devToolsController_ view] bounds]]; - [[devToolsController_ view] - addSubview:[overlayableContentsController_ view]]; + [[self tabContentArea] addSubview:[overlayableContentsController_ view]]; // Create a controller for the tab strip, giving it the model object for // this window's Browser and the tab strip view. The controller will handle @@ -319,8 +306,7 @@ profile:browser->profile() browser:browser]); [[toolbarController_ toolbarView] setResizeDelegate:self]; - [toolbarController_ setHasToolbar:[self hasToolbar] - hasLocationBar:[self hasLocationBar]]; + [toolbarController_ setHasToolbar:[self hasToolbar] hasLocationBar:NO]; [self updateFullscreenCollectionBehavior]; @@ -347,9 +333,6 @@ } } - // Create the bridge for the status bubble. - statusBubble_ = new StatusBubbleMac([self window], self); - extensionKeybindingRegistry_.reset( new ExtensionKeybindingRegistryCocoa(browser_->profile(), [self window], @@ -445,10 +428,6 @@ return tabStripController_.get(); } -- (StatusBubbleMac*)statusBubble { - return statusBubble_; -} - - (LocationBarViewMac*)locationBarBridge { return [toolbarController_ locationBarBridge]; } @@ -495,11 +474,6 @@ DCHECK(browser_->tab_strip_model()->empty()); [savedRegularWindow_ close]; - // We delete statusBubble here because we need to kill off the dependency - // that its window has on our window before our window goes away. - delete statusBubble_; - statusBubble_ = NULL; - // We can't actually use |-autorelease| here because there's an embedded // run loop in the |-performClose:| which contains its own autorelease pool. // Instead call it after a zero-length delay, which gets us back to the main @@ -510,8 +484,6 @@ } - (void)updateDevToolsForContents:(WebContents*)contents { - [devToolsController_ updateDevToolsForWebContents:contents - withProfile:browser_->profile()]; } // Called when the user wants to close a window or from the shutdown process. @@ -905,13 +877,6 @@ content::NativeWebKeyboardEvent(event), priority); } -// StatusBubble delegate method: tell the status bubble the frame it should -// position itself in. -- (NSRect)statusBubbleBaseFrame { - NSView* view = [overlayableContentsController_ view]; - return [view convertRect:[view bounds] toView:nil]; -} - - (void)updateToolbarWithContents:(WebContents*)tab { [toolbarController_ updateToolbarWithContents:tab]; } @@ -1082,7 +1047,6 @@ // Make the location bar the first responder, if possible. - (void)focusLocationBar:(BOOL)selectAll { - [toolbarController_ focusLocationBar:selectAll]; } - (void)focusTabContents { @@ -1241,10 +1205,6 @@ return NO; } -- (DevToolsController*)devToolsController { - return devToolsController_; -} - - (NSWindow*)createFullscreenWindow { NSWindow* window = [[[FullscreenWindow alloc] initForScreen:[[self window] screen]] autorelease]; @@ -1301,8 +1261,6 @@ // Update all the UI bits. windowShim_->UpdateTitleBar(); - [devToolsController_ updateDevToolsForWebContents:contents - withProfile:browser_->profile()]; } - (void)onTabChanged:(TabChangeType)change withContents:(WebContents*)contents { @@ -1404,13 +1362,6 @@ // Delegate method called when window is resized. - (void)windowDidResize:(NSNotification*)notification { [self saveWindowPositionIfNeeded]; - - // Resize (and possibly move) the status bubble. Note that we may get called - // when the status bubble does not exist. - if (statusBubble_) { - statusBubble_->UpdateSizeAndPosition(); - } - [self updatePermissionBubbleAnchor]; } @@ -1676,8 +1627,7 @@ } - (BOOL)floatingBarHasFocus { - NSResponder* focused = [[self window] firstResponder]; - return [focused isKindOfClass:[AutocompleteTextFieldEditor class]]; + return NO; } - (BOOL)isFullscreenForTabContentOrExtension { @@ -1712,10 +1662,6 @@ [self supportsWindowFeature:Browser::FEATURE_TOOLBAR]; } -- (BOOL)hasLocationBar { - return [self supportsWindowFeature:Browser::FEATURE_LOCATIONBAR]; -} - - (BOOL)supportsBookmarkBar { return NO; }
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm index a0b5d38..52bc156 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
@@ -32,7 +32,6 @@ #import "chrome/browser/ui/cocoa/fast_resize_view.h" #import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h" #import "chrome/browser/ui/cocoa/history_overlay_controller.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" @@ -548,7 +547,6 @@ // Insert a non-NTP new tab in the foreground. AddTabAtIndex(0, GURL("http://google.com"), ui::PAGE_TRANSITION_LINK); - ASSERT_FALSE([[controller() toolbarController] isLocationBarFocused]); EXPECT_TRUE([fullscreenToolbarController isRevealingToolbar]); [fullscreenToolbarController resetToolbarFlag]; @@ -559,19 +557,16 @@ // Insert a NTP new tab in the foreground. AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_LINK); - ASSERT_TRUE([[controller() toolbarController] isLocationBarFocused]); EXPECT_TRUE([fullscreenToolbarController isRevealingToolbar]); [fullscreenToolbarController resetToolbarFlag]; AddTabAtBackground(1, GURL("http://google.com")); - ASSERT_TRUE([[controller() toolbarController] isLocationBarFocused]); EXPECT_TRUE([fullscreenToolbarController isRevealingToolbar]); [fullscreenToolbarController resetToolbarFlag]; // Switch to a non-NTP tab. TabStripModel* model = browser()->tab_strip_model(); model->ActivateTabAt(1, true); - ASSERT_FALSE([[controller() toolbarController] isLocationBarFocused]); EXPECT_TRUE([fullscreenToolbarController isRevealingToolbar]); [fullscreenToolbarController resetToolbarFlag]; }
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm index 17b26c7..bdf54b92 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -25,15 +25,12 @@ #import "chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h" #import "chrome/browser/ui/cocoa/browser_window_layout.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h" -#import "chrome/browser/ui/cocoa/dev_tools_controller.h" #import "chrome/browser/ui/cocoa/fast_resize_view.h" #import "chrome/browser/ui/cocoa/floating_bar_backing_view.h" #import "chrome/browser/ui/cocoa/framed_browser_window.h" #import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_cocoa.h" #import "chrome/browser/ui/cocoa/fullscreen_window.h" #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h" -#include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" -#import "chrome/browser/ui/cocoa/status_bubble_mac.h" #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" @@ -345,10 +342,6 @@ [self setWindow:destWindow]; [destWindow setWindowController:[self nsWindowController]]; - // Move the status bubble over, if we have one. - if (statusBubble_) - statusBubble_->SwitchParentWindow(destWindow); - [self updatePermissionBubbleAnchor]; // Move the title over. @@ -723,7 +716,7 @@ [fullscreenToolbarController_ enterFullscreenMode]; if (!floatingBarBackingView_.get() && - ([self hasTabStrip] || [self hasToolbar] || [self hasLocationBar])) { + ([self hasTabStrip] || [self hasToolbar])) { floatingBarBackingView_.reset( [[FloatingBarBackingView alloc] initWithFrame:NSZeroRect]); [floatingBarBackingView_ @@ -832,8 +825,6 @@ [layout setHasToolbar:[self hasToolbar]]; [layout setToolbarHeight:NSHeight([[toolbarController_ view] bounds])]; - - [layout setHasLocationBar:[self hasLocationBar]]; } - (void)applyLayout:(BrowserWindowLayout*)layout { @@ -898,21 +889,6 @@ return; } - // Removing the location bar from the window causes it to resign first - // responder. Remember the location bar's focus state in order to restore - // it before returning. - BOOL locationBarHadFocus = [toolbarController_ locationBarHasFocus]; - FullscreenToolbarVisibilityLockController* visibilityLockController = nil; - if (locationBarHadFocus) { - // The location bar, by being focused, has a visibility lock on the toolbar, - // and the location bar's removal from the view hierarchy will allow the - // toolbar to hide. Create a temporary visibility lock on the toolbar for - // the duration of the view hierarchy change. - visibilityLockController = [self fullscreenToolbarVisibilityLockController]; - [visibilityLockController lockToolbarVisibilityForOwner:self - withAnimation:NO]; - } - // Remove all subviews that aren't the tabContentArea. for (NSView* view in [[[self.chromeContentView subviews] copy] autorelease]) { if (view != tabContentArea) @@ -935,14 +911,6 @@ positioned:NSWindowAbove relativeTo:nil]; } - - // Restore the location bar's focus state and remove the temporary visibility - // lock. - if (locationBarHadFocus) { - [self focusLocationBar:YES]; - [visibilityLockController releaseToolbarVisibilityForOwner:self - withAnimation:NO]; - } } - (BOOL)shouldUseCustomAppKitFullscreenTransition:(BOOL)enterFullScreen {
diff --git a/chrome/browser/ui/cocoa/bubble_anchor_helper.mm b/chrome/browser/ui/cocoa/bubble_anchor_helper.mm index 66be9831..e432ce4 100644 --- a/chrome/browser/ui/cocoa/bubble_anchor_helper.mm +++ b/chrome/browser/ui/cocoa/bubble_anchor_helper.mm
@@ -13,7 +13,6 @@ #import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h" #import "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" #import "ui/base/cocoa/cocoa_base_utils.h" bool HasVisibleLocationBarForBrowser(Browser* browser) {
diff --git a/chrome/browser/ui/cocoa/bubble_combobox.h b/chrome/browser/ui/cocoa/bubble_combobox.h deleted file mode 100644 index d7ee71e7..0000000 --- a/chrome/browser/ui/cocoa/bubble_combobox.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 CHROME_BROWSER_UI_COCOA_BUBBLE_COMBOBOX_H_ -#define CHROME_BROWSER_UI_COCOA_BUBBLE_COMBOBOX_H_ - -#import <Cocoa/Cocoa.h> - -namespace ui { -class ComboboxModel; -} // namespace ui - -// An NSPopUpButton that auto-populates from a ui::ComboboxModel. -// By default it comes with a border, small font size, and small control size. -@interface BubbleCombobox : NSPopUpButton -// Does not take ownership nor store a pointer to |model|; it is used only for -// population of the combobox. -- (id)initWithFrame:(NSRect)frame - pullsDown:(BOOL)pullsDown - model:(ui::ComboboxModel*)model; -@end - -#endif // CHROME_BROWSER_UI_COCOA_BUBBLE_COMBOBOX_H_
diff --git a/chrome/browser/ui/cocoa/bubble_combobox.mm b/chrome/browser/ui/cocoa/bubble_combobox.mm deleted file mode 100644 index b093fcc..0000000 --- a/chrome/browser/ui/cocoa/bubble_combobox.mm +++ /dev/null
@@ -1,32 +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 "chrome/browser/ui/cocoa/bubble_combobox.h" - -#include "base/strings/sys_string_conversions.h" -#include "ui/base/models/combobox_model.h" - -@implementation BubbleCombobox - -- (id)initWithFrame:(NSRect)frame - pullsDown:(BOOL)pullsDown - model:(ui::ComboboxModel*)model { - if ((self = [super initWithFrame:frame pullsDown:pullsDown])) { - [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; - [self setBordered:YES]; - [[self cell] setControlSize:NSSmallControlSize]; - - for (int i = 0; i < model->GetItemCount(); ++i) { - if (model->IsItemSeparatorAt(i)) - [[self menu] addItem:[NSMenuItem separatorItem]]; - else - [self addItemWithTitle:base::SysUTF16ToNSString(model->GetItemAt(i))]; - } - - [self selectItemAtIndex:model->GetDefaultIndex()]; - } - return self; -} - -@end
diff --git a/chrome/browser/ui/cocoa/bubble_view.h b/chrome/browser/ui/cocoa/bubble_view.h deleted file mode 100644 index feeece3..0000000 --- a/chrome/browser/ui/cocoa/bubble_view.h +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright (c) 2011 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_COCOA_BUBBLE_VIEW_H_ -#define CHROME_BROWSER_UI_COCOA_BUBBLE_VIEW_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" - -// A view class that looks like a "bubble" with rounded corners and displays -// text inside. Can be themed. To put flush against the sides of a window, the -// corner flags can be adjusted. - -// Constants that define where the bubble will have a rounded corner. If -// not set, the corner will be square. -enum { - kRoundedTopLeftCorner = 1, - kRoundedTopRightCorner = 1 << 1, - kRoundedBottomLeftCorner = 1 << 2, - kRoundedBottomRightCorner = 1 << 3, - kRoundedAllCorners = kRoundedTopLeftCorner | - kRoundedTopRightCorner | - kRoundedBottomLeftCorner | - kRoundedBottomRightCorner -}; - -// Constants that affect where the text is positioned within the view. They -// are exposed in case anyone needs to use the padding to set the content string -// length appropriately based on available space (such as eliding a URL). -enum { - kBubbleViewTextPositionX = 4, - kBubbleViewTextPositionY = 2 -}; - -@interface BubbleView : NSView { - @private - base::scoped_nsobject<NSString> content_; - unsigned long cornerFlags_; - // The window from which we get the theme used to draw. In some cases, - // it might not be the window we're in. As a result, this may or may not - // directly own us, so it needs to be weak to prevent a cycle. - NSWindow* themeProvider_; -} - -// Sets the string displayed in the bubble. A copy of the string is made. -- (void)setContent:(NSString*)content; - -// Sets which corners will be rounded. -- (void)setCornerFlags:(unsigned long)flags; - -// Sets the window whose theme is used to draw. -- (void)setThemeProvider:(NSWindow*)provider; - -// The font used to display the content string. -- (NSFont*)font; - -@end - -// APIs exposed only for testing. -@interface BubbleView(TestingOnly) -- (NSString*)content; -- (unsigned long)cornerFlags; -@end - -#endif // CHROME_BROWSER_UI_COCOA_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/bubble_view.mm b/chrome/browser/ui/cocoa/bubble_view.mm deleted file mode 100644 index 6eb0ec5..0000000 --- a/chrome/browser/ui/cocoa/bubble_view.mm +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/bubble_view.h" - -#include "chrome/browser/themes/theme_properties.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSBezierPath+RoundRect.h" -#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSColor+Luminance.h" -#include "ui/base/theme_provider.h" - -// The roundedness of the edges of the bubble. This matches the value used on -// Lion for window corners. -const int kBubbleCornerRadius = 3; -const float kWindowEdge = 0.7f; - -@implementation BubbleView - -- (id)initWithFrame:(NSRect)frame { - if ((self = [super initWithFrame:frame])) { - cornerFlags_ = kRoundedAllCorners; - } - return self; -} - -// Sets the string displayed in the bubble. A copy of the string is made. -- (void)setContent:(NSString*)content { - if ([content_ isEqualToString:content]) - return; - content_.reset([content copy]); - [self setNeedsDisplay:YES]; -} - -// Sets which corners will be rounded. -- (void)setCornerFlags:(unsigned long)flags { - if (cornerFlags_ == flags) - return; - cornerFlags_ = flags; - [self setNeedsDisplay:YES]; -} - -- (void)setThemeProvider:(NSWindow*)provider { - if (themeProvider_ == provider) - return; - themeProvider_ = provider; - [self setNeedsDisplay:YES]; -} - -- (NSString*)content { - return content_.get(); -} - -- (unsigned long)cornerFlags { - return cornerFlags_; -} - -// The font used to display the content string. -- (NSFont*)font { - return [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; -} - -// Draws the themed background and the text. Will draw a gray bg if no theme. -- (void)drawRect:(NSRect)rect { - float topLeftRadius = - cornerFlags_ & kRoundedTopLeftCorner ? kBubbleCornerRadius : 0; - float topRightRadius = - cornerFlags_ & kRoundedTopRightCorner ? kBubbleCornerRadius : 0; - float bottomLeftRadius = - cornerFlags_ & kRoundedBottomLeftCorner ? kBubbleCornerRadius : 0; - float bottomRightRadius = - cornerFlags_ & kRoundedBottomRightCorner ? kBubbleCornerRadius : 0; - - const ui::ThemeProvider* themeProvider = themeProvider_ - ? [themeProvider_ themeProvider] - : [[self window] themeProvider]; - - // Background / Edge - - NSRect bounds = [self bounds]; - bounds = NSInsetRect(bounds, 0.5, 0.5); - NSBezierPath* border = - [NSBezierPath gtm_bezierPathWithRoundRect:bounds - topLeftCornerRadius:topLeftRadius - topRightCornerRadius:topRightRadius - bottomLeftCornerRadius:bottomLeftRadius - bottomRightCornerRadius:bottomRightRadius]; - - if (themeProvider) - [themeProvider->GetNSColor(ThemeProperties::COLOR_TOOLBAR) set]; - [border fill]; - - [[NSColor colorWithDeviceWhite:kWindowEdge alpha:1.0f] set]; - [border stroke]; - - // Text - NSColor* textColor = [NSColor blackColor]; - if (themeProvider) - textColor = themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT); - NSFont* textFont = [self font]; - base::scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]); - [textShadow setShadowBlurRadius:0.0f]; - [textShadow.get() setShadowColor:[textColor gtm_legibleTextColor]]; - [textShadow.get() setShadowOffset:NSMakeSize(0.0f, -1.0f)]; - - NSDictionary* textDict = [NSDictionary dictionaryWithObjectsAndKeys: - textColor, NSForegroundColorAttributeName, - textFont, NSFontAttributeName, - textShadow.get(), NSShadowAttributeName, - nil]; - [content_ drawAtPoint:NSMakePoint(kBubbleViewTextPositionX, - kBubbleViewTextPositionY) - withAttributes:textDict]; -} - -@end
diff --git a/chrome/browser/ui/cocoa/bubble_view_unittest.mm b/chrome/browser/ui/cocoa/bubble_view_unittest.mm deleted file mode 100644 index 7749950..0000000 --- a/chrome/browser/ui/cocoa/bubble_view_unittest.mm +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/bubble_view.h" -#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#import "testing/gtest_mac.h" - -class BubbleViewTest : public CocoaTest { - public: - BubbleViewTest() { - NSRect frame = NSMakeRect(0, 0, 50, 50); - base::scoped_nsobject<BubbleView> view( - [[BubbleView alloc] initWithFrame:frame]); - [view setThemeProvider:test_window()]; - view_ = view.get(); - [[test_window() contentView] addSubview:view_]; - [view_ setContent:@"Hi there, I'm a bubble view"]; - } - - BubbleView* view_; -}; - -TEST_VIEW(BubbleViewTest, view_); - -// Test with no themeProvider. -TEST_F(BubbleViewTest, NilThemeProvider) { - NSRect frame = NSMakeRect(0, 0, 50, 50); - base::scoped_nsobject<BubbleView> view( - [[BubbleView alloc] initWithFrame:frame]); - [[test_window() contentView] addSubview:view.get()]; - [view display]; -} - -// Make sure things don't go haywire when given invalid or long strings. -TEST_F(BubbleViewTest, SetContent) { - [view_ setContent:nil]; - EXPECT_TRUE([view_ content] == nil); - [view_ setContent:@""]; - EXPECT_NSEQ(@"", [view_ content]); - NSString* str = @"This is a really really long string that's just too long"; - [view_ setContent:str]; - EXPECT_NSEQ(str, [view_ content]); -} - -TEST_F(BubbleViewTest, CornerFlags) { - // Set some random flags just to check. - [view_ setCornerFlags:kRoundedTopRightCorner | kRoundedTopLeftCorner]; - EXPECT_EQ([view_ cornerFlags], - (unsigned long)kRoundedTopRightCorner | kRoundedTopLeftCorner); - // Set no flags (all 4 draw corners are square). - [view_ setCornerFlags:0]; - EXPECT_EQ([view_ cornerFlags], 0UL); - // Set all bits. Meaningless past the first 4, but harmless to set too many. - [view_ setCornerFlags:0xFFFFFFFF]; - EXPECT_EQ([view_ cornerFlags], 0xFFFFFFFF); -}
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller.h b/chrome/browser/ui/cocoa/dev_tools_controller.h deleted file mode 100644 index b27b70b..0000000 --- a/chrome/browser/ui/cocoa/dev_tools_controller.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_ -#define CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#include "chrome/browser/devtools/devtools_window.h" - -@class FocusTracker; -@class DevToolsContainerView; -class Profile; - -namespace content { -class WebContents; -} - -// A class that handles updates of the devTools view within a browser window. -// It swaps in the relevant devTools contents for a given WebContents or removes -// the view, if there's no devTools contents to show. -@interface DevToolsController : NSObject { - @private - // A view hosting docked devTools contents. - base::scoped_nsobject<DevToolsContainerView> devToolsContainerView_; - - base::scoped_nsobject<FocusTracker> focusTracker_; -} - -- (id)init; - -// This controller's view. -- (NSView*)view; - -// Depending on |contents|'s state, decides whether the docked web inspector -// should be shown or hidden and adjusts inspected page position. -// Returns true iff layout has changed. -- (BOOL)updateDevToolsForWebContents:(content::WebContents*)contents - withProfile:(Profile*)profile; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller.mm b/chrome/browser/ui/cocoa/dev_tools_controller.mm deleted file mode 100644 index 43180271..0000000 --- a/chrome/browser/ui/cocoa/dev_tools_controller.mm +++ /dev/null
@@ -1,163 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/dev_tools_controller.h" - -#include <algorithm> -#include <cmath> - -#include <Cocoa/Cocoa.h> - -#include "chrome/browser/browser_process.h" -#include "chrome/browser/profiles/profile.h" -#import "chrome/browser/ui/cocoa/view_id_util.h" -#include "components/prefs/pref_service.h" -#include "content/public/browser/web_contents.h" -#include "ui/base/cocoa/base_view.h" -#include "ui/base/cocoa/focus_tracker.h" -#include "ui/gfx/geometry/size_conversions.h" -#include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h" - -using content::WebContents; - -@interface DevToolsContainerView : BaseView { - DevToolsContentsResizingStrategy strategy_; - - // Weak references. Ownership via -subviews. - NSView* devToolsView_; - NSView* contentsView_; -} - -// Returns true iff layout has changed. -- (BOOL)setDevToolsView:(NSView*)devToolsView - withStrategy:(const DevToolsContentsResizingStrategy&)strategy; -- (void)adjustSubviews; -- (BOOL)hasDevToolsView; - -@end - - -@implementation DevToolsContainerView - -- (BOOL)setDevToolsView:(NSView*)devToolsView - withStrategy:(const DevToolsContentsResizingStrategy&)strategy { - BOOL strategy_changed = !strategy_.Equals(strategy); - strategy_.CopyFrom(strategy); - if (devToolsView == devToolsView_) { - if (contentsView_) - [contentsView_ setHidden:strategy.hide_inspected_contents()]; - return strategy_changed; - } - - if (devToolsView_) { - DCHECK_EQ(2u, [[self subviews] count]); - [devToolsView_ removeFromSuperview]; - [contentsView_ setHidden:NO]; - contentsView_ = nil; - devToolsView_ = nil; - } - - if (devToolsView) { - NSArray* subviews = [self subviews]; - DCHECK_EQ(1u, [subviews count]); - contentsView_ = [subviews objectAtIndex:0]; - devToolsView_ = devToolsView; - // Place DevTools under contents. - [self addSubview:devToolsView positioned:NSWindowBelow relativeTo:nil]; - - [contentsView_ setHidden:strategy.hide_inspected_contents()]; - } - - return YES; -} - -- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { - [self adjustSubviews]; -} - -- (BOOL)hasDevToolsView { - return devToolsView_ != nil; -} - -- (void)adjustSubviews { - if (![[self subviews] count]) - return; - - if (!devToolsView_) { - DCHECK_EQ(1u, [[self subviews] count]); - NSView* contents = [[self subviews] objectAtIndex:0]; - [contents setFrame:[self bounds]]; - return; - } - - DCHECK_EQ(2u, [[self subviews] count]); - - gfx::Rect new_devtools_bounds; - gfx::Rect new_contents_bounds; - ApplyDevToolsContentsResizingStrategy( - strategy_, gfx::Size(NSSizeToCGSize([self bounds].size)), - &new_devtools_bounds, &new_contents_bounds); - [devToolsView_ setFrame:[self flipRectToNSRect:new_devtools_bounds]]; - [contentsView_ setFrame:[self flipRectToNSRect:new_contents_bounds]]; -} - -@end - - -@implementation DevToolsController - -- (id)init { - if ((self = [super init])) { - devToolsContainerView_.reset( - [[DevToolsContainerView alloc] initWithFrame:NSZeroRect]); - [devToolsContainerView_ - setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - } - return self; -} - -- (NSView*)view { - return devToolsContainerView_.get(); -} - -- (BOOL)updateDevToolsForWebContents:(WebContents*)contents - withProfile:(Profile*)profile { - DevToolsContentsResizingStrategy strategy; - WebContents* devTools = DevToolsWindow::GetInTabWebContents( - contents, &strategy); - - // Make sure we do not draw any transient arrangements of views. - gfx::ScopedCocoaDisableScreenUpdates disabler; - - if (devTools && ![devToolsContainerView_ hasDevToolsView]) { - focusTracker_.reset( - [[FocusTracker alloc] initWithWindow:[devToolsContainerView_ window]]); - } - - if (!devTools && [devToolsContainerView_ hasDevToolsView]) { - [focusTracker_ restoreFocusInWindow:[devToolsContainerView_ window]]; - focusTracker_.reset(); - } - - NSView* devToolsView = nil; - if (devTools) { - devToolsView = devTools->GetNativeView(); - // |devToolsView| is a WebContentsViewCocoa object, whose ViewID was - // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to - // VIEW_ID_DEV_TOOLS_DOCKED here. - view_id_util::SetID(devToolsView, VIEW_ID_DEV_TOOLS_DOCKED); - - devTools->SetAllowOtherViews(true); - contents->SetAllowOtherViews(true); - } else { - contents->SetAllowOtherViews(false); - } - - BOOL result = [devToolsContainerView_ setDevToolsView:devToolsView - withStrategy:strategy]; - [devToolsContainerView_ adjustSubviews]; - return result; -} - -@end
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm b/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm deleted file mode 100644 index bbc6ad51..0000000 --- a/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/dev_tools_controller.h" - -#include "base/macros.h" -#include "chrome/browser/devtools/devtools_window.h" -#include "chrome/browser/devtools/devtools_window_testing.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_list.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/cocoa/browser_window_controller.h" -#include "chrome/browser/ui/find_bar/find_bar.h" -#include "chrome/browser/ui/find_bar/find_bar_controller.h" -#include "chrome/common/url_constants.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/views/scoped_macviews_browser_mode.h" -#include "content/public/browser/notification_types.h" -#include "content/public/browser/web_contents.h" -#include "content/public/test/test_utils.h" - -class DevToolsControllerTest : public InProcessBrowserTest { - public: - DevToolsControllerTest() : InProcessBrowserTest(), devtools_window_(NULL) {} - - protected: - void OpenDevToolsWindow() { - devtools_window_ = - DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true); - } - - void CloseDevToolsWindow() { - DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window_); - } - - content::WebContents* web_contents() { - return browser()->tab_strip_model()->GetActiveWebContents(); - } - - content::WebContents* devtools_web_contents() { - return DevToolsWindow::GetInTabWebContents(web_contents(), NULL); - } - - DevToolsWindow* devtools_window_; - - private: - test::ScopedMacViewsBrowserMode cocoa_browser_mode_{false}; - - DISALLOW_COPY_AND_ASSIGN(DevToolsControllerTest); -}; - -// Verify that AllowOtherViews is set when and only when DevTools is visible. -IN_PROC_BROWSER_TEST_F(DevToolsControllerTest, AllowOtherViews) { - EXPECT_FALSE(web_contents()->GetAllowOtherViews()); - - OpenDevToolsWindow(); - EXPECT_TRUE(devtools_web_contents()->GetAllowOtherViews()); - EXPECT_TRUE(web_contents()->GetAllowOtherViews()); - - CloseDevToolsWindow(); - EXPECT_FALSE(web_contents()->GetAllowOtherViews()); -}
diff --git a/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm b/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm deleted file mode 100644 index 65c0670..0000000 --- a/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm +++ /dev/null
@@ -1,186 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// This file contains the Mac implementation the download animation, displayed -// at the start of a download. The animation produces an arrow pointing -// downwards and animates towards the bottom of the window where the new -// download appears in the download shelf. - -#include "chrome/browser/download/download_started_animation.h" - -#import <QuartzCore/QuartzCore.h> - -#include "base/logging.h" -#include "chrome/app/vector_icons/vector_icons.h" -#import "chrome/browser/ui/cocoa/animatable_image.h" -#import "chrome/browser/ui/cocoa/md_util.h" -#import "chrome/browser/ui/cocoa/nsview_additions.h" -#include "chrome/common/chrome_features.h" -#include "chrome/grit/theme_resources.h" -#include "content/public/browser/web_contents.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_features.h" -#include "ui/gfx/color_palette.h" -#import "ui/gfx/image/image_skia_util_mac.h" -#include "ui/gfx/paint_vector_icon.h" - -namespace { -constexpr CGFloat kLeftMargin = 10; -constexpr CGFloat kMDDownloadStartedImageSize = 72; -} // namespace - -class DownloadAnimationWebObserver; - -// A class for managing the Core Animation download animation. -// Should be instantiated using +startAnimationWithWebContents:. -@interface DownloadStartedAnimationMac : NSObject { - @private - CGFloat imageWidth_; - AnimatableImage* animation_; -}; - -+ (void)startAnimationWithWebContents:(content::WebContents*)webContents; - -@end - -@implementation DownloadStartedAnimationMac - -- (id)initWithWebContents:(content::WebContents*)webContents { - if ((self = [super init])) { - // Load the image of the download arrow. - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - NSImage* image = - base::FeatureList::IsEnabled(features::kMacMaterialDesignDownloadShelf) - ? NSImageFromImageSkia(gfx::CreateVectorIcon( - kFileDownloadShelfIcon, kMDDownloadStartedImageSize, - gfx::kGoogleBlue500)) - : bundle.GetNativeImageNamed(IDR_DOWNLOAD_ANIMATION_BEGIN) - .ToNSImage(); - - // Figure out the positioning in the current tab. Try to position the layer - // against the left edge, and three times the download image's height from - // the bottom of the tab, assuming there is enough room. If there isn't - // enough, don't show the animation and let the shelf speak for itself. - gfx::Rect bounds = webContents->GetContainerBounds(); - imageWidth_ = [image size].width; - CGFloat imageHeight = [image size].height; - - // Sanity check the size in case there's no room to display the animation. - if (bounds.height() < imageHeight) { - [self release]; - return nil; - } - - NSView* tabContentsView = webContents->GetNativeView(); - NSWindow* parentWindow = [tabContentsView window]; - if (!parentWindow) { - // The tab is no longer frontmost. - [self release]; - return nil; - } - - NSRect frame = [tabContentsView frame]; - CGFloat animationHeight = MIN(bounds.height(), 4 * imageHeight); - frame.size = NSMakeSize(imageWidth_, animationHeight); - if (base::FeatureList::IsEnabled( - features::kMacMaterialDesignDownloadShelf)) { - frame.origin.x += kLeftMargin; - } - frame = - [tabContentsView convertRect:[tabContentsView cr_localizedRect:frame] - toView:nil]; - frame = [parentWindow convertRectToScreen:frame]; - - // Create the animation object to assist in animating and fading. - animation_ = [[AnimatableImage alloc] initWithImage:image - animationFrame:frame]; - [parentWindow addChildWindow:animation_ ordered:NSWindowAbove]; - - animationHeight = MIN(bounds.height(), 3 * imageHeight); - [animation_ setStartFrame:CGRectMake(0, animationHeight, - imageWidth_, imageHeight)]; - [animation_ setEndFrame:CGRectMake(0, imageHeight, - imageWidth_, imageHeight)]; - [animation_ setStartOpacity:1.0]; - [animation_ setEndOpacity:0.4]; - [animation_ setDuration:0.6]; - if (base::FeatureList::IsEnabled( - features::kMacMaterialDesignDownloadShelf)) { - [animation_ setTimingFunction:CAMediaTimingFunction - .cr_materialEaseInOutTimingFunction]; - } - - // Set up to get notified about resize events on the parent window. - NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; - [center addObserver:self - selector:@selector(parentWindowDidResize:) - name:NSWindowDidResizeNotification - object:parentWindow]; - // When the animation window closes, it needs to be removed from the - // parent window. - [center addObserver:self - selector:@selector(windowWillClose:) - name:NSWindowWillCloseNotification - object:animation_]; - // If the parent window closes, shut everything down too. - [center addObserver:self - selector:@selector(windowWillClose:) - name:NSWindowWillCloseNotification - object:parentWindow]; - } - return self; -} - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [super dealloc]; -} - -// Called when the parent window is resized. -- (void)parentWindowDidResize:(NSNotification*)notification { - NSWindow* parentWindow = [animation_ parentWindow]; - DCHECK([[notification object] isEqual:parentWindow]); - NSRect parentFrame = [parentWindow frame]; - NSRect frame = parentFrame; - frame.size.width = MIN(imageWidth_, NSWidth(parentFrame)); - [animation_ setFrame:frame display:YES]; -} - -// When the animation closes, release self. -- (void)windowWillClose:(NSNotification*)notification { - [[animation_ parentWindow] removeChildWindow:animation_]; - [self release]; -} - -+ (void)startAnimationWithWebContents:(content::WebContents*)contents { - // Will be deleted when the animation window closes. - DownloadStartedAnimationMac* controller = - [[self alloc] initWithWebContents:contents]; - // The initializer can return nil. - if (!controller) - return; - - // The |controller| releases itself when done. - [controller->animation_ startAnimation]; -} - -@end - -void DownloadStartedAnimation::ShowCocoa(content::WebContents* web_contents) { - DCHECK(web_contents); - - // There's code above for an MD version of the animation, but the current - // plan is to not show it at all. - if (base::FeatureList::IsEnabled(features::kMacMaterialDesignDownloadShelf)) - return; - - // Will be deleted when the animation is complete. - [DownloadStartedAnimationMac startAnimationWithWebContents:web_contents]; -} - -#if !BUILDFLAG(MAC_VIEWS_BROWSER) -void DownloadStartedAnimation::Show(content::WebContents* web_contents) { - ShowCocoa(web_contents); -} -#endif
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h deleted file mode 100644 index 7057e734..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h +++ /dev/null
@@ -1,174 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_H_ -#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/styled_text_field.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#import "chrome/browser/ui/cocoa/url_drop_target.h" - -@class AutocompleteTextFieldCell; -class LocationBarDecoration; - -// AutocompleteTextField intercepts UI actions for forwarding to -// OmniboxViewMac (*), and provides a custom look. It works -// together with AutocompleteTextFieldEditor (mostly for intercepting -// user actions) and AutocompleteTextFieldCell (mostly for custom -// drawing). -// -// For historical reasons, chrome/browser/autocomplete is the core -// implementation of the Omnibox. Chrome code seems to vary between -// autocomplete and Omnibox in describing this. -// -// (*) OmniboxViewMac is a view in the MVC sense for the -// Chrome internals, though it's really more of a mish-mash of model, -// view, and controller. - -// Provides a hook so that we can call directly down to -// OmniboxViewMac rather than traversing the delegate chain. -class AutocompleteTextFieldObserver { - public: - // Called before changing the selected range of the field. - virtual NSRange SelectionRangeForProposedRange(NSRange proposed_range) = 0; - - // Called when the control-key state changes while the field is - // first responder. - virtual void OnControlKeyChanged(bool pressed) = 0; - - // Called when the user pastes into the field. - virtual void OnPaste() = 0; - - // Return |true| if there is a selection to copy. - virtual bool CanCopy() = 0; - - // Creates a pasteboard item from the field's current selection. - virtual base::scoped_nsobject<NSPasteboardItem> CreatePasteboardItem() = 0; - - // Copies the pasteboard item returned from |CreatePasteboardItem()| to - // |pboard|. - virtual void CopyToPasteboard(NSPasteboard* pboard) = 0; - - // Returns true if the current clipboard text supports paste and go - // (or paste and search). - virtual bool CanPasteAndGo() = 0; - - // Returns the appropriate "Paste and Go" or "Paste and Search" - // context menu string, depending on what is currently in the - // clipboard. Must not be called unless CanPasteAndGo() returns - // true. - virtual int GetPasteActionStringId() = 0; - - // Called when the user initiates a "paste and go" or "paste and - // search" into the field. - virtual void OnPasteAndGo() = 0; - - // Called when the field's frame changes. - virtual void OnFrameChanged() = 0; - - // Called when the popup is no longer appropriate, such as when the - // field's window loses focus or a page action is clicked. - virtual void ClosePopup() = 0; - - // Called when the user begins editing the field, for every edit, - // and when the user is done editing the field. - virtual void OnDidBeginEditing() = 0; - virtual void OnBeforeChange() = 0; - virtual void OnDidChange() = 0; - virtual void OnDidEndEditing() = 0; - - // Called when -insertText: is invoked on the editor. - virtual void OnInsertText() = 0; - - // Called before a -drawRect: operation. - virtual void OnBeforeDrawRect() = 0; - - // Called after the completion of a -drawRect: operation. - virtual void OnDidDrawRect() = 0; - - // NSResponder translates certain keyboard actions into selectors - // passed to -doCommandBySelector:. The selector is forwarded here, - // return true if |cmd| is handled, false if the caller should - // handle it. - // TODO(shess): For now, I think having the code which makes these - // decisions closer to the other autocomplete code is worthwhile, - // since it calls a wide variety of methods which otherwise aren't - // clearly relevent to expose here. But consider pulling more of - // the OmniboxViewMac calls up to here. - virtual bool OnDoCommandBySelector(SEL cmd) = 0; - - // Called whenever the autocomplete text field gets focused. - virtual void OnSetFocus(bool control_down) = 0; - - // Called whenever the autocomplete text field is losing focus. - virtual void OnKillFocus() = 0; - - // Called before the text field handles a mouse down event. - virtual void OnMouseDown(NSInteger button_number) = 0; - - protected: - virtual ~AutocompleteTextFieldObserver() {} -}; - -@interface AutocompleteTextField : StyledTextField<NSTextViewDelegate, - URLDropTarget, - ThemedWindowDrawing> { - @private - // Undo manager for this text field. We use a specific instance rather than - // the standard undo manager in order to let us clear the undo stack at will. - base::scoped_nsobject<NSUndoManager> undoManager_; - - AutocompleteTextFieldObserver* observer_; // weak, owned by location bar. - - // Handles being a drag-and-drop target. - base::scoped_nsobject<URLDropTargetHandler> dropHandler_; - - // Holds current tooltip strings, to keep them from being dealloced. - base::scoped_nsobject<NSMutableArray> currentToolTips_; - - // Animation object used for resizing the autocomplete field. - base::scoped_nsobject<NSViewAnimation> resizeAnimation_; -} - -@property(nonatomic) AutocompleteTextFieldObserver* observer; - -// Convenience method to return the cell, casted appropriately. -- (AutocompleteTextFieldCell*)cell; - -// Superclass aborts editing before changing the string, which causes -// problems for undo. This version modifies the field editor's -// contents if the control is already being edited. -- (void)setAttributedStringValue:(NSAttributedString*)aString; - -// Clears the undo chain for this text field. -- (void)clearUndoChain; - -// Animates the text field to the given |frame|. -- (void)animateToFrame:(NSRect)frame; - -// Stops the current animation, if any. The frame will be set to the current -// (mid-animation) frame. -- (void)stopAnimation; - -// Updates cursor and tooltip rects depending on the contents of the text field -// e.g. the security icon should have a default pointer shown on hover instead -// of an I-beam. -- (void)updateMouseTracking; - -// Return the appropriate menu for any decoration under |event|. -- (NSMenu*)decorationMenuForEvent:(NSEvent*)event; - -// Retains |tooltip| (in |currentToolTips_|) and adds this tooltip -// via -[NSView addToolTipRect:owner:userData:]. -- (void)addToolTip:(NSString*)tooltip forRect:(NSRect)aRect; - -// Obtain the bubble anchor point for |decoration| in window coordinates. -- (NSPoint)bubblePointForDecoration:(LocationBarDecoration*)decoration; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm deleted file mode 100644 index b472721..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm +++ /dev/null
@@ -1,559 +0,0 @@ -// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" - -#include "base/logging.h" -#import "base/mac/mac_util.h" -#import "base/mac/sdk_forward_declarations.h" -#include "chrome/browser/themes/theme_service.h" -#include "chrome/browser/ui/cocoa/browser_dialogs_views_mac.h" -#import "chrome/browser/ui/cocoa/browser_window_controller.h" -#include "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h" -#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" -#import "chrome/browser/ui/cocoa/url_drop_target.h" -#import "chrome/browser/ui/cocoa/view_id_util.h" -#import "ui/base/cocoa/nsview_additions.h" -#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" - -namespace { -const CGFloat kResizeAnimationDuration = 0.2; -} - -@implementation AutocompleteTextField - -@synthesize observer = observer_; - -+ (Class)cellClass { - return [AutocompleteTextFieldCell class]; -} - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [super dealloc]; -} - -- (void)awakeFromNib { - DCHECK([[self cell] isKindOfClass:[AutocompleteTextFieldCell class]]); - [[self cell] setTruncatesLastVisibleLine:YES]; - [[self cell] setLineBreakMode:NSLineBreakByTruncatingTail]; - currentToolTips_.reset([[NSMutableArray alloc] init]); - resizeAnimation_.reset([[NSViewAnimation alloc] init]); - [resizeAnimation_ setDuration:kResizeAnimationDuration]; - [resizeAnimation_ setAnimationBlockingMode:NSAnimationNonblocking]; - [self setAlignment:cocoa_l10n_util::ShouldDoExperimentalRTLLayout() - ? NSRightTextAlignment - : NSLeftTextAlignment]; - - // Disable Force Touch in the Omnibox. Note that this API is documented as - // being available in 10.11 or higher, but if the API is available in an older - // version we still want to use it. That prevents us from guarding the call - // with @available, so instead we use respondsToSelector and silence the - // availability warning. Also, because NSPressureConfiguration is not in the - // original 10.10 SDK, use NSClassFromString() to instantiate it (otherwise - // there's a linker error). - if (base::mac::IsAtLeastOS10_10() && - [self respondsToSelector:@selector(setPressureConfiguration:)]) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability" - NSPressureConfiguration* pressureConfiguration = - [[[NSClassFromString(@"NSPressureConfiguration") alloc] - initWithPressureBehavior:NSPressureBehaviorPrimaryClick] - autorelease]; - [self setPressureConfiguration:pressureConfiguration]; -#pragma clang diagnostic pop - } -} - -- (void)flagsChanged:(NSEvent*)theEvent { - if (observer_) { - const bool controlFlag = ([theEvent modifierFlags]&NSControlKeyMask) != 0; - observer_->OnControlKeyChanged(controlFlag); - } -} - -- (AutocompleteTextFieldCell*)cell { - NSCell* cell = [super cell]; - if (!cell) - return nil; - - DCHECK([cell isKindOfClass:[AutocompleteTextFieldCell class]]); - return static_cast<AutocompleteTextFieldCell*>(cell); -} - -// Reroute events for the decoration area to the field editor. This -// will cause the cursor to be moved as close to the edge where the -// event was seen as possible. -// -// The reason for this code's existence is subtle. NSTextField -// implements text selection and editing in terms of a "field editor". -// This is an NSTextView which is installed as a subview of the -// control when the field becomes first responder. When the field -// editor is installed, it will get -mouseDown: events and handle -// them, rather than the text field - EXCEPT for the event which -// caused the change in first responder, or events which fall in the -// decorations outside the field editor's area. In that case, the -// default NSTextField code will setup the field editor all over -// again, which has the side effect of doing "select all" on the text. -// This effect can be observed with a normal NSTextField if you click -// in the narrow border area, and is only really a problem because in -// our case the focus ring surrounds decorations which look clickable. -// -// When the user first clicks on the field, after installing the field -// editor the default NSTextField code detects if the hit is in the -// field editor area, and if so sets the selection to {0,0} to clear -// the selection before forwarding the event to the field editor for -// processing (it will set the cursor position). This also starts the -// click-drag selection machinery. -// -// This code does the same thing for cases where the click was in the -// decoration area. This allows the user to click-drag starting from -// a decoration area and get the expected selection behaviour, -// likewise for multiple clicks in those areas. -- (void)mouseDown:(NSEvent*)theEvent { - // TODO(groby): Figure out if OnMouseDown needs to be postponed/skipped - // for button decorations. - if (observer_) - observer_->OnMouseDown([theEvent buttonNumber]); - - // If the click was a Control-click, bring up the context menu. - // |NSTextField| handles these cases inconsistently if the field is - // not already first responder. - if (([theEvent modifierFlags] & NSControlKeyMask) != 0) { - NSText* editor = [self currentEditor]; - NSMenu* menu = [editor menuForEvent:theEvent]; - [NSMenu popUpContextMenu:menu withEvent:theEvent forView:editor]; - return; - } - - const NSPoint location = - [self convertPoint:[theEvent locationInWindow] fromView:nil]; - const NSRect bounds([self bounds]); - - AutocompleteTextFieldCell* cell = [self cell]; - const NSRect textFrame([cell textFrameForFrame:bounds]); - - // A version of the textFrame which extends across the field's - // entire width. - - const NSRect fullFrame(NSMakeRect(bounds.origin.x, textFrame.origin.y, - bounds.size.width, textFrame.size.height)); - - // If the mouse is in the editing area, or above or below where the - // editing area would be if we didn't add decorations, forward to - // NSTextField -mouseDown: because it does the right thing. The - // above/below test is needed because NSTextView treats mouse events - // above/below as select-to-end-in-that-direction, which makes - // things janky. - BOOL flipped = [self isFlipped]; - if (NSMouseInRect(location, textFrame, flipped) || - !NSMouseInRect(location, fullFrame, flipped)) { - [super mouseDown:theEvent]; - - // After the event has been handled, if the current event is a - // mouse up and no selection was created (the mouse didn't move), - // select the entire field. - // NOTE(shess): This does not interfere with single-clicking to - // place caret after a selection is made. An NSTextField only has - // a selection when it has a field editor. The field editor is an - // NSText subview, which will receive the -mouseDown: in that - // case, and this code will never fire. - NSText* editor = [self currentEditor]; - if (editor) { - NSEvent* currentEvent = [NSApp currentEvent]; - if ([currentEvent type] == NSLeftMouseUp && - ![editor selectedRange].length) { - [editor selectAll:nil]; - } - } - - return; - } - - // Give the cell a chance to intercept clicks in page-actions and - // other decorative items. - if ([cell mouseDown:theEvent inRect:bounds ofView:self]) { - return; - } - - NSText* editor = [self currentEditor]; - - // We should only be here if we accepted first-responder status and - // have a field editor. If one of these fires, it means some - // assumptions are being broken. - DCHECK(editor != nil); - DCHECK([editor isDescendantOf:self]); - - // -becomeFirstResponder does a select-all, which we don't want - // because it can lead to a dragged-text situation. Clear the - // selection (any valid empty selection will do). - [editor setSelectedRange:NSMakeRange(0, 0)]; - - // If the event is to the right of the editing area, scroll the - // field editor to the end of the content so that the selection - // doesn't initiate from somewhere in the middle of the text. - if (location.x > NSMaxX(textFrame)) { - [editor scrollRangeToVisible:NSMakeRange([[self stringValue] length], 0)]; - } - - [editor mouseDown:theEvent]; -} - -- (void)mouseUp:(NSEvent*)theEvent { - const NSRect bounds([self bounds]); - AutocompleteTextFieldCell* cell = [self cell]; - [cell mouseUp:theEvent inRect:bounds ofView:self]; -} - -- (void)rightMouseDown:(NSEvent*)event { - if (observer_) - observer_->OnMouseDown([event buttonNumber]); - [super rightMouseDown:event]; -} - -- (void)otherMouseDown:(NSEvent *)event { - if (observer_) - observer_->OnMouseDown([event buttonNumber]); - [super otherMouseDown:event]; -} - -// Overridden so that cursor and tooltip rects can be updated. -- (void)setFrame:(NSRect)frameRect { - [super setFrame:frameRect]; - if (observer_) { - observer_->OnFrameChanged(); - } - [self updateMouseTracking]; -} - -- (void)setAttributedStringValue:(NSAttributedString*)aString { - AutocompleteTextFieldEditor* editor = - static_cast<AutocompleteTextFieldEditor*>([self currentEditor]); - - if (!editor) { - [super setAttributedStringValue:aString]; - } else { - // The type of the field editor must be AutocompleteTextFieldEditor, - // otherwise things won't work. - DCHECK([editor isKindOfClass:[AutocompleteTextFieldEditor class]]); - - [editor setAttributedString:aString]; - } -} - -- (NSUndoManager*)undoManagerForTextView:(NSTextView*)textView { - if (!undoManager_.get()) - undoManager_.reset([[NSUndoManager alloc] init]); - return undoManager_.get(); -} - -- (void)animateToFrame:(NSRect)frame { - [self stopAnimation]; - NSDictionary* animationDictionary = @{ - NSViewAnimationTargetKey : self, - NSViewAnimationStartFrameKey : [NSValue valueWithRect:[self frame]], - NSViewAnimationEndFrameKey : [NSValue valueWithRect:frame] - }; - [resizeAnimation_ setViewAnimations:@[ animationDictionary ]]; - [resizeAnimation_ startAnimation]; -} - -- (void)stopAnimation { - if ([resizeAnimation_ isAnimating]) { - // [NSViewAnimation stopAnimation] results in advancing the animation to - // the end. Since this is almost certainly not the behavior we want, reset - // the frame to the current frame. - NSRect frame = [self frame]; - [resizeAnimation_ stopAnimation]; - [self setFrame:frame]; - } -} - -- (void)clearUndoChain { - [undoManager_ removeAllActions]; -} - -- (NSRange)textView:(NSTextView *)aTextView - willChangeSelectionFromCharacterRange:(NSRange)oldRange - toCharacterRange:(NSRange)newRange { - if (observer_) - return observer_->SelectionRangeForProposedRange(newRange); - return newRange; -} - -- (void)addToolTip:(NSString*)tooltip forRect:(NSRect)aRect { - [currentToolTips_ addObject:tooltip]; - [self addToolTipRect:aRect owner:tooltip userData:nil]; -} - -- (NSPoint)bubblePointForDecoration:(LocationBarDecoration*)decoration { - // Under MD, dialogs have no arrow and anchor to corner of the location bar - // frame, not a specific point within it. See http://crbug.com/566115. - - // Inset the omnibox frame by 2 real pixels. This is done because the border - // stroke of the omnibox is inside its frame, but bubbles have no border - // stroke. The bubble border is part of the shadow drawn by the window server; - // outside the bubble frame. In the Y direction, some of that same "gap" must - // be kept, otherwise the "border" stroke from the window server shadow would - // be drawn inside the omnibox. But since these insets round to integers when - // positioning the window, retina needs to use a zero vertical offset to avoid - // insetting an entire DIP. This looks OK, since the bubble border and omnibox - // border are still drawn flush. TODO(tapted): Convince the borders to overlap - // on retina somehow. - const CGFloat kStrokeInsetX = 2 * [self cr_lineWidth]; - const CGFloat kStrokeInsetY = [self cr_lineWidth] == 1.0 ? 1 : 0; - const NSRect frame = NSInsetRect([self bounds], kStrokeInsetX, kStrokeInsetY); - - BOOL isLeftDecoration = [[self cell] isLeftDecoration:decoration]; - NSPoint point = NSMakePoint(isLeftDecoration ? NSMinX(frame) : NSMaxX(frame), - NSMaxY(frame)); - return [self convertPoint:point toView:nil]; -} - -// TODO(shess): -resetFieldEditorFrameIfNeeded is the place where -// changes to the cell layout should be flushed. LocationBarViewMac -// and ToolbarController are calling this routine directly, and I -// think they are probably wrong. -// http://crbug.com/40053 -- (void)updateMouseTracking { - // This will force |resetCursorRects| to be called, as it is not to be called - // directly. - [[self window] invalidateCursorRectsForView:self]; - - // |removeAllToolTips| only removes those set on the current NSView, not any - // subviews. Unless more tooltips are added to this view, this should suffice - // in place of managing a set of NSToolTipTag objects. - [self removeAllToolTips]; - - // Reload the decoration tooltips. - [currentToolTips_ removeAllObjects]; - [[self cell] updateMouseTrackingAndToolTipsInRect:[self bounds] ofView:self]; -} - -// NOTE(shess): http://crbug.com/19116 describes a weird bug which -// happens when the user runs a Print panel on Leopard. After that, -// spurious -controlTextDidBeginEditing notifications are sent when an -// NSTextField is firstResponder, even though -currentEditor on that -// field returns nil. That notification caused significant problems -// in OmniboxViewMac. -textDidBeginEditing: was NOT being -// sent in those cases, so this approach doesn't have the problem. -- (void)textDidBeginEditing:(NSNotification*)aNotification { - [super textDidBeginEditing:aNotification]; - if (observer_) { - observer_->OnDidBeginEditing(); - } -} - -- (void)textDidEndEditing:(NSNotification *)aNotification { - [super textDidEndEditing:aNotification]; - if (observer_) { - observer_->OnDidEndEditing(); - } -} - -// When the window resigns, make sure the autocomplete popup is no -// longer visible, since the user's focus is elsewhere. -- (void)windowDidResignKey:(NSNotification*)notification { - DCHECK_EQ([self window], [notification object]); - if (observer_) - observer_->ClosePopup(); -} - -- (void)windowDidResize:(NSNotification*)notification { - DCHECK_EQ([self window], [notification object]); - if (observer_) - observer_->OnFrameChanged(); -} - -- (void)viewWillMoveToWindow:(NSWindow*)newWindow { - if ([self window]) { - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc removeObserver:self - name:NSWindowDidResignKeyNotification - object:[self window]]; - [nc removeObserver:self - name:NSWindowDidResizeNotification - object:[self window]]; - [nc removeObserver:self - name:NSWindowDidChangeScreenNotification - object:[self window]]; - } -} - -- (void)windowDidChangeScreen { - // Inform the AutocompleteTextFieldCell's of the coordinate system line - // width needed to draw a single-pixel line. This value changes as we move - // between Retina and non-Retina displays. - [[self cell] setSinglePixelLineWidth:[self cr_lineWidth]]; - [self setNeedsDisplay]; -} - -- (void)updateColorsToMatchTheme { - if (![[self window] inIncognitoMode]) { - return; - } - - // Invert the textfield's colors when Material Design and Incognito and not - // a custom theme. - bool inDarkMode = [[self window] inIncognitoModeWithSystemTheme]; - const CGFloat kDarkModeGray = 97 / 255.; - [self setBackgroundColor: - inDarkMode ? [NSColor colorWithGenericGamma22White:kDarkModeGray - alpha:1] - : [NSColor whiteColor]]; - [self setTextColor:OmniboxViewMac::BaseTextColor(inDarkMode)]; -} - -- (void)viewDidMoveToWindow { - if (![self window]) { - return; - } - - // Allow the ToolbarController to take action upon the - // AutocompleteTextField being added to the window. - BrowserWindowController* browserWindowController = - [BrowserWindowController browserWindowControllerForView:self]; - [[browserWindowController toolbarController] locationBarWasAddedToWindow]; - - [self updateColorsToMatchTheme]; - - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc addObserver:self - selector:@selector(windowDidResignKey:) - name:NSWindowDidResignKeyNotification - object:[self window]]; - [nc addObserver:self - selector:@selector(windowDidResize:) - name:NSWindowDidResizeNotification - object:[self window]]; - [nc addObserver:self - selector:@selector(windowDidChangeScreen) - name:NSWindowDidChangeScreenNotification - object:[self window]]; - - // Make sure the cell has the current line width. - [[self cell] setSinglePixelLineWidth:[self cr_lineWidth]]; - - // Only register for drops if not in a popup window. Lazily create the - // drop handler when the type of window is known. - BrowserWindowController* windowController = - [BrowserWindowController browserWindowControllerForView:self]; - if ([windowController isTabbedWindow]) - dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]); -} - -// NSTextField becomes first responder by installing a "field editor" -// subview. Clicks outside the field editor (such as a decoration) -// will attempt to make the field the first-responder again, which -// causes a select-all, even if the decoration handles the click. If -// the field editor is already in place, don't accept first responder -// again. This allows the selection to be unmodified if the click is -// handled by a decoration or context menu (|-mouseDown:| will still -// change it if appropriate). -- (BOOL)acceptsFirstResponder { - if ([self currentEditor]) { - DCHECK_EQ([self currentEditor], [[self window] firstResponder]); - return NO; - } - - // If the event is a left-mouse click, and it lands on a decoration, then the - // event should not cause the text field to become first responder. - NSEvent* event = [NSApp currentEvent]; - if ([event type] == NSLeftMouseDown) { - LocationBarDecoration* decoration = - [[self cell] decorationForEvent:event inRect:[self bounds] ofView:self]; - if (decoration && decoration->AcceptsMousePress() != AcceptsPress::NEVER) - return NO; - } - - return [super acceptsFirstResponder]; -} - -// (Overridden from NSResponder) -- (BOOL)becomeFirstResponder { - BOOL doAccept = [super becomeFirstResponder]; - if (doAccept) { - [[BrowserWindowController browserWindowControllerForView:self] - lockToolbarVisibilityForOwner:self - withAnimation:YES]; - - // Tells the observer that we get the focus. - // But we can't call observer_->OnKillFocus() in resignFirstResponder:, - // because the first responder will be immediately set to the field editor - // when calling [super becomeFirstResponder], thus we won't receive - // resignFirstResponder: anymore when losing focus. - [[self cell] handleFocusEvent:[NSApp currentEvent] ofView:self]; - } - return doAccept; -} - -// (Overridden from NSResponder) -- (BOOL)resignFirstResponder { - BOOL doResign = [super resignFirstResponder]; - if (doResign) { - [[BrowserWindowController browserWindowControllerForView:self] - releaseToolbarVisibilityForOwner:self - withAnimation:YES]; - } - return doResign; -} - -// (URLDropTarget protocol) -- (id<URLDropTargetController>)urlDropController { - BrowserWindowController* windowController = - [BrowserWindowController browserWindowControllerForView:self]; - return [windowController toolbarController]; -} - -// (URLDropTarget protocol) -- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { - bool canDropAtLocation = - [[self cell] canDropAtLocationInWindow:[sender draggingLocation] - ofView:self]; - return canDropAtLocation ? [dropHandler_ draggingEntered:sender] - : NSDragOperationNone; -} - -// (URLDropTarget protocol) -- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { - bool canDropAtLocation = - [[self cell] canDropAtLocationInWindow:[sender draggingLocation] - ofView:self]; - return canDropAtLocation ? [dropHandler_ draggingUpdated:sender] - : NSDragOperationNone; -} - -// (URLDropTarget protocol) -- (void)draggingExited:(id<NSDraggingInfo>)sender { - return [dropHandler_ draggingExited:sender]; -} - -// (URLDropTarget protocol) -- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { - return [dropHandler_ performDragOperation:sender]; -} - -- (NSMenu*)decorationMenuForEvent:(NSEvent*)event { - AutocompleteTextFieldCell* cell = [self cell]; - return [cell decorationMenuForEvent:event inRect:[self bounds] ofView:self]; -} - -- (ViewID)viewID { - return VIEW_ID_OMNIBOX; -} - -// ThemedWindowDrawing implementation. - -- (void)windowDidChangeTheme { - [self updateColorsToMatchTheme]; -} - -- (void)windowDidChangeActive { -} - -@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h deleted file mode 100644 index 5529d371..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h +++ /dev/null
@@ -1,156 +0,0 @@ -// Copyright (c) 2010 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_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_CELL_H_ -#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_CELL_H_ - -#include <vector> - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/styled_text_field_cell.h" - -@class AutocompleteTextField; -class LocationBarDecoration; - -// AutocompleteTextFieldCell extends StyledTextFieldCell to provide support for -// certain decorations to be applied to the field. These are the search hint -// ("Type to search" on the right-hand side), the keyword hint ("Press [Tab] to -// search Engine" on the right-hand side), and keyword mode ("Search Engine:" in -// a button-like token on the left-hand side). -@interface AutocompleteTextFieldCell : StyledTextFieldCell { - @private - // Decorations which live before and after the text, ordered - // from outside in. Decorations are owned by |LocationBarViewMac|. - std::vector<LocationBarDecoration*> leadingDecorations_; - std::vector<LocationBarDecoration*> trailingDecorations_; - - // The decoration associated to the current dragging session. - LocationBarDecoration* draggedDecoration_; - - // Decorations with tracking areas attached to the AutocompleteTextField. - std::vector<LocationBarDecoration*> mouseTrackingDecorations_; - - // If YES then the text field will not draw a focus ring or show the insertion - // pointer. - BOOL hideFocusState_; - - // YES if this field is shown in a popup window. - BOOL isPopupMode_; - - // Retains the NSEvent that caused the controlView to become firstResponder. - base::scoped_nsobject<NSEvent> focusEvent_; - - // The coordinate system line width that draws a single pixel line. - CGFloat singlePixelLineWidth_; -} - -@property(assign, nonatomic) BOOL isPopupMode; -@property(assign, nonatomic) CGFloat singlePixelLineWidth; - -// Line height used for text in this cell. -- (CGFloat)lineHeight; - -// Remove all of the tracking areas. -- (void)clearTrackingArea; - -// Clear |leftDecorations_| and |rightDecorations_|. -- (void)clearDecorations; - -// Add a new leading decoration after the existing -// leading decorations. -- (void)addLeadingDecoration:(LocationBarDecoration*)decoration; - -// Add a new trailing decoration before the existing -// trailing decorations. -- (void)addTrailingDecoration:(LocationBarDecoration*)decoration; - -// The width available after accounting for decorations. -- (CGFloat)availableWidthInFrame:(const NSRect)frame; - -// Return the frame for |aDecoration| if the cell is in |cellFrame|. -// Returns |NSZeroRect| for decorations which are not currently visible. -- (NSRect)frameForDecoration:(const LocationBarDecoration*)aDecoration - inFrame:(NSRect)cellFrame; - -// Returns whether |decoration| appears on the left or the right side of the -// text field. -- (BOOL)isLeftDecoration:(LocationBarDecoration*)decoration; - -// Returns true if it's okay to drop dragged data into the view at the -// given location. -- (BOOL)canDropAtLocationInWindow:(NSPoint)location - ofView:(AutocompleteTextField*)controlView; - -// Find the decoration under the location in the window. Return |NULL| if -// there's nothing in the location. -- (LocationBarDecoration*)decorationForLocationInWindow:(NSPoint)location - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*) - field; - -// Find the decoration under the event. |NULL| if |theEvent| is not -// over anything. -- (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)field; - -// Return the appropriate menu for any decorations under event. -// Returns nil if no menu is present for the decoration, or if the -// event is not over a decoration. -- (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView; - -// Called by |AutocompleteTextField| to let page actions intercept -// clicks. Returns |YES| if the click has been intercepted. -- (BOOL)mouseDown:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView; - -// Called by |AutocompleteTextField| to pass the mouse up event to the omnibox -// decorations. -- (void)mouseUp:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView; - -// Overridden from StyledTextFieldCell to include decorations adjacent -// to the text area which don't handle mouse clicks themselves. -// Keyword-search bubble, for instance. -- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame; - -// Setup decoration tooltips and mouse tracking on |controlView| by calling -// |-addToolTip:forRect:| and |SetupTrackingArea()|. -- (void)updateMouseTrackingAndToolTipsInRect:(NSRect)cellFrame - ofView: - (AutocompleteTextField*)controlView; - -// Gets and sets |hideFocusState|. This allows the text field to have focus but -// to appear unfocused. -- (BOOL)hideFocusState; -- (void)setHideFocusState:(BOOL)hideFocusState - ofView:(AutocompleteTextField*)controlView; - -// Handles the |event| that caused |controlView| to become firstResponder. -- (void)handleFocusEvent:(NSEvent*)event - ofView:(AutocompleteTextField*)controlView; - -// Returns the index of |decoration| as a leading decoration, if it is one. The -// leading-most decoration is at index zero, and increasing indices are closer -// to the start of the omnibox text field. Returns -1 if |decoration| is not a -// leading decoration. -- (int)leadingDecorationIndex:(LocationBarDecoration*)decoration; - -@end - -// Methods which are either only for testing, or only public for testing. -@interface AutocompleteTextFieldCell (TestingAPI) - -// Returns |mouseTrackingDecorations_|. -- (const std::vector<LocationBarDecoration*>&)mouseTrackingDecorations; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_CELL_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm deleted file mode 100644 index 3e00eb86..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm +++ /dev/null
@@ -1,786 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" - -#include <stddef.h> - -#include "base/logging.h" -#include "base/mac/foundation_util.h" -#include "base/mac/mac_logging.h" -#include "base/stl_util.h" -#include "chrome/browser/search/search.h" -#include "chrome/browser/themes/theme_service.h" -#include "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#import "extensions/common/feature_switch.h" -#import "third_party/mozilla/NSPasteboard+Utils.h" -#import "ui/base/cocoa/appkit_utils.h" -#import "ui/base/cocoa/nsview_additions.h" -#include "ui/base/cocoa/scoped_cg_context_smooth_fonts.h" -#import "ui/base/cocoa/tracking_area.h" -#include "ui/base/material_design/material_design_controller.h" - -using extensions::FeatureSwitch; - -namespace { - -// Matches the clipping radius of |GradientButtonCell|. -const CGFloat kCornerRadius = 3.0; - -// How far to inset the left- and right-hand decorations from the field's -// bounds. -const CGFloat kTrailingDecorationXPadding = 2.0; -const CGFloat kLeadingDecorationXPadding = 1.0; - -// The padding between each decoration on the right. -const CGFloat kRightDecorationPadding = 1.0f; - -// How much the text frame needs to overlap the outermost leading -// decoration. -const CGFloat kTextFrameDecorationOverlap = 5.0; - -// How long to wait for mouse-up on the location icon before assuming -// that the user wants to drag. -const NSTimeInterval kLocationIconDragTimeout = 0.25; - -// Calculate the positions for a set of decorations. |frame| is the -// overall frame to do layout in, |remaining_frame| will get the -// left-over space. |all_decorations| is the set of decorations to -// lay out, |decorations| will be set to the decorations which are -// visible and which fit, in the same order as |all_decorations|, -// while |decoration_frames| will be the corresponding frames. -// |x_edge| describes the edge to layout the decorations against -// (|NSMinXEdge| or |NSMaxXEdge|). |regular_padding| is the padding -// from the edge of |cell_frame| to use when the first visible decoration -// is a regular decoration. |decoration_padding| is the padding between each -// decoration. -void CalculatePositionsHelper( - NSRect frame, - const std::vector<LocationBarDecoration*>& all_decorations, - NSRectEdge x_edge, - CGFloat regular_padding, - std::vector<LocationBarDecoration*>* decorations, - std::vector<NSRect>* decoration_frames, - NSRect* remaining_frame, - CGFloat decoration_padding) { - DCHECK(x_edge == NSMinXEdge || x_edge == NSMaxXEdge); - DCHECK_EQ(decorations->size(), decoration_frames->size()); - - // The initial padding depends on whether the first visible decoration is - // a button or not. - bool is_first_visible_decoration = true; - - for (size_t i = 0; i < all_decorations.size(); ++i) { - if (all_decorations[i]->IsVisible()) { - CGFloat padding = 0; - if (is_first_visible_decoration) { - padding = regular_padding; - is_first_visible_decoration = false; - } else { - padding = decoration_padding; - } - - NSRect padding_rect, available; - - // Peel off the outside padding. - NSDivideRect(frame, &padding_rect, &available, padding, x_edge); - - // Find out how large the decoration will be in the remaining - // space. - const CGFloat used_width = - all_decorations[i]->GetWidthForSpace(NSWidth(available)); - - if (used_width != LocationBarDecoration::kOmittedWidth) { - DCHECK_GT(used_width, 0.0); - NSRect decoration_frame; - - // Peel off the desired width, leaving the remainder in - // |frame|. - NSDivideRect(available, &decoration_frame, &frame, - used_width, x_edge); - - decorations->push_back(all_decorations[i]); - decoration_frames->push_back(decoration_frame); - DCHECK_EQ(decorations->size(), decoration_frames->size()); - } - } - } - - DCHECK_EQ(decorations->size(), decoration_frames->size()); - *remaining_frame = frame; -} - -// Helper function for calculating placement of decorations w/in the cell. -// |frame| is the cell's boundary rectangle, |text_frame| will get any -// space left after decorations are laid out (for text). -// |leading_decorations| is a set of decorations for the leading side of -// the cell, |trailing_decorations| for the right-hand side. -// |decorations| will contain the resulting visible decorations, and -// |decoration_frames| will contain their frames in the same coordinates as -// |frame|. Decorations will be ordered left to right in LTR, and right to -// left. -// As a convenience, returns the index of the first right-hand decoration. -size_t CalculatePositionsInFrame( - const NSRect frame, - const std::vector<LocationBarDecoration*>& leading_decorations, - const std::vector<LocationBarDecoration*>& trailing_decorations, - std::vector<LocationBarDecoration*>* decorations, - std::vector<NSRect>* decoration_frames, - NSRect* text_frame) { - decorations->clear(); - decoration_frames->clear(); - *text_frame = frame; - - // Layout |leading_decorations| against the leading side. - CalculatePositionsHelper(*text_frame, leading_decorations, NSMinXEdge, - kLeadingDecorationXPadding, decorations, - decoration_frames, text_frame, 0.0f); - DCHECK_EQ(decorations->size(), decoration_frames->size()); - - // Capture the number of visible leading decorations. - size_t leading_count = decorations->size(); - - // Extend the text frame so that it slightly overlaps the rightmost left - // decoration. - if (leading_count) { - text_frame->origin.x -= kTextFrameDecorationOverlap; - text_frame->size.width += kTextFrameDecorationOverlap; - } - - // Layout |trailing_decorations| against the trailing side. - CalculatePositionsHelper(*text_frame, trailing_decorations, NSMaxXEdge, - kTrailingDecorationXPadding, decorations, - decoration_frames, text_frame, - kRightDecorationPadding); - DCHECK_EQ(decorations->size(), decoration_frames->size()); - - // Reverse the right-hand decorations so that overall everything is - // sorted left to right. - std::reverse(decorations->begin() + leading_count, decorations->end()); - std::reverse(decoration_frames->begin() + leading_count, - decoration_frames->end()); - - // Flip all frames in RTL. - if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) { - for (NSRect& rect : *decoration_frames) - rect.origin.x = - NSMinX(frame) + NSMaxX(frame) - NSWidth(rect) - NSMinX(rect); - text_frame->origin.x = NSMinX(frame) + NSMaxX(frame) - - NSWidth(*text_frame) - NSMinX(*text_frame); - leading_count = decorations->size() - leading_count; - } - - return leading_count; -} - -} // namespace - -@implementation AutocompleteTextFieldCell - -@synthesize isPopupMode = isPopupMode_; -@synthesize singlePixelLineWidth = singlePixelLineWidth_; - -- (CGFloat)topTextFrameOffset { - return 3.0; -} - -- (CGFloat)bottomTextFrameOffset { - return 3.0; -} - -- (CGFloat)cornerRadius { - return kCornerRadius; -} - -- (BOOL)shouldDrawBezel { - return YES; -} - -- (CGFloat)lineHeight { - return 17; -} - -- (NSText*)setUpFieldEditorAttributes:(NSText*)textObj { - NSText* fieldEditor = [super setUpFieldEditorAttributes:textObj]; - - // -[NSTextFieldCell setUpFieldEditorAttributes:] matches the field editor's - // background to its own background, which can cover our decorations in their - // hover state. See https://crbug.com/669870. - [fieldEditor setDrawsBackground:NO]; - return fieldEditor; -} - -- (void)clearTrackingArea { - for (auto* decoration : mouseTrackingDecorations_) - decoration->RemoveTrackingArea(); - - mouseTrackingDecorations_.clear(); -} - -- (void)clearDecorations { - leadingDecorations_.clear(); - trailingDecorations_.clear(); - [self clearTrackingArea]; -} - -- (void)addLeadingDecoration:(LocationBarDecoration*)decoration { - leadingDecorations_.push_back(decoration); -} - -- (void)addTrailingDecoration:(LocationBarDecoration*)decoration { - trailingDecorations_.push_back(decoration); -} - -- (CGFloat)availableWidthInFrame:(const NSRect)frame { - std::vector<LocationBarDecoration*> decorations; - std::vector<NSRect> decorationFrames; - NSRect textFrame; - CalculatePositionsInFrame(frame, leadingDecorations_, trailingDecorations_, - &decorations, &decorationFrames, &textFrame); - - return NSWidth(textFrame); -} - -- (NSRect)frameForDecoration:(const LocationBarDecoration*)aDecoration - inFrame:(NSRect)cellFrame { - // Short-circuit if the decoration is known to be not visible. - if (aDecoration && !aDecoration->IsVisible()) - return NSZeroRect; - - // Layout the decorations. - std::vector<LocationBarDecoration*> decorations; - std::vector<NSRect> decorationFrames; - NSRect textFrame; - CalculatePositionsInFrame(cellFrame, leadingDecorations_, - trailingDecorations_, &decorations, - &decorationFrames, &textFrame); - - // Find our decoration and return the corresponding frame. - std::vector<LocationBarDecoration*>::const_iterator iter = - std::find(decorations.begin(), decorations.end(), aDecoration); - if (iter != decorations.end()) { - const size_t index = iter - decorations.begin(); - return decorationFrames[index]; - } - - // Decorations which are not visible should have been filtered out - // at the top, but return |NSZeroRect| rather than a 0-width rect - // for consistency. This can happen while a window is being resized, if it - // becomes too small to contain a decoration in the process of shrinking. - return NSZeroRect; -} - -- (BOOL)isLeftDecoration:(LocationBarDecoration*)decoration { - std::vector<LocationBarDecoration*>& left_decorations = - cocoa_l10n_util::ShouldDoExperimentalRTLLayout() ? trailingDecorations_ - : leadingDecorations_; - return base::ContainsValue(left_decorations, decoration); -} - -// Overriden to account for the decorations. -- (NSRect)textFrameForFrame:(NSRect)cellFrame { - // Get the frame adjusted for decorations. - std::vector<LocationBarDecoration*> decorations; - std::vector<NSRect> decorationFrames; - NSRect textFrame = [super textFrameForFrame:cellFrame]; - CalculatePositionsInFrame(textFrame, leadingDecorations_, - trailingDecorations_, &decorations, - &decorationFrames, &textFrame); - - // The text needs to be slightly higher than its default position to match the - // Material Design spec. It turns out this adjustment is equal to the single - // pixel line width (so 1 on non-Retina, 0.5 on Retina). Make this adjustment - // after computing decoration positions because the decorations are already - // correctly positioned. The spec also calls for positioning the text 1pt to - // the right of its default position. - textFrame.origin.x += 1; - textFrame.size.width -= 1; - textFrame.origin.y -= singlePixelLineWidth_; - - // NOTE: This function must closely match the logic in - // |-drawInteriorWithFrame:inView:|. - - return textFrame; -} - -- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame { - std::vector<LocationBarDecoration*> decorations; - std::vector<NSRect> decorationFrames; - NSRect textFrame; - size_t left_count = CalculatePositionsInFrame( - cellFrame, leadingDecorations_, trailingDecorations_, &decorations, - &decorationFrames, &textFrame); - - // Determine the left-most extent for the i-beam cursor. - CGFloat minX = NSMinX(textFrame); - for (size_t index = left_count; index--; ) { - if (decorations[index]->AcceptsMousePress() != AcceptsPress::NEVER) - break; - - // If at leftmost decoration, expand to edge of cell. - if (!index) - minX = NSMinX(cellFrame); - else - minX = NSMinX(decorationFrames[index]); - } - - // Determine the right-most extent for the i-beam cursor. - CGFloat maxX = NSMaxX(textFrame); - for (size_t index = left_count; index < decorations.size(); ++index) { - if (decorations[index]->AcceptsMousePress() != AcceptsPress::NEVER) - break; - - // If at rightmost decoration, expand to edge of cell. - if (index == decorations.size() - 1) - maxX = NSMaxX(cellFrame); - else - maxX = NSMaxX(decorationFrames[index]); - } - - // I-beam cursor covers left-most to right-most. - return NSMakeRect(minX, NSMinY(textFrame), maxX - minX, NSHeight(textFrame)); -} - -- (void)drawWithFrame:(NSRect)frame inView:(NSView*)controlView { - BOOL inDarkMode = [[controlView window] inIncognitoModeWithSystemTheme]; - BOOL showingFirstResponder = [self showsFirstResponder]; - - // There's a special focus color for incognito, which needs to replace the - // border stroke to provide sufficient contrast with focus. - NSColor* opaqueFocusColor = inDarkMode - ? [NSColor colorWithSRGBRed:123 / 255. - green:170 / 255. - blue:247 / 255. - alpha:1] - : [NSColor keyboardFocusIndicatorColor]; - - // Set the border color. - const ui::ThemeProvider* provider = [[controlView window] themeProvider]; - bool increaseContrast = provider && provider->ShouldIncreaseContrast(); - if (!inDarkMode) { - if (increaseContrast) { - [[NSColor blackColor] set]; - } else { - const CGFloat kNormalStrokeGray = 168 / 255.; - [[NSColor colorWithCalibratedWhite:kNormalStrokeGray alpha:1] set]; - } - } else { - if (increaseContrast) { - [[NSColor whiteColor] set]; - } else if (showingFirstResponder) { - [opaqueFocusColor set]; - } else { - const CGFloat k30PercentAlpha = 0.3; - [[NSColor colorWithCalibratedWhite:0 alpha:k30PercentAlpha] set]; - } - } - - // First, draw the border with a filled rounded rectangle, and draw the - // "background" over it to make a stroke. This avoids drawing a stroke with - // inner and outer radii that differ by an irrational delta. The stroke is - // inset by one screen pixel from the frame to make room for the focus ring, - // should it be needed. - NSRect rect = - NSInsetRect(frame, singlePixelLineWidth_, singlePixelLineWidth_); - NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:rect - xRadius:kCornerRadius - yRadius:kCornerRadius]; - [path fill]; - - // Draw the "background". This will look terrible if it's not opaque. Note - // that insetting rounded rectangles also decreases the corner radius, - // consistent with SkRRect::inset(). - DCHECK_EQ(1.0, [[self backgroundColor] alphaComponent]); - [[self backgroundColor] set]; - const CGFloat innerBorderRadius = kCornerRadius - singlePixelLineWidth_; - rect = - NSInsetRect(frame, 2 * singlePixelLineWidth_, 2 * singlePixelLineWidth_); - path = [NSBezierPath bezierPathWithRoundedRect:rect - xRadius:innerBorderRadius - yRadius:innerBorderRadius]; - [path fill]; - - // Draw the interior contents. We do this after drawing the border as some - // of the interior controls draw over it. - [self drawInteriorWithFrame:frame inView:controlView]; - - if (!showingFirstResponder) - return; - - // Draw the focus ring. It is always 1 real pixel either side of the border. - // That is, 3 real pixels wide; filling the frame. - constexpr CGFloat kFocusAlpha = 0.5; - [[opaqueFocusColor colorWithAlphaComponent:kFocusAlpha] set]; - const CGFloat outerFocusRadius = kCornerRadius + singlePixelLineWidth_; - const CGFloat innerFocusRadius = kCornerRadius - 2 * singlePixelLineWidth_; - rect = - NSInsetRect(frame, 3 * singlePixelLineWidth_, 3 * singlePixelLineWidth_); - path = [NSBezierPath bezierPathWithRoundedRect:rect - xRadius:innerFocusRadius - yRadius:innerFocusRadius]; - [path setWindingRule:NSEvenOddWindingRule]; - [path appendBezierPath:[NSBezierPath - bezierPathWithRoundedRect:frame - xRadius:outerFocusRadius - yRadius:outerFocusRadius]]; - gfx::ScopedNSGraphicsContextSaveGState scopedGState; - [path addClip]; - // Clipping determines the shape, so just fill. - NSRectFillUsingOperation(frame, NSCompositeSourceOver); -} - -- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - ui::ScopedCGContextSmoothFonts fontSmoothing; - [super drawInteriorWithFrame:cellFrame inView:controlView]; - - // NOTE: This method must closely match the logic in |-textFrameForFrame:|. - std::vector<LocationBarDecoration*> decorations; - std::vector<NSRect> decorationFrames; - NSRect workingFrame; - - CalculatePositionsInFrame(cellFrame, leadingDecorations_, - trailingDecorations_, &decorations, - &decorationFrames, &workingFrame); - - // Draw the decorations. Do this after drawing the interior because the - // field editor's background rect overlaps the right edge of the security - // decoration's hover rounded rect. - for (size_t i = 0; i < decorations.size(); ++i) { - if (decorations[i]) { - decorations[i]->DrawWithBackgroundInFrame(decorationFrames[i], - controlView); - } - } -} - -- (BOOL)canDropAtLocationInWindow:(NSPoint)location - ofView:(AutocompleteTextField*)controlView { - NSRect cellFrame = [controlView bounds]; - const NSPoint locationInView = - [controlView convertPoint:location fromView:nil]; - - NSRect textFrame; - std::vector<LocationBarDecoration*> decorations; - std::vector<NSRect> decorationFrames; - CalculatePositionsInFrame(cellFrame, leadingDecorations_, - trailingDecorations_, &decorations, - &decorationFrames, &textFrame); - return NSPointInRect(locationInView, textFrame); -} - -- (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView -{ - return [self decorationForLocationInWindow:[theEvent locationInWindow] - inRect:cellFrame - ofView:controlView]; -} - -- (LocationBarDecoration*)decorationForLocationInWindow:(NSPoint)location - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*) - controlView { - const BOOL flipped = [controlView isFlipped]; - const NSPoint locationInView = - [controlView convertPoint:location fromView:nil]; - - std::vector<LocationBarDecoration*> decorations; - std::vector<NSRect> decorationFrames; - NSRect textFrame; - CalculatePositionsInFrame(cellFrame, leadingDecorations_, - trailingDecorations_, &decorations, - &decorationFrames, &textFrame); - - for (size_t i = 0; i < decorations.size(); ++i) { - if (NSMouseInRect(locationInView, decorationFrames[i], flipped)) - return decorations[i]; - } - - return NULL; -} - -- (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView { - LocationBarDecoration* decoration = - [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView]; - if (decoration) - return decoration->GetMenu(); - return nil; -} - -- (BOOL)mouseDown:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView { - // TODO(groby): Factor this into three pieces - find target for event, handle - // delayed focus (for any and all events), execute mouseDown for target. - - // Check if this mouseDown was the reason the control became firstResponder. - // If not, discard focus event. - base::scoped_nsobject<NSEvent> focusEvent(focusEvent_.release()); - if (![theEvent isEqual:focusEvent]) - focusEvent.reset(); - - LocationBarDecoration* decoration = - [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView]; - if (!decoration || decoration->AcceptsMousePress() == AcceptsPress::NEVER) - return NO; - - decoration->OnMouseDown(); - - NSRect decorationRect = - [self frameForDecoration:decoration inFrame:cellFrame]; - - // If the decoration is draggable, then initiate a drag if the user - // drags or holds the mouse down for awhile. - if (decoration->IsDraggable()) { - NSDate* timeout = - [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout]; - NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask | - NSLeftMouseUpMask) - untilDate:timeout - inMode:NSEventTrackingRunLoopMode - dequeue:YES]; - if (!event || [event type] == NSLeftMouseDragged) { - NSPasteboard* pboard = decoration->GetDragPasteboard(); - DCHECK(pboard); - - NSImage* image = decoration->GetDragImage(); - DCHECK(image); - - NSRect dragImageRect = decoration->GetDragImageFrame(decorationRect); - - // Center under mouse horizontally, with cursor below so the image - // can be seen. - const NSPoint mousePoint = - [controlView convertPoint:[theEvent locationInWindow] fromView:nil]; - dragImageRect.origin = - NSMakePoint(mousePoint.x - NSWidth(dragImageRect) / 2.0, - mousePoint.y - NSHeight(dragImageRect)); - draggedDecoration_ = decoration; - draggedDecoration_->SetActive(true); - - // -[NSView dragImage:at:*] wants the images lower-left point, - // regardless of -isFlipped. Converting the rect to window base - // coordinates doesn't require any special-casing. Note that - // -[NSView dragFile:fromRect:*] takes a rect rather than a - // point, likely for this exact reason. - const NSPoint dragPoint = - [controlView convertRect:dragImageRect toView:nil].origin; - [[controlView window] dragImage:image - at:dragPoint - offset:NSZeroSize - event:theEvent - pasteboard:pboard - source:self - slideBack:YES]; - - return YES; - } - - // On mouse-up fall through to mouse-pressed case. - DCHECK_EQ([event type], NSLeftMouseUp); - decoration->OnMouseUp(); - } - - const NSPoint mouseLocation = [theEvent locationInWindow]; - const NSPoint point = [controlView convertPoint:mouseLocation fromView:nil]; - return decoration->HandleMousePressed( - decorationRect, NSMakePoint(point.x - decorationRect.origin.x, - point.y - decorationRect.origin.y)); -} - -- (void)mouseUp:(NSEvent*)theEvent - inRect:(NSRect)cellFrame - ofView:(AutocompleteTextField*)controlView { - LocationBarDecoration* decoration = - [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView]; - if (decoration) - decoration->OnMouseUp(); -} - -// Returns the file path for file |name| if saved at NSURL |base|. -static NSString* PathWithBaseURLAndName(NSURL* base, NSString* name) { - NSString* filteredName = - [name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - return [[NSURL URLWithString:filteredName relativeToURL:base] path]; -} - -// Returns if there is already a file |name| at dir NSURL |base|. -static BOOL FileAlreadyExists(NSURL* base, NSString* name) { - NSString* path = PathWithBaseURLAndName(base, name); - DCHECK([path hasSuffix:name]); - return [[NSFileManager defaultManager] fileExistsAtPath:path]; -} - -// Takes a destination URL, a suggested file name, & an extension (eg .webloc). -// Returns the complete file name with extension you should use. -// The name returned will not contain /, : or ?, will not start with a dot, -// will not be longer than kMaxNameLength + length of extension, and will not -// be a file name that already exists in that directory. If necessary it will -// try appending a space and a number to the name (but before the extension) -// trying numbers up to and including kMaxIndex. -// If the function gives up it returns nil. -static NSString* UnusedLegalNameForNewDropFile(NSURL* saveLocation, - NSString *fileName, - NSString *extension) { - int number = 1; - const int kMaxIndex = 20; - const unsigned kMaxNameLength = 64; // Arbitrary. - - NSString* filteredName = [fileName stringByReplacingOccurrencesOfString:@"/" - withString:@"-"]; - filteredName = [filteredName stringByReplacingOccurrencesOfString:@":" - withString:@"-"]; - filteredName = [filteredName stringByReplacingOccurrencesOfString:@"?" - withString:@"-"]; - filteredName = - [filteredName stringByReplacingOccurrencesOfString:@"." - withString:@"-" - options:0 - range:NSMakeRange(0,1)]; - - if ([filteredName length] > kMaxNameLength) - filteredName = [filteredName substringToIndex:kMaxNameLength]; - - NSString* candidateName = [filteredName stringByAppendingString:extension]; - - while (FileAlreadyExists(saveLocation, candidateName)) { - if (number > kMaxIndex) - return nil; - else - candidateName = [filteredName stringByAppendingFormat:@" %d%@", - number++, extension]; - } - - return candidateName; -} - -- (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDestination { - NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - NSFileManager* fileManager = [NSFileManager defaultManager]; - - if (![pboard containsURLDataConvertingTextToURL:YES]) - return NULL; - - NSArray *urls = NULL; - NSArray* titles = NULL; - [pboard getURLs:&urls - andTitles:&titles - convertingFilenames:YES - convertingTextToURL:YES]; - - NSString* urlStr = [urls objectAtIndex:0]; - NSString* nameStr = [titles objectAtIndex:0]; - - NSString* nameWithExtensionStr = - UnusedLegalNameForNewDropFile(dropDestination, nameStr, @".webloc"); - if (!nameWithExtensionStr) - return NULL; - - NSDictionary* urlDict = [NSDictionary dictionaryWithObject:urlStr - forKey:@"URL"]; - NSURL* outputURL = - [NSURL fileURLWithPath:PathWithBaseURLAndName(dropDestination, - nameWithExtensionStr)]; - [urlDict writeToURL:outputURL - atomically:NO]; - - if (![fileManager fileExistsAtPath:[outputURL path]]) - return NULL; - - NSDictionary* attr = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:YES], NSFileExtensionHidden, - [NSNumber numberWithUnsignedLong:'ilht'], NSFileHFSTypeCode, - [NSNumber numberWithUnsignedLong:'MACS'], NSFileHFSCreatorCode, - nil]; - [fileManager setAttributes:attr - ofItemAtPath:[outputURL path] - error:nil]; - - return [NSArray arrayWithObject:nameWithExtensionStr]; -} - -- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { - return NSDragOperationCopy; -} - -- (void)draggingSession:(NSDraggingSession*)session - endedAtPoint:(NSPoint)screenPoint - operation:(NSDragOperation)operation { - DCHECK(draggedDecoration_); - draggedDecoration_->SetActive(false); - draggedDecoration_ = nullptr; -} - -- (void)updateMouseTrackingAndToolTipsInRect:(NSRect)cellFrame - ofView: - (AutocompleteTextField*)controlView { - std::vector<LocationBarDecoration*> decorations; - std::vector<NSRect> decorationFrames; - NSRect textFrame; - CalculatePositionsInFrame(cellFrame, leadingDecorations_, - trailingDecorations_, &decorations, - &decorationFrames, &textFrame); - [self clearTrackingArea]; - - for (size_t i = 0; i < decorations.size(); ++i) { - CrTrackingArea* trackingArea = - decorations[i]->SetupTrackingArea(decorationFrames[i], controlView); - if (trackingArea) - mouseTrackingDecorations_.push_back(decorations[i]); - - NSString* tooltip = decorations[i]->GetToolTip(); - if ([tooltip length] > 0) - [controlView addToolTip:tooltip forRect:decorationFrames[i]]; - } -} - -- (BOOL)hideFocusState { - return hideFocusState_; -} - -- (void)setHideFocusState:(BOOL)hideFocusState - ofView:(AutocompleteTextField*)controlView { - if (hideFocusState_ == hideFocusState) - return; - hideFocusState_ = hideFocusState; - [controlView setNeedsDisplay:YES]; - NSTextView* fieldEditor = - base::mac::ObjCCastStrict<NSTextView>([controlView currentEditor]); - [fieldEditor updateInsertionPointStateAndRestartTimer:YES]; -} - -- (BOOL)showsFirstResponder { - return [super showsFirstResponder] && !hideFocusState_; -} - -- (void)handleFocusEvent:(NSEvent*)event - ofView:(AutocompleteTextField*)controlView { - if ([controlView observer]) { - const bool controlDown = ([event modifierFlags] & NSControlKeyMask) != 0; - [controlView observer]->OnSetFocus(controlDown); - } -} - -- (int)leadingDecorationIndex:(LocationBarDecoration*)decoration { - for (size_t i = 0; i < leadingDecorations_.size(); ++i) - if (leadingDecorations_[i] == decoration) - return leadingDecorations_.size() - (i + 1); - return -1; -} - -@end - -@implementation AutocompleteTextFieldCell (TestingAPI) - -- (const std::vector<LocationBarDecoration*>&)mouseTrackingDecorations { - return mouseTrackingDecorations_; -} - -@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm deleted file mode 100644 index d5ccfdaa..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm +++ /dev/null
@@ -1,312 +0,0 @@ -// Copyright (c) 2011 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 <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#include "base/strings/utf_string_conversions.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#import "chrome/browser/ui/cocoa/test/scoped_force_rtl_mac.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#import "testing/gtest_mac.h" -#include "testing/platform_test.h" -#import "third_party/ocmock/OCMock/OCMock.h" -#include "third_party/ocmock/gtest_support.h" -#include "ui/base/material_design/material_design_controller.h" - -using ::testing::Return; -using ::testing::StrictMock; -using ::testing::_; - -namespace { - -// Width of the field so that we don't have to ask |field_| for it all -// the time. -const CGFloat kWidth(300.0); - -class MockDecoration : public LocationBarDecoration { - public: - virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; } - - MOCK_METHOD2(DrawInFrame, void(NSRect frame, NSView* control_view)); - MOCK_METHOD0(GetToolTip, NSString*()); -}; - -class AutocompleteTextFieldCellTest : public CocoaTest { - public: - AutocompleteTextFieldCellTest() { - // Make sure this is wide enough to play games with the cell - // decorations. - const NSRect frame = NSMakeRect(0, 0, kWidth, 30); - - base::scoped_nsobject<NSTextField> view( - [[NSTextField alloc] initWithFrame:frame]); - view_ = view.get(); - - base::scoped_nsobject<AutocompleteTextFieldCell> cell( - [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]); - [cell setEditable:YES]; - [cell setBordered:YES]; - - [cell clearDecorations]; - mock_leading_decoration_.SetVisible(false); - [cell addLeadingDecoration:&mock_leading_decoration_]; - mock_trailing_decoration0_.SetVisible(false); - mock_trailing_decoration1_.SetVisible(false); - [cell addTrailingDecoration:&mock_trailing_decoration0_]; - [cell addTrailingDecoration:&mock_trailing_decoration1_]; - - [view_ setCell:cell.get()]; - - [[test_window() contentView] addSubview:view_]; - } - - NSTextField* view_; - MockDecoration mock_leading_decoration_; - MockDecoration mock_trailing_decoration0_; - MockDecoration mock_trailing_decoration1_; -}; - -// Basic view tests (AddRemove, Display). -TEST_VIEW(AutocompleteTextFieldCellTest, view_); - -// Test drawing, mostly to ensure nothing leaks or crashes. -TEST_F(AutocompleteTextFieldCellTest, FocusedDisplay) { - [view_ display]; - - // Test focused drawing. - [test_window() makePretendKeyWindowAndSetFirstResponder:view_]; - [view_ display]; - [test_window() clearPretendKeyWindowAndFirstResponder]; - - // Test display of various cell configurations. - AutocompleteTextFieldCell* cell = - static_cast<AutocompleteTextFieldCell*>([view_ cell]); - - // Load available decorations and try drawing. To make sure that - // they are actually drawn, check that |GetWidthForSpace()| doesn't - // indicate that they should be omitted. - const CGFloat kVeryWide = 1000.0; - - // Make sure we're actually calling |DrawInFrame()|. - StrictMock<MockDecoration> mock_decoration; - mock_decoration.SetVisible(true); - [cell addLeadingDecoration:&mock_decoration]; - EXPECT_CALL(mock_decoration, DrawInFrame(_, _)); - EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide), - LocationBarDecoration::kOmittedWidth); - - [view_ display]; - - [cell clearDecorations]; -} - -TEST_F(AutocompleteTextFieldCellTest, TextFrame) { - AutocompleteTextFieldCell* cell = - static_cast<AutocompleteTextFieldCell*>([view_ cell]); - const NSRect bounds([view_ bounds]); - NSRect textFrame; - - // The cursor frame should stay the same throughout. - const NSRect cursorFrame([cell textCursorFrameForFrame:bounds]); - EXPECT_NSEQ(cursorFrame, bounds); - - // At default settings, everything goes to the text area. - textFrame = [cell textFrameForFrame:bounds]; - EXPECT_FALSE(NSIsEmptyRect(textFrame)); - EXPECT_TRUE(NSContainsRect(bounds, textFrame)); - EXPECT_EQ(1, NSMinX(textFrame)); - EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame)); - EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); - - // Leading decoration takes up space. - mock_leading_decoration_.SetVisible(true); - textFrame = [cell textFrameForFrame:bounds]; - EXPECT_FALSE(NSIsEmptyRect(textFrame)); - EXPECT_TRUE(NSContainsRect(bounds, textFrame)); - EXPECT_GT(NSMinX(textFrame), NSMinX(bounds)); - EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); -} - -// The editor frame should be slightly inset from the text frame. -TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) { - AutocompleteTextFieldCell* cell = - static_cast<AutocompleteTextFieldCell*>([view_ cell]); - const NSRect bounds([view_ bounds]); - NSRect textFrame, drawingRect; - - textFrame = [cell textFrameForFrame:bounds]; - drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_FALSE(NSIsEmptyRect(drawingRect)); - EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1))); - - // Save the starting frame for after clear. - const NSRect originalDrawingRect = drawingRect; - - mock_leading_decoration_.SetVisible(true); - textFrame = [cell textFrameForFrame:bounds]; - drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_FALSE(NSIsEmptyRect(drawingRect)); - EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); - - mock_trailing_decoration0_.SetVisible(true); - textFrame = [cell textFrameForFrame:bounds]; - drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_FALSE(NSIsEmptyRect(drawingRect)); - EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); - - mock_leading_decoration_.SetVisible(false); - mock_trailing_decoration0_.SetVisible(false); - drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_FALSE(NSIsEmptyRect(drawingRect)); - EXPECT_NSEQ(drawingRect, originalDrawingRect); -} - -// Test that leading decorations are at the correct edge of the cell. -TEST_F(AutocompleteTextFieldCellTest, LeadingDecorationFrame) { - AutocompleteTextFieldCell* cell = - static_cast<AutocompleteTextFieldCell*>([view_ cell]); - const NSRect bounds = [view_ bounds]; - - mock_leading_decoration_.SetVisible(true); - const NSRect decorationRect = - [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds]; - EXPECT_FALSE(NSIsEmptyRect(decorationRect)); - EXPECT_TRUE(NSContainsRect(bounds, decorationRect)); - - // Decoration should be left of |drawingRect|. - const NSRect drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_GT(NSMinX(drawingRect), NSMinX(decorationRect)); - - // Decoration should be left of |textFrame|. - const NSRect textFrame = [cell textFrameForFrame:bounds]; - EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect)); -} - -// Test that trailing decorations are at the correct edge of the cell. -TEST_F(AutocompleteTextFieldCellTest, TrailingDecorationFrame) { - AutocompleteTextFieldCell* cell = - static_cast<AutocompleteTextFieldCell*>([view_ cell]); - const NSRect bounds = [view_ bounds]; - - mock_trailing_decoration0_.SetVisible(true); - mock_trailing_decoration1_.SetVisible(true); - - const NSRect decoration0Rect = - [cell frameForDecoration:&mock_trailing_decoration0_ inFrame:bounds]; - EXPECT_FALSE(NSIsEmptyRect(decoration0Rect)); - EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect)); - - // Trailing decorations are ordered from innermost to outermost. - // Outer decoration (0) to right of inner decoration (1). - const NSRect decoration1Rect = - [cell frameForDecoration:&mock_trailing_decoration1_ inFrame:bounds]; - EXPECT_FALSE(NSIsEmptyRect(decoration1Rect)); - EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect)); - EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect)); - - // Decoration should be right of |drawingRect|. - const NSRect drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_LT(NSMinX(drawingRect), NSMinX(decoration1Rect)); - - // Decoration should be right of |textFrame|. - const NSRect textFrame = [cell textFrameForFrame:bounds]; - EXPECT_LT(NSMinX(textFrame), NSMinX(decoration1Rect)); -} - -// Verify -[AutocompleteTextFieldCell -// updateMouseTrackingAndToolTipsInRect:ofView:]. -TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) { - NSString* tooltip = @"tooltip"; - - // Leading decoration returns a tooltip, make sure it is called at - // least once. - mock_leading_decoration_.SetVisible(true); - EXPECT_CALL(mock_leading_decoration_, GetToolTip()) - .WillOnce(Return(tooltip)) - .WillRepeatedly(Return(tooltip)); - - // Right decoration returns no tooltip, make sure it is called at - // least once. - mock_trailing_decoration0_.SetVisible(true); - EXPECT_CALL(mock_trailing_decoration0_, GetToolTip()) - .WillOnce(Return((NSString*)nil)) - .WillRepeatedly(Return((NSString*)nil)); - - AutocompleteTextFieldCell* cell = - static_cast<AutocompleteTextFieldCell*>([view_ cell]); - const NSRect bounds = [view_ bounds]; - const NSRect leadingDecorationRect = - [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds]; - - // |controlView| gets the tooltip for the leading decoration. - id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]]; - [[controlView expect] addToolTip:tooltip forRect:leadingDecorationRect]; - - [cell updateMouseTrackingAndToolTipsInRect:bounds ofView:controlView]; - - EXPECT_OCMOCK_VERIFY(controlView); -} - -class AutocompleteTextFieldCellTestRTL : public AutocompleteTextFieldCellTest { - private: - cocoa_l10n_util::ScopedForceRTLMac rtl_; -}; - -// Test that leading decorations are at the correct edge of the cell. -TEST_F(AutocompleteTextFieldCellTestRTL, LeadingDecorationFrame) { - AutocompleteTextFieldCell* cell = - static_cast<AutocompleteTextFieldCell*>([view_ cell]); - const NSRect bounds = [view_ bounds]; - - mock_leading_decoration_.SetVisible(true); - const NSRect decorationRect = - [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds]; - EXPECT_FALSE(NSIsEmptyRect(decorationRect)); - EXPECT_TRUE(NSContainsRect(bounds, decorationRect)); - // Decoration should be right of |drawingRect|. - const NSRect drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_LT(NSMinX(drawingRect), NSMinX(decorationRect)); - - // Decoration should be right of |textFrame|. - const NSRect textFrame = [cell textFrameForFrame:bounds]; - EXPECT_LT(NSMinX(textFrame), NSMinX(decorationRect)); -} - -// Test that trailing decorations are at the correct edge of the cell. -TEST_F(AutocompleteTextFieldCellTestRTL, TrailingDecorationFrame) { - AutocompleteTextFieldCell* cell = - static_cast<AutocompleteTextFieldCell*>([view_ cell]); - const NSRect bounds = [view_ bounds]; - - mock_trailing_decoration0_.SetVisible(true); - mock_trailing_decoration1_.SetVisible(true); - - const NSRect decoration0Rect = - [cell frameForDecoration:&mock_trailing_decoration0_ inFrame:bounds]; - EXPECT_FALSE(NSIsEmptyRect(decoration0Rect)); - EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect)); - - // Trailing decorations are ordered from front to back.. - // Outer decoration (0) to the left of inner decoration (1). - const NSRect decoration1Rect = - [cell frameForDecoration:&mock_trailing_decoration1_ inFrame:bounds]; - EXPECT_FALSE(NSIsEmptyRect(decoration1Rect)); - EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect)); - EXPECT_GT(NSMinX(decoration1Rect), NSMinX(decoration0Rect)); - - // Decoration should be left of |drawingRect|. - const NSRect drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_GT(NSMinX(drawingRect), NSMinX(decoration1Rect)); - - // Decoration should be left of |textFrame|. - const NSRect textFrame = [cell textFrameForFrame:bounds]; - EXPECT_GT(NSMinX(textFrame), NSMinX(decoration1Rect)); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h deleted file mode 100644 index adaa98fa..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright (c) 2011 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_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_EDITOR_H_ -#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_EDITOR_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#import "chrome/browser/ui/cocoa/url_drop_target.h" - -@class AutocompleteTextField; -class AutocompleteTextFieldObserver; - -// AutocompleteTextFieldEditor customized the AutocompletTextField -// field editor (helper text-view used in editing). It intercepts UI -// events for forwarding to the core Omnibox code. It also undoes -// some of the effects of using styled text in the Omnibox (the text -// is styled but should not appear that way when copied to the -// pasteboard). - -// Field editor used for the autocomplete field. -@interface AutocompleteTextFieldEditor : NSTextView<URLDropTarget, - ThemedWindowDrawing> { - // Handles being a drag-and-drop target. We handle DnD directly instead - // allowing the |AutocompletTextField| to handle it (by making an empty - // |-updateDragTypeRegistration|), since the latter results in a weird - // start-up time regression. - base::scoped_nsobject<URLDropTargetHandler> dropHandler_; - - base::scoped_nsobject<NSCharacterSet> forbiddenCharacters_; - - // Indicates if the field editor's interpretKeyEvents: method is being called. - // If it's YES, then we should postpone the call to the observer's - // OnDidChange() method after the field editor's interpretKeyEvents: method - // is finished, rather than calling it in textDidChange: method. Because the - // input method may update the marked text after inserting some text, but we - // need the observer be aware of the marked text as well. - BOOL interpretingKeyEvents_; - - // Indicates if the text has been changed by key events. - BOOL textChangedByKeyEvents_; -} - -// The delegate is always an AutocompleteTextField*. Override the superclass -// implementations to allow for proper typing. -- (AutocompleteTextField*)delegate; -- (void)setDelegate:(AutocompleteTextField*)delegate; - -// Sets attributed string programatically through the field editor's text -// storage object. -- (void)setAttributedString:(NSAttributedString*)aString; - -@end - -@interface AutocompleteTextFieldEditor(PrivateTestMethods) -- (AutocompleteTextFieldObserver*)observer; -- (void)pasteAndGo:sender; -@end - -#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_EDITOR_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm deleted file mode 100644 index 3b2ff88..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm +++ /dev/null
@@ -1,616 +0,0 @@ -// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" - -#include "base/mac/sdk_forward_declarations.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "chrome/app/chrome_command_ids.h" // IDC_* -#include "chrome/browser/themes/theme_service.h" -#include "chrome/browser/ui/browser_list.h" -#import "chrome/browser/ui/cocoa/browser_window_controller.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" -#include "chrome/grit/generated_resources.h" -#import "ui/base/cocoa/find_pasteboard.h" -#import "ui/base/cocoa/touch_bar_forward_declarations.h" -#include "ui/base/l10n/l10n_util_mac.h" -#include "ui/base/material_design/material_design_controller.h" - -namespace { - -// Set to true when an instance of this class is running a nested run loop. -// Since this must always be run on the UI thread, there should never be two -// simultaneous drags. -bool gInDrag = false; - -// When too much data is put into a single-line text field, things get -// janky due to the cost of computing the blink rect. Sometimes users -// accidentally paste large amounts, so place a limit on what will be -// accepted. -// -// 10k characters was arbitrarily chosen by seeing how much a text -// field could handle in a single line before it started getting too -// janky to recover from (jankiness was detectable around 5k). -// www.google.com returns an error for searches around 2k characters, -// so this is conservative. -const NSUInteger kMaxPasteLength = 10000; - -// Returns |YES| if too much text would be pasted. -BOOL ThePasteboardIsTooDamnBig() { - NSPasteboard* pb = [NSPasteboard generalPasteboard]; - NSString* type = - [pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]]; - if (!type) - return NO; - - return [[pb stringForType:type] length] > kMaxPasteLength; -} - -// Returns a possibly disabled "Paste and {Go, Search}" menu item. -NSMenuItem* PasteAndGoMenuItemForObserver( - AutocompleteTextFieldObserver* observer) { - DCHECK(observer); - int string_id = IDS_PASTE_AND_GO; - BOOL enabled = !ThePasteboardIsTooDamnBig() && observer->CanPasteAndGo(); - if (enabled) - string_id = observer->GetPasteActionStringId(); - - NSString* title = l10n_util::GetNSStringWithFixup(string_id); - base::scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc] - initWithTitle:title - action:@selector(pasteAndGo:) - keyEquivalent:@""]); - [item setEnabled:enabled]; - return item.autorelease(); -} - -} // namespace - -@interface AutocompleteTextFieldEditor ()<NSDraggingSource> -@end - -@implementation AutocompleteTextFieldEditor - -- (BOOL)shouldDrawInsertionPoint { - return [super shouldDrawInsertionPoint] && - ![[[self delegate] cell] hideFocusState]; -} - -- (id)initWithFrame:(NSRect)frameRect { - if ((self = [super initWithFrame:frameRect])) { - dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]); - - forbiddenCharacters_.reset([[NSCharacterSet controlCharacterSet] retain]); - - // Disable all substitutions by default. In regular NSTextFields a user may - // selectively enable them via context menu, but that submenu is not enabled - // for the omnibox. The substitutions are unlikely to be useful in any case. - // - // Also see http://crbug.com/173405 and http://crbug.com/528014. - NSTextCheckingTypes checkingTypes = 0; - [self setEnabledTextCheckingTypes:checkingTypes]; - } - return self; -} - -// Overridden to prevent unwanted items from appearing in the Touch Bar. -- (NSTouchBar*)makeTouchBar { - return nil; -} - -- (void)updateColorsToMatchTheme { - if (![[self window] inIncognitoMode]) { - return; - } - - bool inDarkMode = [[self window] inIncognitoModeWithSystemTheme]; - // Draw a white insertion point for MD Incognito. - NSColor* insertionPointColor = - inDarkMode ? [NSColor whiteColor] : [NSColor blackColor]; - [self setInsertionPointColor:insertionPointColor]; - - NSColor* textSelectionColor = [NSColor selectedTextBackgroundColor]; - if (inDarkMode) { - // In MD Incognito the text is light gray against a dark background. When - // selected, the light gray text against the selection color is illegible. - // Rather than tweak or change the selection color, make the text black when - // selected. - [self setSelectedTextAttributes:@{ - NSForegroundColorAttributeName : [NSColor blackColor], - NSBackgroundColorAttributeName : textSelectionColor - }]; - } else { - [self setSelectedTextAttributes:@{ - NSBackgroundColorAttributeName : textSelectionColor - }]; - } -} - -- (void)viewDidMoveToWindow { - // Only care about landing in a window. - if ([self window]) { - [self updateColorsToMatchTheme]; - } -} - -// If the entire field is selected, drag the same data as would be -// dragged from the field's location icon. In some cases the textual -// contents will not contain relevant data (for instance, "http://" is -// stripped from URLs). -- (BOOL)dragSelectionWithEvent:(NSEvent *)event - offset:(NSSize)mouseOffset - slideBack:(BOOL)slideBack { - AutocompleteTextFieldObserver* observer = [self observer]; - DCHECK(observer); - if (observer && observer->CanCopy()) { - NSPoint p; - NSImage* image = [self dragImageForSelectionWithEvent:event origin:&p]; - - base::scoped_nsobject<NSPasteboardItem> item( - observer->CreatePasteboardItem()); - base::scoped_nsobject<NSDraggingItem> dragItem( - [[NSDraggingItem alloc] initWithPasteboardWriter:item]); - NSRect draggingFrame = - NSMakeRect(0, 0, image.size.width, image.size.height); - [dragItem setDraggingFrame:draggingFrame contents:image]; - [self beginDraggingSessionWithItems:@[ dragItem.get() ] - event:event - source:self]; - DCHECK(!gInDrag); - gInDrag = true; - while (gInDrag) { - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode - beforeDate:[NSDate distantFuture]]; - } - - return YES; - } - return [super dragSelectionWithEvent:event - offset:mouseOffset - slideBack:slideBack]; -} - -- (void)draggingSession:(NSDraggingSession*)session - endedAtPoint:(NSPoint)aPoint - operation:(NSDragOperation)operation { - gInDrag = false; -} - -- (void)copy:(id)sender { - AutocompleteTextFieldObserver* observer = [self observer]; - DCHECK(observer); - if (observer && observer->CanCopy()) - observer->CopyToPasteboard([NSPasteboard generalPasteboard]); -} - -- (void)cut:(id)sender { - [self copy:sender]; - [self delete:nil]; -} - -// This class assumes that the delegate is an AutocompleteTextField. -// Enforce that assumption. -- (AutocompleteTextField*)delegate { - AutocompleteTextField* delegate = - static_cast<AutocompleteTextField*>([super delegate]); - DCHECK(delegate == nil || - [delegate isKindOfClass:[AutocompleteTextField class]]); - return delegate; -} - -- (void)setDelegate:(AutocompleteTextField*)delegate { - DCHECK(delegate == nil || - [delegate isKindOfClass:[AutocompleteTextField class]]); - - // Unregister from any previously registered undo and redo notifications. - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc removeObserver:self - name:NSUndoManagerDidUndoChangeNotification - object:nil]; - [nc removeObserver:self - name:NSUndoManagerDidRedoChangeNotification - object:nil]; - - // Set the delegate. - [super setDelegate:delegate]; - - // Register for undo and redo notifications from the new |delegate|, if it is - // non-nil. - if ([self delegate]) { - NSUndoManager* undo_manager = [self undoManager]; - [nc addObserver:self - selector:@selector(didUndoOrRedo:) - name:NSUndoManagerDidUndoChangeNotification - object:undo_manager]; - [nc addObserver:self - selector:@selector(didUndoOrRedo:) - name:NSUndoManagerDidRedoChangeNotification - object:undo_manager]; - } -} - -- (void)didUndoOrRedo:(NSNotification *)aNotification { - AutocompleteTextFieldObserver* observer = [self observer]; - if (observer) - observer->OnDidChange(); -} - -// Convenience method for retrieving the observer from the delegate. -- (AutocompleteTextFieldObserver*)observer { - return [[self delegate] observer]; -} - -- (void)paste:(id)sender { - if (ThePasteboardIsTooDamnBig()) { - NSBeep(); - return; - } - - AutocompleteTextFieldObserver* observer = [self observer]; - DCHECK(observer); - if (observer) { - observer->OnPaste(); - } -} - -- (void)pasteAndMatchStyle:(id)sender { - [self paste:sender]; -} - -- (void)pasteAndGo:sender { - if (ThePasteboardIsTooDamnBig()) { - NSBeep(); - return; - } - - AutocompleteTextFieldObserver* observer = [self observer]; - DCHECK(observer); - if (observer) { - observer->OnPasteAndGo(); - } -} - -// We have rich text, but it shouldn't be modified by the user, so -// don't update the font panel. In theory, -setUsesFontPanel: should -// accomplish this, but that gets called frequently with YES when -// NSTextField and NSTextView synchronize their contents. That is -// probably unavoidable because in most cases having rich text in the -// field you probably would expect it to update the font panel. -- (void)updateFontPanel {} - -// No ruler bar, so don't update any of that state, either. -- (void)updateRuler {} - -- (NSMenu*)menuForEvent:(NSEvent*)event { - // Give the control a chance to provide page-action menus. - // NOTE: Note that page actions aren't even in the editor's - // boundaries! The Cocoa control implementation seems to do a - // blanket forward to here if nothing more specific is returned from - // the control and cell calls. - // TODO(shess): Determine if the page-action part of this can be - // moved to the cell. - NSMenu* actionMenu = [[self delegate] decorationMenuForEvent:event]; - if (actionMenu) - return actionMenu; - - NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"TITLE"] autorelease]; - [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_CUT) - action:@selector(cut:) - keyEquivalent:@""]; - [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_COPY) - action:@selector(copy:) - keyEquivalent:@""]; - - [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_PASTE) - action:@selector(paste:) - keyEquivalent:@""]; - - if ([self isEditable]) { - [menu addItem:PasteAndGoMenuItemForObserver([self observer])]; - [menu addItem:[NSMenuItem separatorItem]]; - - NSString* searchEngineLabel = - l10n_util::GetNSStringWithFixup(IDS_EDIT_SEARCH_ENGINES); - DCHECK([searchEngineLabel length]); - NSMenuItem* item = [menu addItemWithTitle:searchEngineLabel - action:@selector(commandDispatch:) - keyEquivalent:@""]; - [item setTag:IDC_EDIT_SEARCH_ENGINES]; - } - - return menu; -} - -// (Overridden from NSResponder) -- (BOOL)becomeFirstResponder { - BOOL doAccept = [super becomeFirstResponder]; - AutocompleteTextField* field = [self delegate]; - // Only lock visibility if we've been set up with a delegate (the text field). - if (doAccept && field) { - // Give the text field ownership of the visibility lock. (The first - // responder dance between the field and the field editor is a little - // weird.) - [[BrowserWindowController browserWindowControllerForView:field] - lockToolbarVisibilityForOwner:field - withAnimation:YES]; - } - return doAccept; -} - -// (Overridden from NSResponder) -- (BOOL)resignFirstResponder { - BOOL doResign = [super resignFirstResponder]; - AutocompleteTextField* field = [self delegate]; - // Only lock visibility if we've been set up with a delegate (the text field). - if (doResign && field) { - // Give the text field ownership of the visibility lock. - [[BrowserWindowController browserWindowControllerForView:field] - releaseToolbarVisibilityForOwner:field - withAnimation:YES]; - - AutocompleteTextFieldObserver* observer = [self observer]; - if (observer) - observer->OnKillFocus(); - } - return doResign; -} - -- (void)mouseDown:(NSEvent*)event { - AutocompleteTextFieldObserver* observer = [self observer]; - if (observer) - observer->OnMouseDown([event buttonNumber]); - [super mouseDown:event]; -} - -- (void)rightMouseDown:(NSEvent *)event { - AutocompleteTextFieldObserver* observer = [self observer]; - if (observer) - observer->OnMouseDown([event buttonNumber]); - [super rightMouseDown:event]; -} - -- (void)otherMouseDown:(NSEvent *)event { - AutocompleteTextFieldObserver* observer = [self observer]; - if (observer) - observer->OnMouseDown([event buttonNumber]); - [super otherMouseDown:event]; -} - -// (URLDropTarget protocol) -- (id<URLDropTargetController>)urlDropController { - BrowserWindowController* windowController = - [BrowserWindowController browserWindowControllerForView:self]; - return [windowController toolbarController]; -} - -// (URLDropTarget protocol) -- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { - // Make ourself the first responder (even though we're presumably already the - // first responder), which will select the text to indicate that our contents - // would be replaced by a drop. - [[self window] makeFirstResponder:self]; - return [dropHandler_ draggingEntered:sender]; -} - -// (URLDropTarget protocol) -- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { - return [dropHandler_ draggingUpdated:sender]; -} - -// (URLDropTarget protocol) -- (void)draggingExited:(id<NSDraggingInfo>)sender { - return [dropHandler_ draggingExited:sender]; -} - -// (URLDropTarget protocol) -- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { - return [dropHandler_ performDragOperation:sender]; -} - -// Prevent control characters from being entered into the Omnibox. -// This is invoked for keyboard entry, not for pasting. -- (void)insertText:(id)aString { - AutocompleteTextFieldObserver* observer = [self observer]; - if (observer) - observer->OnInsertText(); - - // Repeatedly remove control characters. The loop will only ever - // execute at all when the user enters control characters (using - // Ctrl-Alt- or Ctrl-Q). Making this generally efficient would - // probably be a loss, since the input always seems to be a single - // character. - if ([aString isKindOfClass:[NSAttributedString class]]) { - NSRange range = - [[aString string] rangeOfCharacterFromSet:forbiddenCharacters_]; - while (range.location != NSNotFound) { - aString = [[aString mutableCopy] autorelease]; - [aString deleteCharactersInRange:range]; - range = [[aString string] rangeOfCharacterFromSet:forbiddenCharacters_]; - } - DCHECK_EQ(range.length, 0U); - } else { - NSRange range = [aString rangeOfCharacterFromSet:forbiddenCharacters_]; - while (range.location != NSNotFound) { - aString = - [aString stringByReplacingCharactersInRange:range withString:@""]; - range = [aString rangeOfCharacterFromSet:forbiddenCharacters_]; - } - DCHECK_EQ(range.length, 0U); - } - - // NOTE: If |aString| is empty, this intentionally replaces the - // selection with empty. This seems consistent with the case where - // the input contained a mixture of characters and the string ended - // up not empty. - [super insertText:aString]; -} - -- (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange - granularity:(NSSelectionGranularity)granularity { - AutocompleteTextFieldObserver* observer = [self observer]; - NSRange modifiedRange = [super selectionRangeForProposedRange:proposedSelRange - granularity:granularity]; - if (observer) - return observer->SelectionRangeForProposedRange(modifiedRange); - return modifiedRange; -} - -- (void)setSelectedRange:(NSRange)charRange - affinity:(NSSelectionAffinity)affinity - stillSelecting:(BOOL)flag { - [super setSelectedRange:charRange affinity:affinity stillSelecting:flag]; - - // We're only interested in selection changes directly caused by keyboard - // input from the user. - if (interpretingKeyEvents_) - textChangedByKeyEvents_ = YES; -} - -- (void)interpretKeyEvents:(NSArray *)eventArray { - DCHECK(!interpretingKeyEvents_); - interpretingKeyEvents_ = YES; - textChangedByKeyEvents_ = NO; - AutocompleteTextFieldObserver* observer = [self observer]; - - if (observer) - observer->OnBeforeChange(); - - [super interpretKeyEvents:eventArray]; - - if (textChangedByKeyEvents_ && observer) - observer->OnDidChange(); - - DCHECK(interpretingKeyEvents_); - interpretingKeyEvents_ = NO; - - // -[NSTextView interpretKeyEvents:] invalidates the existing layout. - // - // observer->OnDidChange() calls OmniboxViewMac::ApplyTextStyle, which - // invalidates the existing layout again, but in a slightly different way. - // Details unclear. - // - // On older versions of macOS, this results in a single call to -[NSTextView - // drawRect:] on the next frame, which paints the correct contents. - // - // On macOS 10.12 dp4, for unknown reasons, this causes two calls to - // -[NSTextView drawRect:] across two(!) frames. The first call to - // -[NSTextView drawRect:] draws no text, which causes a flicker in the - // omnibox. Forcing a layout ensures that drawRect: is only called once, and - // is drawn with the correct contents. - // https://crbug.com/634318. - [self.layoutManager - ensureLayoutForCharacterRange:NSMakeRange(0, self.textStorage.length)]; -} - -- (BOOL)shouldChangeTextInRange:(NSRange)affectedCharRange - replacementString:(NSString *)replacementString { - BOOL ret = [super shouldChangeTextInRange:affectedCharRange - replacementString:replacementString]; - - if (ret && !interpretingKeyEvents_) { - AutocompleteTextFieldObserver* observer = [self observer]; - if (observer) - observer->OnBeforeChange(); - } - return ret; -} - -- (void)didChangeText { - [super didChangeText]; - - AutocompleteTextFieldObserver* observer = [self observer]; - if (observer) { - if (!interpretingKeyEvents_ && - ![[self undoManager] isUndoing] && ![[self undoManager] isRedoing]) { - observer->OnDidChange(); - } else if (interpretingKeyEvents_) { - textChangedByKeyEvents_ = YES; - } - } -} - -- (void)doCommandBySelector:(SEL)cmd { - // TODO(shess): Review code for cases where we're fruitlessly attempting to - // work in spite of not having an observer. - AutocompleteTextFieldObserver* observer = [self observer]; - - if (observer && observer->OnDoCommandBySelector(cmd)) { - // The observer should already be aware of any changes to the text, so - // setting |textChangedByKeyEvents_| to NO to prevent its OnDidChange() - // method from being called unnecessarily. - textChangedByKeyEvents_ = NO; - return; - } - - // If the escape key was pressed and no revert happened, give focus to the web - // contents. In fullscreen, this will dismiss the overlay. - if (cmd == @selector(cancelOperation:)) { - BrowserWindowController* windowController = - [BrowserWindowController browserWindowControllerForView:self]; - [windowController focusTabContents]; - textChangedByKeyEvents_ = NO; - return; - } - - [super doCommandBySelector:cmd]; -} - -- (void)setAttributedString:(NSAttributedString*)aString { - NSTextStorage* textStorage = [self textStorage]; - DCHECK(textStorage); - [textStorage setAttributedString:aString]; - - // The text has been changed programmatically. The observer should know - // this change, so setting |textChangedByKeyEvents_| to NO to - // prevent its OnDidChange() method from being called unnecessarily. - textChangedByKeyEvents_ = NO; -} - -- (BOOL)validateMenuItem:(NSMenuItem*)item { - if ([item action] == @selector(copyToFindPboard:)) - return [self selectedRange].length > 0; - - // Paste & Go doesn't appear in the mainMenu. Use the enabled state when the - // menu item was added in -menuForEvent:. - if ([item action] == @selector(pasteAndGo:)) - return [item isEnabled]; - - return [super validateMenuItem:item]; -} - -- (void)copyToFindPboard:(id)sender { - NSRange selectedRange = [self selectedRange]; - if (selectedRange.length == 0) - return; - NSAttributedString* selection = - [self attributedSubstringForProposedRange:selectedRange - actualRange:NULL]; - if (!selection) - return; - - [[FindPasteboard sharedInstance] setFindText:[selection string]]; -} - -- (void)drawRect:(NSRect)rect { - AutocompleteTextFieldObserver* observer = [self observer]; - if (observer) - observer->OnBeforeDrawRect(); - [super drawRect:rect]; - if (observer) - observer->OnDidDrawRect(); -} - -// ThemedWindowDrawing implementation. - -- (void)windowDidChangeTheme { - [self updateColorsToMatchTheme]; -} - -- (void)windowDidChangeActive { -} - -@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm deleted file mode 100644 index f4e8081..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm +++ /dev/null
@@ -1,330 +0,0 @@ -// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" - -#include <memory> - -#include "base/mac/scoped_nsobject.h" -#include "base/strings/string_util.h" -#include "chrome/app/chrome_command_ids.h" // IDC_* -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "chrome/grit/generated_resources.h" -#include "testing/gmock/include/gmock/gmock-matchers.h" -#include "testing/gtest/include/gtest/gtest.h" -#import "testing/gtest_mac.h" -#include "testing/platform_test.h" -#import "third_party/ocmock/OCMock/OCMock.h" -#include "third_party/ocmock/gtest_support.h" -#import "third_party/ocmock/ocmock_extensions.h" -#import "ui/base/cocoa/touch_bar_forward_declarations.h" -#import "ui/events/test/cocoa_test_event_utils.h" - -using ::testing::Return; -using ::testing::ReturnArg; -using ::testing::StrictMock; -using ::testing::A; - -namespace { - -NSMenu* MenuFromRightClick(AutocompleteTextFieldEditor* editor) { - NSEvent* event = cocoa_test_event_utils::MouseEventAtPoint( - NSZeroPoint, NSRightMouseDown, 0); - return [editor menuForEvent:event]; -} - -// TODO(shess): Very similar to AutocompleteTextFieldTest. Maybe -// those can be shared. - -class AutocompleteTextFieldEditorTest : public CocoaTest { - public: - void SetUp() override { - CocoaTest::SetUp(); - NSRect frame = NSMakeRect(0, 0, 50, 30); - base::scoped_nsobject<AutocompleteTextField> field( - [[AutocompleteTextField alloc] initWithFrame:frame]); - field_ = field.get(); - [field_ setStringValue:@"Testing"]; - [[test_window() contentView] addSubview:field_]; - - // Arrange for |field_| to get the right field editor. - window_delegate_.reset( - [[AutocompleteTextFieldWindowTestDelegate alloc] init]); - [test_window() setDelegate:window_delegate_.get()]; - - // Get the field editor setup. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - editor_ = static_cast<AutocompleteTextFieldEditor*>([field_ currentEditor]); - - EXPECT_TRUE(editor_); - EXPECT_TRUE([editor_ isKindOfClass:[AutocompleteTextFieldEditor class]]); - } - - AutocompleteTextFieldEditor* editor_; - AutocompleteTextField* field_; - base::scoped_nsobject<AutocompleteTextFieldWindowTestDelegate> - window_delegate_; -}; - -// Disabled because it crashes sometimes. http://crbug.com/49522 -// Can't rename DISABLED_ because the TEST_VIEW macro prepends. -// http://crbug.com/53621 -#if 0 -TEST_VIEW(AutocompleteTextFieldEditorTest, field_); -#endif - -// Test that control characters are stripped from insertions. -TEST_F(AutocompleteTextFieldEditorTest, InsertStripsControlChars) { - // Sets a string in the field. - NSString* test_string = @"astring"; - [field_ setStringValue:test_string]; - [editor_ selectAll:nil]; - - [editor_ insertText:@"t"]; - EXPECT_NSEQ(@"t", [field_ stringValue]); - - [editor_ insertText:@"h"]; - EXPECT_NSEQ(@"th", [field_ stringValue]); - - // TAB doesn't get inserted. - [editor_ insertText:[NSString stringWithFormat:@"%c", 7]]; - EXPECT_NSEQ(@"th", [field_ stringValue]); - - // Newline doesn't get inserted. - [editor_ insertText:[NSString stringWithFormat:@"%c", 12]]; - EXPECT_NSEQ(@"th", [field_ stringValue]); - - // Multi-character strings get through. - [editor_ insertText:[NSString stringWithFormat:@"i%cs%c", 8, 127]]; - EXPECT_NSEQ(@"this", [field_ stringValue]); - - // Attempting to insert newline when everything is selected clears - // the field. - [editor_ selectAll:nil]; - [editor_ insertText:[NSString stringWithFormat:@"%c", 12]]; - EXPECT_NSEQ(@"", [field_ stringValue]); -} - -// Test that |delegate| can provide page action menus. -TEST_F(AutocompleteTextFieldEditorTest, PageActionMenus) { - // The event just needs to be something the mock can recognize. - NSEvent* event = cocoa_test_event_utils::MouseEventAtPoint(NSZeroPoint, - NSRightMouseDown, - 0); - - // Trivial menu which we can recognize and which doesn't look like - // the default editor context menu. - base::scoped_nsobject<id> menu([[NSMenu alloc] initWithTitle:@"Menu"]); - [menu addItemWithTitle:@"Go Fish" - action:@selector(goFish:) - keyEquivalent:@""]; - - // So that we don't have to mock the observer. - [editor_ setEditable:NO]; - - // The delegate's intercept point gets called, and results are - // propagated back. - { - id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]]; - [[[delegate stub] andReturnBool:YES] - isKindOfClass:[AutocompleteTextField class]]; - [[[delegate expect] andReturn:menu.get()] decorationMenuForEvent:event]; - [[[delegate expect] andReturn:nil] undoManagerForTextView:editor_]; - [editor_ setDelegate:delegate]; - NSMenu* contextMenu = [editor_ menuForEvent:event]; - EXPECT_OCMOCK_VERIFY(delegate); - [editor_ setDelegate:nil]; - - EXPECT_EQ(contextMenu, menu.get()); - } - - // If the delegate does not return any menu, the default menu is - // returned. - { - id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]]; - [[[delegate stub] andReturnBool:YES] - isKindOfClass:[AutocompleteTextField class]]; - [[[delegate expect] andReturn:nil] decorationMenuForEvent:event]; - [[[delegate expect] andReturn:nil] undoManagerForTextView:editor_]; - [editor_ setDelegate:delegate]; - NSMenu* contextMenu = [editor_ menuForEvent:event]; - EXPECT_OCMOCK_VERIFY(delegate); - [editor_ setDelegate:nil]; - - EXPECT_NE(contextMenu, menu.get()); - NSArray* items = [contextMenu itemArray]; - ASSERT_GT([items count], 0U); - EXPECT_EQ(@selector(cut:), [[items objectAtIndex:0] action]) - << "action is: " << sel_getName([[items objectAtIndex:0] action]); - } -} - -// Base class for testing AutocompleteTextFieldObserver messages. -class AutocompleteTextFieldEditorObserverTest - : public AutocompleteTextFieldEditorTest { - public: - virtual void SetUp() { - AutocompleteTextFieldEditorTest::SetUp(); - [field_ setObserver:&field_observer_]; - } - - virtual void TearDown() { - // Clear the observer so that we don't show output for - // uninteresting messages to the mock (for instance, if |field_| has - // focus at the end of the test). - [field_ setObserver:NULL]; - - AutocompleteTextFieldEditorTest::TearDown(); - } - - StrictMock<MockAutocompleteTextFieldObserver> field_observer_; -}; - -// Test that the field editor is linked in correctly. -TEST_F(AutocompleteTextFieldEditorTest, FirstResponder) { - EXPECT_EQ(editor_, [field_ currentEditor]); - EXPECT_TRUE([editor_ isDescendantOf:field_]); - EXPECT_EQ([editor_ delegate], field_); - EXPECT_EQ([editor_ observer], [field_ observer]); -} - -// Test drawing, mostly to ensure nothing leaks or crashes. -TEST_F(AutocompleteTextFieldEditorTest, Display) { - [field_ display]; - [editor_ display]; -} - -// Tests that the Touch Bar is nothing. -TEST_F(AutocompleteTextFieldEditorTest, TouchBarTest) { - if (@available(macOS 10.12.2, *)) { - NSTouchBar* touch_bar = [field_ performSelector:@selector(touchBar)]; - EXPECT_FALSE(touch_bar); - } -} - -// Test that -paste: is correctly delegated to the observer. -TEST_F(AutocompleteTextFieldEditorObserverTest, Paste) { - EXPECT_CALL(field_observer_, OnPaste()); - [editor_ paste:nil]; -} - -// Test that -copy: is correctly delegated to the observer. -TEST_F(AutocompleteTextFieldEditorObserverTest, Copy) { - EXPECT_CALL(field_observer_, CanCopy()) - .WillOnce(Return(true)); - EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>())) - .Times(1); - [editor_ copy:nil]; -} - -// Test that -cut: is correctly delegated to the observer and clears -// the text field. -TEST_F(AutocompleteTextFieldEditorObserverTest, Cut) { - // Sets a string in the field. - NSString* test_string = @"astring"; - EXPECT_CALL(field_observer_, OnDidBeginEditing()); - EXPECT_CALL(field_observer_, OnBeforeChange()); - EXPECT_CALL(field_observer_, OnDidChange()); - EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>())) - .WillRepeatedly(ReturnArg<0>()); - [editor_ setString:test_string]; - [editor_ selectAll:nil]; - - // Calls cut. - EXPECT_CALL(field_observer_, CanCopy()) - .WillOnce(Return(true)); - EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>())) - .Times(1); - [editor_ cut:nil]; - - // Check if the field is cleared. - ASSERT_EQ([[editor_ textStorage] length], 0U); -} - -// Test that -pasteAndGo: is correctly delegated to the observer. -TEST_F(AutocompleteTextFieldEditorObserverTest, PasteAndGo) { - EXPECT_CALL(field_observer_, OnPasteAndGo()); - [editor_ pasteAndGo:nil]; -} - -// Test that the menu is constructed correctly. -TEST_F(AutocompleteTextFieldEditorObserverTest, Menu) { - EXPECT_CALL(field_observer_, CanPasteAndGo()).WillOnce(Return(true)); - EXPECT_CALL(field_observer_, GetPasteActionStringId()). - WillOnce(Return(IDS_PASTE_AND_GO)); - - NSMenu* menu = MenuFromRightClick(editor_); - NSArray* items = [menu itemArray]; - ASSERT_EQ([items count], 6U); - // TODO(shess): Check the titles, too? - NSUInteger i = 0; // Use an index to make future changes easier. - EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:)); - EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:)); - EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:)); - NSMenuItem* pasteAndGo = [items objectAtIndex:i++]; - EXPECT_EQ([pasteAndGo action], @selector(pasteAndGo:)); - EXPECT_TRUE([pasteAndGo isEnabled]); - EXPECT_TRUE([[items objectAtIndex:i++] isSeparatorItem]); - EXPECT_EQ([[items objectAtIndex:i] tag], IDC_EDIT_SEARCH_ENGINES); - EXPECT_EQ([[items objectAtIndex:i++] action], @selector(commandDispatch:)); -} - -// Test that the menu is constructed correctly when field isn't -// editable. -TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoMenuNotEditable) { - [field_ setEditable:NO]; - [editor_ setEditable:NO]; - - // Never call this when not editable. - EXPECT_CALL(field_observer_, GetPasteActionStringId()).Times(0); - - NSMenu* menu = MenuFromRightClick(editor_); - NSArray* items = [menu itemArray]; - ASSERT_EQ([items count], 3U); - // TODO(shess): Check the titles, too? - NSUInteger i = 0; // Use an index to make future changes easier. - EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:)); - EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:)); - EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:)); -} - -// Test that the menu validation works as expected when CanPasteAndGo(). -TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoValidate) { - EXPECT_CALL(field_observer_, GetPasteActionStringId()) - .WillOnce(Return(IDS_PASTE_AND_GO)); - EXPECT_CALL(field_observer_, CanPasteAndGo()).WillOnce(Return(true)); - - NSMenu* menu = MenuFromRightClick(editor_); - NSArray* items = [menu itemArray]; - ASSERT_EQ([items count], 6U); - for (NSUInteger i = 0; i < [items count]; ++i) { - NSMenuItem* item = [items objectAtIndex:i]; - if ([item action] == @selector(pasteAndGo:)) { - EXPECT_TRUE([item isEnabled]); - EXPECT_TRUE([editor_ validateMenuItem:item]); - break; - } - } -} - -// Test that the GetPasteActionStringId() is not called when !CanPasteAndGo(). -TEST_F(AutocompleteTextFieldEditorObserverTest, CannotPasteAndGoValidate) { - EXPECT_CALL(field_observer_, GetPasteActionStringId()).Times(0); - EXPECT_CALL(field_observer_, CanPasteAndGo()).WillOnce(Return(false)); - - NSMenu* menu = MenuFromRightClick(editor_); - NSArray* items = [menu itemArray]; - ASSERT_EQ([items count], 6U); - for (NSUInteger i = 0; i < [items count]; ++i) { - NSMenuItem* item = [items objectAtIndex:i]; - if ([item action] == @selector(pasteAndGo:)) { - EXPECT_FALSE([item isEnabled]); - EXPECT_FALSE([editor_ validateMenuItem:item]); - break; - } - } -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm deleted file mode 100644 index 6ad7b0b7..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm +++ /dev/null
@@ -1,980 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import <ApplicationServices/ApplicationServices.h> -#import <Cocoa/Cocoa.h> - -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#import "testing/gtest_mac.h" -#include "testing/platform_test.h" -#include "ui/base/cocoa/cocoa_base_utils.h" - -using ::testing::A; -using ::testing::InSequence; -using ::testing::Return; -using ::testing::ReturnArg; -using ::testing::StrictMock; -using ::testing::_; - -namespace { - -class MockDecoration : public LocationBarDecoration { - public: - virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; } - - virtual void DrawInFrame(NSRect frame, NSView* control_view) { ; } - MOCK_METHOD0(AcceptsMousePress, AcceptsPress()); - MOCK_METHOD2(OnMousePressed, bool(NSRect frame, NSPoint location)); - MOCK_METHOD0(GetMenu, NSMenu*()); -}; - -// Mock up an incrementing event number. -NSUInteger eventNumber = 0; - -// Create an event of the indicated |type| at |point| within |view|. -// TODO(shess): Would be nice to have a MockApplication which provided -// nifty accessors to create these things and inject them. It could -// even provide functions for "Click and drag mouse from point A to -// point B". -NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type, - const NSUInteger clickCount) { - NSWindow* window([view window]); - const NSPoint locationInWindow([view convertPoint:point toView:nil]); - const NSPoint location = - ui::ConvertPointFromWindowToScreen(window, locationInWindow); - return [NSEvent mouseEventWithType:type - location:location - modifierFlags:0 - timestamp:0 - windowNumber:[window windowNumber] - context:nil - eventNumber:eventNumber++ - clickCount:clickCount - pressure:0.0]; -} -NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type) { - return Event(view, point, type, 1); -} - -// Width of the field so that we don't have to ask |field_| for it all -// the time. -static const CGFloat kWidth(300.0); - -class AutocompleteTextFieldTest : public CocoaTest { - public: - AutocompleteTextFieldTest() { - // Make sure this is wide enough to play games with the cell - // decorations. - NSRect frame = NSMakeRect(0, 0, kWidth, 30); - base::scoped_nsobject<AutocompleteTextField> field( - [[AutocompleteTextField alloc] initWithFrame:frame]); - field_ = field.get(); - [field_ setStringValue:@"Test test"]; - [[test_window() contentView] addSubview:field_]; - - AutocompleteTextFieldCell* cell = [field_ cell]; - [cell clearDecorations]; - - mock_leading_decoration_.SetVisible(false); - [cell addLeadingDecoration:&mock_leading_decoration_]; - - mock_trailing_decoration_.SetVisible(false); - [cell addTrailingDecoration:&mock_trailing_decoration_]; - - window_delegate_.reset( - [[AutocompleteTextFieldWindowTestDelegate alloc] init]); - [test_window() setDelegate:window_delegate_.get()]; - } - - NSEvent* KeyDownEventWithFlags(NSUInteger flags) { - return [NSEvent keyEventWithType:NSKeyDown - location:NSZeroPoint - modifierFlags:flags - timestamp:0.0 - windowNumber:[test_window() windowNumber] - context:nil - characters:@"a" - charactersIgnoringModifiers:@"a" - isARepeat:NO - keyCode:'a']; - } - - // Helper to return the field-editor frame being used w/in |field_|. - NSRect EditorFrame() { - EXPECT_TRUE([field_ currentEditor]); - EXPECT_EQ([[field_ subviews] count], 1U); - if ([[field_ subviews] count] > 0) { - return [[[field_ subviews] objectAtIndex:0] frame]; - } else { - // Return something which won't work so the caller can soldier - // on. - return NSZeroRect; - } - } - - AutocompleteTextFieldEditor* FieldEditor() { - return base::mac::ObjCCastStrict<AutocompleteTextFieldEditor>( - [field_ currentEditor]); - } - - AutocompleteTextField* field_; - MockDecoration mock_leading_decoration_; - MockDecoration mock_trailing_decoration_; - base::scoped_nsobject<AutocompleteTextFieldWindowTestDelegate> - window_delegate_; -}; - -TEST_VIEW(AutocompleteTextFieldTest, field_); - -// Base class for testing AutocompleteTextFieldObserver messages. -class AutocompleteTextFieldObserverTest : public AutocompleteTextFieldTest { - public: - virtual void SetUp() { - AutocompleteTextFieldTest::SetUp(); - [field_ setObserver:&field_observer_]; - } - - virtual void TearDown() { - // Clear the observer so that we don't show output for - // uninteresting messages to the mock (for instance, if |field_| has - // focus at the end of the test). - [field_ setObserver:NULL]; - - AutocompleteTextFieldTest::TearDown(); - } - - // Returns the center point of the decoration. - NSPoint ClickLocationForDecoration(LocationBarDecoration* decoration) { - AutocompleteTextFieldCell* cell = [field_ cell]; - NSRect decoration_rect = - [cell frameForDecoration:decoration inFrame:[field_ bounds]]; - EXPECT_FALSE(NSIsEmptyRect(decoration_rect)); - return NSMakePoint(NSMidX(decoration_rect), NSMidY(decoration_rect)); - } - - void SendMouseClickToDecoration(LocationBarDecoration* decoration) { - NSPoint point = ClickLocationForDecoration(decoration); - NSEvent* downEvent = Event(field_, point, NSLeftMouseDown); - NSEvent* upEvent = Event(field_, point, NSLeftMouseUp); - - // Can't just use -sendEvent:, since that doesn't populate -currentEvent. - [NSApp postEvent:downEvent atStart:YES]; - [NSApp postEvent:upEvent atStart:NO]; - - NSEvent* next_event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue:YES]; - [NSApp sendEvent:next_event]; - } - - StrictMock<MockAutocompleteTextFieldObserver> field_observer_; -}; - -// Test that we have the right cell class. -TEST_F(AutocompleteTextFieldTest, CellClass) { - EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]); -} - -// Test that becoming first responder sets things up correctly. -TEST_F(AutocompleteTextFieldTest, FirstResponder) { - EXPECT_EQ(nil, [field_ currentEditor]); - EXPECT_EQ([[field_ subviews] count], 0U); - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - EXPECT_FALSE(nil == [field_ currentEditor]); - EXPECT_EQ([[field_ subviews] count], 1U); - EXPECT_TRUE([[field_ currentEditor] isDescendantOf:field_]); - - // Check that the window delegate is providing the right editor. - Class c = [AutocompleteTextFieldEditor class]; - EXPECT_TRUE([[field_ currentEditor] isKindOfClass:c]); -} - -TEST_F(AutocompleteTextFieldTest, AvailableDecorationWidth) { - // A fudge factor to account for how much space the border takes up. - // The test shouldn't be too dependent on the field's internals, but - // it also shouldn't let deranged cases fall through the cracks - // (like nothing available with no text, or everything available - // with some text). - const CGFloat kBorderWidth = 20.0; - - // With no contents, almost the entire width is available for - // decorations. - [field_ setStringValue:@""]; - CGFloat availableWidth = [field_ availableDecorationWidth]; - EXPECT_LE(availableWidth, kWidth); - EXPECT_GT(availableWidth, kWidth - kBorderWidth); - - // With minor contents, most of the remaining width is available for - // decorations. - NSDictionary* attributes = - [NSDictionary dictionaryWithObject:[field_ font] - forKey:NSFontAttributeName]; - NSString* string = @"Hello world"; - const NSSize size([string sizeWithAttributes:attributes]); - [field_ setStringValue:string]; - availableWidth = [field_ availableDecorationWidth]; - EXPECT_LE(availableWidth, kWidth - size.width); - EXPECT_GT(availableWidth, kWidth - size.width - kBorderWidth); - - // With huge contents, nothing at all is left for decorations. - string = @"A long string which is surely wider than field_ can hold."; - [field_ setStringValue:string]; - availableWidth = [field_ availableDecorationWidth]; - EXPECT_LT(availableWidth, 0.0); -} - -// Test drawing, mostly to ensure nothing leaks or crashes. -TEST_F(AutocompleteTextFieldTest, Display) { - [field_ display]; - - // Test focussed drawing. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - [field_ display]; -} - -TEST_F(AutocompleteTextFieldObserverTest, FlagsChanged) { - InSequence dummy; // Call mock in exactly the order specified. - - // Test without Control key down, but some other modifier down. - EXPECT_CALL(field_observer_, OnControlKeyChanged(false)); - [field_ flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)]; - - // Test with Control key down. - EXPECT_CALL(field_observer_, OnControlKeyChanged(true)); - [field_ flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)]; -} - -// This test is here rather than in the editor's tests because the -// field catches -flagsChanged: because it's on the responder chain, -// the field editor doesn't implement it. -TEST_F(AutocompleteTextFieldObserverTest, FieldEditorFlagsChanged) { - // Many of these methods try to change the selection. - EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>())) - .WillRepeatedly(ReturnArg<0>()); - - InSequence dummy; // Call mock in exactly the order specified. - EXPECT_CALL(field_observer_, OnSetFocus(false)); - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - NSResponder* firstResponder = [[field_ window] firstResponder]; - EXPECT_EQ(firstResponder, [field_ currentEditor]); - - // Test without Control key down, but some other modifier down. - EXPECT_CALL(field_observer_, OnControlKeyChanged(false)); - [firstResponder flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)]; - - // Test with Control key down. - EXPECT_CALL(field_observer_, OnControlKeyChanged(true)); - [firstResponder flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)]; -} - -// Frame size changes are propagated to |observer_|. -TEST_F(AutocompleteTextFieldObserverTest, FrameChanged) { - EXPECT_CALL(field_observer_, OnFrameChanged()); - NSRect frame = [field_ frame]; - frame.size.width += 10.0; - [field_ setFrame:frame]; -} - -// Test that the field editor gets the same bounds when focus is -// delivered by the standard focusing machinery, or by -// -resetFieldEditorFrameIfNeeded. -TEST_F(AutocompleteTextFieldTest, ResetFieldEditorBase) { - // Capture the editor frame resulting from the standard focus - // machinery. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - const NSRect baseEditorFrame = EditorFrame(); - - // A decoration should result in a strictly smaller editor frame. - mock_leading_decoration_.SetVisible(true); - [field_ resetFieldEditorFrameIfNeeded]; - EXPECT_NSNE(baseEditorFrame, EditorFrame()); - EXPECT_TRUE(NSContainsRect(baseEditorFrame, EditorFrame())); - - // Removing the decoration and using -resetFieldEditorFrameIfNeeded - // should result in the same frame as the standard focus machinery. - mock_leading_decoration_.SetVisible(false); - [field_ resetFieldEditorFrameIfNeeded]; - EXPECT_NSEQ(baseEditorFrame, EditorFrame()); -} - -// Test that the field editor gets the same bounds when focus is -// delivered by the standard focusing machinery, or by -// -resetFieldEditorFrameIfNeeded, this time with a decoration -// pre-loaded. -TEST_F(AutocompleteTextFieldTest, ResetFieldEditorWithDecoration) { - AutocompleteTextFieldCell* cell = [field_ cell]; - - // Make sure decoration isn't already visible, then make it visible. - EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_ - inFrame:[field_ bounds]])); - mock_leading_decoration_.SetVisible(true); - EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_ - inFrame:[field_ bounds]])); - - // Capture the editor frame resulting from the standard focus - // machinery. - - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - const NSRect baseEditorFrame = EditorFrame(); - - // When the decoration is not visible the frame should be strictly larger. - mock_leading_decoration_.SetVisible(false); - EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_ - inFrame:[field_ bounds]])); - [field_ resetFieldEditorFrameIfNeeded]; - EXPECT_NSNE(baseEditorFrame, EditorFrame()); - EXPECT_TRUE(NSContainsRect(EditorFrame(), baseEditorFrame)); - - // When the decoration is visible, -resetFieldEditorFrameIfNeeded - // should result in the same frame as the standard focus machinery. - mock_leading_decoration_.SetVisible(true); - EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_ - inFrame:[field_ bounds]])); - - [field_ resetFieldEditorFrameIfNeeded]; - EXPECT_NSEQ(baseEditorFrame, EditorFrame()); -} - -// Test that resetting the field editor bounds does not cause untoward -// messages to the field's observer. -TEST_F(AutocompleteTextFieldObserverTest, ResetFieldEditorContinuesEditing) { - // Many of these methods try to change the selection. - EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>())) - .WillRepeatedly(ReturnArg<0>()); - - EXPECT_CALL(field_observer_, OnSetFocus(false)); - // Becoming first responder doesn't begin editing. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - const NSRect baseEditorFrame = EditorFrame(); - NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]); - EXPECT_TRUE(nil != editor); - - // This should begin editing and indicate a change. - EXPECT_CALL(field_observer_, OnDidBeginEditing()); - EXPECT_CALL(field_observer_, OnBeforeChange()); - EXPECT_CALL(field_observer_, OnDidChange()); - [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""]; - [editor didChangeText]; - - // No messages to |field_observer_| when the frame actually changes. - mock_leading_decoration_.SetVisible(true); - [field_ resetFieldEditorFrameIfNeeded]; - EXPECT_NSNE(baseEditorFrame, EditorFrame()); -} - -// Clicking in a right-hand decoration which does not handle the mouse -// puts the caret rightmost. -TEST_F(AutocompleteTextFieldTest, ClickRightDecorationPutsCaretRightmost) { - // Decoration does not handle the mouse event, so the cell should - // process it. Called at least once. - EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress()) - .WillOnce(Return(AcceptsPress::NEVER)) - .WillRepeatedly(Return(AcceptsPress::NEVER)); - - // Set the decoration before becoming responder. - EXPECT_FALSE([field_ currentEditor]); - mock_trailing_decoration_.SetVisible(true); - - // Make first responder should select all. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - EXPECT_TRUE([field_ currentEditor]); - const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]); - EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange])); - - // Generate a click on the decoration. - AutocompleteTextFieldCell* cell = [field_ cell]; - const NSRect bounds = [field_ bounds]; - const NSRect iconFrame = - [cell frameForDecoration:&mock_trailing_decoration_ inFrame:bounds]; - const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); - NSEvent* downEvent = Event(field_, point, NSLeftMouseDown); - NSEvent* upEvent = Event(field_, point, NSLeftMouseUp); - [NSApp postEvent:upEvent atStart:YES]; - [field_ mouseDown:downEvent]; - - // Selection should be a right-hand-side caret. - EXPECT_TRUE(NSEqualRanges(NSMakeRange([[field_ stringValue] length], 0), - [[field_ currentEditor] selectedRange])); -} - -// Clicking in a left-side decoration which doesn't handle the event -// puts the selection in the leftmost position. -TEST_F(AutocompleteTextFieldTest, ClickLeftDecorationPutsCaretLeftmost) { - // Decoration does not handle the mouse event, so the cell should - // process it. Called at least once. - EXPECT_CALL(mock_leading_decoration_, AcceptsMousePress()) - .WillOnce(Return(AcceptsPress::NEVER)) - .WillRepeatedly(Return(AcceptsPress::NEVER)); - - // Set the decoration before becoming responder. - EXPECT_FALSE([field_ currentEditor]); - mock_leading_decoration_.SetVisible(true); - - // Make first responder should select all. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - EXPECT_TRUE([field_ currentEditor]); - const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]); - EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange])); - - // Generate a click on the decoration. - AutocompleteTextFieldCell* cell = [field_ cell]; - const NSRect bounds = [field_ bounds]; - const NSRect iconFrame = - [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds]; - const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); - NSEvent* downEvent = Event(field_, point, NSLeftMouseDown); - NSEvent* upEvent = Event(field_, point, NSLeftMouseUp); - [NSApp postEvent:upEvent atStart:YES]; - [field_ mouseDown:downEvent]; - - // Selection should be a left-hand-side caret. - EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, 0), - [[field_ currentEditor] selectedRange])); -} - -// Clicks not in the text area or the cell's decorations fall through -// to the editor. -TEST_F(AutocompleteTextFieldTest, ClickBorderSelectsAll) { - // Can't rely on the window machinery to make us first responder, - // here. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - EXPECT_TRUE([field_ currentEditor]); - - const NSPoint point(NSMakePoint(20.0, 1.0)); - NSEvent* downEvent(Event(field_, point, NSLeftMouseDown)); - NSEvent* upEvent(Event(field_, point, NSLeftMouseUp)); - [NSApp postEvent:upEvent atStart:YES]; - [field_ mouseDown:downEvent]; - - // Clicking in the narrow border area around a Cocoa NSTextField - // does a select-all. Regardless of whether this is a good call, it - // works as a test that things get passed down to the editor. - const NSRange selectedRange([[field_ currentEditor] selectedRange]); - EXPECT_EQ(selectedRange.location, 0U); - EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]); -} - -// Single-click with no drag should setup a field editor and -// select all. -TEST_F(AutocompleteTextFieldTest, ClickSelectsAll) { - EXPECT_FALSE([field_ currentEditor]); - - const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds])); - NSEvent* downEvent(Event(field_, point, NSLeftMouseDown)); - NSEvent* upEvent(Event(field_, point, NSLeftMouseUp)); - [NSApp postEvent:upEvent atStart:YES]; - [field_ mouseDown:downEvent]; - EXPECT_TRUE([field_ currentEditor]); - const NSRange selectedRange([[field_ currentEditor] selectedRange]); - EXPECT_EQ(selectedRange.location, 0U); - EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]); -} - -// Click-drag selects text, not select all. -TEST_F(AutocompleteTextFieldTest, ClickDragSelectsText) { - EXPECT_FALSE([field_ currentEditor]); - - NSEvent* downEvent(Event(field_, NSMakePoint(20.0, 5.0), NSLeftMouseDown)); - NSEvent* upEvent(Event(field_, NSMakePoint(0.0, 5.0), NSLeftMouseUp)); - [NSApp postEvent:upEvent atStart:YES]; - [field_ mouseDown:downEvent]; - EXPECT_TRUE([field_ currentEditor]); - - // Expect this to have selected a prefix of the content. Mostly - // just don't want the select-all behavior. - const NSRange selectedRange([[field_ currentEditor] selectedRange]); - EXPECT_EQ(selectedRange.location, 0U); - EXPECT_LT(selectedRange.length, [[field_ stringValue] length]); -} - -// TODO(shess): Test that click/pause/click allows cursor placement. -// In this case the first click goes to the field, but the second -// click goes to the field editor, so the current testing pattern -// can't work. What really needs to happen is to push through the -// NSWindow event machinery so that we can say "two independent clicks -// at the same location have the right effect". Once that is done, it -// might make sense to revise the other tests to use the same -// machinery. - -// Double-click selects word, not select all. -TEST_F(AutocompleteTextFieldTest, DoubleClickSelectsWord) { - EXPECT_FALSE([field_ currentEditor]); - - const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds])); - NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1)); - NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1)); - NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2)); - NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2)); - [NSApp postEvent:upEvent atStart:YES]; - [field_ mouseDown:downEvent]; - [NSApp postEvent:upEvent2 atStart:YES]; - [field_ mouseDown:downEvent2]; - EXPECT_TRUE([field_ currentEditor]); - - // Selected the first word. - const NSRange selectedRange([[field_ currentEditor] selectedRange]); - const NSRange spaceRange([[field_ stringValue] rangeOfString:@" "]); - EXPECT_GT(spaceRange.location, 0U); - EXPECT_LT(spaceRange.length, [[field_ stringValue] length]); - EXPECT_EQ(selectedRange.location, 0U); - EXPECT_EQ(selectedRange.length, spaceRange.location); -} - -TEST_F(AutocompleteTextFieldTest, TripleClickSelectsAll) { - EXPECT_FALSE([field_ currentEditor]); - - const NSPoint point(NSMakePoint(20.0, 5.0)); - NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1)); - NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1)); - NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2)); - NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2)); - NSEvent* downEvent3(Event(field_, point, NSLeftMouseDown, 3)); - NSEvent* upEvent3(Event(field_, point, NSLeftMouseUp, 3)); - [NSApp postEvent:upEvent atStart:YES]; - [field_ mouseDown:downEvent]; - [NSApp postEvent:upEvent2 atStart:YES]; - [field_ mouseDown:downEvent2]; - [NSApp postEvent:upEvent3 atStart:YES]; - [field_ mouseDown:downEvent3]; - EXPECT_TRUE([field_ currentEditor]); - - // Selected the first word. - const NSRange selectedRange([[field_ currentEditor] selectedRange]); - EXPECT_EQ(selectedRange.location, 0U); - EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]); -} - -// Clicking a decoration should call decoration's OnMousePressed. -TEST_F(AutocompleteTextFieldTest, LeftDecorationMouseDown) { - // At this point, not focussed. - EXPECT_FALSE([field_ currentEditor]); - - mock_leading_decoration_.SetVisible(true); - EXPECT_CALL(mock_leading_decoration_, AcceptsMousePress()) - .WillRepeatedly(Return(AcceptsPress::ALWAYS)); - - AutocompleteTextFieldCell* cell = [field_ cell]; - [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_]; - - const NSRect iconFrame = [cell frameForDecoration:&mock_leading_decoration_ - inFrame:[field_ bounds]]; - const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); - NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1); - NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1); - - // Since decorations can be dragged, the mouse-press is sent on - // mouse-up. - [NSApp postEvent:upEvent atStart:YES]; - - EXPECT_CALL(mock_leading_decoration_, OnMousePressed(_, _)) - .WillOnce(Return(true)); - [field_ mouseDown:downEvent]; - - // Focus the field and test that handled clicks don't affect selection. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - EXPECT_TRUE([field_ currentEditor]); - const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]); - EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange])); - - // Generate another click on the decoration. - downEvent = Event(field_, location, NSLeftMouseDown, 1); - upEvent = Event(field_, location, NSLeftMouseUp, 1); - [NSApp postEvent:upEvent atStart:YES]; - EXPECT_CALL(mock_leading_decoration_, OnMousePressed(_, _)) - .WillOnce(Return(true)); - [field_ mouseDown:downEvent]; - - // The selection should not have changed. - EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange])); - - // TODO(shess): Test that mouse drags are initiated if the next - // event is a drag, or if the mouse-up takes too long to arrive. - // IDEA: mock decoration to return a pasteboard which a mock - // AutocompleteTextField notes in -dragImage:*. -} - -// Clicking a decoration should call decoration's OnMousePressed. -TEST_F(AutocompleteTextFieldTest, RightDecorationMouseDown) { - // At this point, not focussed. - EXPECT_FALSE([field_ currentEditor]); - - mock_trailing_decoration_.SetVisible(true); - EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress()) - .WillRepeatedly(Return(AcceptsPress::ALWAYS)); - - AutocompleteTextFieldCell* cell = [field_ cell]; - [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_]; - - const NSRect bounds = [field_ bounds]; - const NSRect iconFrame = - [cell frameForDecoration:&mock_trailing_decoration_ inFrame:bounds]; - const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); - NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1); - NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1); - - // Since decorations can be dragged, the mouse-press is sent on - // mouse-up. - [NSApp postEvent:upEvent atStart:YES]; - - EXPECT_CALL(mock_trailing_decoration_, OnMousePressed(_, _)) - .WillOnce(Return(true)); - [field_ mouseDown:downEvent]; -} - -// Test that page action menus are properly returned. -// TODO(shess): Really, this should test that things are forwarded to -// the cell, and the cell tests should test that the right things are -// selected. It's easier to mock the event here, though. This code's -// event-mockers might be worth promoting to |cocoa_test_event_utils.h| or -// |cocoa_test_helper.h|. -TEST_F(AutocompleteTextFieldTest, DecorationMenu) { - AutocompleteTextFieldCell* cell = [field_ cell]; - const NSRect bounds([field_ bounds]); - - const CGFloat edge = NSHeight(bounds) - 4.0; - const NSSize size = NSMakeSize(edge, edge); - base::scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:size]); - - base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu"]); - - mock_leading_decoration_.SetVisible(true); - mock_trailing_decoration_.SetVisible(true); - - // The item with a menu returns it. - NSRect actionFrame = - [cell frameForDecoration:&mock_trailing_decoration_ inFrame:bounds]; - NSPoint location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame)); - NSEvent* event = Event(field_, location, NSRightMouseDown, 1); - - // Check that the decoration is called, and the field returns the - // menu. - EXPECT_CALL(mock_trailing_decoration_, GetMenu()) - .WillOnce(Return(menu.get())); - NSMenu *decorationMenu = [field_ decorationMenuForEvent:event]; - EXPECT_EQ(decorationMenu, menu); - - // The item without a menu returns nil. - EXPECT_CALL(mock_leading_decoration_, GetMenu()) - .WillOnce(Return(static_cast<NSMenu*>(nil))); - actionFrame = - [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds]; - location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame)); - event = Event(field_, location, NSRightMouseDown, 1); - EXPECT_FALSE([field_ decorationMenuForEvent:event]); - - // Something not in an action returns nil. - location = NSMakePoint(NSMidX(bounds), NSMidY(bounds)); - event = Event(field_, location, NSRightMouseDown, 1); - EXPECT_FALSE([field_ decorationMenuForEvent:event]); -} - -// Verify that -setAttributedStringValue: works as expected when -// focussed or when not focussed. Our code mostly depends on about -// whether -stringValue works right. -TEST_F(AutocompleteTextFieldTest, SetAttributedStringBaseline) { - EXPECT_EQ(nil, [field_ currentEditor]); - - // So that we can set rich text. - [field_ setAllowsEditingTextAttributes:YES]; - - // Set an attribute different from the field's default so we can - // tell we got the same string out as we put in. - NSFont* font = [NSFont fontWithDescriptor:[[field_ font] fontDescriptor] - size:[[field_ font] pointSize] + 2]; - NSDictionary* attributes = - [NSDictionary dictionaryWithObject:font - forKey:NSFontAttributeName]; - NSString* const kString = @"This is a test"; - base::scoped_nsobject<NSAttributedString> attributedString( - [[NSAttributedString alloc] initWithString:kString - attributes:attributes]); - - // Check that what we get back looks like what we put in. - EXPECT_NSNE(kString, [field_ stringValue]); - [field_ setAttributedStringValue:attributedString]; - EXPECT_TRUE([[field_ attributedStringValue] - isEqualToAttributedString:attributedString]); - EXPECT_NSEQ(kString, [field_ stringValue]); - - // Try that again with focus. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - - EXPECT_TRUE([field_ currentEditor]); - - // Check that what we get back looks like what we put in. - [field_ setStringValue:@""]; - EXPECT_NSNE(kString, [field_ stringValue]); - [field_ setAttributedStringValue:attributedString]; - EXPECT_TRUE([[field_ attributedStringValue] - isEqualToAttributedString:attributedString]); - EXPECT_NSEQ(kString, [field_ stringValue]); -} - -// -setAttributedStringValue: shouldn't reset the undo state if things -// are being editted. -TEST_F(AutocompleteTextFieldTest, SetAttributedStringUndo) { - NSColor* redColor = [NSColor redColor]; - NSDictionary* attributes = - [NSDictionary dictionaryWithObject:redColor - forKey:NSForegroundColorAttributeName]; - NSString* const kString = @"This is a test"; - base::scoped_nsobject<NSAttributedString> attributedString( - [[NSAttributedString alloc] initWithString:kString - attributes:attributes]); - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - EXPECT_TRUE([field_ currentEditor]); - NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]); - NSUndoManager* undoManager = [editor undoManager]; - EXPECT_TRUE(undoManager); - - // Nothing to undo, yet. - EXPECT_FALSE([undoManager canUndo]); - - // Starting an editing action creates an undoable item. - [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""]; - [editor didChangeText]; - EXPECT_TRUE([undoManager canUndo]); - - // -setStringValue: resets the editor's undo chain. - [field_ setStringValue:kString]; - EXPECT_FALSE([undoManager canUndo]); - - // Verify that -setAttributedStringValue: does not reset the - // editor's undo chain. - [field_ setStringValue:@""]; - [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""]; - [editor didChangeText]; - EXPECT_TRUE([undoManager canUndo]); - [field_ setAttributedStringValue:attributedString]; - EXPECT_TRUE([undoManager canUndo]); - - // Verify that calling -clearUndoChain clears the undo chain. - [field_ clearUndoChain]; - EXPECT_FALSE([undoManager canUndo]); -} - -TEST_F(AutocompleteTextFieldTest, EditorGetsCorrectUndoManager) { - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - - NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]); - EXPECT_TRUE(editor); - EXPECT_EQ([field_ undoManagerForTextView:editor], [editor undoManager]); -} - -// Verify that hideFocusState correctly hides the focus ring and insertion -// pointer. -TEST_F(AutocompleteTextFieldTest, HideFocusState) { - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - [[field_ cell] setShowsFirstResponder:YES]; - - EXPECT_TRUE([[field_ cell] showsFirstResponder]); - EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]); - - [[field_ cell] setHideFocusState:YES - ofView:field_]; - EXPECT_FALSE([[field_ cell] showsFirstResponder]); - EXPECT_FALSE([FieldEditor() shouldDrawInsertionPoint]); - - [[field_ cell] setHideFocusState:NO - ofView:field_]; - EXPECT_TRUE([[field_ cell] showsFirstResponder]); - EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]); -} - -// Verify that the tracking areas are added properly. -TEST_F(AutocompleteTextFieldTest, UpdateTrackingAreas) { - AutocompleteTextFieldCell* cell = [field_ cell]; - - mock_leading_decoration_.SetVisible(true); - mock_trailing_decoration_.SetVisible(true); - - EXPECT_CALL(mock_leading_decoration_, AcceptsMousePress()) - .WillOnce(Return(AcceptsPress::ALWAYS)) - .WillRepeatedly(Return(AcceptsPress::ALWAYS)); - EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress()) - .WillOnce(Return(AcceptsPress::NEVER)) - .WillRepeatedly(Return(AcceptsPress::NEVER)); - [cell updateMouseTrackingAndToolTipsInRect:[field_ bounds] ofView:field_]; - - EXPECT_EQ([cell mouseTrackingDecorations].size(), 1.0); - - [cell clearTrackingArea]; - EXPECT_TRUE([cell mouseTrackingDecorations].empty()); - - EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress()) - .WillOnce(Return(AcceptsPress::ALWAYS)) - .WillRepeatedly(Return(AcceptsPress::ALWAYS)); - - [cell updateMouseTrackingAndToolTipsInRect:[field_ bounds] ofView:field_]; - EXPECT_EQ([cell mouseTrackingDecorations].size(), 2.0); -} - -// Verify that clicking a decoration that accepts mouse clicks does not focus -// the Omnibox. -TEST_F(AutocompleteTextFieldObserverTest, - ClickingDecorationDoesNotFocusOmnibox) { - AutocompleteTextFieldCell* cell = [field_ cell]; - - // Set up a non-interactive decoration. - MockDecoration noninteractive_decoration; - noninteractive_decoration.SetVisible(true); - EXPECT_CALL(noninteractive_decoration, AcceptsMousePress()) - .WillRepeatedly(Return(AcceptsPress::NEVER)); - [cell addLeadingDecoration:&noninteractive_decoration]; - - // Set up an interactive decoration. - MockDecoration interactive_decoration; - EXPECT_CALL(interactive_decoration, AcceptsMousePress()) - .WillRepeatedly(Return(AcceptsPress::ALWAYS)); - interactive_decoration.SetVisible(true); - [cell addLeadingDecoration:&interactive_decoration]; - [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_]; - EXPECT_CALL(interactive_decoration, OnMousePressed(_, _)) - .WillRepeatedly(testing::Return(true)); - - // Ignore incidental calls. The exact frequency of these calls doesn't matter - // as they are auxiliary. - EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(_)) - .WillRepeatedly(testing::Return(NSMakeRange(0, 0))); - EXPECT_CALL(field_observer_, OnMouseDown(_)).Times(testing::AnyNumber()); - EXPECT_CALL(field_observer_, OnSetFocus(false)).Times(testing::AnyNumber()); - EXPECT_CALL(field_observer_, OnKillFocus()).Times(testing::AnyNumber()); - EXPECT_CALL(field_observer_, OnDidEndEditing()).Times(testing::AnyNumber()); - EXPECT_CALL(field_observer_, OnBeforeDrawRect()).Times(testing::AnyNumber()); - EXPECT_CALL(field_observer_, OnDidDrawRect()).Times(testing::AnyNumber()); - - // Ensure the field is currently not first responder. - [test_window() makePretendKeyWindowAndSetFirstResponder:nil]; - NSResponder* firstResponder = [[field_ window] firstResponder]; - EXPECT_FALSE( - [base::mac::ObjCCast<NSView>(firstResponder) isDescendantOf:field_]); - - // Clicking an interactive decoration doesn't change the first responder. - SendMouseClickToDecoration(&interactive_decoration); - EXPECT_NSEQ(firstResponder, [[field_ window] firstResponder]); - - // Clicking a non-interactive decoration focuses the Omnibox. - SendMouseClickToDecoration(&noninteractive_decoration); - firstResponder = [[field_ window] firstResponder]; - EXPECT_TRUE( - [base::mac::ObjCCast<NSView>(firstResponder) isDescendantOf:field_]); - - // Clicking an interactive decoration doesn't change the first responder. - SendMouseClickToDecoration(&interactive_decoration); - EXPECT_NSEQ(firstResponder, [[field_ window] firstResponder]); -} - -// Verify the behavior of AcceptsPress::WHEN_ACTIVATED. -TEST_F(AutocompleteTextFieldObserverTest, ReceivePressOnlyWhenActivated) { - AutocompleteTextFieldCell* cell = [field_ cell]; - - // Have the mock use AcceptsPress::WHEN_ACTIVATED. - MockDecoration decoration; - EXPECT_CALL(decoration, AcceptsMousePress()) - .WillRepeatedly(Return(AcceptsPress::WHEN_ACTIVATED)); - - decoration.SetVisible(true); - [cell addLeadingDecoration:&decoration]; - [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_]; - - EXPECT_CALL(field_observer_, OnMouseDown(_)).Times(testing::AnyNumber()); - - // Expect a call to OnMousePressed(), since the decoration is not active yet. - EXPECT_CALL(decoration, OnMousePressed(_, _)).WillOnce(Return(true)); - SendMouseClickToDecoration(&decoration); - decoration.SetActive(true); - - // Click again: should be no additional calls, since the decoration is active. - EXPECT_CALL(decoration, OnMousePressed(_, _)).Times(0); - SendMouseClickToDecoration(&decoration); - - // Most popups will call SetActive(false) due to a click occurring outside the - // bubble. (But there is defensive code that makes this unnecessary). Test - // what a popup _should_ do. - decoration.SetActive(false); - EXPECT_CALL(decoration, OnMousePressed(_, _)).WillOnce(Return(true)); - SendMouseClickToDecoration(&decoration); - - // And test a misbehaving bubble that forgets to call SetActive(false). It - // should still see the second click. - decoration.SetActive(true); - EXPECT_CALL(decoration, OnMousePressed(_, _)).Times(0); - SendMouseClickToDecoration(&decoration); - EXPECT_CALL(decoration, OnMousePressed(_, _)).WillOnce(Return(true)); - SendMouseClickToDecoration(&decoration); - - // Verify that AcceptsPress::ALWAYS receives presses when active. - EXPECT_CALL(decoration, AcceptsMousePress()) - .WillRepeatedly(Return(AcceptsPress::ALWAYS)); - decoration.SetActive(true); - EXPECT_CALL(decoration, OnMousePressed(_, _)).WillOnce(Return(true)); - SendMouseClickToDecoration(&decoration); -} - -TEST_F(AutocompleteTextFieldObserverTest, SendsEditingMessages) { - // Many of these methods try to change the selection. - EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>())) - .WillRepeatedly(ReturnArg<0>()); - - EXPECT_CALL(field_observer_, OnSetFocus(false)); - // Becoming first responder doesn't begin editing. - [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; - NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]); - EXPECT_TRUE(nil != editor); - - // This should begin editing and indicate a change. - EXPECT_CALL(field_observer_, OnDidBeginEditing()); - EXPECT_CALL(field_observer_, OnBeforeChange()); - EXPECT_CALL(field_observer_, OnDidChange()); - [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""]; - [editor didChangeText]; - - // Further changes don't send the begin message. - EXPECT_CALL(field_observer_, OnBeforeChange()); - EXPECT_CALL(field_observer_, OnDidChange()); - [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""]; - [editor didChangeText]; - - // -doCommandBySelector: should forward to observer via |field_|. - // TODO(shess): Test with a fake arrow-key event? - const SEL cmd = @selector(moveDown:); - EXPECT_CALL(field_observer_, OnDoCommandBySelector(cmd)) - .WillOnce(Return(true)); - [editor doCommandBySelector:cmd]; - - // Finished with the changes. - EXPECT_CALL(field_observer_, OnKillFocus()); - EXPECT_CALL(field_observer_, OnDidEndEditing()); - [test_window() clearPretendKeyWindowAndFirstResponder]; -} - -// Test that the resign-key notification is forwarded right, and that -// the notification is registered and unregistered when the view moves -// in and out of the window. -// TODO(shess): Should this test the key window for realz? That would -// be really annoying to whoever is running the tests. -TEST_F(AutocompleteTextFieldObserverTest, ClosePopupOnResignKey) { - EXPECT_CALL(field_observer_, ClosePopup()); - [test_window() resignKeyWindow]; - - base::scoped_nsobject<AutocompleteTextField> pin([field_ retain]); - [field_ removeFromSuperview]; - [test_window() resignKeyWindow]; - - [[test_window() contentView] addSubview:field_]; - EXPECT_CALL(field_observer_, ClosePopup()); - [test_window() resignKeyWindow]; -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h deleted file mode 100644 index 88a6f0a..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_ -#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" -#include "testing/gmock/include/gmock/gmock.h" - -@class AutocompleteTextFieldEditor; - -// Return the right field editor for AutocompleteTextField instance. - -@interface AutocompleteTextFieldWindowTestDelegate : - NSObject<NSWindowDelegate> { - base::scoped_nsobject<AutocompleteTextFieldEditor> editor_; -} -- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject; -@end - -// Allow monitoring calls into AutocompleteTextField's observer. -// Being in a .h file with an anonymous namespace is strange, but this -// is here so the mock interface doesn't have to change in multiple -// places. - -// Any method you add here needs a unit test. You knew that. - -class MockAutocompleteTextFieldObserver : public AutocompleteTextFieldObserver { - public: - MockAutocompleteTextFieldObserver(); - ~MockAutocompleteTextFieldObserver(); - - MOCK_METHOD1(SelectionRangeForProposedRange, NSRange(NSRange range)); - MOCK_METHOD1(OnControlKeyChanged, void(bool pressed)); - MOCK_METHOD0(CanCopy, bool()); - MOCK_METHOD0(CreatePasteboardItem, base::scoped_nsobject<NSPasteboardItem>()); - MOCK_METHOD1(CopyToPasteboard, void(NSPasteboard* pboard)); - MOCK_METHOD0(OnPaste, void()); - MOCK_METHOD0(CanPasteAndGo, bool()); - MOCK_METHOD0(GetPasteActionStringId, int()); - MOCK_METHOD0(OnPasteAndGo, void()); - MOCK_METHOD0(OnFrameChanged, void()); - MOCK_METHOD0(ClosePopup, void()); - MOCK_METHOD0(OnDidBeginEditing, void()); - MOCK_METHOD0(OnBeforeChange, void()); - MOCK_METHOD0(OnDidChange, void()); - MOCK_METHOD0(OnDidEndEditing, void()); - MOCK_METHOD0(OnInsertText, void()); - MOCK_METHOD0(OnBeforeDrawRect, void()); - MOCK_METHOD0(OnDidDrawRect, void()); - MOCK_METHOD1(OnDoCommandBySelector, bool(SEL cmd)); - MOCK_METHOD1(OnSetFocus, void(bool control_down)); - MOCK_METHOD0(OnKillFocus, void()); - MOCK_METHOD1(OnMouseDown, void(NSInteger button_number)); -}; - -#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm deleted file mode 100644 index 38d27935..0000000 --- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h" - -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" -#include "testing/gtest/include/gtest/gtest.h" - -@implementation AutocompleteTextFieldWindowTestDelegate - -- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject { - id editor = nil; - if ([anObject isKindOfClass:[AutocompleteTextField class]]) { - if (editor_ == nil) { - editor_.reset([[AutocompleteTextFieldEditor alloc] init]); - } - EXPECT_TRUE(editor_ != nil); - - // This needs to be called every time, otherwise notifications - // aren't sent correctly. - [editor_ setFieldEditor:YES]; - editor = editor_.get(); - } - return editor; -} - -@end - -MockAutocompleteTextFieldObserver::MockAutocompleteTextFieldObserver() {} - -MockAutocompleteTextFieldObserver::~MockAutocompleteTextFieldObserver() {}
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h deleted file mode 100644 index 72d46bf..0000000 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h +++ /dev/null
@@ -1,249 +0,0 @@ -// Copyright (c) 2010 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_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_ -#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" - -@class DecorationMouseTrackingDelegate; -@class CrTrackingArea; - -namespace gfx { -struct VectorIcon; -} - -namespace test { -class LocationBarDecorationTestApi; -} - -// Base class for decorations at the left and right of the location -// bar. For instance, the location icon. - -// |LocationBarDecoration| and subclasses should approximately -// parallel the classes provided under views/location_bar/. The term -// "decoration" is used because "view" has strong connotations in -// Cocoa, and while these are view-like, they aren't views at all. -// Decorations are more like Cocoa cells, except implemented in C++ to -// allow more similarity to the other platform implementations. - -// This enum class represents the state of the decoration's interactions -// with the mouse. -enum class DecorationMouseState { NONE, HOVER, PRESSED }; - -// Return values to indicate when subclasses should receive a press event. -enum class AcceptsPress { - NEVER, // Decoration is not clickable (decorative only). - ALWAYS, // Receives a press whether the button is active or not. - WHEN_ACTIVATED, // Receives a press only if the button was inactive before - // the press began. -}; - -class LocationBarDecoration { - public: - LocationBarDecoration(); - virtual ~LocationBarDecoration(); - - // Determines whether the decoration is visible. - virtual bool IsVisible() const; - virtual void SetVisible(bool visible); - - // Decorations can change their size to fit the available space. - // Returns the width the decoration will use in the space allotted, - // or |kOmittedWidth| if it should be omitted. - virtual CGFloat GetWidthForSpace(CGFloat width); - - // Returns a NSRect derived from |frame| for the background to fill. - virtual NSRect GetBackgroundFrame(NSRect frame); - - // Draw the decoration in the frame provided. The frame will be - // generated from an earlier call to |GetWidthForSpace()|. - virtual void DrawInFrame(NSRect frame, NSView* control_view); - - // Draw the decoration in the frame provided, possibly including a - // background that fills |background_frame|. The frame will be - // generated from an earlier call to |GetWidthForSpace()|, and the - // |background_frame| will include the column of pixels exactly - // between two decorations. - void DrawWithBackgroundInFrame(NSRect frame, NSView* control_view); - - // Returns the tooltip for this decoration, return |nil| for no tooltip. - virtual NSString* GetToolTip(); - - // Returns the accessibility label for this decoration, return |nil| to use - // the result of |GetTooltip()| as a fallback. - virtual NSString* GetAccessibilityLabel(); - - // Returns whether this decoration is a visual decoration only. Any decoration - // that is purely visual must have its state reflected elsewhere to make it - // available to screenreader users. - virtual bool IsAccessibilityIgnored(); - - // Returns a NSRect derived from |frame| to set up the tracking area. - virtual NSRect GetTrackingFrame(NSRect frame); - - // Methods to set up and remove the tracking area from the |control_view|. - CrTrackingArea* SetupTrackingArea(NSRect frame, NSView* control_view); - void RemoveTrackingArea(); - - // Decorations which do not accept mouse events are treated like the - // field's background for purposes of selecting text. When such - // decorations are adjacent to the text area, they will show the - // I-beam cursor. Decorations which do accept mouse events will get - // an arrow cursor when the mouse is over them. - virtual AcceptsPress AcceptsMousePress(); - - // Returns true if the decoration should display a background if it's - // hovered or pressed. The default value is equivalent to the value returned - // from AcceptsMousePress(). - virtual bool HasHoverAndPressEffect(); - - // Determine if the item can act as a drag source. - virtual bool IsDraggable(); - - // The image to drag. - virtual NSImage* GetDragImage(); - - // Return the place within the decoration's frame where the - // |GetDragImage()| comes from. This is used to make sure the image - // appears correctly under the mouse while dragging. |frame| - // matches the frame passed to |DrawInFrame()|. - virtual NSRect GetDragImageFrame(NSRect frame); - - // The pasteboard to drag. - virtual NSPasteboard* GetDragPasteboard(); - - // Called on mouse down. Or, for draggable buttons, on mouse up when a drag - // did not occur. Returns |false| to indicate that the press was not processed - // and should be handled by the cell. - bool HandleMousePressed(NSRect frame, NSPoint location); - - // Hook for subclasses to react to calls to HandleMousePressed(). Not invoked - // if the button was already active and AcceptsMousePress() is WHEN_ACTIVATED. - virtual bool OnMousePressed(NSRect frame, NSPoint location); - - // Mouse events called on mouse down/up. - void OnMouseDown(); - void OnMouseUp(); - - // Called by |tracking_delegate_| when the mouse enters/exits the decoration. - void OnMouseEntered(); - void OnMouseExited(); - - // Sets the active state of the decoration. If the state has changed, call - // UpdateDecorationState(). - void SetActive(bool active); - - // Called to get the right-click menu, return |nil| for no menu. - virtual NSMenu* GetMenu(); - - // Gets the font used to draw text in the decoration. - virtual NSFont* GetFont() const; - - // Gets the accessibility NSView for this decoration. This NSView is - // a transparent button that is positioned over this decoration to allow it to - // accept keyboard focus and keyboard activations. - virtual NSView* GetAccessibilityView(); - - // Helper to get where the bubble point should land. |frame| specifies the - // decorations' image rectangle. Defaults to |frame.origin| if not overriden. - // The return value is in the same coordinate system as |frame|. - virtual NSPoint GetBubblePointInFrame(NSRect frame); - - // Gets the Material Design vector-based icon. - NSImage* GetMaterialIcon(bool location_bar_is_dark) const; - - static void DrawLabel(NSString* label, - NSDictionary* attributes, - const NSRect& frame); - static void DrawAttributedString(NSAttributedString* str, - const NSRect& frame); - static NSSize GetLabelSize(NSString* label, - NSDictionary* attributes); - - // Called when the accessibility view receives an action via a keyboard button - // press or VoiceOver activation. This method is public so it can be exposed - // to the private DecorationAccessibilityView helper class. - void OnAccessibilityViewAction(); - - // Called when the omnibox decoration changes state to update the - // accessibility view's attributes to match. The |apparent_frame| rectangle is - // the frame the accessibility view should appear at visually (which may be - // different from its frame in the Cocoa sense). - void UpdateAccessibilityView(NSRect apparent_frame); - - // Computes the real bounds the focus ring should be drawn around for this - // decoration. Some decorations include visual spacing or separators in their - // bounds, but these should not be encompassed by the focus ring. - virtual NSRect GetRealFocusRingBounds(NSRect bounds) const; - - DecorationMouseState state() const { return state_; } - - bool active() const { return active_; } - - // Width returned by |GetWidthForSpace()| when the item should be - // omitted for this width; - static const CGFloat kOmittedWidth; - - // Material text color if the location bar is dark. - static const SkColor kMaterialDarkModeTextColor; - - protected: - // Returns the amount of padding between the divider and the label text. - virtual CGFloat DividerPadding() const; - - // Gets the color used to draw the Material Design icon. The default - // implementation satisfies most cases - few subclasses should need to - // override. - virtual SkColor GetMaterialIconColor(bool location_bar_is_dark) const; - - // Gets the decoration's Material Design vector icon. Subclasses should - // override to return the correct icon. Not an abstract method because some - // decorations are assigned their icon (vs. creating it themselves). - virtual const gfx::VectorIcon* GetMaterialVectorIcon() const; - - // Draws the decoration's vertical divider. Assumes already lock focused on - // the control_view. - void DrawDivider(NSView* control_view, - NSRect decoration_frame, - CGFloat alpha) const; - - private: - friend class test::LocationBarDecorationTestApi; - - // Called when the state of the decoration is updated. - void UpdateDecorationState(); - - bool visible_ = false; - - // True if the decoration is active. - bool active_ = false; - - // True if the decoration was active when the last mouse down was received. - bool was_active_in_last_mouse_down_ = false; - - base::scoped_nsobject<NSControl> accessibility_view_; - - // The decoration's tracking area. Only set if the decoration accepts a mouse - // press. - base::scoped_nsobject<CrTrackingArea> tracking_area_; - - // The view that |tracking_area_| is added to. - NSView* tracking_area_owner_ = nullptr; - - // Delegate object that handles mouseEntered: and mouseExited: events from - // the tracking area. - base::scoped_nsobject<DecorationMouseTrackingDelegate> tracking_delegate_; - - // The state of the decoration. - DecorationMouseState state_ = DecorationMouseState::NONE; - - DISALLOW_COPY_AND_ASSIGN(LocationBarDecoration); -}; - -#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm deleted file mode 100644 index 636bb40d4..0000000 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm +++ /dev/null
@@ -1,502 +0,0 @@ -// Copyright (c) 2010 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 "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h" - -#include "base/logging.h" -#include "base/mac/scoped_nsobject.h" -#include "chrome/browser/ui/cocoa/l10n_util.h" -#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" -#include "skia/ext/skia_utils_mac.h" -#import "ui/base/cocoa/nsview_additions.h" -#import "ui/base/cocoa/tracking_area.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/font.h" -#include "ui/gfx/image/image_skia_util_mac.h" -#include "ui/gfx/paint_vector_icon.h" - -namespace { - -// Layout and color values for the vertical divider. -const CGFloat kDecorationDividerHeight = 16.0; -const CGFloat kDecorationDividerPadding = - 6.0; // Between the divider and label. -const CGFloat kDecorationDividerGray = 0xFFA6A6A6; -const CGFloat kDecorationDividerGrayIncognito = 0xFFCCCCCC; - -// Color values for the hover and pressed background. -const SkColor kHoverBackgroundColor = 0x14000000; -const SkColor kHoverDarkBackgroundColor = 0x1EFFFFFF; -const SkColor kPressedBackgroundColor = 0x1E000000; -const SkColor kPressedDarkBackgroundColor = 0x3DFFFFFF; - -// Amount of inset for the background frame. -const CGFloat kDecorationBackgroundFrameYInset = 2.0; - -} // namespace - -// A DecorationAccessibilityView is a focusable, pressable button that is fully -// transparent and cannot be hit by mouse clicks. This is overlaid over a drawn -// decoration, to fake keyboard focus on the decoration and make it visible to -// VoiceOver. -@interface DecorationAccessibilityView : NSButton { - LocationBarDecoration* owner_; // weak - NSRect apparentFrame_; -} - -// NSView: -- (id)initWithOwner:(LocationBarDecoration*)owner; -- (BOOL)acceptsFirstResponder; -- (void)drawRect:(NSRect)dirtyRect; -- (NSView*)hitTest:(NSPoint)aPoint; -- (NSString*)accessibilityLabel; - -// This method is called when this DecorationAccessibilityView is activated. -- (void)actionDidHappen; - -- (void)setApparentFrame:(NSRect)r; -@end - -@implementation DecorationAccessibilityView - -- (id)initWithOwner:(LocationBarDecoration*)owner { - if ((self = [super initWithFrame:NSZeroRect])) { - self.bordered = NO; - self.focusRingType = NSFocusRingTypeExterior; - self->owner_ = owner; - [self setAction:@selector(actionDidHappen)]; - [self setTarget:self]; - self->apparentFrame_ = NSZeroRect; - } - return self; -} - -- (BOOL)acceptsFirstResponder { - // This NSView is only focusable if the owning LocationBarDecoration can - // accept mouse presses. - return owner_->AcceptsMousePress() == AcceptsPress::NEVER ? NO : YES; -} - -- (void)drawRect:(NSRect)dirtyRect { - // Draw nothing. This NSView is fully transparent. -} - -- (NSView*)hitTest:(NSPoint)aPoint { - // Mouse clicks cannot hit this NSView. - return nil; -} - -- (void)actionDidHappen { - owner_->OnAccessibilityViewAction(); -} - -- (NSString*)accessibilityLabel { - NSString* label = owner_->GetAccessibilityLabel(); - return label ? label : owner_->GetToolTip(); -} - -- (void)setApparentFrame:(NSRect)r { - apparentFrame_ = r; -} - -// The focus ring (and all other visuals) should be positioned using the -// apparent frame, not the real frame, because of the hack in -// LocationBarViewMac::UpdateAccessibilityView(). -- (void)drawFocusRingMask { - NSRectFill([self focusRingMaskBounds]); -} - -- (NSRect)focusRingMaskBounds { - return owner_->GetRealFocusRingBounds( - [[self superview] convertRect:apparentFrame_ toView:self]); -} - -@end - -@interface DecorationMouseTrackingDelegate : NSObject { - LocationBarDecoration* owner_; // weak -} - -- (id)initWithOwner:(LocationBarDecoration*)owner; -- (void)mouseEntered:(NSEvent*)event; -- (void)mouseExited:(NSEvent*)event; - -@end - -@implementation DecorationMouseTrackingDelegate - -- (id)initWithOwner:(LocationBarDecoration*)owner { - if ((self = [super init])) { - owner_ = owner; - } - - return self; -} - -- (void)mouseEntered:(NSEvent*)event { - owner_->OnMouseEntered(); -} - -- (void)mouseExited:(NSEvent*)event { - owner_->OnMouseExited(); -} - -@end - -const CGFloat LocationBarDecoration::kOmittedWidth = 0.0; -const SkColor LocationBarDecoration::kMaterialDarkModeTextColor = SK_ColorWHITE; - -LocationBarDecoration::LocationBarDecoration() { - accessibility_view_.reset( - [[DecorationAccessibilityView alloc] initWithOwner:this]); - [accessibility_view_.get() setHidden:YES]; -} - -void LocationBarDecoration::OnAccessibilityViewAction() { - DCHECK(!IsAccessibilityIgnored()); - // Turn the action into a synthesized mouse click at the center of |this|. - NSRect frame = [accessibility_view_.get() frame]; - NSPoint mousePoint = NSMakePoint(NSMidX(frame), NSMidY(frame)); - HandleMousePressed(frame, mousePoint); -} - -LocationBarDecoration::~LocationBarDecoration() { - [accessibility_view_.get() removeFromSuperview]; -} - -CGFloat LocationBarDecoration::DividerPadding() const { - return kDecorationDividerPadding; -} - -bool LocationBarDecoration::IsVisible() const { - return visible_; -} - -void LocationBarDecoration::SetVisible(bool visible) { - visible_ = visible; - bool a11y_hidden = !visible || IsAccessibilityIgnored(); - [accessibility_view_.get() setHidden:a11y_hidden]; -} - - -CGFloat LocationBarDecoration::GetWidthForSpace(CGFloat width) { - NOTREACHED(); - return kOmittedWidth; -} - -NSRect LocationBarDecoration::GetBackgroundFrame(NSRect frame) { - return NSInsetRect(frame, 0.0, kDecorationBackgroundFrameYInset); -} - -void LocationBarDecoration::UpdateAccessibilityView(NSRect apparent_frame) { - auto v = static_cast<DecorationAccessibilityView*>(accessibility_view_); - [accessibility_view_ setEnabled:AcceptsMousePress() != AcceptsPress::NEVER]; - [v setApparentFrame:apparent_frame]; -} - -NSRect LocationBarDecoration::GetRealFocusRingBounds(NSRect bounds) const { - return bounds; -} - -void LocationBarDecoration::DrawInFrame(NSRect frame, NSView* control_view) { - NOTREACHED(); -} - -void LocationBarDecoration::DrawWithBackgroundInFrame(NSRect frame, - NSView* control_view) { - // Draw the background if available. - if ((active_ || state_ != DecorationMouseState::NONE) && - HasHoverAndPressEffect()) { - bool in_dark_mode = [[control_view window] inIncognitoModeWithSystemTheme]; - - SkColor background_color; - if (active_ || state_ == DecorationMouseState::PRESSED) { - background_color = - in_dark_mode ? kPressedDarkBackgroundColor : kPressedBackgroundColor; - } else { - background_color = - in_dark_mode ? kHoverDarkBackgroundColor : kHoverBackgroundColor; - } - - [skia::SkColorToSRGBNSColor(background_color) setFill]; - - NSBezierPath* path = [NSBezierPath bezierPath]; - [path appendBezierPathWithRoundedRect:GetBackgroundFrame(frame) - xRadius:2 - yRadius:2]; - [path fill]; - } - DrawInFrame(frame, control_view); -} - -NSString* LocationBarDecoration::GetToolTip() { - return nil; -} - -NSString* LocationBarDecoration::GetAccessibilityLabel() { - return nil; -} - -bool LocationBarDecoration::IsAccessibilityIgnored() { - return false; -} - -NSRect LocationBarDecoration::GetTrackingFrame(NSRect frame) { - return frame; -} - -CrTrackingArea* LocationBarDecoration::SetupTrackingArea(NSRect frame, - NSView* control_view) { - if (!HasHoverAndPressEffect() || !control_view) - return nil; - - NSRect tracking_frame = GetTrackingFrame(frame); - if (control_view == tracking_area_owner_ && tracking_area_.get() && - NSEqualRects([tracking_area_ rect], tracking_frame)) { - return tracking_area_.get(); - } - - if (tracking_area_owner_) - [tracking_area_owner_ removeTrackingArea:tracking_area_.get()]; - - if (!tracking_delegate_) { - tracking_delegate_.reset( - [[DecorationMouseTrackingDelegate alloc] initWithOwner:this]); - } - - tracking_area_.reset([[CrTrackingArea alloc] - initWithRect:tracking_frame - options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow - owner:tracking_delegate_.get() - userInfo:nil]); - - [control_view addTrackingArea:tracking_area_.get()]; - tracking_area_owner_ = control_view; - - state_ = [tracking_area_ mouseInsideTrackingAreaForView:control_view] - ? DecorationMouseState::HOVER - : DecorationMouseState::NONE; - - return tracking_area_.get(); -} - -void LocationBarDecoration::RemoveTrackingArea() { - DCHECK(tracking_area_owner_); - DCHECK(tracking_area_); - [tracking_area_owner_ removeTrackingArea:tracking_area_.get()]; - tracking_area_owner_ = nullptr; - tracking_area_.reset(); -} - -AcceptsPress LocationBarDecoration::AcceptsMousePress() { - return AcceptsPress::NEVER; -} - -bool LocationBarDecoration::HasHoverAndPressEffect() { - return AcceptsMousePress() != AcceptsPress::NEVER; -} - -bool LocationBarDecoration::IsDraggable() { - return false; -} - -NSImage* LocationBarDecoration::GetDragImage() { - return nil; -} - -NSRect LocationBarDecoration::GetDragImageFrame(NSRect frame) { - return NSZeroRect; -} - -NSPasteboard* LocationBarDecoration::GetDragPasteboard() { - return nil; -} - -bool LocationBarDecoration::HandleMousePressed(NSRect frame, NSPoint location) { - if (was_active_in_last_mouse_down_) { - was_active_in_last_mouse_down_ = false; - if (AcceptsMousePress() == AcceptsPress::WHEN_ACTIVATED) { - // Clear the active state. This is usually the responsibility of the popup - // code (i.e. whatever called SetActive(true)). However, there exist some - // tricky lifetimes and corner cases where a client may "forget", or be - // unable to clear the active state. In that case, we risk getting "stuck" - // in a state where client code may never receive a signal. Clearing the - // active state here ensures a subsequent click will always send a signal. - SetActive(false); - return true; - } - } - - return OnMousePressed(frame, location); -} - -bool LocationBarDecoration::OnMousePressed(NSRect frame, NSPoint location) { - return false; -} - -void LocationBarDecoration::OnMouseDown() { - was_active_in_last_mouse_down_ = active_; - state_ = DecorationMouseState::PRESSED; - UpdateDecorationState(); -} - -void LocationBarDecoration::OnMouseUp() { - // Ignore the mouse up if it's not associated with a mouse down event. - if (state_ != DecorationMouseState::PRESSED) - return; - - DCHECK(tracking_area_owner_); - state_ = [tracking_area_ mouseInsideTrackingAreaForView:tracking_area_owner_] - ? DecorationMouseState::HOVER - : DecorationMouseState::NONE; - UpdateDecorationState(); -} - -void LocationBarDecoration::OnMouseEntered() { - state_ = DecorationMouseState::HOVER; - UpdateDecorationState(); -} - -void LocationBarDecoration::OnMouseExited() { - state_ = DecorationMouseState::NONE; - UpdateDecorationState(); -} - -void LocationBarDecoration::SetActive(bool active) { - if (active_ == active) - return; - - active_ = active; - state_ = [tracking_area_ mouseInsideTrackingAreaForView:tracking_area_owner_] - ? DecorationMouseState::HOVER - : DecorationMouseState::NONE; - UpdateDecorationState(); -} - -void LocationBarDecoration::UpdateDecorationState() { - if (tracking_area_owner_) - [tracking_area_owner_ setNeedsDisplay:YES]; -} - -NSMenu* LocationBarDecoration::GetMenu() { - return nil; -} - -NSFont* LocationBarDecoration::GetFont() const { - return OmniboxViewMac::GetNormalFieldFont(); -} - -NSView* LocationBarDecoration::GetAccessibilityView() { - return accessibility_view_.get(); -} - -NSPoint LocationBarDecoration::GetBubblePointInFrame(NSRect frame) { - // Clients that use a bubble should implement this. Can't be abstract - // because too many LocationBarDecoration subclasses don't use a bubble. - // Can't live on subclasses only because it needs to be on a shared API. - NOTREACHED(); - return frame.origin; -} - -NSImage* LocationBarDecoration::GetMaterialIcon( - bool location_bar_is_dark) const { - const int kIconSize = 16; - const gfx::VectorIcon* vector_icon = GetMaterialVectorIcon(); - if (!vector_icon) { - // Return an empty image when the decoration specifies no vector icon, so - // that its bubble is positioned correctly (the position is based on the - // width of the image; returning nil will mess up the positioning). - NSSize icon_size = NSMakeSize(kIconSize, kIconSize); - return [[[NSImage alloc] initWithSize:icon_size] autorelease]; - } - - SkColor vector_icon_color = GetMaterialIconColor(location_bar_is_dark); - return NSImageFromImageSkia( - gfx::CreateVectorIcon(*vector_icon, kIconSize, vector_icon_color)); -} - -// static -void LocationBarDecoration::DrawLabel(NSString* label, - NSDictionary* attributes, - const NSRect& frame) { - base::scoped_nsobject<NSAttributedString> str( - [[NSAttributedString alloc] initWithString:label attributes:attributes]); - DrawAttributedString(str, frame); -} - -// static -void LocationBarDecoration::DrawAttributedString(NSAttributedString* str, - const NSRect& frame) { - NSRect text_rect = frame; - text_rect.size.height = [str size].height; - text_rect.origin.y = roundf(NSMidY(frame) - NSHeight(text_rect) / 2.0) - 1; - [str drawInRect:text_rect]; -} - -// static -NSSize LocationBarDecoration::GetLabelSize(NSString* label, - NSDictionary* attributes) { - return [label sizeWithAttributes:attributes]; -} - -SkColor LocationBarDecoration::GetMaterialIconColor( - bool location_bar_is_dark) const { - return location_bar_is_dark ? SK_ColorWHITE : gfx::kChromeIconGrey; -} - -void LocationBarDecoration::DrawDivider(NSView* control_view, - NSRect decoration_frame, - CGFloat alpha) const { - if (alpha == 0.0) { - return; - } - - NSBezierPath* line = [NSBezierPath bezierPath]; - - CGFloat line_width = [control_view cr_lineWidth]; - [line setLineWidth:line_width]; - - const BOOL is_rtl = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); - NSPoint divider_origin = NSZeroPoint; - divider_origin.x = is_rtl ? NSMinX(decoration_frame) + DividerPadding() - : NSMaxX(decoration_frame) - DividerPadding(); - // Screen pixels lay between integral coordinates in user space. If you - // draw a line from (16, 16) to (16, 32), Core Graphics maps that line to - // the pixels that lay along x=16.5. In order to achieve a line that - // appears to lay along x=16, CG will perform dithering. To get a crisp - // line, you have to specify x=16.5, so translating by 1/2 the 1-pixel - // line width creates the crisp line we want. We subtract to better center - // the line between the label and URL. - divider_origin.x -= line_width / 2.; - CGFloat divider_y_frame_offset = - (NSHeight(decoration_frame) - kDecorationDividerHeight) / 2.0; - divider_origin.y = NSMinY(decoration_frame) + divider_y_frame_offset; - // Adjust the divider origin by 1/2 a point to visually center the - // divider vertically on Retina. - if (line_width < 1) { - divider_origin.y -= 0.5; - } - [line moveToPoint:divider_origin]; - [line relativeLineToPoint:NSMakePoint(0, kDecorationDividerHeight)]; - - NSColor* divider_color = nil; - bool location_bar_is_dark = - [[control_view window] inIncognitoModeWithSystemTheme]; - if (location_bar_is_dark) { - divider_color = skia::SkColorToSRGBNSColor(kDecorationDividerGrayIncognito); - } else { - divider_color = skia::SkColorToSRGBNSColor(kDecorationDividerGray); - } - - if (alpha < 1) { - divider_color = [divider_color colorWithAlphaComponent:alpha]; - } - [divider_color set]; - [line stroke]; -} - -const gfx::VectorIcon* LocationBarDecoration::GetMaterialVectorIcon() const { - NOTREACHED(); - return nullptr; -}
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h index 43ccc28..4d60858 100644 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h +++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
@@ -13,46 +13,23 @@ #include "base/macros.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h" -#include "chrome/browser/ui/page_action/page_action_icon_container.h" -#include "components/content_settings/core/common/content_settings_types.h" #include "components/prefs/pref_member.h" #include "components/security_state/core/security_state.h" -#include "components/zoom/zoom_event_manager_observer.h" -@class AutocompleteTextField; class CommandUpdater; -class LocationBarDecoration; class Profile; -namespace { -class LocationBarViewMacTest; -} - -// Enumeration of the type of verbose that is displayed on the page info -// decoration. -enum class PageInfoVerboseType { - kNone = 0, - kSecurity, - kEVCert, - kChrome, - kExtension -}; - // A C++ bridge class that represents the location bar UI element to // the portable code. Wires up an OmniboxViewMac instance to // the location bar text field, which handles most of the work. class LocationBarViewMac : public LocationBar, public LocationBarTesting, - public ChromeOmniboxEditController, - public PageActionIconContainer, - public zoom::ZoomEventManagerObserver { + public ChromeOmniboxEditController { public: - LocationBarViewMac(AutocompleteTextField* field, - CommandUpdater* command_updater, + LocationBarViewMac(CommandUpdater* command_updater, Profile* profile, Browser* browser); ~LocationBarViewMac() override; @@ -83,125 +60,13 @@ bool TestContentSettingImagePressed(size_t index) override; bool IsContentSettingBubbleShowing(size_t index) override; - // Set/Get the editable state of the field. - void SetEditable(bool editable); - bool IsEditable(); - - // Happens when the zoom changes for the active tab. |can_show_bubble| is - // false when the change in zoom for the active tab wasn't an explicit user - // action (e.g. switching tabs, creating a new tab, creating a new browser). - // Additionally, |can_show_bubble| will only be true when the bubble wouldn't - // be obscured by other UI (app menu) or redundant (+/- from app menu). - void ZoomChangedForActiveTab(bool can_show_bubble); - - // Get the point in window coordinates in the |decoration| at which the - // associate bubble aims. - NSPoint GetBubblePointForDecoration(LocationBarDecoration* decoration) const; - - // When any image decorations change, call this to ensure everything is - // redrawn and laid out if necessary. - void OnDecorationsChanged(); - - // Layout the various decorations which live in the field. - void Layout(); - - // Re-draws |decoration| if it's already being displayed. - void RedrawDecoration(LocationBarDecoration* decoration); - - // Updates the controller, and, if |contents| is non-null, restores saved - // state that the tab holds. - void Update(const content::WebContents* contents); - - // Clears any location bar state stored for |contents|. - void ResetTabState(content::WebContents* contents); - - // Set the location bar's icon to the correct image for the current URL. - void UpdateLocationIcon(); - - // Set the location bar's controls to visibly match the current theme. - void UpdateColorsToMatchTheme(); - - // Notify the location bar that it was added to the browser window. Provides - // an update point for interface objects that need to set their appearance - // based on the window's theme. - void OnAddedToWindow(); - - // Notify the location bar that the browser window theme has changed. Provides - // an update point for interface objects that need to set their appearance - // based on the window's theme. - void OnThemeChanged(); - // ChromeOmniboxEditController: - void UpdateWithoutTabRestore() override; - void OnChanged() override; ToolbarModel* GetToolbarModel() override; const ToolbarModel* GetToolbarModel() const override; - content::WebContents* GetWebContents() override; - - // PageActionIconContainer: - void UpdatePageActionIcon(PageActionIconType) override; - - PageInfoVerboseType GetPageInfoVerboseType() const; - - // Returns true if the page info decoration should display security verbose. - // The verbose should only be shown for valid and invalid HTTPS states. - bool HasSecurityVerboseText() const; - - NSImage* GetKeywordImage(const base::string16& keyword); - - // Returns the color for the vector icon in the location bar. - SkColor GetLocationBarIconColor() const; - - AutocompleteTextField* GetAutocompleteTextField() { return field_; } - - // Returns true if the location bar is dark. - bool IsLocationBarDark() const; - - Browser* browser() const { return browser_; } - - // ZoomManagerObserver: - // Updates the view for the zoom icon when default zoom levels change. - void OnDefaultZoomLevelChanged() override; - - // Returns the decoration accessibility views for all of this - // LocationBarViewMac's decorations. The returned NSViews may not have been - // positioned yet. - std::vector<NSView*> GetDecorationAccessibilityViews(); private: - friend class LocationBarViewMacTest; - - // Posts |notification| to the default notification center. - void PostNotification(NSString* notification); - - void OnEditBookmarksEnabledChanged(); - - // Updates visibility of the content settings icons based on the current - // tab contents state. - bool RefreshContentSettingsDecorations(); - - // Returns pointers to all of the LocationBarDecorations owned by this - // LocationBarViewMac. This helper function is used for positioning and - // re-positioning accessibility views. - std::vector<LocationBarDecoration*> GetDecorations(); - - // Updates |decoration|'s accessibility view's position to match the computed - // position the decoration will be drawn at, and update its enabled state - // based on whether |decoration| is accepting presses currently. - void UpdateAccessibilityView(LocationBarDecoration* decoration); - - std::unique_ptr<OmniboxViewMac> omnibox_view_; - - AutocompleteTextField* field_; // owned by tab controller - Browser* browser_; - // Used to change the visibility of the star decoration. - BooleanPrefMember edit_bookmarks_enabled_; - - // Indicates whether or not the location bar is currently visible. - bool location_bar_visible_; - DISALLOW_COPY_AND_ASSIGN(LocationBarViewMac); };
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm index d01fea9..5611e018 100644 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm +++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -4,108 +4,14 @@ #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#import "base/mac/mac_util.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_task_runner_handle.h" -#include "chrome/app/chrome_command_ids.h" -#import "chrome/browser/app_controller_mac.h" -#include "chrome/browser/command_updater.h" -#include "chrome/browser/defaults.h" -#include "chrome/browser/extensions/api/omnibox/omnibox_api.h" -#include "chrome/browser/extensions/extension_ui_util.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/search_engines/template_url_service_factory.h" -#include "chrome/browser/translate/chrome_translate_client.h" -#include "chrome/browser/translate/translate_service.h" -#include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h" -#include "chrome/browser/ui/browser_list.h" -#import "chrome/browser/ui/cocoa/browser_window_controller.h" -#import "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" -#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" -#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" -#include "chrome/browser/ui/content_settings/content_setting_image_model.h" -#include "chrome/browser/ui/page_info/page_info_dialog.h" -#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/common/pref_names.h" -#include "chrome/grit/chromium_strings.h" -#include "components/bookmarks/common/bookmark_pref_names.h" -#import "components/omnibox/browser/omnibox_popup_model.h" -#include "components/prefs/pref_service.h" -#include "components/search_engines/template_url.h" -#include "components/search_engines/template_url_service.h" -#include "components/toolbar/vector_icons.h" -#include "components/translate/core/browser/language_state.h" -#include "components/variations/variations_associated_data.h" -#include "components/vector_icons/vector_icons.h" -#include "components/zoom/zoom_controller.h" -#include "components/zoom/zoom_event_manager.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/url_constants.h" -#include "skia/ext/skia_utils_mac.h" -#import "ui/base/cocoa/cocoa_base_utils.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/l10n_util_mac.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/color_utils.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/image/image_skia_util_mac.h" -#include "ui/gfx/paint_vector_icon.h" - -using content::WebContents; - -namespace { - -const int kDefaultIconSize = 16; - -// Color of the vector graphic icons when the location bar is dark. -// SkColorSetARGB(0xCC, 0xFF, 0xFF 0xFF); -const SkColor kMaterialDarkVectorIconColor = SK_ColorWHITE; - -} // namespace - -// TODO(shess): This code is mostly copied from the gtk -// implementation. Make sure it's all appropriate and flesh it out. - -LocationBarViewMac::LocationBarViewMac(AutocompleteTextField* field, - CommandUpdater* command_updater, +LocationBarViewMac::LocationBarViewMac(CommandUpdater* command_updater, Profile* profile, Browser* browser) : LocationBar(profile), ChromeOmniboxEditController(command_updater), - omnibox_view_(new OmniboxViewMac(this, profile, command_updater, field)), - field_(field), - browser_(browser), - location_bar_visible_(true) { - edit_bookmarks_enabled_.Init( - bookmarks::prefs::kEditBookmarksEnabled, profile->GetPrefs(), - base::Bind(&LocationBarViewMac::OnEditBookmarksEnabledChanged, - base::Unretained(this))); - - zoom::ZoomEventManager::GetForBrowserContext(profile)->AddObserver(this); - - [[field_ cell] setIsPopupMode: - !browser->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)]; - - // Sets images for the decorations, and performs a layout. This call ensures - // that this class is in a consistent state after initialization. - OnChanged(); -} + browser_(browser) {} LocationBarViewMac::~LocationBarViewMac() { - // Disconnect from cell in case it outlives us. - [[field_ cell] clearDecorations]; - - zoom::ZoomEventManager::GetForBrowserContext(profile())->RemoveObserver(this); } GURL LocationBarViewMac::GetDestinationURL() const { @@ -125,23 +31,16 @@ } void LocationBarViewMac::AcceptInput() { - AcceptInput(base::TimeTicks()); } void LocationBarViewMac::AcceptInput( base::TimeTicks match_selection_timestamp) { - WindowOpenDisposition disposition = - ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); - omnibox_view_->model()->AcceptInput(disposition, false, - match_selection_timestamp); } void LocationBarViewMac::FocusLocation(bool select_all) { - omnibox_view_->FocusLocation(select_all); } void LocationBarViewMac::FocusSearch() { - omnibox_view_->EnterKeywordModeForDefaultSearchProvider(); } void LocationBarViewMac::UpdateContentSettingsIcons() { @@ -154,8 +53,6 @@ } void LocationBarViewMac::UpdateLocalCardMigrationIcon() { - // TODO(crbug.com/859652): Implement for mac. - NOTIMPLEMENTED(); } void LocationBarViewMac::UpdateBookmarkStarVisibility() { @@ -163,31 +60,19 @@ void LocationBarViewMac::UpdateLocationBarVisibility(bool visible, bool animate) { - // Track the target location bar visibility to avoid redundant transitions - // being initiated when one is already in progress. - if (visible != location_bar_visible_) { - [[[BrowserWindowController browserWindowControllerForView:field_] - toolbarController] updateVisibility:visible - withAnimation:animate]; - location_bar_visible_ = visible; - } } -void LocationBarViewMac::SaveStateToContents(WebContents* contents) { - // TODO(shess): Why SaveStateToContents vs SaveStateToTab? - omnibox_view_->SaveStateToTab(contents); -} +void LocationBarViewMac::SaveStateToContents(content::WebContents* contents) {} void LocationBarViewMac::Revert() { - omnibox_view_->RevertAll(); } const OmniboxView* LocationBarViewMac::GetOmniboxView() const { - return omnibox_view_.get(); + return nullptr; } OmniboxView* LocationBarViewMac::GetOmniboxView() { - return omnibox_view_.get(); + return nullptr; } LocationBarTesting* LocationBarViewMac::GetLocationBarForTesting() { @@ -206,107 +91,6 @@ return false; } -void LocationBarViewMac::SetEditable(bool editable) { - [field_ setEditable:editable ? YES : NO]; - UpdateBookmarkStarVisibility(); - Layout(); -} - -bool LocationBarViewMac::IsEditable() { - return [field_ isEditable] ? true : false; -} - -void LocationBarViewMac::ZoomChangedForActiveTab(bool can_show_bubble) { -} - -NSPoint LocationBarViewMac::GetBubblePointForDecoration( - LocationBarDecoration* decoration) const { - return [field_ bubblePointForDecoration:decoration]; -} - -void LocationBarViewMac::OnDecorationsChanged() { -} - -// TODO(shess): This function should over time grow to closely match -// the views Layout() function. -void LocationBarViewMac::Layout() { - AutocompleteTextFieldCell* cell = [field_ cell]; - - // Reset the leading decorations. - // TODO(shess): Shortly, this code will live somewhere else, like in - // the constructor. I am still wrestling with how best to deal with - // right-hand decorations, which are not a static set. - [cell clearDecorations]; - - // Get the keyword to use for keyword-search and hinting. - const base::string16 keyword = omnibox_view_->model()->keyword(); - base::string16 short_name; - bool is_extension_keyword = false; - if (!keyword.empty()) { - short_name = TemplateURLServiceFactory::GetForProfile(profile())-> - GetKeywordShortName(keyword, &is_extension_keyword); - } - - // These need to change anytime the layout changes. - // TODO(shess): Anytime the field editor might have changed, the - // cursor rects almost certainly should have changed. The tooltips - // might change even when the rects don't change. - OnDecorationsChanged(); -} - -void LocationBarViewMac::RedrawDecoration(LocationBarDecoration* decoration) { - AutocompleteTextFieldCell* cell = [field_ cell]; - NSRect frame = [cell frameForDecoration:decoration - inFrame:[field_ bounds]]; - if (!NSIsEmptyRect(frame)) - [field_ setNeedsDisplayInRect:frame]; -} - -void LocationBarViewMac::ResetTabState(WebContents* contents) { - omnibox_view_->ResetTabState(contents); -} - -void LocationBarViewMac::Update(const WebContents* contents) { - UpdateManagePasswordsIconAndBubble(); - UpdateBookmarkStarVisibility(); - UpdateSaveCreditCardIcon(); - RefreshContentSettingsDecorations(); - if (contents) { - omnibox_view_->OnTabChanged(contents); - } else { - omnibox_view_->Update(); - } - - OnChanged(); -} - -void LocationBarViewMac::UpdateWithoutTabRestore() { - Update(nullptr); -} - -void LocationBarViewMac::UpdateLocationIcon() { -} - -void LocationBarViewMac::UpdateColorsToMatchTheme() { - // Update the location-bar icon. - UpdateLocationIcon(); - - // Update the appearance of the text in the Omnibox. - omnibox_view_->Update(); -} - -void LocationBarViewMac::OnAddedToWindow() { - UpdateColorsToMatchTheme(); -} - -void LocationBarViewMac::OnThemeChanged() { - UpdateColorsToMatchTheme(); -} - -void LocationBarViewMac::OnChanged() { - UpdateLocationIcon(); -} - ToolbarModel* LocationBarViewMac::GetToolbarModel() { return browser_->toolbar_model(); } @@ -314,109 +98,3 @@ const ToolbarModel* LocationBarViewMac::GetToolbarModel() const { return browser_->toolbar_model(); } - -WebContents* LocationBarViewMac::GetWebContents() { - return browser_->tab_strip_model()->GetActiveWebContents(); -} - -void LocationBarViewMac::UpdatePageActionIcon(PageActionIconType type) { -} - -PageInfoVerboseType LocationBarViewMac::GetPageInfoVerboseType() const { - if (omnibox_view_->IsEditingOrEmpty() || - omnibox_view_->model()->is_keyword_hint()) { - return PageInfoVerboseType::kNone; - } else if (GetToolbarModel()->GetSecurityLevel(false) == - security_state::EV_SECURE) { - return PageInfoVerboseType::kEVCert; - } else if (GetToolbarModel()->GetURL().SchemeIs( - extensions::kExtensionScheme)) { - return PageInfoVerboseType::kExtension; - } else if (GetToolbarModel()->GetURL().SchemeIs(content::kChromeUIScheme)) { - return PageInfoVerboseType::kChrome; - } else { - return PageInfoVerboseType::kSecurity; - } -} - -bool LocationBarViewMac::HasSecurityVerboseText() const { - if (GetPageInfoVerboseType() != PageInfoVerboseType::kSecurity) - return false; - - return !GetToolbarModel()->GetSecureVerboseText().empty(); -} - -bool LocationBarViewMac::IsLocationBarDark() const { - return [[field_ window] inIncognitoModeWithSystemTheme]; -} - -NSImage* LocationBarViewMac::GetKeywordImage(const base::string16& keyword) { - const TemplateURL* template_url = TemplateURLServiceFactory::GetForProfile( - profile())->GetTemplateURLForKeyword(keyword); - if (template_url && - (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)) { - return extensions::OmniboxAPI::Get(profile())-> - GetOmniboxIcon(template_url->GetExtensionId()).AsNSImage(); - } - - SkColor icon_color = - IsLocationBarDark() ? kMaterialDarkVectorIconColor : gfx::kGoogleBlue700; - return NSImageFromImageSkiaWithColorSpace( - gfx::CreateVectorIcon(vector_icons::kSearchIcon, kDefaultIconSize, - icon_color), - base::mac::GetSRGBColorSpace()); -} - -SkColor LocationBarViewMac::GetLocationBarIconColor() const { - bool in_dark_mode = IsLocationBarDark(); - if (in_dark_mode) - return kMaterialDarkVectorIconColor; - - if (GetPageInfoVerboseType() == PageInfoVerboseType::kEVCert) - return gfx::kGoogleGreen700; - - security_state::SecurityLevel security_level = - GetToolbarModel()->GetSecurityLevel(false); - - if (security_level == security_state::NONE || - security_level == security_state::HTTP_SHOW_WARNING) { - return gfx::kChromeIconGrey; - } - - NSColor* srgb_color = - OmniboxViewMac::GetSecureTextColor(security_level, in_dark_mode); - NSColor* device_color = - [srgb_color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]]; - return skia::NSDeviceColorToSkColor(device_color); -} - -void LocationBarViewMac::PostNotification(NSString* notification) { - [[NSNotificationCenter defaultCenter] postNotificationName:notification - object:[NSValue valueWithPointer:this]]; -} - -void LocationBarViewMac::OnEditBookmarksEnabledChanged() { - UpdateBookmarkStarVisibility(); - OnChanged(); -} - -bool LocationBarViewMac::RefreshContentSettingsDecorations() { - return false; -} - -void LocationBarViewMac::UpdateAccessibilityView( - LocationBarDecoration* decoration) { -} - -std::vector<LocationBarDecoration*> LocationBarViewMac::GetDecorations() { - std::vector<LocationBarDecoration*> decorations; - return decorations; -} - -void LocationBarViewMac::OnDefaultZoomLevelChanged() { -} - -std::vector<NSView*> LocationBarViewMac::GetDecorationAccessibilityViews() { - std::vector<NSView*> views; - return views; -}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h deleted file mode 100644 index b54a3715..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_ -#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#include "components/omnibox/browser/autocomplete_match.h" - -class OmniboxPopupViewMac; - -@interface OmniboxPopupCellData : NSObject<NSCopying> - -// Left hand side of the separator (e.g. a hyphen). -@property(readonly, retain, nonatomic) NSAttributedString* contents; - -// Right hand side of the separator (e.g. a hyphen). -@property(readonly, retain, nonatomic) NSAttributedString* description; - -// NOTE: While |prefix_| is used only for tail suggestions, it still needs -// to be a member of the class. This allows the |NSAttributedString| instance -// to stay alive between the call to |drawTitle| and the actual paint event -// which accesses the |NSAttributedString| instance. -@property(readonly, retain, nonatomic) NSAttributedString* prefix; - -// Common icon that shows next to most rows in the list. -@property(retain, nonatomic) NSImage* image; - -// Uncommon icon that only shows on answer rows (e.g. weather). -@property(readonly, retain, nonatomic) NSImage* answerImage; - -@property(readonly, nonatomic) BOOL isContentsRTL; - -// Is this suggestion an answer or calculator result. -@property(readonly, nonatomic) bool isAnswer; -@property(readonly, nonatomic) AutocompleteMatch::Type matchType; -@property(readonly, nonatomic) int maxLines; - -- (instancetype)initWithMatch:(const AutocompleteMatch&)matchFromModel - image:(NSImage*)image - answerImage:(NSImage*)answerImage - forDarkTheme:(BOOL)isDarkTheme; - -// Returns the width of the match contents. -- (CGFloat)getMatchContentsWidth; - -@end - -// Overrides how cells are displayed. Uses information from -// OmniboxPopupCellData to draw suggestion results. -@interface OmniboxPopupCell : NSCell - -- (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView; - -// Returns the offset of the start of the contents in the input text for the -// given match. It is costly to compute this offset, so it is computed once and -// shared by all OmniboxPopupCell instances through OmniboxPopupViewMac parent. -+ (CGFloat)computeContentsOffset:(const AutocompleteMatch&)match; - -+ (NSAttributedString*)createSeparatorStringForDarkTheme:(BOOL)isDarkTheme; - -+ (CGFloat)getTextContentAreaWidth:(CGFloat)cellContentMaxWidth; - -+ (CGFloat)getContentTextHeight; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm deleted file mode 100644 index 893665b..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm +++ /dev/null
@@ -1,656 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h" - -#include <stddef.h> - -#include <algorithm> -#include <cmath> - -#include "base/i18n/rtl.h" -#include "base/mac/foundation_util.h" -#include "base/mac/objc_release_properties.h" -#include "base/mac/scoped_nsobject.h" -#include "base/metrics/field_trial_params.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h" -#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#include "chrome/grit/generated_resources.h" -#include "components/omnibox/browser/omnibox_field_trial.h" -#include "components/omnibox/browser/omnibox_popup_model.h" -#include "components/omnibox/browser/suggestion_answer.h" -#include "skia/ext/skia_utils_mac.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/font.h" - -namespace { - -// Extra padding beyond the vertical text padding. -constexpr CGFloat kMaterialExtraVerticalImagePadding = 2.0; - -constexpr CGFloat kMaterialTextStartOffset = 27.0; - -constexpr CGFloat kMaterialImageXOffset = 6.0; - -constexpr CGFloat kDefaultVerticalMargin = 3.0; - -constexpr CGFloat kDefaultTextHeight = 19; - -// Returns the margin that should appear at the top and bottom of the result. -CGFloat GetVerticalMargin() { - return base::GetFieldTrialParamByFeatureAsInt( - omnibox::kUIExperimentVerticalMargin, - OmniboxFieldTrial::kUIVerticalMarginParam, kDefaultVerticalMargin); -} - -// Flips the given |rect| in context of the given |frame|. -NSRect FlipIfRTL(NSRect rect, NSRect frame) { - DCHECK_LE(NSMinX(frame), NSMinX(rect)); - DCHECK_GE(NSMaxX(frame), NSMaxX(rect)); - if (base::i18n::IsRTL()) { - NSRect result = rect; - result.origin.x = NSMinX(frame) + (NSMaxX(frame) - NSMaxX(rect)); - return result; - } - return rect; -} - -NSColor* SelectedBackgroundColor(BOOL is_dark_theme) { - return is_dark_theme - ? skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorWHITE, 0x14)) - : skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorBLACK, 0x14)); -} - -NSColor* HoveredBackgroundColor(BOOL is_dark_theme) { - return is_dark_theme - ? skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorWHITE, 0x0D)) - : [NSColor controlHighlightColor]; -} - -NSColor* ContentTextColor(BOOL is_dark_theme) { - return is_dark_theme ? [NSColor whiteColor] : [NSColor blackColor]; -} -NSColor* DimTextColor(BOOL is_dark_theme) { - return is_dark_theme - ? skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorWHITE, 0x7F)) - : skia::SkColorToSRGBNSColor(SkColorSetRGB(0x64, 0x64, 0x64)); -} -NSColor* InvisibleTextColor() { - return skia::SkColorToSRGBNSColor(SK_ColorTRANSPARENT); -} -NSColor* PositiveTextColor() { - return skia::SkColorToSRGBNSColor(SkColorSetRGB(0x3d, 0x94, 0x00)); -} -NSColor* NegativeTextColor() { - return skia::SkColorToSRGBNSColor(SkColorSetRGB(0xdd, 0x4b, 0x39)); -} -NSColor* URLTextColor(BOOL is_dark_theme) { - return is_dark_theme ? skia::SkColorToSRGBNSColor(gfx::kGoogleBlue300) - : skia::SkColorToSRGBNSColor(gfx::kGoogleBlue700); -} - -NSFont* FieldFont() { - return OmniboxViewMac::GetNormalFieldFont(); -} -NSFont* BoldFieldFont() { - return OmniboxViewMac::GetBoldFieldFont(); -} -NSFont* LargeFont() { - return OmniboxViewMac::GetLargeFont(); -} -NSFont* LargeSuperscriptFont() { - NSFont* font = OmniboxViewMac::GetLargeFont(); - // Calculate a slightly smaller font. The ratio here is somewhat arbitrary. - // Proportions from 5/9 to 5/7 all look pretty good. - CGFloat size = [font pointSize] * 5.0 / 9.0; - NSFontDescriptor* descriptor = [font fontDescriptor]; - return [NSFont fontWithDescriptor:descriptor size:size]; -} - -// Sets the writing direction to |direction| for a given |range| of -// |attributedString|. -void SetTextDirectionForRange(NSMutableAttributedString* attributedString, - NSWritingDirection direction, - NSRange range) { - [attributedString - enumerateAttribute:NSParagraphStyleAttributeName - inRange:range - options:0 - usingBlock:^(id paragraph_style, NSRange range, BOOL* stop) { - [paragraph_style setBaseWritingDirection:direction]; - }]; -} - -NSAttributedString* CreateAnswerStringHelper(const base::string16& text, - NSInteger style_type, - bool is_bold, - BOOL is_dark_theme) { - NSDictionary* answer_style = nil; - NSFont* answer_font = nil; - switch (style_type) { - case SuggestionAnswer::TOP_ALIGNED: - answer_style = @{ - NSForegroundColorAttributeName : DimTextColor(is_dark_theme), - NSFontAttributeName : LargeSuperscriptFont(), - NSSuperscriptAttributeName : @1 - }; - break; - case SuggestionAnswer::DESCRIPTION_NEGATIVE: - answer_style = @{ - NSForegroundColorAttributeName : NegativeTextColor(), - NSFontAttributeName : LargeSuperscriptFont() - }; - break; - case SuggestionAnswer::DESCRIPTION_POSITIVE: - answer_style = @{ - NSForegroundColorAttributeName : PositiveTextColor(), - NSFontAttributeName : LargeSuperscriptFont() - }; - break; - case SuggestionAnswer::PERSONALIZED_SUGGESTION: - answer_style = @{ - NSForegroundColorAttributeName : ContentTextColor(is_dark_theme), - NSFontAttributeName : FieldFont() - }; - break; - case SuggestionAnswer::ANSWER_TEXT_MEDIUM: - answer_style = @{ - NSForegroundColorAttributeName : DimTextColor(is_dark_theme), - NSFontAttributeName : FieldFont() - }; - break; - case SuggestionAnswer::ANSWER_TEXT_LARGE: - answer_style = @{ - NSForegroundColorAttributeName : DimTextColor(is_dark_theme), - NSFontAttributeName : LargeFont() - }; - break; - case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_SMALL: - answer_font = FieldFont(); - answer_style = @{ - NSForegroundColorAttributeName : DimTextColor(is_dark_theme), - NSFontAttributeName : answer_font - }; - break; - case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_MEDIUM: - answer_font = LargeSuperscriptFont(); - answer_style = @{ - NSForegroundColorAttributeName : DimTextColor(is_dark_theme), - NSFontAttributeName : answer_font - }; - break; - case SuggestionAnswer::SUGGESTION: // Fall through. - default: - answer_style = @{ - NSForegroundColorAttributeName : ContentTextColor(is_dark_theme), - NSFontAttributeName : FieldFont() - }; - break; - } - - if (is_bold) { - NSMutableDictionary* bold_style = [answer_style mutableCopy]; - // TODO(dschuyler): Account for bolding fonts other than FieldFont. - // Field font is the only one currently necessary to bold. - [bold_style setObject:BoldFieldFont() forKey:NSFontAttributeName]; - answer_style = bold_style; - } - - return [[[NSAttributedString alloc] - initWithString:base::SysUTF16ToNSString(text) - attributes:answer_style] autorelease]; -} - -NSAttributedString* CreateAnswerString(const base::string16& text, - NSInteger style_type, - BOOL is_dark_theme) { - // TODO(dschuyler): make this better. Right now this only supports unnested - // bold tags. In the future we'll need to flag unexpected tags while adding - // support for b, i, u, sub, and sup. We'll also need to support HTML - // entities (< for '<', etc.). - const base::string16 begin_tag = base::ASCIIToUTF16("<b>"); - const base::string16 end_tag = base::ASCIIToUTF16("</b>"); - size_t begin = 0; - base::scoped_nsobject<NSMutableAttributedString> result( - [[NSMutableAttributedString alloc] init]); - while (true) { - size_t end = text.find(begin_tag, begin); - if (end == base::string16::npos) { - [result appendAttributedString:CreateAnswerStringHelper( - text.substr(begin), style_type, false, - is_dark_theme)]; - break; - } - [result appendAttributedString:CreateAnswerStringHelper( - text.substr(begin, end - begin), - style_type, false, is_dark_theme)]; - begin = end + begin_tag.length(); - end = text.find(end_tag, begin); - if (end == base::string16::npos) - break; - [result appendAttributedString:CreateAnswerStringHelper( - text.substr(begin, end - begin), - style_type, true, is_dark_theme)]; - begin = end + end_tag.length(); - } - return result.autorelease(); -} - -NSAttributedString* CreateAnswerLine(const SuggestionAnswer::ImageLine& line, - BOOL is_dark_theme) { - base::scoped_nsobject<NSMutableAttributedString> answer_string( - [[NSMutableAttributedString alloc] init]); - DCHECK(!line.text_fields().empty()); - for (const SuggestionAnswer::TextField& text_field : line.text_fields()) { - [answer_string appendAttributedString:CreateAnswerString(text_field.text(), - text_field.type(), - is_dark_theme)]; - } - const base::string16 space(base::ASCIIToUTF16(" ")); - const SuggestionAnswer::TextField* text_field = line.additional_text(); - if (text_field) { - [answer_string - appendAttributedString:CreateAnswerString(space + text_field->text(), - text_field->type(), - is_dark_theme)]; - } - text_field = line.status_text(); - if (text_field) { - [answer_string - appendAttributedString:CreateAnswerString(space + text_field->text(), - text_field->type(), - is_dark_theme)]; - } - base::scoped_nsobject<NSMutableParagraphStyle> style( - [[NSMutableParagraphStyle alloc] init]); - [style setTighteningFactorForTruncation:0.0]; - [answer_string addAttribute:NSParagraphStyleAttributeName - value:style - range:NSMakeRange(0, [answer_string length])]; - return answer_string.autorelease(); -} - -NSMutableAttributedString* CreateAttributedString( - const base::string16& text, - NSColor* text_color, - NSTextAlignment textAlignment) { - // Start out with a string using the default style info. - NSString* s = base::SysUTF16ToNSString(text); - NSDictionary* attributes = @{ - NSFontAttributeName : FieldFont(), - NSForegroundColorAttributeName : text_color - }; - NSMutableAttributedString* attributedString = [[ - [NSMutableAttributedString alloc] initWithString:s - attributes:attributes] autorelease]; - - NSMutableParagraphStyle* style = - [[[NSMutableParagraphStyle alloc] init] autorelease]; - [style setTighteningFactorForTruncation:0.0]; - [style setAlignment:textAlignment]; - if (@available(macOS 10.11, *)) - [style setAllowsDefaultTighteningForTruncation:NO]; - [attributedString addAttribute:NSParagraphStyleAttributeName - value:style - range:NSMakeRange(0, [attributedString length])]; - - return attributedString; -} - -NSMutableAttributedString* CreateAttributedString( - const base::string16& text, - NSColor* text_color) { - return CreateAttributedString(text, text_color, NSNaturalTextAlignment); -} - -NSAttributedString* CreateClassifiedAttributedString( - const base::string16& text, - NSColor* text_color, - const ACMatchClassifications& classifications, - BOOL is_dark_theme) { - NSMutableAttributedString* attributedString = - CreateAttributedString(text, text_color); - NSUInteger match_length = [attributedString length]; - - // Mark up the runs which differ from the default. - for (ACMatchClassifications::const_iterator i = classifications.begin(); - i != classifications.end(); ++i) { - const bool is_last = ((i + 1) == classifications.end()); - const NSUInteger next_offset = - (is_last ? match_length : static_cast<NSUInteger>((i + 1)->offset)); - const NSUInteger location = static_cast<NSUInteger>(i->offset); - const NSUInteger length = next_offset - static_cast<NSUInteger>(i->offset); - // Guard against bad, off-the-end classification ranges. - if (location >= match_length || length <= 0) - break; - const NSRange range = - NSMakeRange(location, std::min(length, match_length - location)); - - if (0 != (i->style & ACMatchClassification::MATCH)) { - [attributedString addAttribute:NSFontAttributeName - value:BoldFieldFont() - range:range]; - } - - if (0 != (i->style & ACMatchClassification::URL)) { - // URLs have their text direction set to to LTR (avoids RTL characters - // making the URL render from right to left, as per RFC 3987 Section 4.1). - SetTextDirectionForRange(attributedString, NSWritingDirectionLeftToRight, - range); - [attributedString addAttribute:NSForegroundColorAttributeName - value:URLTextColor(is_dark_theme) - range:range]; - } else if (0 != (i->style & ACMatchClassification::DIM)) { - [attributedString addAttribute:NSForegroundColorAttributeName - value:DimTextColor(is_dark_theme) - range:range]; - } else if (0 != (i->style & ACMatchClassification::INVISIBLE)) { - [attributedString addAttribute:NSForegroundColorAttributeName - value:InvisibleTextColor() - range:range]; - } - } - - return attributedString; -} - -} // namespace - -@interface OmniboxPopupCellData () -@end - -@interface OmniboxPopupCell () -- (CGFloat)drawMatchPart:(NSAttributedString*)attributedString - withFrame:(NSRect)cellFrame - origin:(NSPoint)origin - withMaxWidth:(int)maxWidth - forDarkTheme:(BOOL)isDarkTheme - withHeightCap:(BOOL)hasHeightCap; -- (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView; -@end - -@implementation OmniboxPopupCellData - -@synthesize contents = contents_; -@synthesize description = description_; -@synthesize prefix = prefix_; -@synthesize image = image_; -@synthesize answerImage = answerImage_; -@synthesize isContentsRTL = isContentsRTL_; -@synthesize isAnswer = isAnswer_; -@synthesize matchType = matchType_; -@synthesize maxLines = maxLines_; - -- (instancetype)initWithMatch:(const AutocompleteMatch&)matchFromModel - image:(NSImage*)image - answerImage:(NSImage*)answerImage - forDarkTheme:(BOOL)isDarkTheme { - if ((self = [super init])) { - image_ = [image retain]; - answerImage_ = [answerImage retain]; - - AutocompleteMatch match = - matchFromModel.GetMatchWithContentsAndDescriptionPossiblySwapped(); - - isContentsRTL_ = - (base::i18n::RIGHT_TO_LEFT == - base::i18n::GetFirstStrongCharacterDirection(match.contents)); - matchType_ = match.type; - - // Prefix may not have any characters with strong directionality, and may - // take the UI directionality. But prefix needs to appear in continuation - // of the contents so we force the directionality. - NSTextAlignment textAlignment = - isContentsRTL_ ? NSRightTextAlignment : NSLeftTextAlignment; - prefix_ = [CreateAttributedString( - base::UTF8ToUTF16( - match.GetAdditionalInfo(kACMatchPropertyContentsPrefix)), - ContentTextColor(isDarkTheme), textAlignment) retain]; - - isAnswer_ = !!match.answer; - if (isAnswer_) { - contents_ = - [CreateAnswerLine(match.answer->first_line(), isDarkTheme) retain]; - description_ = - [CreateAnswerLine(match.answer->second_line(), isDarkTheme) retain]; - maxLines_ = match.answer->second_line().num_text_lines(); - } else { - contents_ = [CreateClassifiedAttributedString( - match.contents, ContentTextColor(isDarkTheme), match.contents_class, - isDarkTheme) retain]; - if (!match.description.empty()) { - description_ = [CreateClassifiedAttributedString( - match.description, DimTextColor(isDarkTheme), - match.description_class, isDarkTheme) retain]; - } - } - } - return self; -} - -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - -- (instancetype)copyWithZone:(NSZone*)zone { - return [self retain]; -} - -- (CGFloat)getMatchContentsWidth { - return [contents_ size].width; -} - -@end - -@implementation OmniboxPopupCell - -- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - OmniboxPopupMatrix* matrix = - base::mac::ObjCCastStrict<OmniboxPopupMatrix>(controlView); - BOOL isDarkTheme = [matrix hasDarkTheme]; - - if ([self state] == NSOnState || [self isHighlighted]) { - if ([self state] == NSOnState) { - [SelectedBackgroundColor(isDarkTheme) set]; - } else { - [HoveredBackgroundColor(isDarkTheme) set]; - } - NSRectFillUsingOperation(cellFrame, NSCompositeSourceOver); - } - - [self drawMatchWithFrame:cellFrame inView:controlView]; -} - -- (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - OmniboxPopupCellData* cellData = - base::mac::ObjCCastStrict<OmniboxPopupCellData>([self objectValue]); - OmniboxPopupMatrix* tableView = - base::mac::ObjCCastStrict<OmniboxPopupMatrix>(controlView); - CGFloat remainingWidth = - [OmniboxPopupCell getTextContentAreaWidth:[tableView contentMaxWidth]]; - CGFloat contentsWidth = [cellData getMatchContentsWidth]; - CGFloat separatorWidth = [[tableView separator] size].width; - CGFloat descriptionWidth = - [cellData description] ? [[cellData description] size].width : 0; - int contentsMaxWidth, descriptionMaxWidth; - OmniboxPopupModel::ComputeMatchMaxWidths( - ceilf(contentsWidth), ceilf(separatorWidth), ceilf(descriptionWidth), - ceilf(remainingWidth), [cellData isAnswer], - !AutocompleteMatch::IsSearchType([cellData matchType]), &contentsMaxWidth, - &descriptionMaxWidth); - - NSWindow* parentWindow = [[controlView window] parentWindow]; - BOOL isDarkTheme = [parentWindow hasDarkTheme]; - NSRect imageRect = cellFrame; - imageRect.size = [[cellData image] size]; - imageRect.origin.x += kMaterialImageXOffset + [tableView contentLeftPadding]; - imageRect.origin.y += - GetVerticalMargin() + kMaterialExtraVerticalImagePadding; - [[cellData image] drawInRect:FlipIfRTL(imageRect, cellFrame) - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1.0 - respectFlipped:YES - hints:nil]; - - CGFloat left = kMaterialTextStartOffset + [tableView contentLeftPadding]; - NSPoint origin = NSMakePoint(left, GetVerticalMargin()); - - origin.x += [self drawMatchPart:[cellData contents] - withFrame:cellFrame - origin:origin - withMaxWidth:contentsMaxWidth - forDarkTheme:isDarkTheme - withHeightCap:true]; - - if (descriptionMaxWidth > 0) { - if ([cellData isAnswer]) { - origin = NSMakePoint( - left, [OmniboxPopupCell getContentTextHeight] - GetVerticalMargin()); - CGFloat imageSize = [tableView answerLineHeight]; - NSRect imageRect = - NSMakeRect(NSMinX(cellFrame) + origin.x, NSMinY(cellFrame) + origin.y, - imageSize, imageSize); - [[cellData answerImage] drawInRect:FlipIfRTL(imageRect, cellFrame) - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1.0 - respectFlipped:YES - hints:nil]; - if ([cellData answerImage]) { - origin.x += imageSize + kMaterialImageXOffset; - - // Have to nudge the baseline down 1pt in Material Design for the text - // that follows, so that it's the same as the bottom of the image. - origin.y += 1; - } - } else { - origin.x += [self drawMatchPart:[tableView separator] - withFrame:cellFrame - origin:origin - withMaxWidth:separatorWidth - forDarkTheme:isDarkTheme - withHeightCap:true]; - } - [self drawMatchPart:[cellData description] - withFrame:cellFrame - origin:origin - withMaxWidth:descriptionMaxWidth - forDarkTheme:isDarkTheme - withHeightCap:false]; - } -} - -- (CGFloat)drawMatchPart:(NSAttributedString*)attributedString - withFrame:(NSRect)cellFrame - origin:(NSPoint)origin - withMaxWidth:(int)maxWidth - forDarkTheme:(BOOL)isDarkTheme - withHeightCap:(BOOL)hasHeightCap { - NSRect renderRect = NSIntersectionRect( - cellFrame, NSOffsetRect(cellFrame, origin.x, origin.y)); - renderRect.size.width = - std::min(NSWidth(renderRect), static_cast<CGFloat>(maxWidth)); - if (hasHeightCap) - renderRect.size.height = - std::min(NSHeight(renderRect), [attributedString size].height); - if (!NSIsEmptyRect(renderRect)) { - [attributedString drawWithRect:FlipIfRTL(renderRect, cellFrame) - options:NSStringDrawingUsesLineFragmentOrigin | - NSStringDrawingTruncatesLastVisibleLine]; - } - return NSWidth(renderRect); -} - -+ (CGFloat)computeContentsOffset:(const AutocompleteMatch&)match { - const base::string16& inputText = base::UTF8ToUTF16( - match.GetAdditionalInfo(kACMatchPropertySuggestionText)); - int contentsStartIndex = 0; - base::StringToInt( - match.GetAdditionalInfo(kACMatchPropertyContentsStartIndex), - &contentsStartIndex); - // Ignore invalid state. - if (!base::StartsWith(match.fill_into_edit, inputText, - base::CompareCase::SENSITIVE) || - !base::EndsWith(match.fill_into_edit, match.contents, - base::CompareCase::SENSITIVE) || - ((size_t)contentsStartIndex >= inputText.length())) { - return 0; - } - bool isContentsRTL = (base::i18n::RIGHT_TO_LEFT == - base::i18n::GetFirstStrongCharacterDirection(match.contents)); - - // Color does not matter. - NSAttributedString* attributedString = - CreateAttributedString(inputText, DimTextColor(false)); - base::scoped_nsobject<NSTextStorage> textStorage( - [[NSTextStorage alloc] initWithAttributedString:attributedString]); - base::scoped_nsobject<NSLayoutManager> layoutManager( - [[NSLayoutManager alloc] init]); - base::scoped_nsobject<NSTextContainer> textContainer( - [[NSTextContainer alloc] init]); - [layoutManager addTextContainer:textContainer]; - [textStorage addLayoutManager:layoutManager]; - - NSUInteger charIndex = static_cast<NSUInteger>(contentsStartIndex); - NSUInteger glyphIndex = - [layoutManager glyphIndexForCharacterAtIndex:charIndex]; - - // This offset is computed from the left edge of the glyph always from the - // left edge of the string, irrespective of the directionality of UI or text. - CGFloat glyphOffset = [layoutManager locationForGlyphAtIndex:glyphIndex].x; - - CGFloat inputWidth = [attributedString size].width; - - // The offset obtained above may need to be corrected because the left-most - // glyph may not have 0 offset. So we find the offset of left-most glyph, and - // subtract it from the offset of the glyph we obtained above. - CGFloat minOffset = glyphOffset; - - // If content is RTL, we are interested in the right-edge of the glyph. - // Unfortunately the bounding rect computation methods from NSLayoutManager or - // NSFont don't work correctly with bidirectional text. So we compute the - // glyph width by finding the closest glyph offset to the right of the glyph - // we are looking for. - CGFloat glyphWidth = inputWidth; - - for (NSUInteger i = 0; i < [attributedString length]; i++) { - if (i == charIndex) continue; - glyphIndex = [layoutManager glyphIndexForCharacterAtIndex:i]; - CGFloat offset = [layoutManager locationForGlyphAtIndex:glyphIndex].x; - minOffset = std::min(minOffset, offset); - if (offset > glyphOffset) - glyphWidth = std::min(glyphWidth, offset - glyphOffset); - } - glyphOffset -= minOffset; - if (glyphWidth == 0) - glyphWidth = inputWidth - glyphOffset; - if (isContentsRTL) - glyphOffset += glyphWidth; - return base::i18n::IsRTL() ? (inputWidth - glyphOffset) : glyphOffset; -} - -+ (NSAttributedString*)createSeparatorStringForDarkTheme:(BOOL)isDarkTheme { - base::string16 raw_separator = - l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR); - return CreateAttributedString(raw_separator, DimTextColor(isDarkTheme)); -} - -+ (CGFloat)getTextContentAreaWidth:(CGFloat)cellContentMaxWidth { - return cellContentMaxWidth - kMaterialTextStartOffset; -} - -+ (CGFloat)getContentTextHeight { - return kDefaultTextHeight + 2 * GetVerticalMargin(); -} - -@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm deleted file mode 100644 index caea321..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm +++ /dev/null
@@ -1,161 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h" - -#include <stddef.h> - -#include "base/json/json_reader.h" -#include "base/mac/scoped_nsobject.h" -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "components/omnibox/browser/suggestion_answer.h" -#import "testing/gtest_mac.h" - -namespace { - -class OmniboxPopupCellTest : public CocoaTest { - public: - OmniboxPopupCellTest() { - } - - void SetUp() override { - CocoaTest::SetUp(); - control_.reset([[NSControl alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)]); - [control_ setCell:cell_]; - [[test_window() contentView] addSubview:control_]; - }; - - protected: - base::scoped_nsobject<OmniboxPopupCellData> cellData_; - base::scoped_nsobject<OmniboxPopupCell> cell_; - base::scoped_nsobject<NSControl> control_; - - private: - DISALLOW_COPY_AND_ASSIGN(OmniboxPopupCellTest); -}; - -TEST_VIEW(OmniboxPopupCellTest, control_); - -TEST_F(OmniboxPopupCellTest, Image) { - AutocompleteMatch match; - cellData_.reset([[OmniboxPopupCellData alloc] - initWithMatch:match - image:[NSImage imageNamed:NSImageNameInfo] - answerImage:nil - forDarkTheme:NO]); - [cell_ setObjectValue:cellData_]; - [control_ display]; -} - -TEST_F(OmniboxPopupCellTest, Title) { - AutocompleteMatch match; - match.contents = - base::ASCIIToUTF16("The quick brown fox jumps over the lazy dog."); - cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match - image:nil - answerImage:nil - forDarkTheme:NO]); - [cell_ setObjectValue:cellData_]; - [control_ display]; -} - -TEST_F(OmniboxPopupCellTest, AnswerStyle) { - const char* weatherJson = - "{\"l\": [ {\"il\": {\"t\": [ {" - "\"t\": \"weather in pari<b>s</b>\", \"tt\": 8} ]}}, {" - "\"il\": {\"at\": {\"t\": \"Thu\",\"tt\": 12}, " - "\"i\": {\"d\": \"//ssl.gstatic.com/onebox/weather/64/cloudy.png\"," - "\"t\": 3}, \"t\": [ {\"t\": \"46\",\"tt\": 1}, {" - "\"t\": \"°F\",\"tt\": 3} ]}} ]}"; - NSString* finalString = @"46°F Thu"; - - std::unique_ptr<base::Value> root(base::JSONReader::Read(weatherJson)); - ASSERT_NE(root, nullptr); - base::DictionaryValue* dictionary; - root->GetAsDictionary(&dictionary); - ASSERT_NE(dictionary, nullptr); - SuggestionAnswer answer; - EXPECT_TRUE(SuggestionAnswer::ParseAnswer(dictionary, - base::ASCIIToUTF16("-1"), &answer)); - AutocompleteMatch match; - match.answer = answer; - cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match - image:nil - answerImage:nil - forDarkTheme:NO]); - EXPECT_NSEQ([[cellData_ description] string], finalString); - size_t length = [[[cellData_ description] string] length]; - EXPECT_EQ(length, 8UL); - const NSRange checkValues[] = {{0, 2}, {2, 2}, {4, 4}}; - NSDictionary* lastAttributes = nil; - for (const NSRange& value : checkValues) { - NSRange range; - NSDictionary* currentAttributes = - [[cellData_ description] attributesAtIndex:value.location - effectiveRange:&range]; - EXPECT_TRUE(NSEqualRanges(value, range)); - EXPECT_FALSE([currentAttributes isEqualToDictionary:lastAttributes]); - lastAttributes = currentAttributes; - } -} - -TEST_F(OmniboxPopupCellTest, DefinitionAnswerStyle) { - const char* definitionJson = - "{\"l\":" - "[" - "{\"il\":" - "{\"at\":" - "{\"t\":\"\u2022 /??s??SH????liz??m/\"," - "\"tt\":8}," - "\"t\":" - "[" - "{\"t\":\"definition of socialism\"," - "\"tt\":8}" - "]" - "}" - "}," - "{\"il\":" - "{\"t\":" - "[" - "{\"t\":\"a political and economic theory\"," - "\"tt\":8," - "\"ln\":3}" - "]" - "}" - "}" - "]" - "}"; - NSString* finalString = @"a political and economic theory"; - - std::unique_ptr<base::Value> root(base::JSONReader::Read(definitionJson)); - ASSERT_NE(root, nullptr); - base::DictionaryValue* dictionary; - root->GetAsDictionary(&dictionary); - ASSERT_NE(dictionary, nullptr); - SuggestionAnswer answer; - EXPECT_TRUE(SuggestionAnswer::ParseAnswer(dictionary, - base::ASCIIToUTF16("-1"), &answer)); - AutocompleteMatch match; - match.answer = answer; - cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match - image:nil - answerImage:nil - forDarkTheme:NO]); - EXPECT_NSEQ([[cellData_ description] string], finalString); - size_t length = [[[cellData_ description] string] length]; - EXPECT_EQ(length, 31UL); - const NSRange checkValue = {0, 31}; - NSDictionary* lastAttributes = nil; - NSRange range; - NSDictionary* currentAttributes = - [[cellData_ description] attributesAtIndex:checkValue.location - effectiveRange:&range]; - EXPECT_TRUE(NSEqualRanges(checkValue, range)); - EXPECT_FALSE([currentAttributes isEqualToDictionary:lastAttributes]); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h deleted file mode 100644 index 413ad26..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h +++ /dev/null
@@ -1,113 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_MATRIX_H_ -#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_MATRIX_H_ - -#import <Cocoa/Cocoa.h> -#include <stddef.h> - -#import "ui/base/cocoa/tracking_area.h" -#include "ui/base/window_open_disposition.h" - -class AutocompleteResult; -@class OmniboxPopupCell; -@class OmniboxPopupMatrix; -class OmniboxPopupViewMac; - -@interface OmniboxPopupTableController - : NSObject<NSTableViewDelegate, NSTableViewDataSource> { - @private - base::scoped_nsobject<NSArray> array_; - NSInteger hoveredIndex_; -}; - -// Setup the information used by the NSTableView data source. -- (instancetype)initWithMatchResults:(const AutocompleteResult&)result - tableView:(OmniboxPopupMatrix*)tableView - popupView:(const OmniboxPopupViewMac&)popupView - answerImage:(NSImage*)answerImage; - -// Set the hovered highlight. -- (void)setHighlightedRow:(NSInteger)rowIndex; - -// Sets a custom match icon. -- (void)setMatchIcon:(NSImage*)icon forRow:(NSInteger)rowIndex; - -// Which row has the hovered highlight. -- (NSInteger)highlightedRow; - -@end - -@interface OmniboxPopupTableController (TestingAPI) -- (instancetype)initWithArray:(NSArray*)array; -@end - -@class OmniboxPopupMatrix; - -class OmniboxPopupMatrixObserver { - public: - // Called when the selection in the matrix changes. - virtual void OnMatrixRowSelected(OmniboxPopupMatrix* matrix, size_t row) = 0; - - // Called when the user clicks on a row. - virtual void OnMatrixRowClicked(OmniboxPopupMatrix* matrix, size_t row) = 0; - - // Called when the user middle clicks on a row. - virtual void OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix, - size_t row) = 0; -}; - -// Sets up a tracking area to implement hover by highlighting the cell the mouse -// is over. -@interface OmniboxPopupMatrix : NSTableView { - base::scoped_nsobject<OmniboxPopupTableController> matrixController_; - OmniboxPopupMatrixObserver* observer_; // weak - ui::ScopedCrTrackingArea trackingArea_; - NSAttributedString* separator_; - - // The width of widest match contents in a set of tail suggestions. - CGFloat maxMatchContentsWidth_; - - CGFloat answerLineHeight_; - - // Left margin padding for the content (i.e. icon and text) in a cell. - CGFloat contentLeftPadding_; - - // Max width for the content in the cell. - CGFloat contentMaxWidth_; - - // true if the OmniboxPopupMatrix should use the dark theme style. - BOOL hasDarkTheme_; -} - -@property(retain, nonatomic) NSAttributedString* separator; -@property(nonatomic) CGFloat maxMatchContentsWidth; -@property(nonatomic) CGFloat answerLineHeight; -@property(nonatomic) CGFloat contentLeftPadding; -@property(nonatomic) CGFloat contentMaxWidth; -@property(readonly, nonatomic) BOOL hasDarkTheme; - -// Create a zero-size matrix. -- (instancetype)initWithObserver:(OmniboxPopupMatrixObserver*)observer - forDarkTheme:(BOOL)isDarkTheme; - -// Sets the observer. -- (void)setObserver:(OmniboxPopupMatrixObserver*)observer; - -// Return the currently highlighted row. Returns -1 if no row is highlighted. -- (NSInteger)highlightedRow; - -// Move the selection to |rowIndex|. -- (void)selectRowIndex:(NSInteger)rowIndex; - -// Setup the NSTableView data source. -- (void)setController:(OmniboxPopupTableController*)controller; - -// Sets a custom match icon. -- (void)setMatchIcon:(NSImage*)icon forRow:(NSInteger)rowIndex; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_MATRIX_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm deleted file mode 100644 index fbaabd7b..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm +++ /dev/null
@@ -1,325 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h" - -#include "base/logging.h" -#include "base/mac/foundation_util.h" -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h" -#include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h" -#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" -#include "components/omnibox/browser/autocomplete_result.h" - -namespace { - -// NSEvent -buttonNumber for middle mouse button. -const NSInteger kMiddleButtonNumber = 2; - -} // namespace - -@interface OmniboxPopupMatrix () -- (OmniboxPopupTableController*)controller; -- (void)resetTrackingArea; -- (void)highlightRowUnder:(NSEvent*)theEvent; -- (BOOL)selectCellForEvent:(NSEvent*)theEvent; -@end - -@implementation OmniboxPopupTableController - -- (instancetype)initWithMatchResults:(const AutocompleteResult&)result - tableView:(OmniboxPopupMatrix*)tableView - popupView:(const OmniboxPopupViewMac&)popupView - answerImage:(NSImage*)answerImage { - base::scoped_nsobject<NSMutableArray> array([[NSMutableArray alloc] init]); - BOOL isDarkTheme = [tableView hasDarkTheme]; - for (const AutocompleteMatch& match : result) { - base::scoped_nsobject<OmniboxPopupCellData> cellData( - [[OmniboxPopupCellData alloc] - initWithMatch:match - image:popupView.ImageForMatch(match) - answerImage:(match.answer ? answerImage : nil) - forDarkTheme:isDarkTheme]); - [array addObject:cellData]; - } - - return [self initWithArray:array]; -} - -- (instancetype)initWithArray:(NSArray*)array { - if ((self = [super init])) { - hoveredIndex_ = -1; - array_.reset([array copy]); - } - return self; -} - -- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView { - return [array_ count]; -} - -- (id)tableView:(NSTableView*)tableView - objectValueForTableColumn:(NSTableColumn*)tableColumn - row:(NSInteger)rowIndex { - return [array_ objectAtIndex:rowIndex]; -} - -- (void)tableView:(NSTableView*)tableView - setObjectValue:(id)object - forTableColumn:(NSTableColumn*)tableColumn - row:(NSInteger)rowIndex { - NOTREACHED(); -} - -- (void)tableView:(NSTableView*)tableView - willDisplayCell:(id)cell - forTableColumn:(NSTableColumn*)tableColumn - row:(NSInteger)rowIndex { - OmniboxPopupCell* popupCell = - base::mac::ObjCCastStrict<OmniboxPopupCell>(cell); - [popupCell - setState:([tableView selectedRow] == rowIndex) ? NSOnState : NSOffState]; - [popupCell highlight:(hoveredIndex_ == rowIndex) - withFrame:[tableView bounds] - inView:tableView]; -} - -- (NSInteger)highlightedRow { - return hoveredIndex_; -} - -- (void)setHighlightedRow:(NSInteger)rowIndex { - hoveredIndex_ = rowIndex; -} - -- (void)setMatchIcon:(NSImage*)icon forRow:(NSInteger)rowIndex { - OmniboxPopupCellData* cellData = - base::mac::ObjCCastStrict<OmniboxPopupCellData>( - [array_ objectAtIndex:rowIndex]); - [cellData setImage:icon]; -} - -- (CGFloat)tableView:(NSTableView*)tableView heightOfRow:(NSInteger)row { - BOOL isAnswer = [[array_ objectAtIndex:row] isAnswer]; - CGFloat height = [OmniboxPopupCell getContentTextHeight]; - - if (isAnswer) { - OmniboxPopupMatrix* matrix = - base::mac::ObjCCastStrict<OmniboxPopupMatrix>(tableView); - NSRect rowRect = [tableView rectOfColumn:0]; - OmniboxPopupCellData* cellData = - base::mac::ObjCCastStrict<OmniboxPopupCellData>( - [array_ objectAtIndex:row]); - // Subtract any Material Design padding and/or icon. - rowRect.size.width = - [OmniboxPopupCell getTextContentAreaWidth:[matrix contentMaxWidth]]; - NSAttributedString* text = [cellData description]; - // Provide no more than 3 lines of space. - rowRect.size.height = - std::min(3, [cellData maxLines]) * [text size].height; - NSRect textRect = - [text boundingRectWithSize:rowRect.size - options:NSStringDrawingUsesLineFragmentOrigin | - NSStringDrawingTruncatesLastVisibleLine]; - // Add a little padding or it looks cramped. - int heightProvided = textRect.size.height + 2; - height += heightProvided; - } - return height; -} - -@end - -@implementation OmniboxPopupMatrix - -@synthesize separator = separator_; -@synthesize maxMatchContentsWidth = maxMatchContentsWidth_; -@synthesize contentLeftPadding = contentLeftPadding_; -@synthesize contentMaxWidth = contentMaxWidth_; -@synthesize answerLineHeight = answerLineHeight_; -@synthesize hasDarkTheme = hasDarkTheme_; - -- (instancetype)initWithObserver:(OmniboxPopupMatrixObserver*)observer - forDarkTheme:(BOOL)isDarkTheme { - if ((self = [super initWithFrame:NSZeroRect])) { - observer_ = observer; - hasDarkTheme_ = isDarkTheme; - - base::scoped_nsobject<NSTableColumn> column( - [[NSTableColumn alloc] initWithIdentifier:@"MainColumn"]); - [column setDataCell:[[[OmniboxPopupCell alloc] init] autorelease]]; - [self addTableColumn:column]; - - // Cells pack with no spacing. - [self setIntercellSpacing:NSMakeSize(0.0, 0.0)]; - - [self setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone]; - NSColor* backgroundColor = - OmniboxPopupViewMac::BackgroundColor(hasDarkTheme_); - [self setBackgroundColor:backgroundColor]; - [self setAllowsEmptySelection:YES]; - [self deselectAll:self]; - - [self resetTrackingArea]; - - base::scoped_nsobject<NSLayoutManager> layoutManager( - [[NSLayoutManager alloc] init]); - answerLineHeight_ = - [layoutManager defaultLineHeightForFont:OmniboxViewMac::GetLargeFont()]; - } - return self; -} - -- (OmniboxPopupTableController*)controller { - return base::mac::ObjCCastStrict<OmniboxPopupTableController>( - [self delegate]); -} - -- (void)setObserver:(OmniboxPopupMatrixObserver*)observer { - observer_ = observer; -} - -- (void)updateTrackingAreas { - [self resetTrackingArea]; - [super updateTrackingAreas]; -} - -// Callbacks from tracking area. -- (void)mouseMoved:(NSEvent*)theEvent { - [self highlightRowUnder:theEvent]; -} - -- (void)mouseExited:(NSEvent*)theEvent { - [self highlightRowUnder:theEvent]; -} - -// The tracking area events aren't forwarded during a drag, so handle -// highlighting manually for middle-click and middle-drag. -- (void)otherMouseDown:(NSEvent*)theEvent { - if ([theEvent buttonNumber] == kMiddleButtonNumber) { - [self highlightRowUnder:theEvent]; - } - [super otherMouseDown:theEvent]; -} - -- (void)otherMouseDragged:(NSEvent*)theEvent { - if ([theEvent buttonNumber] == kMiddleButtonNumber) { - [self highlightRowUnder:theEvent]; - } - [super otherMouseDragged:theEvent]; -} - -- (void)otherMouseUp:(NSEvent*)theEvent { - // Only intercept middle button. - if ([theEvent buttonNumber] != kMiddleButtonNumber) { - [super otherMouseUp:theEvent]; - return; - } - - // -otherMouseDragged: should always have been called at this location, but - // make sure the user is getting the right feedback. - [self highlightRowUnder:theEvent]; - - const NSInteger highlightedRow = [[self controller] highlightedRow]; - if (highlightedRow != -1) { - DCHECK(observer_); - observer_->OnMatrixRowMiddleClicked(self, highlightedRow); - } -} - -// Track the mouse until released, keeping the cell under the mouse selected. -// If the mouse wanders off-view, revert to the originally-selected cell. If -// the mouse is released over a cell, call the delegate to open the row's URL. -- (void)mouseDown:(NSEvent*)theEvent { - NSCell* selectedCell = [self selectedCell]; - - // Clear any existing highlight. - [[self controller] setHighlightedRow:-1]; - - do { - if (![self selectCellForEvent:theEvent]) { - [self selectCell:selectedCell]; - } - - const NSUInteger mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask; - theEvent = [[self window] nextEventMatchingMask:mask]; - } while ([theEvent type] == NSLeftMouseDragged); - - // Do not message the delegate if released outside view. - if (![self selectCellForEvent:theEvent]) { - [self selectCell:selectedCell]; - } else { - const NSInteger selectedRow = [self selectedRow]; - - // No row could be selected if the model failed to update. - if (selectedRow == -1) { - NOTREACHED(); - return; - } - - DCHECK(observer_); - observer_->OnMatrixRowClicked(self, selectedRow); - } -} - -- (void)selectRowIndex:(NSInteger)rowIndex { - NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:rowIndex]; - [self selectRowIndexes:indexSet byExtendingSelection:NO]; -} - -- (NSInteger)highlightedRow { - return [[self controller] highlightedRow]; -} - -- (void)setController:(OmniboxPopupTableController*)controller { - matrixController_.reset([controller retain]); - [self setDelegate:controller]; - [self setDataSource:controller]; - [self reloadData]; -} - -- (void)resetTrackingArea { - if (trackingArea_.get()) - [self removeTrackingArea:trackingArea_.get()]; - - trackingArea_.reset([[CrTrackingArea alloc] - initWithRect:[self frame] - options:NSTrackingMouseEnteredAndExited | - NSTrackingMouseMoved | - NSTrackingActiveInActiveApp | - NSTrackingInVisibleRect - owner:self - userInfo:nil]); - [self addTrackingArea:trackingArea_.get()]; -} - -- (void)highlightRowUnder:(NSEvent*)theEvent { - NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil]; - NSInteger oldRow = [[self controller] highlightedRow]; - NSInteger newRow = [self rowAtPoint:point]; - if (oldRow != newRow) { - [[self controller] setHighlightedRow:newRow]; - [self setNeedsDisplayInRect:[self rectOfRow:oldRow]]; - [self setNeedsDisplayInRect:[self rectOfRow:newRow]]; - } -} - -- (BOOL)selectCellForEvent:(NSEvent*)theEvent { - NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil]; - - NSInteger row = [self rowAtPoint:point]; - [self selectRowIndex:row]; - if (row != -1) { - DCHECK(observer_); - observer_->OnMatrixRowSelected(self, row); - return YES; - } - return NO; -} - -- (void)setMatchIcon:(NSImage*)icon forRow:(NSInteger)rowIndex { - [[self controller] setMatchIcon:icon forRow:rowIndex]; - [self setNeedsDisplayInRect:[self rectOfRow:rowIndex]]; -} - -@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm deleted file mode 100644 index 616a638..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h" -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h" - -#include <stddef.h> - -#include "base/macros.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#import "ui/events/test/cocoa_test_event_utils.h" - -namespace { - -NSEvent* MouseEventInRow(OmniboxPopupMatrix* matrix, - NSEventType type, - NSInteger row) { - NSRect cell_rect = [matrix rectOfRow:row]; - NSPoint point_in_view = NSMakePoint(NSMidX(cell_rect), NSMidY(cell_rect)); - NSPoint point_in_window = [matrix convertPoint:point_in_view toView:nil]; - return cocoa_test_event_utils::MouseEventAtPoint( - point_in_window, type, 0); -} - -class OmniboxPopupMatrixTest : public CocoaTest, - public OmniboxPopupMatrixObserver { - public: - OmniboxPopupMatrixTest() - : selected_row_(0), clicked_row_(0), middle_clicked_row_(0) {} - - void SetUp() override { - CocoaTest::SetUp(); - matrix_.reset([[OmniboxPopupMatrix alloc] initWithObserver:this - forDarkTheme:NO]); - [[test_window() contentView] addSubview:matrix_]; - - NSMutableArray* array = [NSMutableArray array]; - for (size_t i = 0; i < 3; ++i) - [array addObject:[[[OmniboxPopupCellData alloc] init] autorelease]]; - - matrixController_.reset( - [[OmniboxPopupTableController alloc] initWithArray:array]); - [matrix_ setController:matrixController_]; - }; - - void OnMatrixRowSelected(OmniboxPopupMatrix* matrix, size_t row) override { - selected_row_ = row; - } - - void OnMatrixRowClicked(OmniboxPopupMatrix* matrix, size_t row) override { - clicked_row_ = row; - } - - void OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix, - size_t row) override { - middle_clicked_row_ = row; - } - - protected: - base::scoped_nsobject<OmniboxPopupMatrix> matrix_; - base::scoped_nsobject<OmniboxPopupTableController> matrixController_; - size_t selected_row_; - size_t clicked_row_; - size_t middle_clicked_row_; - - private: - DISALLOW_COPY_AND_ASSIGN(OmniboxPopupMatrixTest); -}; - -TEST_VIEW(OmniboxPopupMatrixTest, matrix_); - -TEST_F(OmniboxPopupMatrixTest, HighlightedRow) { - EXPECT_EQ(-1, [matrix_ highlightedRow]); - - [matrix_ mouseMoved:MouseEventInRow(matrix_, NSMouseMoved, 0)]; - EXPECT_EQ(0, [matrix_ highlightedRow]); - [matrix_ mouseMoved:MouseEventInRow(matrix_, NSMouseMoved, 2)]; - EXPECT_EQ(2, [matrix_ highlightedRow]); - - [matrix_ mouseExited:cocoa_test_event_utils::MouseEventAtPoint( - NSZeroPoint, NSMouseMoved, 0)]; - EXPECT_EQ(-1, [matrix_ highlightedRow]); -} - -TEST_F(OmniboxPopupMatrixTest, SelectedRow) { - [NSApp postEvent:MouseEventInRow(matrix_, NSLeftMouseUp, 2) atStart:YES]; - [matrix_ mouseDown:MouseEventInRow(matrix_, NSLeftMouseDown, 2)]; - - EXPECT_EQ(2u, selected_row_); - EXPECT_EQ(2u, clicked_row_); - EXPECT_EQ(0u, middle_clicked_row_); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h deleted file mode 100644 index 1b91be76..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_SEPARATOR_VIEW_H_ -#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_SEPARATOR_VIEW_H_ - -#import <Cocoa/Cocoa.h> - -#include "chrome/browser/ui/cocoa/background_gradient_view.h" - -// A view used to draw a separator above omnibox popup. -@interface OmniboxPopupTopSeparatorView : BackgroundGradientView { -} - -+ (CGFloat)preferredHeight; - -@end - -// A view used to draw a drop shadow beneath the omnibox popup. -@interface OmniboxPopupBottomSeparatorView : NSView { - @private - BOOL isDarkTheme_; -} - -+ (CGFloat)preferredHeight; -- (instancetype)initWithFrame:(NSRect)frame forDarkTheme:(BOOL)isDarkTheme; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_SEPARATOR_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.mm deleted file mode 100644 index f763108..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.mm +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h" - -#import "base/mac/scoped_nsobject.h" -#include "chrome/grit/theme_resources.h" -#import "ui/base/cocoa/nsview_additions.h" -#include "ui/base/resource/resource_bundle.h" - -@implementation OmniboxPopupTopSeparatorView - -+ (CGFloat)preferredHeight { - return 1; -} - -- (void)drawRect:(NSRect)rect { - NSRect separatorRect = [self bounds]; - separatorRect.size.height = [self cr_lineWidth]; - [[self strokeColor] set]; - NSRectFillUsingOperation(separatorRect, NSCompositeSourceOver); -} - -@end - -@implementation OmniboxPopupBottomSeparatorView - -+ (CGFloat)preferredHeight { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - NSImage* shadowImage = - rb.GetNativeImageNamed(IDR_OVERLAY_DROP_SHADOW).ToNSImage(); - return [shadowImage size].height; -} - -- (instancetype)initWithFrame:(NSRect)frame forDarkTheme:(BOOL)isDarkTheme { - if ((self = [self initWithFrame:frame])) { - isDarkTheme_ = isDarkTheme; - // For dark themes the OmniboxPopupBottomSeparatorView will render a shadow - // rather than blit a bitmap. Shadows are expensive to draw so use a layer - // to cache the result. - if (isDarkTheme_) { - [self setWantsLayer:YES]; - } - } - return self; -} - -- (void)drawRect:(NSRect)rect { - NSRect bounds = [self bounds]; - - if (isDarkTheme_) { - // There's an image for the shadow the Omnibox casts, but this shadow is - // an opaque mix of white and black, which makes it look strange against a - // dark NTP page. For dark mode, draw the shadow in code instead so that - // it has some transparency. - base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); - [shadow setShadowBlurRadius:8]; - [shadow setShadowColor:[NSColor blackColor]]; - [shadow set]; - - // Fill a rect that's out of view to get just the shadow it casts. - [[NSColor blackColor] set]; - NSRectFill(NSMakeRect(-3, NSMaxY(bounds), NSWidth(bounds) + 6, 5)); - return; - } - - // Draw the shadow. - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - NSImage* shadowImage = - rb.GetNativeImageNamed(IDR_OVERLAY_DROP_SHADOW).ToNSImage(); - [shadowImage drawInRect:bounds - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1.0]; -} - -@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm deleted file mode 100644 index 1c7e18c..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h" - -#include "base/mac/scoped_nsobject.h" -#include "base/macros.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" - -class OmniboxPopupBottomSeparatorViewTest : public CocoaTest { - public: - OmniboxPopupBottomSeparatorViewTest() { - NSView* contentView = [test_window() contentView]; - bottom_view_.reset([[OmniboxPopupBottomSeparatorView alloc] - initWithFrame:[contentView bounds]]); - [contentView addSubview:bottom_view_]; - } - - protected: - base::scoped_nsobject<OmniboxPopupBottomSeparatorView> bottom_view_; - - private: - DISALLOW_COPY_AND_ASSIGN(OmniboxPopupBottomSeparatorViewTest); -}; - -TEST_VIEW(OmniboxPopupBottomSeparatorViewTest, bottom_view_); - -TEST_F(OmniboxPopupBottomSeparatorViewTest, PreferredHeight) { - EXPECT_LT(0, [OmniboxPopupBottomSeparatorView preferredHeight]); -} - -class OmniboxPopupTopSeparatorViewTest : public CocoaTest { - public: - OmniboxPopupTopSeparatorViewTest() { - NSView* contentView = [test_window() contentView]; - top_view_.reset([[OmniboxPopupTopSeparatorView alloc] - initWithFrame:[contentView bounds]]); - [contentView addSubview:top_view_]; - } - - protected: - base::scoped_nsobject<OmniboxPopupTopSeparatorView> top_view_; - - private: - DISALLOW_COPY_AND_ASSIGN(OmniboxPopupTopSeparatorViewTest); -}; - -TEST_VIEW(OmniboxPopupTopSeparatorViewTest, top_view_); - -TEST_F(OmniboxPopupTopSeparatorViewTest, PreferredHeight) { - EXPECT_LT(0, [OmniboxPopupTopSeparatorView preferredHeight]); -}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h deleted file mode 100644 index cba9c9b..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_VIEW_MAC_H_ -#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_VIEW_MAC_H_ - -#import <Cocoa/Cocoa.h> -#include <stddef.h> - -#include <memory> - -#include "base/mac/scoped_nsobject.h" -#include "base/macros.h" -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h" -#include "components/omnibox/browser/autocomplete_match.h" -#include "components/omnibox/browser/omnibox_popup_view.h" -#include "ui/gfx/font.h" - -class AutocompleteResult; -class OmniboxEditModel; -class OmniboxPopupModel; -class OmniboxView; - -// Implements OmniboxPopupView using a raw NSWindow containing an -// NSTableView. -class OmniboxPopupViewMac : public OmniboxPopupView, - public OmniboxPopupMatrixObserver { - public: - OmniboxPopupViewMac(OmniboxView* omnibox_view, - OmniboxEditModel* edit_model, - NSTextField* field); - ~OmniboxPopupViewMac() override; - - // Return the OmniboxPopupViewMac background color. - static NSColor* BackgroundColor(bool is_dark_theme); - - // Overridden from OmniboxPopupView: - bool IsOpen() const override; - void InvalidateLine(size_t line) override {} - void OnLineSelected(size_t line) override {} - void UpdatePopupAppearance() override; - void OnMatchIconUpdated(size_t match_index) override; - // This is only called by model in SetSelectedLine() after updating - // everything. Popup should already be visible. - void PaintUpdatesNow() override; - void OnDragCanceled() override {} - - // Overridden from OmniboxPopupMatrixDelegate: - void OnMatrixRowSelected(OmniboxPopupMatrix* matrix, size_t row) override; - void OnMatrixRowClicked(OmniboxPopupMatrix* matrix, size_t row) override; - void OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix, - size_t row) override; - - // Returns the NSImage that should be used as an icon for the given match. - NSImage* ImageForMatch(const AutocompleteMatch& match) const; - - OmniboxPopupMatrix* matrix() { return matrix_; } - - protected: - // Gets the autocomplete results. This is virtual so that it can be overridden - // by tests. - virtual const AutocompleteResult& GetResult() const; - - private: - // Create the popup_ instance if needed. - void CreatePopupIfNeeded(); - - // Calculate the appropriate position for the popup based on the - // field's screen position and the given target for the matrix - // height, and makes the popup visible. Animates to the new frame - // if the popup shrinks, snaps to the new frame if the popup grows, - // allows existing animations to continue if the size doesn't - // change. - void PositionPopup(const CGFloat matrixHeight); - - // Opens the URL at the given row. - void OpenURLForRow(size_t row, WindowOpenDisposition disposition); - - OmniboxView* omnibox_view_; - std::unique_ptr<OmniboxPopupModel> model_; - NSTextField* field_; // owned by tab controller - - // Child window containing a matrix which implements the popup. - base::scoped_nsobject<NSWindow> popup_; - - base::scoped_nsobject<OmniboxPopupMatrix> matrix_; - base::scoped_nsobject<NSView> top_separator_view_; - base::scoped_nsobject<NSView> bottom_separator_view_; - base::scoped_nsobject<NSBox> background_view_; - - DISALLOW_COPY_AND_ASSIGN(OmniboxPopupViewMac); -}; - -#endif // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_VIEW_MAC_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm deleted file mode 100644 index 8a19238d0..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm +++ /dev/null
@@ -1,335 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h" - -#include <cmath> - -#include "base/mac/mac_util.h" -#import "base/mac/sdk_forward_declarations.h" -#include "base/stl_util.h" -#include "base/strings/sys_string_conversions.h" -#include "chrome/browser/search/search.h" -#include "chrome/browser/ui/cocoa/browser_window_controller.h" -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h" -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h" -#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" -#include "components/omnibox/browser/autocomplete_match.h" -#include "components/omnibox/browser/autocomplete_match_type.h" -#include "components/omnibox/browser/omnibox_edit_model.h" -#include "components/omnibox/browser/omnibox_popup_model.h" -#include "components/toolbar/vector_icons.h" -#include "skia/ext/skia_utils_mac.h" -#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h" -#import "ui/base/cocoa/cocoa_base_utils.h" -#import "ui/base/cocoa/flipped_view.h" -#include "ui/base/cocoa/window_size_constants.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image_skia_util_mac.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" -#include "ui/gfx/text_elider.h" - -namespace { - -const int kMaterialPopupPaddingVertical = 4; - -// Padding between matrix and the top and bottom of the popup window. -CGFloat PopupPaddingVertical() { - return kMaterialPopupPaddingVertical; -} - -// Animation duration when animating the popup window smaller. -const NSTimeInterval kShrinkAnimationDuration = 0.1; - -} // namespace - -OmniboxPopupViewMac::OmniboxPopupViewMac(OmniboxView* omnibox_view, - OmniboxEditModel* edit_model, - NSTextField* field) - : omnibox_view_(omnibox_view), - model_(new OmniboxPopupModel(this, edit_model)), - field_(field), - popup_(nil) { - DCHECK(omnibox_view); - DCHECK(edit_model); -} - -OmniboxPopupViewMac::~OmniboxPopupViewMac() { - // Destroy the popup model before this object is destroyed, because - // it can call back to us in the destructor. - model_.reset(); - - // Break references to |this| because the popup may not be - // deallocated immediately. - [matrix_ setObserver:NULL]; -} - -// Background colors for different states of the popup elements. -// static -NSColor* OmniboxPopupViewMac::BackgroundColor(bool is_dark_theme) { - const CGFloat kMDDarkControlBackground = 40 / 255.; - return is_dark_theme - ? [NSColor colorWithGenericGamma22White:kMDDarkControlBackground - alpha:1] - : [NSColor controlBackgroundColor]; -} - -bool OmniboxPopupViewMac::IsOpen() const { - return popup_ != nil; -} - -void OmniboxPopupViewMac::UpdatePopupAppearance() { - DCHECK([NSThread isMainThread]); - model_->autocomplete_controller()->InlineTailPrefixes(); - const AutocompleteResult& result = GetResult(); - const size_t rows = result.size(); - if (rows == 0) { - [[popup_ parentWindow] removeChildWindow:popup_]; - [popup_ orderOut:nil]; - - // Break references to |this| because the popup may not be - // deallocated immediately. - [matrix_ setObserver:NULL]; - matrix_.reset(); - - popup_.reset(nil); - return; - } - - CreatePopupIfNeeded(); - - NSImage* answerImage = nil; - const size_t result_size = model_->result().size(); - for (size_t i = 0; i < result_size; ++i) { - const SkBitmap* bitmap = model_->RichSuggestionBitmapAt(i); - if (result.match_at(i).answer && bitmap != nullptr) { - answerImage = gfx::Image::CreateFrom1xBitmap(*bitmap).CopyNSImage(); - break; - } - } - [matrix_ setController:[[[OmniboxPopupTableController alloc] - initWithMatchResults:result - tableView:matrix_ - popupView:*this - answerImage:answerImage] autorelease]]; - BOOL is_dark_theme = [matrix_ hasDarkTheme]; - [matrix_ setSeparator:[OmniboxPopupCell - createSeparatorStringForDarkTheme:is_dark_theme]]; - - // Update the selection before placing (and displaying) the window. - PaintUpdatesNow(); - - // Calculate the matrix size manually rather than using -sizeToCells - // because actually resizing the matrix messed up the popup size - // animation. - DCHECK_EQ([matrix_ intercellSpacing].height, 0.0); - PositionPopup(NSHeight([matrix_ frame])); -} - -void OmniboxPopupViewMac::OnMatchIconUpdated(size_t match_index) { - [matrix_ setMatchIcon:ImageForMatch(GetResult().match_at(match_index)) - forRow:match_index]; -} - -// This is only called by model in SetSelectedLine() after updating -// everything. Popup should already be visible. -void OmniboxPopupViewMac::PaintUpdatesNow() { - [matrix_ selectRowIndex:model_->selected_line()]; -} - -void OmniboxPopupViewMac::OnMatrixRowSelected(OmniboxPopupMatrix* matrix, - size_t row) { - model_->SetSelectedLine(row, false, false); -} - -void OmniboxPopupViewMac::OnMatrixRowClicked(OmniboxPopupMatrix* matrix, - size_t row) { - OpenURLForRow(row, - ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent])); -} - -void OmniboxPopupViewMac::OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix, - size_t row) { - OpenURLForRow(row, WindowOpenDisposition::NEW_BACKGROUND_TAB); -} - -const AutocompleteResult& OmniboxPopupViewMac::GetResult() const { - return model_->result(); -} - -void OmniboxPopupViewMac::CreatePopupIfNeeded() { - if (!popup_) { - popup_.reset( - [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]); - [popup_ setBackgroundColor:[NSColor clearColor]]; - [popup_ setOpaque:NO]; - - // Use a flipped view to pin the matrix top the top left. This is needed - // for animated resize. - base::scoped_nsobject<FlippedView> contentView( - [[FlippedView alloc] initWithFrame:NSZeroRect]); - [popup_ setContentView:contentView]; - - BOOL is_dark_theme = [[field_ window] hasDarkTheme]; - - // View to draw a background beneath the matrix. - background_view_.reset([[NSBox alloc] initWithFrame:NSZeroRect]); - [background_view_ setBoxType:NSBoxCustom]; - [background_view_ setBorderType:NSNoBorder]; - [background_view_ setFillColor:BackgroundColor(is_dark_theme)]; - [background_view_ setContentViewMargins:NSZeroSize]; - [contentView addSubview:background_view_]; - - matrix_.reset([[OmniboxPopupMatrix alloc] initWithObserver:this - forDarkTheme:is_dark_theme]); - [background_view_ addSubview:matrix_]; - - top_separator_view_.reset( - [[OmniboxPopupTopSeparatorView alloc] initWithFrame:NSZeroRect]); - [contentView addSubview:top_separator_view_]; - - bottom_separator_view_.reset([[OmniboxPopupBottomSeparatorView alloc] - initWithFrame:NSZeroRect - forDarkTheme:is_dark_theme]); - [contentView addSubview:bottom_separator_view_]; - - // TODO(dtseng): Ignore until we provide NSAccessibility support. - [popup_ accessibilitySetOverrideValue:NSAccessibilityUnknownRole - forAttribute:NSAccessibilityRoleAttribute]; - } -} - -void OmniboxPopupViewMac::PositionPopup(const CGFloat matrixHeight) { - BrowserWindowController* controller = - [BrowserWindowController browserWindowControllerForView:field_]; - NSRect anchor_rect_base = [controller omniboxPopupAnchorRect]; - - // Calculate the popup's position on the screen. - NSRect popup_frame = anchor_rect_base; - - CGFloat table_width = NSWidth([[[field_ window] contentView] bounds]); - DCHECK_GT(table_width, 0.0); - - NSPoint field_origin_base = - [field_ convertPoint:[field_ bounds].origin toView:nil]; - - // Size to fit the matrix and shift down by the size. - popup_frame.size.height = matrixHeight + PopupPaddingVertical() * 2.0; - popup_frame.size.height += [OmniboxPopupTopSeparatorView preferredHeight]; - popup_frame.size.height += [OmniboxPopupBottomSeparatorView preferredHeight]; - popup_frame.origin.x = 0; - popup_frame.origin.y -= NSHeight(popup_frame); - - // Shift to screen coordinates. - if ([controller window]) { - popup_frame = [[controller window] convertRectToScreen:popup_frame]; - } - - // Top separator. - NSRect top_separator_frame = NSZeroRect; - top_separator_frame.size.width = NSWidth(popup_frame); - top_separator_frame.size.height = - [OmniboxPopupTopSeparatorView preferredHeight]; - [top_separator_view_ setFrame:top_separator_frame]; - - // Bottom separator. - NSRect bottom_separator_frame = NSZeroRect; - bottom_separator_frame.size.width = NSWidth(popup_frame); - bottom_separator_frame.size.height = - [OmniboxPopupBottomSeparatorView preferredHeight]; - bottom_separator_frame.origin.y = - NSHeight(popup_frame) - NSHeight(bottom_separator_frame); - [bottom_separator_view_ setFrame:bottom_separator_frame]; - - // Background view. - NSRect background_rect = NSZeroRect; - background_rect.size.width = NSWidth(popup_frame); - background_rect.size.height = NSHeight(popup_frame) - - NSHeight(top_separator_frame) - NSHeight(bottom_separator_frame); - background_rect.origin.y = NSMaxY(top_separator_frame); - [background_view_ setFrame:background_rect]; - - // Matrix. - NSRect matrix_frame = NSZeroRect; - matrix_frame.origin.x = 0; - [matrix_ setContentLeftPadding:field_origin_base.x]; - [matrix_ setContentMaxWidth:NSWidth([field_ bounds])]; - matrix_frame.origin.y = PopupPaddingVertical(); - matrix_frame.size.width = table_width; - matrix_frame.size.height = matrixHeight; - [matrix_ setFrame:matrix_frame]; - [[[matrix_ tableColumns] objectAtIndex:0] setWidth:table_width]; - - // Don't play animation games on first display. - if (![popup_ parentWindow]) { - DCHECK(![popup_ isVisible]); - [popup_ setFrame:popup_frame display:NO]; - [[field_ window] addChildWindow:popup_ ordered:NSWindowAbove]; - return; - } - DCHECK([popup_ isVisible]); - - // Animate the frame change if the only change is that the height got smaller. - // Otherwise, resize immediately. - NSRect current_popup_frame = [popup_ frame]; - bool animate = (NSHeight(popup_frame) < NSHeight(current_popup_frame) && - NSWidth(popup_frame) == NSWidth(current_popup_frame)); - - base::scoped_nsobject<NSDictionary> savedAnimations; - if (!animate) { - // In an ideal world, running a zero-length animation would cancel any - // running animations and set the new frame value immediately. In practice, - // zero-length animations are ignored entirely. Work around this AppKit bug - // by explicitly setting an NSNull animation for the "frame" key and then - // running the animation with a non-zero(!!) duration. This somehow - // convinces AppKit to do the right thing. Save off the current animations - // dictionary so it can be restored later. - savedAnimations.reset([[popup_ animations] copy]); - [popup_ setAnimations:@{@"frame" : [NSNull null]}]; - } - - [NSAnimationContext beginGrouping]; - // Don't use the GTM addition for the "Steve" slowdown because this can - // happen async from user actions and the effects could be a surprise. - [[NSAnimationContext currentContext] setDuration:kShrinkAnimationDuration]; - // When using the animator to update |popup_| on El Capitan, for some reason - // the window does not get redrawn. Use a completion handler to make sure - // |popup_| gets redrawn once the animation completes. See - // http://crbug.com/538590 and http://crbug.com/551007 . - if (base::mac::IsAtLeastOS10_11()) { - NSWindow* popup = popup_.get(); - [[NSAnimationContext currentContext] setCompletionHandler:^{ - [popup display]; - }]; - } - [[popup_ animator] setFrame:popup_frame display:YES]; - [NSAnimationContext endGrouping]; - - if (!animate) { - // Restore the original animations dictionary. This does not reinstate any - // previously running animations. - [popup_ setAnimations:savedAnimations]; - } -} - -NSImage* OmniboxPopupViewMac::ImageForMatch( - const AutocompleteMatch& match) const { - bool is_dark_mode = [matrix_ hasDarkTheme]; - const SkColor vector_icon_color = - is_dark_mode ? SkColorSetA(SK_ColorWHITE, 0xCC) : gfx::kChromeIconGrey; - return model_->GetMatchIcon(match, vector_icon_color).ToNSImage(); -} - -void OmniboxPopupViewMac::OpenURLForRow(size_t row, - WindowOpenDisposition disposition) { - DCHECK_LT(row, GetResult().size()); - omnibox_view_->OpenMatch(GetResult().match_at(row), disposition, GURL(), - base::string16(), row, base::TimeTicks()); -}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm deleted file mode 100644 index e81c00c..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h" - -#include <stddef.h> - -#include <memory> - -#include "base/macros.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" -#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h" -#include "chrome/test/base/testing_profile.h" -#include "components/omnibox/browser/autocomplete_input.h" -#include "components/omnibox/browser/autocomplete_result.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/text_elider.h" - -namespace { - -class MockOmniboxPopupViewMac : public OmniboxPopupViewMac { - public: - MockOmniboxPopupViewMac(OmniboxView* omnibox_view, - OmniboxEditModel* edit_model, - NSTextField* field) - : OmniboxPopupViewMac(omnibox_view, edit_model, field) { - } - - void SetResultCount(size_t count) { - ACMatches matches; - for (size_t i = 0; i < count; ++i) - matches.push_back(AutocompleteMatch()); - result_.Reset(); - result_.AppendMatches(AutocompleteInput(), matches); - } - - protected: - const AutocompleteResult& GetResult() const override { return result_; } - - private: - AutocompleteResult result_; -}; - -class OmniboxPopupViewMacTest : public CocoaProfileTest { - public: - OmniboxPopupViewMacTest() {} - - private: - DISALLOW_COPY_AND_ASSIGN(OmniboxPopupViewMacTest); -}; - -TEST_F(OmniboxPopupViewMacTest, UpdatePopupAppearance) { - base::scoped_nsobject<NSTextField> field( - [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)]); - [[test_window() contentView] addSubview:field]; - - OmniboxViewMac view(NULL, profile(), NULL, NULL); - MockOmniboxPopupViewMac popup_view(&view, view.model(), field); - - popup_view.UpdatePopupAppearance(); - EXPECT_FALSE(popup_view.IsOpen()); - EXPECT_EQ(0, [popup_view.matrix() numberOfRows]); - - popup_view.SetResultCount(3); - popup_view.UpdatePopupAppearance(); - EXPECT_TRUE(popup_view.IsOpen()); - EXPECT_EQ(3, [popup_view.matrix() numberOfRows]); - - popup_view.SetResultCount(5); - popup_view.UpdatePopupAppearance(); - EXPECT_EQ(5, [popup_view.matrix() numberOfRows]); - - popup_view.SetResultCount(0); - popup_view.UpdatePopupAppearance(); - EXPECT_FALSE(popup_view.IsOpen()); - EXPECT_EQ(0, [popup_view.matrix() numberOfRows]); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h deleted file mode 100644 index 222d8dd..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h +++ /dev/null
@@ -1,246 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_VIEW_MAC_H_ -#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_VIEW_MAC_H_ - -#import <Cocoa/Cocoa.h> -#include <stddef.h> - -#include <memory> - -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "base/strings/string16.h" -#include "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" -#include "components/omnibox/browser/omnibox_view.h" -#include "components/security_state/core/security_state.h" -#include "third_party/skia/include/core/SkColor.h" - -class CommandUpdater; -class OmniboxPopupView; -class Profile; - -namespace content { -class WebContents; -} - -// Implements OmniboxView on an AutocompleteTextField. -class OmniboxViewMac : public OmniboxView, - public AutocompleteTextFieldObserver { - public: - static SkColor BaseTextColorSkia(bool in_dark_mode); - static NSColor* BaseTextColor(bool in_dark_mode); - // Returns a color representing |security_level|, adjusted based on whether - // the browser is in Incognito mode. - static NSColor* GetSecureTextColor( - security_state::SecurityLevel security_level, - bool in_dark_mode); - - OmniboxViewMac(OmniboxEditController* controller, - Profile* profile, - CommandUpdater* command_updater, - AutocompleteTextField* field); - ~OmniboxViewMac() override; - - // For use when switching tabs, this saves the current state onto the tab so - // that it can be restored during a later call to Update(). - void SaveStateToTab(content::WebContents* tab); - - // Called when the window's active tab changes. - void OnTabChanged(const content::WebContents* web_contents); - - // Called to clear the saved state for |web_contents|. - void ResetTabState(content::WebContents* web_contents); - - // OmniboxView: - void Update() override; - void OpenMatch(const AutocompleteMatch& match, - WindowOpenDisposition disposition, - const GURL& alternate_nav_url, - const base::string16& pasted_text, - size_t selected_line, - base::TimeTicks match_selection_timestamp) override; - base::string16 GetText() const override; - void SetWindowTextAndCaretPos(const base::string16& text, - size_t caret_pos, - bool update_popup, - bool notify_text_changed) override; - void SetCaretPos(size_t caret_pos) override; - void EnterKeywordModeForDefaultSearchProvider() override; - bool IsSelectAll() const override; - void GetSelectionBounds(base::string16::size_type* start, - base::string16::size_type* end) const override; - void SelectAll(bool reversed) override; - void RevertAll() override; - void UpdatePopup() override; - void CloseOmniboxPopup() override; - void SetFocus() override; - void ApplyCaretVisibility() override; - void OnTemporaryTextMaybeChanged(const base::string16& display_text, - const AutocompleteMatch& match, - bool save_original_selection, - bool notify_text_changed) override; - bool OnInlineAutocompleteTextMaybeChanged(const base::string16& display_text, - size_t user_text_length) override; - void OnInlineAutocompleteTextCleared() override; - void OnRevertTemporaryText() override; - void OnBeforePossibleChange() override; - bool OnAfterPossibleChange(bool allow_keyword_ui_change) override; - gfx::NativeView GetNativeView() const override; - gfx::NativeView GetRelativeWindowForPopup() const override; - int GetTextWidth() const override; - int GetWidth() const override; - bool IsImeComposing() const override; - - // Implement the AutocompleteTextFieldObserver interface. - NSRange SelectionRangeForProposedRange(NSRange proposed_range) override; - void OnControlKeyChanged(bool pressed) override; - bool CanCopy() override; - base::scoped_nsobject<NSPasteboardItem> CreatePasteboardItem() override; - void CopyToPasteboard(NSPasteboard* pboard) override; - void OnPaste() override; - bool CanPasteAndGo() override; - int GetPasteActionStringId() override; - void OnPasteAndGo() override; - void OnFrameChanged() override; - void ClosePopup() override; - void OnDidBeginEditing() override; - void OnBeforeChange() override; - void OnDidChange() override; - void OnDidEndEditing() override; - void OnInsertText() override; - void OnBeforeDrawRect() override; - void OnDidDrawRect() override; - bool OnDoCommandBySelector(SEL cmd) override; - void OnSetFocus(bool control_down) override; - void OnKillFocus() override; - void OnMouseDown(NSInteger button_number) override; - - // Helper for LocationBarViewMac. Optionally selects all in |field_|. - void FocusLocation(bool select_all); - - // Helper to get the font to use in the field, exposed for the - // popup. - static NSFont* GetNormalFieldFont(); - static NSFont* GetBoldFieldFont(); - static NSFont* GetLargeFont(); - static NSFont* GetSmallFont(); - - // If |resource_id| has a PDF image which can be used, return it. - // Otherwise return the PNG image from the resource bundle. - static NSImage* ImageForResource(int resource_id); - - // Color used to draw suggest text. - static NSColor* SuggestTextColor(); - - AutocompleteTextField* field() const { return field_; } - - private: - FRIEND_TEST_ALL_PREFIXES(OmniboxViewMacTest, WritingDirectionLTR); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewMacTest, WritingDirectionRTL); - // Called when the user hits backspace in |field_|. Checks whether - // keyword search is being terminated. Returns true if the - // backspace should be intercepted (not forwarded on to the standard - // machinery). - bool OnBackspacePressed(); - - // Returns the field's currently selected range. Only valid if the - // field has focus. - NSRange GetSelectedRange() const; - - // Returns the field's currently marked range. Only valid if the field has - // focus. - NSRange GetMarkedRange() const; - - // Returns true if |field_| is first-responder in the window. Used - // in various DCHECKS to make sure code is running in appropriate - // situations. - bool IsFirstResponder() const; - - // If |model_| believes it has focus, grab focus if needed and set - // the selection to |range|. Otherwise does nothing. - void SetSelectedRange(const NSRange range); - - // Update the field with |display_text| and highlight the host and scheme (if - // it's an URL or URL-fragment). Resets any suggest text that may be present. - void SetText(const base::string16& display_text); - - // Internal implementation of SetText. Does not reset the suggest text before - // setting the display text. Most callers should use |SetText()| instead. - void SetTextInternal(const base::string16& display_text); - - // Update the field with |display_text| and set the selection. - void SetTextAndSelectedRange(const base::string16& display_text, - const NSRange range); - - // Pass the current content of |field_| to SetText(), maintaining - // any selection. Named to be consistent with GTK and Windows, - // though here we cannot really do the in-place operation they do. - void EmphasizeURLComponents() override; - - // Apply our font and paragraph style to |attributedString|. - void ApplyTextStyle(NSMutableAttributedString* attributedString); - - // Calculates text attributes according to |display_text| and applies them - // to the given |attributed_string| object. - void ApplyTextAttributes(const base::string16& display_text, - NSMutableAttributedString* attributed_string); - - // OmniboxView: - void SetEmphasis(bool emphasize, const gfx::Range& range) override; - void UpdateSchemeStyle(const gfx::Range& scheme_range) override; - - // Return the number of UTF-16 units in the current buffer, excluding the - // suggested text. - int GetOmniboxTextLength() const override; - NSUInteger GetTextLength() const; - - // Returns true if the caret is at the end of the content. - bool IsCaretAtEnd() const; - - // Announce that an inline autocomplete is available for screenreaders. - void AnnounceAutocompleteForScreenReader(const base::string16& text); - - Profile* profile_; - - std::unique_ptr<OmniboxPopupView> popup_view_; - - AutocompleteTextField* field_; // owned by tab controller - - // Selection at the point where the user started using the - // arrows to move around in the popup. - NSRange saved_temporary_selection_; - - // Tracking state before and after a possible change for reporting - // to model_. - State state_before_change_; - NSRange marked_range_before_change_; - - // Was delete pressed? - bool delete_was_pressed_; - - // State used to coalesce changes to text and selection to avoid drawing - // transient state. - bool in_coalesced_update_block_; - bool do_coalesced_text_update_; - base::string16 coalesced_text_update_; - bool do_coalesced_range_update_; - NSRange coalesced_range_update_; - - // The time of the first character insert operation that has not yet been - // painted. Used to measure omnibox responsiveness with a histogram. - base::TimeTicks insert_char_time_; - - // The time when OnBeforeDrawRect() was called. - base::TimeTicks draw_rect_start_time_; - - // Temporary pointer to the attributed display string, stored as color and - // other emphasis attributes are applied by the superclass. - NSMutableAttributedString* attributing_display_string_; // weak - - DISALLOW_COPY_AND_ASSIGN(OmniboxViewMac); -}; - -#endif // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_VIEW_MAC_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm deleted file mode 100644 index df24ddc..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm +++ /dev/null
@@ -1,1084 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" - -#include <Carbon/Carbon.h> // kVK_Return - -#include "base/auto_reset.h" -#include "base/mac/foundation_util.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/search/search.h" -#include "chrome/browser/themes/theme_service.h" -#import "chrome/browser/ui/cocoa/browser_window_controller.h" -#import "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" -#include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h" -#include "chrome/browser/ui/omnibox/chrome_omnibox_client.h" -#include "chrome/browser/ui/omnibox/clipboard_utils.h" -#include "chrome/grit/generated_resources.h" -#include "components/omnibox/browser/autocomplete_input.h" -#include "components/omnibox/browser/autocomplete_match.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" -#include "components/omnibox/browser/omnibox_field_trial.h" -#include "components/omnibox/browser/omnibox_popup_model.h" -#include "components/toolbar/toolbar_model.h" -#include "content/public/browser/web_contents.h" -#include "extensions/common/constants.h" -#import "skia/ext/skia_utils_mac.h" -#import "third_party/mozilla/NSPasteboard+Utils.h" -#include "ui/base/clipboard/clipboard.h" -#include "ui/base/clipboard/clipboard_util_mac.h" -#import "ui/base/cocoa/cocoa_base_utils.h" -#import "ui/base/l10n/l10n_util_mac.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/font.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/geometry/rect.h" - -using content::WebContents; - -// Focus-handling between |field_| and model() is a bit subtle. -// Other platforms detect change of focus, which is inconvenient -// without subclassing NSTextField (even with a subclass, the use of a -// field editor may complicate things). -// -// model() doesn't actually do anything when it gains focus, it just -// initializes. Visible activity happens only after the user edits. -// NSTextField delegate receives messages around starting and ending -// edits, so that suffices to catch focus changes. Since all calls -// into model() start from OmniboxViewMac, in the worst case -// we can add code to sync up the sense of focus as needed. -// -// I've added DCHECK(IsFirstResponder()) in the places which I believe -// should only be reachable when |field_| is being edited. If these -// fire, it probably means someone unexpected is calling into -// model(). -// -// Other platforms don't appear to have the sense of "key window" that -// Mac does (I believe their fields lose focus when the window loses -// focus). Rather than modifying focus outside the control's edit -// scope, when the window resigns key the autocomplete popup is -// closed. model() still believes it has focus, and the popup will -// be regenerated on the user's next edit. That seems to match how -// things work on other platforms. - -namespace { -const int kOmniboxLargeFontSizeDelta = 9; -const int kOmniboxNormalFontSizeDelta = 1; -const int kOmniboxSmallMaterialFontSizeDelta = -1; - -NSColor* HostTextColor(bool in_dark_mode) { - return in_dark_mode ? [NSColor whiteColor] : [NSColor blackColor]; -} -NSColor* SecureSchemeColor(bool in_dark_mode) { - return in_dark_mode ? skia::SkColorToSRGBNSColor(SK_ColorWHITE) - : skia::SkColorToSRGBNSColor(gfx::kGoogleGreen700); -} -NSColor* SecurityErrorSchemeColor(bool in_dark_mode) { - return in_dark_mode - ? skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorWHITE, 0x7F)) - : skia::SkColorToSRGBNSColor(gfx::kGoogleRed700); -} - -const char kOmniboxViewMacStateKey[] = "OmniboxViewMacState"; - -// Store's the model and view state across tab switches. -struct OmniboxViewMacState : public base::SupportsUserData::Data { - OmniboxViewMacState(const OmniboxEditModel::State model_state, - const bool has_focus, - const NSRange& selection) - : model_state(model_state), - has_focus(has_focus), - selection(selection) { - } - ~OmniboxViewMacState() override {} - - const OmniboxEditModel::State model_state; - const bool has_focus; - const NSRange selection; -}; - -// Accessors for storing and getting the state from the tab. -void StoreStateToTab(WebContents* tab, - std::unique_ptr<OmniboxViewMacState> state) { - tab->SetUserData(kOmniboxViewMacStateKey, std::move(state)); -} - -const OmniboxViewMacState* GetStateFromTab(const WebContents* tab) { - return static_cast<OmniboxViewMacState*>( - tab->GetUserData(&kOmniboxViewMacStateKey)); -} - -} // namespace - -// static -NSImage* OmniboxViewMac::ImageForResource(int resource_id) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - return rb.GetNativeImageNamed(resource_id).ToNSImage(); -} - -// static -NSColor* OmniboxViewMac::SuggestTextColor() { - return [NSColor colorWithCalibratedWhite:0.0 alpha:0.5]; -} - -//static -SkColor OmniboxViewMac::BaseTextColorSkia(bool in_dark_mode) { - return in_dark_mode ? SkColorSetA(SK_ColorWHITE, 0x7F) - : SkColorSetA(SK_ColorBLACK, 0x7F); -} - -// static -NSColor* OmniboxViewMac::BaseTextColor(bool in_dark_mode) { - return skia::SkColorToSRGBNSColor(BaseTextColorSkia(in_dark_mode)); -} - -// static -NSColor* OmniboxViewMac::GetSecureTextColor( - security_state::SecurityLevel security_level, - bool in_dark_mode) { - if (security_level == security_state::EV_SECURE || - security_level == security_state::SECURE) { - return SecureSchemeColor(in_dark_mode); - } - - DCHECK_EQ(security_state::DANGEROUS, security_level); - return SecurityErrorSchemeColor(in_dark_mode); -} - -OmniboxViewMac::OmniboxViewMac(OmniboxEditController* controller, - Profile* profile, - CommandUpdater* command_updater, - AutocompleteTextField* field) - : OmniboxView( - controller, - base::WrapUnique(new ChromeOmniboxClient(controller, profile))), - profile_(profile), - popup_view_(new OmniboxPopupViewMac(this, model(), field)), - field_(field), - saved_temporary_selection_(NSMakeRange(0, 0)), - marked_range_before_change_(NSMakeRange(0, 0)), - delete_was_pressed_(false), - in_coalesced_update_block_(false), - do_coalesced_text_update_(false), - do_coalesced_range_update_(false), - attributing_display_string_(nil) { - [field_ setObserver:this]; - - // Needed so that editing doesn't lose the styling. - [field_ setAllowsEditingTextAttributes:YES]; - - // Get the appropriate line height for the font that we use. - base::scoped_nsobject<NSLayoutManager> layoutManager( - [[NSLayoutManager alloc] init]); - [layoutManager setUsesScreenFonts:YES]; -} - -OmniboxViewMac::~OmniboxViewMac() { - // Destroy popup view before this object in case it tries to call us - // back in the destructor. - popup_view_.reset(); - - // Disconnect from |field_|, it outlives this object. - [field_ setObserver:NULL]; -} - -void OmniboxViewMac::SaveStateToTab(WebContents* tab) { - DCHECK(tab); - - const bool hasFocus = [field_ currentEditor] ? true : false; - - NSRange range; - if (hasFocus) { - range = GetSelectedRange(); - } else { - // If we are not focused, there is no selection. Manufacture - // something reasonable in case it starts to matter in the future. - range = NSMakeRange(0, GetTextLength()); - } - - StoreStateToTab(tab, std::make_unique<OmniboxViewMacState>( - model()->GetStateForTabSwitch(), hasFocus, range)); -} - -void OmniboxViewMac::OnTabChanged(const WebContents* web_contents) { - const OmniboxViewMacState* state = GetStateFromTab(web_contents); - model()->RestoreState(state ? &state->model_state : NULL); - // Restore focus and selection if they were present when the tab - // was switched away. - if (state && state->has_focus) { -// TODO(shess): Unfortunately, there is no safe way to update -// this because TabStripControllerCocoa -selectTabWithContents:* is -// also messing with focus. Both parties need to agree to -// store existing state before anyone tries to setup the new -// state. Anyhow, it would look something like this. -#if 0 - [[field_ window] makeFirstResponder:field_]; - [[field_ currentEditor] setSelectedRange:state->selection]; -#endif - } -} - -void OmniboxViewMac::ResetTabState(WebContents* web_contents) { - StoreStateToTab(web_contents, nullptr); -} - -void OmniboxViewMac::Update() { - if (model()->ResetDisplayTexts()) { - // Restore everything to the baseline look. - RevertAll(); - - // Only select all when we have focus. It's incorrect to have the - // Omnibox text selected while unfocused, and we'll re-select it - // when focus returns. - if (model()->has_focus()) - SelectAll(true); - } else { - // TODO(shess): This corresponds to _win and _gtk, except those - // guard it with a test for whether the security level changed. - // But AFAICT, that can only change if the text changed, and that - // code compares the toolbar model security level with the local - // security level. Dig in and figure out why this isn't a no-op - // that should go away. - EmphasizeURLComponents(); - } -} - -void OmniboxViewMac::OpenMatch(const AutocompleteMatch& match, - WindowOpenDisposition disposition, - const GURL& alternate_nav_url, - const base::string16& pasted_text, - size_t selected_line, - base::TimeTicks match_selection_timestamp) { - // Coalesce text and selection updates from the following function. If we - // don't do this, the user may see intermediate states as brief flickers. - in_coalesced_update_block_ = true; - OmniboxView::OpenMatch(match, disposition, alternate_nav_url, pasted_text, - selected_line, match_selection_timestamp); - in_coalesced_update_block_ = false; - if (do_coalesced_text_update_) { - SetText(coalesced_text_update_); - // Ensure location bar icon is updated to reflect text. - controller()->OnChanged(); - } - do_coalesced_text_update_ = false; - if (do_coalesced_range_update_) - SetSelectedRange(coalesced_range_update_); - do_coalesced_range_update_ = false; -} - -base::string16 OmniboxViewMac::GetText() const { - return base::SysNSStringToUTF16([field_ stringValue]); -} - -NSRange OmniboxViewMac::GetSelectedRange() const { - return [[field_ currentEditor] selectedRange]; -} - -NSRange OmniboxViewMac::GetMarkedRange() const { - DCHECK([field_ currentEditor]); - return [(NSTextView*)[field_ currentEditor] markedRange]; -} - -void OmniboxViewMac::SetSelectedRange(const NSRange range) { - if (in_coalesced_update_block_) { - do_coalesced_range_update_ = true; - coalesced_range_update_ = range; - return; - } - - // This can be called when we don't have focus. For instance, when - // the user clicks the "Go" button. - if (model()->has_focus()) { - // TODO(shess): If model() thinks we have focus, this should not - // be necessary. Try to convert to DCHECK(IsFirstResponder()). - if (![field_ currentEditor]) { - [[field_ window] makeFirstResponder:field_]; - } - - // TODO(shess): What if it didn't get first responder, and there is - // no field editor? This will do nothing. Well, at least it won't - // crash. Think of something more productive to do, or prove that - // it cannot occur and DCHECK appropriately. - [[field_ currentEditor] setSelectedRange:range]; - } -} - -void OmniboxViewMac::SetWindowTextAndCaretPos(const base::string16& text, - size_t caret_pos, - bool update_popup, - bool notify_text_changed) { - DCHECK_LE(caret_pos, text.size()); - SetTextAndSelectedRange(text, NSMakeRange(caret_pos, 0)); - - if (update_popup) - UpdatePopup(); - - if (notify_text_changed) - TextChanged(); -} - -void OmniboxViewMac::SetCaretPos(size_t caret_pos) { - size_t pos = std::min(caret_pos, GetTextLength()); - SetSelectedRange(NSMakeRange(pos, 0)); -} - -void OmniboxViewMac::EnterKeywordModeForDefaultSearchProvider() { - // We need to do this first, else |SetSelectedRange()| won't work. - FocusLocation(true); - - // Transition the user into keyword mode using their default search provider. - model()->EnterKeywordModeForDefaultSearchProvider( - KeywordModeEntryMethod::KEYBOARD_SHORTCUT); -} - -bool OmniboxViewMac::IsSelectAll() const { - if (![field_ currentEditor]) - return true; - const NSRange all_range = NSMakeRange(0, GetTextLength()); - if (all_range.length == 0) - return false; - return NSEqualRanges(all_range, GetSelectedRange()); -} - -void OmniboxViewMac::GetSelectionBounds(base::string16::size_type* start, - base::string16::size_type* end) const { - if (![field_ currentEditor]) { - *start = *end = 0; - return; - } - - const NSRange selected_range = GetSelectedRange(); - *start = static_cast<size_t>(selected_range.location); - *end = static_cast<size_t>(NSMaxRange(selected_range)); -} - -void OmniboxViewMac::SelectAll(bool reversed) { - if (!model()->has_focus()) - return; - - NSRange full_range = NSMakeRange(0, GetTextLength()); - - // When coalescing updates, just set the range and not the direction. It's - // unlikely that the direction will matter after OpenMatch() applies updates. - if (in_coalesced_update_block_) { - SetSelectedRange(full_range); - return; - } - - NSTextView* text_view = - base::mac::ObjCCastStrict<NSTextView>([field_ currentEditor]); - NSSelectionAffinity affinity = - reversed ? NSSelectionAffinityUpstream : NSSelectionAffinityDownstream; - - [text_view setSelectedRange:full_range affinity:affinity stillSelecting:NO]; -} - -void OmniboxViewMac::RevertAll() { - OmniboxView::RevertAll(); - [field_ clearUndoChain]; -} - -void OmniboxViewMac::UpdatePopup() { - // Comment copied from OmniboxViewWin::UpdatePopup(): - // Don't inline autocomplete when: - // * The user is deleting text - // * The caret/selection isn't at the end of the text - // * The user has just pasted in something that replaced all the text - // * The user is trying to compose something in an IME - bool prevent_inline_autocomplete = IsImeComposing(); - NSTextView* editor = (NSTextView*)[field_ currentEditor]; - if (editor) { - if (NSMaxRange([editor selectedRange]) < [[editor textStorage] length]) - prevent_inline_autocomplete = true; - } - - model()->UpdateInput([editor selectedRange].length != 0, - prevent_inline_autocomplete); -} - -void OmniboxViewMac::CloseOmniboxPopup() { - // Call both base class methods. - ClosePopup(); - OmniboxView::CloseOmniboxPopup(); -} - -void OmniboxViewMac::SetFocus() { - FocusLocation(false); - model()->SetCaretVisibility(true); -} - -void OmniboxViewMac::ApplyCaretVisibility() { - [[field_ cell] setHideFocusState:!model()->is_caret_visible() - ofView:field_]; -} - -void OmniboxViewMac::SetText(const base::string16& display_text) { - SetTextInternal(display_text); -} - -void OmniboxViewMac::SetTextInternal(const base::string16& display_text) { - if (in_coalesced_update_block_) { - do_coalesced_text_update_ = true; - coalesced_text_update_ = display_text; - // Don't do any selection changes, since they apply to the previous text. - do_coalesced_range_update_ = false; - return; - } - - NSString* ss = base::SysUTF16ToNSString(display_text); - NSMutableAttributedString* attributedString = - [[[NSMutableAttributedString alloc] initWithString:ss] autorelease]; - - ApplyTextAttributes(display_text, attributedString); - [field_ setAttributedStringValue:attributedString]; - - // TODO(shess): This may be an appropriate place to call: - // model()->OnChanged(); - // In the current implementation, this tells LocationBarViewMac to - // mess around with model() and update |field_|. Unfortunately, - // when I look at our peer implementations, it's not entirely clear - // to me if this is safe. SetTextInternal() is sort of an utility method, - // and different callers sometimes have different needs. Research - // this issue so that it can be added safely. - - // TODO(shess): Also, consider whether this code couldn't just - // manage things directly. Windows uses a series of overlaid view - // objects to accomplish the hinting stuff that OnChanged() does, so - // it makes sense to have it in the controller that lays those - // things out. Mac instead pushes the support into a custom - // text-field implementation. -} - -void OmniboxViewMac::SetTextAndSelectedRange(const base::string16& display_text, - const NSRange range) { - SetText(display_text); - SetSelectedRange(range); -} - -void OmniboxViewMac::EmphasizeURLComponents() { - NSTextView* editor = (NSTextView*)[field_ currentEditor]; - // If the autocomplete text field is in editing mode, then we can just change - // its attributes through its editor. Otherwise, we simply reset its content. - if (editor) { - NSTextStorage* storage = [editor textStorage]; - [storage beginEditing]; - - // Clear the existing attributes from the text storage, then - // overlay the appropriate Omnibox attributes. - [storage setAttributes:[NSDictionary dictionary] - range:NSMakeRange(0, [storage length])]; - ApplyTextAttributes(GetText(), storage); - - [storage endEditing]; - - // This function can be called during the editor's -resignFirstResponder. If - // that happens, |storage| and |field_| will not be synced automatically any - // more. Calling -stringValue ensures that |field_| reflects the changes to - // |storage|. - [field_ stringValue]; - } else if (!in_coalesced_update_block_) { - // Skip this if we're in a coalesced update block. Otherwise, the user text - // entered can get set in a new tab because we haven't yet set the URL text. - SetText(GetText()); - } -} - -void OmniboxViewMac::ApplyTextStyle( - NSMutableAttributedString* attributedString) { - [attributedString addAttribute:NSFontAttributeName - value:GetNormalFieldFont() - range:NSMakeRange(0, [attributedString length])]; - - // Make a paragraph style locking in the standard line height as the maximum, - // otherwise the baseline may shift "downwards". - base::scoped_nsobject<NSMutableParagraphStyle> paragraph_style( - [[NSMutableParagraphStyle alloc] init]); - CGFloat line_height = [[field_ cell] lineHeight]; - [paragraph_style setMaximumLineHeight:line_height]; - [paragraph_style setMinimumLineHeight:line_height]; - [paragraph_style setLineBreakMode:NSLineBreakByTruncatingTail]; - // Set an explicit alignment so it isn't implied from writing direction. - [paragraph_style setAlignment:cocoa_l10n_util::ShouldDoExperimentalRTLLayout() - ? NSRightTextAlignment - : NSLeftTextAlignment]; - if (@available(macOS 10.11, *)) - [paragraph_style setAllowsDefaultTighteningForTruncation:NO]; - // If this is a URL, set the top-level paragraph direction to LTR (avoids RTL - // characters from making the URL render from right to left, as per RFC 3987 - // Section 4.1). - if (model()->CurrentTextIsURL()) - [paragraph_style setBaseWritingDirection:NSWritingDirectionLeftToRight]; - [attributedString addAttribute:NSParagraphStyleAttributeName - value:paragraph_style - range:NSMakeRange(0, [attributedString length])]; -} - -void OmniboxViewMac::SetEmphasis(bool emphasize, const gfx::Range& range) { - bool in_dark_mode = [[field_ window] inIncognitoModeWithSystemTheme]; - - NSRange ns_range = range.IsValid() - ? range.ToNSRange() - : NSMakeRange(0, [attributing_display_string_ length]); - - [attributing_display_string_ - addAttribute:NSForegroundColorAttributeName - value:(emphasize) ? HostTextColor(in_dark_mode) - : BaseTextColor(in_dark_mode) - range:ns_range]; -} - -void OmniboxViewMac::UpdateSchemeStyle(const gfx::Range& range) { - if (!range.IsValid()) - return; - - const security_state::SecurityLevel security_level = - controller()->GetToolbarModel()->GetSecurityLevel(false); - - if ((security_level == security_state::NONE) || - (security_level == security_state::HTTP_SHOW_WARNING)) - return; - - if (security_level == security_state::DANGEROUS) { - // Add a strikethrough through the scheme. - [attributing_display_string_ - addAttribute:NSStrikethroughStyleAttributeName - value:[NSNumber numberWithInt:NSUnderlineStyleSingle] - range:range.ToNSRange()]; - } - - bool in_dark_mode = [[field_ window] inIncognitoModeWithSystemTheme]; - - [attributing_display_string_ - addAttribute:NSForegroundColorAttributeName - value:GetSecureTextColor(security_level, in_dark_mode) - range:range.ToNSRange()]; -} - -void OmniboxViewMac::ApplyTextAttributes( - const base::string16& display_text, - NSMutableAttributedString* attributed_string) { - NSUInteger as_length = [attributed_string length]; - if (as_length == 0) { - return; - } - - ApplyTextStyle(attributed_string); - - // A kinda hacky way to add breaking at periods. This is what Safari does. - // This works for IDNs too, despite the "en_US". - [attributed_string addAttribute:@"NSLanguage" - value:@"en_US_POSIX" - range:NSMakeRange(0, as_length)]; - - // Cache a pointer to the attributed string to allow the superclass' - // virtual method invocations to add attributes. - DCHECK(attributing_display_string_ == nil); - base::AutoReset<NSMutableAttributedString*> resetter( - &attributing_display_string_, attributed_string); - UpdateTextStyle(display_text, model()->CurrentTextIsURL(), - ChromeAutocompleteSchemeClassifier(profile_)); -} - -void OmniboxViewMac::OnTemporaryTextMaybeChanged( - const base::string16& display_text, - const AutocompleteMatch& match, - bool save_original_selection, - bool notify_text_changed) { - if (save_original_selection) - saved_temporary_selection_ = GetSelectedRange(); - - SetWindowTextAndCaretPos(display_text, display_text.size(), false, false); - if (notify_text_changed) - model()->OnChanged(); - [field_ clearUndoChain]; - - // Get friendly accessibility label. - AnnounceAutocompleteForScreenReader( - AutocompleteMatchType::ToAccessibilityLabel( - match, display_text, model()->popup_model()->selected_line(), - model()->result().size(), false)); -} - -bool OmniboxViewMac::OnInlineAutocompleteTextMaybeChanged( - const base::string16& display_text, - size_t user_text_length) { - // TODO(shess): Make sure that this actually works. The round trip - // to native form and back may mean that it's the same but not the - // same. - if (display_text == GetText()) - return false; - - DCHECK_LE(user_text_length, display_text.size()); - const NSRange range = - NSMakeRange(user_text_length, display_text.size() - user_text_length); - SetTextAndSelectedRange(display_text, range); - model()->OnChanged(); - [field_ clearUndoChain]; - - AnnounceAutocompleteForScreenReader(display_text); - - return true; -} - -void OmniboxViewMac::OnInlineAutocompleteTextCleared() { -} - -void OmniboxViewMac::OnRevertTemporaryText() { - SetSelectedRange(saved_temporary_selection_); - // We got here because the user hit the Escape key. We explicitly don't call - // TextChanged(), since OmniboxPopupModel::ResetToDefaultMatch() has already - // been called by now, and it would've called TextChanged() if it was - // warranted. -} - -bool OmniboxViewMac::IsFirstResponder() const { - return [field_ currentEditor] != nil ? true : false; -} - -void OmniboxViewMac::OnBeforePossibleChange() { - // We should only arrive here when the field is focused. - DCHECK(IsFirstResponder()); - - GetState(&state_before_change_); - marked_range_before_change_ = GetMarkedRange(); -} - -bool OmniboxViewMac::OnAfterPossibleChange(bool allow_keyword_ui_change) { - // We should only arrive here when the field is focused. - DCHECK(IsFirstResponder()); - - State new_state; - GetState(&new_state); - OmniboxView::StateChanges state_changes = - GetStateChanges(state_before_change_, new_state); - - const bool something_changed = model()->OnAfterPossibleChange( - state_changes, allow_keyword_ui_change && !IsImeComposing()); - - // Restyle in case the user changed something. - // TODO(shess): I believe there are multiple-redraw cases, here. - // Linux watches for something_changed && text_differs, but that - // fails for us in case you copy the URL and paste the identical URL - // back (we'll lose the styling). - TextChanged(); - - delete_was_pressed_ = false; - - return something_changed; -} - -gfx::NativeView OmniboxViewMac::GetNativeView() const { - return field_; -} - -gfx::NativeView OmniboxViewMac::GetRelativeWindowForPopup() const { - // Not used on mac. - NOTREACHED(); - return NULL; -} - -int OmniboxViewMac::GetTextWidth() const { - // Not used on mac. - NOTREACHED(); - return 0; -} - -int OmniboxViewMac::GetWidth() const { - return ceil([field_ bounds].size.width); -} - -bool OmniboxViewMac::IsImeComposing() const { - return [(NSTextView*)[field_ currentEditor] hasMarkedText]; -} - -void OmniboxViewMac::OnDidBeginEditing() { - // We should only arrive here when the field is focused. - DCHECK([field_ currentEditor]); -} - -void OmniboxViewMac::OnBeforeChange() { - // Capture the current state. - OnBeforePossibleChange(); -} - -void OmniboxViewMac::OnDidChange() { - // Figure out what changed and notify the model. - OnAfterPossibleChange(true); -} - -void OmniboxViewMac::OnDidEndEditing() { - ClosePopup(); -} - -void OmniboxViewMac::OnInsertText() { - // If |insert_char_time_| is not null, there's a pending insert char operation - // that hasn't been painted yet. Keep the earlier time. - if (insert_char_time_.is_null()) - insert_char_time_ = base::TimeTicks::Now(); -} - -void OmniboxViewMac::OnBeforeDrawRect() { - if (!insert_char_time_.is_null()) { - UMA_HISTOGRAM_TIMES("Omnibox.CharTypedToRepaintLatency.ToPaint", - base::TimeTicks::Now() - insert_char_time_); - } - draw_rect_start_time_ = base::TimeTicks::Now(); -} - -void OmniboxViewMac::OnDidDrawRect() { - base::TimeTicks now = base::TimeTicks::Now(); - UMA_HISTOGRAM_TIMES("Omnibox.PaintTime", now - draw_rect_start_time_); - if (!insert_char_time_.is_null()) { - UMA_HISTOGRAM_TIMES("Omnibox.CharTypedToRepaintLatency", - now - insert_char_time_); - insert_char_time_ = base::TimeTicks(); - } -} - -bool OmniboxViewMac::OnDoCommandBySelector(SEL cmd) { - if (cmd == @selector(deleteForward:)) - delete_was_pressed_ = true; - - if (cmd == @selector(moveDown:)) { - model()->OnUpOrDownKeyPressed(1); - return true; - } - - if (cmd == @selector(moveUp:)) { - model()->OnUpOrDownKeyPressed(-1); - return true; - } - - if (model()->popup_model()->IsOpen()) { - if (cmd == @selector(insertBacktab:)) { - if (model()->popup_model()->selected_line_state() == - OmniboxPopupModel::KEYWORD) { - model()->ClearKeyword(); - return true; - } else { - model()->OnUpOrDownKeyPressed(-1); - return true; - } - } - - if ((cmd == @selector(insertTab:) || - cmd == @selector(insertTabIgnoringFieldEditor:)) && - !model()->is_keyword_hint()) { - model()->OnUpOrDownKeyPressed(1); - return true; - } - } - - if (cmd == @selector(scrollPageDown:)) { - model()->OnUpOrDownKeyPressed(model()->result().size()); - return true; - } - - if (cmd == @selector(scrollPageUp:)) { - model()->OnUpOrDownKeyPressed(-model()->result().size()); - return true; - } - - if (cmd == @selector(cancelOperation:)) { - return model()->OnEscapeKeyPressed(); - } - - if ((cmd == @selector(insertTab:) || - cmd == @selector(insertTabIgnoringFieldEditor:)) && - model()->is_keyword_hint()) { - return model()->AcceptKeyword(KeywordModeEntryMethod::TAB); - } - - // |-noop:| is sent when the user presses Cmd+Return. Override the no-op - // behavior with the proper WindowOpenDisposition. - NSEvent* event = [NSApp currentEvent]; - if (cmd == @selector(insertNewline:) || - (cmd == @selector(noop:) && - ([event type] == NSKeyDown || [event type] == NSKeyUp) && - [event keyCode] == kVK_Return)) { - // If the user hasn't entered any text in keyword search mode, we need to - // return early in order to avoid cancelling the search. - if (GetTextLength() == 0) - return true; - - WindowOpenDisposition disposition = - ui::WindowOpenDispositionFromNSEvent(event); - model()->AcceptInput(disposition, false); - // Opening a URL in a background tab should also revert the omnibox contents - // to their original state. We cannot do a blanket revert in OpenURL() - // because middle-clicks also open in a new background tab, but those should - // not revert the omnibox text. - RevertAll(); - return true; - } - - // Option-Return - if (cmd == @selector(insertNewlineIgnoringFieldEditor:)) { - model()->AcceptInput(WindowOpenDisposition::NEW_FOREGROUND_TAB, false); - return true; - } - - // When the user does Control-Enter, the existing content has "www." - // prepended and ".com" appended. model() should already have - // received notification when the Control key was depressed, but it - // is safe to tell it twice. - if (cmd == @selector(insertLineBreak:)) { - OnControlKeyChanged(true); - WindowOpenDisposition disposition = - ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); - model()->AcceptInput(disposition, false); - return true; - } - - if (cmd == @selector(deleteBackward:)) { - if (OnBackspacePressed()) { - return true; - } - } - - if (cmd == @selector(deleteForward:)) { - const NSUInteger modifiers = [[NSApp currentEvent] modifierFlags]; - if ((modifiers & NSShiftKeyMask) != 0) { - if (model()->popup_model()->IsOpen()) { - model()->popup_model()->TryDeletingCurrentItem(); - return true; - } - } - } - - return false; -} - -void OmniboxViewMac::OnSetFocus(bool control_down) { - model()->OnSetFocus(control_down); - // Update the keyword and search hint states. - controller()->OnChanged(); -} - -void OmniboxViewMac::OnKillFocus() { - // Tell the model to reset itself. - model()->OnWillKillFocus(); - model()->OnKillFocus(); -} - -void OmniboxViewMac::OnMouseDown(NSInteger button_number) { - // Restore caret visibility whenever the user clicks in the the omnibox. This - // is not always covered by OnSetFocus() because when clicking while the - // omnibox has invisible focus does not trigger a new OnSetFocus() call. - if (button_number == 0 || button_number == 1) - model()->SetCaretVisibility(true); -} - -bool OmniboxViewMac::CanCopy() { - const NSRange selection = GetSelectedRange(); - return selection.length > 0; -} - -base::scoped_nsobject<NSPasteboardItem> OmniboxViewMac::CreatePasteboardItem() { - DCHECK(CanCopy()); - - const NSRange selection = GetSelectedRange(); - base::string16 text = base::SysNSStringToUTF16( - [[field_ stringValue] substringWithRange:selection]); - - // Copy the URL. - GURL url; - bool write_url = false; - model()->AdjustTextForCopy(selection.location, &text, &url, &write_url); - - if (IsSelectAll()) - UMA_HISTOGRAM_COUNTS_1M(OmniboxEditModel::kCutOrCopyAllTextHistogram, 1); - - NSString* nstext = base::SysUTF16ToNSString(text); - if (write_url) { - return ui::ClipboardUtil::PasteboardItemFromUrl( - base::SysUTF8ToNSString(url.spec()), nstext); - } else { - return ui::ClipboardUtil::PasteboardItemFromString(nstext); - } -} - -void OmniboxViewMac::CopyToPasteboard(NSPasteboard* pboard) { - [pboard clearContents]; - base::scoped_nsobject<NSPasteboardItem> item(CreatePasteboardItem()); - [pboard writeObjects:@[ item.get() ]]; -} - -void OmniboxViewMac::OnPaste() { - // This code currently expects |field_| to be focused. - DCHECK([field_ currentEditor]); - - base::string16 text = GetClipboardText(); - if (text.empty()) { - return; - } - NSString* s = base::SysUTF16ToNSString(text); - - // -shouldChangeTextInRange:* and -didChangeText are documented in - // NSTextView as things you need to do if you write additional - // user-initiated editing functions. They cause the appropriate - // delegate methods to be called. - // TODO(shess): It would be nice to separate the Cocoa-specific code - // from the Chrome-specific code. - NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]); - const NSRange selectedRange = GetSelectedRange(); - if ([editor shouldChangeTextInRange:selectedRange replacementString:s]) { - // Record this paste, so we can do different behavior. - model()->OnPaste(); - - // Force a Paste operation to trigger the text_changed code in - // OnAfterPossibleChange(), even if identical contents are pasted - // into the text box. - state_before_change_.text.clear(); - - [editor replaceCharactersInRange:selectedRange withString:s]; - [editor didChangeText]; - } -} - -bool OmniboxViewMac::CanPasteAndGo() { - return model()->CanPasteAndGo(GetClipboardText()); -} - -int OmniboxViewMac::GetPasteActionStringId() { - base::string16 text(GetClipboardText()); - DCHECK(model()->CanPasteAndGo(text)); - return model()->ClassifiesAsSearch(text) ? IDS_PASTE_AND_SEARCH - : IDS_PASTE_AND_GO; -} - -void OmniboxViewMac::OnPasteAndGo() { - base::string16 text(GetClipboardText()); - if (model()->CanPasteAndGo(text)) - model()->PasteAndGo(text); -} - -void OmniboxViewMac::OnFrameChanged() { - // TODO(shess): UpdatePopupAppearance() is called frequently, so it - // should be really cheap, but in this case we could probably make - // things even cheaper by refactoring between the popup-placement - // code and the matrix-population code. - popup_view_->UpdatePopupAppearance(); - - // Give controller a chance to rearrange decorations. - model()->OnChanged(); -} - -void OmniboxViewMac::ClosePopup() { - OmniboxView::CloseOmniboxPopup(); -} - -bool OmniboxViewMac::OnBackspacePressed() { - // Don't intercept if not in keyword search mode. - if (model()->is_keyword_hint() || model()->keyword().empty()) { - return false; - } - - // Don't intercept if there is a selection, or the cursor isn't at - // the leftmost position. - const NSRange selection = GetSelectedRange(); - if (selection.length > 0 || selection.location > 0) { - return false; - } - - // We're showing a keyword and the user pressed backspace at the - // beginning of the text. Delete the selected keyword. - model()->ClearKeyword(); - return true; -} - -NSRange OmniboxViewMac::SelectionRangeForProposedRange(NSRange proposed_range) { - return proposed_range; -} - -void OmniboxViewMac::OnControlKeyChanged(bool pressed) { - model()->OnControlKeyChanged(pressed); -} - -void OmniboxViewMac::FocusLocation(bool select_all) { - if ([field_ isEditable]) { - // If the text field has a field editor, it's the first responder, meaning - // that it's already focused. makeFirstResponder: will select all, so only - // call it if this behavior is desired. - if (select_all || ![field_ currentEditor]) - [[field_ window] makeFirstResponder:field_]; - DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]); - } -} - -// static -NSFont* OmniboxViewMac::GetNormalFieldFont() { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - return rb - .GetFontWithDelta(kOmniboxNormalFontSizeDelta, gfx::Font::NORMAL, - gfx::Font::Weight::NORMAL) - .GetNativeFont(); -} - -NSFont* OmniboxViewMac::GetBoldFieldFont() { - // Request a bold font, then make it larger. ResourceBundle will do the - // opposite which makes a large system normal font a non-system bold font. - // That gives a different baseline to making the non-system bold font larger. - // And while the omnibox locks the baseline in ApplyTextStyle(), - // OmniboxPopupCellData does not. - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - return rb - .GetFontWithDelta(0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD) - .Derive(kOmniboxNormalFontSizeDelta, gfx::Font::NORMAL, - gfx::Font::Weight::BOLD) - .GetNativeFont(); -} - -NSFont* OmniboxViewMac::GetLargeFont() { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - return rb - .GetFontWithDelta(kOmniboxLargeFontSizeDelta, gfx::Font::NORMAL, - gfx::Font::Weight::NORMAL) - .GetNativeFont(); -} - -NSFont* OmniboxViewMac::GetSmallFont() { - return ui::ResourceBundle::GetSharedInstance() - .GetFontWithDelta(kOmniboxSmallMaterialFontSizeDelta, gfx::Font::NORMAL, - gfx::Font::Weight::NORMAL) - .GetNativeFont(); -} - -int OmniboxViewMac::GetOmniboxTextLength() const { - return static_cast<int>(GetTextLength()); -} - -NSUInteger OmniboxViewMac::GetTextLength() const { - return [field_ currentEditor] ? [[[field_ currentEditor] string] length] : - [[field_ stringValue] length]; -} - -bool OmniboxViewMac::IsCaretAtEnd() const { - const NSRange selection = GetSelectedRange(); - return NSMaxRange(selection) == GetTextLength(); -} - -void OmniboxViewMac::AnnounceAutocompleteForScreenReader( - const base::string16& display_text) { - NSDictionary* notification_info = @{ - NSAccessibilityAnnouncementKey : base::SysUTF16ToNSString(display_text), - NSAccessibilityPriorityKey : @(NSAccessibilityPriorityHigh) - }; - // We direct the screen reader to announce the friendly text. - NSAccessibilityPostNotificationWithUserInfo( - [field_ window], - NSAccessibilityAnnouncementRequestedNotification, - notification_info); -}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_browsertest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_browsertest.mm deleted file mode 100644 index 9fd195a..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_browsertest.mm +++ /dev/null
@@ -1,100 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" - -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_window.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" -#include "chrome/browser/ui/location_bar/location_bar.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/views/scoped_macviews_browser_mode.h" -#include "components/omnibox/browser/omnibox_edit_model.h" -#include "ui/base/clipboard/clipboard_util_mac.h" - -class OmniboxViewMacBrowserTest : public InProcessBrowserTest { - public: - OmniboxViewMac* GetOmnibox() { - return static_cast<OmniboxViewMac*>( - browser()->window()->GetLocationBar()->GetOmniboxView()); - } - - private: - test::ScopedMacViewsBrowserMode cocoa_browser_mode_{false}; -}; - -// Verify that the OmniboxViewMac::SetFocus API works. -IN_PROC_BROWSER_TEST_F(OmniboxViewMacBrowserTest, SetFocus) { - EXPECT_FALSE([[GetOmnibox()->field() window] firstResponder] == - GetOmnibox()->field()); - GetOmnibox()->SetFocus(); - // Unfortunately there's no way to test that the field has keyboard focus. -} - -// Verify that the OmniboxViewMac::ApplyCaretVisibility API works. -IN_PROC_BROWSER_TEST_F(OmniboxViewMacBrowserTest, ApplyCaretVisibility) { - EXPECT_FALSE([[GetOmnibox()->field() cell] hideFocusState]); - - // |SetCaretVisibility(false)| should hide focus state. - GetOmnibox()->model()->SetCaretVisibility(false); - GetOmnibox()->ApplyCaretVisibility(); - EXPECT_TRUE([[GetOmnibox()->field() cell] hideFocusState]); - - // |SetCaretVisibility(true)| should show focus state. - GetOmnibox()->model()->SetCaretVisibility(true); - GetOmnibox()->ApplyCaretVisibility(); - EXPECT_FALSE([[GetOmnibox()->field() cell] hideFocusState]); - - // Focusing on the omnibox should show focus state. - GetOmnibox()->model()->SetCaretVisibility(false); - GetOmnibox()->ApplyCaretVisibility(); - EXPECT_TRUE([[GetOmnibox()->field() cell] hideFocusState]); - GetOmnibox()->SetFocus(); - EXPECT_FALSE([[GetOmnibox()->field() cell] hideFocusState]); -} - - -// Verify that mouse down sets caret visibility to true. -IN_PROC_BROWSER_TEST_F(OmniboxViewMacBrowserTest, MouseDownCaretVisibility) { - GetOmnibox()->model()->SetCaretVisibility(false); - EXPECT_FALSE(GetOmnibox()->model()->is_caret_visible()); - GetOmnibox()->OnMouseDown(0); - EXPECT_TRUE(GetOmnibox()->model()->is_caret_visible()); -} - -// Verify that copying text from the omnibox into the pasteboard works. -IN_PROC_BROWSER_TEST_F(OmniboxViewMacBrowserTest, CopyToPasteboard) { - std::string text = "orange yam"; - NSString* pboard_type = @"com.google.chrome.asdf"; - - scoped_refptr<ui::UniquePasteboard> pasteboard = new ui::UniquePasteboard; - [[GetOmnibox()->field() currentEditor] - setString:base::SysUTF8ToNSString(text)]; - [[GetOmnibox()->field() currentEditor] - setSelectedRange:NSMakeRange(0, text.size())]; - - GetOmnibox()->model()->SetUserText(base::UTF8ToUTF16(text)); - GetOmnibox()->CopyToPasteboard(pasteboard->get()); - - NSString* pasteboard_string = - [pasteboard->get() stringForType:NSPasteboardTypeString]; - EXPECT_EQ(text, pasteboard_string.UTF8String); - - // Clear the pasteboard and set some new contents, using a custom Pboard type. - [pasteboard->get() clearContents]; - [pasteboard->get() - setString:@"bad result" - forType:ui::ClipboardUtil::UTIForPasteboardType(pboard_type)]; - GetOmnibox()->CopyToPasteboard(pasteboard->get()); - - // Check that the custom Pboard type is no longer present. - EXPECT_FALSE([pasteboard->get() - stringForType:ui::ClipboardUtil::UTIForPasteboardType(pboard_type)]); - - // Check that the contents of the omnibox were copied to the clipboard. - pasteboard_string = [pasteboard->get() stringForType:NSPasteboardTypeString]; - EXPECT_EQ(text, pasteboard_string.UTF8String); -}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm deleted file mode 100644 index 552401f..0000000 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm +++ /dev/null
@@ -1,241 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" - -#include <stddef.h> - -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h" -#include "chrome/browser/ui/cocoa/test/scoped_force_rtl_mac.h" -#include "chrome/browser/ui/omnibox/chrome_omnibox_client.h" -#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h" -#include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h" -#include "chrome/test/base/testing_profile.h" -#include "components/omnibox/browser/omnibox_popup_model.h" -#include "components/omnibox/browser/omnibox_popup_view.h" -#include "components/toolbar/toolbar_model_impl.h" -#include "content/public/common/content_constants.h" -#include "testing/platform_test.h" -#include "ui/gfx/font.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image.h" - -namespace { - -class MockOmniboxEditModel : public OmniboxEditModel { - public: - MockOmniboxEditModel(OmniboxView* view, - OmniboxEditController* controller, - Profile* profile) - : OmniboxEditModel( - view, - controller, - base::WrapUnique(new ChromeOmniboxClient(controller, profile))), - up_or_down_count_(0) {} - - void OnUpOrDownKeyPressed(int count) override { up_or_down_count_ = count; } - - int up_or_down_count() const { return up_or_down_count_; } - - void set_up_or_down_count(int count) { - up_or_down_count_ = count; - } - - private: - int up_or_down_count_; - - DISALLOW_COPY_AND_ASSIGN(MockOmniboxEditModel); -}; - -class MockOmniboxPopupView : public OmniboxPopupView { - public: - MockOmniboxPopupView() : is_open_(false) {} - ~MockOmniboxPopupView() override {} - - // Overridden from OmniboxPopupView: - bool IsOpen() const override { return is_open_; } - void InvalidateLine(size_t line) override {} - void OnLineSelected(size_t line) override {} - void UpdatePopupAppearance() override {} - void OnMatchIconUpdated(size_t match_index) override {} - void PaintUpdatesNow() override {} - void OnDragCanceled() override {} - - void set_is_open(bool is_open) { is_open_ = is_open; } - - private: - bool is_open_; - - DISALLOW_COPY_AND_ASSIGN(MockOmniboxPopupView); -}; - -class TestingToolbarModelDelegate : public ChromeToolbarModelDelegate { - public: - TestingToolbarModelDelegate() {} - ~TestingToolbarModelDelegate() override {} - - // Overridden from ChromeToolbarModelDelegate: - content::WebContents* GetActiveWebContents() const override { return NULL; } - - private: - DISALLOW_COPY_AND_ASSIGN(TestingToolbarModelDelegate); -}; - -class TestingOmniboxEditController : public ChromeOmniboxEditController { - public: - explicit TestingOmniboxEditController(ToolbarModel* toolbar_model) - : ChromeOmniboxEditController(NULL), toolbar_model_(toolbar_model) {} - ~TestingOmniboxEditController() override {} - - protected: - // Overridden from ChromeOmniboxEditController: - void UpdateWithoutTabRestore() override {} - void OnChanged() override {} - ToolbarModel* GetToolbarModel() override { return toolbar_model_; } - const ToolbarModel* GetToolbarModel() const override { - return toolbar_model_; - } - content::WebContents* GetWebContents() override { return nullptr; } - - private: - ToolbarModel* toolbar_model_; - - DISALLOW_COPY_AND_ASSIGN(TestingOmniboxEditController); -}; - -} // namespace - -class OmniboxViewMacTest : public CocoaProfileTest { - public: - void SetModel(OmniboxViewMac* view, OmniboxEditModel* model) { - view->model_.reset(model); - } -}; - -TEST_F(OmniboxViewMacTest, GetFonts) { - EXPECT_TRUE(OmniboxViewMac::GetNormalFieldFont()); - EXPECT_TRUE(OmniboxViewMac::GetBoldFieldFont()); - EXPECT_TRUE(OmniboxViewMac::GetLargeFont()); - EXPECT_TRUE(OmniboxViewMac::GetSmallFont()); -} - -TEST_F(OmniboxViewMacTest, TabToAutocomplete) { - OmniboxViewMac view(NULL, profile(), NULL, NULL); - - // This is deleted by the omnibox view. - MockOmniboxEditModel* model = - new MockOmniboxEditModel(&view, NULL, profile()); - SetModel(&view, model); - - MockOmniboxPopupView popup_view; - OmniboxPopupModel popup_model(&popup_view, model); - - // With popup closed verify that tab doesn't autocomplete. - popup_view.set_is_open(false); - view.OnDoCommandBySelector(@selector(insertTab:)); - EXPECT_EQ(0, model->up_or_down_count()); - view.OnDoCommandBySelector(@selector(insertBacktab:)); - EXPECT_EQ(0, model->up_or_down_count()); - - // With popup open verify that tab does autocomplete. - popup_view.set_is_open(true); - view.OnDoCommandBySelector(@selector(insertTab:)); - EXPECT_EQ(1, model->up_or_down_count()); - view.OnDoCommandBySelector(@selector(insertBacktab:)); - EXPECT_EQ(-1, model->up_or_down_count()); -} - -TEST_F(OmniboxViewMacTest, UpDownArrow) { - OmniboxViewMac view(NULL, profile(), NULL, NULL); - - // This is deleted by the omnibox view. - MockOmniboxEditModel* model = - new MockOmniboxEditModel(&view, NULL, profile()); - SetModel(&view, model); - - MockOmniboxPopupView popup_view; - OmniboxPopupModel popup_model(&popup_view, model); - - // With popup closed verify that pressing up and down arrow works. - popup_view.set_is_open(false); - model->set_up_or_down_count(0); - view.OnDoCommandBySelector(@selector(moveDown:)); - EXPECT_EQ(1, model->up_or_down_count()); - model->set_up_or_down_count(0); - view.OnDoCommandBySelector(@selector(moveUp:)); - EXPECT_EQ(-1, model->up_or_down_count()); - - // With popup open verify that pressing up and down arrow works. - popup_view.set_is_open(true); - model->set_up_or_down_count(0); - view.OnDoCommandBySelector(@selector(moveDown:)); - EXPECT_EQ(1, model->up_or_down_count()); - model->set_up_or_down_count(0); - view.OnDoCommandBySelector(@selector(moveUp:)); - EXPECT_EQ(-1, model->up_or_down_count()); -} - -TEST_F(OmniboxViewMacTest, WritingDirectionLTR) { - TestingToolbarModelDelegate delegate; - ToolbarModelImpl toolbar_model(&delegate, 32 * 1024); - TestingOmniboxEditController edit_controller(&toolbar_model); - OmniboxViewMac view(&edit_controller, profile(), NULL, NULL); - - // This is deleted by the omnibox view. - MockOmniboxEditModel* model = - new MockOmniboxEditModel(&view, &edit_controller, profile()); - MockOmniboxPopupView popup_view; - OmniboxPopupModel popup_model(&popup_view, model); - - model->OnSetFocus(true); - SetModel(&view, model); - view.SetUserText(base::ASCIIToUTF16("foo.com")); - model->OnChanged(); - - base::scoped_nsobject<NSMutableAttributedString> string( - [[NSMutableAttributedString alloc] initWithString:@"foo.com"]); - view.ApplyTextStyle(string); - - NSParagraphStyle* paragraphStyle = - [string attribute:NSParagraphStyleAttributeName - atIndex:0 - effectiveRange:NULL]; - DCHECK(paragraphStyle); - EXPECT_EQ(paragraphStyle.alignment, NSLeftTextAlignment); - EXPECT_EQ(paragraphStyle.baseWritingDirection, NSWritingDirectionLeftToRight); -} - -TEST_F(OmniboxViewMacTest, WritingDirectionRTL) { - cocoa_l10n_util::ScopedForceRTLMac rtl; - - TestingToolbarModelDelegate delegate; - ToolbarModelImpl toolbar_model(&delegate, 32 * 1024); - TestingOmniboxEditController edit_controller(&toolbar_model); - OmniboxViewMac view(&edit_controller, profile(), NULL, NULL); - - // This is deleted by the omnibox view. - MockOmniboxEditModel* model = - new MockOmniboxEditModel(&view, &edit_controller, profile()); - MockOmniboxPopupView popup_view; - OmniboxPopupModel popup_model(&popup_view, model); - - model->OnSetFocus(true); - SetModel(&view, model); - view.SetUserText(base::ASCIIToUTF16("foo.com")); - model->OnChanged(); - - base::scoped_nsobject<NSMutableAttributedString> string( - [[NSMutableAttributedString alloc] initWithString:@"foo.com"]); - view.ApplyTextStyle(string); - - NSParagraphStyle* paragraphStyle = - [string attribute:NSParagraphStyleAttributeName - atIndex:0 - effectiveRange:NULL]; - DCHECK(paragraphStyle); - EXPECT_EQ(paragraphStyle.alignment, NSRightTextAlignment); - EXPECT_EQ(paragraphStyle.baseWritingDirection, NSWritingDirectionLeftToRight); -}
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm index 7736dcc..f62a9ad7 100644 --- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm +++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm
@@ -15,7 +15,6 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_window.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h"
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm index 70c5e81..a73ad31 100644 --- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm +++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm
@@ -10,7 +10,6 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/cocoa/browser_window_cocoa.h" #include "chrome/browser/ui/cocoa/browser_window_controller.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.h b/chrome/browser/ui/cocoa/status_bubble_mac.h deleted file mode 100644 index 8c03a306..0000000 --- a/chrome/browser/ui/cocoa/status_bubble_mac.h +++ /dev/null
@@ -1,210 +0,0 @@ -// Copyright (c) 2011 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_COCOA_STATUS_BUBBLE_MAC_H_ -#define CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_ - -#include <string> - -#import <Cocoa/Cocoa.h> -#import <QuartzCore/QuartzCore.h> -#include <stdint.h> - -#include "base/compiler_specific.h" -#include "base/mac/scoped_nsobject.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/strings/string16.h" -#include "chrome/browser/ui/status_bubble.h" -#include "url/gurl.h" - -namespace gfx { -class Point; -} - -class StatusBubbleMacTest; -@class StatusBubbleWindow; - -class StatusBubbleMac : public StatusBubble { - public: - // The various states that a status bubble may be in. Public for delegate - // access (for testing). - enum StatusBubbleState { - kBubbleHidden, // Fully hidden - kBubbleShowingTimer, // Waiting to fade in - kBubbleShowingFadeIn, // In a fade-in transition - kBubbleShown, // Fully visible - kBubbleHidingTimer, // Waiting to fade out - kBubbleHidingFadeOut // In a fade-out transition - }; - - StatusBubbleMac(NSWindow* parent, id delegate); - ~StatusBubbleMac() override; - - // StatusBubble implementation. - void SetStatus(const base::string16& status) override; - void SetURL(const GURL& url) override; - void Hide() override; - void MouseMoved(bool left_content) override; - void UpdateDownloadShelfVisibility(bool visible) override; - - // Mac-specific method: Update the size and position of the status bubble to - // match the parent window. Safe to call even when the status bubble does not - // exist. - void UpdateSizeAndPosition(); - - // Mac-specific method: Change the parent window of the status bubble. Safe to - // call even when the status bubble does not exist. - void SwitchParentWindow(NSWindow* parent); - - // Expand the bubble to fit a URL too long for the standard bubble size. - void ExpandBubble(); - - protected: - // Get the current location of the mouse. Protected so that it can be - // stubbed out for testing. - virtual gfx::Point GetMouseLocation(); - - // Notify mouse events with current mouse location. The location is (0,0) when - // mouse is at the bottom-left of the screen. - void MouseMovedAt(const gfx::Point& location, bool left_content); - - private: - friend class StatusBubbleMacTest; - - // Setter for state_. Use this instead of writing to state_ directly so - // that state changes can be observed by unit tests. - void SetState(StatusBubbleState state); - - // Sets the bubble text for SetStatus and SetURL. - void SetText(const base::string16& text, bool is_url); - - // Construct the window/widget if it does not already exist. (Safe to call if - // it does.) - void Create(); - - // Attaches the status bubble window to its parent window. Safe to call even - // when already attached. - void Attach(); - - // Detaches the status bubble window from its parent window. - void Detach(); - - // Is the status bubble attached to the browser window? It should be attached - // when shown and during any fades, but should be detached when hidden. - bool is_attached(); - - // Begins fading the status bubble window in or out depending on the value - // of |show|. This must be called from the appropriate fade state, - // kBubbleShowingFadeIn or kBubbleHidingFadeOut, or from the appropriate - // fully-shown/hidden state, kBubbleShown or kBubbleHidden. This may be - // called at any point during a fade-in or fade-out; it is even possible to - // reverse a transition before it has completed. - void Fade(bool show); - - // Starts an animation of the bubble window to a specific alpha value over a - // specific period of time. - void AnimateWindowAlpha(CGFloat alpha, NSTimeInterval duration); - - // Method called from the completion callbacks when a fade-in or fade-out - // transition has completed. - void AnimationDidStop(); - - // One-shot timer operations to manage the delays associated with the - // kBubbleShowingTimer and kBubbleHidingTimer states. StartTimer and - // TimerFired must be called from one of these states. StartTimer may be - // called while the timer is still running; in that case, the timer will be - // reset. CancelTimer may be called from any state. - void StartTimer(int64_t time_ms); - void CancelTimer(); - void TimerFired(); - - // Begin the process of showing or hiding the status bubble. These may be - // called from any state, and will take the appropriate action to initiate - // any state changes that may be needed. - void StartShowing(); - void StartHiding(); - - // Cancel the expansion timer. - void CancelExpandTimer(); - - // Sets the frame of the status bubble window to |window_frame|, adjusting - // for the given mouse position if necessary. Protected for use in tests. - void SetFrameAvoidingMouse(NSRect window_frame, const gfx::Point& mouse_pos); - - // Calculate the appropriate frame for the status bubble window. If - // |expanded_width|, use entire width of parent frame. - NSRect CalculateWindowFrame(bool expanded_width); - - // Returns the flags to be used to round the corners of the status bubble. - // Before 10.7, windows have square bottom corners, but in 10.7, the bottom - // corners are rounded. This method considers the bubble's placement (as - // proposed in window_frame) relative to its parent window in determining - // which flags to return. This function may choose to round any corner, - // including top corners. Note that there may be other reasons that a - // status bubble's corner may be rounded in addition to those dependent on - // OS version, and flags will be set or unset elsewhere to address these - // concerns. - unsigned long OSDependentCornerFlags(NSRect window_frame); - - // Returns the status bubble window as an NSWindow. For use in tests. - NSWindow* GetWindow(); - - // The window we attach ourselves to. - NSWindow* parent_; // WEAK - - // The object that we query about our vertical offset for positioning. - id delegate_; // WEAK - - // The window we own. - base::scoped_nsobject<StatusBubbleWindow> window_; - - // The status text we want to display when there are no URLs to display. - NSString* status_text_; - - // The url we want to display when there is no status text to display. - NSString* url_text_; - - // The status bubble's current state. Do not write to this field directly; - // use SetState(). - StatusBubbleState state_; - - // True if operations are to be performed immediately rather than waiting - // for delays and transitions. Normally false, this should only be set to - // true for testing. - bool immediate_; - - // True if the status bubble has been expanded. If the bubble is in the - // expanded state and encounters a new URL, change size immediately, - // with no hover delay. - bool is_expanded_; - - // The original, non-elided URL. - GURL url_; - - // The factory used to generate weak pointers for the show and hide delay - // timers. - base::WeakPtrFactory<StatusBubbleMac> timer_factory_; - - // The factory used to generate weak pointers for the expansion delay timer. - base::WeakPtrFactory<StatusBubbleMac> expand_timer_factory_; - - // The factory used to generate weak pointers for the CAAnimation completion - // handlers. - base::WeakPtrFactory<StatusBubbleMac> completion_handler_factory_; - - DISALLOW_COPY_AND_ASSIGN(StatusBubbleMac); -}; - -// Delegate interface -@interface NSObject(StatusBubbleDelegate) -// Called to query the delegate about the frame StatusBubble should position -// itself in. Frame is returned in the parent window coordinates. -- (NSRect)statusBubbleBaseFrame; - -// Called from SetState to notify the delegate of state changes. -- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state; -@end - -#endif // CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.mm b/chrome/browser/ui/cocoa/status_bubble_mac.mm deleted file mode 100644 index a519186d..0000000 --- a/chrome/browser/ui/cocoa/status_bubble_mac.mm +++ /dev/null
@@ -1,800 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/cocoa/status_bubble_mac.h" - -#include <limits> - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/debug/stack_trace.h" -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_block.h" -#include "base/mac/sdk_forward_declarations.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_task_runner_handle.h" -#import "chrome/browser/ui/cocoa/bubble_view.h" -#include "chrome/browser/ui/cocoa/cocoa_util.h" -#include "components/url_formatter/elide_url.h" -#include "components/url_formatter/url_formatter.h" -#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h" -#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSBezierPath+RoundRect.h" -#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSColor+Luminance.h" -#include "ui/base/cocoa/cocoa_base_utils.h" -#include "ui/base/cocoa/window_size_constants.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/platform_font.h" -#include "ui/gfx/text_elider.h" -#include "ui/gfx/text_utils.h" - -namespace { - -const int kStatusBubbleWindowHeight = 18; - -// The width of the bubble in relation to the width of the parent window. -const CGFloat kStatusBubbleWindowWidthPercent = 1.0 / 3.0; - -// How close the mouse can get to the infobubble before it starts sliding -// off-screen. -const int kMousePadding = 20; - -const int kTextPadding = 3; - -// The status bubble's maximum opacity, when fully faded in. -const CGFloat kBubbleOpacity = 1.0; - -// Delay before showing or hiding the bubble after a SetStatus or SetURL call. -const int64_t kShowDelayMS = 80; -const int64_t kHideDelayMS = 250; - -// How long each fade should last. -const NSTimeInterval kShowFadeInDurationSeconds = 0.120; -const NSTimeInterval kHideFadeOutDurationSeconds = 0.200; - -// How quickly the status bubble should expand. -const CGFloat kExpansionDurationSeconds = 0.125; - -} // namespace - -// StatusBubbleWindow becomes a child of |statusBubbleParentWindow|, but waits -// until |statusBubbleParentWindow| is visible. This works around macOS -// bugs/features which make unexpected things happen when adding a child window -// to a window that's in another space, miniaturized, or hidden -// (https://crbug.com/783521, https://crbug.com/798792). -@interface StatusBubbleWindow : NSWindow - -// The window which this window should become a child of. May be changed or -// nilled out at any time. -@property(assign, nonatomic) NSWindow* statusBubbleParentWindow; - -@end - -@implementation StatusBubbleWindow { - BOOL observingParentWindowVisibility_; -} -@synthesize statusBubbleParentWindow = statusBubbleParentWindow_; - -- (void)dealloc { - // StatusBubbleMac is expected to always clear statusBubbleParentWindow - // before releasing StatusBubbleWindow. If that changes, it's OK to remove - // this DCHECK as long as StatusBubbleWindow will never outlive its parent. - DCHECK(!statusBubbleParentWindow_); - - [self stopObserving]; - [super dealloc]; -} - -- (void)setStatusBubbleParentWindow:(NSWindow*)statusBubbleParentWindow { - if (statusBubbleParentWindow_ == statusBubbleParentWindow) - return; - - // First, detach from the current parent window, if any. - if (statusBubbleParentWindow_) { - [self stopObserving]; - [self orderOut:nil]; // Also removes |self| from its parent window. - } - - // Assign the new parent window. - statusBubbleParentWindow_ = statusBubbleParentWindow; - - if (statusBubbleParentWindow_) { - // Attach to the new parent window if it's visible and on the active space. - [self maybeAttach]; - - if (!self.parentWindow) { - // If maybeAttach bailed, start observing the window's visibility and the - // active space, and try again when they change. - observingParentWindowVisibility_ = YES; - [statusBubbleParentWindow_ addObserver:self - forKeyPath:@"visible" - options:0 - context:nil]; - [[NSWorkspace sharedWorkspace].notificationCenter - addObserver:self - selector:@selector(maybeAttach) - name:NSWorkspaceActiveSpaceDidChangeNotification - object:[NSWorkspace sharedWorkspace]]; - } - } -} - -- (void)stopObserving { - if (!observingParentWindowVisibility_) - return; - observingParentWindowVisibility_ = NO; - [statusBubbleParentWindow_ removeObserver:self - forKeyPath:@"visible" - context:nil]; - [[NSWorkspace sharedWorkspace].notificationCenter removeObserver:self]; -} - -- (void)maybeAttach { - if (![statusBubbleParentWindow_ isVisible]) - return; - if (![statusBubbleParentWindow_ isOnActiveSpace]) - return; - [self stopObserving]; - // Adding |self| as a child window also orders it in. - [statusBubbleParentWindow_ addChildWindow:self ordered:NSWindowAbove]; -} - -- (void)observeValueForKeyPath:(NSString*)keyPath - ofObject:(id)object - change:(NSDictionary<NSKeyValueChangeKey, id>*)change - context:(void*)context { - [self maybeAttach]; -} - -@end - -StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate) - : parent_(parent), - delegate_(delegate), - status_text_(nil), - url_text_(nil), - state_(kBubbleHidden), - immediate_(false), - is_expanded_(false), - timer_factory_(this), - expand_timer_factory_(this), - completion_handler_factory_(this) { - Create(); -} - -StatusBubbleMac::~StatusBubbleMac() { - DCHECK(window_); - - Hide(); - - completion_handler_factory_.InvalidateWeakPtrs(); - Detach(); -} - -void StatusBubbleMac::SetStatus(const base::string16& status) { - SetText(status, false); -} - -void StatusBubbleMac::SetURL(const GURL& url) { - url_ = url; - - CGFloat bubble_width = NSWidth([window_ frame]); - if (state_ == kBubbleHidden) - bubble_width = NSWidth(CalculateWindowFrame(/*expand=*/false)); - int text_width = static_cast<int>(bubble_width - - kBubbleViewTextPositionX - - kTextPadding); - - // Scale from view to window coordinates before eliding URL string. - NSSize scaled_width = NSMakeSize(text_width, 0); - scaled_width = [[parent_ contentView] convertSize:scaled_width fromView:nil]; - text_width = static_cast<int>(scaled_width.width); - NSFont* font = [[window_ contentView] font]; - gfx::FontList font_list_chr( - gfx::Font(gfx::PlatformFont::CreateFromNativeFont(font))); - - base::string16 original_url_text = url_formatter::FormatUrl(url); - base::string16 status = url_formatter::ElideUrl( - url, font_list_chr, text_width, gfx::Typesetter::BROWSER); - - SetText(status, true); - - // In testing, don't use animation. When ExpandBubble is tested, it is - // called explicitly. - if (immediate_) - return; - else - CancelExpandTimer(); - - // If the bubble has been expanded, the user has already hovered over a link - // to trigger the expanded state. Don't wait to change the bubble in this - // case -- immediately expand or contract to fit the URL. - if (is_expanded_ && !url.is_empty()) { - ExpandBubble(); - } else if (original_url_text.length() > status.length()) { - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::Bind(&StatusBubbleMac::ExpandBubble, - expand_timer_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(kExpandHoverDelayMS)); - } -} - -void StatusBubbleMac::SetText(const base::string16& text, bool is_url) { - // The status bubble allows the status and URL strings to be set - // independently. Whichever was set non-empty most recently will be the - // value displayed. When both are empty, the status bubble hides. - - NSString* text_ns = base::SysUTF16ToNSString(text); - - NSString** main; - NSString** backup; - - if (is_url) { - main = &url_text_; - backup = &status_text_; - } else { - main = &status_text_; - backup = &url_text_; - } - - // Don't return from this function early. It's important to make sure that - // all calls to StartShowing and StartHiding are made, so that all delays - // are observed properly. Specifically, if the state is currently - // kBubbleShowingTimer, the timer will need to be restarted even if - // [text_ns isEqualToString:*main] is true. - - [*main autorelease]; - *main = [text_ns retain]; - - bool show = true; - if ([*main length] > 0) - [[window_ contentView] setContent:*main]; - else if ([*backup length] > 0) - [[window_ contentView] setContent:*backup]; - else - show = false; - - if (show) { - // Call StartShowing() first to update the current bubble state before - // calculating a new size. - StartShowing(); - UpdateSizeAndPosition(); - } else { - StartHiding(); - } -} - -void StatusBubbleMac::Hide() { - CancelTimer(); - CancelExpandTimer(); - is_expanded_ = false; - - bool fade_out = false; - if (state_ == kBubbleHidingFadeOut || state_ == kBubbleShowingFadeIn) { - SetState(kBubbleHidingFadeOut); - - if (!immediate_) { - // An animation is in progress. Cancel it by starting a new animation. - // Use cocoa_util::kMinimumTimeInterval to set the opacity as rapidly as - // possible. - fade_out = true; - AnimateWindowAlpha(0.0, cocoa_util::kMinimumTimeInterval); - } - } - - NSRect frame = CalculateWindowFrame(/*expand=*/false); - if (!fade_out) { - // No animation is in progress, so the opacity can be set directly. - [window_ setAlphaValue:0.0]; - SetState(kBubbleHidden); - frame.size = ui::kWindowSizeDeterminedLater.size; - } - - // Stop any width animation and reset the bubble size. - if (!immediate_) { - [NSAnimationContext beginGrouping]; - [[NSAnimationContext currentContext] - setDuration:cocoa_util::kMinimumTimeInterval]; - [[window_ animator] setFrame:frame display:NO]; - [NSAnimationContext endGrouping]; - } else { - [window_ setFrame:frame display:NO]; - } - - [status_text_ release]; - status_text_ = nil; - [url_text_ release]; - url_text_ = nil; -} - -void StatusBubbleMac::SetFrameAvoidingMouse( - NSRect window_frame, const gfx::Point& mouse_pos) { - if (!window_) - return; - - // Bubble's base rect in |parent_| (window base) coordinates. - NSRect base_rect; - if ([delegate_ respondsToSelector:@selector(statusBubbleBaseFrame)]) { - base_rect = [delegate_ statusBubbleBaseFrame]; - } else { - base_rect = [[parent_ contentView] bounds]; - base_rect = [[parent_ contentView] convertRect:base_rect toView:nil]; - } - - // To start, assume default positioning in the lower left corner. - // The window_frame position is in global (screen) coordinates. - window_frame.origin = - ui::ConvertPointFromWindowToScreen(parent_, base_rect.origin); - - // Get the cursor position relative to the top right corner of the bubble. - gfx::Point relative_pos(mouse_pos.x() - NSMaxX(window_frame), - mouse_pos.y() - NSMaxY(window_frame)); - - // If the mouse is in a position where we think it would move the - // status bubble, figure out where and how the bubble should be moved, and - // what sorts of corners it should have. - unsigned long corner_flags; - if (relative_pos.y() < kMousePadding && - relative_pos.x() < kMousePadding) { - int offset = kMousePadding - relative_pos.y(); - - // Make the movement non-linear. - offset = offset * offset / kMousePadding; - - // When the mouse is entering from the right, we want the offset to be - // scaled by how horizontally far away the cursor is from the bubble. - if (relative_pos.x() > 0) { - offset *= (kMousePadding - relative_pos.x()) / kMousePadding; - } - - bool is_on_screen = true; - NSScreen* screen = [window_ screen]; - if (screen && - NSMinY([screen visibleFrame]) > NSMinY(window_frame) - offset) { - is_on_screen = false; - } - - // If something is shown below tab contents (devtools, download shelf etc.), - // adjust the position to sit on top of it. - bool is_any_shelf_visible = NSMinY(base_rect) > 0; - - if (is_on_screen && !is_any_shelf_visible) { - // Cap the offset and change the visual presentation of the bubble - // depending on where it ends up (so that rounded corners square off - // and mate to the edges of the tab content). - if (offset >= NSHeight(window_frame)) { - offset = NSHeight(window_frame); - corner_flags = kRoundedBottomLeftCorner | kRoundedBottomRightCorner; - } else if (offset > 0) { - corner_flags = kRoundedTopRightCorner | - kRoundedBottomLeftCorner | - kRoundedBottomRightCorner; - } else { - corner_flags = kRoundedTopRightCorner; - } - - // Place the bubble on the left, but slightly lower. - window_frame.origin.y -= offset; - } else { - // Cannot move the bubble down without obscuring other content. - // Move it to the far right instead. - corner_flags = kRoundedTopLeftCorner; - window_frame.origin.x += NSWidth(base_rect) - NSWidth(window_frame); - } - } else { - // Use the default position in the lower left corner of the content area. - corner_flags = kRoundedTopRightCorner; - } - - corner_flags |= OSDependentCornerFlags(window_frame); - - BubbleView* contentView = - base::mac::ObjCCast<BubbleView>([window_ contentView]); - [contentView setCornerFlags:corner_flags]; - [window_ setFrame:window_frame display:YES]; -} - -void StatusBubbleMac::MouseMoved(bool left_content) { - MouseMovedAt(gfx::Point([NSEvent mouseLocation]), left_content); -} - -void StatusBubbleMac::MouseMovedAt( - const gfx::Point& location, bool left_content) { - if (!left_content) - SetFrameAvoidingMouse([window_ frame], location); -} - -void StatusBubbleMac::UpdateDownloadShelfVisibility(bool visible) { - UpdateSizeAndPosition(); -} - -void StatusBubbleMac::Create() { - DCHECK(!window_); - - window_.reset([[StatusBubbleWindow alloc] - initWithContentRect:ui::kWindowSizeDeterminedLater - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]); - [window_ setCollectionBehavior:[window_ collectionBehavior] | - NSWindowCollectionBehaviorTransient]; - [window_ setMovableByWindowBackground:NO]; - [window_ setBackgroundColor:[NSColor clearColor]]; - [window_ setOpaque:NO]; - [window_ setHasShadow:NO]; - - base::scoped_nsobject<BubbleView> view( - [[BubbleView alloc] initWithFrame:NSZeroRect]); - [window_ setContentView:view]; - - [window_ setAlphaValue:0.0]; - - // TODO(dtseng): Ignore until we provide NSAccessibility support. - [window_ accessibilitySetOverrideValue:NSAccessibilityUnknownRole - forAttribute:NSAccessibilityRoleAttribute]; - - [view setCornerFlags:kRoundedTopRightCorner]; - MouseMovedAt(gfx::Point(), false); -} - -void StatusBubbleMac::Attach() { - if (is_attached()) - return; - [window_ setStatusBubbleParentWindow:parent_]; - [[window_ contentView] setThemeProvider:parent_]; -} - -void StatusBubbleMac::Detach() { - if (!is_attached()) - return; - - // Magic setFrame: See http://crbug.com/58506 and http://crrev.com/3564021 . - // TODO(rohitrao): Does the frame size actually matter here? Can we always - // set it to kWindowSizeDeterminedLater? - NSRect frame = [window_ frame]; - frame.size = ui::kWindowSizeDeterminedLater.size; - if (state_ != kBubbleHidden) { - frame = CalculateWindowFrame(/*expand=*/false); - } - // See https://crbug.com/28107 and https://crbug.com/29054. - [window_ setFrame:frame display:NO]; - [window_ setStatusBubbleParentWindow:nil]; - - [[window_ contentView] setThemeProvider:nil]; -} - -bool StatusBubbleMac::is_attached() { - return [window_ statusBubbleParentWindow] != nil; -} - -void StatusBubbleMac::AnimationDidStop() { - DCHECK([NSThread isMainThread]); - DCHECK(state_ == kBubbleShowingFadeIn || state_ == kBubbleHidingFadeOut); - DCHECK(is_attached()); - - if (state_ == kBubbleShowingFadeIn) { - DCHECK_EQ([[window_ animator] alphaValue], kBubbleOpacity); - SetState(kBubbleShown); - } else { - DCHECK_EQ([[window_ animator] alphaValue], 0.0); - SetState(kBubbleHidden); - } -} - -void StatusBubbleMac::SetState(StatusBubbleState state) { - if (state == state_) - return; - - if (state == kBubbleHidden) { - is_expanded_ = false; - Detach(); - } else { - Attach(); - } - - if ([delegate_ respondsToSelector:@selector(statusBubbleWillEnterState:)]) - [delegate_ statusBubbleWillEnterState:state]; - - state_ = state; -} - -void StatusBubbleMac::Fade(bool show) { - DCHECK([NSThread isMainThread]); - - StatusBubbleState fade_state = kBubbleShowingFadeIn; - StatusBubbleState target_state = kBubbleShown; - NSTimeInterval full_duration = kShowFadeInDurationSeconds; - CGFloat opacity = kBubbleOpacity; - - if (!show) { - fade_state = kBubbleHidingFadeOut; - target_state = kBubbleHidden; - full_duration = kHideFadeOutDurationSeconds; - opacity = 0.0; - } - - DCHECK(state_ == fade_state || state_ == target_state); - - if (state_ == target_state) - return; - - if (immediate_) { - [window_ setAlphaValue:opacity]; - SetState(target_state); - return; - } - - // If an incomplete transition has left the opacity somewhere between 0 and - // kBubbleOpacity, the fade rate is kept constant by shortening the duration. - NSTimeInterval duration = - full_duration * - fabs(opacity - [[window_ animator] alphaValue]) / kBubbleOpacity; - - // 0.0 will not cancel an in-progress animation. - if (duration == 0.0) - duration = cocoa_util::kMinimumTimeInterval; - - // Cancel an in-progress transition and replace it with this fade. - AnimateWindowAlpha(opacity, duration); -} - -void StatusBubbleMac::AnimateWindowAlpha(CGFloat alpha, - NSTimeInterval duration) { - completion_handler_factory_.InvalidateWeakPtrs(); - base::WeakPtr<StatusBubbleMac> weak_ptr( - completion_handler_factory_.GetWeakPtr()); - [NSAnimationContext runAnimationGroup:^(NSAnimationContext* context) { - [context setDuration:duration]; - [[window_ animator] setAlphaValue:alpha]; - } - completionHandler:^{ - if (weak_ptr) - weak_ptr->AnimationDidStop(); - }]; -} - -void StatusBubbleMac::StartTimer(int64_t delay_ms) { - DCHECK([NSThread isMainThread]); - DCHECK(state_ == kBubbleShowingTimer || state_ == kBubbleHidingTimer); - - if (immediate_) { - TimerFired(); - return; - } - - // There can only be one running timer. - CancelTimer(); - - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::Bind(&StatusBubbleMac::TimerFired, timer_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(delay_ms)); -} - -void StatusBubbleMac::CancelTimer() { - DCHECK([NSThread isMainThread]); - - if (timer_factory_.HasWeakPtrs()) - timer_factory_.InvalidateWeakPtrs(); -} - -void StatusBubbleMac::TimerFired() { - DCHECK(state_ == kBubbleShowingTimer || state_ == kBubbleHidingTimer); - DCHECK([NSThread isMainThread]); - - if (state_ == kBubbleShowingTimer) { - SetState(kBubbleShowingFadeIn); - Fade(true); - } else { - SetState(kBubbleHidingFadeOut); - Fade(false); - } -} - -void StatusBubbleMac::StartShowing() { - if (state_ == kBubbleHidden) { - // Arrange to begin fading in after a delay. - SetState(kBubbleShowingTimer); - StartTimer(kShowDelayMS); - } else if (state_ == kBubbleHidingFadeOut) { - // Cancel the fade-out in progress and replace it with a fade in. - SetState(kBubbleShowingFadeIn); - Fade(true); - } else if (state_ == kBubbleHidingTimer) { - // The bubble was already shown but was waiting to begin fading out. It's - // given a stay of execution. - SetState(kBubbleShown); - CancelTimer(); - } else if (state_ == kBubbleShowingTimer) { - // The timer was already running but nothing was showing yet. Reaching - // this point means that there is a new request to show something. Start - // over again by resetting the timer, effectively invalidating the earlier - // request. - StartTimer(kShowDelayMS); - } - - // If the state is kBubbleShown or kBubbleShowingFadeIn, leave everything - // alone. -} - -void StatusBubbleMac::StartHiding() { - if (state_ == kBubbleShown) { - // Arrange to begin fading out after a delay. - SetState(kBubbleHidingTimer); - StartTimer(kHideDelayMS); - } else if (state_ == kBubbleShowingFadeIn) { - // Cancel the fade-in in progress and replace it with a fade out. - SetState(kBubbleHidingFadeOut); - Fade(false); - } else if (state_ == kBubbleShowingTimer) { - // The bubble was already hidden but was waiting to begin fading in. Too - // bad, it won't get the opportunity now. - SetState(kBubbleHidden); - CancelTimer(); - } - - // If the state is kBubbleHidden, kBubbleHidingFadeOut, or - // kBubbleHidingTimer, leave everything alone. The timer is not reset as - // with kBubbleShowingTimer in StartShowing() because a subsequent request - // to hide something while one is already in flight does not invalidate the - // earlier request. -} - -void StatusBubbleMac::CancelExpandTimer() { - DCHECK([NSThread isMainThread]); - expand_timer_factory_.InvalidateWeakPtrs(); -} - -// Get the current location of the mouse in screen coordinates. To make this -// class testable, all code should use this method rather than using -// NSEvent mouseLocation directly. -gfx::Point StatusBubbleMac::GetMouseLocation() { - NSPoint p = [NSEvent mouseLocation]; - --p.y; // The docs say the y coord starts at 1 not 0; don't ask why. - return gfx::Point(p.x, p.y); -} - -void StatusBubbleMac::ExpandBubble() { - // Calculate the width available for expanded and standard bubbles. - NSRect window_frame = CalculateWindowFrame(/*expand=*/true); - CGFloat max_bubble_width = NSWidth(window_frame); - CGFloat standard_bubble_width = - NSWidth(CalculateWindowFrame(/*expand=*/false)); - - // Generate the URL string that fits in the expanded bubble. - NSFont* font = [[window_ contentView] font]; - gfx::FontList font_list_chr( - gfx::Font(gfx::PlatformFont::CreateFromNativeFont(font))); - base::string16 expanded_url = url_formatter::ElideUrl( - url_, font_list_chr, max_bubble_width, gfx::Typesetter::BROWSER); - - // Scale width from gfx::Font in view coordinates to window coordinates. - int required_width_for_string = - gfx::GetStringWidth(expanded_url, font_list_chr, - gfx::Typesetter::NATIVE) + - kTextPadding * 2 + kBubbleViewTextPositionX; - NSSize scaled_width = NSMakeSize(required_width_for_string, 0); - scaled_width = [[parent_ contentView] convertSize:scaled_width toView:nil]; - required_width_for_string = scaled_width.width; - - // The expanded width must be at least as wide as the standard width, but no - // wider than the maximum width for its parent frame. - int expanded_bubble_width = - std::max(standard_bubble_width, - std::min(max_bubble_width, - static_cast<CGFloat>(required_width_for_string))); - - SetText(expanded_url, true); - is_expanded_ = true; - window_frame.size.width = expanded_bubble_width; - - // In testing, don't do any animation. - if (immediate_) { - [window_ setFrame:window_frame display:YES]; - return; - } - - NSRect actual_window_frame = [window_ frame]; - // Adjust status bubble origin if bubble was moved to the right. - // TODO(alekseys): fix for RTL. - if (NSMinX(actual_window_frame) > NSMinX(window_frame)) { - actual_window_frame.origin.x = - NSMaxX(actual_window_frame) - NSWidth(window_frame); - } - actual_window_frame.size.width = NSWidth(window_frame); - - // Do not expand if it's going to cover mouse location. - gfx::Point p = GetMouseLocation(); - if (NSPointInRect(NSMakePoint(p.x(), p.y()), actual_window_frame)) - return; - - // Get the current corner flags and see what needs to change based on the - // expansion. - BubbleView* contentView = - base::mac::ObjCCast<BubbleView>([window_ contentView]); - unsigned long corner_flags = [contentView cornerFlags]; - corner_flags |= OSDependentCornerFlags(actual_window_frame); - [contentView setCornerFlags:corner_flags]; - - [NSAnimationContext beginGrouping]; - [[NSAnimationContext currentContext] setDuration:kExpansionDurationSeconds]; - [[window_ animator] setFrame:actual_window_frame display:YES]; - [NSAnimationContext endGrouping]; -} - -void StatusBubbleMac::UpdateSizeAndPosition() { - if (!window_) - return; - - // There is no need to update the size if the bubble is hidden. - if (state_ == kBubbleHidden) - return; - - SetFrameAvoidingMouse(CalculateWindowFrame(/*expand=*/false), - GetMouseLocation()); -} - -void StatusBubbleMac::SwitchParentWindow(NSWindow* parent) { - DCHECK(parent); - Detach(); - parent_ = parent; - Attach(); - UpdateSizeAndPosition(); -} - -NSRect StatusBubbleMac::CalculateWindowFrame(bool expanded_width) { - DCHECK(parent_); - - NSRect screenRect; - if ([delegate_ respondsToSelector:@selector(statusBubbleBaseFrame)]) { - screenRect = [delegate_ statusBubbleBaseFrame]; - screenRect = [parent_ convertRectToScreen:screenRect]; - } else { - screenRect = [parent_ frame]; - } - - NSSize size = NSMakeSize(0, kStatusBubbleWindowHeight); - size = [[parent_ contentView] convertSize:size toView:nil]; - - if (expanded_width) { - size.width = screenRect.size.width; - } else { - size.width = kStatusBubbleWindowWidthPercent * screenRect.size.width; - } - - screenRect.size = size; - return screenRect; -} - -unsigned long StatusBubbleMac::OSDependentCornerFlags(NSRect window_frame) { - unsigned long corner_flags = 0; - - NSRect parent_frame = [parent_ frame]; - - // Round the bottom corners when they're right up against the - // corresponding edge of the parent window, or when below the parent - // window. - if (NSMinY(window_frame) <= NSMinY(parent_frame)) { - if (NSMinX(window_frame) == NSMinX(parent_frame)) { - corner_flags |= kRoundedBottomLeftCorner; - } - - if (NSMaxX(window_frame) == NSMaxX(parent_frame)) { - corner_flags |= kRoundedBottomRightCorner; - } - } - - // Round the top corners when the bubble is below the parent window. - if (NSMinY(window_frame) < NSMinY(parent_frame)) { - corner_flags |= kRoundedTopLeftCorner | kRoundedTopRightCorner; - } - - return corner_flags; -} - -NSWindow* StatusBubbleMac::GetWindow() { - return window_; -}
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm deleted file mode 100644 index b31159f8..0000000 --- a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm +++ /dev/null
@@ -1,699 +0,0 @@ -// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/status_bubble_mac.h" - -#include <Cocoa/Cocoa.h> - -#include <memory> - -#include "base/mac/scoped_nsobject.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/utf_string_conversions.h" -#import "chrome/browser/ui/cocoa/bubble_view.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "testing/gtest/include/gtest/gtest.h" -#import "testing/gtest_mac.h" -#include "testing/platform_test.h" -#import "third_party/ocmock/OCMock/OCMock.h" -#include "ui/gfx/geometry/point.h" -#include "url/gurl.h" - -using base::UTF8ToUTF16; - -// The test delegate records all of the status bubble object's state -// transitions. -@interface StatusBubbleMacTestDelegate : NSObject { - @private - NSWindow* window_; // Weak. - NSPoint baseFrameOffset_; - std::vector<StatusBubbleMac::StatusBubbleState> states_; -} -- (id)initWithWindow:(NSWindow*)window; -- (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset; -- (NSRect)statusBubbleBaseFrame; -- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state; -@end -@implementation StatusBubbleMacTestDelegate -- (id)initWithWindow:(NSWindow*)window { - if ((self = [super init])) { - window_ = window; - baseFrameOffset_ = NSZeroPoint; - } - return self; -} -- (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset { - baseFrameOffset_ = baseFrameOffset; -} -- (NSRect)statusBubbleBaseFrame { - NSView* contentView = [window_ contentView]; - NSRect baseFrame = [contentView convertRect:[contentView frame] toView:nil]; - if (baseFrameOffset_.x > 0 || baseFrameOffset_.y > 0) { - baseFrame = NSOffsetRect(baseFrame, baseFrameOffset_.x, baseFrameOffset_.y); - baseFrame.size.width -= baseFrameOffset_.x; - baseFrame.size.height -= baseFrameOffset_.y; - } - return baseFrame; -} -- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state { - states_.push_back(state); -} -- (std::vector<StatusBubbleMac::StatusBubbleState>*)states { - return &states_; -} -@end - -// This class implements, for testing purposes, a subclass of |StatusBubbleMac| -// whose |MouseMoved()| method does nothing. This lets the tests fake the mouse -// position and avoid being affected by the true mouse position. -class StatusBubbleMacIgnoreMouseMoved : public StatusBubbleMac { - public: - StatusBubbleMacIgnoreMouseMoved(NSWindow* parent, id delegate) - : StatusBubbleMac(parent, delegate), mouseLocation_(0, 0) { - // Set the fake mouse position to the top right of the content area. - NSRect contentBounds = [[parent contentView] bounds]; - mouseLocation_.SetPoint(NSMaxX(contentBounds), NSMaxY(contentBounds)); - } - - void MouseMoved(bool left_content) override {} - - gfx::Point GetMouseLocation() override { return mouseLocation_; } - - void SetMouseLocationForTesting(int x, int y) { - mouseLocation_.SetPoint(x, y); - StatusBubbleMac::MouseMovedAt(gfx::Point(x, y), false); - } - - private: - gfx::Point mouseLocation_; -}; - -class StatusBubbleMacTest : public CocoaTest { - public: - void SetUp() override { - CocoaTest::SetUp(); - CocoaTestHelperWindow* window = test_window(); - EXPECT_TRUE(window); - delegate_.reset( - [[StatusBubbleMacTestDelegate alloc] initWithWindow: window]); - EXPECT_TRUE(delegate_.get()); - bubble_ = new StatusBubbleMacIgnoreMouseMoved(window, delegate_); - EXPECT_TRUE(bubble_); - - // Turn off delays and transitions for test mode. This doesn't just speed - // things along, it's actually required to get StatusBubbleMac to behave - // synchronously, because the tests here don't know how to wait for - // results. This allows these tests to be much more complete with a - // minimal loss of coverage and without any heinous rearchitecting. - bubble_->immediate_ = true; - - EXPECT_TRUE(bubble_->window_); // immediately creates window - } - - void TearDown() override { - // Not using a scoped_ptr because bubble must be deleted before calling - // TearDown to get rid of bubble's window. - delete bubble_; - CocoaTest::TearDown(); - } - - bool IsVisible() { - if (![bubble_->window_ isVisible]) - return false; - return [bubble_->window_ alphaValue] > 0.0; - } - NSString* GetText() { - return bubble_->status_text_; - } - NSString* GetURLText() { - return bubble_->url_text_; - } - NSString* GetBubbleViewText() { - BubbleView* bubbleView = [bubble_->window_ contentView]; - return [bubbleView content]; - } - NSWindow* GetWindow() { return bubble_->GetWindow(); } - NSWindow* parent() { - return bubble_->parent_; - } - StatusBubbleMac::StatusBubbleState GetState() { - return bubble_->state_; - } - void SetState(StatusBubbleMac::StatusBubbleState state) { - bubble_->SetState(state); - } - std::vector<StatusBubbleMac::StatusBubbleState>* States() { - return [delegate_ states]; - } - StatusBubbleMac::StatusBubbleState StateAt(int index) { - return (*States())[index]; - } - - bool IsPointInBubble(int x, int y) { - return NSPointInRect(NSMakePoint(x, y), [GetWindow() frame]); - } - - void SetMouseLocation(int relative_x, int relative_y) { - // Convert to screen coordinates. - NSRect window_frame = [test_window() frame]; - int x = relative_x + window_frame.origin.x; - int y = relative_y + window_frame.origin.y; - - ((StatusBubbleMacIgnoreMouseMoved*) - bubble_)->SetMouseLocationForTesting(x, y); - } - - // Test helper for moving the fake mouse location, and checking that - // the bubble avoids that location. - // For convenience & clarity, coordinates are relative to the main window. - bool CheckAvoidsMouse(int relative_x, int relative_y) { - SetMouseLocation(relative_x, relative_y); - return !IsPointInBubble(relative_x, relative_y); - } - - base::MessageLoop message_loop_; - base::scoped_nsobject<StatusBubbleMacTestDelegate> delegate_; - StatusBubbleMac* bubble_; // Strong. -}; - -TEST_F(StatusBubbleMacTest, SetStatus) { - bubble_->SetStatus(base::string16()); - bubble_->SetStatus(UTF8ToUTF16("This is a test")); - EXPECT_NSEQ(@"This is a test", GetText()); - EXPECT_TRUE(IsVisible()); - - // Set the status to the exact same thing again - bubble_->SetStatus(UTF8ToUTF16("This is a test")); - EXPECT_NSEQ(@"This is a test", GetText()); - - // Hide it - bubble_->SetStatus(base::string16()); - EXPECT_FALSE(IsVisible()); -} - -TEST_F(StatusBubbleMacTest, SetURL) { - bubble_->SetURL(GURL()); - EXPECT_FALSE(IsVisible()); - bubble_->SetURL(GURL("bad url")); - EXPECT_FALSE(IsVisible()); - bubble_->SetURL(GURL("http://")); - EXPECT_FALSE(IsVisible()); - bubble_->SetURL(GURL("about:blank")); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"about:blank", GetURLText()); - bubble_->SetURL(GURL("foopy://")); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"foopy://", GetURLText()); - bubble_->SetURL(GURL("http://www.cnn.com")); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"www.cnn.com", GetURLText()); -} - -// Test hiding bubble that's already hidden. -TEST_F(StatusBubbleMacTest, Hides) { - bubble_->SetStatus(UTF8ToUTF16("Showing")); - EXPECT_TRUE(IsVisible()); - bubble_->Hide(); - EXPECT_FALSE(IsVisible()); - bubble_->Hide(); - EXPECT_FALSE(IsVisible()); -} - -// Test the "main"/"backup" behavior in StatusBubbleMac::SetText(). -TEST_F(StatusBubbleMacTest, SetStatusAndURL) { - EXPECT_FALSE(IsVisible()); - bubble_->SetStatus(UTF8ToUTF16("Status")); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"Status", GetBubbleViewText()); - bubble_->SetURL(GURL("http://www.nytimes.com")); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText()); - bubble_->SetURL(GURL()); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"Status", GetBubbleViewText()); - bubble_->SetStatus(base::string16()); - EXPECT_FALSE(IsVisible()); - bubble_->SetURL(GURL("http://www.nytimes.com")); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText()); - bubble_->SetStatus(UTF8ToUTF16("Status")); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"Status", GetBubbleViewText()); - bubble_->SetStatus(base::string16()); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText()); - bubble_->SetURL(GURL()); - EXPECT_FALSE(IsVisible()); -} - -// Test that the status bubble goes through the correct delay and fade states. -// The delay and fade duration are simulated and not actually experienced -// during the test because StatusBubbleMacTest sets immediate_ mode. -TEST_F(StatusBubbleMacTest, StateTransitions) { - // First, some sanity - - EXPECT_FALSE(IsVisible()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - - States()->clear(); - EXPECT_TRUE(States()->empty()); - - bubble_->SetStatus(base::string16()); - EXPECT_FALSE(IsVisible()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_TRUE(States()->empty()); // no change from initial kBubbleHidden state - - // Next, a few ordinary cases - - // Test StartShowing from kBubbleHidden - bubble_->SetStatus(UTF8ToUTF16("Status")); - EXPECT_TRUE(IsVisible()); - // Check GetState before checking States to make sure that all state - // transitions have been flushed to States. - EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState()); - EXPECT_EQ(3u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleShowingTimer, StateAt(0)); - EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(1)); - EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(2)); - - // Test StartShowing from kBubbleShown with the same message - States()->clear(); - bubble_->SetStatus(UTF8ToUTF16("Status")); - EXPECT_TRUE(IsVisible()); - EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState()); - EXPECT_TRUE(States()->empty()); - - // Test StartShowing from kBubbleShown with a different message - bubble_->SetStatus(UTF8ToUTF16("New Status")); - EXPECT_TRUE(IsVisible()); - EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState()); - EXPECT_TRUE(States()->empty()); - - // Test StartHiding from kBubbleShown - bubble_->SetStatus(base::string16()); - EXPECT_FALSE(IsVisible()); - // Check GetState before checking States to make sure that all state - // transitions have been flushed to States. - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_EQ(3u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidingTimer, StateAt(0)); - EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(1)); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(2)); - - // Test StartHiding from kBubbleHidden - States()->clear(); - bubble_->SetStatus(base::string16()); - EXPECT_FALSE(IsVisible()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_TRUE(States()->empty()); - - // Now, the edge cases - - // Test StartShowing from kBubbleShowingTimer - bubble_->SetStatus(UTF8ToUTF16("Status")); - SetState(StatusBubbleMac::kBubbleShowingTimer); - [GetWindow() setAlphaValue:0.0]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->SetStatus(UTF8ToUTF16("Status")); - EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState()); - EXPECT_EQ(2u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0)); - EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1)); - - // Test StartShowing from kBubbleShowingFadeIn - bubble_->SetStatus(UTF8ToUTF16("Status")); - SetState(StatusBubbleMac::kBubbleShowingFadeIn); - [GetWindow() setAlphaValue:0.5]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->SetStatus(UTF8ToUTF16("Status")); - // The actual state values can't be tested in immediate_ mode because - // the window wasn't actually fading in. Without immediate_ mode, - // expect kBubbleShown. - bubble_->SetStatus(base::string16()); // Go back to a deterministic state. - - // Test StartShowing from kBubbleHidingTimer - bubble_->SetStatus(base::string16()); - SetState(StatusBubbleMac::kBubbleHidingTimer); - [GetWindow() setAlphaValue:1.0]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->SetStatus(UTF8ToUTF16("Status")); - EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState()); - EXPECT_EQ(1u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(0)); - - // Test StartShowing from kBubbleHidingFadeOut - bubble_->SetStatus(base::string16()); - SetState(StatusBubbleMac::kBubbleHidingFadeOut); - [GetWindow() setAlphaValue:0.5]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->SetStatus(UTF8ToUTF16("Status")); - EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState()); - EXPECT_EQ(2u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0)); - EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1)); - - // Test StartHiding from kBubbleShowingTimer - bubble_->SetStatus(UTF8ToUTF16("Status")); - SetState(StatusBubbleMac::kBubbleShowingTimer); - [GetWindow() setAlphaValue:0.0]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->SetStatus(base::string16()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_EQ(1u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0)); - - // Test StartHiding from kBubbleShowingFadeIn - bubble_->SetStatus(UTF8ToUTF16("Status")); - SetState(StatusBubbleMac::kBubbleShowingFadeIn); - [GetWindow() setAlphaValue:0.5]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->SetStatus(base::string16()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_EQ(2u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0)); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1)); - - // Test StartHiding from kBubbleHidingTimer - bubble_->SetStatus(base::string16()); - SetState(StatusBubbleMac::kBubbleHidingTimer); - [GetWindow() setAlphaValue:1.0]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->SetStatus(base::string16()); - // The actual state values can't be tested in immediate_ mode because - // the timer wasn't actually running. Without immediate_ mode, expect - // kBubbleHidingFadeOut and kBubbleHidden. - // Go back to a deterministic state. - bubble_->SetStatus(UTF8ToUTF16("Status")); - - // Test StartHiding from kBubbleHidingFadeOut - bubble_->SetStatus(base::string16()); - SetState(StatusBubbleMac::kBubbleHidingFadeOut); - [GetWindow() setAlphaValue:0.5]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->SetStatus(base::string16()); - // The actual state values can't be tested in immediate_ mode because - // the window wasn't actually fading out. Without immediate_ mode, expect - // kBubbleHidden. - // Go back to a deterministic state. - bubble_->SetStatus(UTF8ToUTF16("Status")); - - // Test Hide from kBubbleHidden - bubble_->SetStatus(base::string16()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->Hide(); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_TRUE(States()->empty()); - - // Test Hide from kBubbleShowingTimer - bubble_->SetStatus(UTF8ToUTF16("Status")); - SetState(StatusBubbleMac::kBubbleShowingTimer); - [GetWindow() setAlphaValue:0.0]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->Hide(); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_EQ(1u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0)); - - // Test Hide from kBubbleShowingFadeIn - bubble_->SetStatus(UTF8ToUTF16("Status")); - SetState(StatusBubbleMac::kBubbleShowingFadeIn); - [GetWindow() setAlphaValue:0.5]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->Hide(); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_EQ(2u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0)); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1)); - - // Test Hide from kBubbleShown - bubble_->SetStatus(UTF8ToUTF16("Status")); - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->Hide(); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_EQ(1u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0)); - - // Test Hide from kBubbleHidingTimer - bubble_->SetStatus(UTF8ToUTF16("Status")); - SetState(StatusBubbleMac::kBubbleHidingTimer); - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->Hide(); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_EQ(1u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0)); - - // Test Hide from kBubbleHidingFadeOut - bubble_->SetStatus(UTF8ToUTF16("Status")); - SetState(StatusBubbleMac::kBubbleHidingFadeOut); - [GetWindow() setAlphaValue:0.5]; - States()->clear(); - EXPECT_TRUE(States()->empty()); - bubble_->Hide(); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState()); - EXPECT_EQ(1u, States()->size()); - EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0)); -} - -TEST_F(StatusBubbleMacTest, Delete) { - NSWindow* window = test_window(); - // Create and delete immediately. - StatusBubbleMac* bubble = new StatusBubbleMac(window, nil); - delete bubble; - - // Create then delete while visible. - bubble = new StatusBubbleMac(window, nil); - bubble->SetStatus(UTF8ToUTF16("showing")); - delete bubble; -} - -TEST_F(StatusBubbleMacTest, UpdateSizeAndPosition) { - // Test |UpdateSizeAndPosition()| when status bubble does not exist (shouldn't - // crash; shouldn't create window). - EXPECT_TRUE(GetWindow()); - bubble_->UpdateSizeAndPosition(); - EXPECT_TRUE(GetWindow()); - - // Create a status bubble (with contents) and call resize (without actually - // resizing); the frame size shouldn't change. - bubble_->SetStatus(UTF8ToUTF16("UpdateSizeAndPosition test")); - ASSERT_TRUE(GetWindow()); - NSRect rect_before = [GetWindow() frame]; - bubble_->UpdateSizeAndPosition(); - NSRect rect_after = [GetWindow() frame]; - EXPECT_NSEQ(rect_before, rect_after); - - // Move the window and call resize; only the origin should change. - NSWindow* window = test_window(); - ASSERT_TRUE(window); - NSRect frame = [window frame]; - rect_before = [GetWindow() frame]; - frame.origin.x += 10.0; // (fairly arbitrary nonzero value) - frame.origin.y += 10.0; // (fairly arbitrary nonzero value) - [window setFrame:frame display:YES]; - bubble_->UpdateSizeAndPosition(); - rect_after = [GetWindow() frame]; - EXPECT_NE(rect_before.origin.x, rect_after.origin.x); - EXPECT_NE(rect_before.origin.y, rect_after.origin.y); - EXPECT_EQ(rect_before.size.width, rect_after.size.width); - EXPECT_EQ(rect_before.size.height, rect_after.size.height); - - // Resize the window (without moving). The origin shouldn't change. The width - // should change (in the current implementation), but not the height. - frame = [window frame]; - rect_before = [GetWindow() frame]; - frame.size.width += 50.0; // (fairly arbitrary nonzero value) - frame.size.height += 50.0; // (fairly arbitrary nonzero value) - [window setFrame:frame display:YES]; - bubble_->UpdateSizeAndPosition(); - rect_after = [GetWindow() frame]; - EXPECT_EQ(rect_before.origin.x, rect_after.origin.x); - EXPECT_EQ(rect_before.origin.y, rect_after.origin.y); - EXPECT_NE(rect_before.size.width, rect_after.size.width); - EXPECT_EQ(rect_before.size.height, rect_after.size.height); -} - -TEST_F(StatusBubbleMacTest, MovingWindowUpdatesPosition) { - NSWindow* window = test_window(); - - // Show the bubble and make sure it has the same origin as |window|. - bubble_->SetStatus(UTF8ToUTF16("Showing")); - NSWindow* child = GetWindow(); - EXPECT_NSEQ([window frame].origin, [child frame].origin); - - // Hide the bubble, move the window, and show it again. - bubble_->Hide(); - NSRect frame = [window frame]; - frame.origin.x += 50; - [window setFrame:frame display:YES]; - bubble_->SetStatus(UTF8ToUTF16("Reshowing")); - - // The bubble should reattach in the correct location. - child = GetWindow(); - EXPECT_NSEQ([window frame].origin, [child frame].origin); -} - -TEST_F(StatusBubbleMacTest, StatuBubbleRespectsBaseFrameLimits) { - NSWindow* window = test_window(); - - // Show the bubble and make sure it has the same origin as |window|. - bubble_->SetStatus(UTF8ToUTF16("Showing")); - NSWindow* child = GetWindow(); - EXPECT_NSEQ([window frame].origin, [child frame].origin); - - // Hide the bubble, change base frame offset, and show it again. - bubble_->Hide(); - - NSPoint baseFrameOffset = NSMakePoint(0, [window frame].size.height / 3); - EXPECT_GT(baseFrameOffset.y, 0); - [delegate_ forceBaseFrameOffset:baseFrameOffset]; - - bubble_->SetStatus(UTF8ToUTF16("Reshowing")); - - // The bubble should reattach in the correct location. - child = GetWindow(); - NSPoint expectedOrigin = [window frame].origin; - expectedOrigin.x += baseFrameOffset.x; - expectedOrigin.y += baseFrameOffset.y; - EXPECT_NSEQ(expectedOrigin, [child frame].origin); -} - -TEST_F(StatusBubbleMacTest, ExpandBubble) { - NSWindow* window = test_window(); - - // The system font changes between OSX 10.9 and OSX 10.10. Use the system - // font from OSX 10.9 for this test. - id mockContentView = - [OCMockObject partialMockForObject:[GetWindow() contentView]]; - [[[mockContentView stub] - andReturn:[NSFont fontWithName:@"Lucida Grande" size:11]] font]; - - ASSERT_TRUE(window); - NSRect window_frame = [window frame]; - window_frame.size.width = 600.0; - [window setFrame:window_frame display:YES]; - - // Check basic expansion - bubble_->SetStatus(UTF8ToUTF16("Showing")); - EXPECT_TRUE(IsVisible()); - bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html")); - EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]); - bubble_->ExpandBubble(); - EXPECT_TRUE(IsVisible()); - EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText()); - bubble_->Hide(); - - // Make sure bubble resets after hide. - bubble_->SetStatus(UTF8ToUTF16("Showing")); - bubble_->SetURL(GURL("http://www.snickersnee.com/pioneer_fishstix.html")); - EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]); - // ...and that it expands again properly. - bubble_->ExpandBubble(); - EXPECT_NSEQ(@"www.snickersnee.com/pioneer_fishstix.html", GetURLText()); - // ...again, again! - bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html")); - bubble_->ExpandBubble(); - EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText()); - bubble_->Hide(); - - window_frame = [window frame]; - window_frame.size.width = 300.0; - [window setFrame:window_frame display:YES]; - - // Very long URL's will be cut off even in the expanded state. - bubble_->SetStatus(UTF8ToUTF16("Showing")); - const char veryLongUrl[] = - "http://www.diewahrscheinlichlaengstepralinederwelt.com/duuuuplo.html"; - bubble_->SetURL(GURL(veryLongUrl)); - EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]); - bubble_->ExpandBubble(); - EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]); -} - -TEST_F(StatusBubbleMacTest, BubbleAvoidsMouse) { - NSWindow* window = test_window(); - - // All coordinates here are relative to the window origin. - - // Initially, the bubble should appear in the bottom left. - bubble_->SetStatus(UTF8ToUTF16("Showing")); - EXPECT_TRUE(IsPointInBubble(0, 0)); - bubble_->Hide(); - - // Check that the bubble doesn't appear in the left corner if the - // mouse is currently located there. - SetMouseLocation(0, 0); - bubble_->SetStatus(UTF8ToUTF16("Showing")); - EXPECT_FALSE(IsPointInBubble(0, 0)); - - // Leave the bubble visible, and try moving the mouse around. - int smallValue = NSHeight([GetWindow() frame]) / 2; - EXPECT_TRUE(CheckAvoidsMouse(0, 0)); - EXPECT_TRUE(CheckAvoidsMouse(smallValue, 0)); - EXPECT_TRUE(CheckAvoidsMouse(0, smallValue)); - EXPECT_TRUE(CheckAvoidsMouse(smallValue, smallValue)); - - // Simulate moving the mouse down from the top of the window. - for (int y = NSHeight([window frame]); y >= 0; y -= smallValue) { - ASSERT_TRUE(CheckAvoidsMouse(smallValue, y)); - } - - // Simulate moving the mouse from left to right. - int windowWidth = NSWidth([window frame]); - for (int x = 0; x < windowWidth; x += smallValue) { - ASSERT_TRUE(CheckAvoidsMouse(x, smallValue)); - } - - // Simulate moving the mouse from right to left. - for (int x = windowWidth; x >= 0; x -= smallValue) { - ASSERT_TRUE(CheckAvoidsMouse(x, smallValue)); - } -} - -TEST_F(StatusBubbleMacTest, ReparentBubble) { - // The second window is borderless, like the window used in fullscreen mode. - base::scoped_nsobject<NSWindow> fullscreenParent( - [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600) - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]); - - // Switch parents with the bubble hidden. - bubble_->SwitchParentWindow(fullscreenParent); - - // Switch back to the original parent with the bubble showing. - bubble_->SetStatus(UTF8ToUTF16("Showing")); - bubble_->SwitchParentWindow(test_window()); -} - -TEST_F(StatusBubbleMacTest, WaitsUntilVisible) { - [test_window() orderOut:nil]; - bubble_->SetStatus(UTF8ToUTF16("Show soon")); - EXPECT_NSEQ(nil, GetWindow().parentWindow); - - [test_window() orderBack:nil]; - EXPECT_NSNE(nil, GetWindow().parentWindow); -} - -TEST_F(StatusBubbleMacTest, WaitsUntilOnActiveSpace) { - test_window().pretendIsOnActiveSpace = NO; - bubble_->SetStatus(UTF8ToUTF16("Show soon")); - EXPECT_NSEQ(nil, GetWindow().parentWindow); - - test_window().pretendIsOnActiveSpace = YES; - EXPECT_NSNE(nil, GetWindow().parentWindow); -}
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h index 54d44c8..27e38c4 100644 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h +++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
@@ -16,8 +16,6 @@ #include "components/prefs/pref_member.h" #import "ui/base/cocoa/tracking_area.h" -@class AutocompleteTextField; -@class AutocompleteTextFieldEditor; @class BackForwardMenuController; class Browser; class CommandUpdater; @@ -53,7 +51,7 @@ IBOutlet ReloadButtonCocoa* reloadButton_; IBOutlet ToolbarButtonCocoa* homeButton_; IBOutlet MenuButton* appMenuButton_; - IBOutlet AutocompleteTextField* locationBar_; + IBOutlet id locationBar_; IBOutlet id browserActionsContainerView_; @private @@ -63,8 +61,6 @@ std::unique_ptr<ToolbarControllerInternal::CommandObserverBridge> commandObserver_; std::unique_ptr<LocationBarViewMac> locationBarView_; - base::scoped_nsobject<AutocompleteTextFieldEditor> - autocompleteTextFieldEditor_; base::scoped_nsobject<BackForwardMenuController> backMenuController_; base::scoped_nsobject<BackForwardMenuController> forwardMenuController_;
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm index 3b471c3d..bb8a778 100644 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm +++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -31,8 +31,6 @@ #include "chrome/browser/ui/cocoa/drag_util.h" #import "chrome/browser/ui/cocoa/image_button_cell.h" #import "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h" #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" #import "chrome/browser/ui/cocoa/menu_button.h" #import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h" @@ -88,9 +86,6 @@ // wide inset. const CGFloat kButtonInset = 2; -// The minimum width of the location bar in pixels. -const CGFloat kMinimumLocationBarWidth = 100.0; - } // namespace @interface ToolbarController() @@ -108,7 +103,6 @@ // Height of the toolbar in pixels when the bookmark bar is closed. - (CGFloat)baseToolbarHeight; - (void)toolbarFrameChanged; -- (void)showLocationBarOnly; - (void)maintainMinimumLocationBarWidth; - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate; - (void)updateAppMenuButtonSeverity:(AppMenuIconController::Severity)severity @@ -350,22 +344,7 @@ [self initCommandStatus:commands_]; [reloadButton_ setCommandUpdater:commands_]; - locationBarView_.reset(new LocationBarViewMac(locationBar_, commands_, - profile_, browser_)); - [locationBar_ setFont:[NSFont systemFontOfSize:14]]; - - // Add the location bar's accessibility views as direct subviews of the - // toolbar. They are logical children of the location bar, but the location - // bar's actual Cocoa control is an NSCell, so it cannot have child views. - // The |locationBarView_| is responsible for positioning the accessibility - // views. - std::vector<NSView*> accessibility_views = - locationBarView_->GetDecorationAccessibilityViews(); - for (const auto& view : accessibility_views) { - [[self toolbarView] addSubview:view - positioned:NSWindowAbove - relativeTo:locationBar_]; - } + locationBarView_.reset(new LocationBarViewMac(commands_, profile_, browser_)); // Register pref observers for the optional home and page/options buttons // and then add them to the toolbar based on those prefs. @@ -491,17 +470,6 @@ [[homeButton_ cell] accessibilitySetOverrideValue:description forAttribute:NSAccessibilityDescriptionAttribute]; - description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_LOCATION); - [[locationBar_ cell] - accessibilitySetOverrideValue:description - forAttribute:NSAccessibilityDescriptionAttribute]; - // Expose Cmd+L shortcut in help for now. - // TODO(aleventhal) Key shortcuts attribute should eventually get - // its own field. Follow what WebKit does for aria-keyshortcuts, see - // https://bugs.webkit.org/show_bug.cgi?id=159215 (WebKit bug). - [[locationBar_ cell] - accessibilitySetOverrideValue:@"\u2318L" // Expose Cmd+L shortcut. - forAttribute:NSAccessibilityHelpAttribute]; description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_APP); [[appMenuButton_ cell] accessibilitySetOverrideValue:description @@ -550,19 +518,13 @@ } - (void)locationBarWasAddedToWindow { - // Allow the |locationBarView_| to update itself to match the browser window - // theme. - locationBarView_->OnAddedToWindow(); } - (BOOL)locationBarHasFocus { - return [autocompleteTextFieldEditor_ window] != nil; + return NO; } - (void)focusLocationBar:(BOOL)selectAll { - if (locationBarView_.get()) { - locationBarView_->FocusLocation(selectAll ? true : false); - } } // Called when the state for a command changes to |enabled|. Update the @@ -594,16 +556,11 @@ } - (void)updateToolbarWithContents:(WebContents*)tab { - locationBarView_->Update(tab); - - [locationBar_ updateMouseTracking]; - BOOL needReloadMenu = chrome::IsDebuggerAttachedToCurrentTab(browser_); [reloadButton_ setMenuEnabled:needReloadMenu]; } - (void)resetTabState:(WebContents*)tab { - locationBarView_->ResetTabState(tab); } - (void)setStarredState:(BOOL)isStarred { @@ -613,7 +570,6 @@ } - (void)zoomChangedForActiveTab:(BOOL)canShowBubble { - locationBarView_->ZoomChangedForActiveTab(canShowBubble); } - (void)setIsLoading:(BOOL)isLoading force:(BOOL)force { @@ -625,37 +581,13 @@ hasToolbar_ = toolbar; - // If there's a toolbar, there must be a location bar. - DCHECK((toolbar && locBar) || !toolbar); - hasLocationBar_ = toolbar ? YES : locBar; + hasLocationBar_ = NO; // Decide whether to hide/show based on whether there's a location bar. - [[self view] setHidden:!hasLocationBar_]; - - // Make location bar not editable when in a pop-up or an app window. - locationBarView_->SetEditable(toolbar); - - // If necessary, resize the location bar and hide the toolbar icons to display - // the toolbar with only the location bar inside it. - if (!hasToolbar_ && hasLocationBar_) - [self showLocationBarOnly]; + [[self view] setHidden:!toolbar]; } - (id)customFieldEditorForObject:(id)obj { - if (obj == locationBar_) { - // Lazily construct Field editor, Cocoa UI code always runs on the - // same thread, so there shoudn't be a race condition here. - if (autocompleteTextFieldEditor_.get() == nil) { - autocompleteTextFieldEditor_.reset( - [[AutocompleteTextFieldEditor alloc] init]); - } - - // This needs to be called every time, otherwise notifications - // aren't sent correctly. - DCHECK(autocompleteTextFieldEditor_.get()); - [autocompleteTextFieldEditor_.get() setFieldEditor:YES]; - return autocompleteTextFieldEditor_.get(); - } return nil; } @@ -676,19 +608,6 @@ if (hide == [homeButton_ isHidden]) return; // Nothing to do, view state matches pref state. - // Always shift the text field by the width of the home button minus one pixel - // since the frame edges of each button are right on top of each other. When - // hiding the button, reverse the direction of the movement (to the left). - CGFloat moveX = [homeButton_ frame].size.width; - // Ensure proper spacing between the home button and the location bar. - moveX += kElementPadding; - if (hide) - moveX *= -1; // Reverse the direction of the move. - CGRect locationBarFrame = [locationBar_ frame]; - locationBarFrame.size.width -= moveX; - if (!cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) - locationBarFrame.origin.x += moveX; - [locationBar_ setFrame:locationBarFrame]; [homeButton_ setHidden:hide]; } @@ -720,66 +639,12 @@ } - (void)maintainMinimumLocationBarWidth { - CGFloat locationBarWidth = NSWidth([locationBar_ frame]); - locationBarAtMinSize_ = locationBarWidth <= kMinimumLocationBarWidth; - if (locationBarAtMinSize_) { - CGFloat dX = kMinimumLocationBarWidth - locationBarWidth; - [self adjustLocationSizeBy:dX animate:NO]; - } } - (void)toolbarFrameChanged { } -// Hide the back, forward, reload, home, and app menu buttons of the toolbar. -// This allows the location bar to occupy the entire width. There is no way to -// undo this operation, and once it is called, no other programmatic changes -// to the toolbar or location bar width should be made. This message is -// invalid if the toolbar is shown or the location bar is hidden. -- (void)showLocationBarOnly { - // -showLocationBarOnly is only ever called once, shortly after - // initialization, so the regular buttons should all be visible. - DCHECK(!hasToolbar_ && hasLocationBar_); - DCHECK(![backButton_ isHidden]); - - // Ensure the location bar fills the toolbar. - NSRect toolbarFrame = [[self view] frame]; - toolbarFrame.size.height = [ToolbarController locationBarHeight]; - [[self view] setFrame:toolbarFrame]; - - [locationBar_ setFrame:NSMakeRect(0, 0, NSWidth([[self view] frame]), - [ToolbarController locationBarHeight])]; - - [backButton_ setHidden:YES]; - [forwardButton_ setHidden:YES]; - [reloadButton_ setHidden:YES]; - [appMenuButton_ setHidden:YES]; - [homeButton_ setHidden:YES]; -} - - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate { - NSRect locationFrame = [locationBar_ frame]; - - CGFloat location_bar_flex = NSWidth(locationFrame) - kMinimumLocationBarWidth; - - [locationBar_ stopAnimation]; - - if (dX == 0) - return; - - if (dX < 0) { - // Clip to the minimum width. Speculative fix for crbug.com/746944. - dX = std::max(dX, -location_bar_flex); - } - // Ensure that the location bar is in its proper place. - locationFrame.size.width += dX; - if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) - locationFrame.origin.x -= dX; - - if (animate) - [locationBar_ animateToFrame:locationFrame]; - else - [locationBar_ setFrame:locationFrame]; } - (NSPoint)bookmarkBubblePoint { @@ -818,8 +683,7 @@ } - (BOOL)isLocationBarFocused { - OmniboxEditModel* model = locationBarView_->GetOmniboxView()->model(); - return model->has_focus(); + return NO; } // (URLDropTargetController protocol)
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc index b647ac7..a61ce08 100644 --- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc +++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
@@ -13,6 +13,7 @@ #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/sessions/chrome_tab_restore_service_client.h" @@ -21,6 +22,7 @@ #include "chrome/browser/sessions/tab_restore_service_factory.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/sync/profile_sync_test_util.h" +#include "chrome/browser/sync/session_sync_service_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/sync/browser_synced_window_delegates_getter.h" @@ -35,11 +37,11 @@ #include "components/sessions/core/persistent_tab_restore_service.h" #include "components/sessions/core/serialized_navigation_entry_test_helper.h" #include "components/sessions/core/session_types.h" -#include "components/sync/base/sync_prefs.h" #include "components/sync/device_info/local_device_info_provider_mock.h" -#include "components/sync/driver/sync_client.h" +#include "components/sync/driver/sync_driver_switches.h" #include "components/sync/model/fake_sync_change_processor.h" #include "components/sync/model/sync_error_factory_mock.h" +#include "components/sync_sessions/session_sync_service.h" #include "components/sync_sessions/sessions_sync_manager.h" #include "components/sync_sessions/synced_session.h" #include "content/public/browser/browser_thread.h" @@ -147,7 +149,9 @@ class RecentTabsSubMenuModelTest : public BrowserWithTestWindowTest { public: - RecentTabsSubMenuModelTest() {} + RecentTabsSubMenuModelTest() { + override_features_.InitAndDisableFeature(switches::kSyncUSSSessions); + } void SetUp() override { // Set up our mock sync service factory before the sync service (and any @@ -159,10 +163,11 @@ BrowserWithTestWindowTest::SetUp(); - sync_prefs_ = std::make_unique<syncer::SyncPrefs>(profile()->GetPrefs()); - mock_sync_service_ = static_cast<browser_sync::ProfileSyncServiceMock*>( ProfileSyncServiceFactory::GetForProfile(profile())); + manager_ = static_cast<sync_sessions::SessionsSyncManager*>( + SessionSyncServiceFactory::GetForProfile(profile()) + ->GetSyncableService()); // Needed because ProfileSyncService::Initialize() is not exercised. mock_sync_service_->SetLocalDeviceInfoProviderForTest( @@ -177,12 +182,10 @@ ON_CALL(*mock_sync_service_, RemoveObserver(_)) .WillByDefault(Invoke(&fake_sync_service_observer_list_, &FakeSyncServiceObserverList::RemoveObserver)); - - manager_ = std::make_unique<sync_sessions::SessionsSyncManager>( - mock_sync_service_->GetSyncClient()->GetSyncSessionsClient(), - sync_prefs_.get(), - base::Bind(&FakeSyncServiceObserverList::NotifyForeignSessionUpdated, - base::Unretained(&fake_sync_service_observer_list_))); + ON_CALL(*mock_sync_service_, NotifyForeignSessionUpdated()) + .WillByDefault( + Invoke(&fake_sync_service_observer_list_, + &FakeSyncServiceObserverList::NotifyForeignSessionUpdated)); manager_->MergeDataAndStartSyncing( syncer::SESSIONS, syncer::SyncDataList(), @@ -192,12 +195,6 @@ new syncer::SyncErrorFactoryMock)); } - void TearDown() override { - manager_.reset(); - sync_prefs_.reset(); - BrowserWithTestWindowTest::TearDown(); - } - void WaitForLoadFromLastSession() { content::RunAllTasksUntilIdle(); } void DisableSync() { @@ -242,7 +239,7 @@ } void RegisterRecentTabs(RecentTabsBuilderTestHelper* helper) { - helper->ExportToSessionsSyncManager(manager_.get()); + helper->ExportToSessionsSyncManager(manager_); } private: @@ -252,14 +249,15 @@ context, BuildMockProfileSyncService); } + base::test::ScopedFeatureList override_features_; + std::unique_ptr< base::CallbackList<void(content::BrowserContext*)>::Subscription> will_create_browser_context_services_subscription_; - std::unique_ptr<syncer::SyncPrefs> sync_prefs_; FakeSyncServiceObserverList fake_sync_service_observer_list_; browser_sync::ProfileSyncServiceMock* mock_sync_service_ = nullptr; - std::unique_ptr<sync_sessions::SessionsSyncManager> manager_; + sync_sessions::SessionsSyncManager* manager_; DISALLOW_COPY_AND_ASSIGN(RecentTabsSubMenuModelTest); };
diff --git a/chrome/browser/ui/views/download/download_feedback_dialog_view.cc b/chrome/browser/ui/views/download/download_feedback_dialog_view.cc deleted file mode 100644 index 4af90f2..0000000 --- a/chrome/browser/ui/views/download/download_feedback_dialog_view.cc +++ /dev/null
@@ -1,177 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/download/download_feedback_dialog_view.h" - -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/supports_user_data.h" -#include "chrome/browser/platform_util.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser_dialogs.h" -#include "chrome/common/pref_names.h" -#include "chrome/grit/chromium_strings.h" -#include "chrome/grit/generated_resources.h" -#include "components/constrained_window/constrained_window_views.h" -#include "components/prefs/pref_service.h" -#include "components/safe_browsing/common/safe_browsing_prefs.h" -#include "components/security_interstitials/core/urls.h" -#include "components/strings/grit/components_strings.h" -#include "content/public/browser/page_navigator.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/views/controls/link.h" -#include "ui/views/controls/message_box_view.h" -#include "ui/views/widget/widget.h" - -using content::OpenURLParams; - -namespace { - -const void* const kDialogStatusKey = &kDialogStatusKey; - -class DialogStatusData : public base::SupportsUserData::Data { - public: - DialogStatusData() : currently_shown_(false) {} - ~DialogStatusData() override {} - bool currently_shown() const { return currently_shown_; } - void set_currently_shown(bool shown) { currently_shown_ = shown; } - private: - bool currently_shown_; -}; - -} // namespace - -// static -void DownloadFeedbackDialogView::Show( - gfx::NativeWindow parent_window, - Profile* profile, - content::PageNavigator* navigator, - const UserDecisionCallback& callback) { - // This dialog should only be shown if it hasn't been shown before. - DCHECK(!safe_browsing::ExtendedReportingPrefExists(*profile->GetPrefs())); - - // Determine if any prefs need to be updated prior to showing the dialog. - safe_browsing::UpdatePrefsBeforeSecurityInterstitial(profile->GetPrefs()); - - // Only one dialog should be shown at a time, so check to see if another one - // is open. If another one is open, treat this parallel call as if reporting - // is disabled (to be conservative). - DialogStatusData* data = - static_cast<DialogStatusData*>(profile->GetUserData(kDialogStatusKey)); - if (data == NULL) { - data = new DialogStatusData(); - profile->SetUserData(kDialogStatusKey, base::WrapUnique(data)); - } - if (data->currently_shown() == false) { - data->set_currently_shown(true); - DownloadFeedbackDialogView* window = - new DownloadFeedbackDialogView(profile, navigator, callback); - constrained_window::CreateBrowserModalDialogViews( - window, parent_window)->Show(); - } else { - callback.Run(false); - } -} - -DownloadFeedbackDialogView::DownloadFeedbackDialogView( - Profile* profile, - content::PageNavigator* navigator, - const UserDecisionCallback& callback) - : profile_(profile), - navigator_(navigator), - callback_(callback), - explanation_box_view_( - new views::MessageBoxView(views::MessageBoxView::InitParams( - l10n_util::GetStringUTF16(safe_browsing::ChooseOptInTextResource( - *profile->GetPrefs(), - IDS_FEEDBACK_SERVICE_DIALOG_EXPLANATION, - IDS_FEEDBACK_SERVICE_DIALOG_EXPLANATION_SCOUT))))), - link_view_(new views::Link( - l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE))), - title_text_(l10n_util::GetStringUTF16(IDS_FEEDBACK_SERVICE_DIALOG_TITLE)), - ok_button_text_(l10n_util::GetStringUTF16( - IDS_FEEDBACK_SERVICE_DIALOG_OK_BUTTON_LABEL)), - cancel_button_text_(l10n_util::GetStringUTF16( - IDS_FEEDBACK_SERVICE_DIALOG_CANCEL_BUTTON_LABEL)) { - link_view_->set_listener(this); - chrome::RecordDialogCreation( - chrome::DialogIdentifier::SAFE_BROWSING_DOWNLOAD_FEEDBACK); -} - -DownloadFeedbackDialogView::~DownloadFeedbackDialogView() {} - -int DownloadFeedbackDialogView::GetDefaultDialogButton() const { - return ui::DIALOG_BUTTON_CANCEL; -} - -base::string16 DownloadFeedbackDialogView::GetDialogButtonLabel( - ui::DialogButton button) const { - return (button == ui::DIALOG_BUTTON_OK) ? - ok_button_text_ : cancel_button_text_; -} - -bool DownloadFeedbackDialogView::OnButtonClicked(bool accepted) { - safe_browsing::SetExtendedReportingPrefAndMetric( - profile_->GetPrefs(), accepted, - safe_browsing::SBER_OPTIN_SITE_DOWNLOAD_FEEDBACK_POPUP); - DialogStatusData* data = - static_cast<DialogStatusData*>(profile_->GetUserData(kDialogStatusKey)); - DCHECK(data); - data->set_currently_shown(false); - - UMA_HISTOGRAM_BOOLEAN("Download.FeedbackDialogEnabled", accepted); - - callback_.Run(accepted); - return true; -} - -bool DownloadFeedbackDialogView::Cancel() { - return OnButtonClicked(false); -} - -bool DownloadFeedbackDialogView::Accept() { - return OnButtonClicked(true); -} - -ui::ModalType DownloadFeedbackDialogView::GetModalType() const { - return ui::MODAL_TYPE_WINDOW; -} - -base::string16 DownloadFeedbackDialogView::GetWindowTitle() const { - return title_text_; -} - -void DownloadFeedbackDialogView::DeleteDelegate() { - delete this; -} - -views::Widget* DownloadFeedbackDialogView::GetWidget() { - return explanation_box_view_->GetWidget(); -} - -const views::Widget* DownloadFeedbackDialogView::GetWidget() const { - return explanation_box_view_->GetWidget(); -} - -views::View* DownloadFeedbackDialogView::GetContentsView() { - return explanation_box_view_; -} - -views::View* DownloadFeedbackDialogView::CreateExtraView() { - return link_view_; -} - -void DownloadFeedbackDialogView::LinkClicked( - views::Link* source, int event_flags) { - WindowOpenDisposition disposition = - ui::DispositionFromEventFlags(event_flags); - content::OpenURLParams params( - GURL(security_interstitials::kSafeBrowsingPrivacyPolicyUrl), - content::Referrer(), - disposition == WindowOpenDisposition::CURRENT_TAB - ? WindowOpenDisposition::NEW_FOREGROUND_TAB - : disposition, - ui::PAGE_TRANSITION_LINK, false); - navigator_->OpenURL(params); -}
diff --git a/chrome/browser/ui/views/download/download_feedback_dialog_view.h b/chrome/browser/ui/views/download/download_feedback_dialog_view.h deleted file mode 100644 index c32ae95..0000000 --- a/chrome/browser/ui/views/download/download_feedback_dialog_view.h +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_DOWNLOAD_DOWNLOAD_FEEDBACK_DIALOG_VIEW_H_ -#define CHROME_BROWSER_UI_VIEWS_DOWNLOAD_DOWNLOAD_FEEDBACK_DIALOG_VIEW_H_ - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "ui/views/controls/link_listener.h" -#include "ui/views/window/dialog_delegate.h" - -namespace views { -class MessageBoxView; -} - -namespace content { -class PageNavigator; -} - -class Profile; - -// Asks the user whether they want to participate in the Safe Browsing -// download feedback program. Shown only for downloads marked DANGEROUS_HOST -// or UNCOMMON_DOWNLOAD. The user should only see this dialog once. -class DownloadFeedbackDialogView : public views::DialogDelegate, - public views::LinkListener { - public: - // Callback with the user's decision. |accepted| is true if the user clicked - // Accept(). Otherwise, assume the user cancelled. - typedef base::Callback<void(bool accepted)> UserDecisionCallback; - - static void Show( - gfx::NativeWindow parent_window, - Profile* profile, - content::PageNavigator* navigator, - const UserDecisionCallback& callback); - - private: - DownloadFeedbackDialogView( - Profile* profile, - content::PageNavigator* navigator, - const UserDecisionCallback& callback); - ~DownloadFeedbackDialogView() override; - - // Handles the user's decision. - bool OnButtonClicked(bool accepted); - - // views::DialogDelegate: - ui::ModalType GetModalType() const override; - base::string16 GetWindowTitle() const override; - void DeleteDelegate() override; - views::Widget* GetWidget() override; - const views::Widget* GetWidget() const override; - views::View* GetContentsView() override; - int GetDefaultDialogButton() const override; - base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; - bool Cancel() override; - bool Accept() override; - views::View* CreateExtraView() override; - - // views::LinkListener: - void LinkClicked(views::Link* source, int event_flags) override; - - Profile* profile_; - content::PageNavigator* navigator_; - const UserDecisionCallback callback_; - views::MessageBoxView* explanation_box_view_; - views::Link* link_view_; - base::string16 title_text_; - base::string16 ok_button_text_; - base::string16 cancel_button_text_; - - DISALLOW_COPY_AND_ASSIGN(DownloadFeedbackDialogView); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_DOWNLOAD_DOWNLOAD_FEEDBACK_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc index 33fd655..e792a2b 100644 --- a/chrome/browser/ui/views/download/download_item_view.cc +++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -32,7 +32,6 @@ #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/themes/theme_properties.h" -#include "chrome/browser/ui/views/download/download_feedback_dialog_view.h" #include "chrome/browser/ui/views/download/download_shelf_context_menu_view.h" #include "chrome/browser/ui/views/download/download_shelf_view.h" #include "chrome/browser/ui/views/frame/browser_view.h" @@ -216,21 +215,8 @@ void DownloadItemView::MaybeSubmitDownloadToFeedbackService( DownloadCommands::Command download_command) { - PrefService* prefs = shelf_->browser()->profile()->GetPrefs(); if (model_->ShouldAllowDownloadFeedback() && - !shelf_->browser()->profile()->IsOffTheRecord()) { - if (safe_browsing::ExtendedReportingPrefExists(*prefs)) { - SubmitDownloadWhenFeedbackServiceEnabled( - download_command, safe_browsing::IsExtendedReportingEnabled(*prefs)); - } else { - // Show dialog, because the dialog hasn't been shown before. - DownloadFeedbackDialogView::Show( - shelf_->get_parent()->GetNativeWindow(), shelf_->browser()->profile(), - shelf_->GetNavigator(), - base::Bind( - &DownloadItemView::SubmitDownloadWhenFeedbackServiceEnabled, - weak_ptr_factory_.GetWeakPtr(), download_command)); - } + SubmitDownloadToFeedbackService(download_command)) { } else { DownloadCommands(model_.get()).ExecuteCommand(download_command); } @@ -771,8 +757,8 @@ return false; // TODO(shaktisahu): Enable feedback service for offline item. if (model_->download()) { - download_protection_service->feedback_service()->BeginFeedbackForDownload( - model_->download(), download_command); + return download_protection_service->MaybeBeginFeedbackForDownload( + shelf_->browser()->profile(), model_->download(), download_command); } // WARNING: we are deleted at this point. Don't access 'this'. return true; @@ -782,16 +768,6 @@ #endif } -void DownloadItemView::SubmitDownloadWhenFeedbackServiceEnabled( - DownloadCommands::Command download_command, - bool feedback_enabled) { - if (feedback_enabled && SubmitDownloadToFeedbackService(download_command)) - return; - - DownloadCommands(model_.get()).ExecuteCommand(download_command); - // WARNING: 'this' is deleted at this point. Don't access 'this'. -} - void DownloadItemView::LoadIcon() { IconManager* im = g_browser_process->icon_manager(); last_download_item_path_ = model_->GetTargetFilePath();
diff --git a/chrome/browser/ui/views/download/download_started_animation_views.cc b/chrome/browser/ui/views/download/download_started_animation_views.cc index fc3f8ea..462d3963 100644 --- a/chrome/browser/ui/views/download/download_started_animation_views.cc +++ b/chrome/browser/ui/views/download/download_started_animation_views.cc
@@ -6,9 +6,7 @@ #include "base/macros.h" #include "base/time/time.h" -#include "build/build_config.h" #include "chrome/app/vector_icons/vector_icons.h" -#include "chrome/browser/ui/views_mode_controller.h" #include "content/public/browser/web_contents.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/animation/linear_animation.h" @@ -123,10 +121,6 @@ // static void DownloadStartedAnimation::Show(content::WebContents* web_contents) { -#if defined(OS_MACOSX) - if (views_mode_controller::IsViewsBrowserCocoa()) - return ShowCocoa(web_contents); -#endif // The animation will delete itself when it's finished. new DownloadStartedAnimationViews(web_contents); }
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 523c4ab5..65881ea 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -119,6 +119,7 @@ #include "components/omnibox/browser/omnibox_popup_view.h" #include "components/omnibox/browser/omnibox_view.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/password_protection/metrics_util.h" #include "components/sessions/core/tab_restore_service.h" #include "components/signin/core/browser/profile_management_switches.h" #include "components/translate/core/browser/language_state.h" @@ -757,6 +758,13 @@ top_controls_slide_controller_->SetShownRatio(web_contents, ratio); } +bool BrowserView::DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const { + return top_controls_slide_controller_ && + top_controls_slide_controller_->DoBrowserControlsShrinkRendererSize( + contents); +} + int BrowserView::GetTopControlsHeight() const { if (top_controls_slide_controller_ && top_controls_slide_controller_->IsEnabled()) { @@ -2078,6 +2086,7 @@ void BrowserView::OnWindowEndUserBoundsChange() { if (!interactive_resize_) return; + safe_browsing::LogContentsSize(GetContentsSize()); auto now = base::TimeTicks::Now(); DCHECK(!interactive_resize_->begin_timestamp.is_null()); UMA_HISTOGRAM_TIMES("BrowserWindow.Resize.Duration",
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index 4246032b..4015fd36 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -299,6 +299,8 @@ gfx::NativeWindow GetNativeWindow() const override; void SetTopControlsShownRatio(content::WebContents* web_contents, float ratio) override; + bool DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const override; int GetTopControlsHeight() const override; void SetTopControlsGestureScrollInProgress(bool in_progress) override; StatusBubble* GetStatusBubble() override;
diff --git a/chrome/browser/ui/views/frame/browser_window_factory.cc b/chrome/browser/ui/views/frame/browser_window_factory.cc index 98cd0ad..f3a3c00 100644 --- a/chrome/browser/ui/views/frame/browser_window_factory.cc +++ b/chrome/browser/ui/views/frame/browser_window_factory.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h" #include "chrome/browser/ui/views_mode_controller.h" #include "chrome/grit/chromium_strings.h" +#include "components/safe_browsing/password_protection/metrics_util.h" #if defined(USE_AURA) #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" @@ -40,5 +41,6 @@ view->GetWidget()->GetNativeWindow()->SetProperty( aura::client::kCreatedByUserGesture, user_gesture); #endif + safe_browsing::LogContentsSize(view->GetContentsSize()); return view; }
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller.h b/chrome/browser/ui/views/frame/top_controls_slide_controller.h index 19ea3312aa..dfa72ed 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller.h +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller.h
@@ -42,6 +42,12 @@ virtual void OnBrowserFullscreenStateWillChange( bool new_fullscreen_state) = 0; + // Whether or not the renderer's viewport size has been shrunk by the height + // of the browser's top controls. + // See BrowserWindow::DoBrowserControlsShrinkRendererSize() for more details. + virtual bool DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const = 0; + // Called from the renderer to inform the controller that gesture scrolling // changed state. virtual void SetTopControlsGestureScrollInProgress(bool in_progress) = 0;
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc index 516438f..c1b0b08 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
@@ -32,6 +32,11 @@ namespace { +bool IsTabletModeEnabled() { + return TabletModeClient::Get() && + TabletModeClient::Get()->tablet_mode_enabled(); +} + // Based on the current status of |contents|, returns the browser top controls // shown state constraints, which specifies if the top controls are allowed to // be only shown, or either shown or hidden. @@ -42,7 +47,8 @@ content::WebContents* contents) { DCHECK(contents); - if (contents->IsFullscreen() || contents->IsFocusedElementEditable() || + if (!IsTabletModeEnabled() || contents->IsFullscreen() || + contents->IsFocusedElementEditable() || contents->ShowingInterstitialPage() || contents->IsBeingDestroyed() || contents->IsCrashed()) { return content::BROWSER_CONTROLS_STATE_SHOWN; @@ -155,7 +161,17 @@ ~TopControlsSlideTabObserver() override = default; float shown_ratio() const { return shown_ratio_; } - void set_shown_ratio(float ratio) { shown_ratio_ = ratio; } + bool shrink_renderer_size() const { return shrink_renderer_size_; } + + void SetShownRatio(float ratio, bool sliding_in_progress) { + shown_ratio_ = ratio; + if (!sliding_in_progress) + UpdateDoBrowserControlsShrinkRendererSize(); + } + + void UpdateDoBrowserControlsShrinkRendererSize() { + shrink_renderer_size_ = shown_ratio_ > 0; + } // content::WebContentsObserver: void RenderProcessGone(base::TerminationStatus status) override { @@ -230,6 +246,12 @@ // should be shown. float shown_ratio_ = 1.f; + // Indicates whether the renderer's viewport size should be shrunk by the + // height of the browser's top controls. This value should only be updated at + // the end of sliding, and should never change while sliding is in progress. + // https://crbug.com/885223. + bool shrink_renderer_size_ = true; + DISALLOW_COPY_AND_ASSIGN(TopControlsSlideTabObserver); }; @@ -238,10 +260,7 @@ TopControlsSlideControllerChromeOS::TopControlsSlideControllerChromeOS( BrowserView* browser_view) - : browser_view_(browser_view), - tablet_mode_enabled_(TabletModeClient::Get() && - TabletModeClient::Get()->tablet_mode_enabled()), - browser_frame_is_fullscreen_(browser_view->IsFullscreen()) { + : browser_view_(browser_view) { DCHECK(browser_view); DCHECK(browser_view->frame()); DCHECK(browser_view->browser()); @@ -253,17 +272,23 @@ if (TabletModeClient::Get()) TabletModeClient::Get()->AddObserver(this); - browser_view->browser()->tab_strip_model()->AddObserver(this); + + browser_view_->browser()->tab_strip_model()->AddObserver(this); + + OnEnabledStateChanged(IsTabletModeEnabled() && !browser_view->IsFullscreen()); } TopControlsSlideControllerChromeOS::~TopControlsSlideControllerChromeOS() { + OnEnabledStateChanged(false); + browser_view_->browser()->tab_strip_model()->RemoveObserver(this); + if (TabletModeClient::Get()) TabletModeClient::Get()->RemoveObserver(this); } bool TopControlsSlideControllerChromeOS::IsEnabled() const { - return tablet_mode_enabled_ && !browser_frame_is_fullscreen_; + return is_enabled_; } float TopControlsSlideControllerChromeOS::GetShownRatio() const { @@ -275,35 +300,55 @@ float ratio) { DCHECK(contents); - if (!IsEnabled()) + // Make sure the value tracked per tab is always updated even when sliding is + // disabled, so that we're always synchronized with the renderer. + DCHECK(observed_tabs_.count(contents)); + observed_tabs_[contents]->SetShownRatio(ratio, is_sliding_in_progress_); + + if (!IsEnabled()) { + // However, if sliding is disabled, we don't update |shown_ratio_|, which is + // the current value for the entire browser, and it must always be 1.f (i.e. + // the top controls are fully shown). + DCHECK_EQ(shown_ratio_, 1.f); return; + } if (shown_ratio_ == ratio) return; shown_ratio_ = ratio; - DCHECK(observed_tabs_.count(contents)); - observed_tabs_[contents]->set_shown_ratio(ratio); Refresh(); + + // When disabling is deferred, we're waiting for the render to fully show top- + // chrome, so look for a value of 1.f. The renderer may be animating towards + // that value. + if (defer_disabling_ && shown_ratio_ == 1.f) { + defer_disabling_ = false; + + // Don't just set |is_enabled_| to false. Make sure it's a correct value. + OnEnabledStateChanged(IsTabletModeEnabled() && + !browser_view_->IsFullscreen()); + } } void TopControlsSlideControllerChromeOS::OnBrowserFullscreenStateWillChange( bool new_fullscreen_state) { - auto* active_web_contents = browser_view_->GetActiveWebContents(); - if (new_fullscreen_state && !browser_frame_is_fullscreen_ && - shown_ratio_ < 1.f) { - // Immersive fullscreen mode could be about to start for this browser's - // window. Therefore show the top-chrome immediately without animation. - ShowTopChrome(active_web_contents, false /* animate */); + OnEnabledStateChanged(IsTabletModeEnabled() && !new_fullscreen_state); +} + +bool TopControlsSlideControllerChromeOS::DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const { + if (!IsEnabled()) + return false; + + auto iter = observed_tabs_.find(contents); + if (iter == observed_tabs_.end()) { + // this may be called for a new tab that hasn't attached yet to the tabstrip + return false; } - browser_frame_is_fullscreen_ = new_fullscreen_state; - - // Now that the state of this feature is changed, force the renderer to get - // the new top controls height by triggering a visual properties - // synchrnoization event. - SynchronizeVisualProperties(active_web_contents); + return iter->second->shrink_renderer_size(); } void TopControlsSlideControllerChromeOS::SetTopControlsGestureScrollInProgress( @@ -324,17 +369,9 @@ Refresh(); } -void TopControlsSlideControllerChromeOS::OnTabletModeToggled(bool enabled) { - auto* active_web_contents = browser_view_->GetActiveWebContents(); - if (!enabled) - ShowTopChrome(active_web_contents, false /* animate */); - - tablet_mode_enabled_ = enabled; - - // Now that the state of this feature is changed, force the renderer to get - // the new top controls height by triggering a visual properties - // synchrnoization event. - SynchronizeVisualProperties(active_web_contents); +void TopControlsSlideControllerChromeOS::OnTabletModeToggled( + bool tablet_mode_enabled) { + OnEnabledStateChanged(tablet_mode_enabled && !browser_view_->IsFullscreen()); } void TopControlsSlideControllerChromeOS::TabInsertedAt( @@ -389,7 +426,8 @@ void TopControlsSlideControllerChromeOS::SetTabNeedsAttentionAt( int index, bool attention) { - ShowTopChrome(browser_view_->GetActiveWebContents(), true /* animate */); + UpdateBrowserControlsStateShown(browser_view_->GetActiveWebContents(), + true /* animate */); } void TopControlsSlideControllerChromeOS::Observe( @@ -401,13 +439,58 @@ if (type != content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE) return; + // Make sure this notification is meant for us. + content::WebContents* active_contents = browser_view_->GetActiveWebContents(); + content::RenderViewHost* render_view_host = + content::Source<content::RenderViewHost>(source).ptr(); + if (!active_contents || content::WebContents::FromRenderViewHost( + render_view_host) != active_contents) { + return; + } + content::FocusedNodeDetails* node_details = content::Details<content::FocusedNodeDetails>(details).ptr(); // If a non-editable node gets focused and top-chrome is fully shown, we // should also update the browser controls state constraints so that // top-chrome is able to be hidden again. if (node_details->is_editable_node || shown_ratio_ == 1.f) - ShowTopChrome(browser_view_->GetActiveWebContents(), true /* animate */); + UpdateBrowserControlsStateShown(active_contents, true /* animate */); +} + +void TopControlsSlideControllerChromeOS::OnEnabledStateChanged(bool new_state) { + if (new_state == is_enabled_) + return; + + is_enabled_ = new_state; + + TabStripModel* tab_strip_model = browser_view_->browser()->tab_strip_model(); + content::WebContents* active_contents = + tab_strip_model->GetActiveWebContents(); + if (!active_contents) + return; + + if (!new_state && shown_ratio_ < 1.f) { + // We should never set the shown ratio immediately here, rather ask the + // renderer to show top-chrome without animation. Since this will happen + // later asynchronously, we need to defer the enabled status update until + // we get called by the renderer to set the shown ratio to 1.f. Otherwise + // we will layout the page to a smaller height before the renderer gets + // to know that it needs to update the shown ratio to 1.f. + // https://crbug.com/884453. + is_enabled_ = true; + defer_disabling_ = true; + } else { + defer_disabling_ = false; + + // Now that the state of this feature is changed, force the renderer to get + // the new top controls height by triggering a visual properties + // synchrnoization event. + SynchronizeVisualProperties(active_contents); + } + + // This will also update the browser controls state constraints in the render + // now that the state changed. + UpdateBrowserControlsStateShown(active_contents, false /* animate */); } void TopControlsSlideControllerChromeOS::Refresh() { @@ -510,6 +593,10 @@ // It should never be called while gesture scrolling is still in progress. DCHECK(!is_gesture_scrolling_in_progress_); + // If disabling is deferred, sliding should end only when top-chrome is fully + // shown. + DCHECK(!defer_disabling_ || (shown_ratio_ == 1.f)); + // It can, however, be called when sliding is not in progress as a result of // Setting the value directly (for example due to renderer crash), or a direct // call from the renderer to set the shown ratio to a terminal value. @@ -543,6 +630,11 @@ const int original_height = root_bounds.height(); const int new_height = widget_layer->bounds().height(); + // This must be updated here **before** the browser is laid out, since the + // renderer (as a result of the layout) may query this value, and hence it + // should be correct. + UpdateDoBrowserControlsShrinkRendererSize(); + // We need to guarantee a browser view re-layout, but want to avoid doing that // twice. if (new_height != original_height) { @@ -561,15 +653,19 @@ widget_layer->SetMasksToBounds(shown_ratio_ < 1.f); } -void TopControlsSlideControllerChromeOS::ShowTopChrome( - content::WebContents* contents, - bool animate) { - // If |animate| is true, we will rely on the renderer's compositor animating - // the value of the shown ratio and updating us by calling SetShownRatio() - // repeatedly. Otherwise we will set the shown ratio to 1.f immediately. - if (!animate) - SetShownRatio(contents, 1.f); +void TopControlsSlideControllerChromeOS:: + UpdateDoBrowserControlsShrinkRendererSize() { + // It should never be called while gesture scrolling is still in progress. + DCHECK(!is_gesture_scrolling_in_progress_); - // We also must synchronize with the renderer. - UpdateBrowserControlsStateShown(contents, animate); + // Nor should it be called while sliding is in progress. + DCHECK(!is_sliding_in_progress_); + + content::WebContents* active_contents = browser_view_->GetActiveWebContents(); + if (!active_contents) + return; + + DCHECK(observed_tabs_.count(active_contents)); + + observed_tabs_[active_contents]->UpdateDoBrowserControlsShrinkRendererSize(); }
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h index 7fc887c..0c0b11b 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h
@@ -48,10 +48,12 @@ float GetShownRatio() const override; void SetShownRatio(content::WebContents* contents, float ratio) override; void OnBrowserFullscreenStateWillChange(bool new_fullscreen_state) override; + bool DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const override; void SetTopControlsGestureScrollInProgress(bool in_progress) override; // TabletModeClientObserver: - void OnTabletModeToggled(bool enabled) override; + void OnTabletModeToggled(bool tablet_mode_enabled) override; // TabStripModelObserver: // TODO(afakhry): The below overrides are deprecated, but we have to keep @@ -79,6 +81,8 @@ const content::NotificationDetails& details) override; private: + void OnEnabledStateChanged(bool new_state); + // Refreshes the status of the browser top controls. void Refresh(); @@ -94,10 +98,9 @@ // BrowserView is laid out into its final bounds. void OnEndSliding(); - // Shows the top-chrome completely and updates the renderer of |contents| so - // that the values of the |shown_ratio_| and the renderer's - // |LayerTreeImpl::top_controls_shown_ratio_| are synchronized. - void ShowTopChrome(content::WebContents* contents, bool animate); + // Updates whether the currently active tab has shrunk its renderer's viewport + // size. + void UpdateDoBrowserControlsShrinkRendererSize(); BrowserView* browser_view_; @@ -105,13 +108,20 @@ // controls that is currently applied. float shown_ratio_ = 1.f; - // The following two values are cached here since they need to be queried - // whenever we get an update from the renderer to adjust the shown ratio. - // These updates result from touch gesture scrolls, so we need to minimize the - // work we do to get these values, so sliding the browser top controls feels - // smooth. - bool tablet_mode_enabled_; - bool browser_frame_is_fullscreen_; + // Indicates whether sliding the top controls with gesture scrolls is + // currently enabled, which is true when tablet mode is enabled and the + // browser window is not full-screened. This value is cached here since it + // needs to be queried whenever we get an update from the renderer to adjust + // the shown ratio. These updates result from touch gesture scrolls, so we + // need to minimize the work we do to get these values, so sliding the browser + // top controls feels smooth. + bool is_enabled_ = false; + + // Whether we need to wait for the renderer to set the shown ratio to 1.f + // before we toggle |is_enabled_| to false. It is used to postpone disabling + // top-chrome sliding until the renderer responds so that we can make sure + // both the renderer and the browser are both synchronized. + bool defer_disabling_ = false; // Indicates whether a touch gesture scrolling is in progress. This value is // updated by the renderer when it receives a GestureEventAck of type either
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc index bd7d042..c104d14 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -250,6 +250,10 @@ // Widget should not allow things to show outside its bounds. EXPECT_TRUE(browser_view->frame()->GetLayer()->GetMasksToBounds()); + + // The browser controls doesn't shrink the blink viewport size. + EXPECT_FALSE(browser_view->DoBrowserControlsShrinkRendererSize( + browser_view->GetActiveWebContents())); } else { // Top container start at the top. EXPECT_EQ(top_container_bounds.y(), 0); @@ -261,6 +265,10 @@ browser_view->contents_container()->height()); EXPECT_FALSE(browser_view->frame()->GetLayer()->GetMasksToBounds()); + + // The browser controls does shrink the blink viewport size. + EXPECT_TRUE(browser_view->DoBrowserControlsShrinkRendererSize( + browser_view->GetActiveWebContents())); } } @@ -297,6 +305,8 @@ // Renderer will get a zero-height top controls. EXPECT_EQ(browser_view->GetTopControlsHeight(), 0); + EXPECT_FALSE(browser_view->DoBrowserControlsShrinkRendererSize( + browser_view->GetActiveWebContents())); } IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest, @@ -311,6 +321,8 @@ // The browser reports a zero height for top-chrome UIs when the behavior is // disabled, so the render doesn't think it needs to move the top controls. EXPECT_EQ(browser_view()->GetTopControlsHeight(), 0); + EXPECT_FALSE(browser_view()->DoBrowserControlsShrinkRendererSize( + browser_view()->GetActiveWebContents())); // Now enable tablet mode. ToggleTabletMode(); @@ -321,23 +333,31 @@ EXPECT_TRUE(top_controls_slide_controller()->IsEnabled()); EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 1.f); EXPECT_NE(browser_view()->GetTopControlsHeight(), 0); + EXPECT_TRUE(browser_view()->DoBrowserControlsShrinkRendererSize( + browser_view()->GetActiveWebContents())); // Immersive fullscreen mode disables the behavior. chrome::ToggleFullscreenMode(browser()); EXPECT_TRUE(browser_view()->IsFullscreen()); EXPECT_FALSE(top_controls_slide_controller()->IsEnabled()); EXPECT_EQ(browser_view()->GetTopControlsHeight(), 0); + EXPECT_FALSE(browser_view()->DoBrowserControlsShrinkRendererSize( + browser_view()->GetActiveWebContents())); // Exit immersive mode. chrome::ToggleFullscreenMode(browser()); EXPECT_FALSE(browser_view()->IsFullscreen()); EXPECT_TRUE(top_controls_slide_controller()->IsEnabled()); EXPECT_NE(browser_view()->GetTopControlsHeight(), 0); + EXPECT_TRUE(browser_view()->DoBrowserControlsShrinkRendererSize( + browser_view()->GetActiveWebContents())); ToggleTabletMode(); EXPECT_FALSE(GetTabletModeEnabled()); EXPECT_FALSE(top_controls_slide_controller()->IsEnabled()); EXPECT_EQ(browser_view()->GetTopControlsHeight(), 0); + EXPECT_FALSE(browser_view()->DoBrowserControlsShrinkRendererSize( + browser_view()->GetActiveWebContents())); } IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest, TestScrollingPage) { @@ -431,6 +451,16 @@ waiter.WaitForRatio(0.f); EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 0); CheckBrowserLayout(browser_view(), TopChromeShownState::kFullyHidden); + + // The `DoBrowserControlsShrinkRendererSize` bit is separately tracked for + // each tab. + auto* tab_strip_model = browser()->tab_strip_model(); + auto* scrollable_page_contents = tab_strip_model->GetWebContentsAt(0); + auto* ntp_contents = tab_strip_model->GetWebContentsAt(1); + EXPECT_TRUE( + browser_view()->DoBrowserControlsShrinkRendererSize(ntp_contents)); + EXPECT_FALSE(browser_view()->DoBrowserControlsShrinkRendererSize( + scrollable_page_contents)); } IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest, TestClosingATab) {
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn index c6aac0c..f79a4475 100644 --- a/chrome/browser/vr/BUILD.gn +++ b/chrome/browser/vr/BUILD.gn
@@ -203,7 +203,15 @@ ] if (use_command_buffer) { - sources += [ "skia_surface_provider_factory_cmd_buffer.cc" ] + sources += [ + "cmd_buffer_surface_provider.cc", + "cmd_buffer_surface_provider.h", + "skia_surface_provider_factory_cmd_buffer.cc", + ] + deps += [ + "//gpu/command_buffer/client:gles2_implementation", + "//gpu/skia_bindings", + ] } else { sources += [ "native_gl_surface_provider.cc",
diff --git a/chrome/browser/vr/cmd_buffer_surface_provider.cc b/chrome/browser/vr/cmd_buffer_surface_provider.cc new file mode 100644 index 0000000..b148eaeb --- /dev/null +++ b/chrome/browser/vr/cmd_buffer_surface_provider.cc
@@ -0,0 +1,58 @@ +// 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/cmd_buffer_surface_provider.h" + +#include "base/logging.h" +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "gpu/command_buffer/client/gles2_lib.h" +#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/gpu/GrBackendSurface.h" +#include "third_party/skia/include/gpu/GrContext.h" +#include "third_party/skia/include/gpu/gl/GrGLInterface.h" +#include "ui/gfx/geometry/size.h" + +namespace vr { + +CmdBufferSurfaceProvider::CmdBufferSurfaceProvider() { + auto* gles2_implementation = + static_cast<gpu::gles2::GLES2Implementation*>(gles2::GetGLContext()); + DCHECK(gles2_implementation); + sk_sp<const GrGLInterface> gr_interface = + skia_bindings::CreateGLES2InterfaceBindings(gles2_implementation, + gles2_implementation); + gr_context_ = GrContext::MakeGL(std::move(gr_interface)); + DCHECK(gr_context_); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &main_fbo_); +} + +CmdBufferSurfaceProvider::~CmdBufferSurfaceProvider() = default; + +sk_sp<SkSurface> CmdBufferSurfaceProvider::MakeSurface(const gfx::Size& size) { + return SkSurface::MakeRenderTarget( + gr_context_.get(), SkBudgeted::kNo, + SkImageInfo::MakeN32Premul(size.width(), size.height()), 0, + kTopLeft_GrSurfaceOrigin, nullptr); +} + +GLuint CmdBufferSurfaceProvider::FlushSurface(SkSurface* surface, + GLuint reuse_texture_id) { + surface->getCanvas()->flush(); + GrBackendTexture backend_texture = + surface->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess); + DCHECK(backend_texture.isValid()); + GrGLTextureInfo info; + bool result = backend_texture.getGLTextureInfo(&info); + DCHECK(result); + GLuint texture_id = info.fID; + DCHECK_NE(texture_id, 0u); + surface->getCanvas()->getGrContext()->resetContext(); + glBindFramebuffer(GL_FRAMEBUFFER, main_fbo_); + + return texture_id; +} + +} // namespace vr
diff --git a/chrome/browser/vr/cmd_buffer_surface_provider.h b/chrome/browser/vr/cmd_buffer_surface_provider.h new file mode 100644 index 0000000..a8e72976 --- /dev/null +++ b/chrome/browser/vr/cmd_buffer_surface_provider.h
@@ -0,0 +1,30 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_VR_CMD_BUFFER_SURFACE_PROVIDER_H_ +#define CHROME_BROWSER_VR_CMD_BUFFER_SURFACE_PROVIDER_H_ + +#include "chrome/browser/vr/skia_surface_provider.h" +#include "chrome/browser/vr/vr_ui_export.h" + +class GrContext; + +namespace vr { + +class VR_UI_EXPORT CmdBufferSurfaceProvider : public SkiaSurfaceProvider { + public: + CmdBufferSurfaceProvider(); + ~CmdBufferSurfaceProvider() override; + + sk_sp<SkSurface> MakeSurface(const gfx::Size& size) override; + GLuint FlushSurface(SkSurface* surface, GLuint reuse_texture_id) override; + + private: + sk_sp<GrContext> gr_context_; + GLint main_fbo_ = 0; +}; + +} // namespace vr + +#endif // CHROME_BROWSER_VR_CMD_BUFFER_SURFACE_PROVIDER_H_
diff --git a/chrome/browser/vr/skia_surface_provider_factory_cmd_buffer.cc b/chrome/browser/vr/skia_surface_provider_factory_cmd_buffer.cc index 42702c7..3af44fc 100644 --- a/chrome/browser/vr/skia_surface_provider_factory_cmd_buffer.cc +++ b/chrome/browser/vr/skia_surface_provider_factory_cmd_buffer.cc
@@ -4,14 +4,12 @@ #include "chrome/browser/vr/skia_surface_provider_factory.h" -#include "base/logging.h" +#include "chrome/browser/vr/cmd_buffer_surface_provider.h" namespace vr { std::unique_ptr<SkiaSurfaceProvider> SkiaSurfaceProviderFactory::Create() { - // TODO(crbug/884256): Implement a surface provider using the command buffer. - NOTIMPLEMENTED(); - return nullptr; + return std::make_unique<CmdBufferSurfaceProvider>(); } } // namespace vr
diff --git a/chrome/browser/vr/test/gl_test_environment_unittest.cc b/chrome/browser/vr/test/gl_test_environment_unittest.cc index 783e727..ee62da2 100644 --- a/chrome/browser/vr/test/gl_test_environment_unittest.cc +++ b/chrome/browser/vr/test/gl_test_environment_unittest.cc
@@ -10,13 +10,9 @@ namespace vr { TEST(GlTestEnvironmentTest, InitializeAndCleanup) { -// TODO(crbug/771794): Test temporarily disabled on Windows because it crashes -// on trybots. Fix before enabling Windows support. -#ifndef OS_WIN GlTestEnvironment gl_test_environment(gfx::Size(100, 100)); EXPECT_NE(gl_test_environment.GetFrameBufferForTesting(), 0u); EXPECT_EQ(glGetError(), (GLenum)GL_NO_ERROR); -#endif // We just test that clean up doesn't crash. }
diff --git a/chrome/browser/vr/test/run_all_perftests.cc b/chrome/browser/vr/test/run_all_perftests.cc index 9b7663af..cec581f3 100644 --- a/chrome/browser/vr/test/run_all_perftests.cc +++ b/chrome/browser/vr/test/run_all_perftests.cc
@@ -4,13 +4,13 @@ #include "base/bind.h" #include "base/test/launcher/unit_test_launcher.h" -#include "chrome/browser/vr/test/vr_test_suite.h" +#include "chrome/browser/vr/test/vr_gl_test_suite.h" int main(int argc, char** argv) { - vr::VrTestSuite test_suite(argc, argv); + vr::VrGlTestSuite test_suite(argc, argv); return base::LaunchUnitTestsSerially( argc, argv, - base::BindRepeating(&vr::VrTestSuite::Run, + base::BindRepeating(&vr::VrGlTestSuite::Run, base::Unretained(&test_suite))); }
diff --git a/chrome/browser/vr/test/ui_pixel_test.cc b/chrome/browser/vr/test/ui_pixel_test.cc index b0b20c9..b5062b3 100644 --- a/chrome/browser/vr/test/ui_pixel_test.cc +++ b/chrome/browser/vr/test/ui_pixel_test.cc
@@ -21,9 +21,6 @@ UiPixelTest::~UiPixelTest() = default; void UiPixelTest::SetUp() { -// TODO(crbug/771794): Test temporarily disabled on Windows because it crashes -// on trybots. Fix before enabling Windows support. -#ifndef OS_WIN gl_test_environment_ = std::make_unique<GlTestEnvironment>(frame_buffer_size_); @@ -36,17 +33,12 @@ ASSERT_EQ(glGetError(), (GLenum)GL_NO_ERROR); browser_ = std::make_unique<MockUiBrowserInterface>(); -#endif } void UiPixelTest::TearDown() { -// TODO(crbug/771794): Test temporarily disabled on Windows because it crashes -// on trybots. Fix before enabling Windows support. -#ifndef OS_WIN ui_.reset(); glDeleteTextures(1, &content_texture_); gl_test_environment_.reset(); -#endif } void UiPixelTest::MakeUi(const UiInitialState& ui_initial_state,
diff --git a/chrome/browser/vr/test/vr_gl_test_suite.cc b/chrome/browser/vr/test/vr_gl_test_suite.cc index e5af480..d47e18d 100644 --- a/chrome/browser/vr/test/vr_gl_test_suite.cc +++ b/chrome/browser/vr/test/vr_gl_test_suite.cc
@@ -8,10 +8,11 @@ #include "ui/gl/test/gl_image_test_support.h" #if defined(VR_USE_COMMAND_BUFFER) -#include "gpu/config/gpu_info_collector.h" // nogncheck -#include "gpu/config/gpu_preferences.h" // nogncheck -#include "gpu/config/gpu_util.h" // nogncheck -#include "gpu/ipc/in_process_command_buffer.h" // nogncheck +#include "gpu/command_buffer/client/gles2_lib.h" // nogncheck +#include "gpu/config/gpu_info_collector.h" // nogncheck +#include "gpu/config/gpu_preferences.h" // nogncheck +#include "gpu/config/gpu_util.h" // nogncheck +#include "gpu/ipc/in_process_command_buffer.h" // nogncheck #endif // defined(VR_USE_COMMAND_BUFFER) namespace vr { @@ -36,6 +37,7 @@ gpu::kGpuFeatureStatusEnabled; gpu::InProcessCommandBuffer::InitializeDefaultServiceForTesting( gpu_feature_info); + gles2::Initialize(); #endif // defined(VR_USE_COMMAND_BUFFER) }
diff --git a/chrome/browser/vr/text_perftest.cc b/chrome/browser/vr/text_perftest.cc index 3fa2b15..172d674 100644 --- a/chrome/browser/vr/text_perftest.cc +++ b/chrome/browser/vr/text_perftest.cc
@@ -36,6 +36,7 @@ void TearDown() override { text_element_.reset(); + provider_.reset(); gl_test_environment_.reset(); } @@ -59,8 +60,8 @@ cc::LapTimer timer_; private: - std::unique_ptr<GlTestEnvironment> gl_test_environment_; std::unique_ptr<SkiaSurfaceProvider> provider_; + std::unique_ptr<GlTestEnvironment> gl_test_environment_; }; TEST_F(TextPerfTest, RenderLoremIpsum100Chars) {
diff --git a/chrome/browser/vr/ui_pixeltest.cc b/chrome/browser/vr/ui_pixeltest.cc index 2d29e12..64c15d3 100644 --- a/chrome/browser/vr/ui_pixeltest.cc +++ b/chrome/browser/vr/ui_pixeltest.cc
@@ -14,19 +14,11 @@ namespace { -static const gfx::Transform kIdentity; +constexpr gfx::Transform kIdentity; } // namespace -// TODO(crbug/771794): Test temporarily disabled on Windows because it crashes -// on trybots. Fix before enabling Windows support. -#if defined(OS_WIN) -#define MAYBE(x) DISABLED_##x -#else -#define MAYBE(x) x -#endif - -TEST_F(UiPixelTest, MAYBE(DrawVrBrowsingMode)) { +TEST_F(UiPixelTest, DrawVrBrowsingMode) { // Set up scene. UiInitialState ui_initial_state; ui_initial_state.in_web_vr = false;
diff --git a/chrome/notification_helper/OWNERS b/chrome/notification_helper/OWNERS index a537112..ae9c4f8 100644 --- a/chrome/notification_helper/OWNERS +++ b/chrome/notification_helper/OWNERS
@@ -1,3 +1,4 @@ chengx@chromium.org +finnur@chromium.org grt@chromium.org robliao@chromium.org
diff --git a/chrome/renderer/benchmarking_extension.cc b/chrome/renderer/benchmarking_extension.cc index b0fe829..2d957fd 100644 --- a/chrome/renderer/benchmarking_extension.cc +++ b/chrome/renderer/benchmarking_extension.cc
@@ -54,10 +54,14 @@ v8::Isolate* isolate, v8::Local<v8::String> name) override { if (name->StringEquals( - v8::String::NewFromUtf8(isolate, "IsSingleProcess"))) { + v8::String::NewFromUtf8(isolate, "IsSingleProcess", + v8::NewStringType::kInternalized) + .ToLocalChecked())) { return v8::FunctionTemplate::New(isolate, IsSingleProcess); } else if (name->StringEquals( - v8::String::NewFromUtf8(isolate, "HiResTime"))) { + v8::String::NewFromUtf8(isolate, "HiResTime", + v8::NewStringType::kInternalized) + .ToLocalChecked())) { return v8::FunctionTemplate::New(isolate, HiResTime); }
diff --git a/chrome/renderer/extensions/app_bindings.cc b/chrome/renderer/extensions/app_bindings.cc index 434c2ac..e44d35e8 100644 --- a/chrome/renderer/extensions/app_bindings.cc +++ b/chrome/renderer/extensions/app_bindings.cc
@@ -55,8 +55,11 @@ void AppBindings::GetRunningState( const v8::FunctionCallbackInfo<v8::Value>& args) { - args.GetReturnValue().Set(v8::String::NewFromUtf8( - context()->isolate(), app_core_.GetRunningState(context()))); + args.GetReturnValue().Set( + v8::String::NewFromUtf8(context()->isolate(), + app_core_.GetRunningState(context()), + v8::NewStringType::kInternalized) + .ToLocalChecked()); } void AppBindings::OnAppInstallStateResponse(int callback_id, @@ -68,9 +71,10 @@ v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context()->v8_context()); v8::Local<v8::Value> argv[] = { - v8::String::NewFromUtf8(isolate, state.c_str()), - v8::Integer::New(isolate, callback_id) - }; + v8::String::NewFromUtf8(isolate, state.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked(), + v8::Integer::New(isolate, callback_id)}; context()->module_system()->CallModuleMethodSafe( "app", "onInstallStateResponse", arraysize(argv), argv); }
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.cc b/chrome/renderer/extensions/automation_internal_custom_bindings.cc index f52bc2e..c145cee5 100644 --- a/chrome/renderer/extensions/automation_internal_custom_bindings.cc +++ b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
@@ -73,7 +73,7 @@ while (node && !ui::IsTableLikeRole(node->data().role)) node = node->parent(); - if (ui::IsTableLikeRole(node->data().role)) + if (node && ui::IsTableLikeRole(node->data().role)) return node; return nullptr; @@ -481,17 +481,21 @@ AutomationAXTreeWrapper* tree_wrapper) { result.Set(v8::Integer::New(isolate, tree_wrapper->tree()->root()->id())); }); - RouteTreeIDFunction( - "GetDocURL", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, - AutomationAXTreeWrapper* tree_wrapper) { - result.Set(v8::String::NewFromUtf8( - isolate, tree_wrapper->tree()->data().url.c_str())); - }); + RouteTreeIDFunction("GetDocURL", [](v8::Isolate* isolate, + v8::ReturnValue<v8::Value> result, + AutomationAXTreeWrapper* tree_wrapper) { + result.Set(v8::String::NewFromUtf8(isolate, + tree_wrapper->tree()->data().url.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); + }); RouteTreeIDFunction( "GetDocTitle", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, AutomationAXTreeWrapper* tree_wrapper) { result.Set(v8::String::NewFromUtf8( - isolate, tree_wrapper->tree()->data().title.c_str())); + isolate, tree_wrapper->tree()->data().title.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); }); RouteTreeIDFunction( "GetDocLoaded", @@ -609,7 +613,9 @@ } std::string role_name = ui::ToString(mapped_role); - result.Set(v8::String::NewFromUtf8(isolate, role_name.c_str())); + result.Set(v8::String::NewFromUtf8(isolate, role_name.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); }); RouteNodeIDFunction( "GetLocation", @@ -737,7 +743,9 @@ return; } - result.Set(v8::String::NewFromUtf8(isolate, attr_value.c_str())); + result.Set(v8::String::NewFromUtf8(isolate, attr_value.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); }); RouteNodeIDPlusAttributeFunction( "GetBoolAttribute", @@ -845,7 +853,9 @@ if (!node->data().GetHtmlAttribute(attribute_name.c_str(), &attr_value)) return; - result.Set(v8::String::NewFromUtf8(isolate, attr_value.c_str())); + result.Set(v8::String::NewFromUtf8(isolate, attr_value.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); }); RouteNodeIDFunction( "GetNameFrom", @@ -854,7 +864,9 @@ ax::mojom::NameFrom name_from = static_cast<ax::mojom::NameFrom>( node->data().GetIntAttribute(ax::mojom::IntAttribute::kNameFrom)); std::string name_from_str = ui::ToString(name_from); - result.Set(v8::String::NewFromUtf8(isolate, name_from_str.c_str())); + result.Set(v8::String::NewFromUtf8(isolate, name_from_str.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); }); RouteNodeIDFunction("GetSubscript", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, @@ -970,7 +982,9 @@ for (size_t i = 0; i < standard_actions.size(); i++) { const v8::Maybe<bool>& did_set_value = actions_result->Set( isolate->GetCurrentContext(), i, - v8::String::NewFromUtf8(isolate, standard_actions[i].c_str())); + v8::String::NewFromUtf8(isolate, standard_actions[i].c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); bool did_set_value_result = false; if (!did_set_value.To(&did_set_value_result) || !did_set_value_result) @@ -987,7 +1001,9 @@ ax::mojom::IntAttribute::kCheckedState)); if (checked_state != ax::mojom::CheckedState::kNone) { const std::string checked_str = ui::ToString(checked_state); - result.Set(v8::String::NewFromUtf8(isolate, checked_str.c_str())); + result.Set(v8::String::NewFromUtf8(isolate, checked_str.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); } }); RouteNodeIDFunction( @@ -998,7 +1014,9 @@ node->data().GetRestriction(); if (restriction != ax::mojom::Restriction::kNone) { const std::string restriction_str = ui::ToString(restriction); - result.Set(v8::String::NewFromUtf8(isolate, restriction_str.c_str())); + result.Set(v8::String::NewFromUtf8(isolate, restriction_str.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); } }); RouteNodeIDFunction( @@ -1010,8 +1028,10 @@ node->data().GetIntAttribute( ax::mojom::IntAttribute::kDefaultActionVerb)); std::string default_action_verb_str = ui::ToString(default_action_verb); - result.Set( - v8::String::NewFromUtf8(isolate, default_action_verb_str.c_str())); + result.Set(v8::String::NewFromUtf8(isolate, + default_action_verb_str.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); }); RouteNodeIDPlusStringBoolFunction( "GetNextTextMatch",
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.cc b/chrome/renderer/extensions/cast_streaming_native_handler.cc index eea058b..eb57fda 100644 --- a/chrome/renderer/extensions/cast_streaming_native_handler.cc +++ b/chrome/renderer/extensions/cast_streaming_native_handler.cc
@@ -105,8 +105,10 @@ if (config->sender_ssrc == config->receiver_ssrc) { DVLOG(1) << "sender_ssrc " << config->sender_ssrc << " cannot be equal to receiver_ssrc"; - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } config->min_playout_delay = base::TimeDelta::FromMilliseconds( @@ -120,23 +122,29 @@ if (config->min_playout_delay <= base::TimeDelta()) { DVLOG(1) << "min_playout_delay " << config->min_playout_delay << " must be greater than zero"; - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } if (config->min_playout_delay > config->max_playout_delay) { DVLOG(1) << "min_playout_delay " << config->min_playout_delay << " must be less than or equal to max_palyout_delay"; - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } if (config->animated_playout_delay < config->min_playout_delay || config->animated_playout_delay > config->max_playout_delay) { DVLOG(1) << "animated_playout_delay " << config->animated_playout_delay << " must be between (inclusive) the min and max playout delay"; - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } if (ext_params.codec_name == kCodecNameOpus) { @@ -156,13 +164,17 @@ default: DVLOG(1) << "rtp_timebase " << config->rtp_timebase << " is invalid"; isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } config->channels = ext_params.channels ? *ext_params.channels : 2; if (config->channels != 1 && config->channels != 2) { isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); DVLOG(1) << "channels " << config->channels << " is invalid"; return false; } @@ -177,7 +189,9 @@ config->channels = ext_params.channels ? *ext_params.channels : 1; if (config->channels != 1) { isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); DVLOG(1) << "channels " << config->channels << " is invalid"; return false; } @@ -191,7 +205,9 @@ DVLOG(1) << "min_bitrate " << config->min_bitrate << " is larger than " << "max_bitrate " << config->max_bitrate; isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } config->start_bitrate = config->min_bitrate; @@ -200,7 +216,9 @@ if (config->max_frame_rate > media::limits::kMaxFramesPerSecond) { DVLOG(1) << "max_frame_rate " << config->max_frame_rate << " is invalid"; isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } if (ext_params.codec_name == kCodecNameVp8) { @@ -225,19 +243,25 @@ config->codec = media::cast::CODEC_VIDEO_REMOTE; } else { DVLOG(1) << "codec_name " << ext_params.codec_name << " is invalid"; - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } if (ext_params.aes_key && !HexDecode(*ext_params.aes_key, &config->aes_key)) { - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidAesKey))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesKey, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } if (ext_params.aes_iv_mask && !HexDecode(*ext_params.aes_iv_mask, &config->aes_iv_mask)) { - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidAesIvMask))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesIvMask, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } return true; @@ -398,7 +422,9 @@ blink::WebDOMMediaStreamTrack::FromV8Value(args[0]); if (track.IsNull()) { isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); + v8::String::NewFromUtf8(isolate, kInvalidStreamArgs, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } stream1.reset(new CastRtpStream(track.Component(), session)); @@ -409,7 +435,9 @@ blink::WebDOMMediaStreamTrack::FromV8Value(args[1]); if (track.IsNull()) { isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); + v8::String::NewFromUtf8(isolate, kInvalidStreamArgs, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } stream2.reset(new CastRtpStream(track.Component(), session)); @@ -533,13 +561,17 @@ V8ValueConverter::Create()->FromV8Value(args[1], context()->v8_context()); if (!params_value) { args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams))); + v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } std::unique_ptr<RtpParams> params = RtpParams::FromValue(*params_value); if (!params) { args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams))); + v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -629,7 +661,9 @@ args[1], context()->v8_context())); if (!options) { args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs))); + v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } transport->SetOptions(std::move(options)); @@ -743,8 +777,10 @@ if (iter != rtp_stream_map_.end()) return iter->second.get(); v8::Isolate* isolate = context()->v8_context()->GetIsolate(); - isolate->ThrowException(v8::Exception::RangeError(v8::String::NewFromUtf8( - isolate, kRtpStreamNotFound))); + isolate->ThrowException(v8::Exception::RangeError( + v8::String::NewFromUtf8(isolate, kRtpStreamNotFound, + v8::NewStringType::kNormal) + .ToLocalChecked())); return NULL; } @@ -756,7 +792,9 @@ return iter->second.get(); v8::Isolate* isolate = context()->v8_context()->GetIsolate(); isolate->ThrowException(v8::Exception::RangeError( - v8::String::NewFromUtf8(isolate, kUdpTransportNotFound))); + v8::String::NewFromUtf8(isolate, kUdpTransportNotFound, + v8::NewStringType::kNormal) + .ToLocalChecked())); return NULL; } @@ -768,14 +806,18 @@ V8ValueConverter::Create()->FromV8Value(arg, context()->v8_context()); if (!params_value) { isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kUnableToConvertParams))); + v8::String::NewFromUtf8(isolate, kUnableToConvertParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } std::unique_ptr<RtpReceiverParams> params = RtpReceiverParams::FromValue(*params_value); if (!params) { isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); + v8::String::NewFromUtf8(isolate, kInvalidRtpParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } @@ -784,7 +826,9 @@ config->rtp_max_delay_ms = params->max_latency; if (config->rtp_max_delay_ms < 0 || config->rtp_max_delay_ms > 1000) { isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kInvalidLatency))); + v8::String::NewFromUtf8(isolate, kInvalidLatency, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } config->channels = 2; @@ -813,20 +857,26 @@ config->rtp_timebase = *params->rtp_timebase; if (config->rtp_timebase < 1000 || config->rtp_timebase > 1000000) { isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kInvalidRtpTimebase))); + v8::String::NewFromUtf8(isolate, kInvalidRtpTimebase, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } } if (params->aes_key && !HexDecode(*params->aes_key, &config->aes_key)) { - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidAesKey))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesKey, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } if (params->aes_iv_mask && !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) { - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidAesIvMask))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesIvMask, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } return true; @@ -840,20 +890,26 @@ V8ValueConverter::Create()->FromV8Value(arg, context()->v8_context()); if (!destination_value) { isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kInvalidAesIvMask))); + v8::String::NewFromUtf8(isolate, kInvalidAesIvMask, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } std::unique_ptr<IPEndPoint> destination = IPEndPoint::FromValue(*destination_value); if (!destination) { isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kInvalidDestination))); + v8::String::NewFromUtf8(isolate, kInvalidDestination, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } net::IPAddress ip; if (!ip.AssignFromIPLiteral(destination->address)) { isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kInvalidDestination))); + v8::String::NewFromUtf8(isolate, kInvalidDestination, + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } *ip_endpoint = net::IPEndPoint(ip, destination->port); @@ -871,7 +927,9 @@ !args[5]->IsNumber() || !args[6]->IsString()) { args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs))); + v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -896,7 +954,9 @@ if (fps <= 1) { args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS))); + v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -906,7 +966,9 @@ if (stream.IsNull()) { args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL))); + v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -925,7 +987,9 @@ if (!params.IsValid()) { args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams))); + v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -938,7 +1002,9 @@ options = base::DictionaryValue::From(std::move(options_value)); if (!options) { args.GetIsolate()->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs))); + v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } } @@ -965,10 +1031,10 @@ v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent function, const std::string& error_message) { v8::Isolate* isolate = context()->v8_context()->GetIsolate(); - v8::Local<v8::Value> arg = v8::String::NewFromUtf8(isolate, - error_message.data(), - v8::String::kNormalString, - error_message.size()); + v8::Local<v8::Value> arg = + v8::String::NewFromUtf8(isolate, error_message.data(), + v8::NewStringType::kNormal, error_message.size()) + .ToLocalChecked(); context()->SafeCallFunction(v8::Local<v8::Function>::New(isolate, function), 1, &arg); }
diff --git a/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc b/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc index 960ebbe..997f24ed 100644 --- a/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc +++ b/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc
@@ -39,15 +39,24 @@ v8::Isolate* isolate = args.GetIsolate(); std::string file_system_name(*v8::String::Utf8Value( isolate, - file_def->Get(v8::String::NewFromUtf8(isolate, "fileSystemName")))); + file_def->Get(v8::String::NewFromUtf8(isolate, "fileSystemName", + v8::NewStringType::kInternalized) + .ToLocalChecked()))); GURL file_system_root(*v8::String::Utf8Value( isolate, - file_def->Get(v8::String::NewFromUtf8(isolate, "fileSystemRoot")))); + file_def->Get(v8::String::NewFromUtf8(isolate, "fileSystemRoot", + v8::NewStringType::kInternalized) + .ToLocalChecked()))); std::string file_full_path(*v8::String::Utf8Value( isolate, - file_def->Get(v8::String::NewFromUtf8(isolate, "fileFullPath")))); + file_def->Get(v8::String::NewFromUtf8(isolate, "fileFullPath", + v8::NewStringType::kInternalized) + .ToLocalChecked()))); bool is_directory = - file_def->Get(v8::String::NewFromUtf8(isolate, "fileIsDirectory")) + file_def + ->Get(v8::String::NewFromUtf8(isolate, "fileIsDirectory", + v8::NewStringType::kInternalized) + .ToLocalChecked()) ->BooleanValue(context->v8_context()) .FromMaybe(false); blink::WebDOMFileSystem::EntryType entry_type =
diff --git a/chrome/renderer/extensions/webstore_bindings.cc b/chrome/renderer/extensions/webstore_bindings.cc index ff95be9..bbbda3c 100644 --- a/chrome/renderer/extensions/webstore_bindings.cc +++ b/chrome/renderer/extensions/webstore_bindings.cc
@@ -75,10 +75,13 @@ v8::Context::Scope context_scope(context()->v8_context()); v8::Local<v8::Value> argv[] = { v8::Integer::New(isolate, install_id), v8::Boolean::New(isolate, success), - v8::String::NewFromUtf8(isolate, error.c_str()), + v8::String::NewFromUtf8(isolate, error.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked(), v8::String::NewFromUtf8( - isolate, - api::webstore::kInstallResultCodes[static_cast<int>(result)])}; + isolate, api::webstore::kInstallResultCodes[static_cast<int>(result)], + v8::NewStringType::kNormal) + .ToLocalChecked()}; context()->module_system()->CallModuleMethodSafe( "webstore", "onInstallResponse", arraysize(argv), argv); } @@ -98,7 +101,8 @@ v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context()->v8_context()); v8::Local<v8::Value> argv[] = { - v8::String::NewFromUtf8(isolate, stage_string)}; + v8::String::NewFromUtf8(isolate, stage_string, v8::NewStringType::kNormal) + .ToLocalChecked()}; context()->module_system()->CallModuleMethodSafe( "webstore", "onInstallStageChanged", arraysize(argv), argv); } @@ -143,7 +147,9 @@ if (!GetWebstoreItemIdFromFrame( frame, preferred_store_link_url, &webstore_item_id, &error)) { args.GetIsolate()->ThrowException( - v8::String::NewFromUtf8(args.GetIsolate(), error.c_str())); + v8::String::NewFromUtf8(args.GetIsolate(), error.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); return; }
diff --git a/chrome/renderer/loadtimes_extension_bindings.cc b/chrome/renderer/loadtimes_extension_bindings.cc index dda7d71..a79a0a2d 100644 --- a/chrome/renderer/loadtimes_extension_bindings.cc +++ b/chrome/renderer/loadtimes_extension_bindings.cc
@@ -64,9 +64,15 @@ v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( v8::Isolate* isolate, v8::Local<v8::String> name) override { - if (name->StringEquals(v8::String::NewFromUtf8(isolate, "GetLoadTimes"))) { + if (name->StringEquals( + v8::String::NewFromUtf8(isolate, "GetLoadTimes", + v8::NewStringType::kInternalized) + .ToLocalChecked())) { return v8::FunctionTemplate::New(isolate, GetLoadTimes); - } else if (name->StringEquals(v8::String::NewFromUtf8(isolate, "GetCSI"))) { + } else if (name->StringEquals( + v8::String::NewFromUtf8(isolate, "GetCSI", + v8::NewStringType::kInternalized) + .ToLocalChecked())) { return v8::FunctionTemplate::New(isolate, GetCSI); } return v8::Local<v8::FunctionTemplate>();
diff --git a/chrome/renderer/net_benchmarking_extension.cc b/chrome/renderer/net_benchmarking_extension.cc index a43add3..37f75e87 100644 --- a/chrome/renderer/net_benchmarking_extension.cc +++ b/chrome/renderer/net_benchmarking_extension.cc
@@ -48,16 +48,25 @@ v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( v8::Isolate* isolate, v8::Local<v8::String> name) override { - if (name->StringEquals(v8::String::NewFromUtf8(isolate, "ClearCache"))) { + if (name->StringEquals( + v8::String::NewFromUtf8(isolate, "ClearCache", + v8::NewStringType::kInternalized) + .ToLocalChecked())) { return v8::FunctionTemplate::New(isolate, ClearCache); - } else if (name->StringEquals(v8::String::NewFromUtf8( - isolate, "ClearHostResolverCache"))) { + } else if (name->StringEquals( + v8::String::NewFromUtf8(isolate, "ClearHostResolverCache", + v8::NewStringType::kInternalized) + .ToLocalChecked())) { return v8::FunctionTemplate::New(isolate, ClearHostResolverCache); } else if (name->StringEquals( - v8::String::NewFromUtf8(isolate, "ClearPredictorCache"))) { + v8::String::NewFromUtf8(isolate, "ClearPredictorCache", + v8::NewStringType::kInternalized) + .ToLocalChecked())) { return v8::FunctionTemplate::New(isolate, ClearPredictorCache); } else if (name->StringEquals( - v8::String::NewFromUtf8(isolate, "CloseConnections"))) { + v8::String::NewFromUtf8(isolate, "CloseConnections", + v8::NewStringType::kInternalized) + .ToLocalChecked())) { return v8::FunctionTemplate::New(isolate, CloseConnections); }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 401aa4a..d11517d 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -744,6 +744,7 @@ "../browser/renderer_context_menu/spelling_menu_observer_browsertest.cc", "../browser/renderer_host/render_process_host_chrome_browsertest.cc", "../browser/repost_form_warning_browsertest.cc", + "../browser/resource_coordinator/discard_before_unload_helper_browsertest.cc", "../browser/resource_coordinator/local_site_characteristics_data_store_factory_browsertest.cc", "../browser/resource_coordinator/local_site_characteristics_data_unittest_utils.cc", "../browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h", @@ -1965,8 +1966,6 @@ "../browser/ui/cocoa/accelerators_cocoa_browsertest.mm", "../browser/ui/cocoa/apps/app_shim_menu_controller_mac_browsertest.mm", "../browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm", - "../browser/ui/cocoa/dev_tools_controller_browsertest.mm", - "../browser/ui/cocoa/omnibox/omnibox_view_mac_browsertest.mm", "../browser/ui/cocoa/permission_bubble/permission_bubble_views_cocoa_browsertest.mm", "../browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm", "../browser/ui/cocoa/ssl_client_certificate_selector_cocoa_browsertest.mm", @@ -2681,8 +2680,8 @@ "../browser/subresource_filter/subresource_filter_test_harness.cc", "../browser/subresource_filter/subresource_filter_test_harness.h", "../browser/subresource_filter/subresource_filter_unittest.cc", - "../browser/sync/chrome_sync_client_unittest.cc", "../browser/sync/profile_sync_service_factory_unittest.cc", + "../browser/sync/session_sync_service_factory_unittest.cc", "../browser/sync/sessions/sync_sessions_web_contents_router_unittest.cc", "../browser/sync/sync_startup_tracker_unittest.cc", "../browser/thumbnails/thumbnail_service_unittest.cc", @@ -4128,7 +4127,6 @@ "../browser/ui/cocoa/browser_window_controller_unittest.mm", "../browser/ui/cocoa/browser_window_layout_unittest.mm", "../browser/ui/cocoa/browser_window_utils_unittest.mm", - "../browser/ui/cocoa/bubble_view_unittest.mm", "../browser/ui/cocoa/chrome_browser_window_unittest.mm", "../browser/ui/cocoa/clickhold_button_cell_unittest.mm", "../browser/ui/cocoa/color_panel_cocoa_unittest.mm", @@ -4148,11 +4146,6 @@ "../browser/ui/cocoa/history_overlay_controller_unittest.mm", "../browser/ui/cocoa/hover_close_button_unittest.mm", "../browser/ui/cocoa/image_button_cell_unittest.mm", - "../browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm", - "../browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm", - "../browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm", - "../browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h", - "../browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm", "../browser/ui/cocoa/main_menu_builder_unittest.mm", "../browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm", "../browser/ui/cocoa/menu_button_unittest.mm", @@ -4160,16 +4153,10 @@ "../browser/ui/cocoa/notifications/notification_response_builder_mac_unittest.mm", "../browser/ui/cocoa/nsmenuitem_additions_unittest.mm", "../browser/ui/cocoa/nsview_additions_unittest.mm", - "../browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm", - "../browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm", - "../browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm", - "../browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm", - "../browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm", "../browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm", "../browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm", "../browser/ui/cocoa/scoped_menu_bar_lock_unittest.mm", "../browser/ui/cocoa/spinner_view_unittest.mm", - "../browser/ui/cocoa/status_bubble_mac_unittest.mm", "../browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm", "../browser/ui/cocoa/styled_text_field_cell_unittest.mm", "../browser/ui/cocoa/styled_text_field_unittest.mm",
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc index 25c9c2e..4af45fe 100644 --- a/chrome/test/base/test_browser_window.cc +++ b/chrome/test/base/test_browser_window.cc
@@ -76,6 +76,11 @@ content::WebContents* web_contents, float ratio) {} +bool TestBrowserWindow::DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const { + return false; +} + int TestBrowserWindow::GetTopControlsHeight() const { return 0; }
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h index 45e8111..7e9cbb0 100644 --- a/chrome/test/base/test_browser_window.h +++ b/chrome/test/base/test_browser_window.h
@@ -53,6 +53,8 @@ gfx::NativeWindow GetNativeWindow() const override; void SetTopControlsShownRatio(content::WebContents* web_contents, float ratio) override; + bool DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const override; int GetTopControlsHeight() const override; void SetTopControlsGestureScrollInProgress(bool in_progress) override; StatusBubble* GetStatusBubble() override;
diff --git a/chrome/test/base/v8_unit_test.cc b/chrome/test/base/v8_unit_test.cc index 23cd96a..7f8ed5b 100644 --- a/chrome/test/base/v8_unit_test.cc +++ b/chrome/test/base/v8_unit_test.cc
@@ -98,8 +98,10 @@ v8::MicrotasksScope microtasks( isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); - v8::Local<v8::Value> function_property = - context->Global()->Get(v8::String::NewFromUtf8(isolate, "runTest")); + v8::Local<v8::Value> function_property = context->Global()->Get( + v8::String::NewFromUtf8(isolate, "runTest", + v8::NewStringType::kInternalized) + .ToLocalChecked()); EXPECT_FALSE(function_property.IsEmpty()); if (::testing::Test::HasNonfatalFailure()) return false; @@ -110,19 +112,19 @@ v8::Local<v8::Function>::Cast(function_property); v8::Local<v8::Array> params = v8::Array::New(isolate); - params->Set(0, - v8::String::NewFromUtf8(isolate, - test_fixture.data(), - v8::String::kNormalString, - test_fixture.size())); - params->Set(1, - v8::String::NewFromUtf8(isolate, - test_name.data(), - v8::String::kNormalString, - test_name.size())); + params->Set(0, v8::String::NewFromUtf8(isolate, test_fixture.data(), + v8::NewStringType::kNormal, + test_fixture.size()) + .ToLocalChecked()); + params->Set( + 1, v8::String::NewFromUtf8(isolate, test_name.data(), + v8::NewStringType::kNormal, test_name.size()) + .ToLocalChecked()); v8::Local<v8::Value> args[] = { v8::Boolean::New(isolate, false), - v8::String::NewFromUtf8(isolate, "RUN_TEST_F"), params}; + v8::String::NewFromUtf8(isolate, "RUN_TEST_F", v8::NewStringType::kNormal) + .ToLocalChecked(), + params}; v8::TryCatch try_catch(isolate); v8::Local<v8::Value> result = function->Call(context->Global(), 3, args); @@ -167,7 +169,9 @@ void V8UnitTest::SetUp() { v8::Isolate* isolate = blink::MainThreadIsolate(); v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); - v8::Local<v8::String> log_string = v8::String::NewFromUtf8(isolate, "log"); + v8::Local<v8::String> log_string = + v8::String::NewFromUtf8(isolate, "log", v8::NewStringType::kInternalized) + .ToLocalChecked(); v8::Local<v8::FunctionTemplate> log_function = v8::FunctionTemplate::New(isolate, &V8UnitTest::Log); log_function->RemovePrototype(); @@ -175,29 +179,50 @@ // Set up chrome object for chrome.send(). v8::Local<v8::ObjectTemplate> chrome = v8::ObjectTemplate::New(isolate); - global->Set(v8::String::NewFromUtf8(isolate, "chrome"), chrome); + global->Set(v8::String::NewFromUtf8(isolate, "chrome", + v8::NewStringType::kInternalized) + .ToLocalChecked(), + chrome); v8::Local<v8::FunctionTemplate> send_function = v8::FunctionTemplate::New(isolate, &V8UnitTest::ChromeSend); send_function->RemovePrototype(); - chrome->Set(v8::String::NewFromUtf8(isolate, "send"), send_function); + chrome->Set( + v8::String::NewFromUtf8(isolate, "send", v8::NewStringType::kInternalized) + .ToLocalChecked(), + send_function); context_.Reset(isolate, v8::Context::New(isolate, NULL, global)); // Set up console object for console.log(), etc. v8::Local<v8::ObjectTemplate> console = v8::ObjectTemplate::New(isolate); - global->Set(v8::String::NewFromUtf8(isolate, "console"), console); + global->Set(v8::String::NewFromUtf8(isolate, "console", + v8::NewStringType::kInternalized) + .ToLocalChecked(), + console); console->Set(log_string, log_function); - console->Set(v8::String::NewFromUtf8(isolate, "info"), log_function); - console->Set(v8::String::NewFromUtf8(isolate, "warn"), log_function); + console->Set( + v8::String::NewFromUtf8(isolate, "info", v8::NewStringType::kInternalized) + .ToLocalChecked(), + log_function); + console->Set( + v8::String::NewFromUtf8(isolate, "warn", v8::NewStringType::kInternalized) + .ToLocalChecked(), + log_function); v8::Local<v8::FunctionTemplate> error_function = v8::FunctionTemplate::New(isolate, &V8UnitTest::Error); error_function->RemovePrototype(); - console->Set(v8::String::NewFromUtf8(isolate, "error"), error_function); + console->Set(v8::String::NewFromUtf8(isolate, "error", + v8::NewStringType::kInternalized) + .ToLocalChecked(), + error_function); { v8::Local<v8::Context> context = context_.Get(isolate); v8::Context::Scope context_scope(context); context->Global() - ->Set(context, v8::String::NewFromUtf8(isolate, "console"), + ->Set(context, + v8::String::NewFromUtf8(isolate, "console", + v8::NewStringType::kInternalized) + .ToLocalChecked(), console->NewInstance(context).ToLocalChecked()) .ToChecked(); } @@ -210,12 +235,13 @@ v8::Local<v8::Context>::New(isolate, context_); v8::Context::Scope context_scope(context); context->Global()->Set( - v8::String::NewFromUtf8(isolate, - var_name.c_str(), - v8::String::kNormalString, - var_name.length()), - v8::String::NewFromUtf8( - isolate, value.c_str(), v8::String::kNormalString, value.length())); + v8::String::NewFromUtf8(isolate, var_name.c_str(), + v8::NewStringType::kInternalized, + var_name.length()) + .ToLocalChecked(), + v8::String::NewFromUtf8(isolate, value.c_str(), + v8::NewStringType::kNormal, value.length()) + .ToLocalChecked()); } void V8UnitTest::ExecuteScriptInContext(const base::StringPiece& script_source, @@ -228,15 +254,13 @@ v8::MicrotasksScope microtasks( isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::Local<v8::String> source = - v8::String::NewFromUtf8(isolate, - script_source.data(), - v8::String::kNormalString, - script_source.size()); + v8::String::NewFromUtf8(isolate, script_source.data(), + v8::NewStringType::kNormal, script_source.size()) + .ToLocalChecked(); v8::Local<v8::String> name = - v8::String::NewFromUtf8(isolate, - script_name.data(), - v8::String::kNormalString, - script_name.size()); + v8::String::NewFromUtf8(isolate, script_name.data(), + v8::NewStringType::kNormal, script_name.size()) + .ToLocalChecked(); v8::TryCatch try_catch(isolate); v8::ScriptOrigin origin(name); @@ -283,7 +307,9 @@ isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::Local<v8::Value> function_property = context->Global()->Get( - v8::String::NewFromUtf8(isolate, function_name.c_str())); + v8::String::NewFromUtf8(isolate, function_name.c_str(), + v8::NewStringType::kInternalized) + .ToLocalChecked()); ASSERT_FALSE(function_property.IsEmpty()); ASSERT_TRUE(function_property->IsFunction()); v8::Local<v8::Function> function =
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc index 3849b02..c4e50e8 100644 --- a/chrome/test/chromedriver/capabilities.cc +++ b/chrome/test/chromedriver/capabilities.cc
@@ -197,22 +197,26 @@ Status ParsePageLoadStrategy(const base::Value& option, Capabilities* capabilities) { if (!option.GetAsString(&capabilities->page_load_strategy)) - return Status(kUnknownError, "must be a string"); - if (capabilities->page_load_strategy == PageLoadStrategy::kNormal || - capabilities->page_load_strategy == PageLoadStrategy::kNone) + return Status(kInvalidArgument, "'pageLoadStrategy' must be a string"); + if (capabilities->page_load_strategy == PageLoadStrategy::kNone || + capabilities->page_load_strategy == PageLoadStrategy::kEager || + capabilities->page_load_strategy == PageLoadStrategy::kNormal) return Status(kOk); - return Status(kUnknownError, "page load strategy unsupported"); + return Status(kInvalidArgument, "invalid 'pageLoadStrategy'"); } -Status ParseUnexpectedAlertBehaviour(const base::Value& option, - Capabilities* capabilities) { - if (!option.GetAsString(&capabilities->unexpected_alert_behaviour)) - return Status(kUnknownError, "must be a string"); - if (capabilities->unexpected_alert_behaviour == kAccept || - capabilities->unexpected_alert_behaviour == kDismiss || - capabilities->unexpected_alert_behaviour == kIgnore) +Status ParseUnhandledPromptBehavior(const base::Value& option, + Capabilities* capabilities) { + if (!option.GetAsString(&capabilities->unhandled_prompt_behavior)) + return Status(kInvalidArgument, + "'unhandledPromptBehavior' must be a string"); + if (capabilities->unhandled_prompt_behavior == kDismiss || + capabilities->unhandled_prompt_behavior == kAccept || + capabilities->unhandled_prompt_behavior == kDismissAndNotify || + capabilities->unhandled_prompt_behavior == kAcceptAndNotify || + capabilities->unhandled_prompt_behavior == kIgnore) return Status(kOk); - return Status(kUnknownError, "unexpected alert behaviour unsupported"); + return Status(kInvalidArgument, "invalid 'unhandledPromptBehavior'"); } Status ParseSwitches(const base::Value& option, @@ -669,13 +673,13 @@ PerfLoggingPrefs::~PerfLoggingPrefs() {} Capabilities::Capabilities() - : android_use_running_app(false), + : accept_insecure_certs(false), + page_load_strategy(PageLoadStrategy::kNormal), + android_use_running_app(false), detach(false), extension_load_timeout(base::TimeDelta::FromSeconds(10)), force_devtools_screenshot(true), - page_load_strategy(PageLoadStrategy::kNormal), network_emulation_enabled(false), - accept_insecure_certs(false), use_automation_extension(true) {} Capabilities::~Capabilities() {} @@ -690,29 +694,44 @@ Status Capabilities::Parse(const base::DictionaryValue& desired_caps) { std::map<std::string, Parser> parser_map; + + // W3C defined capabilities. + parser_map["acceptInsecureCerts"] = + base::BindRepeating(&ParseBoolean, &accept_insecure_certs); + parser_map["browserName"] = base::BindRepeating(&ParseString, &browser_name); + parser_map["browserVersion"] = + base::BindRepeating(&ParseString, &browser_version); + parser_map["platformName"] = + base::BindRepeating(&ParseString, &platform_name); + parser_map["pageLoadStrategy"] = base::BindRepeating(&ParsePageLoadStrategy); + parser_map["proxy"] = base::BindRepeating(&ParseProxy); + // TODO(https://crbug.com/chromedriver/1997): Parse "timeouts". + // TODO(https://crbug.com/chromedriver/2596): "unexpectedAlertBehaviour" is + // legacy name of "unhandledPromptBehavior", remove when we stop supporting + // legacy mode. + parser_map["unexpectedAlertBehaviour"] = + base::BindRepeating(&ParseUnhandledPromptBehavior); + parser_map["unhandledPromptBehavior"] = + base::BindRepeating(&ParseUnhandledPromptBehavior); + + // ChromeDriver specific capabilities. // goog:chromeOptions is the current spec conformance, but chromeOptions is // still supported if (desired_caps.GetDictionary("goog:chromeOptions", nullptr)) { - parser_map["goog:chromeOptions"] = base::Bind(&ParseChromeOptions); + parser_map["goog:chromeOptions"] = base::BindRepeating(&ParseChromeOptions); } else { - parser_map["chromeOptions"] = base::Bind(&ParseChromeOptions); + parser_map["chromeOptions"] = base::BindRepeating(&ParseChromeOptions); } - - parser_map["loggingPrefs"] = base::Bind(&ParseLoggingPrefs); - parser_map["proxy"] = base::Bind(&ParseProxy); - parser_map["pageLoadStrategy"] = base::Bind(&ParsePageLoadStrategy); - parser_map["unexpectedAlertBehaviour"] = - base::Bind(&ParseUnexpectedAlertBehaviour); - parser_map["acceptInsecureCerts"] = - base::BindRepeating(&ParseBoolean, &accept_insecure_certs); + parser_map["loggingPrefs"] = base::BindRepeating(&ParseLoggingPrefs); // Network emulation requires device mode, which is only enabled when // mobile emulation is on. if (desired_caps.GetDictionary("goog:chromeOptions.mobileEmulation", nullptr) || desired_caps.GetDictionary("chromeOptions.mobileEmulation", nullptr)) { parser_map["networkConnectionEnabled"] = - base::Bind(&ParseBoolean, &network_emulation_enabled); + base::BindRepeating(&ParseBoolean, &network_emulation_enabled); } + for (std::map<std::string, Parser>::iterator it = parser_map.begin(); it != parser_map.end(); ++it) { const base::Value* capability = NULL; @@ -750,3 +769,27 @@ } return Status(kOk); } + +Status Capabilities::CheckSupport() const { + // TODO(https://crbug.com/chromedriver/1902): pageLoadStrategy=eager not yet + // supported. + if (page_load_strategy.length() > 0 && + page_load_strategy != PageLoadStrategy::kNormal && + page_load_strategy != PageLoadStrategy::kNone) { + return Status(kInvalidArgument, "'pageLoadStrategy=" + page_load_strategy + + "' not yet supported"); + } + + // TODO(https://crbug.com/chromedriver/2597): Some unhandledPromptBehavior + // modes not yet supported. + if (unhandled_prompt_behavior.length() > 0 && + unhandled_prompt_behavior != kAccept && + unhandled_prompt_behavior != kDismiss && + unhandled_prompt_behavior != kIgnore) { + return Status(kInvalidArgument, + "'unhandledPromptBehavior=" + unhandled_prompt_behavior + + "' not yet supported"); + } + + return Status(kOk); +}
diff --git a/chrome/test/chromedriver/capabilities.h b/chrome/test/chromedriver/capabilities.h index 4ffbc38..425eeef1 100644 --- a/chrome/test/chromedriver/capabilities.h +++ b/chrome/test/chromedriver/capabilities.h
@@ -96,8 +96,40 @@ // Return true if android package is specified. bool IsAndroid() const; + // Accepts all W3C defined capabilities (including those not yet supported by + // ChromeDriver) and all ChromeDriver-specific extensions. Status Parse(const base::DictionaryValue& desired_caps); + // Check if all specified capabilities are supported by ChromeDriver. + // The long term goal is to support all standard capabilities, thus making + // this method unnecessary. + Status CheckSupport() const; + + // + // W3C defined capabilities + // + + bool accept_insecure_certs; + + std::string browser_name; + std::string browser_version; + std::string platform_name; + + std::string page_load_strategy; + + // Data from "proxy" capability are stored in "switches" field. + + // The default values for the timeout fields came from W3C spec. + base::TimeDelta script_timeout = base::TimeDelta::FromSeconds(30); + base::TimeDelta page_load_timeout = base::TimeDelta::FromSeconds(300); + base::TimeDelta implicit_wait_timeout = base::TimeDelta::FromSeconds(0); + + std::string unhandled_prompt_behavior; + + // + // ChromeDriver specific capabilities + // + std::string android_activity; std::string android_device_serial; @@ -147,14 +179,8 @@ // If set, enable minidump for chrome crashes and save to this directory. std::string minidump_path; - std::string page_load_strategy; - - std::string unexpected_alert_behaviour; - bool network_emulation_enabled; - bool accept_insecure_certs; - PerfLoggingPrefs perf_logging_prefs; std::unique_ptr<base::ListValue> devtools_events_logging_prefs;
diff --git a/chrome/test/chromedriver/session.h b/chrome/test/chromedriver/session.h index 70bd049d..24ca85d 100644 --- a/chrome/test/chromedriver/session.h +++ b/chrome/test/chromedriver/session.h
@@ -21,7 +21,9 @@ #include "chrome/test/chromedriver/command_listener.h" static const char kAccept[] = "accept"; +static const char kAcceptAndNotify[] = "accept and notify"; static const char kDismiss[] = "dismiss"; +static const char kDismissAndNotify[] = "dismiss and notify"; static const char kIgnore[] = "ignore"; // Controls whether ChromeDriver operates in W3C mode (when true) or legacy @@ -104,7 +106,7 @@ // |CommandListener|s might be |CommandListenerProxy|s that forward to // |DevToolsEventListener|s owned by |chrome|. std::vector<std::unique_ptr<CommandListener>> command_listeners; - std::string unexpected_alert_behaviour; + std::string unhandled_prompt_behavior; }; Session* GetThreadLocalSession();
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc index 14e31f7c..3664417 100644 --- a/chrome/test/chromedriver/session_commands.cc +++ b/chrome/test/chromedriver/session_commands.cc
@@ -134,8 +134,9 @@ caps->SetBoolean("acceptInsecureCerts", capabilities.accept_insecure_certs); caps->SetBoolean("nativeEvents", true); caps->SetBoolean("hasTouchScreen", session->chrome->HasTouchScreen()); - caps->SetString("unexpectedAlertBehaviour", - session->unexpected_alert_behaviour); + caps->SetString(session->w3c_compliant ? "unhandledPromptBehavior" + : "unexpectedAlertBehaviour", + session->unhandled_prompt_behavior); // add setWindowRect based on whether we are desktop/android/remote if (capabilities.IsAndroid() || capabilities.IsRemoteBrowser()) { @@ -262,9 +263,11 @@ Status status = capabilities.Parse(*desired_caps); if (status.IsError()) return status; + status = capabilities.CheckSupport(); + if (status.IsError()) + return status; - desired_caps->GetString("unexpectedAlertBehaviour", - &session->unexpected_alert_behaviour); + session->unhandled_prompt_behavior = capabilities.unhandled_prompt_behavior; Log::Level driver_level = Log::kWarning; if (capabilities.logging_prefs.count(WebDriverLog::kDriverType))
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc index 766a01a4..f7360859 100644 --- a/chrome/test/chromedriver/window_commands.cc +++ b/chrome/test/chromedriver/window_commands.cc
@@ -249,10 +249,10 @@ // Close the dialog depending on the unexpectedalert behaviour set by user // before returning an error, so that subsequent commands do not fail. - std::string alert_behaviour = session->unexpected_alert_behaviour; - if (alert_behaviour == kAccept) + std::string prompt_behavior = session->unhandled_prompt_behavior; + if (prompt_behavior == kAccept) status = dialog_manager->HandleDialog(true, session->prompt_text.get()); - else if (alert_behaviour == kDismiss) + else if (prompt_behavior == kDismiss) status = dialog_manager->HandleDialog(false, session->prompt_text.get()); if (status.IsError()) return status;
diff --git a/chrome/test/data/emptybeforeunload.html b/chrome/test/data/emptybeforeunload.html new file mode 100644 index 0000000..804efef --- /dev/null +++ b/chrome/test/data/emptybeforeunload.html
@@ -0,0 +1,11 @@ +<html> + <head> + <title>Loading...</title> + <script> + window.onbeforeunload = function(e) { return null; }; + </script> + </head> + <body> + <p>Navigate to another page to trigger beforeunload handler.</p> + </body> +</html>
diff --git a/chrome/test/data/extensions/api_test/debugger/background.js b/chrome/test/data/extensions/api_test/debugger/background.js index ca2423d..3cbd7cb6 100644 --- a/chrome/test/data/extensions/api_test/debugger/background.js +++ b/chrome/test/data/extensions/api_test/debugger/background.js
@@ -302,13 +302,24 @@ const url = 'http://127.0.0.1//extensions/api_test/debugger/inspected.html'; chrome.tabs.create({url: url}, function(tab) { var debuggee = {tabId: tab.id}; - var failed = false; + var finished = false; + var failure = ''; + var expectingFrameNavigated = false; + + function finishIfError() { + if (chrome.runtime.lastError) { + failure = chrome.runtime.lastError.message; + finish(true); + return true; + } + return false; + } function onAttach() { chrome.debugger.sendCommand(debuggee, 'Network.enable', null, - () => chrome.test.assertNoLastError()); + finishIfError); chrome.debugger.sendCommand(debuggee, 'Page.enable', null, - () => chrome.test.assertNoLastError()); + finishIfError); var offlineParams = { offline: true, latency: 0, downloadThroughput: 0, uploadThroughput: 0 }; chrome.debugger.sendCommand(debuggee, @@ -317,31 +328,50 @@ } function onOffline() { - chrome.test.assertNoLastError(); + if (finishIfError()) + return; + expectingFrameNavigated = true; chrome.debugger.sendCommand(debuggee, 'Page.reload', null, - () => chrome.test.assertNoLastError()); + finishIfError); } - function cleanup(detach) { + function finish(detach) { + if (finished) + return; + finished = true; chrome.debugger.onDetach.removeListener(onDetach); chrome.debugger.onEvent.removeListener(onEvent); if (detach) chrome.debugger.detach(debuggee); - chrome.tabs.remove(tab.id); + chrome.tabs.remove(tab.id, () => { + if (failure) + chrome.test.fail(failure); + else + chrome.test.succeed(); + }); } function onDetach() { - failed = true; - cleanup(false); - chrome.test.fail('Detached before navigated to error page'); + failure = 'Detached before navigated to error page'; + finish(false); } function onEvent(_, method, params) { - if (failed || method !== 'Page.frameNavigated') + if (!expectingFrameNavigated || method !== 'Page.frameNavigated') return; - cleanup(true); - chrome.test.assertNoLastError(); - chrome.test.succeed(); + + if (finishIfError()) + return; + + expectingFrameNavigated = false; + chrome.debugger.sendCommand( + debuggee, 'Page.navigate', {url: 'about:blank'}, onNavigateDone); + } + + function onNavigateDone() { + if (finishIfError()) + return; + finish(true); } chrome.debugger.onDetach.addListener(onDetach);
diff --git a/chrome/test/data/webui/print_preview/pages_settings_test.js b/chrome/test/data/webui/print_preview/pages_settings_test.js index 9cb3c55..954fdc7 100644 --- a/chrome/test/data/webui/print_preview/pages_settings_test.js +++ b/chrome/test/data/webui/print_preview/pages_settings_test.js
@@ -174,6 +174,10 @@ }) .then(function() { validateErrorState(syntaxError); + return setupInput('--', 100); + }) + .then(function() { + validateErrorState(syntaxError); }); });
diff --git a/chrome/test/data/webui/settings/sync_account_control_test.js b/chrome/test/data/webui/settings/sync_account_control_test.js index 43675de..1f246a0 100644 --- a/chrome/test/data/webui/settings/sync_account_control_test.js +++ b/chrome/test/data/webui/settings/sync_account_control_test.js
@@ -93,7 +93,12 @@ assertVisible(testElement.$$('#promo-header'), true); assertVisible(testElement.$$('#avatar-row'), false); - assertVisible(testElement.$$('#menu'), false); + // TODO (rbpotter): Remove this conditional when the migration to + // Polymer 2 is completed. + if (Polymer.DomIf) + assertEquals(null, testElement.$$('#menu')); + else + assertVisible(testElement.$$('#menu'), false); assertVisible(testElement.$$('#sign-in'), true); testElement.$$('#sign-in').click();
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index 27853a3..2aaa2e8 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -57,6 +57,7 @@ "autofill_manager.cc", "autofill_manager.h", "autofill_manager_test_delegate.h", + "autofill_metadata.h", "autofill_metrics.cc", "autofill_metrics.h", "autofill_popup_delegate.h",
diff --git a/components/autofill/core/browser/autofill_data_model.cc b/components/autofill/core/browser/autofill_data_model.cc index 1d36be4..72464e8e 100644 --- a/components/autofill/core/browser/autofill_data_model.cc +++ b/components/autofill/core/browser/autofill_data_model.cc
@@ -6,6 +6,7 @@ #include <math.h> +#include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/common/autofill_clock.h" #include "url/gurl.h" @@ -46,6 +47,19 @@ return guid_ > other->guid_; } +AutofillMetadata AutofillDataModel::GetMetadata() const { + AutofillMetadata metadata; + metadata.use_count = use_count_; + metadata.use_date = use_date_; + return metadata; +} + +bool AutofillDataModel::SetMetadata(const AutofillMetadata metadata) { + use_count_ = metadata.use_count; + use_date_ = metadata.use_date; + return true; +} + double AutofillDataModel::GetFrecencyScore(base::Time time) const { // The formula calculates a score based on both the frequency and the recency // of the profile and leveraging the properties of the logarithmic function.
diff --git a/components/autofill/core/browser/autofill_data_model.h b/components/autofill/core/browser/autofill_data_model.h index 4cc373b..a9f562a 100644 --- a/components/autofill/core/browser/autofill_data_model.h +++ b/components/autofill/core/browser/autofill_data_model.h
@@ -15,6 +15,8 @@ namespace autofill { +struct AutofillMetadata; + // This class is an interface for the primary data models that back Autofill. // The information in objects of this class is managed by the // PersonalDataManager. @@ -52,6 +54,13 @@ bool CompareFrecency(const AutofillDataModel* other, base::Time comparison_time) const; + // Gets the metadata associated with this autofill data model. + virtual AutofillMetadata GetMetadata() const; + + // Sets the |use_count_| and |use_date_| of this autofill data model. Returns + // whether the metadata was set. + virtual bool SetMetadata(const AutofillMetadata metadata); + protected: // Called to update |use_count_| and |use_date_| when this data model is // the subject of user interaction (usually, when it's used to fill a form).
diff --git a/components/autofill/core/browser/autofill_data_model_unittest.cc b/components/autofill/core/browser/autofill_data_model_unittest.cc index 8432b10..5ab0d1b 100644 --- a/components/autofill/core/browser/autofill_data_model_unittest.cc +++ b/components/autofill/core/browser/autofill_data_model_unittest.cc
@@ -9,6 +9,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/time/time.h" +#include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/common/autofill_constants.h" #include "testing/gtest/include/gtest/gtest.h" @@ -16,6 +17,8 @@ namespace { +const base::Time kArbitraryTime = base::Time::FromDoubleT(25); + // Provides concrete implementations for pure virtual methods. class TestAutofillDataModel : public AutofillDataModel { public: @@ -71,6 +74,27 @@ EXPECT_FALSE(model.IsVerified()); } +TEST(AutofillDataModelTest, GetMetadata) { + TestAutofillDataModel model("guid", std::string()); + model.set_use_count(10); + model.set_use_date(kArbitraryTime); + + AutofillMetadata metadata = model.GetMetadata(); + EXPECT_EQ(model.use_count(), metadata.use_count); + EXPECT_EQ(model.use_date(), metadata.use_date); +} + +TEST(AutofillDataModelTest, SetMetadata) { + AutofillMetadata metadata; + metadata.use_count = 10; + metadata.use_date = kArbitraryTime; + + TestAutofillDataModel model("guid", std::string()); + EXPECT_TRUE(model.SetMetadata(metadata)); + EXPECT_EQ(metadata.use_count, model.use_count()); + EXPECT_EQ(metadata.use_date, model.use_date()); +} + enum Expectation { GREATER, LESS }; struct CompareFrecencyTestCase { const std::string guid_a;
diff --git a/components/autofill/core/browser/autofill_metadata.h b/components/autofill/core/browser/autofill_metadata.h new file mode 100644 index 0000000..ebaeb22 --- /dev/null +++ b/components/autofill/core/browser/autofill_metadata.h
@@ -0,0 +1,42 @@ +// 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 COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_METADATA_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_METADATA_H_ + +#include <string> + +#include "base/time/time.h" + +namespace autofill { + +// This struct contains the metadata to an autofill data model. It is used to +// abstract the data from the metadata. +struct AutofillMetadata { + public: + AutofillMetadata(){}; + ~AutofillMetadata(){}; + + // The ID for the model. This should be the guid for local data and server_id + // for the server data. + std::string id; + + // The number of times the model has been used. + size_t use_count; + + // The last time the model was used. + base::Time use_date; + + // Only useful for SERVER_PROFILEs. Whether the server profile has been + // converted to a local profile. + bool has_converted; + + // Only useful for SERVER_CARDs. The identifier of the billing address for the + // card. + std::string billing_address_id; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_METADATA_H_
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc index da32d58a..ffe5996 100644 --- a/components/autofill/core/browser/autofill_profile.cc +++ b/components/autofill/core/browser/autofill_profile.cc
@@ -26,6 +26,7 @@ #include "components/autofill/core/browser/address_i18n.h" #include "components/autofill/core/browser/autofill_country.h" #include "components/autofill/core/browser/autofill_field.h" +#include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_profile_comparator.h" #include "components/autofill/core/browser/autofill_type.h" @@ -285,6 +286,25 @@ return *this; } +AutofillMetadata AutofillProfile::GetMetadata() const { + AutofillMetadata metadata = AutofillDataModel::GetMetadata(); + metadata.id = (record_type_ == LOCAL_PROFILE ? guid() : server_id_); + metadata.has_converted = has_converted_; + return metadata; +} + +bool AutofillProfile::SetMetadata(const AutofillMetadata metadata) { + // Make sure the ids matches. + if (metadata.id != (record_type_ == LOCAL_PROFILE ? guid() : server_id_)) + return false; + + if (!AutofillDataModel::SetMetadata(metadata)) + return false; + + has_converted_ = metadata.has_converted; + return true; +} + // TODO(crbug.com/589535): Disambiguate similar field types before uploading. void AutofillProfile::GetMatchingTypes( const base::string16& text,
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h index d928d7f..482878a 100644 --- a/components/autofill/core/browser/autofill_profile.h +++ b/components/autofill/core/browser/autofill_profile.h
@@ -25,6 +25,8 @@ namespace autofill { +struct AutofillMetadata; + // A collection of FormGroups stored in a profile. AutofillProfile also // implements the FormGroup interface so that owners of this object can request // form information from the profile, and the profile will delegate the request @@ -73,6 +75,10 @@ AutofillProfile& operator=(const AutofillProfile& profile); + // AutofillDataModel: + AutofillMetadata GetMetadata() const override; + bool SetMetadata(const AutofillMetadata metadata) override; + // FormGroup: void GetMatchingTypes(const base::string16& text, const std::string& app_locale,
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc index 3e7053c03..75197d85 100644 --- a/components/autofill/core/browser/autofill_profile_unittest.cc +++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -16,6 +16,7 @@ #include "base/strings/string16.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/field_types.h" @@ -1690,4 +1691,78 @@ AutofillProfile::AutofillProfile::CLIENT)); } +TEST(AutofillProfileTest, GetMetadata) { + AutofillProfile local_profile = test::GetFullProfile(); + local_profile.set_use_count(2); + local_profile.set_use_date(base::Time::FromDoubleT(25)); + local_profile.set_has_converted(false); + AutofillMetadata local_metadata = local_profile.GetMetadata(); + EXPECT_EQ(local_profile.guid(), local_metadata.id); + EXPECT_EQ(local_profile.has_converted(), local_metadata.has_converted); + EXPECT_EQ(local_profile.use_count(), local_metadata.use_count); + EXPECT_EQ(local_profile.use_date(), local_metadata.use_date); + + AutofillProfile server_profile = test::GetServerProfile(); + server_profile.set_use_count(10); + server_profile.set_use_date(base::Time::FromDoubleT(100)); + server_profile.set_has_converted(true); + AutofillMetadata server_metadata = server_profile.GetMetadata(); + EXPECT_EQ(server_profile.server_id(), server_metadata.id); + EXPECT_EQ(server_profile.has_converted(), server_metadata.has_converted); + EXPECT_EQ(server_profile.use_count(), server_metadata.use_count); + EXPECT_EQ(server_profile.use_date(), server_metadata.use_date); +} + +TEST(AutofillProfileTest, SetMetadata_MatchingId) { + AutofillProfile local_profile = test::GetFullProfile(); + AutofillMetadata local_metadata; + local_metadata.id = local_profile.guid(); + local_metadata.use_count = 100; + local_metadata.use_date = base::Time::FromDoubleT(50); + local_metadata.has_converted = true; + EXPECT_TRUE(local_profile.SetMetadata(local_metadata)); + EXPECT_EQ(local_metadata.id, local_profile.guid()); + EXPECT_EQ(local_metadata.has_converted, local_profile.has_converted()); + EXPECT_EQ(local_metadata.use_count, local_profile.use_count()); + EXPECT_EQ(local_metadata.use_date, local_profile.use_date()); + + AutofillProfile server_profile = test::GetServerProfile(); + AutofillMetadata server_metadata; + server_metadata.id = server_profile.server_id(); + server_metadata.use_count = 100; + server_metadata.use_date = base::Time::FromDoubleT(50); + server_metadata.has_converted = true; + EXPECT_TRUE(server_profile.SetMetadata(server_metadata)); + EXPECT_EQ(server_metadata.id, server_profile.server_id()); + EXPECT_EQ(server_metadata.has_converted, server_profile.has_converted()); + EXPECT_EQ(server_metadata.use_count, server_profile.use_count()); + EXPECT_EQ(server_metadata.use_date, server_profile.use_date()); +} + +TEST(AutofillProfileTest, SetMetadata_NotMatchingId) { + AutofillProfile local_profile = test::GetFullProfile(); + AutofillMetadata local_metadata; + local_metadata.id = "WrongId"; + local_metadata.use_count = 100; + local_metadata.use_date = base::Time::FromDoubleT(50); + local_metadata.has_converted = true; + EXPECT_FALSE(local_profile.SetMetadata(local_metadata)); + EXPECT_NE(local_metadata.id, local_profile.guid()); + EXPECT_NE(local_metadata.has_converted, local_profile.has_converted()); + EXPECT_NE(local_metadata.use_count, local_profile.use_count()); + EXPECT_NE(local_metadata.use_date, local_profile.use_date()); + + AutofillProfile server_profile = test::GetServerProfile(); + AutofillMetadata server_metadata; + server_metadata.id = "WrongId"; + server_metadata.use_count = 100; + server_metadata.use_date = base::Time::FromDoubleT(50); + server_metadata.has_converted = true; + EXPECT_FALSE(server_profile.SetMetadata(server_metadata)); + EXPECT_NE(server_metadata.id, server_profile.guid()); + EXPECT_NE(server_metadata.has_converted, server_profile.has_converted()); + EXPECT_NE(server_metadata.use_count, server_profile.use_count()); + EXPECT_NE(server_metadata.use_date, server_profile.use_date()); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc index f5df5df..325c2db 100644 --- a/components/autofill/core/browser/autofill_test_utils.cc +++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -428,6 +428,14 @@ return credit_card; } +CreditCard GetFullServerCard() { + CreditCard credit_card(CreditCard::FULL_SERVER_CARD, "c123"); + test::SetCreditCardInfo(&credit_card, "Full Carter", + "4111111111111111" /* Visa */, "12", "2020", "1"); + credit_card.set_card_type(CreditCard::CARD_TYPE_CREDIT); + return credit_card; +} + CreditCard GetRandomCreditCard(CreditCard::RecordType record_type) { static const char* const kNetworks[] = { kAmericanExpressCard,
diff --git a/components/autofill/core/browser/autofill_test_utils.h b/components/autofill/core/browser/autofill_test_utils.h index 0817dcbd8..2e7aebd 100644 --- a/components/autofill/core/browser/autofill_test_utils.h +++ b/components/autofill/core/browser/autofill_test_utils.h
@@ -137,6 +137,9 @@ CreditCard GetMaskedServerCard(); CreditCard GetMaskedServerCardAmex(); +// Returns a full server card full of dummy info. +CreditCard GetFullServerCard(); + // Returns a randomly generated credit card of |record_type|. Note that the // card is not guaranteed to be valid/sane from a card validation standpoint. CreditCard GetRandomCreditCard(CreditCard::RecordType record_Type);
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc index 3c309e8b..0a4a2894 100644 --- a/components/autofill/core/browser/credit_card.cc +++ b/components/autofill/core/browser/credit_card.cc
@@ -29,6 +29,7 @@ #include "build/build_config.h" #include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_field.h" +#include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" @@ -312,6 +313,25 @@ return server_status_; } +AutofillMetadata CreditCard::GetMetadata() const { + AutofillMetadata metadata = AutofillDataModel::GetMetadata(); + metadata.id = (record_type_ == LOCAL_CARD ? guid() : server_id_); + metadata.billing_address_id = billing_address_id_; + return metadata; +} + +bool CreditCard::SetMetadata(const AutofillMetadata metadata) { + // Make sure the ids matches. + if (metadata.id != (record_type_ == LOCAL_CARD ? guid() : server_id_)) + return false; + + if (!AutofillDataModel::SetMetadata(metadata)) + return false; + + billing_address_id_ = metadata.billing_address_id; + return true; +} + base::string16 CreditCard::GetRawInfo(ServerFieldType type) const { DCHECK_EQ(CREDIT_CARD, AutofillType(type).group()); switch (type) {
diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h index 9fa815d..815d788 100644 --- a/components/autofill/core/browser/credit_card.h +++ b/components/autofill/core/browser/credit_card.h
@@ -19,6 +19,8 @@ namespace autofill { +struct AutofillMetadata; + // A midline horizontal ellipsis (U+22EF). extern const base::char16 kMidlineEllipsis[]; @@ -106,6 +108,10 @@ void SetServerStatus(ServerStatus status); ServerStatus GetServerStatus() const; + // AutofillDataModel: + AutofillMetadata GetMetadata() const override; + bool SetMetadata(const AutofillMetadata metadata) override; + // FormGroup: void GetMatchingTypes(const base::string16& text, const std::string& app_locale,
diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc index 05f85fe4..88a452f 100644 --- a/components/autofill/core/browser/credit_card_unittest.cc +++ b/components/autofill/core/browser/credit_card_unittest.cc
@@ -11,6 +11,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_experiments.h" +#include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" @@ -233,6 +234,117 @@ EXPECT_EQ(a, b); } +TEST(CreditCardTest, GetMetadata) { + CreditCard local_card = test::GetCreditCard(); + local_card.set_use_count(2); + local_card.set_use_date(base::Time::FromDoubleT(25)); + local_card.set_billing_address_id("123"); + AutofillMetadata local_metadata = local_card.GetMetadata(); + EXPECT_EQ(local_card.guid(), local_metadata.id); + EXPECT_EQ(local_card.billing_address_id(), local_metadata.billing_address_id); + EXPECT_EQ(local_card.use_count(), local_metadata.use_count); + EXPECT_EQ(local_card.use_date(), local_metadata.use_date); + + CreditCard masked_card = test::GetMaskedServerCard(); + masked_card.set_use_count(4); + masked_card.set_use_date(base::Time::FromDoubleT(50)); + masked_card.set_billing_address_id("abc"); + AutofillMetadata masked_metadata = masked_card.GetMetadata(); + EXPECT_EQ(masked_card.server_id(), masked_metadata.id); + EXPECT_EQ(masked_card.billing_address_id(), + masked_metadata.billing_address_id); + EXPECT_EQ(masked_card.use_count(), masked_metadata.use_count); + EXPECT_EQ(masked_card.use_date(), masked_metadata.use_date); + + CreditCard full_card = test::GetFullServerCard(); + full_card.set_use_count(6); + full_card.set_use_date(base::Time::FromDoubleT(100)); + full_card.set_billing_address_id("xyz"); + AutofillMetadata full_metadata = full_card.GetMetadata(); + EXPECT_EQ(full_card.server_id(), full_metadata.id); + EXPECT_EQ(full_card.billing_address_id(), full_metadata.billing_address_id); + EXPECT_EQ(full_card.use_count(), full_metadata.use_count); + EXPECT_EQ(full_card.use_date(), full_metadata.use_date); +} + +TEST(CreditCardTest, SetMetadata_MatchingId) { + CreditCard local_card = test::GetCreditCard(); + AutofillMetadata local_metadata; + local_metadata.id = local_card.guid(); + local_metadata.use_count = 100; + local_metadata.use_date = base::Time::FromDoubleT(50); + local_metadata.billing_address_id = "billId1"; + EXPECT_TRUE(local_card.SetMetadata(local_metadata)); + EXPECT_EQ(local_metadata.id, local_card.guid()); + EXPECT_EQ(local_metadata.billing_address_id, local_card.billing_address_id()); + EXPECT_EQ(local_metadata.use_count, local_card.use_count()); + EXPECT_EQ(local_metadata.use_date, local_card.use_date()); + + CreditCard masked_card = test::GetMaskedServerCard(); + AutofillMetadata masked_metadata; + masked_metadata.id = masked_card.server_id(); + masked_metadata.use_count = 100; + masked_metadata.use_date = base::Time::FromDoubleT(50); + masked_metadata.billing_address_id = "billId1"; + EXPECT_TRUE(masked_card.SetMetadata(masked_metadata)); + EXPECT_EQ(masked_metadata.id, masked_card.server_id()); + EXPECT_EQ(masked_metadata.billing_address_id, + masked_card.billing_address_id()); + EXPECT_EQ(masked_metadata.use_count, masked_card.use_count()); + EXPECT_EQ(masked_metadata.use_date, masked_card.use_date()); + + CreditCard full_card = test::GetFullServerCard(); + AutofillMetadata full_metadata; + full_metadata.id = full_card.server_id(); + full_metadata.use_count = 100; + full_metadata.use_date = base::Time::FromDoubleT(50); + full_metadata.billing_address_id = "billId1"; + EXPECT_TRUE(full_card.SetMetadata(full_metadata)); + EXPECT_EQ(full_metadata.id, full_card.server_id()); + EXPECT_EQ(full_metadata.billing_address_id, full_card.billing_address_id()); + EXPECT_EQ(full_metadata.use_count, full_card.use_count()); + EXPECT_EQ(full_metadata.use_date, full_card.use_date()); +} + +TEST(CreditCardTest, SetMetadata_NotMatchingId) { + CreditCard local_card = test::GetCreditCard(); + AutofillMetadata local_metadata; + local_metadata.id = "WrongId"; + local_metadata.use_count = 100; + local_metadata.use_date = base::Time::FromDoubleT(50); + local_metadata.billing_address_id = "billId1"; + EXPECT_FALSE(local_card.SetMetadata(local_metadata)); + EXPECT_NE(local_metadata.id, local_card.guid()); + EXPECT_NE(local_metadata.billing_address_id, local_card.billing_address_id()); + EXPECT_NE(local_metadata.use_count, local_card.use_count()); + EXPECT_NE(local_metadata.use_date, local_card.use_date()); + + CreditCard masked_card = test::GetMaskedServerCard(); + AutofillMetadata masked_metadata; + masked_metadata.id = "WrongId"; + masked_metadata.use_count = 100; + masked_metadata.use_date = base::Time::FromDoubleT(50); + masked_metadata.billing_address_id = "billId1"; + EXPECT_FALSE(masked_card.SetMetadata(masked_metadata)); + EXPECT_NE(masked_metadata.id, masked_card.server_id()); + EXPECT_NE(masked_metadata.billing_address_id, + masked_card.billing_address_id()); + EXPECT_NE(masked_metadata.use_count, masked_card.use_count()); + EXPECT_NE(masked_metadata.use_date, masked_card.use_date()); + + CreditCard full_card = test::GetFullServerCard(); + AutofillMetadata full_metadata; + full_metadata.id = "WrongId"; + full_metadata.use_count = 100; + full_metadata.use_date = base::Time::FromDoubleT(50); + full_metadata.billing_address_id = "billId1"; + EXPECT_FALSE(full_card.SetMetadata(full_metadata)); + EXPECT_NE(full_metadata.id, full_card.server_id()); + EXPECT_NE(full_metadata.billing_address_id, full_card.billing_address_id()); + EXPECT_NE(full_metadata.use_count, full_card.use_count()); + EXPECT_NE(full_metadata.use_date, full_card.use_date()); +} + struct SetExpirationYearFromStringTestCase { std::string expiration_year; int expected_year;
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h index 53eea81..236b28d 100644 --- a/components/autofill_assistant/browser/actions/action_delegate.h +++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -67,13 +67,11 @@ virtual void FocusElement(const std::vector<std::string>& selectors, base::OnceCallback<void(bool)> callback) = 0; - // Get the value of all fields in |selector_list| and return the result - // through |callback|. The list of returned values will have the same size as - // |selectors_list|, and will be the empty string in case of error or empty - // value. - virtual void GetFieldsValue( - const std::vector<std::vector<std::string>>& selectors_list, - base::OnceCallback<void(const std::vector<std::string>&)> callback) = 0; + // Get the value of |selectors| and return the result through |callback|. The + // returned value will be the empty string in case of error or empty value. + virtual void GetFieldValue( + const std::vector<std::string>& selectors, + base::OnceCallback<void(const std::string&)> callback) = 0; // Set the |values| of all fields in |selectors_list| and return the result // through |callback|. Selectors and values are one on one matched, i.e. the
diff --git a/components/autofill_assistant/browser/actions/autofill_action.cc b/components/autofill_assistant/browser/actions/autofill_action.cc index 3df90c8..4451e7ae 100644 --- a/components/autofill_assistant/browser/actions/autofill_action.cc +++ b/components/autofill_assistant/browser/actions/autofill_action.cc
@@ -175,33 +175,42 @@ return; } - std::vector<std::vector<std::string>> selectors_list; - for (const auto& required_address_field : - proto_.use_address().required_fields()) { - selectors_list.emplace_back(std::vector<std::string>()); + int required_fields_size = proto_.use_address().required_fields_size(); + required_fields_value_status_.clear(); + required_fields_value_status_.resize(required_fields_size, UNKNOWN); + for (int i = 0; i < required_fields_size; i++) { + const auto& required_address_field = + proto_.use_address().required_fields(i); DCHECK(required_address_field.has_address_field()); DCHECK(!required_address_field.element().selectors().empty()); + std::vector<std::string> selectors; for (const auto& selector : required_address_field.element().selectors()) { - selectors_list.back().emplace_back(selector); + selectors.emplace_back(selector); } + delegate->GetFieldValue( + selectors, + base::BindOnce(&AutofillAction::OnGetRequiredFieldValue, + weak_ptr_factory_.GetWeakPtr(), guid, delegate, + std::move(action_callback), allow_fallback, i)); } - - delegate->GetFieldsValue( - selectors_list, - base::BindOnce(&AutofillAction::OnGetRequiredFieldsValue, - weak_ptr_factory_.GetWeakPtr(), guid, delegate, - std::move(action_callback), allow_fallback)); } -void AutofillAction::OnGetRequiredFieldsValue( +void AutofillAction::OnGetRequiredFieldValue( const std::string& guid, ActionDelegate* delegate, ProcessActionCallback action_callback, bool allow_fallback, - const std::vector<std::string>& values) { + int index, + const std::string& value) { DCHECK(!is_autofill_card_); - DCHECK_EQ(proto_.use_address().required_fields_size(), - static_cast<int>(values.size())); + required_fields_value_status_[index] = value.empty() ? EMPTY : NOT_EMPTY; + + // Wait for the value of all required fields. + for (const auto& status : required_fields_value_status_) { + if (status == UNKNOWN) { + return; + } + } const autofill::AutofillProfile* profile = delegate->GetAutofillProfile(guid); DCHECK(profile); @@ -211,8 +220,8 @@ bool validation_successful = true; std::vector<std::vector<std::string>> failed_selectors; std::vector<std::string> fallback_values; - for (size_t i = 0; i < values.size(); i++) { - if (values[i].empty()) { + for (size_t i = 0; i < required_fields_value_status_.size(); i++) { + if (required_fields_value_status_[i] == EMPTY) { if (!allow_fallback) { // Validation failed and we don't want to try the fallback, so we fail // the action.
diff --git a/components/autofill_assistant/browser/actions/autofill_action.h b/components/autofill_assistant/browser/actions/autofill_action.h index bee8523..4218f08 100644 --- a/components/autofill_assistant/browser/actions/autofill_action.h +++ b/components/autofill_assistant/browser/actions/autofill_action.h
@@ -30,6 +30,8 @@ ProcessActionCallback callback) override; private: + enum FieldValueStatus { UNKNOWN, EMPTY, NOT_EMPTY }; + // Called when the user selected the data. void OnDataSelected(ActionDelegate* delegate, ProcessActionCallback callback, @@ -57,11 +59,12 @@ bool allow_fallback); // Called when we get the value of the required fields. - void OnGetRequiredFieldsValue(const std::string& guid, - ActionDelegate* delegate, - ProcessActionCallback action_callback, - bool allow_fallback, - const std::vector<std::string>& values); + void OnGetRequiredFieldValue(const std::string& guid, + ActionDelegate* delegate, + ProcessActionCallback action_callback, + bool allow_fallback, + int index, + const std::string& value); // Get the value of |address_field| associated to profile |profile|. Return // empty string if there is no data available. @@ -83,6 +86,7 @@ // True if autofilling a card, otherwise we are autofilling an address. bool is_autofill_card_; + std::vector<FieldValueStatus> required_fields_value_status_; base::WeakPtrFactory<AutofillAction> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(AutofillAction);
diff --git a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc index 0b9edceb..5aae1bd 100644 --- a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc +++ b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
@@ -58,14 +58,7 @@ int rounds, ProcessActionCallback callback, bool result) { - bool for_absence = proto_.wait_for_dom().check_for_absence(); - if (for_absence && !result) { - UpdateProcessedAction(true); - std::move(callback).Run(std::move(processed_action_proto_)); - return; - } - - if (!for_absence && result) { + if (result) { UpdateProcessedAction(true); std::move(callback).Run(std::move(processed_action_proto_)); return;
diff --git a/components/autofill_assistant/browser/mock_web_controller.h b/components/autofill_assistant/browser/mock_web_controller.h index 3a70c39..c243260 100644 --- a/components/autofill_assistant/browser/mock_web_controller.h +++ b/components/autofill_assistant/browser/mock_web_controller.h
@@ -38,6 +38,15 @@ MOCK_METHOD2(OnElementExists, void(const std::vector<std::string>& selectors, base::OnceCallback<void(bool)>& callback)); + + void GetFieldValue( + const std::vector<std::string>& selectors, + base::OnceCallback<void(const std::string&)> callback) override { + OnGetFieldValue(selectors, callback); + } + MOCK_METHOD2(OnGetFieldValue, + void(const std::vector<std::string>& selectors, + base::OnceCallback<void(const std::string&)>& callback)); }; } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc index 59f4ef41..d7f3379 100644 --- a/components/autofill_assistant/browser/script_executor.cc +++ b/components/autofill_assistant/browser/script_executor.cc
@@ -86,11 +86,10 @@ delegate_->GetWebController()->FocusElement(selectors, std::move(callback)); } -void ScriptExecutor::GetFieldsValue( - const std::vector<std::vector<std::string>>& selectors_list, - base::OnceCallback<void(const std::vector<std::string>&)> callback) { - delegate_->GetWebController()->GetFieldsValue(selectors_list, - std::move(callback)); +void ScriptExecutor::GetFieldValue( + const std::vector<std::string>& selectors, + base::OnceCallback<void(const std::string&)> callback) { + delegate_->GetWebController()->GetFieldValue(selectors, std::move(callback)); } void ScriptExecutor::SetFieldsValue(
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h index 218f826f..fa9f1fb6 100644 --- a/components/autofill_assistant/browser/script_executor.h +++ b/components/autofill_assistant/browser/script_executor.h
@@ -51,10 +51,9 @@ base::OnceCallback<void(bool)> callback) override; void FocusElement(const std::vector<std::string>& selectors, base::OnceCallback<void(bool)> callback) override; - void GetFieldsValue( - const std::vector<std::vector<std::string>>& selectors_list, - base::OnceCallback<void(const std::vector<std::string>&)> callback) - override; + void GetFieldValue( + const std::vector<std::string>& selectors, + base::OnceCallback<void(const std::string&)> callback) override; void SetFieldsValue( const std::vector<std::vector<std::string>>& selectors_list, const std::vector<std::string>& values,
diff --git a/components/autofill_assistant/browser/script_precondition.cc b/components/autofill_assistant/browser/script_precondition.cc index f632b43d..e324747 100644 --- a/components/autofill_assistant/browser/script_precondition.cc +++ b/components/autofill_assistant/browser/script_precondition.cc
@@ -46,10 +46,16 @@ parameter_match.emplace_back(match); } + std::vector<FormValueMatchProto> form_value_match; + for (const auto& match : proto.form_value_match()) { + form_value_match.emplace_back(match); + } + // TODO(crbug.com/806868): Detect unknown or unsupported conditions and reject // them. return std::make_unique<ScriptPrecondition>( - elements_exist, domain_match, std::move(path_pattern), parameter_match); + elements_exist, domain_match, std::move(path_pattern), parameter_match, + form_value_match); } ScriptPrecondition::~ScriptPrecondition() {} @@ -64,44 +70,60 @@ return; } - if (elements_exist_.empty()) { + pending_preconditions_check_count_ = + elements_exist_.size() + form_value_match_.size(); + if (!pending_preconditions_check_count_) { std::move(callback).Run(true); return; } + // TODO(crbug.com/806868): Instead of running all checks in parallel and + // waiting for all of them to be finished, it might be better to check them + // one by one and fail the precondition early when one fails. check_preconditions_callback_ = std::move(callback); - pending_elements_exist_check_ = 0; + all_preconditions_check_satisfied_ = true; + for (const auto& element : elements_exist_) { - pending_elements_exist_check_++; web_controller->ElementExists( element, base::BindOnce(&ScriptPrecondition::OnCheckElementExists, weak_ptr_factory_.GetWeakPtr())); } + + for (const auto& value_match : form_value_match_) { + DCHECK(!value_match.element().selectors().empty()); + std::vector<std::string> selectors; + for (const auto& selector : value_match.element().selectors()) { + selectors.emplace_back(selector); + } + web_controller->GetFieldValue( + selectors, base::BindOnce(&ScriptPrecondition::OnGetFieldValue, + weak_ptr_factory_.GetWeakPtr())); + } } ScriptPrecondition::ScriptPrecondition( const std::vector<std::vector<std::string>>& elements_exist, const std::set<std::string>& domain_match, std::vector<std::unique_ptr<re2::RE2>> path_pattern, - const std::vector<ScriptParameterMatchProto>& parameter_match) + const std::vector<ScriptParameterMatchProto>& parameter_match, + const std::vector<FormValueMatchProto>& form_value_match) : elements_exist_(elements_exist), + pending_preconditions_check_count_(0), + all_preconditions_check_satisfied_(false), domain_match_(domain_match), path_pattern_(std::move(path_pattern)), parameter_match_(parameter_match), + form_value_match_(form_value_match), weak_ptr_factory_(this) {} void ScriptPrecondition::OnCheckElementExists(bool result) { - pending_elements_exist_check_--; - // Return false early if there is a check failed. + DCHECK_LT(0u, pending_preconditions_check_count_); + pending_preconditions_check_count_--; if (!result) { - std::move(check_preconditions_callback_).Run(false); - return; + all_preconditions_check_satisfied_ = false; } - // Return true if all checks have been completed and there is no failed check. - if (!pending_elements_exist_check_ && check_preconditions_callback_) { - std::move(check_preconditions_callback_).Run(true); - } + MaybeRunCheckPreconditionCallback(); } bool ScriptPrecondition::MatchDomain(const GURL& url) const { @@ -145,4 +167,22 @@ } return true; } + +void ScriptPrecondition::OnGetFieldValue(const std::string& value) { + DCHECK_LT(0u, pending_preconditions_check_count_); + pending_preconditions_check_count_--; + if (value.empty()) { + all_preconditions_check_satisfied_ = false; + } + + MaybeRunCheckPreconditionCallback(); +} + +void ScriptPrecondition::MaybeRunCheckPreconditionCallback() { + if (!pending_preconditions_check_count_ && check_preconditions_callback_) { + std::move(check_preconditions_callback_) + .Run(all_preconditions_check_satisfied_); + } +} + } // namespace autofill_assistant.
diff --git a/components/autofill_assistant/browser/script_precondition.h b/components/autofill_assistant/browser/script_precondition.h index 9bf9b37..210775f 100644 --- a/components/autofill_assistant/browser/script_precondition.h +++ b/components/autofill_assistant/browser/script_precondition.h
@@ -35,7 +35,8 @@ const std::vector<std::vector<std::string>>& elements_exist, const std::set<std::string>& domain_match, std::vector<std::unique_ptr<re2::RE2>> path_pattern, - const std::vector<ScriptParameterMatchProto>& parameter_match); + const std::vector<ScriptParameterMatchProto>& parameter_match, + const std::vector<FormValueMatchProto>& form_value_match); ~ScriptPrecondition(); // Check whether the conditions satisfied and return the result through @@ -50,10 +51,16 @@ bool MatchPath(const GURL& url) const; bool MatchParameters( const std::map<std::string, std::string>& parameters) const; + void OnGetFieldValue(const std::string& value); + + // Return if all checks have been completed and we have not returned anything + // yet. + void MaybeRunCheckPreconditionCallback(); std::vector<std::vector<std::string>> elements_exist_; base::OnceCallback<void(bool)> check_preconditions_callback_; - size_t pending_elements_exist_check_; + size_t pending_preconditions_check_count_; + bool all_preconditions_check_satisfied_; // Domain (exact match) excluding the last '/' character. std::set<std::string> domain_match_; @@ -64,6 +71,9 @@ // Condition on parameters, identified by name, as found in the intent. std::vector<ScriptParameterMatchProto> parameter_match_; + // Conditions on form fields value. + std::vector<FormValueMatchProto> form_value_match_; + base::WeakPtrFactory<ScriptPrecondition> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ScriptPrecondition);
diff --git a/components/autofill_assistant/browser/script_precondition_unittest.cc b/components/autofill_assistant/browser/script_precondition_unittest.cc index e19e119b..dfff053 100644 --- a/components/autofill_assistant/browser/script_precondition_unittest.cc +++ b/components/autofill_assistant/browser/script_precondition_unittest.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/macros.h" +#include "base/run_loop.h" #include "components/autofill_assistant/browser/mock_run_once_callback.h" #include "components/autofill_assistant/browser/mock_web_controller.h" #include "components/autofill_assistant/browser/service.pb.h" @@ -61,6 +62,11 @@ SetUrl("http://www.example.com/path"); ON_CALL(mock_web_controller_, GetUrl()) .WillByDefault(Invoke(this, &ScriptPreconditionTest::GetUrl)); + ON_CALL(mock_web_controller_, OnGetFieldValue(ElementsAre("exists"), _)) + .WillByDefault(RunOnceCallback<1>("foo")); + ON_CALL(mock_web_controller_, + OnGetFieldValue(ElementsAre("does_not_exist"), _)) + .WillByDefault(RunOnceCallback<1>("")); } protected: @@ -197,5 +203,15 @@ EXPECT_FALSE(Check(proto)); } +TEST_F(ScriptPreconditionTest, FormValueMatch) { + ScriptPreconditionProto proto; + FormValueMatchProto* match = proto.add_form_value_match(); + match->mutable_element()->add_selectors("exists"); + EXPECT_TRUE(Check(proto)); + + match->mutable_element()->set_selectors(0, "does_not_exist"); + EXPECT_FALSE(Check(proto)); +} + } // namespace } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto index 2cef1f6..671a3bb7 100644 --- a/components/autofill_assistant/browser/service.proto +++ b/components/autofill_assistant/browser/service.proto
@@ -69,6 +69,8 @@ repeated string domain = 6; // Combined with AND: all matches must be true for precondition to hold. repeated ScriptParameterMatchProto script_parameter_match = 7; + // Combined with AND: all matches must be true for precondition to hold. + repeated FormValueMatchProto form_value_match = 9; } message ScriptParameterMatchProto { @@ -83,6 +85,12 @@ optional string value_equals = 3; } +message FormValueMatchProto { + // Required. The selector associated to the form element whose value should be + // checked. + optional ElementReferenceProto element = 1; +} + enum PolicyType { UNKNOWN_POLICY = 0; SCRIPT = 1; @@ -302,10 +310,6 @@ // Fail after waiting this amount of time. optional int32 timeout_ms = 2; - - // If true, wait for the given element to be absent, otherwise wait for - // existence. - optional bool check_for_absence = 3; } // Volatile upload of a portion of the dom for backend analysis, does not store
diff --git a/components/autofill_assistant/browser/web_controller.cc b/components/autofill_assistant/browser/web_controller.cc index d941614c..8c07096 100644 --- a/components/autofill_assistant/browser/web_controller.cc +++ b/components/autofill_assistant/browser/web_controller.cc
@@ -54,6 +54,10 @@ return true; })"; +// Javascript code to retrieve the 'value' attribute of a node. +const char* const kGetValueAttributeScript = + "function () { return this.value; }"; + } // namespace // static @@ -390,6 +394,13 @@ std::move(callback).Run(result); } +void WebController::OnResult( + const std::string& result, + base::OnceCallback<void(const std::string&)> callback) { + devtools_client_->GetDOM()->Disable(); + std::move(callback).Run(result); +} + void WebController::OnFindElementForFocusElement( base::OnceCallback<void(bool)> callback, std::unique_ptr<FindElementResult> element_result) { @@ -574,15 +585,51 @@ weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } -void WebController::GetFieldsValue( - const std::vector<std::vector<std::string>>& selectors_list, - base::OnceCallback<void(const std::vector<std::string>&)> callback) { - // TODO(crbug.com/806868): Implement get fields value operation. - std::vector<std::string> values; - for (size_t i = 0; i < selectors_list.size(); i++) { - values.emplace_back(""); +void WebController::GetFieldValue( + const std::vector<std::string>& selectors, + base::OnceCallback<void(const std::string&)> callback) { + FindElement( + selectors, + base::BindOnce(&WebController::OnFindElementForGetFieldValue, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void WebController::OnFindElementForGetFieldValue( + base::OnceCallback<void(const std::string&)> callback, + std::unique_ptr<FindElementResult> element_result) { + const std::string object_id = element_result->object_id; + if (object_id.empty()) { + OnResult("", std::move(callback)); + return; } - std::move(callback).Run(values); + + std::vector<std::unique_ptr<runtime::CallArgument>> argument; + argument.emplace_back( + runtime::CallArgument::Builder().SetObjectId(object_id).Build()); + devtools_client_->GetRuntime()->Enable(); + devtools_client_->GetRuntime()->CallFunctionOn( + runtime::CallFunctionOnParams::Builder() + .SetObjectId(object_id) + .SetArguments(std::move(argument)) + .SetFunctionDeclaration(std::string(kGetValueAttributeScript)) + .SetReturnByValue(true) + .Build(), + base::BindOnce(&WebController::OnGetValueAttribute, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void WebController::OnGetValueAttribute( + base::OnceCallback<void(const std::string&)> callback, + std::unique_ptr<runtime::CallFunctionOnResult> result) { + devtools_client_->GetRuntime()->Disable(); + if (!result || result->HasExceptionDetails()) { + OnResult("", std::move(callback)); + return; + } + + // Read the result returned from Javascript code. + DCHECK(result->GetResult()->GetValue()->is_string()); + OnResult(result->GetResult()->GetValue()->GetString(), std::move(callback)); } void WebController::SetFieldsValue(
diff --git a/components/autofill_assistant/browser/web_controller.h b/components/autofill_assistant/browser/web_controller.h index 6d58b52..1e57e87e 100644 --- a/components/autofill_assistant/browser/web_controller.h +++ b/components/autofill_assistant/browser/web_controller.h
@@ -78,13 +78,11 @@ virtual void FocusElement(const std::vector<std::string>& selectors, base::OnceCallback<void(bool)> callback); - // Get the value of all fields in |selector_list| and return the result - // through |callback|. The list of returned values will have the same size as - // |selectors_list|, and will be the empty string in case of error or empty - // value. - virtual void GetFieldsValue( - const std::vector<std::vector<std::string>>& selectors_list, - base::OnceCallback<void(const std::vector<std::string>&)> callback); + // Get the value of |selectors| and return the result through |callback|. The + // returned value will be the empty string in case of error or empty value. + virtual void GetFieldValue( + const std::vector<std::string>& selectors, + base::OnceCallback<void(const std::string&)> callback); // Set the |values| of all fields in |selectors_list| and return the result // through |callback|. Selectors and values are one on one matched, i.e. the @@ -176,6 +174,8 @@ FindElementCallback callback, std::unique_ptr<dom::PushNodesByBackendIdsToFrontendResult> result); void OnResult(bool result, base::OnceCallback<void(bool)> callback); + void OnResult(const std::string& result, + base::OnceCallback<void(const std::string&)> callback); void OnFindElementForFillingForm( const std::string& autofill_data_guid, const std::vector<std::string>& selectors, @@ -204,6 +204,12 @@ std::unique_ptr<FindElementResult> element_result); void OnSelectOption(base::OnceCallback<void(bool)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); + void OnFindElementForGetFieldValue( + base::OnceCallback<void(const std::string&)> callback, + std::unique_ptr<FindElementResult> element_result); + void OnGetValueAttribute( + base::OnceCallback<void(const std::string&)> callback, + std::unique_ptr<runtime::CallFunctionOnResult> result); // Weak pointer is fine here since it must outlive this web controller, which // is guaranteed by the owner of this object.
diff --git a/components/autofill_assistant/browser/web_controller_browsertest.cc b/components/autofill_assistant/browser/web_controller_browsertest.cc index 56506e4..1630d3134 100644 --- a/components/autofill_assistant/browser/web_controller_browsertest.cc +++ b/components/autofill_assistant/browser/web_controller_browsertest.cc
@@ -162,6 +162,24 @@ ASSERT_FALSE(result->object_id.empty()); } + std::string GetFieldValue(const std::vector<std::string>& selectors) { + base::RunLoop run_loop; + std::string result; + web_controller_->GetFieldValue( + selectors, base::BindOnce(&WebControllerBrowserTest::OnGetFieldValue, + base::Unretained(this), + run_loop.QuitClosure(), &result)); + run_loop.Run(); + return result; + } + + void OnGetFieldValue(const base::Closure& done_callback, + std::string* value_output, + const std::string& value) { + *value_output = value; + std::move(done_callback).Run(); + } + private: std::unique_ptr<net::EmbeddedTestServer> http_server_; std::unique_ptr<WebController> web_controller_; @@ -346,4 +364,14 @@ EXPECT_EQ(node.value(), "BODY"); } +IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetFieldValue) { + std::vector<std::string> selectors; + selectors.emplace_back("#input"); + EXPECT_EQ("helloworld", GetFieldValue(selectors)); + + selectors.clear(); + selectors.emplace_back("#invalid_selector"); + EXPECT_EQ("", GetFieldValue(selectors)); +} + } // namespace
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc index 4e602db..a861e9c 100644 --- a/components/browser_sync/profile_sync_components_factory_impl.cc +++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -36,6 +36,7 @@ #include "components/sync/driver/sync_client.h" #include "components/sync/driver/sync_driver_switches.h" #include "components/sync/engine/sync_engine.h" +#include "components/sync/model_impl/forwarding_model_type_controller_delegate.h" #include "components/sync/model_impl/proxy_model_type_controller_delegate.h" #include "components/sync_bookmarks/bookmark_change_processor.h" #include "components/sync_bookmarks/bookmark_data_type_controller.h" @@ -43,6 +44,7 @@ #include "components/sync_bookmarks/bookmark_sync_service.h" #include "components/sync_sessions/session_data_type_controller.h" #include "components/sync_sessions/session_model_type_controller.h" +#include "components/sync_sessions/session_sync_service.h" using base::FeatureList; using bookmarks::BookmarkModel; @@ -249,11 +251,10 @@ controllers.push_back( std::make_unique<sync_sessions::SessionModelTypeController>( sync_client_->GetPrefService(), - std::make_unique<syncer::ProxyModelTypeControllerDelegate>( - ui_thread_, - base::BindRepeating( - &syncer::SyncClient::GetControllerDelegateForModelType, - base::Unretained(sync_client_), syncer::SESSIONS)), + std::make_unique<syncer::ForwardingModelTypeControllerDelegate>( + sync_client_->GetSessionSyncService() + ->GetControllerDelegate() + .get()), history_disabled_pref_)); } else { controllers.push_back(std::make_unique<SessionDataTypeController>(
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc index 12cfe5e..15db980 100644 --- a/components/browser_sync/profile_sync_service.cc +++ b/components/browser_sync/profile_sync_service.cc
@@ -59,11 +59,7 @@ #include "components/sync/syncable/directory.h" #include "components/sync/syncable/syncable_read_transaction.h" #include "components/sync_preferences/pref_service_syncable.h" -#include "components/sync_sessions/favicon_cache.h" -#include "components/sync_sessions/session_data_type_controller.h" -#include "components/sync_sessions/session_sync_bridge.h" -#include "components/sync_sessions/sessions_sync_manager.h" -#include "components/sync_sessions/sync_sessions_client.h" +#include "components/sync_sessions/session_sync_service.h" #include "components/version_info/version_info_values.h" #include "services/identity/public/cpp/identity_manager.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -257,33 +253,6 @@ sync_service_url_, local_device_->GetSyncUserAgent(), url_loader_factory_, syncer::SyncStoppedReporter::ResultCallback()); - // Not all |sync_client_|s will return a sync_sessions::SyncSessionsClient. - sync_sessions::SyncSessionsClient* sync_sessions_client = - sync_client_->GetSyncSessionsClient(); - if (sync_sessions_client) { - if (base::FeatureList::IsEnabled(switches::kSyncUSSSessions)) { - DCHECK(sync_client_->GetSyncSessionsClient()); - sessions_sync_manager_ = - std::make_unique<sync_sessions::SessionSyncBridge>( - sync_client_->GetSyncSessionsClient(), &sync_prefs_, - model_type_store_factory, - base::BindRepeating( - &ProfileSyncService::NotifyForeignSessionUpdated, - sync_enabled_weak_factory_.GetWeakPtr()), - std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( - syncer::SESSIONS, - base::BindRepeating(&syncer::ReportUnrecoverableError, - channel_))); - } else { - sessions_sync_manager_ = - std::make_unique<sync_sessions::SessionsSyncManager>( - sync_client_->GetSyncSessionsClient(), &sync_prefs_, - base::BindRepeating( - &ProfileSyncService::NotifyForeignSessionUpdated, - sync_enabled_weak_factory_.GetWeakPtr())); - } - } - device_info_sync_bridge_ = std::make_unique<syncer::DeviceInfoSyncBridge>( local_device_.get(), model_type_store_factory, std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( @@ -294,22 +263,6 @@ data_type_controllers_ = BuildDataTypeControllerMap( sync_client_->CreateDataTypeControllers(local_device_.get())); - // If |sessions_sync_manager_| is null, make sure that certain data types - // are not enabled. This is because these data types will call into functions - // defined in ProfileSyncService which uses a |sessions_sync_manager_|. - if (!sessions_sync_manager_) { - DCHECK(data_type_controllers_.find(syncer::USER_EVENTS) == - data_type_controllers_.end()); - DCHECK(data_type_controllers_.find(syncer::FAVICON_IMAGES) == - data_type_controllers_.end()); - DCHECK(data_type_controllers_.find(syncer::FAVICON_TRACKING) == - data_type_controllers_.end()); - DCHECK(data_type_controllers_.find(syncer::PROXY_TABS) == - data_type_controllers_.end()); - DCHECK(data_type_controllers_.find(syncer::SESSIONS) == - data_type_controllers_.end()); - } - if (gaia_cookie_manager_service_) gaia_cookie_manager_service_->AddObserver(this); @@ -400,13 +353,7 @@ return nullptr; } - DCHECK(sessions_sync_manager_); - return sessions_sync_manager_->GetOpenTabsUIDelegate(); -} - -sync_sessions::FaviconCache* ProfileSyncService::GetFaviconCache() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return sessions_sync_manager_->GetFaviconCache(); + return sync_client_->GetSessionSyncService()->GetRawOpenTabsUIDelegate(); } syncer::DeviceInfoTracker* ProfileSyncService::GetDeviceInfoTracker() const { @@ -898,11 +845,6 @@ observer.OnSyncCycleCompleted(this); } -void ProfileSyncService::NotifyForeignSessionUpdated() { - for (auto& observer : observers_) - observer.OnForeignSessionUpdated(this); -} - void ProfileSyncService::NotifyShutdown() { for (auto& observer : observers_) observer.OnSyncShutdown(this); @@ -1085,7 +1027,7 @@ !syncer::HasSyncerError(snapshot.model_neutral_state())) { // Trigger garbage collection of old sessions now that we've downloaded // any new session data. - sessions_sync_manager_->ScheduleGarbageCollection(); + sync_client_->GetSessionSyncService()->ScheduleGarbageCollection(); } DVLOG(2) << "Notifying observers sync cycle completed"; NotifySyncCycleCompleted(); @@ -2057,10 +1999,6 @@ return auth_manager_->GetActiveAccountInfo().is_primary; } -syncer::GlobalIdMapper* ProfileSyncService::GetGlobalIdMapper() const { - return sessions_sync_manager_->GetGlobalIdMapper(); -} - base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return sync_js_controller_.AsWeakPtr(); @@ -2169,23 +2107,6 @@ return auth_manager_->access_token(); } -syncer::SyncableService* ProfileSyncService::GetSessionsSyncableService() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!sessions_sync_manager_) - return nullptr; - return sessions_sync_manager_->GetSyncableService(); -} - -base::WeakPtr<syncer::ModelTypeControllerDelegate> -ProfileSyncService::GetSessionSyncControllerDelegate() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!sessions_sync_manager_) - return nullptr; - return sessions_sync_manager_->GetModelTypeSyncBridge() - ->change_processor() - ->GetControllerDelegate(); -} - base::WeakPtr<syncer::ModelTypeControllerDelegate> ProfileSyncService::GetDeviceInfoSyncControllerDelegate() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -2242,6 +2163,12 @@ engine_->FlushDirectory(); } +void ProfileSyncService::NotifyForeignSessionUpdated() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + for (auto& observer : observers_) + observer.OnForeignSessionUpdated(this); +} + base::MessageLoop* ProfileSyncService::GetSyncLoopForTest() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return sync_thread_ ? sync_thread_->message_loop() : nullptr;
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h index 3779277..4b6efca 100644 --- a/components/browser_sync/profile_sync_service.h +++ b/components/browser_sync/profile_sync_service.h
@@ -60,21 +60,13 @@ class SharedURLLoaderFactory; } // namespace network -namespace sync_sessions { -class AbstractSessionsSyncManager; -class FaviconCache; -class OpenTabsUIDelegate; -} // namespace sync_sessions - namespace syncer { class BackendMigrator; class BaseTransaction; class DeviceInfoSyncBridge; class DeviceInfoTracker; -class LocalDeviceInfoProvider; class ModelTypeControllerDelegate; class NetworkResources; -class SyncableService; class SyncTypePreferenceProvider; class TypeDebugInfoObserver; struct CommitCounters; @@ -292,7 +284,6 @@ callback) override; AccountInfo GetAuthenticatedAccountInfo() const override; bool IsAuthenticatedAccountPrimary() const override; - syncer::GlobalIdMapper* GetGlobalIdMapper() const override; // Add a sync type preference provider. Each provider may only be added once. void AddPreferenceProvider(syncer::SyncTypePreferenceProvider* provider); @@ -308,11 +299,6 @@ void SetLocalDeviceInfoProviderForTest( std::unique_ptr<syncer::LocalDeviceInfoProvider> provider); - // Returns the SyncableService or USS bridge for syncer::SESSIONS. - syncer::SyncableService* GetSessionsSyncableService(); - base::WeakPtr<syncer::ModelTypeControllerDelegate> - GetSessionSyncControllerDelegate(); - // Returns the ModelTypeControllerDelegate for syncer::DEVICE_INFO. base::WeakPtr<syncer::ModelTypeControllerDelegate> GetDeviceInfoSyncControllerDelegate(); @@ -444,8 +430,6 @@ // once (before this object is destroyed). void Shutdown() override; - sync_sessions::FaviconCache* GetFaviconCache(); - // Overrides the NetworkResources used for Sync connections. // TODO(treib): Inject this in the ctor instead. As it is, it's possible that // the real NetworkResources were already used before the test had a chance @@ -461,6 +445,12 @@ // killed in the near future. void FlushDirectory() const; + // Notifies observers that foreign sessions have been updated. + // TODO(crbug.com/883199): This doesn't belong here, just like + // OnForeignSessionUpdated() doesn't belong in the observer. Let's move them + // to OpenTabsUIDelegate by introducing a similar observer mechanism. + virtual void NotifyForeignSessionUpdated(); + // Returns a serialized NigoriKey proto generated from the bootstrap token in // SyncPrefs. Will return the empty string if no bootstrap token exists. std::string GetCustomPassphraseKey() const; @@ -548,7 +538,6 @@ void NotifyObservers(); void NotifySyncCycleCompleted(); - void NotifyForeignSessionUpdated(); void NotifyShutdown(); void ClearStaleErrors(); @@ -746,10 +735,6 @@ std::unique_ptr<syncer::LocalDeviceInfoProvider> local_device_; - // Locally owned SyncableService or ModelTypeSyncBridge implementations. - std::unique_ptr<sync_sessions::AbstractSessionsSyncManager> - sessions_sync_manager_; - std::unique_ptr<syncer::DeviceInfoSyncBridge> device_info_sync_bridge_; std::unique_ptr<syncer::NetworkResources> network_resources_;
diff --git a/components/browser_sync/profile_sync_service_mock.h b/components/browser_sync/profile_sync_service_mock.h index 0078459..e34a32d1 100644 --- a/components/browser_sync/profile_sync_service_mock.h +++ b/components/browser_sync/profile_sync_service_mock.h
@@ -56,6 +56,7 @@ MOCK_METHOD0(RequestStart, void()); MOCK_METHOD1(RequestStop, void(ProfileSyncService::SyncStopDataFate)); + MOCK_METHOD0(NotifyForeignSessionUpdated, void()); MOCK_METHOD1(AddObserver, void(syncer::SyncServiceObserver*)); MOCK_METHOD1(RemoveObserver, void(syncer::SyncServiceObserver*)); MOCK_METHOD0(GetJsController, base::WeakPtr<syncer::JsController>());
diff --git a/components/browser_sync/profile_sync_test_util.cc b/components/browser_sync/profile_sync_test_util.cc index 07ab16b5..cc965ce 100644 --- a/components/browser_sync/profile_sync_test_util.cc +++ b/components/browser_sync/profile_sync_test_util.cc
@@ -22,7 +22,6 @@ #include "components/sync/engine/sequenced_model_worker.h" #include "components/sync/engine/ui_model_worker.h" #include "components/sync/model/model_type_store_test_util.h" -#include "components/sync_sessions/local_session_event_router.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_network_connection_tracker.h" @@ -33,21 +32,11 @@ namespace { -class DummyRouter : public sync_sessions::LocalSessionEventRouter { - public: - DummyRouter() {} - ~DummyRouter() override {} - void StartRoutingTo( - sync_sessions::LocalSessionEventHandler* handler) override {} - void Stop() override {} -}; - class BundleSyncClient : public syncer::FakeSyncClient { public: BundleSyncClient(syncer::SyncApiComponentFactory* factory, PrefService* pref_service, syncer::ModelTypeStoreService* model_type_store_service, - sync_sessions::SyncSessionsClient* sync_sessions_client, autofill::PersonalDataManager* personal_data_manager, const base::Callback<base::WeakPtr<syncer::SyncableService>( syncer::ModelType type)>& get_syncable_service_callback, @@ -62,7 +51,6 @@ ~BundleSyncClient() override; PrefService* GetPrefService() override; - sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override; autofill::PersonalDataManager* GetPersonalDataManager() override; base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType( syncer::ModelType type) override; @@ -76,7 +64,6 @@ private: PrefService* const pref_service_; syncer::ModelTypeStoreService* const model_type_store_service_; - sync_sessions::SyncSessionsClient* const sync_sessions_client_; autofill::PersonalDataManager* const personal_data_manager_; const base::Callback<base::WeakPtr<syncer::SyncableService>( syncer::ModelType type)> @@ -94,7 +81,6 @@ syncer::SyncApiComponentFactory* factory, PrefService* pref_service, syncer::ModelTypeStoreService* model_type_store_service, - sync_sessions::SyncSessionsClient* sync_sessions_client, autofill::PersonalDataManager* personal_data_manager, const base::Callback<base::WeakPtr<syncer::SyncableService>( syncer::ModelType type)>& get_syncable_service_callback, @@ -107,7 +93,6 @@ : syncer::FakeSyncClient(factory), pref_service_(pref_service), model_type_store_service_(model_type_store_service), - sync_sessions_client_(sync_sessions_client), personal_data_manager_(personal_data_manager), get_syncable_service_callback_(get_syncable_service_callback), get_sync_service_callback_(get_sync_service_callback), @@ -124,10 +109,6 @@ return pref_service_; } -sync_sessions::SyncSessionsClient* BundleSyncClient::GetSyncSessionsClient() { - return sync_sessions_client_; -} - autofill::PersonalDataManager* BundleSyncClient::GetPersonalDataManager() { return personal_data_manager_; } @@ -238,9 +219,9 @@ ProfileSyncServiceBundle::SyncClientBuilder::Build() { return std::make_unique<BundleSyncClient>( bundle_->component_factory(), bundle_->pref_service(), - &bundle_->model_type_store_service_, bundle_->sync_sessions_client(), - personal_data_manager_, get_syncable_service_callback_, - get_sync_service_callback_, get_bookmark_model_callback_, + &bundle_->model_type_store_service_, personal_data_manager_, + get_syncable_service_callback_, get_sync_service_callback_, + get_bookmark_model_callback_, activate_model_creation_ ? bundle_->db_thread() : nullptr, activate_model_creation_ ? base::SequencedTaskRunnerHandle::Get() : nullptr, @@ -270,11 +251,8 @@ auth_service_.set_auto_post_fetch_response_on_message_loop(true); account_tracker_.Initialize(&pref_service_, base::FilePath()); signin_manager_.Initialize(&pref_service_); - local_session_event_router_ = std::make_unique<DummyRouter>(); identity_provider_ = std::make_unique<invalidation::ProfileIdentityProvider>( identity_manager()); - ON_CALL(sync_sessions_client_, GetLocalSessionEventRouter()) - .WillByDefault(testing::Return(local_session_event_router_.get())); } ProfileSyncServiceBundle::~ProfileSyncServiceBundle() {}
diff --git a/components/browser_sync/profile_sync_test_util.h b/components/browser_sync/profile_sync_test_util.h index 90662510..37915d6 100644 --- a/components/browser_sync/profile_sync_test_util.h +++ b/components/browser_sync/profile_sync_test_util.h
@@ -22,7 +22,6 @@ #include "components/sync/driver/sync_api_component_factory_mock.h" #include "components/sync/model/test_model_type_store_service.h" #include "components/sync_preferences/testing_pref_service_syncable.h" -#include "components/sync_sessions/mock_sync_sessions_client.h" #include "services/identity/public/cpp/identity_manager.h" #include "services/network/test/test_url_loader_factory.h" @@ -34,10 +33,6 @@ class PrefRegistrySyncable; } -namespace sync_sessions { -class LocalSessionEventRouter; -} - namespace browser_sync { // Call this to register preferences needed for ProfileSyncService creation. @@ -144,10 +139,6 @@ return &component_factory_; } - sync_sessions::MockSyncSessionsClient* sync_sessions_client() { - return &sync_sessions_client_; - } - invalidation::ProfileIdentityProvider* identity_provider() { return identity_provider_.get(); } @@ -174,10 +165,6 @@ FakeGaiaCookieManagerService gaia_cookie_manager_service_; identity::IdentityManager identity_manager_; testing::NiceMock<syncer::SyncApiComponentFactoryMock> component_factory_; - std::unique_ptr<sync_sessions::LocalSessionEventRouter> - local_session_event_router_; - testing::NiceMock<sync_sessions::MockSyncSessionsClient> - sync_sessions_client_; std::unique_ptr<invalidation::ProfileIdentityProvider> identity_provider_; invalidation::FakeInvalidationService fake_invalidation_service_; network::TestURLLoaderFactory test_url_loader_factory_;
diff --git a/components/dom_distiller/content/renderer/distiller_native_javascript.cc b/components/dom_distiller/content/renderer/distiller_native_javascript.cc index 3f9321c3e..10c012c 100644 --- a/components/dom_distiller/content/renderer/distiller_native_javascript.cc +++ b/components/dom_distiller/content/renderer/distiller_native_javascript.cc
@@ -54,10 +54,12 @@ v8::Local<v8::Object> javascript_object, const std::string& name, const base::Callback<Sig> callback) { + v8::Local<v8::Context> context = isolate->GetCurrentContext(); // Get the isolate associated with this object. - javascript_object->Set( - gin::StringToSymbol(isolate, name), - gin::CreateFunctionTemplate(isolate, callback)->GetFunction()); + javascript_object->Set(gin::StringToSymbol(isolate, name), + gin::CreateFunctionTemplate(isolate, callback) + ->GetFunction(context) + .ToLocalChecked()); } void DistillerNativeJavaScript::EnsureServiceConnected() {
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc index f53ce4e..cfc076b 100644 --- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc +++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
@@ -397,7 +397,8 @@ return Java_WebContentsDelegateAndroid_getBottomControlsHeight(env, obj); } -bool WebContentsDelegateAndroid::DoBrowserControlsShrinkBlinkSize() const { +bool WebContentsDelegateAndroid::DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env); if (obj.is_null())
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.h b/components/embedder_support/android/delegate/web_contents_delegate_android.h index 643068d..8a48fab 100644 --- a/components/embedder_support/android/delegate/web_contents_delegate_android.h +++ b/components/embedder_support/android/delegate/web_contents_delegate_android.h
@@ -116,7 +116,8 @@ const GURL& url) override; int GetTopControlsHeight() const override; int GetBottomControlsHeight() const override; - bool DoBrowserControlsShrinkBlinkSize() const override; + bool DoBrowserControlsShrinkRendererSize( + const content::WebContents* contents) const override; protected: base::android::ScopedJavaLocalRef<jobject> GetJavaDelegate(JNIEnv* env) const;
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc index 92c7faa4..871246d 100644 --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -70,6 +70,22 @@ const base::Feature kExperimentalKeywordMode{"ExperimentalKeywordMode", base::FEATURE_DISABLED_BY_DEFAULT}; +// Feature used to enable pedal suggestion as either in-suggestion side button +// or dedicated suggestion beneath triggering suggestion. +const base::Feature kOmniboxPedalSuggestions{"OmniboxPedalSuggestions", + base::FEATURE_DISABLED_BY_DEFAULT}; +constexpr base::FeatureParam<OmniboxFieldTrial::PedalSuggestionMode>::Option + kPedalSuggestionModeOptions[] = { + {OmniboxFieldTrial::PedalSuggestionMode::IN_SUGGESTION, + "in_suggestion"}, + {OmniboxFieldTrial::PedalSuggestionMode::DEDICATED, "dedicated"}, +}; +constexpr base::FeatureParam<OmniboxFieldTrial::PedalSuggestionMode> + pedal_suggestion_mode{&kOmniboxPedalSuggestions, + OmniboxFieldTrial::kPedalSuggestionModeParam, + OmniboxFieldTrial::PedalSuggestionMode::DEDICATED, + &kPedalSuggestionModeOptions}; + // Feature used to enable clipboard provider, which provides the user with // suggestions of the URL in the user's clipboard (if any) upon omnibox focus. const base::Feature kEnableClipboardProvider { @@ -748,6 +764,15 @@ base::FeatureList::IsEnabled(features::kExperimentalUi); } +OmniboxFieldTrial::PedalSuggestionMode +OmniboxFieldTrial::GetPedalSuggestionMode() { + // Disabled case is handled specially, as no parameter values are specified. + if (!base::FeatureList::IsEnabled(omnibox::kOmniboxPedalSuggestions)) { + return PedalSuggestionMode::NONE; + } + return omnibox::pedal_suggestion_mode.Get(); +} + bool OmniboxFieldTrial::IsHideSteadyStateUrlSchemeAndSubdomainsEnabled() { #if defined(OS_MACOSX) #if BUILDFLAG(MAC_VIEWS_BROWSER) @@ -857,6 +882,8 @@ const char OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam[] = "UIMaxAutocompleteMatches"; const char OmniboxFieldTrial::kUIVerticalMarginParam[] = "UIVerticalMargin"; +const char OmniboxFieldTrial::kPedalSuggestionModeParam[] = + "PedalSuggestionMode"; const char OmniboxFieldTrial::kZeroSuggestRedirectToChromeExperimentIdParam[] = "ZeroSuggestRedirectToChromeExperimentID";
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h index fc8b6f6..a2cd9c6 100644 --- a/components/omnibox/browser/omnibox_field_trial.h +++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -31,6 +31,7 @@ extern const base::Feature kOmniboxTailSuggestions; extern const base::Feature kOmniboxTabSwitchSuggestions; extern const base::Feature kExperimentalKeywordMode; +extern const base::Feature kOmniboxPedalSuggestions; extern const base::Feature kEnableClipboardProvider; extern const base::Feature kSearchProviderWarmUpOnFocus; extern const base::Feature kZeroSuggestRedirectToChrome; @@ -156,6 +157,13 @@ EMPHASIZE_NEVER = 3 }; + // These are the discrete possibilities for pedal behavior. + enum class PedalSuggestionMode { + NONE, + IN_SUGGESTION, + DEDICATED, + }; + // --------------------------------------------------------- // For any experiment that's part of the bundled omnibox field trial. @@ -428,6 +436,9 @@ // or the #upcoming-ui-features flag is enabled. static bool IsTabSwitchSuggestionsEnabled(); + // Returns the #omnibox-pedal-suggestions feature's mode parameter as enum. + static PedalSuggestionMode GetPedalSuggestionMode(); + // Returns true if either the steady-state elision flag or the // #upcoming-ui-features flag is enabled. static bool IsHideSteadyStateUrlSchemeAndSubdomainsEnabled(); @@ -503,6 +514,7 @@ // Parameter names used by UI experiments. static const char kUIMaxAutocompleteMatchesParam[]; static const char kUIVerticalMarginParam[]; + static const char kPedalSuggestionModeParam[]; // Parameter names used by Zero Suggest Redirect to Chrome. static const char kZeroSuggestRedirectToChromeExperimentIdParam[];
diff --git a/components/onc/docs/onc_spec.md b/components/onc/docs/onc_spec.md index a272f884..ae9813d 100644 --- a/components/onc/docs/onc_spec.md +++ b/components/onc/docs/onc_spec.md
@@ -141,6 +141,63 @@ however it should not be considered an error if no such field is present. --- +## Global Network Configuration + +Field **GlobaNetworkConfiguration** has the [GlobalNetworkConfiguration] +(#GlobalNetworkConfiguration-type) type. + +### GlobalNetworkConfiguration type + +The [GlobalNetworkConfiguration](#GlobalNetworkConfiguration-type) contains +settings which apply to all of the networks that the device may connect to. The +client supports this only in device-level policy; the client-side ONC validator +fails if it appears in user policy. +To avoid bricking devices, these policies will only be enforced in user +sessions. The login screen ignores these policies and may still be used for +fetching new policy or logging in. +A [Help Center article](https://support.google.com/chrome/a/answer/6326250) +warns admins of the implications of mis-using this policy for Chrome OS. + + +* **AllowOnlyPolicyNetworksToAutoconnect** + * (optional, defaults to false) - **boolean** + * When this field is present and set to true, on startup the device will + only auto connect to those networks that are present in its policy. This + is necessary for devices that are used as kiosks, for example, so that + they can’t be hijacked by some other user on startup. + +* **AllowOnlyPolicyNetworksToConnect** + * (optional, defaults to false) - **boolean** + * When this field is present and set to true, only networks present in + policy may be connected to. This allows schools to enforce that only + known-good networks (e.g., filtered student networks) may be used. + Existing connections to unmanaged networks will be disconnected on policy + fetch. + +* **AllowOnlyPolicyNetworksToConnectIfAvailable** + * (optional, defaults to false) - **boolean** + * When this field is present, set to true and a policy network is in range, + only policy networks may be connected to. If no managed network is in + range (e.g. user’s home), the device may connect to any network. If + enabled and a network scan shows a new policy managed network, the device + will automatically switch to the managed network. + +* **BlacklistedHexSSIDs** + * (optional) - **array of string** + * List of strings containing blacklisted hex SSIDs. Networks included in + this list will not be connectable. Existing connections to networks + contained in this list will be disconnected on policy fetch. + +* **DisableNetworkTypes** + * (optional) - **array of string** + * Allowed values are: + * Cellular + * Ethernet + * WiFi + * WiMAX + * Tether + * List of strings containing disabled network interfaces. + ## Network Configuration Field **NetworkConfigurations** is an array of @@ -164,7 +221,7 @@ if **NameServersConfigType** is specified) - **string** * Allowed values are: * *DHCP* - * *Static*. + * *Static* * Determines whether the IP Address configuration is statically configured, see **StaticIPConfig**, or automatically configured using DHCP. @@ -174,7 +231,7 @@ if **IPAddressConfigType** is specified) - **string** * Allowed values are: * *DHCP* - * *Static*. + * *Static* * Determines whether the NameServers configuration is statically configured, see **StaticIPConfig**, or automatically configured using DHCP. @@ -1805,6 +1862,29 @@ * "${PASSWORD}foo" -> "${PASSWORD}foo" +## Recommended Values +When a policy is providing ONC configurations, the assumption is that all values +are mandatory and immutable. To specify values that can be overridden by a user +(e.g. proxy or username), use the **Recommended** property. + +* **Recommended** + * (optional) - **array of string** + * The field(s) with the names in the strings in this array are to be treated + as recommended settings. Any fields not mentioned in this array remain + mandatory. This also means that fields that are not mentioned in the array + and also not mentioned in the objects are mandatory and have the default + value of the field. If not present, all fields are mandatory. Fields that + are objects or arrays of objects included in Recommended will be ignored. In + those cases, the nested objects should have their own Recommended fields. A + special case is if the string "." is included in the list. When this is + present, it means that the entire certificate or network can be forgotten or + deleted by the user. Including the "." has no implications on the rest of + the settings. For instance, a network may have Recommended set to [ "." ], + in which case its settings may not be changed by the user, but the whole + network can be forgotten by the user. The "." is valid in a Certificate + object and the NetworkConfiguration object, it is ignored elsewhere. + + ## Detection This format should be sent in files ending in the .onc extension. When @@ -1831,6 +1911,25 @@ ## Examples +### GlobalNetworkConfiguration Example + +In this example, we only allow managed networks to auto connect and +disallow any other networks if a managed network is available. We also blacklist +the "Guest" network (hex("Guest")=4775657374) and disable Cellular and WiMAX +services. +``` +{ + "Type": "UnencryptedConfiguration", + "GlobalNetworkConfiguration": { + "AllowOnlyPolicyNetworksToAutoconnect": true, + “AllowOnlyPolicyNetworksToConnect”: false, + “AllowOnlyPolicyNetworksToConnectIfAvailable”: true, + “BlacklistedHexSSIDs”: [“4775657374”], + "DisableNetworkTypes": ["Cellular", "WiMAX"] + } +} +``` + ### Simple format example: PEAP/MSCHAPv2 network (per device) ``` @@ -1948,6 +2047,40 @@ } ``` +### Recommended values example + +In this example, the EAP Identity and Password are marked as recommended, i.e. +they can be edited by the user. All other values are mandatory. + +``` +{ + "Type": "UnencryptedConfiguration", + "GlobalNetworkConfiguration": {}, + "NetworkConfigurations": [ + { + "GUID": "{485e6176-dd34-6b6d-1234}", + "Name": "wifi_test", + "Type": "WiFi", + "WiFi": { + "SSID": "wifi_test", + "Security": "WPA-EAP", + "AutoConnect": true, + "EAP": { + "Inner": "MSCHAPv2", + "Outer": "PEAP", + "SaveCredentials": true, + "UseSystemCAs": false, + "Identity": "john-doe", + "Password": "secret-password-123", + "Recommended": ["Identity", "Password"] + } + } + } + } + ] +} +``` + ## Standalone editor
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn index 726fb22a..e2d3371 100644 --- a/components/password_manager/core/browser/BUILD.gn +++ b/components/password_manager/core/browser/BUILD.gn
@@ -76,6 +76,8 @@ "import/password_csv_reader.h", "import/password_importer.cc", "import/password_importer.h", + "invalid_realm_credential_cleaner.cc", + "invalid_realm_credential_cleaner.h", "keychain_migration_status_mac.h", "log_manager.cc", "log_manager.h", @@ -381,6 +383,7 @@ "import/csv_reader_unittest.cc", "import/password_csv_reader_unittest.cc", "import/password_importer_unittest.cc", + "invalid_realm_credential_cleaner_unittest.cc", "log_manager_unittest.cc", "log_router_unittest.cc", "login_database_unittest.cc",
diff --git a/components/password_manager/core/browser/blacklisted_duplicates_cleaner_unittest.cc b/components/password_manager/core/browser/blacklisted_duplicates_cleaner_unittest.cc index eebef9b..f65f18d 100644 --- a/components/password_manager/core/browser/blacklisted_duplicates_cleaner_unittest.cc +++ b/components/password_manager/core/browser/blacklisted_duplicates_cleaner_unittest.cc
@@ -81,7 +81,13 @@ prefs()->registry()->RegisterBooleanPref( prefs::kDuplicatedBlacklistedCredentialsRemoved, false); - password_manager_util::DeleteBlacklistedDuplicates(store(), prefs(), 0); + // In this test we are explicitly only testing the clean up of duplicated + // credentials and setting this true will prevent making another unrelated + // clean-up. + prefs()->registry()->RegisterBooleanPref( + prefs::kCredentialsWithWrongSignonRealmRemoved, true); + + password_manager_util::RemoveUselessCredentials(store(), prefs(), 0); scoped_task_environment.RunUntilIdle(); // Check that one of the next two forms was removed. @@ -93,7 +99,7 @@ EXPECT_FALSE( prefs()->GetBoolean(prefs::kDuplicatedBlacklistedCredentialsRemoved)); - password_manager_util::DeleteBlacklistedDuplicates(store(), prefs(), 0); + password_manager_util::RemoveUselessCredentials(store(), prefs(), 0); scoped_task_environment.RunUntilIdle(); EXPECT_TRUE( prefs()->GetBoolean(prefs::kDuplicatedBlacklistedCredentialsRemoved));
diff --git a/components/password_manager/core/browser/invalid_realm_credential_cleaner.cc b/components/password_manager/core/browser/invalid_realm_credential_cleaner.cc new file mode 100644 index 0000000..aa72fc8 --- /dev/null +++ b/components/password_manager/core/browser/invalid_realm_credential_cleaner.cc
@@ -0,0 +1,242 @@ +// 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/password_manager/core/browser/invalid_realm_credential_cleaner.h" + +#include <algorithm> +#include <map> +#include <set> +#include <string> +#include <tuple> +#include <utility> + +#include "base/strings/string_piece.h" +#include "components/autofill/core/common/password_form.h" +#include "components/password_manager/core/browser/password_store.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/prefs/pref_service.h" +#include "url/gurl.h" + +namespace password_manager { + +namespace { + +using FormVector = std::vector<std::unique_ptr<autofill::PasswordForm>>; + +// This type defines a subset of PasswordForm where the first argument is the +// date_created, the second argument is the origin (excluding protocol), and the +// third argument is the username of the form. +// Excluding protocol from an url means, for example, that "http://google.com/" +// after excluding protocol becomes "google.com/". +using FormKeyForHttpMatch = std::tuple<base::Time, std::string, base::string16>; + +// This type defines a subset of PasswordForm where the first argument is +// the web origin (given by origin.GetOrigin().spec()) and the second +// argument is the username of the form. +using FormKeyForHttpsMatch = std::pair<std::string, base::string16>; + +// This function moves the elements from |forms| for which predicate |p| is true +// to |.first| and the rest of elements to |.second|. +template <typename UnaryPredicate> +std::pair<FormVector, FormVector> SplitFormsBy(FormVector forms, + UnaryPredicate p) { + auto first_false = std::partition(forms.begin(), forms.end(), p); + + return std::make_pair(FormVector(std::make_move_iterator(forms.begin()), + std::make_move_iterator(first_false)), + FormVector(std::make_move_iterator(first_false), + std::make_move_iterator(forms.end()))); +} + +// Returns the fields from PasswordForm necessary to match an HTTPS form with +// an invalid signon_realm with the HTTP form credentials from which HTTPS form +// was created. +FormKeyForHttpMatch GetFormKeyForHttpMatch(const autofill::PasswordForm& form) { + return {form.date_created, form.origin.GetContent(), form.username_value}; +} + +// Returns the fields from PasswordForm necessary to match an HTTPS form with an +// invalid signon_realm with an HTTPS form with a valid signon_realm. This +// function is used only for matching an HTML credential with an invalid +// signon_realm with an HTML credentils with a valid signon_realm. +FormKeyForHttpsMatch GetFormKeyForHttpsMatch( + const autofill::PasswordForm& form) { + DCHECK_EQ(form.scheme, autofill::PasswordForm::Scheme::SCHEME_HTML); + return {form.origin.GetOrigin().spec(), form.username_value}; +} + +// Removes HTML forms with HTTPS protocol which have an invalid signon_realm +// from the password store as follow: +// (1) Credentials with the signon_realm equal to the web origin are ignored. +// (2) Blacklisted credentials with an invalid signom_realm are removed. +// (3) Credentials for which an equivalent HTTP credential exists in the +// password store are removed, relying on migrator to recreate them. +// (4) Credentials for which an equivalent HTTPS credential exists in the +// password store are removed as well, because they are already correctly +// recreated. +// (5) If none of these steps happened then the credentials are not +// fixed and they could not be re-created from HTTP credentials. Thus, this +// function will fix their signon_realm. +// Note that credentials with an invalid signon_realm cannot be fixed without +// checking steps (3) and (4) because it might lead to overwriting the most +// up-to-date password value for that site. +void RemoveHtmlCredentialsWithInvalidRealm( + PasswordStore* store, + const std::map<FormKeyForHttpMatch, std::string>& http_credentials_map, + const std::set<FormKeyForHttpsMatch>& https_credentials_keys, + FormVector https_html_forms) { + DCHECK(std::all_of( + https_html_forms.begin(), https_html_forms.end(), [](const auto& form) { + return form->scheme == autofill::PasswordForm::Scheme::SCHEME_HTML; + })); + + // Ignore credentials which are valid. + base::EraseIf(https_html_forms, [](const auto& form) { + return form->signon_realm == form->origin.GetOrigin().spec(); + }); + + for (const auto& form : https_html_forms) { + store->RemoveLogin(*form); + + if (form->blacklisted_by_user || + base::ContainsKey(http_credentials_map, + GetFormKeyForHttpMatch(*form)) || + base::ContainsKey(https_credentials_keys, + GetFormKeyForHttpsMatch(*form))) { + // If form is blacklisted then it was useless so far. + // If there is an HTTP match then credentials can be recovered. + // If there is an HTTPS match then credentials are already recovered. + // In all cases credentials can be safely removed. + continue; + } + // Fix the signon_realm. + form->signon_realm = form->origin.GetOrigin().spec(); + store->AddLogin(*form); + } +} + +// Removes non-HTML forms with HTTPS protocol which have an invalid signon_realm +// from the password store as follow: +// (1) Search for an HTTP form with the same date of creation, same origin and +// same username. +// (2) If such a corresponding HTTP credential exists then compare their +// signon_realm (excluding protocol). If the signon_realms are different, +// HTTPS credentials will be deleted from the password store. +void RemoveNonHtmlCredentialsWithInvalidRealm( + PasswordStore* store, + const std::map<FormKeyForHttpMatch, std::string>& http_credentials_map, + FormVector https_non_html_forms) { + DCHECK(std::all_of(https_non_html_forms.begin(), https_non_html_forms.end(), + [](const auto& form) { + return form->scheme != + autofill::PasswordForm::Scheme::SCHEME_HTML; + })); + // Credentials with signon_realm different from the origin were not created by + // faulty migration and are ignored. + base::EraseIf(https_non_html_forms, [](const auto& form) { + return form->origin.spec() != form->signon_realm; + }); + + for (const auto& form : https_non_html_forms) { + // Match HTTPS credentials with HTTP credentials if they have same + // date_created, origin (excluding protocol) and username_value. + // Because only forms with signon_realm equal to the origin URL remained at + // this point (see the erasing above), GURL(form->signon_realm) is the same + // as form->origin. + auto it = http_credentials_map.find(GetFormKeyForHttpMatch(*form)); + if (it != http_credentials_map.end() && + it->second != form->origin.GetContent()) { + // The password store contains a corresponding HTTP credential, current + // HTTPS credential being the migrated version of the HTTP credential. + // Thus, they must have the same signon_realm (excluding their + // protocol). Because the current signon_realm (excluding protocol) of + // the HTTPS credential is different from the signon_realm (excluding + // protocol) given by the corresponding HTTP credential (which is the + // good one) means that the HTTPS credential was faulty migrated and + // thus the form can be removed. + store->RemoveLogin(*form); + } + } +} + +} // namespace + +InvalidRealmCredentialCleaner::InvalidRealmCredentialCleaner( + scoped_refptr<PasswordStore> store, + PrefService* prefs) + : store_(std::move(store)), prefs_(prefs) {} + +InvalidRealmCredentialCleaner::~InvalidRealmCredentialCleaner() = default; + +void InvalidRealmCredentialCleaner::StartCleaning(Observer* observer) { + DCHECK(observer); + DCHECK(!observer_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + observer_ = observer; + remaining_cleaning_tasks_ = 2; + store_->GetBlacklistLogins(this); + store_->GetAutofillableLogins(this); +} + +void InvalidRealmCredentialCleaner::OnGetPasswordStoreResults( + FormVector results) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Non HTTP or HTTPS credentials are ignored. + base::EraseIf(results, [](const auto& form) { + return !form->origin.SchemeIsHTTPOrHTTPS(); + }); + + // Separate HTTP and HTTPS credentials. + FormVector http_forms, https_forms; + std::tie(http_forms, https_forms) = SplitFormsBy( + std::move(results), + [](const auto& form) { return form->origin.SchemeIs(url::kHttpScheme); }); + + // Map from (date_created, origin (excluding protocol), username_value) of + // HTTP forms to the expected signon_realm (excluding the protocol). + std::map<FormKeyForHttpMatch, std::string> http_credentials_map; + for (const auto& form : http_forms) { + base::StringPiece signon_realm = form->signon_realm; + // Find the web origin in the signon_realm and remove what is before it. + // This will result in removing the protocol ("http://"). + signon_realm = signon_realm.substr( + signon_realm.find(form->origin.GetOrigin().GetContent())); + http_credentials_map.emplace(GetFormKeyForHttpMatch(*form), signon_realm); + } + + // Separate HTML and non-HTML HTTPS credentials. + FormVector https_html_forms, https_non_html_forms; + std::tie(https_html_forms, https_non_html_forms) = + SplitFormsBy(std::move(https_forms), [](const auto& form) { + return form->scheme == autofill::PasswordForm::Scheme::SCHEME_HTML; + }); + + // This set indicates if the password store contains an HTML form with HTTPS + // protocol with a specific web origin and username. Only forms with the + // correct signon_realm are inserted in this set. + std::set<FormKeyForHttpsMatch> https_credentials_keys; + for (const auto& form : https_html_forms) { + if (form->signon_realm == form->origin.GetOrigin().spec()) + https_credentials_keys.insert(GetFormKeyForHttpsMatch(*form)); + } + + RemoveHtmlCredentialsWithInvalidRealm(store_.get(), http_credentials_map, + https_credentials_keys, + std::move(https_html_forms)); + + RemoveNonHtmlCredentialsWithInvalidRealm(store_.get(), http_credentials_map, + std::move(https_non_html_forms)); + if (--remaining_cleaning_tasks_ == 0) + CleaningFinished(); +} + +void InvalidRealmCredentialCleaner::CleaningFinished() { + // Set the preference in order to avoid calling clean-up again. + prefs_->SetBoolean(prefs::kCredentialsWithWrongSignonRealmRemoved, true); + + observer_->CleaningCompleted(); +} + +} // namespace password_manager \ No newline at end of file
diff --git a/components/password_manager/core/browser/invalid_realm_credential_cleaner.h b/components/password_manager/core/browser/invalid_realm_credential_cleaner.h new file mode 100644 index 0000000..a060b0c0 --- /dev/null +++ b/components/password_manager/core/browser/invalid_realm_credential_cleaner.h
@@ -0,0 +1,78 @@ +// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_INVALID_REALM_CREDENTIAL_CLEANER_H_ +#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_INVALID_REALM_CREDENTIAL_CLEANER_H_ + +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/sequence_checker.h" +#include "components/password_manager/core/browser/credentials_cleaner.h" +#include "components/password_manager/core/browser/password_store_consumer.h" + +namespace autofill { +struct PasswordForm; +} // namespace autofill + +class PrefService; + +namespace password_manager { + +class PasswordStore; + +// This class removes HTTPS credentials with invalid signon_realm created by +// faulty HTTP->HTTPS migration. See https://crbug.com/881731 for details. +// TODO(https://crbug.com/880090): Remove the code once majority of the users +// executed it. +class InvalidRealmCredentialCleaner : public PasswordStoreConsumer, + public CredentialsCleaner { + public: + // The cleaning will be made for credentials from |store|. + // A preference from |prefs| is used to set the cleaning state as finished. + InvalidRealmCredentialCleaner(scoped_refptr<PasswordStore> store, + PrefService* prefs); + + ~InvalidRealmCredentialCleaner() override; + + // CredentialsCleaner: + void StartCleaning(Observer* observer) override; + + // PasswordStoreConsumer: + void OnGetPasswordStoreResults( + std::vector<std::unique_ptr<autofill::PasswordForm>> results) override; + + private: + // After the clean-up is done, this function will inform the |observer_| about + // clean-up completion and set a preference in |prefs_| to true to avoid + // calling clean-up multiple times. + void CleaningFinished(); + + // Clean-up is performed on |store_|. + scoped_refptr<PasswordStore> store_; + + // |prefs_| is not an owning pointer. It is used to record that the clean-up + // happened and thus does not have to happen again. + PrefService* prefs_; + + // Used to signal completion of the clean-up. It is null until + // StartCleaning is called. + Observer* observer_ = nullptr; + + // Indicates the number of responses from PasswordStore remaining to be + // processed. The number will be set in StartCleaning method. + int remaining_cleaning_tasks_ = 0; + + // This guard checks that all operations performed on + // |remaining_cleaning_tasks_| run on the same sequence. + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(InvalidRealmCredentialCleaner); +}; + +} // namespace password_manager + +#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_INVALID_REALM_CREDENTIAL_CLEANER_H_ \ No newline at end of file
diff --git a/components/password_manager/core/browser/invalid_realm_credential_cleaner_unittest.cc b/components/password_manager/core/browser/invalid_realm_credential_cleaner_unittest.cc new file mode 100644 index 0000000..620f0762 --- /dev/null +++ b/components/password_manager/core/browser/invalid_realm_credential_cleaner_unittest.cc
@@ -0,0 +1,404 @@ +// 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/password_manager/core/browser/invalid_realm_credential_cleaner.h" + +#include "base/stl_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.h" +#include "components/password_manager/core/browser/password_manager_util.h" +#include "components/password_manager/core/browser/test_password_store.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/testing_pref_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace password_manager { + +namespace { + +struct MigrationFormsPair { + autofill::PasswordForm http_form; + autofill::PasswordForm migrated_https_form; +}; + +constexpr struct HttpMatchState { + bool same_creation_time; + bool same_origin; + bool same_username; + // This member is just the logical conjunction on the members above. + bool is_matching; +} kHttpMatchStates[] = { + {false, false, false, false}, {false, false, true, false}, + {false, true, false, false}, {false, true, true, false}, + {true, false, false, false}, {true, false, true, false}, + {true, true, false, false}, {true, true, true, true}, +}; + +// |kDates|, |kOrigins|, and |kUsernames| are used to easily manipulate the +// fields of HTTP and HTTPS forms that should be equal. The HTTP forms will +// use the component [1] from these arrays. The HTTPS forms will use [1] if the +// field (given by array name) should be the same and [0] otherwise. Component +// [2] is used when we want to create a form with the field different from both +// ([0] and [1]). +const base::Time kDates[] = {base::Time::FromDoubleT(100), + base::Time::FromDoubleT(200), + base::Time::FromDoubleT(300)}; + +const GURL kOrigins[] = {GURL("https://example.org/path-0/"), + GURL("https://example.org/path-1/"), + GURL("https://google.com/path/")}; + +const base::string16 kUsernames[] = {base::ASCIIToUTF16("user0"), + base::ASCIIToUTF16("user1")}; + +bool StoreContains(TestPasswordStore* store, + const autofill::PasswordForm& form) { + const auto it = store->stored_passwords().find(form.signon_realm); + return it != store->stored_passwords().end() && + base::ContainsValue(it->second, form); +} + +// Returns the HTTP form for given parameters and the migrated version of that +// form. +MigrationFormsPair GetCredentialsFrom(bool is_blacklisted, + bool invalid_signon_realm, + const HttpMatchState& http_match_state) { + autofill::PasswordForm http_form; + http_form.origin = GURL("http://example.org/path-1/"); + http_form.signon_realm = "http://example.org/"; + http_form.date_created = kDates[1]; + http_form.username_value = + (is_blacklisted ? base::string16() : kUsernames[1]); + http_form.blacklisted_by_user = is_blacklisted; + + autofill::PasswordForm https_form; + https_form.origin = kOrigins[http_match_state.same_origin]; + https_form.signon_realm = (invalid_signon_realm ? https_form.origin.spec() + : "https://example.org/"); + https_form.date_created = kDates[http_match_state.same_creation_time]; + https_form.username_value = + (is_blacklisted ? base::string16() + : kUsernames[http_match_state.same_username]); + https_form.blacklisted_by_user = is_blacklisted; + return {http_form, https_form}; +} + +} // namespace + +// This test checks that HTML credentials are correctly removed for the case +// when both (HTTP and HTTPS credentials) are blacklisted, or both are not +// blacklsited. +TEST(InvalidRealmCredentialCleanerTest, + RemoveHtmlCredentialsWithWrongSignonRealm) { + enum class ExpectedOperation { kNothing, kFix, kDelete }; + + static constexpr struct HttpsMatchState { + bool same_signon_realm; + bool same_username; + // This member is just the logical conjunction on the members above. + bool is_matching; + } kHttpsMatchStates[] = {{false, false, false}, + {false, true, false}, + {true, false, false}, + {true, true, true}}; + + struct TestCase { + bool is_blacklisted; + bool invalid_signon_realm; + HttpMatchState http_state; + HttpsMatchState https_state; + ExpectedOperation expected_operation; + }; + + std::vector<TestCase> cases; + for (bool is_blacklisted : {true, false}) { + for (bool invalid_signon_realm : {true, false}) { + for (const HttpMatchState& http_state : kHttpMatchStates) { + for (const HttpsMatchState& https_state : kHttpsMatchStates) { + // This state is invalid since blacklisted credentials have username + // cleared. + if (is_blacklisted && + (!http_state.same_username || !https_state.same_username)) + continue; + + ExpectedOperation expected_operation = ExpectedOperation::kNothing; + if (invalid_signon_realm) { + if (is_blacklisted || http_state.is_matching || + https_state.is_matching) + expected_operation = ExpectedOperation::kDelete; + else + expected_operation = ExpectedOperation::kFix; + } + cases.push_back({is_blacklisted, invalid_signon_realm, http_state, + https_state, expected_operation}); + } + } + } + } + + for (const TestCase& test : cases) { + SCOPED_TRACE(testing::Message() + << "is_blacklisted=" << test.is_blacklisted + << ", invalid_signon_realm=" << test.invalid_signon_realm + << ", http_match=" << test.http_state.is_matching + << ", http_same_username=" << test.http_state.same_username + << ", http_same_creation_time=" + << test.http_state.same_creation_time + << ", http_same_origin=" << test.http_state.same_origin + << ", https_match=" << test.https_state.is_matching + << ", https_same_signon_realm=" + << test.https_state.same_signon_realm + << ", https_ssame_username=" << test.https_state.same_username + << ", expected_operation=" + << static_cast<int>(test.expected_operation)); + + base::test::ScopedTaskEnvironment scoped_task_environment; + auto password_store = base::MakeRefCounted<TestPasswordStore>(); + ASSERT_TRUE(password_store->Init(syncer::SyncableService::StartSyncFlare(), + nullptr)); + + const auto migration_pair = GetCredentialsFrom( + test.is_blacklisted, test.invalid_signon_realm, test.http_state); + + // |https_form| is the form to be tested. + const autofill::PasswordForm& http_form_to_match = migration_pair.http_form; + const autofill::PasswordForm& https_form = + migration_pair.migrated_https_form; + + autofill::PasswordForm https_form_to_match = https_form; + // |https_form| have one of kOrigins[0] or kOrigins[1]. + // If we don't want to match |https_form| with |https_form_to_match| by + // web origin then we can simply use kOrigins[2]. + if (!test.https_state.same_signon_realm) { + https_form_to_match.origin = kOrigins[2]; + } else { + // Make |https_form| and |https_form_to_match| to have different unique + // key. + https_form_to_match.origin = + GURL(https_form_to_match.origin.spec() + "/different/"); + } + + // Make sure that HTTPS credentials we want to match with have valid + // signon_realm. + https_form_to_match.signon_realm = + https_form_to_match.origin.GetOrigin().spec(); + + if (!test.https_state.same_username) + https_form_to_match.username_value += base::ASCIIToUTF16("different"); + // Even if |https_form| and |https_form_to_match| have the same signon_realm + // and username, they have to be created at different date of creation to + // simulate the real behavior when user manually adds credentials for the + // website. + https_form_to_match.date_created = kDates[2]; + + password_store->AddLogin(http_form_to_match); + password_store->AddLogin(https_form); + // The store will save |https_form| twice if it is equals with + // |https_form_to_match|. + password_store->AddLogin(https_form_to_match); + + scoped_task_environment.RunUntilIdle(); + // Check that all credentials were successfully added. + ASSERT_TRUE(StoreContains(password_store.get(), http_form_to_match)); + ASSERT_TRUE(StoreContains(password_store.get(), https_form)); + ASSERT_TRUE(StoreContains(password_store.get(), https_form_to_match)); + + TestingPrefServiceSimple prefs; + // Prevent cleaning of duplicated blacklist entries. + prefs.registry()->RegisterBooleanPref( + prefs::kDuplicatedBlacklistedCredentialsRemoved, true); + prefs.registry()->RegisterBooleanPref( + prefs::kCredentialsWithWrongSignonRealmRemoved, false); + + password_manager_util::RemoveUselessCredentials(password_store, &prefs, 0); + scoped_task_environment.RunUntilIdle(); + + EXPECT_EQ(StoreContains(password_store.get(), https_form), + (test.expected_operation == ExpectedOperation::kNothing)); + + autofill::PasswordForm https_form_fixed = https_form; + https_form_fixed.signon_realm = https_form_fixed.origin.GetOrigin().spec(); + // Check that they are fixed only when we expect them to be fixed. + EXPECT_EQ(StoreContains(password_store.get(), https_form_fixed), + !test.invalid_signon_realm || + (test.expected_operation == ExpectedOperation::kFix)); + EXPECT_TRUE( + prefs.GetBoolean(prefs::kCredentialsWithWrongSignonRealmRemoved)); + + // HTTP form and valid HTTPS form have to stay untouched. + EXPECT_TRUE(StoreContains(password_store.get(), http_form_to_match)); + EXPECT_TRUE(StoreContains(password_store.get(), https_form_to_match)); + + password_store->ShutdownOnUIThread(); + scoped_task_environment.RunUntilIdle(); + } +} + +// This test checks that non-HTML credentials with invalid signon_realm are +// correctly deleted. +TEST(InvalidRealmCredentialCleanerTest, + RemoveNonHtmlCredentialsWithWrongSignonRealm) { + static constexpr struct SignonRealmState { + // Indicates whether HTTPS credentials were faulty migrated (the + // signon_realm contains the whole URL). + bool invalid_signon_realm; + + // Indicates whether HTTP credentials which will be matched with HTTPS + // credentials had empty auth realm. + bool http_empty_realm; + + // Indicates whether HTTPS credentials which were migrated have empty auth + // realm. If |invalid_signon_realm| is true then |https_empty_realm| should + // also be true. + bool https_empty_realm; + + // Indicates whether signon_realms (excluding their protocol) of HTTP + // credentials and migrated HTTPS credentials are matching. + bool matching_signon_realm; + } kSignonRealmStates[]{ + {false, false, false, true}, + {false, false, true, false}, + {false, true, false, false}, + {false, true, true, true}, + // For the next test matching_signon_realm is not + // set true because invalid_signon_realm means that + // HTTPS credentials will consists of the whole URL + // which is different by HTTP signon_realm (excluding protocol). + {true, true, true, false}, + {true, false, true, false}}; + + struct TestCase { + bool is_blacklisted; + HttpMatchState http_state; + SignonRealmState signon_realm_state; + bool delete_expected; + }; + + std::vector<TestCase> cases; + for (bool is_blacklisted : {true, false}) { + for (const HttpMatchState& http_state : kHttpMatchStates) { + for (const SignonRealmState& signon_realm_state : kSignonRealmStates) { + // This state is invalid because blacklisted credentials has username + // cleared. + if (is_blacklisted && !http_state.same_username) + continue; + // This state is invalid because if the signon_realm is valid and there + // is a matching HTTP credential means that the migration was + // successful. So, signon_realms should be the same. If they are not, + // then state is invalid. + if (!signon_realm_state.invalid_signon_realm && + http_state.is_matching && !signon_realm_state.matching_signon_realm) + continue; + cases.push_back({is_blacklisted, http_state, signon_realm_state, + signon_realm_state.invalid_signon_realm & + http_state.is_matching & + !signon_realm_state.matching_signon_realm}); + } + } + } + + for (const TestCase& test : cases) { + SCOPED_TRACE( + testing::Message() + << "is_blacklisted=" << test.is_blacklisted + << ", http_empty_realm=" << test.signon_realm_state.http_empty_realm + << ", https_empty_realm=" << test.signon_realm_state.https_empty_realm + << ", invalid_signon_realm=" + << test.signon_realm_state.invalid_signon_realm + << ", same_creation_time=" << test.http_state.same_creation_time + << ", same_origin=" << test.http_state.same_origin + << ", same_username=" << test.http_state.same_username + << ", delete_expected=" << test.delete_expected); + base::test::ScopedTaskEnvironment scoped_task_environment; + auto password_store = base::MakeRefCounted<TestPasswordStore>(); + ASSERT_TRUE(password_store->Init(syncer::SyncableService::StartSyncFlare(), + nullptr)); + + auto migration_pair = GetCredentialsFrom( + test.is_blacklisted, test.signon_realm_state.invalid_signon_realm, + test.http_state); + autofill::PasswordForm& http_form = migration_pair.http_form; + autofill::PasswordForm& https_form = migration_pair.migrated_https_form; + + http_form.scheme = autofill::PasswordForm::SCHEME_BASIC; + https_form.scheme = autofill::PasswordForm::SCHEME_BASIC; + + // If the signon_realm is invalid that means the auth realm is empty. + if (test.signon_realm_state.invalid_signon_realm) { + ASSERT_TRUE(test.signon_realm_state.https_empty_realm); + } + if (!test.signon_realm_state.http_empty_realm) { + http_form.signon_realm += "realm"; + } + if (!test.signon_realm_state.https_empty_realm) { + https_form.signon_realm += "realm"; + } + + password_store->AddLogin(http_form); + password_store->AddLogin(https_form); + + scoped_task_environment.RunUntilIdle(); + // Check that credentials were successfully added. + ASSERT_TRUE(StoreContains(password_store.get(), http_form)); + ASSERT_TRUE(StoreContains(password_store.get(), https_form)); + + TestingPrefServiceSimple prefs; + // Prevent cleaning of duplicated blacklist entries. + prefs.registry()->RegisterBooleanPref( + prefs::kDuplicatedBlacklistedCredentialsRemoved, true); + prefs.registry()->RegisterBooleanPref( + prefs::kCredentialsWithWrongSignonRealmRemoved, false); + + password_manager_util::RemoveUselessCredentials(password_store, &prefs, 0); + scoped_task_environment.RunUntilIdle(); + + EXPECT_NE(StoreContains(password_store.get(), https_form), + test.delete_expected); + EXPECT_TRUE(StoreContains(password_store.get(), http_form)); + EXPECT_TRUE( + prefs.GetBoolean(prefs::kCredentialsWithWrongSignonRealmRemoved)); + + password_store->ShutdownOnUIThread(); + scoped_task_environment.RunUntilIdle(); + } +} + +// This test checks that credentials that are not HTTP or HTTPS will be +// untouched by the cleaning. +TEST(InvalidRealmCredentialCleanerTest, + NotHttpAndHttpsCredentialsAreNotRemoved) { + base::test::ScopedTaskEnvironment scoped_task_environment; + auto password_store = base::MakeRefCounted<TestPasswordStore>(); + ASSERT_TRUE( + password_store->Init(syncer::SyncableService::StartSyncFlare(), nullptr)); + + autofill::PasswordForm file_url; + file_url.origin = GURL("file://something.html"); + password_store->AddLogin(file_url); + + autofill::PasswordForm ftp_url; + ftp_url.origin = GURL("ftp://ftp.funet.fi/fc959.txt"); + password_store->AddLogin(ftp_url); + + scoped_task_environment.RunUntilIdle(); + TestingPrefServiceSimple prefs; + // Prevent cleaning of duplicated blacklist entries. + prefs.registry()->RegisterBooleanPref( + prefs::kDuplicatedBlacklistedCredentialsRemoved, true); + prefs.registry()->RegisterBooleanPref( + prefs::kCredentialsWithWrongSignonRealmRemoved, false); + + password_manager_util::RemoveUselessCredentials(password_store, &prefs, 0); + scoped_task_environment.RunUntilIdle(); + + // Check that credentials were not deleted. + ASSERT_TRUE(StoreContains(password_store.get(), file_url)); + ASSERT_TRUE(StoreContains(password_store.get(), ftp_url)); + + password_store->ShutdownOnUIThread(); + scoped_task_environment.RunUntilIdle(); +} + +} // namespace password_manager \ No newline at end of file
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc index cfdaf594..89575227 100644 --- a/components/password_manager/core/browser/password_manager.cc +++ b/components/password_manager/core/browser/password_manager.cc
@@ -281,6 +281,9 @@ user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); registry->RegisterBooleanPref(prefs::kDuplicatedBlacklistedCredentialsRemoved, false); + registry->RegisterBooleanPref(prefs::kCredentialsWithWrongSignonRealmRemoved, + false); + #if defined(OS_MACOSX) registry->RegisterIntegerPref( prefs::kKeychainMigrationStatus,
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc index 96990ac..639fc0f 100644 --- a/components/password_manager/core/browser/password_manager_util.cc +++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -20,6 +20,7 @@ #include "components/password_manager/core/browser/credentials_cleaner.h" #include "components/password_manager/core/browser/credentials_cleaner_runner.h" #include "components/password_manager/core/browser/hsts_query.h" +#include "components/password_manager/core/browser/invalid_realm_credential_cleaner.h" #include "components/password_manager/core/browser/log_manager.h" #include "components/password_manager/core/browser/password_generation_manager.h" #include "components/password_manager/core/browser/password_manager.h" @@ -337,20 +338,39 @@ autofill::password_generation::PASSWORD_GENERATION_CONTEXT_MENU_PRESSED); } -void DeleteBlacklistedDuplicates( +void RemoveUselessCredentials( scoped_refptr<password_manager::PasswordStore> store, PrefService* prefs, int delay_in_seconds) { + // TODO(https://crbug.com/887889): Remove the knowledge of the particular + // preferences from this code. + const bool need_to_remove_blacklisted_duplicates = !prefs->GetBoolean( password_manager::prefs::kDuplicatedBlacklistedCredentialsRemoved); base::UmaHistogramBoolean( "PasswordManager.BlacklistedSites.NeedRemoveBlacklistDuplicates", need_to_remove_blacklisted_duplicates); + const bool need_to_remove_invalid_credentials = !prefs->GetBoolean( + password_manager::prefs::kCredentialsWithWrongSignonRealmRemoved); + base::UmaHistogramBoolean( + "PasswordManager.InvalidtHttpsCredentialsNeedToBeCleared", + need_to_remove_invalid_credentials); + // The object will delete itself once the clearing tasks are done. auto* cleaning_tasks_runner = new password_manager::CredentialsCleanerRunner(); + // Cleaning of credentials with invalid signon_realm needs to search for + // blacklisted non-HTML HTTPS credentials for a corresponding HTTP + // credentials. Thus, this clean-up must be done before cleaning blacklisted + // credentials. Otherwise finding a corresponding HTTP credentials will fail. + if (need_to_remove_invalid_credentials) { + cleaning_tasks_runner->AddCleaningTask( + std::make_unique<password_manager::InvalidRealmCredentialCleaner>( + store, prefs)); + } + if (need_to_remove_blacklisted_duplicates) { cleaning_tasks_runner->AddCleaningTask( std::make_unique<password_manager::BlacklistedDuplicatesCleaner>(
diff --git a/components/password_manager/core/browser/password_manager_util.h b/components/password_manager/core/browser/password_manager_util.h index c6912f5..cb80509a 100644 --- a/components/password_manager/core/browser/password_manager_util.h +++ b/components/password_manager/core/browser/password_manager_util.h
@@ -92,9 +92,15 @@ void UserTriggeredManualGenerationFromContextMenu( password_manager::PasswordManagerClient* password_manager_client); -// Two blacklisted forms are considered equal if they have the same -// signon_realm. -void DeleteBlacklistedDuplicates( +// This function handles the following clean-ups of credentials: +// (1) Removing blacklisted duplicates: if two blacklisted credentials have the +// same signon_realm, they are duplicates of each other. Deleting all but one +// sharing the signon_realm does not affect Chrome's behaviour and hence +// duplicates can be removed. Having duplicates makes un-blacklisting not work, +// hence blacklisted duplicates need to be removed. +// (2) Removing or fixing of HTTPS credentials with wrong signon_realm. See +// https://crbug.com/881731 for details. +void RemoveUselessCredentials( scoped_refptr<password_manager::PasswordStore> store, PrefService* prefs, int delay_in_seconds);
diff --git a/components/password_manager/core/browser/password_manager_util_unittest.cc b/components/password_manager/core/browser/password_manager_util_unittest.cc index 832f064..b49c280 100644 --- a/components/password_manager/core/browser/password_manager_util_unittest.cc +++ b/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -5,6 +5,7 @@ #include "components/password_manager/core/browser/password_manager_util.h" #include <memory> +#include <string> #include <utility> #include <vector> @@ -20,6 +21,8 @@ #include "components/password_manager/core/browser/password_manager_test_utils.h" #include "components/password_manager/core/browser/test_password_store.h" #include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/testing_pref_service.h" #include "net/url_request/url_request_test_util.h" #include "services/network/network_context.h" #include "testing/gmock/include/gmock/gmock.h" @@ -45,6 +48,13 @@ return form; } +bool StoreContains(password_manager::TestPasswordStore* store, + const autofill::PasswordForm& form) { + const auto it = store->stored_passwords().find(form.signon_realm); + return it != store->stored_passwords().end() && + base::ContainsValue(it->second, form); +} + // The argument is std::vector<autofill::PasswordForm*>*. The caller is // responsible for the lifetime of all the password forms. ACTION_P(AppendForm, form) { @@ -259,6 +269,125 @@ } #endif // !defined(OS_IOS) +// This test is supposed to check the behavior when: +// 1. User blacklisted on http site two forms (they being considered +// duplicated because they have the same signon_realm). +// 2. They are faulty migrated, resulting in 2 blacklisted invalid credentials. +// Check that both duplicated and invalid credentials are +// correctly deleted. +TEST(PasswordManagerUtil, + RemoveInvalidHttpsCredentialsAndBlacklistedDuplicates) { + for (auto scheme : {autofill::PasswordForm::Scheme::SCHEME_HTML, + autofill::PasswordForm::Scheme::SCHEME_BASIC}) { + SCOPED_TRACE(testing::Message() << "scheme=" << static_cast<int>(scheme)); + + base::test::ScopedTaskEnvironment scoped_task_environment; + auto password_store = + base::MakeRefCounted<password_manager::TestPasswordStore>(); + ASSERT_TRUE(password_store->Init(syncer::SyncableService::StartSyncFlare(), + nullptr)); + + autofill::PasswordForm http_blacklisted; + http_blacklisted.origin = GURL("http://example.com/something/"); + http_blacklisted.signon_realm = "http://example.com/"; + http_blacklisted.blacklisted_by_user = true; + http_blacklisted.date_created = base::Time::FromDoubleT(100); + http_blacklisted.scheme = scheme; + password_store->AddLogin(http_blacklisted); + + // Duplicate version of |http_blacklisted|. + autofill::PasswordForm http_blacklisted_duplicate; + http_blacklisted_duplicate.origin = GURL("http://example.com/something-2/"); + http_blacklisted_duplicate.signon_realm = "http://example.com/"; + http_blacklisted_duplicate.blacklisted_by_user = true; + http_blacklisted_duplicate.date_created = base::Time::FromDoubleT(200); + http_blacklisted_duplicate.scheme = scheme; + password_store->AddLogin(http_blacklisted_duplicate); + + // Migrated version of |http_blacklisted|. + autofill::PasswordForm invalid_blacklisted = http_blacklisted; + invalid_blacklisted.origin = GURL("https://example.com/something/"); + invalid_blacklisted.signon_realm = "https://example.com/something/"; + password_store->AddLogin(invalid_blacklisted); + + // Migrated version of |http_blacklisted_duplicate|. + autofill::PasswordForm invalid_blacklisted_duplicate = + http_blacklisted_duplicate; + invalid_blacklisted_duplicate.origin = + GURL("https://example.com/something-2/"); + invalid_blacklisted_duplicate.signon_realm = + "https://example.com/something-2/"; + password_store->AddLogin(invalid_blacklisted_duplicate); + + // These credentials have to be untouched by cleaning of invalid https but + // one of them has to be removed by function that removes blacklisted + // duplicates. + autofill::PasswordForm https_blacklisted; + https_blacklisted.blacklisted_by_user = true; + https_blacklisted.origin = GURL("https://google.com/something/"); + https_blacklisted.signon_realm = "https://google.com/"; + https_blacklisted.scheme = scheme; + password_store->AddLogin(https_blacklisted); + + autofill::PasswordForm https_blacklisted_duplicate = https_blacklisted; + https_blacklisted_duplicate.origin = + GURL("https://google.com/something-2/"); + https_blacklisted_duplicate.signon_realm = "https://google.com/"; + password_store->AddLogin(https_blacklisted_duplicate); + + scoped_task_environment.RunUntilIdle(); + // Check that all credentials were successfully added. + ASSERT_TRUE(StoreContains(password_store.get(), http_blacklisted)); + ASSERT_TRUE( + StoreContains(password_store.get(), http_blacklisted_duplicate)); + ASSERT_TRUE(StoreContains(password_store.get(), invalid_blacklisted)); + ASSERT_TRUE( + StoreContains(password_store.get(), invalid_blacklisted_duplicate)); + ASSERT_TRUE(StoreContains(password_store.get(), https_blacklisted)); + ASSERT_TRUE( + StoreContains(password_store.get(), https_blacklisted_duplicate)); + + TestingPrefServiceSimple prefs; + prefs.registry()->RegisterBooleanPref( + password_manager::prefs::kDuplicatedBlacklistedCredentialsRemoved, + false); + + prefs.registry()->RegisterBooleanPref( + password_manager::prefs::kCredentialsWithWrongSignonRealmRemoved, + false); + + RemoveUselessCredentials(password_store, &prefs, 0); + scoped_task_environment.RunUntilIdle(); + + // Check that invalid credentials were removed. + EXPECT_FALSE(StoreContains(password_store.get(), invalid_blacklisted)); + EXPECT_FALSE( + StoreContains(password_store.get(), invalid_blacklisted_duplicate)); + + // One of them has to be removed. + EXPECT_NE(StoreContains(password_store.get(), http_blacklisted), + StoreContains(password_store.get(), http_blacklisted_duplicate)); + // One of them has to be removed. + EXPECT_NE(StoreContains(password_store.get(), https_blacklisted), + StoreContains(password_store.get(), https_blacklisted_duplicate)); + + RemoveUselessCredentials(password_store, &prefs, 0); + scoped_task_environment.RunUntilIdle(); + + // Nothing must be removed by a second call. + EXPECT_FALSE(StoreContains(password_store.get(), invalid_blacklisted)); + EXPECT_FALSE( + StoreContains(password_store.get(), invalid_blacklisted_duplicate)); + EXPECT_NE(StoreContains(password_store.get(), http_blacklisted), + StoreContains(password_store.get(), http_blacklisted_duplicate)); + EXPECT_NE(StoreContains(password_store.get(), https_blacklisted), + StoreContains(password_store.get(), https_blacklisted_duplicate)); + + password_store->ShutdownOnUIThread(); + scoped_task_environment.RunUntilIdle(); + } +} + TEST(PasswordManagerUtil, FindBestMatches) { const int kNotFound = -1; struct TestMatch {
diff --git a/components/password_manager/core/common/password_manager_pref_names.cc b/components/password_manager/core/common/password_manager_pref_names.cc index a54e88e..9a99340b 100644 --- a/components/password_manager/core/common/password_manager_pref_names.cc +++ b/components/password_manager/core/common/password_manager_pref_names.cc
@@ -44,6 +44,9 @@ const char kDuplicatedBlacklistedCredentialsRemoved[] = "profile.duplicated_blacklisted_credentials_removed"; +const char kCredentialsWithWrongSignonRealmRemoved[] = + "profile.credentials_with_wrong_signon_realm_removed"; + const char kPasswordHashDataList[] = "profile.password_hash_data_list"; } // namespace prefs
diff --git a/components/password_manager/core/common/password_manager_pref_names.h b/components/password_manager/core/common/password_manager_pref_names.h index 5209543..a978d6e7 100644 --- a/components/password_manager/core/common/password_manager_pref_names.h +++ b/components/password_manager/core/common/password_manager_pref_names.h
@@ -73,6 +73,9 @@ // Whether Chrome deleted blacklisted credentials that were duplicated. extern const char kDuplicatedBlacklistedCredentialsRemoved[]; +// Whether Chrome deleted credentials that had wrong signon_realm. +extern const char kCredentialsWithWrongSignonRealmRemoved[]; + // List that contains captured password hashes. extern const char kPasswordHashDataList[];
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc index 79e01ec..0391266 100644 --- a/components/plugins/renderer/webview_plugin.cc +++ b/components/plugins/renderer/webview_plugin.cc
@@ -262,7 +262,7 @@ content::RenderView::ApplyWebPreferences(preferences, web_view_); WebLocalFrame* web_frame = WebLocalFrame::CreateMainFrame(web_view_, this, nullptr, nullptr); - WebFrameWidget::Create(this, web_frame); + WebFrameWidget::CreateForMainFrame(this, web_frame); } WebViewPlugin::WebViewHelper::~WebViewHelper() {
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc index fc7f0f5..26b88c1d 100644 --- a/components/printing/renderer/print_render_frame_helper.cc +++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -632,10 +632,6 @@ blink::WebLocalFrame* frame_; }; - HeaderAndFooterClient frame_client; - blink::WebLocalFrame* frame = blink::WebLocalFrame::CreateMainFrame( - web_view, &frame_client, nullptr, nullptr); - class NonCompositingWebWidgetClient : public blink::WebWidgetClient { public: // blink::WebWidgetClient implementation. @@ -645,8 +641,12 @@ } }; + HeaderAndFooterClient frame_client; + blink::WebLocalFrame* frame = blink::WebLocalFrame::CreateMainFrame( + web_view, &frame_client, nullptr, nullptr); + NonCompositingWebWidgetClient web_widget_client; - blink::WebFrameWidget::Create(&web_widget_client, frame); + blink::WebFrameWidget::CreateForMainFrame(&web_widget_client, frame); base::Value html(ui::ResourceBundle::GetSharedInstance().GetRawDataResource( IDR_PRINT_HEADER_FOOTER_TEMPLATE_PAGE)); @@ -876,7 +876,7 @@ blink::WebLocalFrame* main_frame = blink::WebLocalFrame::CreateMainFrame(web_view, this, nullptr, nullptr); frame_.Reset(main_frame); - blink::WebFrameWidget::Create(this, main_frame); + blink::WebFrameWidget::CreateForMainFrame(this, main_frame); node_to_print_.Reset(); // When loading is done this will call didStopLoading() and that will do the
diff --git a/components/safe_browsing/password_protection/BUILD.gn b/components/safe_browsing/password_protection/BUILD.gn index c1d76c9..87b9e3f5 100644 --- a/components/safe_browsing/password_protection/BUILD.gn +++ b/components/safe_browsing/password_protection/BUILD.gn
@@ -50,6 +50,7 @@ "//base", "//components/safe_browsing:csd_proto", "//net:net", + "//ui/gfx/geometry:geometry", ] }
diff --git a/components/safe_browsing/password_protection/DEPS b/components/safe_browsing/password_protection/DEPS index 0aea96dc..c305e06 100644 --- a/components/safe_browsing/password_protection/DEPS +++ b/components/safe_browsing/password_protection/DEPS
@@ -9,5 +9,6 @@ "+net", "+services/network/public", "+services/network/test", + "+ui/gfx/geometry", ]
diff --git a/components/safe_browsing/password_protection/metrics_util.cc b/components/safe_browsing/password_protection/metrics_util.cc index 9f5655de..6e6bfa2 100644 --- a/components/safe_browsing/password_protection/metrics_util.cc +++ b/components/safe_browsing/password_protection/metrics_util.cc
@@ -238,4 +238,11 @@ reuse_count); } +void LogContentsSize(const gfx::Size& size) { + if (size.width() <= 0 || size.height() <= 0) + return; + UMA_HISTOGRAM_COUNTS_10000("SafeBrowsing.ContentsSize.Width", size.width()); + UMA_HISTOGRAM_COUNTS_10000("SafeBrowsing.ContentsSize.Height", size.height()); +} + } // namespace safe_browsing
diff --git a/components/safe_browsing/password_protection/metrics_util.h b/components/safe_browsing/password_protection/metrics_util.h index 07577e8..4ffbc45 100644 --- a/components/safe_browsing/password_protection/metrics_util.h +++ b/components/safe_browsing/password_protection/metrics_util.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "components/safe_browsing/proto/csd.pb.h" +#include "ui/gfx/geometry/size.h" namespace base { class TimeTicks; @@ -183,6 +184,9 @@ LoginReputationClientResponse::VerdictType verdict_type, int referrer_chain_size); +// Logs the content area size in DIPs. +void LogContentsSize(const gfx::Size& size); + } // namespace safe_browsing #endif // COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_METRICS_UTIL_H_
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc index 7901ac0..ff07af8 100644 --- a/components/signin/core/browser/account_reconcilor.cc +++ b/components/signin/core/browser/account_reconcilor.cc
@@ -409,10 +409,23 @@ } void AccountReconcilor::FinishReconcileWithMultiloginEndpoint( - const std::vector<gaia::ListedAccount>& gaia_accounts) { + const std::string& primary_account, + const std::vector<std::string>& chrome_accounts, + std::vector<gaia::ListedAccount>&& gaia_accounts) { DCHECK(base::FeatureList::IsEnabled(kUseMultiloginEndpoint)); - NOTIMPLEMENTED(); - // TODO(valeriyas): implement. + + std::vector<std::string> accounts_to_send; + if (delegate_->ReorderChromeAccountsForReconcileIfNeeded( + chrome_accounts, primary_account, gaia_accounts, &accounts_to_send)) { + PerformSetCookiesAction(accounts_to_send); + } else { + OnSetAccountsInCookieCompleted(GoogleServiceAuthError::AuthErrorNone()); + } + // TODO(valeriyas): Log operation here. + if (!is_reconcile_started_) + delegate_->OnReconcileFinished(gaia_accounts[0].id, reconcile_is_noop_); + first_execution_ = false; + ScheduleStartReconcileIfChromeAccountsChanged(); } void AccountReconcilor::OnGaiaAccountsInCookieUpdated( @@ -467,7 +480,9 @@ } if (base::FeatureList::IsEnabled(kUseMultiloginEndpoint)) { - FinishReconcileWithMultiloginEndpoint(std::move(verified_gaia_accounts)); + FinishReconcileWithMultiloginEndpoint(primary_account, + LoadValidAccountsFromTokenService(), + std::move(verified_gaia_accounts)); } else { FinishReconcile(primary_account, LoadValidAccountsFromTokenService(), std::move(verified_gaia_accounts)); @@ -684,8 +699,15 @@ if (error.state() != GoogleServiceAuthError::State::NONE && !error_during_last_reconcile_.IsPersistentError()) { error_during_last_reconcile_ = error; + delegate_->OnReconcileError(error_during_last_reconcile_); } - CalculateIfReconcileIsDone(); + is_reconcile_started_ = false; + + timer_->Stop(); + base::TimeDelta duration = base::Time::Now() - reconcile_start_time_; + signin_metrics::LogSigninAccountReconciliationDuration( + duration, (error_during_last_reconcile_.state() == + GoogleServiceAuthError::State::NONE)); ScheduleStartReconcileIfChromeAccountsChanged(); } }
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h index 3a7b8e1..af197e7 100644 --- a/components/signin/core/browser/account_reconcilor.h +++ b/components/signin/core/browser/account_reconcilor.h
@@ -115,10 +115,13 @@ friend class Lock; friend class AccountReconcilorTest; friend class DiceBrowserTestBase; - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, SigninManagerRegistration); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, Reauth); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, ProfileAlreadyConnected); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestDice, TableRowTest); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + SigninManagerRegistration); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, Reauth); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + ProfileAlreadyConnected); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestTable, TableRowTest); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestMirrorMultilogin, TableRowTest); FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DiceTokenServiceRegistration); FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DiceReconcileWhithoutSignin); FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DiceReconcileNoop); @@ -136,41 +139,55 @@ FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, MigrationClearSecondaryTokens); FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, MigrationClearAllTokens); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, TokensNotLoaded); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + TokensNotLoaded); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, StartReconcileCookiesDisabled); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, StartReconcileContentSettings); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, StartReconcileContentSettingsGaiaUrl); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, StartReconcileContentSettingsNonGaiaUrl); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, StartReconcileContentSettingsInvalidPattern); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, GetAccountsFromCookieSuccess); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, GetAccountsFromCookieFailure); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoop); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoopWithDots); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoopMultiple); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileAddToCookie); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + GetAccountsFromCookieSuccess); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + GetAccountsFromCookieFailure); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + StartReconcileNoop); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + StartReconcileNoopWithDots); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + StartReconcileNoopMultiple); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + StartReconcileAddToCookie); FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, AuthErrorTriggersListAccount); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, SignoutAfterErrorDoesNotRecordUma); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + TokenErrorOnPrimary); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, StartReconcileRemoveFromCookie); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, StartReconcileAddToCookieTwice); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileBadPrimary); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileOnlyOnce); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, Lock); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + StartReconcileBadPrimary); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + StartReconcileOnlyOnce); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, Lock); FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMethodParamTest, StartReconcileWithSessionInfoExpiredDefault); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, AddAccountToCookieCompletedWithBogusAccount); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, NoLoopWithBadPrimary); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, WontMergeAccountsWithError); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + NoLoopWithBadPrimary); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + WontMergeAccountsWithError); FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DelegateTimeoutIsCalled); - FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DelegateTimeoutIsNotCalled); + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, + DelegateTimeoutIsNotCalled); FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DelegateTimeoutIsNotCalledIfTimeoutIsNotReached); @@ -240,7 +257,9 @@ const GoogleServiceAuthError& error) override; void FinishReconcileWithMultiloginEndpoint( - const std::vector<gaia::ListedAccount>& gaia_accounts); + const std::string& primary_account, + const std::vector<std::string>& chrome_accounts, + std::vector<gaia::ListedAccount>&& gaia_accounts); // Lock related methods. void IncrementLockCount();
diff --git a/components/signin/core/browser/account_reconcilor_delegate.cc b/components/signin/core/browser/account_reconcilor_delegate.cc index 867040f4..334667a 100644 --- a/components/signin/core/browser/account_reconcilor_delegate.cc +++ b/components/signin/core/browser/account_reconcilor_delegate.cc
@@ -36,6 +36,14 @@ return std::string(); } +bool AccountReconcilorDelegate::ReorderChromeAccountsForReconcileIfNeeded( + const std::vector<std::string>& chrome_accounts, + const std::string primary_account, + const std::vector<gaia::ListedAccount>& gaia_accounts, + std::vector<std::string>* accounts_to_send) const { + return false; +} + AccountReconcilorDelegate::RevokeTokenOption AccountReconcilorDelegate::ShouldRevokeSecondaryTokensBeforeReconcile( const std::vector<gaia::ListedAccount>& gaia_accounts) {
diff --git a/components/signin/core/browser/account_reconcilor_delegate.h b/components/signin/core/browser/account_reconcilor_delegate.h index d4bdd20..1e4d994 100644 --- a/components/signin/core/browser/account_reconcilor_delegate.h +++ b/components/signin/core/browser/account_reconcilor_delegate.h
@@ -61,6 +61,16 @@ bool first_execution, bool will_logout) const; + // Reorders chrome accounts in the order they should appear in cookies with + // respect to existing cookies. Returns true if the resulting vector is not + // the same as existing vector of gaia accounts (i.e. cookies should be + // rebuilt). + virtual bool ReorderChromeAccountsForReconcileIfNeeded( + const std::vector<std::string>& chrome_accounts, + const std::string primary_account, + const std::vector<gaia::ListedAccount>& gaia_accounts, + std::vector<std::string>* accounts_to_send) const; + // Returns whether secondary accounts should be cleared at the beginning of // the reconcile. virtual RevokeTokenOption ShouldRevokeSecondaryTokensBeforeReconcile(
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc index 5d2756b6..91ec30c 100644 --- a/components/signin/core/browser/account_reconcilor_unittest.cc +++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -15,6 +15,7 @@ #include "base/scoped_observer.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "base/timer/mock_timer.h" #include "build/build_config.h" @@ -193,6 +194,8 @@ MOCK_METHOD1(PerformMergeAction, void(const std::string& account_id)); MOCK_METHOD0(PerformLogoutAllAccountsAction, void()); + MOCK_METHOD1(PerformSetCookiesAction, + void(const std::vector<std::string>& account_id)); }; MockAccountReconcilor::MockAccountReconcilor( @@ -256,6 +259,10 @@ content_settings::Observer* observer, const ContentSettingsPattern& primary_pattern); + void SimulateSetAccountsInCookieCompleted( + GaiaCookieManagerService::Observer* observer, + const GoogleServiceAuthError& error); + GURL get_check_connection_info_url() { return get_check_connection_info_url_; } @@ -280,6 +287,25 @@ DISALLOW_COPY_AND_ASSIGN(AccountReconcilorTest); }; +class AccountReconcilorMirrorEndpointParamTest + : public AccountReconcilorTest, + public ::testing::WithParamInterface<bool> { + public: + AccountReconcilorMirrorEndpointParamTest() = default; + + void SetUp() override { + SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); + if (GetParam()) + scoped_feature_list_.InitAndEnableFeature(kUseMultiloginEndpoint); + } + + protected: + base::test::ScopedFeatureList scoped_feature_list_; + + private: + DISALLOW_COPY_AND_ASSIGN(AccountReconcilorMirrorEndpointParamTest); +}; + // For tests that must be run with multiple account consistency methods. class AccountReconcilorMethodParamTest : public AccountReconcilorTest, @@ -386,6 +412,12 @@ observer->OnAddAccountToCookieCompleted(account_id, error); } +void AccountReconcilorTest::SimulateSetAccountsInCookieCompleted( + GaiaCookieManagerService::Observer* observer, + const GoogleServiceAuthError& error) { + observer->OnSetAccountsInCookieCompleted(error); +} + void AccountReconcilorTest::SimulateCookieContentSettingsChanged( content_settings::Observer* observer, const ContentSettingsPattern& primary_pattern) { @@ -404,244 +436,51 @@ ASSERT_TRUE(reconcilor); } -#if !defined(OS_CHROMEOS) +enum class IsFirstReconcile { + kBoth = 0, + kFirst, + kNotFirst, +}; -// This method requires the use of the |TestSigninClient| to be created from the -// |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded| -// method with an empty implementation. On MacOS, the normal implementation -// causes the try_bots to time out. -TEST_F(AccountReconcilorTest, SigninManagerRegistration) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); - AccountReconcilor* reconcilor = GetMockReconcilor(); - ASSERT_TRUE(reconcilor); - ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService()); - - account_tracker()->SeedAccountInfo("12345", "user@gmail.com"); - signin_manager()->SignIn("12345", "user@gmail.com", "password"); - ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); - - EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); - - signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST, - signin_metrics::SignoutDelete::IGNORE_METRIC); - ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService()); -} - -// This method requires the use of the |TestSigninClient| to be created from the -// |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded| -// method with an empty implementation. On MacOS, the normal implementation -// causes the try_bots to time out. -TEST_F(AccountReconcilorTest, Reauth) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); - const std::string email = "user@gmail.com"; - const std::string account_id = ConnectProfileToAccount("12345", email); - - AccountReconcilor* reconcilor = GetMockReconcilor(); - ASSERT_TRUE(reconcilor); - ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); - - // Simulate reauth. The state of the reconcilor should not change. - signin_manager()->OnExternalSigninCompleted(email); - ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); -} - -#endif // !defined(OS_CHROMEOS) - -TEST_F(AccountReconcilorTest, ProfileAlreadyConnected) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); - ConnectProfileToAccount("12345", "user@gmail.com"); - - AccountReconcilor* reconcilor = GetMockReconcilor(); - ASSERT_TRUE(reconcilor); - ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); -} - -#if BUILDFLAG(ENABLE_DICE_SUPPORT) - -struct AccountReconcilorTestDiceParam { +struct AccountReconcilorTestTableParam { const char* tokens; const char* cookies; - bool is_first_reconcile; + IsFirstReconcile is_first_reconcile; const char* gaia_api_calls; const char* tokens_after_reconcile; const char* cookies_after_reconcile; }; -// Pretty prints a AccountReconcilorTestDiceParam. Used by gtest. -void PrintTo(const AccountReconcilorTestDiceParam& param, ::std::ostream* os) { - *os << "Tokens: " << param.tokens << ". Cookies: " << param.cookies - << ". First reconcile: " << param.is_first_reconcile; +std::vector<AccountReconcilorTestTableParam> GenerateTestCasesFromParams( + const std::vector<AccountReconcilorTestTableParam>& params) { + std::vector<AccountReconcilorTestTableParam> return_params; + for (const AccountReconcilorTestTableParam& param : params) { + if (param.is_first_reconcile == IsFirstReconcile::kBoth) { + AccountReconcilorTestTableParam param_true = param; + param_true.is_first_reconcile = IsFirstReconcile::kFirst; + AccountReconcilorTestTableParam param_false = param; + param_false.is_first_reconcile = IsFirstReconcile::kNotFirst; + return_params.push_back(param_true); + return_params.push_back(param_false); + } else { + return_params.push_back(param); + } + } + return return_params; } -// clang-format off -const AccountReconcilorTestDiceParam kDiceParams[] = { - // This table encodes the initial state and expectations of a reconcile. - // The syntax is: - // - Tokens: - // A, B, C: Accounts for which we have a token in Chrome. - // *: The next account is the main Chrome account (i.e. in SigninManager). - // x: The next account has a token error. - // - Cookies: - // A, B, C: Accounts in the Gaia cookie (returned by ListAccounts). - // x: The next cookie is marked "invalid". - // - First Run: true if this is the first reconcile (i.e. Chrome startup). - // - API calls: - // X: Logout all accounts. - // A, B, C: Merge account. - // ------------------------------------------------------------------------- - // Tokens | Cookies | First Run | Gaia calls | Tokens after | Cookies after - // ------------------------------------------------------------------------- - - // First reconcile (Chrome restart): Rebuild the Gaia cookie to match the - // tokens. Make the Sync account the default account in the Gaia cookie. - // Sync enabled. - { "*AB", "AB", true, "", "*AB", "AB"}, - { "*AB", "BA", true, "XAB", "*AB", "AB"}, - { "*AB", "A", true, "B", "*AB", "AB"}, - { "*AB", "B", true, "XAB", "*AB", "AB"}, - { "*AB", "", true, "AB", "*AB", "AB"}, - // Sync enabled, token error on primary. - { "*xAB", "AB", true, "X", "*xA", ""}, - { "*xAB", "BA", true, "XB", "*xAB", "B"}, - { "*xAB", "A", true, "X", "*xA", ""}, - { "*xAB", "B", true, "", "*xAB", "B"}, - { "*xAB", "", true, "B", "*xAB", "B"}, - // Sync enabled, token error on secondary. - { "*AxB", "AB", true, "XA", "*A", "A"}, - { "*AxB", "BA", true, "XA", "*A", "A"}, - { "*AxB", "A", true, "", "*A", "A"}, - { "*AxB", "B", true, "XA", "*A", "A"}, - { "*AxB", "", true, "A", "*A", "A"}, - // Sync enabled, token error on both accounts. - { "*xAxB", "AB", true, "X", "*xA", ""}, - { "*xAxB", "BA", true, "X", "*xA", ""}, - { "*xAxB", "A", true, "X", "*xA", ""}, - { "*xAxB", "B", true, "X", "*xA", ""}, - { "*xAxB", "", true, "", "*xA", ""}, - // Sync disabled. - { "AB", "AB", true, "", "AB", "AB"}, - { "AB", "BA", true, "", "AB", "BA"}, - { "AB", "A", true, "B", "AB", "AB"}, - { "AB", "B", true, "A", "AB", "BA"}, - { "AB", "", true, "AB", "AB", "AB"}, - // Sync disabled, token error on first account. - { "xAB", "AB", true, "XB", "B", "B"}, - { "xAB", "BA", true, "XB", "B", "B"}, - { "xAB", "A", true, "XB", "B", "B"}, - { "xAB", "B", true, "", "B", "B"}, - { "xAB", "", true, "B", "B", "B"}, - // Sync disabled, token error on second account . - { "AxB", "AB", true, "XA", "A", "A"}, - { "AxB", "BA", true, "XA", "A", "A"}, - { "AxB", "A", true, "", "A", "A"}, - { "AxB", "B", true, "XA", "A", "A"}, - { "AxB", "", true, "A", "A", "A"}, - // Sync disabled, token error on both accounts. - { "xAxB", "AB", true, "X", "", ""}, - { "xAxB", "BA", true, "X", "", ""}, - { "xAxB", "A", true, "X", "", ""}, - { "xAxB", "B", true, "X", "", ""}, - { "xAxB", "", true, "", "", ""}, - - // Chrome is running: Do not change the order of accounts already present in - // the Gaia cookies. - // Sync enabled. - { "*AB", "AB", false, "", "*AB", "AB"}, - { "*AB", "BA", false, "", "*AB", "BA"}, - { "*AB", "A", false, "B", "*AB", "AB"}, - { "*AB", "B", false, "A", "*AB", "BA"}, - { "*AB", "", false, "AB", "*AB", "AB"}, - // Sync enabled, token error on primary. - { "*xAB", "AB", false, "X", "*xA", ""}, - { "*xAB", "BA", false, "XB", "*xAB", "B"}, - { "*xAB", "A", false, "X", "*xA", ""}, - { "*xAB", "B", false, "", "*xAB", "B"}, - { "*xAB", "", false, "B", "*xAB", "B"}, - // Sync enabled, token error on secondary. - { "*AxB", "AB", false, "XA", "*A", "A"}, - { "*AxB", "BA", false, "XA", "*A", "A"}, - { "*AxB", "A", false, "", "*A", "A"}, - { "*AxB", "B", false, "XA", "*A", "A"}, - { "*AxB", "", false, "A", "*A", "A"}, - // Sync enabled, token error on both accounts. - { "*xAxB", "AB", false, "X", "*xA", ""}, - { "*xAxB", "BA", false, "X", "*xA", ""}, - { "*xAxB", "A", false, "X", "*xA", ""}, - { "*xAxB", "B", false, "X", "*xA", ""}, - { "*xAxB", "", false, "", "*xA", ""}, - // Sync disabled. - { "AB", "AB", false, "", "AB", "AB"}, - { "AB", "BA", false, "", "AB", "BA"}, - { "AB", "A", false, "B", "AB", "AB"}, - { "AB", "B", false, "A", "AB", "BA"}, - { "AB", "", false, "AB", "AB", "AB"}, - // Sync disabled, token error on first account. - { "xAB", "AB", false, "X", "", ""}, - { "xAB", "BA", false, "XB", "B", "B"}, - { "xAB", "A", false, "X", "", ""}, - { "xAB", "B", false, "", "B", "B"}, - { "xAB", "", false, "B", "B", "B"}, - // Sync disabled, token error on second account. - { "AxB", "AB", false, "XA", "A", "A"}, - { "AxB", "BA", false, "X", "", ""}, - { "AxB", "A", false, "", "A", "A"}, - { "AxB", "B", false, "X", "", ""}, - { "AxB", "", false, "A", "A", "A"}, - // Sync disabled, token error on both accounts. - { "xAxB", "AB", false, "X", "", ""}, - { "xAxB", "BA", false, "X", "", ""}, - { "xAxB", "A", false, "X", "", ""}, - { "xAxB", "B", false, "X", "", ""}, - { "xAxB", "", false, "", "", ""}, - - // Account marked as invalid in cookies. - // Do not logout. Regression tests for http://crbug.com/854799 - { "", "xA", false, "", "", "xA"}, - { "", "xAxB", false, "", "", "xAxB"}, - { "xA", "xA", false, "", "", "xA"}, - { "xAB", "xAB", false, "", "B", "xAB"}, - { "AxB", "AxC", false, "", "A", "AxC"}, - { "B", "xAB", false, "", "B", "xAB"}, - { "*xA", "xA", false, "", "*xA", "xA"}, - { "*xA", "xB", false, "", "*xA", "xB"}, - { "*xAB", "xAB", false, "", "*xAB", "xAB"}, - // Appending a new cookie after the invalid one. - { "B", "xA", false, "B", "B", "xAB"}, - { "xAB", "xA", false, "B", "B", "xAB"}, - // Cookies can be refreshed in pace, without logout. - { "AB", "xAB", false, "A", "AB", "AB"}, - { "*AB", "xBxA", false, "BA", "*AB", "BA"}, - // Logout when necessary. - { "", "xAB", false, "X", "", ""}, - { "xAB", "xAC", false, "X", "", ""}, - { "xAB", "AxC", false, "X", "", ""}, - { "*xAB", "xABC", false, "X", "*xA", ""}, - { "xAB", "xABC", false, "X", "", ""}, - - // Miscellaneous cases. - // Check that unknown Gaia accounts are signed out. - { "", "A", true, "X", "", ""}, - { "", "A", false, "X", "", ""}, - { "*A", "AB", true, "XA", "*A", "A"}, - { "*A", "AB", false, "XA", "*A", "A"}, - // Check that Gaia default account is kept in first position. - { "AB", "BC", true, "XBA", "AB", "BA"}, - { "AB", "BC", false, "XBA", "AB", "BA"}, - // Required for idempotency check. - { "", "", false, "", "", ""}, - { "*A", "A", false, "", "*A", "A"}, - { "A", "A", false, "", "A", "A"}, - { "B", "B", false, "", "B", "B"}, - { "*xA", "", false, "", "*xA", ""}, - { "*xAB", "B", false, "", "*xAB", "B"}, - { "A", "AxC", false, "", "A", "AxC"}, -}; -// clang-format on +// Pretty prints a AccountReconcilorTestTableParam. Used by gtest. +void PrintTo(const AccountReconcilorTestTableParam& param, ::std::ostream* os) { + *os << "Tokens: " << param.tokens << ". Cookies: " << param.cookies + << ". First reconcile: " + << (param.is_first_reconcile == IsFirstReconcile::kFirst ? "true" + : "false"); +} // Parameterized version of AccountReconcilorTest. -class AccountReconcilorTestDice +class AccountReconcilorTestTable : public AccountReconcilorTest, - public ::testing::WithParamInterface<AccountReconcilorTestDiceParam> { + public ::testing::WithParamInterface<AccountReconcilorTestTableParam> { protected: struct Account { std::string email; @@ -664,7 +503,7 @@ } }; - AccountReconcilorTestDice() { + AccountReconcilorTestTable() { accounts_['A'] = {"a@gmail.com", "A"}; accounts_['B'] = {"b@gmail.com", "B"}; accounts_['C'] = {"c@gmail.com", "C"}; @@ -730,11 +569,13 @@ } // Checks that reconcile is idempotent. - void CheckReconcileIdempotent(const AccountReconcilorTestDiceParam& param) { + void CheckReconcileIdempotent( + const std::vector<AccountReconcilorTestTableParam>& params, + const AccountReconcilorTestTableParam& param) { // Simulate another reconcile based on the results of this one: find the // corresponding row in the table and check that it does nothing. - for (const AccountReconcilorTestDiceParam& row : kDiceParams) { - if (row.is_first_reconcile) + for (const AccountReconcilorTestTableParam& row : params) { + if (row.is_first_reconcile == IsFirstReconcile::kFirst) continue; if (strcmp(row.tokens, param.tokens_after_reconcile) != 0) continue; @@ -763,14 +604,230 @@ std::map<char, Account> accounts_; }; +#if !defined(OS_CHROMEOS) + +// This method requires the use of the |TestSigninClient| to be created from the +// |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded| +// method with an empty implementation. On MacOS, the normal implementation +// causes the try_bots to time out. +TEST_P(AccountReconcilorMirrorEndpointParamTest, SigninManagerRegistration) { + AccountReconcilor* reconcilor = GetMockReconcilor(); + ASSERT_TRUE(reconcilor); + ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService()); + + account_tracker()->SeedAccountInfo("12345", "user@gmail.com"); + signin_manager()->SignIn("12345", "user@gmail.com", "password"); + ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); + + EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); + + signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST, + signin_metrics::SignoutDelete::IGNORE_METRIC); + ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService()); +} + +// This method requires the use of the |TestSigninClient| to be created from the +// |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded| +// method with an empty implementation. On MacOS, the normal implementation +// causes the try_bots to time out. +TEST_P(AccountReconcilorMirrorEndpointParamTest, Reauth) { + const std::string email = "user@gmail.com"; + const std::string account_id = ConnectProfileToAccount("12345", email); + + AccountReconcilor* reconcilor = GetMockReconcilor(); + ASSERT_TRUE(reconcilor); + ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); + + // Simulate reauth. The state of the reconcilor should not change. + signin_manager()->OnExternalSigninCompleted(email); + ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); +} + +#endif // !defined(OS_CHROMEOS) + +TEST_P(AccountReconcilorMirrorEndpointParamTest, ProfileAlreadyConnected) { + ConnectProfileToAccount("12345", "user@gmail.com"); + + AccountReconcilor* reconcilor = GetMockReconcilor(); + ASSERT_TRUE(reconcilor); + ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); +} + +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + +// clang-format off +const std::vector<AccountReconcilorTestTableParam> kDiceParams = { + // This table encodes the initial state and expectations of a reconcile. + // The syntax is: + // - Tokens: + // A, B, C: Accounts for which we have a token in Chrome. + // *: The next account is the main Chrome account (i.e. in SigninManager). + // x: The next account has a token error. + // - Cookies: + // A, B, C: Accounts in the Gaia cookie (returned by ListAccounts). + // x: The next cookie is marked "invalid". + // - First Run: true if this is the first reconcile (i.e. Chrome startup). + // - API calls: + // X: Logout all accounts. + // A, B, C: Merge account. + // ------------------------------------------------------------------------- + // Tokens | Cookies | First Run | Gaia calls | Tokens after | Cookies after + // ------------------------------------------------------------------------- + + // First reconcile (Chrome restart): Rebuild the Gaia cookie to match the + // tokens. Make the Sync account the default account in the Gaia cookie. + // Sync enabled. + { "*AB", "AB", IsFirstReconcile::kFirst, "", "*AB", "AB"}, + { "*AB", "BA", IsFirstReconcile::kFirst, "XAB", "*AB", "AB"}, + { "*AB", "A", IsFirstReconcile::kFirst, "B", "*AB", "AB"}, + { "*AB", "B", IsFirstReconcile::kFirst, "XAB", "*AB", "AB"}, + { "*AB", "", IsFirstReconcile::kFirst, "AB", "*AB", "AB"}, + // Sync enabled, token error on primary. + { "*xAB", "AB", IsFirstReconcile::kFirst, "X", "*xA", ""}, + { "*xAB", "BA", IsFirstReconcile::kFirst, "XB", "*xAB", "B"}, + { "*xAB", "A", IsFirstReconcile::kFirst, "X", "*xA", ""}, + { "*xAB", "B", IsFirstReconcile::kFirst, "", "*xAB", "B"}, + { "*xAB", "", IsFirstReconcile::kFirst, "B", "*xAB", "B"}, + // Sync enabled, token error on secondary. + { "*AxB", "AB", IsFirstReconcile::kFirst, "XA", "*A", "A"}, + { "*AxB", "BA", IsFirstReconcile::kFirst, "XA", "*A", "A"}, + { "*AxB", "A", IsFirstReconcile::kFirst, "", "*A", "A"}, + { "*AxB", "B", IsFirstReconcile::kFirst, "XA", "*A", "A"}, + { "*AxB", "", IsFirstReconcile::kFirst, "A", "*A", "A"}, + // Sync enabled, token error on both accounts. + { "*xAxB", "AB", IsFirstReconcile::kFirst, "X", "*xA", ""}, + { "*xAxB", "BA", IsFirstReconcile::kFirst, "X", "*xA", ""}, + { "*xAxB", "A", IsFirstReconcile::kFirst, "X", "*xA", ""}, + { "*xAxB", "B", IsFirstReconcile::kFirst, "X", "*xA", ""}, + { "*xAxB", "", IsFirstReconcile::kFirst, "", "*xA", ""}, + // Sync disabled. + { "AB", "AB", IsFirstReconcile::kFirst, "", "AB", "AB"}, + { "AB", "BA", IsFirstReconcile::kFirst, "", "AB", "BA"}, + { "AB", "A", IsFirstReconcile::kFirst, "B", "AB", "AB"}, + { "AB", "B", IsFirstReconcile::kFirst, "A", "AB", "BA"}, + { "AB", "", IsFirstReconcile::kFirst, "AB", "AB", "AB"}, + // Sync disabled, token error on first account. + { "xAB", "AB", IsFirstReconcile::kFirst, "XB", "B", "B"}, + { "xAB", "BA", IsFirstReconcile::kFirst, "XB", "B", "B"}, + { "xAB", "A", IsFirstReconcile::kFirst, "XB", "B", "B"}, + { "xAB", "B", IsFirstReconcile::kFirst, "", "B", "B"}, + { "xAB", "", IsFirstReconcile::kFirst, "B", "B", "B"}, + // Sync disabled, token error on second account . + { "AxB", "AB", IsFirstReconcile::kFirst, "XA", "A", "A"}, + { "AxB", "BA", IsFirstReconcile::kFirst, "XA", "A", "A"}, + { "AxB", "A", IsFirstReconcile::kFirst, "", "A", "A"}, + { "AxB", "B", IsFirstReconcile::kFirst, "XA", "A", "A"}, + { "AxB", "", IsFirstReconcile::kFirst, "A", "A", "A"}, + // Sync disabled, token error on both accounts. + { "xAxB", "AB", IsFirstReconcile::kFirst, "X", "", ""}, + { "xAxB", "BA", IsFirstReconcile::kFirst, "X", "", ""}, + { "xAxB", "A", IsFirstReconcile::kFirst, "X", "", ""}, + { "xAxB", "B", IsFirstReconcile::kFirst, "X", "", ""}, + { "xAxB", "", IsFirstReconcile::kFirst, "", "", ""}, + + // Chrome is running: Do not change the order of accounts already present in + // the Gaia cookies. + // Sync enabled. + { "*AB", "AB", IsFirstReconcile::kNotFirst, "", "*AB", "AB"}, + { "*AB", "BA", IsFirstReconcile::kNotFirst, "", "*AB", "BA"}, + { "*AB", "A", IsFirstReconcile::kNotFirst, "B", "*AB", "AB"}, + { "*AB", "B", IsFirstReconcile::kNotFirst, "A", "*AB", "BA"}, + { "*AB", "", IsFirstReconcile::kNotFirst, "AB", "*AB", "AB"}, + // Sync enabled, token error on primary. + { "*xAB", "AB", IsFirstReconcile::kNotFirst, "X", "*xA", ""}, + { "*xAB", "BA", IsFirstReconcile::kNotFirst, "XB", "*xAB", "B"}, + { "*xAB", "A", IsFirstReconcile::kNotFirst, "X", "*xA", ""}, + { "*xAB", "B", IsFirstReconcile::kNotFirst, "", "*xAB", "B"}, + { "*xAB", "", IsFirstReconcile::kNotFirst, "B", "*xAB", "B"}, + // Sync enabled, token error on secondary. + { "*AxB", "AB", IsFirstReconcile::kNotFirst, "XA", "*A", "A"}, + { "*AxB", "BA", IsFirstReconcile::kNotFirst, "XA", "*A", "A"}, + { "*AxB", "A", IsFirstReconcile::kNotFirst, "", "*A", "A"}, + { "*AxB", "B", IsFirstReconcile::kNotFirst, "XA", "*A", "A"}, + { "*AxB", "", IsFirstReconcile::kNotFirst, "A", "*A", "A"}, + // Sync enabled, token error on both accounts. + { "*xAxB", "AB", IsFirstReconcile::kNotFirst, "X", "*xA", ""}, + { "*xAxB", "BA", IsFirstReconcile::kNotFirst, "X", "*xA", ""}, + { "*xAxB", "A", IsFirstReconcile::kNotFirst, "X", "*xA", ""}, + { "*xAxB", "B", IsFirstReconcile::kNotFirst, "X", "*xA", ""}, + { "*xAxB", "", IsFirstReconcile::kNotFirst, "", "*xA", ""}, + // Sync disabled. + { "AB", "AB", IsFirstReconcile::kNotFirst, "", "AB", "AB"}, + { "AB", "BA", IsFirstReconcile::kNotFirst, "", "AB", "BA"}, + { "AB", "A", IsFirstReconcile::kNotFirst, "B", "AB", "AB"}, + { "AB", "B", IsFirstReconcile::kNotFirst, "A", "AB", "BA"}, + { "AB", "", IsFirstReconcile::kNotFirst, "AB", "AB", "AB"}, + // Sync disabled, token error on first account. + { "xAB", "AB", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "xAB", "BA", IsFirstReconcile::kNotFirst, "XB", "B", "B"}, + { "xAB", "A", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "xAB", "B", IsFirstReconcile::kNotFirst, "", "B", "B"}, + { "xAB", "", IsFirstReconcile::kNotFirst, "B", "B", "B"}, + // Sync disabled, token error on second account. + { "AxB", "AB", IsFirstReconcile::kNotFirst, "XA", "A", "A"}, + { "AxB", "BA", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "AxB", "A", IsFirstReconcile::kNotFirst, "", "A", "A"}, + { "AxB", "B", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "AxB", "", IsFirstReconcile::kNotFirst, "A", "A", "A"}, + // Sync disabled, token error on both accounts. + { "xAxB", "AB", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "xAxB", "BA", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "xAxB", "A", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "xAxB", "B", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "xAxB", "", IsFirstReconcile::kNotFirst, "", "", ""}, + + // Account marked as invalid in cookies. + // Do not logout. Regression tests for http://crbug.com/854799 + { "", "xA", IsFirstReconcile::kNotFirst, "", "", "xA"}, + { "", "xAxB", IsFirstReconcile::kNotFirst, "", "", "xAxB"}, + { "xA", "xA", IsFirstReconcile::kNotFirst, "", "", "xA"}, + { "xAB", "xAB", IsFirstReconcile::kNotFirst, "", "B", "xAB"}, + { "AxB", "AxC", IsFirstReconcile::kNotFirst, "", "A", "AxC"}, + { "B", "xAB", IsFirstReconcile::kNotFirst, "", "B", "xAB"}, + { "*xA", "xA", IsFirstReconcile::kNotFirst, "", "*xA", "xA"}, + { "*xA", "xB", IsFirstReconcile::kNotFirst, "", "*xA", "xB"}, + { "*xAB", "xAB", IsFirstReconcile::kNotFirst, "", "*xAB", "xAB"}, + // Appending a new cookie after the invalid one. + { "B", "xA", IsFirstReconcile::kNotFirst, "B", "B", "xAB"}, + { "xAB", "xA", IsFirstReconcile::kNotFirst, "B", "B", "xAB"}, + // Cookies can be refreshed in pace, without logout. + { "AB", "xAB", IsFirstReconcile::kNotFirst, "A", "AB", "AB"}, + { "*AB", "xBxA", IsFirstReconcile::kNotFirst, "BA", "*AB", "BA"}, + // Logout when necessary. + { "", "xAB", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "xAB", "xAC", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "xAB", "AxC", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "*xAB", "xABC", IsFirstReconcile::kNotFirst, "X", "*xA", ""}, + { "xAB", "xABC", IsFirstReconcile::kNotFirst, "X", "", ""}, + + // Miscellaneous cases. + // Check that unknown Gaia accounts are signed out. + { "", "A", IsFirstReconcile::kFirst, "X", "", ""}, + { "", "A", IsFirstReconcile::kNotFirst, "X", "", ""}, + { "*A", "AB", IsFirstReconcile::kFirst, "XA", "*A", "A"}, + { "*A", "AB", IsFirstReconcile::kNotFirst, "XA", "*A", "A"}, + // Check that Gaia default account is kept in first position. + { "AB", "BC", IsFirstReconcile::kFirst, "XBA", "AB", "BA"}, + { "AB", "BC", IsFirstReconcile::kNotFirst, "XBA", "AB", "BA"}, + // Required for idempotency check. + { "", "", IsFirstReconcile::kNotFirst, "", "", ""}, + { "*A", "A", IsFirstReconcile::kNotFirst, "", "*A", "A"}, + { "A", "A", IsFirstReconcile::kNotFirst, "", "A", "A"}, + { "B", "B", IsFirstReconcile::kNotFirst, "", "B", "B"}, + { "*xA", "", IsFirstReconcile::kNotFirst, "", "*xA", ""}, + { "*xAB", "B", IsFirstReconcile::kNotFirst, "", "*xAB", "B"}, + { "A", "AxC", IsFirstReconcile::kNotFirst, "", "A", "AxC"}, +}; +// clang-format on + // Checks one row of the kDiceParams table above. -TEST_P(AccountReconcilorTestDice, TableRowTest) { +TEST_P(AccountReconcilorTestTable, TableRowTest) { // Enable Dice. SetAccountConsistency(signin::AccountConsistencyMethod::kDice); // Check that reconcile is idempotent: when called twice in a row it should do // nothing on the second call. - CheckReconcileIdempotent(GetParam()); + CheckReconcileIdempotent(kDiceParams, GetParam()); // Setup tokens. std::vector<Token> tokens_before_reconcile = @@ -832,7 +889,8 @@ // Reconcile. AccountReconcilor* reconcilor = GetMockReconcilor(); ASSERT_TRUE(reconcilor->first_execution_); - reconcilor->first_execution_ = GetParam().is_first_reconcile; + reconcilor->first_execution_ = + GetParam().is_first_reconcile == IsFirstReconcile::kFirst ? true : false; reconcilor->StartReconcile(); for (int i = 0; GetParam().gaia_api_calls[i] != '\0'; ++i) { if (GetParam().gaia_api_calls[i] == 'X') @@ -859,9 +917,10 @@ base::RunLoop().RunUntilIdle(); } -INSTANTIATE_TEST_CASE_P(DiceTable, - AccountReconcilorTestDice, - ::testing::ValuesIn(kDiceParams)); +INSTANTIATE_TEST_CASE_P( + DiceTable, + AccountReconcilorTestTable, + ::testing::ValuesIn(GenerateTestCasesFromParams(kDiceParams))); // Tests that the AccountReconcilor is always registered. TEST_F(AccountReconcilorTest, DiceTokenServiceRegistration) { @@ -1241,10 +1300,154 @@ #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) +// clang-format off +const std::vector<AccountReconcilorTestTableParam> kMirrorParams = { + // This table encodes the initial state and expectations of a reconcile. + // The syntax is: + // - Tokens: + // A, B, C: Accounts for which we have a token in Chrome. + // *: The next account is the main Chrome account (i.e. in SigninManager). + // x: The next account has a token error. + // - Cookies: + // A, B, C: Accounts in the Gaia cookie (returned by ListAccounts). + // x: The next cookie is marked "invalid". + // - First Run: true if this is the first reconcile (i.e. Chrome startup). + // M: Multilogin. + // ----------------- + // ------------------------------------------------------------------------- + // Tokens | Cookies | First Run | Gaia calls | Tokens after | Cookies after + // ------------------------------------------------------------------------- + + // First reconcile (Chrome restart): Rebuild the Gaia cookie to match the + // tokens. Make the Sync account the default account in the Gaia cookie. + // Sync enabled. + { "*AB", "AB", IsFirstReconcile::kBoth, "", "*AB", "AB"}, + { "*AB", "BA", IsFirstReconcile::kBoth, "M", "*AB", "AB"}, + { "*AB", "A", IsFirstReconcile::kBoth, "M", "*AB", "AB"}, + { "*AB", "B", IsFirstReconcile::kBoth, "M", "*AB", "AB"}, + { "*AB", "", IsFirstReconcile::kBoth, "M", "*AB", "AB"}, + // Sync enabled, token error on primary. + // Sync enabled, token error on secondary. + { "*AxB", "AB", IsFirstReconcile::kBoth, "M", "*AxB", "A"}, + { "*AxB", "BA", IsFirstReconcile::kBoth, "M", "*AxB", "A"}, + { "*AxB", "A", IsFirstReconcile::kBoth, "", "*AxB", "" }, + { "*AxB", "B", IsFirstReconcile::kBoth, "M", "*AxB", "A"}, + { "*AxB", "", IsFirstReconcile::kBoth, "M", "*AxB", "A"}, + + // Cookies can be refreshed in pace, without logout. + { "*AB", "xBxA", IsFirstReconcile::kBoth, "M", "*AB", "AB"}, + + // Check that unknown Gaia accounts are signed out. + { "*A", "AB", IsFirstReconcile::kBoth, "M", "*A", "A"}, + // Check that the previous case is idempotent.. + { "*A", "A", IsFirstReconcile::kBoth, "", "*A", ""}, +}; +// clang-format on + +// Parameterized version of AccountReconcilorTest that tests Mirror +// implementation with Multilogin endpoint. +class AccountReconcilorTestMirrorMultilogin + : public AccountReconcilorTestTable { + public: + AccountReconcilorTestMirrorMultilogin() = default; + + protected: + base::test::ScopedFeatureList scoped_feature_list_; + + private: + DISALLOW_COPY_AND_ASSIGN(AccountReconcilorTestMirrorMultilogin); +}; + +// Checks one row of the kDiceParams table above. +TEST_P(AccountReconcilorTestMirrorMultilogin, TableRowTest) { + // Enable Mirror. + SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); + scoped_feature_list_.InitAndEnableFeature(kUseMultiloginEndpoint); + + // Setup tokens. + std::vector<Token> tokens_before_reconcile = + ParseTokenString(GetParam().tokens); + for (const Token& token : tokens_before_reconcile) { + std::string account_id = + PickAccountIdForAccount(token.gaia_id, token.email); + if (token.is_authenticated) + ConnectProfileToAccount(token.gaia_id, token.email); + else + token_service()->UpdateCredentials(account_id, "refresh_token"); + if (token.has_error) { + token_service()->UpdateAuthErrorForTesting( + account_id, GoogleServiceAuthError( + GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); + } + } + VerifyCurrentTokens(tokens_before_reconcile); + + // Setup cookies. + std::vector<Cookie> cookies = ParseCookieString(GetParam().cookies); + ConfigureCookieManagerService(cookies); + + // Call list accounts now so that the next call completes synchronously. + cookie_manager_service()->ListAccounts(nullptr, nullptr, "foo"); + base::RunLoop().RunUntilIdle(); + + // Setup expectations. + testing::InSequence mock_sequence; + bool logout_action = false; + for (int i = 0; GetParam().gaia_api_calls[i] != '\0'; ++i) { + if (GetParam().gaia_api_calls[i] == 'M') { + std::vector<std::string> accounts_to_send; + for (int i = 0; GetParam().cookies_after_reconcile[i] != '\0'; ++i) { + std::string account_to_send = + std::string(1, GetParam().cookies_after_reconcile[i]); + accounts_to_send.push_back(PickAccountIdForAccount( + account_to_send, + accounts_[GetParam().cookies_after_reconcile[i]].email)); + } + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)) + .Times(1); + } + } + if (!logout_action) { + EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()) + .Times(0); + } + + // Reconcile. + AccountReconcilor* reconcilor = GetMockReconcilor(); + ASSERT_TRUE(reconcilor); + ASSERT_TRUE(reconcilor->first_execution_); + reconcilor->first_execution_ = + GetParam().is_first_reconcile == IsFirstReconcile::kFirst ? true : false; + reconcilor->StartReconcile(); + + SimulateSetAccountsInCookieCompleted(reconcilor, + GoogleServiceAuthError::AuthErrorNone()); + + ASSERT_FALSE(reconcilor->is_reconcile_started_); + ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState()); + VerifyCurrentTokens(ParseTokenString(GetParam().tokens_after_reconcile)); + + testing::Mock::VerifyAndClearExpectations(GetMockReconcilor()); + + // // Another reconcile is sometimes triggered if Chrome accounts have + // changed. Allow it to finish. + EXPECT_CALL(*GetMockReconcilor(), PerformSetCookiesAction(testing::_)) + .WillRepeatedly(testing::Return()); + EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()) + .WillRepeatedly(testing::Return()); + ConfigureCookieManagerService({}); + base::RunLoop().RunUntilIdle(); +} + +INSTANTIATE_TEST_CASE_P( + DiceTableMirrorMultilogin, + AccountReconcilorTestMirrorMultilogin, + ::testing::ValuesIn(GenerateTestCasesFromParams(kMirrorParams))); + // Tests that reconcile cannot start before the tokens are loaded, and is // automatically started when tokens are loaded. -TEST_F(AccountReconcilorTest, TokensNotLoaded) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, TokensNotLoaded) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); cookie_manager_service()->SetListAccountsResponseNoAccounts(); @@ -1261,23 +1464,39 @@ token_service()->LoadCredentials(account_id); #endif - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); + } else { + std::vector<std::string> accounts_to_set = {account_id}; + EXPECT_CALL(*GetMockReconcilor(), PerformSetCookiesAction(accounts_to_set)); + } ASSERT_TRUE(reconcilor->is_reconcile_started_); base::RunLoop().RunUntilIdle(); - SimulateAddAccountToCookieCompleted(reconcilor, account_id, - GoogleServiceAuthError::AuthErrorNone()); + if (!GetParam()) { + SimulateAddAccountToCookieCompleted( + reconcilor, account_id, GoogleServiceAuthError::AuthErrorNone()); + } else { + SimulateSetAccountsInCookieCompleted( + reconcilor, GoogleServiceAuthError::AuthErrorNone()); + } ASSERT_FALSE(reconcilor->is_reconcile_started_); ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState()); } -TEST_F(AccountReconcilorTest, GetAccountsFromCookieSuccess) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, GetAccountsFromCookieSuccess) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); cookie_manager_service()->SetListAccountsResponseOneAccountWithParams( {"user@gmail.com", "12345", false /* valid */, false /* signed_out */, true /* verified */}); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); + + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); + } else { + std::vector<std::string> accounts_to_send = {account_id}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } AccountReconcilor* reconcilor = GetMockReconcilor(); ASSERT_TRUE(reconcilor); @@ -1297,8 +1516,8 @@ ASSERT_EQ(0u, signed_out_accounts.size()); } -TEST_F(AccountReconcilorTest, GetAccountsFromCookieFailure) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, GetAccountsFromCookieFailure) { + ; ConnectProfileToAccount("12345", "user@gmail.com"); cookie_manager_service()->SetListAccountsResponseWebLoginRequired(); @@ -1321,8 +1540,7 @@ ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_ERROR, reconcilor->GetState()); } -TEST_F(AccountReconcilorTest, StartReconcileNoop) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoop) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); @@ -1338,15 +1556,17 @@ base::RunLoop().RunUntilIdle(); ASSERT_FALSE(reconcilor->is_reconcile_started_); - histogram_tester()->ExpectTotalCount( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", - signin_metrics::ACCOUNTS_SAME, 1); + if (!GetParam()) { + histogram_tester()->ExpectTotalCount( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", + signin_metrics::ACCOUNTS_SAME, 1); + } } -TEST_F(AccountReconcilorTest, StartReconcileCookiesDisabled) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, + StartReconcileCookiesDisabled) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); token_service()->UpdateCredentials(account_id, "refresh_token"); @@ -1366,8 +1586,8 @@ ASSERT_FALSE(reconcilor->is_reconcile_started_); } -TEST_F(AccountReconcilorTest, StartReconcileContentSettings) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, + StartReconcileContentSettings) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); token_service()->UpdateCredentials(account_id, "refresh_token"); @@ -1386,8 +1606,8 @@ ASSERT_TRUE(reconcilor->is_reconcile_started_); } -TEST_F(AccountReconcilorTest, StartReconcileContentSettingsGaiaUrl) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, + StartReconcileContentSettingsGaiaUrl) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); token_service()->UpdateCredentials(account_id, "refresh_token"); @@ -1401,8 +1621,8 @@ ASSERT_TRUE(reconcilor->is_reconcile_started_); } -TEST_F(AccountReconcilorTest, StartReconcileContentSettingsNonGaiaUrl) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, + StartReconcileContentSettingsNonGaiaUrl) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); token_service()->UpdateCredentials(account_id, "refresh_token"); @@ -1416,8 +1636,8 @@ ASSERT_FALSE(reconcilor->is_reconcile_started_); } -TEST_F(AccountReconcilorTest, StartReconcileContentSettingsInvalidPattern) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, + StartReconcileContentSettingsInvalidPattern) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); token_service()->UpdateCredentials(account_id, "refresh_token"); @@ -1441,8 +1661,7 @@ // tests makes sure that an email like "Dot.S@hmail.com", as seen by the // token service, will be considered the same as "dots@gmail.com" as returned // by gaia::ParseListAccountsData(). -TEST_F(AccountReconcilorTest, StartReconcileNoopWithDots) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoopWithDots) { if (account_tracker()->GetMigrationState() != AccountTrackerService::MIGRATION_NOT_STARTED) { return; @@ -1459,19 +1678,20 @@ base::RunLoop().RunUntilIdle(); ASSERT_FALSE(reconcilor->is_reconcile_started_); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", - signin_metrics::ACCOUNTS_SAME, 1); + if (!GetParam()) { + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", + signin_metrics::ACCOUNTS_SAME, 1); + } } -TEST_F(AccountReconcilorTest, StartReconcileNoopMultiple) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoopMultiple) { const std::string account_id = - ConnectProfileToAccount("12345", "user@gmail.com"); + ConnectProfileToAccount("67890", "user@gmail.com"); const std::string account_id2 = - PickAccountIdForAccount("67890", "other@gmail.com"); + PickAccountIdForAccount("12345", "other@gmail.com"); cookie_manager_service()->SetListAccountsResponseTwoAccounts( - "user@gmail.com", "12345", "other@gmail.com", "67890"); + "user@gmail.com", "67890", "other@gmail.com", "12345"); token_service()->UpdateCredentials(account_id2, "refresh_token"); AccountReconcilor* reconcilor = GetMockReconcilor(); @@ -1481,43 +1701,57 @@ base::RunLoop().RunUntilIdle(); ASSERT_FALSE(reconcilor->is_reconcile_started_); - histogram_tester()->ExpectTotalCount( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", - signin_metrics::ACCOUNTS_SAME, 1); + if (!GetParam()) { + histogram_tester()->ExpectTotalCount( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", + signin_metrics::ACCOUNTS_SAME, 1); + } } -TEST_F(AccountReconcilorTest, StartReconcileAddToCookie) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileAddToCookie) { const std::string account_id = - ConnectProfileToAccount("12345", "user@gmail.com"); + ConnectProfileToAccount("67890", "user@gmail.com"); token_service()->UpdateCredentials(account_id, "refresh_token"); cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com", - "12345"); + "67890"); const std::string account_id2 = - PickAccountIdForAccount("67890", "other@gmail.com"); + PickAccountIdForAccount("12345", "other@gmail.com"); token_service()->UpdateCredentials(account_id2, "refresh_token"); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); + } else { + std::vector<std::string> accounts_to_send = {account_id, account_id2}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } AccountReconcilor* reconcilor = GetMockReconcilor(); reconcilor->StartReconcile(); base::RunLoop().RunUntilIdle(); ASSERT_TRUE(reconcilor->is_reconcile_started_); - SimulateAddAccountToCookieCompleted(reconcilor, account_id2, - GoogleServiceAuthError::AuthErrorNone()); + if (!GetParam()) { + SimulateAddAccountToCookieCompleted( + reconcilor, account_id2, GoogleServiceAuthError::AuthErrorNone()); + } else { + SimulateSetAccountsInCookieCompleted( + reconcilor, GoogleServiceAuthError::AuthErrorNone()); + } ASSERT_FALSE(reconcilor->is_reconcile_started_); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", - signin_metrics::ACCOUNTS_SAME, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1); + if (!GetParam()) { + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", + signin_metrics::ACCOUNTS_SAME, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1); + } base::HistogramTester::CountsMap expected_counts; expected_counts["Signin.Reconciler.Duration.Success"] = 1; @@ -1584,8 +1818,8 @@ // This test does not run on ChromeOS because it calls // FakeSigninManagerForTesting::SignOut() which doesn't exist for ChromeOS. -TEST_F(AccountReconcilorTest, SignoutAfterErrorDoesNotRecordUma) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, + SignoutAfterErrorDoesNotRecordUma) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); token_service()->UpdateCredentials(account_id, "refresh_token"); @@ -1596,7 +1830,13 @@ PickAccountIdForAccount("67890", "other@gmail.com"); token_service()->UpdateCredentials(account_id2, "refresh_token"); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); + } else { + std::vector<std::string> accounts_to_send = {account_id, account_id2}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } AccountReconcilor* reconcilor = GetMockReconcilor(); reconcilor->StartReconcile(); @@ -1605,7 +1845,11 @@ ASSERT_TRUE(reconcilor->is_reconcile_started_); GoogleServiceAuthError error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); - SimulateAddAccountToCookieCompleted(reconcilor, account_id2, error); + if (!GetParam()) { + SimulateAddAccountToCookieCompleted(reconcilor, account_id2, error); + } else { + SimulateSetAccountsInCookieCompleted(reconcilor, error); + } ASSERT_FALSE(reconcilor->is_reconcile_started_); EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); @@ -1614,107 +1858,166 @@ base::HistogramTester::CountsMap expected_counts; expected_counts["Signin.Reconciler.Duration.Failure"] = 1; - EXPECT_THAT(histogram_tester()->GetTotalCountsForPrefix( - "Signin.Reconciler.Duration.Failure"), - testing::ContainerEq(expected_counts)); + if (!GetParam()) { + EXPECT_THAT(histogram_tester()->GetTotalCountsForPrefix( + "Signin.Reconciler.Duration.Failure"), + testing::ContainerEq(expected_counts)); + } } #endif // !defined(OS_CHROMEOS) -TEST_F(AccountReconcilorTest, StartReconcileRemoveFromCookie) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, + StartReconcileRemoveFromCookie) { const std::string account_id = - ConnectProfileToAccount("12345", "user@gmail.com"); + ConnectProfileToAccount("67890", "user@gmail.com"); token_service()->UpdateCredentials(account_id, "refresh_token"); cookie_manager_service()->SetListAccountsResponseTwoAccounts( - "user@gmail.com", "12345", "other@gmail.com", "67890"); + "user@gmail.com", "67890", "other@gmail.com", "12345"); - EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); + } else { + std::vector<std::string> accounts_to_send = {account_id}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } AccountReconcilor* reconcilor = GetMockReconcilor(); reconcilor->StartReconcile(); ASSERT_TRUE(reconcilor->is_reconcile_started_); base::RunLoop().RunUntilIdle(); - SimulateAddAccountToCookieCompleted(reconcilor, account_id, - GoogleServiceAuthError::AuthErrorNone()); + + if (!GetParam()) { + SimulateAddAccountToCookieCompleted( + reconcilor, account_id, GoogleServiceAuthError::AuthErrorNone()); + } else { + SimulateSetAccountsInCookieCompleted( + reconcilor, GoogleServiceAuthError::AuthErrorNone()); + } ASSERT_FALSE(reconcilor->is_reconcile_started_); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", - signin_metrics::ACCOUNTS_SAME, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 1, 1); + if (!GetParam()) { + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", + signin_metrics::ACCOUNTS_SAME, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 1, 1); + } } -TEST_F(AccountReconcilorTest, StartReconcileAddToCookieTwice) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +// Check that reconcile is aborted if there is token error on primary account. +TEST_P(AccountReconcilorMirrorEndpointParamTest, TokenErrorOnPrimary) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); + token_service()->UpdateAuthErrorForTesting( + account_id, + GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); + + cookie_manager_service()->SetListAccountsResponseTwoAccounts( + "user@gmail.com", "12345", "other@gmail.com", "67890"); + + AccountReconcilor* reconcilor = GetMockReconcilor(); + reconcilor->StartReconcile(); + + base::RunLoop().RunUntilIdle(); + ASSERT_FALSE(reconcilor->is_reconcile_started_); +} + +TEST_P(AccountReconcilorMirrorEndpointParamTest, + StartReconcileAddToCookieTwice) { + const std::string account_id = + ConnectProfileToAccount("67890", "user@gmail.com"); const std::string account_id2 = - PickAccountIdForAccount("67890", "other@gmail.com"); + PickAccountIdForAccount("12345", "other@gmail.com"); const std::string account_id3 = PickAccountIdForAccount("34567", "third@gmail.com"); cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com", - "12345"); + "67890"); token_service()->UpdateCredentials(account_id2, "refresh_token"); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id3)); + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id3)); + } else { + std::vector<std::string> accounts_to_send = {account_id, account_id2}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } AccountReconcilor* reconcilor = GetMockReconcilor(); reconcilor->StartReconcile(); base::RunLoop().RunUntilIdle(); ASSERT_TRUE(reconcilor->is_reconcile_started_); - SimulateAddAccountToCookieCompleted(reconcilor, account_id2, - GoogleServiceAuthError::AuthErrorNone()); + if (!GetParam()) { + SimulateAddAccountToCookieCompleted( + reconcilor, account_id2, GoogleServiceAuthError::AuthErrorNone()); + } else { + SimulateSetAccountsInCookieCompleted( + reconcilor, GoogleServiceAuthError::AuthErrorNone()); + } ASSERT_FALSE(reconcilor->is_reconcile_started_); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", - signin_metrics::ACCOUNTS_SAME, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1); + if (!GetParam()) { + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", + signin_metrics::ACCOUNTS_SAME, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1); + } // Do another pass after I've added a third account to the token service cookie_manager_service()->SetListAccountsResponseTwoAccounts( - "user@gmail.com", "12345", "other@gmail.com", "67890"); + "user@gmail.com", "67890", "other@gmail.com", "12345"); cookie_manager_service()->set_list_accounts_stale_for_testing(true); // This will cause the reconcilor to fire. token_service()->UpdateCredentials(account_id3, "refresh_token"); + if (GetParam()) { + std::vector<std::string> accounts_to_send = {account_id, account_id2, + account_id3}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } base::RunLoop().RunUntilIdle(); ASSERT_TRUE(reconcilor->is_reconcile_started_); - SimulateAddAccountToCookieCompleted(reconcilor, account_id3, - GoogleServiceAuthError::AuthErrorNone()); + if (!GetParam()) { + SimulateAddAccountToCookieCompleted( + reconcilor, account_id3, GoogleServiceAuthError::AuthErrorNone()); + } else { + SimulateSetAccountsInCookieCompleted( + reconcilor, GoogleServiceAuthError::AuthErrorNone()); + } ASSERT_FALSE(reconcilor->is_reconcile_started_); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", - signin_metrics::ACCOUNTS_SAME, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.DifferentPrimaryAccounts.SubsequentRun", - signin_metrics::ACCOUNTS_SAME, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.AddedToCookieJar.SubsequentRun", 1, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.RemovedFromCookieJar.SubsequentRun", 0, 1); + if (!GetParam()) { + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", + signin_metrics::ACCOUNTS_SAME, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.DifferentPrimaryAccounts.SubsequentRun", + signin_metrics::ACCOUNTS_SAME, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.AddedToCookieJar.SubsequentRun", 1, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.RemovedFromCookieJar.SubsequentRun", 0, 1); + } } -TEST_F(AccountReconcilorTest, StartReconcileBadPrimary) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileBadPrimary) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); const std::string account_id2 = @@ -1724,33 +2027,45 @@ cookie_manager_service()->SetListAccountsResponseTwoAccounts( "other@gmail.com", "67890", "user@gmail.com", "12345"); - EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); + } else { + std::vector<std::string> accounts_to_send = {account_id, account_id2}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } AccountReconcilor* reconcilor = GetMockReconcilor(); reconcilor->StartReconcile(); base::RunLoop().RunUntilIdle(); ASSERT_TRUE(reconcilor->is_reconcile_started_); - SimulateAddAccountToCookieCompleted(reconcilor, account_id2, - GoogleServiceAuthError::AuthErrorNone()); - ASSERT_TRUE(reconcilor->is_reconcile_started_); - SimulateAddAccountToCookieCompleted(reconcilor, account_id, - GoogleServiceAuthError::AuthErrorNone()); + if (!GetParam()) { + SimulateAddAccountToCookieCompleted( + reconcilor, account_id2, GoogleServiceAuthError::AuthErrorNone()); + ASSERT_TRUE(reconcilor->is_reconcile_started_); + SimulateAddAccountToCookieCompleted( + reconcilor, account_id, GoogleServiceAuthError::AuthErrorNone()); + } else { + SimulateSetAccountsInCookieCompleted( + reconcilor, GoogleServiceAuthError::AuthErrorNone()); + } ASSERT_FALSE(reconcilor->is_reconcile_started_); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", - signin_metrics::COOKIE_AND_TOKEN_PRIMARIES_DIFFERENT, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1); - histogram_tester()->ExpectUniqueSample( - "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1); + if (!GetParam()) { + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", + signin_metrics::COOKIE_AND_TOKEN_PRIMARIES_DIFFERENT, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1); + histogram_tester()->ExpectUniqueSample( + "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1); + } } -TEST_F(AccountReconcilorTest, StartReconcileOnlyOnce) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileOnlyOnce) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com", @@ -1767,8 +2082,7 @@ ASSERT_FALSE(reconcilor->is_reconcile_started_); } -TEST_F(AccountReconcilorTest, Lock) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, Lock) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com", @@ -1869,15 +2183,21 @@ ASSERT_FALSE(reconcilor->is_reconcile_started_); } -TEST_F(AccountReconcilorTest, AddAccountToCookieCompletedWithBogusAccount) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, + AddAccountToCookieCompletedWithBogusAccount) { const std::string account_id = ConnectProfileToAccount("12345", "user@gmail.com"); cookie_manager_service()->SetListAccountsResponseOneAccountWithParams( {"user@gmail.com", "12345", false /* valid */, false /* signed_out */, true /* verified */}); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)); + } else { + std::vector<std::string> accounts_to_send = {account_id}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } AccountReconcilor* reconcilor = GetMockReconcilor(); ASSERT_TRUE(reconcilor); @@ -1889,17 +2209,18 @@ base::RunLoop().RunUntilIdle(); // If an unknown account id is sent, it should not upset the state. - SimulateAddAccountToCookieCompleted(reconcilor, "bogus_account_id", - GoogleServiceAuthError::AuthErrorNone()); ASSERT_TRUE(reconcilor->is_reconcile_started_); - - SimulateAddAccountToCookieCompleted(reconcilor, account_id, - GoogleServiceAuthError::AuthErrorNone()); + if (!GetParam()) { + SimulateAddAccountToCookieCompleted( + reconcilor, account_id, GoogleServiceAuthError::AuthErrorNone()); + } else { + SimulateSetAccountsInCookieCompleted( + reconcilor, GoogleServiceAuthError::AuthErrorNone()); + } ASSERT_FALSE(reconcilor->is_reconcile_started_); } -TEST_F(AccountReconcilorTest, NoLoopWithBadPrimary) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, NoLoopWithBadPrimary) { // Connect profile to a primary account and then add a secondary account. const std::string account_id1 = ConnectProfileToAccount("12345", "user@gmail.com"); @@ -1907,10 +2228,15 @@ PickAccountIdForAccount("67890", "other@gmail.com"); token_service()->UpdateCredentials(account_id2, "refresh_token"); - EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1)); - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); - + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1)); + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2)); + } else { + std::vector<std::string> accounts_to_send = {account_id1, account_id2}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } // The primary account is in auth error, so it is not in the cookie. cookie_manager_service()->SetListAccountsResponseOneAccountWithParams( {"other@gmail.com", "67890", false /* valid */, false /* signed_out */, @@ -1927,9 +2253,13 @@ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); // The primary cannot be added to cookie, so it fails. - SimulateAddAccountToCookieCompleted(reconcilor, account_id1, error); - SimulateAddAccountToCookieCompleted(reconcilor, account_id2, - GoogleServiceAuthError::AuthErrorNone()); + if (!GetParam()) { + SimulateAddAccountToCookieCompleted(reconcilor, account_id1, error); + SimulateAddAccountToCookieCompleted( + reconcilor, account_id2, GoogleServiceAuthError::AuthErrorNone()); + } else { + SimulateSetAccountsInCookieCompleted(reconcilor, error); + } base::RunLoop().RunUntilIdle(); ASSERT_FALSE(reconcilor->is_reconcile_started_); ASSERT_NE(GoogleServiceAuthError::State::NONE, @@ -1947,8 +2277,7 @@ testing::Mock::VerifyAndClearExpectations(GetMockReconcilor()); } -TEST_F(AccountReconcilorTest, WontMergeAccountsWithError) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, WontMergeAccountsWithError) { // Connect profile to a primary account and then add a secondary account. const std::string account_id1 = ConnectProfileToAccount("12345", "user@gmail.com"); @@ -1967,7 +2296,13 @@ // Since the cookie jar starts empty, the reconcilor should attempt to merge // accounts into it. However, it should only try accounts not in auth // error state. - EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1)); + if (!GetParam()) { + EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1)); + } else { + std::vector<std::string> accounts_to_send = {account_id1}; + EXPECT_CALL(*GetMockReconcilor(), + PerformSetCookiesAction(accounts_to_send)); + } AccountReconcilor* reconcilor = GetMockReconcilor(); ASSERT_TRUE(reconcilor); @@ -1976,8 +2311,13 @@ base::RunLoop().RunUntilIdle(); ASSERT_TRUE(reconcilor->is_reconcile_started_); - SimulateAddAccountToCookieCompleted(reconcilor, account_id1, - GoogleServiceAuthError::AuthErrorNone()); + if (!GetParam()) { + SimulateAddAccountToCookieCompleted( + reconcilor, account_id1, GoogleServiceAuthError::AuthErrorNone()); + } else { + SimulateSetAccountsInCookieCompleted( + reconcilor, GoogleServiceAuthError::AuthErrorNone()); + } base::RunLoop().RunUntilIdle(); ASSERT_FALSE(reconcilor->is_reconcile_started_); ASSERT_EQ(GoogleServiceAuthError::State::NONE, @@ -2010,8 +2350,7 @@ // Test that delegate timeout is not called when the delegate does not offer a // valid timeout. -TEST_F(AccountReconcilorTest, DelegateTimeoutIsNotCalled) { - SetAccountConsistency(signin::AccountConsistencyMethod::kMirror); +TEST_P(AccountReconcilorMirrorEndpointParamTest, DelegateTimeoutIsNotCalled) { ConnectProfileToAccount("12345", "user@gmail.com"); cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com", "12345"); @@ -2026,6 +2365,10 @@ EXPECT_FALSE(timer->IsRunning()); } +INSTANTIATE_TEST_CASE_P(TestEndpoint, + AccountReconcilorMirrorEndpointParamTest, + ::testing::ValuesIn({false, true})); + TEST_F(AccountReconcilorTest, DelegateTimeoutIsNotCalledIfTimeoutIsNotReached) { ConnectProfileToAccount("12345", "user@gmail.com"); cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com", @@ -2047,4 +2390,4 @@ EXPECT_EQ(0, spy_delegate->num_reconcile_timeout_calls_); EXPECT_EQ(1, spy_delegate->num_reconcile_finished_calls_); EXPECT_FALSE(reconcilor->is_reconcile_started_); -} +} \ No newline at end of file
diff --git a/components/signin/core/browser/mirror_account_reconcilor_delegate.cc b/components/signin/core/browser/mirror_account_reconcilor_delegate.cc index 519c572..ed10c7c2 100644 --- a/components/signin/core/browser/mirror_account_reconcilor_delegate.cc +++ b/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
@@ -49,6 +49,39 @@ return primary_account; } +bool MirrorAccountReconcilorDelegate::ReorderChromeAccountsForReconcileIfNeeded( + const std::vector<std::string>& chrome_accounts, + const std::string primary_account, + const std::vector<gaia::ListedAccount>& gaia_accounts, + std::vector<std::string>* accounts_to_send) const { + DCHECK(accounts_to_send); + accounts_to_send->clear(); + accounts_to_send->reserve(chrome_accounts.size()); + bool needs_reordering = false; + + DCHECK(!primary_account.empty()); + accounts_to_send->push_back(primary_account); + + for (const std::string& chrome_account : chrome_accounts) { + if (chrome_account == primary_account) + continue; + accounts_to_send->push_back(chrome_account); + } + + if (gaia_accounts.size() != accounts_to_send->size()) { + needs_reordering = true; + } else { + for (size_t i = 0; i < accounts_to_send->size(); ++i) { + const gaia::ListedAccount& gaia_account = gaia_accounts[i]; + if (gaia_account.id != accounts_to_send->at(i) || !gaia_account.valid) { + needs_reordering = true; + break; + } + } + } + return needs_reordering; +} + void MirrorAccountReconcilorDelegate::GoogleSigninSucceeded( const std::string& account_id, const std::string& username) {
diff --git a/components/signin/core/browser/mirror_account_reconcilor_delegate.h b/components/signin/core/browser/mirror_account_reconcilor_delegate.h index 1a9e3c84..5be1d28 100644 --- a/components/signin/core/browser/mirror_account_reconcilor_delegate.h +++ b/components/signin/core/browser/mirror_account_reconcilor_delegate.h
@@ -31,6 +31,12 @@ bool first_execution, bool will_logout) const override; + bool ReorderChromeAccountsForReconcileIfNeeded( + const std::vector<std::string>& chrome_accounts, + const std::string primary_account, + const std::vector<gaia::ListedAccount>& gaia_accounts, + std::vector<std::string>* accounts_to_send) const override; + // SigninManagerBase::Observer: void GoogleSigninSucceeded(const std::string& account_id, const std::string& username) override;
diff --git a/components/sync/base/pref_names.cc b/components/sync/base/pref_names.cc index 712c0fa..be1c5fd 100644 --- a/components/sync/base/pref_names.cc +++ b/components/sync/base/pref_names.cc
@@ -90,10 +90,6 @@ const char kSyncKeystoreEncryptionBootstrapToken[] = "sync.keystore_encryption_bootstrap_token"; -// The GUID session sync will use to identify this client, even across sync -// disable/enable events. -const char kSyncSessionsGUID[] = "sync.session_sync_guid"; - #if defined(OS_CHROMEOS) // A string that is used to store first-time sync startup after once sync is // disabled. This will be refreshed every sign-in.
diff --git a/components/sync/base/pref_names.h b/components/sync/base/pref_names.h index a1f9300..3999182 100644 --- a/components/sync/base/pref_names.h +++ b/components/sync/base/pref_names.h
@@ -64,8 +64,6 @@ extern const char kSyncEncryptionBootstrapToken[]; extern const char kSyncKeystoreEncryptionBootstrapToken[]; -extern const char kSyncSessionsGUID[]; - #if defined(OS_CHROMEOS) extern const char kSyncSpareBootstrapToken[]; #endif // defined(OS_CHROMEOS)
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc index 7b427ad..38fb56b 100644 --- a/components/sync/base/sync_prefs.cc +++ b/components/sync/base/sync_prefs.cc
@@ -64,8 +64,6 @@ } // namespace -SessionSyncPrefs::~SessionSyncPrefs() {} - CryptoSyncPrefs::~CryptoSyncPrefs() {} SyncPrefObserver::~SyncPrefObserver() {} @@ -130,7 +128,6 @@ #endif registry->RegisterBooleanPref(prefs::kSyncHasAuthError, false); - registry->RegisterStringPref(prefs::kSyncSessionsGUID, std::string()); registry->RegisterBooleanPref(prefs::kSyncPassphrasePrompted, false); registry->RegisterIntegerPref(prefs::kSyncMemoryPressureWarningCount, -1); registry->RegisterBooleanPref(prefs::kSyncShutdownCleanly, false); @@ -322,16 +319,6 @@ pref_service_->SetString(prefs::kSyncKeystoreEncryptionBootstrapToken, token); } -std::string SyncPrefs::GetSyncSessionsGUID() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return pref_service_->GetString(prefs::kSyncSessionsGUID); -} - -void SyncPrefs::SetSyncSessionsGUID(const std::string& guid) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - pref_service_->SetString(prefs::kSyncSessionsGUID, guid); -} - // static const char* SyncPrefs::GetPrefNameForDataType(ModelType type) { switch (type) {
diff --git a/components/sync/base/sync_prefs.h b/components/sync/base/sync_prefs.h index fddc65e..645f442 100644 --- a/components/sync/base/sync_prefs.h +++ b/components/sync/base/sync_prefs.h
@@ -40,15 +40,6 @@ virtual ~SyncPrefObserver(); }; -// Use this for the unique machine tag used for session sync. -class SessionSyncPrefs { - public: - virtual ~SessionSyncPrefs(); - - virtual std::string GetSyncSessionsGUID() const = 0; - virtual void SetSyncSessionsGUID(const std::string& guid) = 0; -}; - // Use this for crypto/passphrase-related parts of sync prefs. class CryptoSyncPrefs { public: @@ -90,8 +81,7 @@ // sync_setup_wizard.cc // sync_setup_wizard_unittest.cc // two_client_preferences_sync_test.cc -class SyncPrefs : public SessionSyncPrefs, - public CryptoSyncPrefs, +class SyncPrefs : public CryptoSyncPrefs, public base::SupportsWeakPtr<SyncPrefs> { public: // |pref_service| may not be null. @@ -178,10 +168,6 @@ std::string GetKeystoreEncryptionBootstrapToken() const override; void SetKeystoreEncryptionBootstrapToken(const std::string& token) override; - // Use this for the unique machine tag used for session sync. - std::string GetSyncSessionsGUID() const override; - void SetSyncSessionsGUID(const std::string& guid) override; - // Maps |type| to its corresponding preference name. static const char* GetPrefNameForDataType(ModelType type);
diff --git a/components/sync/driver/fake_sync_client.cc b/components/sync/driver/fake_sync_client.cc index 012d402..b6c0b94 100644 --- a/components/sync/driver/fake_sync_client.cc +++ b/components/sync/driver/fake_sync_client.cc
@@ -59,6 +59,10 @@ return nullptr; } +sync_sessions::SessionSyncService* FakeSyncClient::GetSessionSyncService() { + return nullptr; +} + bool FakeSyncClient::HasPasswordStore() { return false; } @@ -90,10 +94,6 @@ return scoped_refptr<ExtensionsActivity>(); } -sync_sessions::SyncSessionsClient* FakeSyncClient::GetSyncSessionsClient() { - return nullptr; -} - base::WeakPtr<SyncableService> FakeSyncClient::GetSyncableServiceForType( ModelType type) { return base::WeakPtr<SyncableService>();
diff --git a/components/sync/driver/fake_sync_client.h b/components/sync/driver/fake_sync_client.h index 3765d75..ff38e989 100644 --- a/components/sync/driver/fake_sync_client.h +++ b/components/sync/driver/fake_sync_client.h
@@ -31,6 +31,7 @@ bookmarks::BookmarkModel* GetBookmarkModel() override; favicon::FaviconService* GetFaviconService() override; history::HistoryService* GetHistoryService() override; + sync_sessions::SessionSyncService* GetSessionSyncService() override; bool HasPasswordStore() override; base::Closure GetPasswordStateChangedCallback() override; DataTypeController::TypeVector CreateDataTypeControllers( @@ -39,7 +40,6 @@ BookmarkUndoService* GetBookmarkUndoServiceIfExists() override; invalidation::InvalidationService* GetInvalidationService() override; scoped_refptr<ExtensionsActivity> GetExtensionsActivity() override; - sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override; base::WeakPtr<SyncableService> GetSyncableServiceForType( ModelType type) override; base::WeakPtr<ModelTypeControllerDelegate> GetControllerDelegateForModelType(
diff --git a/components/sync/driver/fake_sync_service.cc b/components/sync/driver/fake_sync_service.cc index 1c070842..53641a9 100644 --- a/components/sync/driver/fake_sync_service.cc +++ b/components/sync/driver/fake_sync_service.cc
@@ -206,10 +206,6 @@ void FakeSyncService::GetAllNodes( const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback) {} -GlobalIdMapper* FakeSyncService::GetGlobalIdMapper() const { - return nullptr; -} - bool FakeSyncService::IsPassphraseRequired() const { return false; }
diff --git a/components/sync/driver/fake_sync_service.h b/components/sync/driver/fake_sync_service.h index 5798382..5bb5898 100644 --- a/components/sync/driver/fake_sync_service.h +++ b/components/sync/driver/fake_sync_service.h
@@ -88,7 +88,6 @@ base::WeakPtr<JsController> GetJsController() override; void GetAllNodes(const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback) override; - GlobalIdMapper* GetGlobalIdMapper() const override; // DataTypeEncryptionHandler implementation. bool IsPassphraseRequired() const override;
diff --git a/components/sync/driver/sync_client.h b/components/sync/driver/sync_client.h index 9a87945..203bc88 100644 --- a/components/sync/driver/sync_client.h +++ b/components/sync/driver/sync_client.h
@@ -39,7 +39,7 @@ } // namespace invalidation namespace sync_sessions { -class SyncSessionsClient; +class SessionSyncService; } // namespace sync_sessions namespace syncer { @@ -76,6 +76,7 @@ virtual bookmarks::BookmarkModel* GetBookmarkModel() = 0; virtual favicon::FaviconService* GetFaviconService() = 0; virtual history::HistoryService* GetHistoryService() = 0; + virtual sync_sessions::SessionSyncService* GetSessionSyncService() = 0; virtual bool HasPasswordStore() = 0; // Returns a vector with all supported datatypes and their controllers. @@ -92,7 +93,6 @@ virtual BookmarkUndoService* GetBookmarkUndoServiceIfExists() = 0; virtual invalidation::InvalidationService* GetInvalidationService() = 0; virtual scoped_refptr<ExtensionsActivity> GetExtensionsActivity() = 0; - virtual sync_sessions::SyncSessionsClient* GetSyncSessionsClient() = 0; // Returns a weak pointer to the syncable service specified by |type|. // Weak pointer may be unset if service is already destroyed.
diff --git a/components/sync/driver/sync_client_mock.h b/components/sync/driver/sync_client_mock.h index 6e27bed..221e986 100644 --- a/components/sync/driver/sync_client_mock.h +++ b/components/sync/driver/sync_client_mock.h
@@ -24,6 +24,7 @@ MOCK_METHOD0(GetFaviconService, favicon::FaviconService*()); MOCK_METHOD0(GetHistoryService, history::HistoryService*()); MOCK_METHOD0(HasPasswordStore, bool()); + MOCK_METHOD0(GetSessionSyncService, sync_sessions::SessionSyncService*()); MOCK_METHOD1(CreateDataTypeControllers, DataTypeController::TypeVector( LocalDeviceInfoProvider* local_device_info_provider)); @@ -33,7 +34,6 @@ MOCK_METHOD0(GetBookmarkUndoServiceIfExists, BookmarkUndoService*()); MOCK_METHOD0(GetInvalidationService, invalidation::InvalidationService*()); MOCK_METHOD0(GetExtensionsActivity, scoped_refptr<ExtensionsActivity>()); - MOCK_METHOD0(GetSyncSessionsClient, sync_sessions::SyncSessionsClient*()); MOCK_METHOD1(GetSyncableServiceForType, base::WeakPtr<SyncableService>(ModelType type)); MOCK_METHOD1(GetControllerDelegateForModelType,
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h index 7a19975..0277215 100644 --- a/components/sync/driver/sync_service.h +++ b/components/sync/driver/sync_service.h
@@ -30,7 +30,6 @@ class BaseTransaction; class JsController; -class GlobalIdMapper; class ProtocolEventObserver; class SyncClient; class SyncCycleSnapshot; @@ -384,9 +383,6 @@ // function. virtual UserShare* GetUserShare() const = 0; - // TODO(crbug.com/865936): Move this down into ProfileSyncService. - virtual GlobalIdMapper* GetGlobalIdMapper() const = 0; - ////////////////////////////////////////////////////////////////////////////// // DETAILED STATE FOR DEBUG UI //////////////////////////////////////////////////////////////////////////////
diff --git a/components/sync/engine_impl/uss_migrator.cc b/components/sync/engine_impl/uss_migrator.cc index 55d407c..9e1e69b 100644 --- a/components/sync/engine_impl/uss_migrator.cc +++ b/components/sync/engine_impl/uss_migrator.cc
@@ -48,16 +48,21 @@ if (!entry.GetServerParentId().IsNull()) { entity->set_parent_id_string(entry.GetServerParentId().GetServerId()); } - if (entry.GetServerUniquePosition().IsValid()) { + + if (!entry.GetUniqueServerTag().empty()) { + // Permanent nodes don't have unique_positions and are assigned unique + // server tags. + entity->set_server_defined_unique_tag(entry.GetUniqueServerTag()); + } else if (entry.GetServerUniquePosition().IsValid()) { *entity->mutable_unique_position() = entry.GetServerUniquePosition().ToProto(); } else { - // All boookmarks should have valid unique_positions including legacy - // bookmarks that are missing the field. Directory should have taken care of - // assigning proper unique_position during the first sync flow. + // All boookmarks (except permanent ones with server tag) should have valid + // unique_positions including legacy bookmarks that are missing the field. + // Directory should have taken care of assigning proper unique_position + // during the first sync flow. DCHECK_NE(BOOKMARKS, type); } - entity->set_server_defined_unique_tag(entry.GetUniqueServerTag()); // It looks like there are fancy other ways to get e.g. passwords specifics // out of Entry. Do we need to special-case them when we ship those types? @@ -65,6 +70,20 @@ return true; } +void AppendAllDescendantIds(const ReadTransaction* trans, + const ReadNode& node, + std::vector<int64_t>* all_descendant_ids) { + std::vector<int64_t> child_ids; + node.GetChildIds(&child_ids); + + for (int child_id : child_ids) { + all_descendant_ids->push_back(child_id); + ReadNode child(trans); + child.InitByIdLookup(child_id); + AppendAllDescendantIds(trans, child, all_descendant_ids); + } +} + } // namespace bool MigrateDirectoryData(ModelType type, @@ -96,7 +115,7 @@ &context); std::vector<int64_t> child_ids; - root.GetChildIds(&child_ids); + AppendAllDescendantIds(&trans, root, &child_ids); // Process |batch_size| entities at a time to reduce memory usage. size_t i = 0;
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc index a2ff46a5..68f6f2e 100644 --- a/components/sync/model_impl/client_tag_based_model_type_processor.cc +++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -776,8 +776,12 @@ // Squash the pending commit. entity->RecordForcedUpdate(update); // Update client data to match server. - changes->push_back( - EntityChange::CreateUpdate(entity->storage_key(), update.entity)); + if (update.entity->is_deleted()) { + changes->push_back(EntityChange::CreateDelete(entity->storage_key())); + } else { + changes->push_back( + EntityChange::CreateUpdate(entity->storage_key(), update.entity)); + } break; case ConflictResolution::USE_NEW: // Record that we received the update.
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc index 99025bed..d12beaa 100644 --- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc +++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -1216,6 +1216,20 @@ } TEST_F(ClientTagBasedModelTypeProcessorTest, + ShouldResolveConflictToRemoteDeletion) { + InitializeToReadyState(); + bridge()->WriteItem(kKey1, kValue1); + bridge()->SetConflictResolution(ConflictResolution::UseRemote()); + worker()->TombstoneFromServer(kHash1); + + // Updated client data and metadata; no new commit request. + EXPECT_EQ(0U, db().data_count()); + EXPECT_EQ(0U, db().metadata_count()); + EXPECT_EQ(2U, db().data_change_count()); + EXPECT_EQ(2U, db().metadata_change_count()); +} + +TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldResolveConflictToNewVersion) { InitializeToReadyState(); bridge()->WriteItem(kKey1, kValue1);
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn index 7be002c27..57f9057 100644 --- a/components/sync_sessions/BUILD.gn +++ b/components/sync_sessions/BUILD.gn
@@ -25,6 +25,10 @@ "session_store.h", "session_sync_bridge.cc", "session_sync_bridge.h", + "session_sync_prefs.cc", + "session_sync_prefs.h", + "session_sync_service.cc", + "session_sync_service.h", "sessions_global_id_mapper.cc", "sessions_global_id_mapper.h", "sessions_sync_manager.cc", @@ -56,8 +60,10 @@ "//components/bookmarks/browser", "//components/favicon/core", "//components/history/core/browser", + "//components/keyed_service/core", "//components/prefs", "//components/variations", + "//components/version_info", "//ui/base:base", "//ui/gfx", "//url",
diff --git a/components/sync_sessions/DEPS b/components/sync_sessions/DEPS index 564d4219..9ce25856 100644 --- a/components/sync_sessions/DEPS +++ b/components/sync_sessions/DEPS
@@ -2,10 +2,12 @@ "+components/bookmarks/browser", "+components/favicon/core", "+components/history/core/browser", + "+components/keyed_service/core", "+components/prefs", "+components/sessions", "+components/sync", "+components/variations", + "+components/version_info", "+ui/base/page_transition_types.h", "+ui/gfx", ]
diff --git a/components/sync_sessions/mock_sync_sessions_client.h b/components/sync_sessions/mock_sync_sessions_client.h index 33b301cd..0492dee1 100644 --- a/components/sync_sessions/mock_sync_sessions_client.h +++ b/components/sync_sessions/mock_sync_sessions_client.h
@@ -19,10 +19,14 @@ MOCK_METHOD0(GetFaviconService, favicon::FaviconService*()); MOCK_METHOD0(GetHistoryService, history::HistoryService*()); + MOCK_METHOD0(GetSessionSyncPrefs, SessionSyncPrefs*()); + MOCK_METHOD0(GetStoreFactory, syncer::RepeatingModelTypeStoreFactory()); MOCK_METHOD0(GetLocalDeviceInfo, const syncer::DeviceInfo*()); MOCK_CONST_METHOD1(ShouldSyncURL, bool(const GURL& url)); MOCK_METHOD0(GetSyncedWindowDelegatesGetter, SyncedWindowDelegatesGetter*()); MOCK_METHOD0(GetLocalSessionEventRouter, LocalSessionEventRouter*()); + MOCK_METHOD0(IsProxyTabsSyncRunning, bool()); + MOCK_METHOD0(NotifyForeignSessionUpdated, void()); }; } // namespace sync_sessions
diff --git a/components/sync_sessions/session_store.cc b/components/sync_sessions/session_store.cc index 2431884..2e8dfc2 100644 --- a/components/sync_sessions/session_store.cc +++ b/components/sync_sessions/session_store.cc
@@ -16,7 +16,6 @@ #include "base/metrics/histogram_macros.h" #include "base/pickle.h" #include "base/strings/stringprintf.h" -#include "components/sync/base/sync_prefs.h" #include "components/sync/base/time.h" #include "components/sync/device_info/device_info.h" #include "components/sync/device_info/device_info_util.h" @@ -25,6 +24,7 @@ #include "components/sync/model/mutable_data_batch.h" #include "components/sync/protocol/model_type_state.pb.h" #include "components/sync/protocol/sync.pb.h" +#include "components/sync_sessions/session_sync_prefs.h" #include "components/sync_sessions/sync_sessions_client.h" namespace sync_sessions { @@ -77,7 +77,8 @@ } std::string GetSessionTagWithPrefs(const std::string& cache_guid, - syncer::SessionSyncPrefs* sync_prefs) { + SessionSyncPrefs* sync_prefs) { + DCHECK(sync_prefs); const std::string persisted_guid = sync_prefs->GetSyncSessionsGUID(); if (!persisted_guid.empty()) { DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid; @@ -102,17 +103,11 @@ public: // Raw pointers must not be null and must outlive this object. FactoryImpl(SyncSessionsClient* sessions_client, - syncer::SessionSyncPrefs* sync_prefs, - const syncer::RepeatingModelTypeStoreFactory& store_factory, const SessionStore::RestoredForeignTabCallback& restored_foreign_tab_callback) : sessions_client_(sessions_client), - sync_prefs_(sync_prefs), - store_factory_(store_factory), restored_foreign_tab_callback_(restored_foreign_tab_callback) { DCHECK(sessions_client); - DCHECK(sync_prefs); - DCHECK(store_factory_); } ~FactoryImpl() {} @@ -125,11 +120,12 @@ SessionStore::SessionInfo session_info; session_info.client_name = device_info.client_name(); session_info.device_type = device_info.device_type(); - session_info.session_tag = GetSessionTagWithPrefs(cache_guid, sync_prefs_); + session_info.session_tag = GetSessionTagWithPrefs( + cache_guid, sessions_client_->GetSessionSyncPrefs()); DVLOG(1) << "Initiating creation of session store"; - store_factory_.Run( + sessions_client_->GetStoreFactory().Run( syncer::SESSIONS, base::BindOnce(&FactoryImpl::OnStoreCreated, base::AsWeakPtr(this), session_info, std::move(callback))); @@ -204,8 +200,6 @@ } SyncSessionsClient* const sessions_client_; - syncer::SessionSyncPrefs* const sync_prefs_; - const syncer::RepeatingModelTypeStoreFactory store_factory_; const SessionStore::RestoredForeignTabCallback restored_foreign_tab_callback_; }; @@ -214,12 +208,9 @@ // static SessionStore::Factory SessionStore::CreateFactory( SyncSessionsClient* sessions_client, - syncer::SessionSyncPrefs* sync_prefs, - const syncer::RepeatingModelTypeStoreFactory& store_factory, const RestoredForeignTabCallback& restored_foreign_tab_callback) { - auto factory = - std::make_unique<FactoryImpl>(sessions_client, sync_prefs, store_factory, - restored_foreign_tab_callback); + auto factory = std::make_unique<FactoryImpl>(sessions_client, + restored_foreign_tab_callback); return base::BindRepeating(&FactoryImpl::Create, std::move(factory)); }
diff --git a/components/sync_sessions/session_store.h b/components/sync_sessions/session_store.h index 9b4675f..db274633 100644 --- a/components/sync_sessions/session_store.h +++ b/components/sync_sessions/session_store.h
@@ -21,7 +21,6 @@ namespace syncer { class DeviceInfo; -class SessionSyncPrefs; } // namespace syncer namespace sync_sessions { @@ -53,12 +52,10 @@ base::RepeatingCallback<void(const sync_pb::SessionTab&, base::Time)>; // Creates a factory object that is capable of constructing instances of type - // |SessionStore| and handling the involved IO. All pointer arguments must not - // be null and must outlive the factory as well as the instantiated stores. + // |SessionStore| and handling the involved IO. |sessions_client| must not be + // null and must outlive the factory as well as the instantiated stores. static Factory CreateFactory( SyncSessionsClient* sessions_client, - syncer::SessionSyncPrefs* sync_prefs, - const syncer::RepeatingModelTypeStoreFactory& store_factory, const RestoredForeignTabCallback& restored_foreign_tab_callback); // Verifies whether a proto is malformed (e.g. required fields are missing).
diff --git a/components/sync_sessions/session_store_unittest.cc b/components/sync_sessions/session_store_unittest.cc index d1fa2df9..2a4aab80 100644 --- a/components/sync_sessions/session_store_unittest.cc +++ b/components/sync_sessions/session_store_unittest.cc
@@ -12,13 +12,14 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/test/mock_callback.h" +#include "components/prefs/testing_pref_service.h" #include "components/sync/base/hash_util.h" -#include "components/sync/base/sync_prefs.h" #include "components/sync/device_info/device_info.h" #include "components/sync/model/model_type_store_test_util.h" #include "components/sync/protocol/session_specifics.pb.h" #include "components/sync/test/test_matchers.h" #include "components/sync_sessions/mock_sync_sessions_client.h" +#include "components/sync_sessions/session_sync_prefs.h" #include "components/sync_sessions/test_matchers.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -51,15 +52,6 @@ const char kCacheGuid[] = "SomeCacheGuid"; const char kClientName[] = "Some Client Name"; -class MockSessionSyncPrefs : public syncer::SessionSyncPrefs { - public: - MockSessionSyncPrefs() = default; - ~MockSessionSyncPrefs() override = default; - - MOCK_CONST_METHOD0(GetSyncSessionsGUID, std::string()); - MOCK_METHOD1(SetSyncSessionsGUID, void(const std::string& guid)); -}; - // A mock callback that a) can be used as mock to verify call expectations and // b) conveniently exposes the last instantiated session store. class MockFactoryCompletionCallback { @@ -169,22 +161,30 @@ "Chrome 10k", sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id"), + session_sync_prefs_(&pref_service_), underlying_store_( syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest( - syncer::SESSIONS)), - factory_(SessionStore::CreateFactory( - &mock_sync_sessions_client_, - &mock_sync_prefs_, - syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore( - underlying_store_.get()), - mock_restored_foreign_tab_callback_.Get())) {} + syncer::SESSIONS)) { + SessionSyncPrefs::RegisterProfilePrefs(pref_service_.registry()); + + ON_CALL(mock_sync_sessions_client_, GetSessionSyncPrefs()) + .WillByDefault(Return(&session_sync_prefs_)); + ON_CALL(mock_sync_sessions_client_, GetStoreFactory()) + .WillByDefault( + Return(syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore( + underlying_store_.get()))); + + factory_ = SessionStore::CreateFactory( + &mock_sync_sessions_client_, mock_restored_foreign_tab_callback_.Get()); + } ~SessionStoreFactoryTest() override {} base::MessageLoop message_loop_; const syncer::DeviceInfo local_device_info_; + TestingPrefServiceSimple pref_service_; + SessionSyncPrefs session_sync_prefs_; testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_; - testing::NiceMock<MockSessionSyncPrefs> mock_sync_prefs_; testing::NiceMock< base::MockCallback<SessionStore::RestoredForeignTabCallback>> mock_restored_foreign_tab_callback_; @@ -194,9 +194,7 @@ }; TEST_F(SessionStoreFactoryTest, ShouldCreateStore) { - EXPECT_CALL(mock_sync_prefs_, GetSyncSessionsGUID()); - EXPECT_CALL(mock_sync_prefs_, - SetSyncSessionsGUID(std::string("session_sync") + kCacheGuid)); + ASSERT_THAT(session_sync_prefs_.GetSyncSessionsGUID(), IsEmpty()); MockFactoryCompletionCallback completion; EXPECT_CALL(completion, Run(NoModelError(), /*store=*/NotNull(), @@ -206,13 +204,13 @@ ASSERT_THAT(completion.GetResult(), NotNull()); EXPECT_THAT(completion.GetResult()->local_session_info().client_name, Eq(kClientName)); + EXPECT_THAT(session_sync_prefs_.GetSyncSessionsGUID(), + Eq(std::string("session_sync") + kCacheGuid)); } TEST_F(SessionStoreFactoryTest, ShouldReadSessionsGuidFromPrefs) { const std::string kCachedGuid = "cachedguid1"; - EXPECT_CALL(mock_sync_prefs_, SetSyncSessionsGUID(_)).Times(0); - EXPECT_CALL(mock_sync_prefs_, GetSyncSessionsGUID()) - .WillOnce(Return(kCachedGuid)); + session_sync_prefs_.SetSyncSessionsGUID(kCachedGuid); NiceMock<MockFactoryCompletionCallback> completion; factory_.Run(local_device_info_, completion.Get()); @@ -220,6 +218,7 @@ ASSERT_THAT(completion.GetResult(), NotNull()); EXPECT_THAT(completion.GetResult()->local_session_info().session_tag, Eq(kCachedGuid)); + EXPECT_THAT(session_sync_prefs_.GetSyncSessionsGUID(), Eq(kCachedGuid)); } // Test fixture that creates an initial session store. @@ -228,9 +227,7 @@ const std::string kLocalSessionTag = "localsessiontag"; SessionStoreTest() { - ON_CALL(mock_sync_prefs_, GetSyncSessionsGUID()) - .WillByDefault(Return(kLocalSessionTag)); - + session_sync_prefs_.SetSyncSessionsGUID(kLocalSessionTag); session_store_ = CreateSessionStore(); }
diff --git a/components/sync_sessions/session_sync_bridge.cc b/components/sync_sessions/session_sync_bridge.cc index a336278..78e55cdd 100644 --- a/components/sync_sessions/session_sync_bridge.cc +++ b/components/sync_sessions/session_sync_bridge.cc
@@ -102,28 +102,21 @@ SessionSyncBridge::SessionSyncBridge( SyncSessionsClient* sessions_client, - syncer::SessionSyncPrefs* sync_prefs, - const syncer::RepeatingModelTypeStoreFactory& store_factory, - const base::RepeatingClosure& foreign_sessions_updated_callback, std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor) : ModelTypeSyncBridge(std::move(change_processor)), sessions_client_(sessions_client), local_session_event_router_( sessions_client->GetLocalSessionEventRouter()), - foreign_sessions_updated_callback_(foreign_sessions_updated_callback), favicon_cache_(sessions_client->GetFaviconService(), sessions_client->GetHistoryService(), kMaxSyncFavicons), session_store_factory_(SessionStore::CreateFactory( sessions_client, - sync_prefs, - store_factory, base::BindRepeating(&FaviconCache::UpdateMappingsFromForeignTab, base::Unretained(&favicon_cache_)))), weak_ptr_factory_(this) { DCHECK(sessions_client_); DCHECK(local_session_event_router_); - DCHECK(foreign_sessions_updated_callback_); } SessionSyncBridge::~SessionSyncBridge() { @@ -265,7 +258,7 @@ SessionStore::WriteBatch::Commit(std::move(batch)); if (!entity_changes.empty()) { - foreign_sessions_updated_callback_.Run(); + sessions_client_->NotifyForeignSessionUpdated(); } return base::nullopt; @@ -346,18 +339,9 @@ const syncer::DeviceInfo* device_info = sessions_client_->GetLocalDeviceInfo(); - // DeviceInfo must be available by the time sync starts. - // TODO(crbug.com/867801): The DCHECKs later below should suffice but such - // condition is currently not guaranteed due to posting of tasks, which means - // |request| might be slightly stale if sync was disabled and re-enabled - // quickly. As a temporary mitigation, we report an error in this case. - if (!device_info || device_info->guid() != request.cache_guid) { - DLOG(WARNING) << "Stale datatype activation request, treating as error."; - change_processor()->ReportError( - syncer::ModelError(FROM_HERE, "Stale cache GUID")); - return; - } + // DeviceInfo must be available by the time sync starts, because there's no + // task posting involved in the sessions controller. DCHECK(device_info); DCHECK_EQ(device_info->guid(), request.cache_guid); @@ -461,7 +445,7 @@ change_processor()->Delete(header_storage_key, batch->GetMetadataChangeList()); - foreign_sessions_updated_callback_.Run(); + sessions_client_->NotifyForeignSessionUpdated(); } std::unique_ptr<SessionStore::WriteBatch>
diff --git a/components/sync_sessions/session_sync_bridge.h b/components/sync_sessions/session_sync_bridge.h index de8af125..9c35134 100644 --- a/components/sync_sessions/session_sync_bridge.h +++ b/components/sync_sessions/session_sync_bridge.h
@@ -43,9 +43,6 @@ // Raw pointers must not be null and their pointees must outlive this object. SessionSyncBridge( SyncSessionsClient* sessions_client, - syncer::SessionSyncPrefs* sync_prefs, - const syncer::RepeatingModelTypeStoreFactory& store_factory, - const base::RepeatingClosure& foreign_sessions_updated_callback, std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor); ~SessionSyncBridge() override; @@ -99,7 +96,6 @@ SyncSessionsClient* const sessions_client_; LocalSessionEventRouter* const local_session_event_router_; - const base::RepeatingClosure foreign_sessions_updated_callback_; FaviconCache favicon_cache_; SessionsGlobalIdMapper global_id_mapper_;
diff --git a/components/sync_sessions/session_sync_bridge_unittest.cc b/components/sync_sessions/session_sync_bridge_unittest.cc index 174ab8fd..916f2ef 100644 --- a/components/sync_sessions/session_sync_bridge_unittest.cc +++ b/components/sync_sessions/session_sync_bridge_unittest.cc
@@ -15,7 +15,7 @@ #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/test/bind_test_util.h" -#include "base/test/mock_callback.h" +#include "components/prefs/testing_pref_service.h" #include "components/sync/base/hash_util.h" #include "components/sync/base/sync_prefs.h" #include "components/sync/device_info/device_info.h" @@ -33,6 +33,7 @@ #include "components/sync/test/test_matchers.h" #include "components/sync_sessions/favicon_cache.h" #include "components/sync_sessions/mock_sync_sessions_client.h" +#include "components/sync_sessions/session_sync_prefs.h" #include "components/sync_sessions/tab_node_pool.h" #include "components/sync_sessions/test_matchers.h" #include "components/sync_sessions/test_synced_window_delegates_getter.h" @@ -71,15 +72,6 @@ const char kLocalSessionTag[] = "sessiontag1"; -class MockSessionSyncPrefs : public syncer::SessionSyncPrefs { - public: - MockSessionSyncPrefs() = default; - ~MockSessionSyncPrefs() override = default; - - MOCK_CONST_METHOD0(GetSyncSessionsGUID, std::string()); - MOCK_METHOD1(SetSyncSessionsGUID, void(const std::string& guid)); -}; - MATCHER_P(EntityDataHasSpecifics, session_specifics_matcher, "") { return session_specifics_matcher.MatchAndExplain(arg->specifics.session(), result_listener); @@ -174,17 +166,26 @@ "device_id"), store_(syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest( syncer::SESSIONS)), + session_sync_prefs_(&pref_service_), favicon_cache_(/*favicon_service=*/nullptr, /*history_service=*/nullptr, /*max_sync_favicon_limit=*/0) { + SessionSyncPrefs::RegisterProfilePrefs(pref_service_.registry()); + + ON_CALL(mock_sync_sessions_client_, GetSessionSyncPrefs()) + .WillByDefault(Return(&session_sync_prefs_)); + ON_CALL(mock_sync_sessions_client_, GetStoreFactory()) + .WillByDefault( + Return(syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore( + store_.get()))); ON_CALL(mock_sync_sessions_client_, GetLocalDeviceInfo()) .WillByDefault(Return(&local_device_info_)); ON_CALL(mock_sync_sessions_client_, GetSyncedWindowDelegatesGetter()) .WillByDefault(Return(&window_getter_)); ON_CALL(mock_sync_sessions_client_, GetLocalSessionEventRouter()) .WillByDefault(Return(window_getter_.router())); - ON_CALL(mock_sync_prefs_, GetSyncSessionsGUID()) - .WillByDefault(Return(kLocalSessionTag)); + + session_sync_prefs_.SetSyncSessionsGUID(kLocalSessionTag); // Even if we use NiceMock, let's be strict about errors and let tests // explicitly list them. @@ -201,10 +202,7 @@ mock_processor_.DelegateCallsByDefaultTo(real_processor_.get()); // Instantiate the bridge. bridge_ = std::make_unique<SessionSyncBridge>( - &mock_sync_sessions_client_, &mock_sync_prefs_, - /*store_factory=*/ - syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore(store_.get()), - mock_foreign_sessions_updated_callback_.Get(), + &mock_sync_sessions_client_, mock_processor_.CreateForwardingProcessor()); } @@ -305,6 +303,10 @@ void SessionRestoreComplete() { window_getter_.SessionRestoreComplete(); } + MockSyncSessionsClient& mock_sync_sessions_client() { + return mock_sync_sessions_client_; + } + SessionSyncBridge* bridge() { return bridge_.get(); } syncer::MockModelTypeChangeProcessor& mock_processor() { @@ -315,22 +317,16 @@ return real_processor_.get(); } - base::MockCallback<base::RepeatingClosure>& - mock_foreign_sessions_updated_callback() { - return mock_foreign_sessions_updated_callback_; - } - private: base::MessageLoop message_loop_; const syncer::DeviceInfo local_device_info_; const std::unique_ptr<syncer::ModelTypeStore> store_; // Dependencies. + TestingPrefServiceSimple pref_service_; + SessionSyncPrefs session_sync_prefs_; testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_; - testing::NiceMock<MockSessionSyncPrefs> mock_sync_prefs_; testing::NiceMock<MockModelTypeChangeProcessor> mock_processor_; - testing::NiceMock<base::MockCallback<base::RepeatingClosure>> - mock_foreign_sessions_updated_callback_; TestSyncedWindowDelegatesGetter window_getter_; FaviconCache favicon_cache_; @@ -464,7 +460,8 @@ StartSyncing(); ASSERT_THAT(GetAllData(), SizeIs(2)); - EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()).Times(0); + EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated()) + .Times(0); // Expectations for the processor. std::string header_storage_key; @@ -998,8 +995,7 @@ EXPECT_CALL( mock_processor(), Put(_, EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _)), _)); - EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()); - + EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated()); StartSyncing({foreign_header, foreign_tab}); std::vector<const SyncedSession*> foreign_sessions; @@ -1146,7 +1142,7 @@ sync_pb::ModelTypeState state; state.set_initial_sync_done(true); - EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()); + EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated()); real_processor()->OnUpdateReceived( state, {CreateTombstone(SessionStore::GetClientTag(foreign_header))}); @@ -1315,7 +1311,7 @@ // Mimic the user requesting a session deletion from the UI. EXPECT_CALL(mock_processor(), Delete(foreign_header_storage_key, _)); EXPECT_CALL(mock_processor(), Delete(foreign_tab_storage_key, _)); - EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()); + EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated()); bridge()->GetOpenTabsUIDelegate()->DeleteForeignSession(kForeignSessionTag); // Verify what gets exposed to the UI. @@ -1337,7 +1333,8 @@ InitializeBridge(); StartSyncing(); - EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()).Times(0); + EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated()) + .Times(0); EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); bridge()->GetOpenTabsUIDelegate()->DeleteForeignSession(kLocalSessionTag); @@ -1355,7 +1352,8 @@ InitializeBridge(); StartSyncing(); - EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()).Times(0); + EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated()) + .Times(0); // Mimic receiving an empty list of remote updates. sync_pb::ModelTypeState state; @@ -1406,7 +1404,7 @@ EXPECT_CALL( mock_processor(), Delete(SessionStore::GetTabStorageKey(kStaleSessionTag, kTabNodeId), _)); - EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()); + EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated()); bridge()->ScheduleGarbageCollection(); base::RunLoop().RunUntilIdle();
diff --git a/components/sync_sessions/session_sync_prefs.cc b/components/sync_sessions/session_sync_prefs.cc new file mode 100644 index 0000000..8cb5f266 --- /dev/null +++ b/components/sync_sessions/session_sync_prefs.cc
@@ -0,0 +1,39 @@ +// 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/sync_sessions/session_sync_prefs.h" + +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" + +namespace sync_sessions { +namespace { + +// The GUID session sync will use to identify this client, even across sync +// disable/enable events. +const char kSyncSessionsGUID[] = "sync.session_sync_guid"; + +} // namespace + +// static +void SessionSyncPrefs::RegisterProfilePrefs(PrefRegistrySimple* registry) { + registry->RegisterStringPref(kSyncSessionsGUID, std::string()); +} + +SessionSyncPrefs::SessionSyncPrefs(PrefService* pref_service) + : pref_service_(pref_service) { + DCHECK(pref_service); +} + +SessionSyncPrefs::~SessionSyncPrefs() {} + +std::string SessionSyncPrefs::GetSyncSessionsGUID() const { + return pref_service_->GetString(kSyncSessionsGUID); +} + +void SessionSyncPrefs::SetSyncSessionsGUID(const std::string& guid) { + pref_service_->SetString(kSyncSessionsGUID, guid); +} + +} // namespace sync_sessions
diff --git a/components/sync_sessions/session_sync_prefs.h b/components/sync_sessions/session_sync_prefs.h new file mode 100644 index 0000000..5e5774a --- /dev/null +++ b/components/sync_sessions/session_sync_prefs.h
@@ -0,0 +1,36 @@ +// 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 COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_PREFS_H_ +#define COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_PREFS_H_ + +#include <string> + +#include "base/macros.h" + +class PrefService; +class PrefRegistrySimple; + +namespace sync_sessions { + +// Use this for the unique machine tag used for session sync. +class SessionSyncPrefs { + public: + static void RegisterProfilePrefs(PrefRegistrySimple* registry); + + explicit SessionSyncPrefs(PrefService* pref_service); + ~SessionSyncPrefs(); + + std::string GetSyncSessionsGUID() const; + void SetSyncSessionsGUID(const std::string& guid); + + private: + PrefService* const pref_service_; + + DISALLOW_COPY_AND_ASSIGN(SessionSyncPrefs); +}; + +} // namespace sync_sessions + +#endif // COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_PREFS_H_
diff --git a/components/sync_sessions/session_sync_service.cc b/components/sync_sessions/session_sync_service.cc new file mode 100644 index 0000000..ae81516 --- /dev/null +++ b/components/sync_sessions/session_sync_service.cc
@@ -0,0 +1,73 @@ +// 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/sync_sessions/session_sync_service.h" + +#include <utility> + +#include "base/bind_helpers.h" +#include "components/sync/base/report_unrecoverable_error.h" +#include "components/sync/driver/sync_driver_switches.h" +#include "components/sync/model_impl/client_tag_based_model_type_processor.h" +#include "components/sync_sessions/favicon_cache.h" +#include "components/sync_sessions/session_data_type_controller.h" +#include "components/sync_sessions/session_sync_bridge.h" +#include "components/sync_sessions/session_sync_prefs.h" +#include "components/sync_sessions/sessions_sync_manager.h" +#include "components/sync_sessions/sync_sessions_client.h" + +namespace sync_sessions { + +SessionSyncService::SessionSyncService( + version_info::Channel channel, + std::unique_ptr<SyncSessionsClient> sessions_client) + : sessions_client_(std::move(sessions_client)) { + DCHECK(sessions_client_); + if (base::FeatureList::IsEnabled(switches::kSyncUSSSessions)) { + sessions_sync_manager_ = std::make_unique<sync_sessions::SessionSyncBridge>( + sessions_client_.get(), + std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( + syncer::SESSIONS, + base::BindRepeating(&syncer::ReportUnrecoverableError, channel))); + } else { + sessions_sync_manager_ = + std::make_unique<sync_sessions::SessionsSyncManager>( + sessions_client_.get()); + } +} + +SessionSyncService::~SessionSyncService() {} + +syncer::GlobalIdMapper* SessionSyncService::GetGlobalIdMapper() const { + return sessions_sync_manager_->GetGlobalIdMapper(); +} + +OpenTabsUIDelegate* SessionSyncService::GetRawOpenTabsUIDelegate() { + return sessions_sync_manager_->GetOpenTabsUIDelegate(); +} + +void SessionSyncService::ScheduleGarbageCollection() { + sessions_sync_manager_->ScheduleGarbageCollection(); +} + +syncer::SyncableService* SessionSyncService::GetSyncableService() { + return sessions_sync_manager_->GetSyncableService(); +} + +base::WeakPtr<syncer::ModelTypeControllerDelegate> +SessionSyncService::GetControllerDelegate() { + return sessions_sync_manager_->GetModelTypeSyncBridge() + ->change_processor() + ->GetControllerDelegate(); +} + +FaviconCache* SessionSyncService::GetFaviconCache() { + return sessions_sync_manager_->GetFaviconCache(); +} + +void SessionSyncService::SetSyncSessionsGUID(const std::string& guid) { + sessions_client_->GetSessionSyncPrefs()->SetSyncSessionsGUID(guid); +} + +} // namespace sync_sessions
diff --git a/components/sync_sessions/session_sync_service.h b/components/sync_sessions/session_sync_service.h new file mode 100644 index 0000000..c6bd77d --- /dev/null +++ b/components/sync_sessions/session_sync_service.h
@@ -0,0 +1,73 @@ +// 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 COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_SERVICE_H_ +#define COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_SERVICE_H_ + +#include <memory> +#include <string> + +#include "base/memory/weak_ptr.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/sync/model/model_type_store.h" +#include "components/version_info/channel.h" + +namespace syncer { +class GlobalIdMapper; +class ModelTypeControllerDelegate; +class SyncableService; +} // namespace syncer + +namespace sync_sessions { + +class AbstractSessionsSyncManager; +class FaviconCache; +class OpenTabsUIDelegate; +class SyncSessionsClient; + +// KeyedService responsible session sync (aka tab sync), including favicon sync. +// This powers things like the history UI, where "Tabs from other devices" +// exists, as well as the uploading counterpart for other devices to see our +// local tabs. +class SessionSyncService : public KeyedService { + public: + SessionSyncService(version_info::Channel channel, + std::unique_ptr<SyncSessionsClient> sessions_client); + ~SessionSyncService() override; + + syncer::GlobalIdMapper* GetGlobalIdMapper() const; + + // Intended for ProfileSyncService: returns the OpenTabsUIDelegate instance, + // which is guaranteed to be non-null (independently of whether sync is + // running or not) + OpenTabsUIDelegate* GetRawOpenTabsUIDelegate(); + + // Schedules garbage collection of foreign sessions. + void ScheduleGarbageCollection(); + + // For ProfileSyncService to initialize the controller for SESSIONS. Exactly + // one of the two below will return non-null (depending on a feature toggle). + syncer::SyncableService* GetSyncableService(); + base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate(); + + // For ProfileSyncService to initialize the controller for FAVICON_IMAGES and + // FAVICON_TRACKING. + FaviconCache* GetFaviconCache(); + + // Used on Android only, to override the machine tag. + void SetSyncSessionsGUID(const std::string& guid); + + private: + std::unique_ptr<SyncSessionsClient> sessions_client_; + + // Locally owned SyncableService or ModelTypeSyncBridge implementations. + std::unique_ptr<sync_sessions::AbstractSessionsSyncManager> + sessions_sync_manager_; + + DISALLOW_COPY_AND_ASSIGN(SessionSyncService); +}; + +} // namespace sync_sessions + +#endif // COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_SERVICE_H_
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc index a890612..503f362 100644 --- a/components/sync_sessions/sessions_sync_manager.cc +++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -22,6 +22,7 @@ #include "components/sync/model/sync_merge_result.h" #include "components/sync/model/time.h" #include "components/sync_sessions/local_session_event_router.h" +#include "components/sync_sessions/session_sync_prefs.h" #include "components/sync_sessions/sync_sessions_client.h" #include "components/sync_sessions/tab_node_pool.h" @@ -137,9 +138,7 @@ // |local_device| is owned by ProfileSyncService, its lifetime exceeds // lifetime of SessionSyncManager. SessionsSyncManager::SessionsSyncManager( - sync_sessions::SyncSessionsClient* sessions_client, - syncer::SessionSyncPrefs* sync_prefs, - const base::RepeatingClosure& sessions_updated_callback) + sync_sessions::SyncSessionsClient* sessions_client) : sessions_client_(sessions_client), session_tracker_(sessions_client), favicon_cache_(sessions_client->GetFaviconService(), @@ -152,9 +151,7 @@ base::BindRepeating(&SessionsSyncManager::DeleteForeignSessionFromUI, base::Unretained(this))), local_tab_pool_out_of_sync_(true), - sync_prefs_(sync_prefs), - stale_session_threshold_days_(kDefaultStaleSessionThresholdDays), - sessions_updated_callback_(sessions_updated_callback) {} + stale_session_threshold_days_(kDefaultStaleSessionThresholdDays) {} SessionsSyncManager::~SessionsSyncManager() {} @@ -391,8 +388,7 @@ } } - if (!sessions_updated_callback_.is_null()) - sessions_updated_callback_.Run(); + sessions_client_->NotifyForeignSessionUpdated(); return syncer::SyncError(); } @@ -502,7 +498,8 @@ const std::string& cache_guid) { DCHECK(current_machine_tag_.empty()); std::string persisted_guid; - persisted_guid = sync_prefs_->GetSyncSessionsGUID(); + persisted_guid = + sessions_client_->GetSessionSyncPrefs()->GetSyncSessionsGUID(); if (!persisted_guid.empty()) { current_machine_tag_ = persisted_guid; DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid; @@ -510,7 +507,8 @@ DCHECK(!cache_guid.empty()); current_machine_tag_ = BuildMachineTag(cache_guid); DVLOG(1) << "Creating session sync guid: " << current_machine_tag_; - sync_prefs_->SetSyncSessionsGUID(current_machine_tag_); + sessions_client_->GetSessionSyncPrefs()->SetSyncSessionsGUID( + current_machine_tag_); } } @@ -532,8 +530,8 @@ SyncData::CreateLocalDelete(tag, syncer::SESSIONS))); } AppendDeletionsForTabNodes(tab_node_ids_to_delete, tag, change_output); - if (!sessions_updated_callback_.is_null()) - sessions_updated_callback_.Run(); + + sessions_client_->NotifyForeignSessionUpdated(); } void SessionsSyncManager::DeleteForeignSessionFromUI(const std::string& tag) {
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h index d632cbb..0805a0d1 100644 --- a/components/sync_sessions/sessions_sync_manager.h +++ b/components/sync_sessions/sessions_sync_manager.h
@@ -21,7 +21,6 @@ #include "base/time/time.h" #include "components/sessions/core/session_id.h" #include "components/sessions/core/session_types.h" -#include "components/sync/base/sync_prefs.h" #include "components/sync/device_info/device_info.h" #include "components/sync/model/syncable_service.h" #include "components/sync_sessions/abstract_sessions_sync_manager.h" @@ -54,9 +53,7 @@ public syncer::SyncableService, public LocalSessionEventHandlerImpl::Delegate { public: - SessionsSyncManager(SyncSessionsClient* sessions_client, - syncer::SessionSyncPrefs* sync_prefs, - const base::RepeatingClosure& sessions_updated_callback); + explicit SessionsSyncManager(SyncSessionsClient* sessions_client); ~SessionsSyncManager() override; // AbstractSessionsSyncManager implementation. @@ -188,8 +185,6 @@ // proves that we are still relevant. bool local_tab_pool_out_of_sync_; - syncer::SessionSyncPrefs* sync_prefs_; - std::unique_ptr<syncer::SyncErrorFactory> error_handler_; std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_; @@ -206,9 +201,6 @@ std::unique_ptr<sync_sessions::LostNavigationsRecorder> lost_navigations_recorder_; - // Callback to inform interested observer that new sessions data has arrived. - base::RepeatingClosure sessions_updated_callback_; - DISALLOW_COPY_AND_ASSIGN(SessionsSyncManager); };
diff --git a/components/sync_sessions/sessions_sync_manager_unittest.cc b/components/sync_sessions/sessions_sync_manager_unittest.cc index 46b849b..9f2dc2ba 100644 --- a/components/sync_sessions/sessions_sync_manager_unittest.cc +++ b/components/sync_sessions/sessions_sync_manager_unittest.cc
@@ -9,10 +9,10 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" -#include "components/sync/driver/fake_sync_client.h" -#include "components/sync/driver/sync_api_component_factory.h" +#include "components/prefs/testing_pref_service.h" #include "components/sync/model/sync_error_factory_mock.h" #include "components/sync_sessions/mock_sync_sessions_client.h" +#include "components/sync_sessions/session_sync_prefs.h" #include "components/sync_sessions/session_sync_test_helper.h" #include "components/sync_sessions/sync_sessions_client.h" #include "components/sync_sessions/test_synced_window_delegates_getter.h" @@ -113,21 +113,6 @@ return testing::AssertionSuccess(); } -class SessionNotificationObserver { - public: - SessionNotificationObserver() : notified_of_update_(false) {} - void NotifyOfUpdate() { notified_of_update_ = true; } - - bool notified_of_update() const { return notified_of_update_; } - - void Reset() { - notified_of_update_ = false; - } - - private: - bool notified_of_update_; -}; - class TestSyncChangeProcessor : public syncer::SyncChangeProcessor { public: explicit TestSyncChangeProcessor(SyncChangeList* output) : output_(output) {} @@ -188,9 +173,14 @@ "Chromium 10k", "Chrome 10k", sync_pb::SyncEnums_DeviceType_TYPE_LINUX, - "device_id") {} + "device_id"), + session_sync_prefs_(&pref_service_) {} void SetUp() override { + SessionSyncPrefs::RegisterProfilePrefs(pref_service_.registry()); + + ON_CALL(mock_sync_sessions_client_, GetSessionSyncPrefs()) + .WillByDefault(testing::Return(&session_sync_prefs_)); ON_CALL(mock_sync_sessions_client_, GetLocalDeviceInfo()) .WillByDefault(testing::Return(&local_device_info_)); ON_CALL(mock_sync_sessions_client_, GetSyncedWindowDelegatesGetter()) @@ -198,19 +188,13 @@ ON_CALL(mock_sync_sessions_client_, GetLocalSessionEventRouter()) .WillByDefault(testing::Return(window_getter_.router())); - sync_client_ = std::make_unique<syncer::FakeSyncClient>(); - sync_prefs_ = - std::make_unique<syncer::SyncPrefs>(sync_client_->GetPrefService()); - manager_ = std::make_unique<SessionsSyncManager>( - &mock_sync_sessions_client_, sync_prefs_.get(), - base::Bind(&SessionNotificationObserver::NotifyOfUpdate, - base::Unretained(&observer_))); + manager_ = + std::make_unique<SessionsSyncManager>(&mock_sync_sessions_client_); } void TearDown() override { test_processor_ = nullptr; helper()->Reset(); - sync_prefs_.reset(); manager_.reset(); } @@ -218,8 +202,6 @@ SessionsSyncManager* manager() { return manager_.get(); } SessionSyncTestHelper* helper() { return &helper_; } - SessionNotificationObserver* observer() { return &observer_; } - syncer::SyncPrefs* sync_prefs() { return sync_prefs_.get(); } MockSyncSessionsClient* mock_sync_sessions_client() { return &mock_sync_sessions_client_; } @@ -388,10 +370,9 @@ private: const syncer::DeviceInfo local_device_info_; - std::unique_ptr<syncer::FakeSyncClient> sync_client_; + TestingPrefServiceSimple pref_service_; + SessionSyncPrefs session_sync_prefs_; testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_; - std::unique_ptr<syncer::SyncPrefs> sync_prefs_; - SessionNotificationObserver observer_; std::unique_ptr<SessionsSyncManager> manager_; SessionSyncTestHelper helper_; TestSyncChangeProcessor* test_processor_ = nullptr; @@ -1549,7 +1530,6 @@ // Test that NOTIFICATION_FOREIGN_SESSION_UPDATED is sent when processing // sync changes. TEST_F(SessionsSyncManagerTest, NotifiedOfUpdates) { - ASSERT_FALSE(observer()->notified_of_update()); InitWithNoSyncData(); std::vector<sync_pb::SessionSpecifics> tabs1; @@ -1558,20 +1538,18 @@ SyncChangeList changes; changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD)); + EXPECT_CALL(*mock_sync_sessions_client(), NotifyForeignSessionUpdated()); manager()->ProcessSyncChanges(FROM_HERE, changes); - EXPECT_TRUE(observer()->notified_of_update()); changes.clear(); - observer()->Reset(); AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes); + EXPECT_CALL(*mock_sync_sessions_client(), NotifyForeignSessionUpdated()); manager()->ProcessSyncChanges(FROM_HERE, changes); - EXPECT_TRUE(observer()->notified_of_update()); changes.clear(); - observer()->Reset(); changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_DELETE)); + EXPECT_CALL(*mock_sync_sessions_client(), NotifyForeignSessionUpdated()); manager()->ProcessSyncChanges(FROM_HERE, changes); - EXPECT_TRUE(observer()->notified_of_update()); } // Test that NOTIFICATION_FOREIGN_SESSION_UPDATED is sent when handling @@ -1587,10 +1565,8 @@ changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD)); manager()->ProcessSyncChanges(FROM_HERE, changes); - observer()->Reset(); - ASSERT_FALSE(observer()->notified_of_update()); + EXPECT_CALL(*mock_sync_sessions_client(), NotifyForeignSessionUpdated()); manager()->GetOpenTabsUIDelegate()->DeleteForeignSession(tag); - ASSERT_TRUE(observer()->notified_of_update()); } // Tests receipt of duplicate tab IDs in the same window. This should never
diff --git a/components/sync_sessions/sync_sessions_client.h b/components/sync_sessions/sync_sessions_client.h index a256193f..4459f48 100644 --- a/components/sync_sessions/sync_sessions_client.h +++ b/components/sync_sessions/sync_sessions_client.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "components/sync/model/model_type_store.h" class GURL; @@ -21,11 +22,12 @@ namespace syncer { class DeviceInfo; -} +} // namespace syncer namespace sync_sessions { class LocalSessionEventRouter; +class SessionSyncPrefs; class SyncedWindowDelegatesGetter; // Interface for clients of a sync sessions datatype. Should be used as a getter @@ -38,6 +40,8 @@ // Getters for services that sessions depends on. virtual favicon::FaviconService* GetFaviconService() = 0; virtual history::HistoryService* GetHistoryService() = 0; + virtual SessionSyncPrefs* GetSessionSyncPrefs() = 0; + virtual syncer::RepeatingModelTypeStoreFactory GetStoreFactory() = 0; // Checks if the given url is considered interesting enough to sync. Most urls // are considered interesting. Examples of ones that are not are invalid urls, @@ -57,8 +61,8 @@ // embedder's context. virtual LocalSessionEventRouter* GetLocalSessionEventRouter() = 0; - // TODO(zea): add getters for the history and favicon services for the favicon - // cache to consume once it's componentized. + // Called when foreign sessions have been updated. + virtual void NotifyForeignSessionUpdated() = 0; private: DISALLOW_COPY_AND_ASSIGN(SyncSessionsClient);
diff --git a/components/test/data/autofill_assistant/autofill_assistant_target_website.html b/components/test/data/autofill_assistant/autofill_assistant_target_website.html index 836951c..7c96e97 100644 --- a/components/test/data/autofill_assistant/autofill_assistant_target_website.html +++ b/components/test/data/autofill_assistant/autofill_assistant_target_website.html
@@ -32,7 +32,7 @@ section. --> <div id="full_height_section"> - <p>Blank Section + <p>Blank Section</p> </div> <div> @@ -49,6 +49,10 @@ </select> </div> + <div> + <input id="input" type="field" value="helloworld" /> + </div> + <iframe id="iframe" name="test_iframe" width="100%" height="500" src= "autofill_assistant_target_website_iframe_one.html"></iframe> </body>
diff --git a/components/viz/common/quads/compositor_frame_metadata.h b/components/viz/common/quads/compositor_frame_metadata.h index 1baee74d..91be80e 100644 --- a/components/viz/common/quads/compositor_frame_metadata.h +++ b/components/viz/common/quads/compositor_frame_metadata.h
@@ -132,16 +132,16 @@ // determine if scrolling/scaling in a particular direction is possible. float min_page_scale_factor = 0.f; + // Used to position the location top bar and page content, whose precise + // position is computed by the renderer compositor. + float top_controls_height = 0.f; + float top_controls_shown_ratio = 0.f; + #if defined(OS_ANDROID) float max_page_scale_factor = 0.f; gfx::SizeF root_layer_size; bool root_overflow_y_hidden = false; - // Used to position the Android location top bar and page content, whose - // precise position is computed by the renderer compositor. - float top_controls_height = 0.f; - float top_controls_shown_ratio = 0.f; - // Used to position Android bottom bar, whose position is computed by the // renderer compositor. float bottom_controls_height = 0.f;
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc index 33034de..088058c 100644 --- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc +++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -499,12 +499,10 @@ frame_metadata.root_scroll_offset.x()); metadata->SetDouble(VideoFrameMetadata::ROOT_SCROLL_OFFSET_Y, frame_metadata.root_scroll_offset.y()); -#if defined(OS_ANDROID) metadata->SetDouble(VideoFrameMetadata::TOP_CONTROLS_HEIGHT, frame_metadata.top_controls_height); metadata->SetDouble(VideoFrameMetadata::TOP_CONTROLS_SHOWN_RATIO, frame_metadata.top_controls_shown_ratio); -#endif // defined(OS_ANDROID) oracle_.RecordCapture(utilization); const int64_t frame_number = next_capture_frame_number_++;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index dcc7cb4..e56eb6e 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1278,6 +1278,8 @@ "renderer_host/clipboard_host_impl.cc", "renderer_host/clipboard_host_impl.h", "renderer_host/clipboard_host_impl_mac.mm", + "renderer_host/code_cache_host_impl.cc", + "renderer_host/code_cache_host_impl.h", "renderer_host/cursor_manager.cc", "renderer_host/cursor_manager.h", "renderer_host/dip_util.cc",
diff --git a/content/browser/accessibility/accessibility_event_recorder_win.cc b/content/browser/accessibility/accessibility_event_recorder_win.cc index be122ba..0f1c7120 100644 --- a/content/browser/accessibility/accessibility_event_recorder_win.cc +++ b/content/browser/accessibility/accessibility_event_recorder_win.cc
@@ -210,8 +210,33 @@ return; } + std::string event_str = AccessibilityEventToStringUTF8(event); + if (event_str.empty()) { + VLOG(1) << "Ignoring event " << event; + return; + } + + base::win::ScopedVariant childid_self(CHILDID_SELF); + base::win::ScopedVariant role; + iaccessible->get_accRole(childid_self, role.Receive()); + base::win::ScopedVariant state; + iaccessible->get_accState(childid_self, state.Receive()); + int ia_state = V_I4(state.ptr()); + std::string hwnd_class_name = base::UTF16ToUTF8(gfx::GetClassName(hwnd)); + + // Caret is special: + // Log all caret events that occur, with their window class, so that we can + // test to make sure they are only occurring on the desired window class. + if (ROLE_SYSTEM_CARET == V_I4(role.ptr())) { + base::string16 state_str = IAccessibleStateToString(ia_state); + std::string log = base::StringPrintf( + "%s role=ROLE_SYSTEM_CARET %ls window_class=%s", event_str.c_str(), + state_str.c_str(), hwnd_class_name.c_str()); + OnEvent(log); + return; + } + if (only_web_events_) { - std::string hwnd_class_name = base::UTF16ToUTF8(gfx::GetClassName(hwnd)); if (hwnd_class_name != "Chrome_RenderWidgetHostHWND") return; @@ -227,22 +252,10 @@ return; } - std::string event_str = AccessibilityEventToStringUTF8(event); - if (event_str.empty()) { - VLOG(1) << "Ignoring event " << event; - return; - } - - base::win::ScopedVariant childid_self(CHILDID_SELF); - base::win::ScopedVariant role; - iaccessible->get_accRole(childid_self, role.Receive()); base::win::ScopedBstr name_bstr; iaccessible->get_accName(childid_self, name_bstr.Receive()); base::win::ScopedBstr value_bstr; iaccessible->get_accValue(childid_self, value_bstr.Receive()); - base::win::ScopedVariant state; - iaccessible->get_accState(childid_self, state.Receive()); - int ia_state = V_I4(state.ptr()); // Avoid flakiness. Events fired on a WINDOW are out of the control // of a test.
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc index 76f0cce..77b9831 100644 --- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc +++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -142,7 +142,8 @@ void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives( const std::string& test_html, std::vector<Filter>* filters, - std::vector<std::string>* wait_for) { + std::vector<std::string>* wait_for, + std::vector<std::string>* run_until) { for (const std::string& line : base::SplitString(test_html, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { @@ -150,6 +151,7 @@ const std::string& allow_str = formatter_->GetAllowString(); const std::string& deny_str = formatter_->GetDenyString(); const std::string& wait_str = "@WAIT-FOR:"; + const std::string& until_str = "@RUN-UNTIL-EVENT:"; if (base::StartsWith(line, allow_empty_str, base::CompareCase::SENSITIVE)) { filters->push_back( @@ -168,6 +170,9 @@ } else if (base::StartsWith(line, wait_str, base::CompareCase::SENSITIVE)) { wait_for->push_back(line.substr(wait_str.size())); + } else if (base::StartsWith(line, until_str, + base::CompareCase::SENSITIVE)) { + run_until->push_back(line.substr(until_str.size())); } } } @@ -254,9 +259,10 @@ // Parse filters and other directives in the test file. std::vector<std::string> wait_for; + std::vector<std::string> run_until; filters_.clear(); AddDefaultFilters(&filters_); - ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for); + ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for, &run_until); // Get the test URL. GURL url(embedded_test_server()->GetURL( @@ -354,7 +360,7 @@ } // Call the subclass to dump the output. - std::vector<std::string> actual_lines = Dump(); + std::vector<std::string> actual_lines = Dump(run_until); std::string actual_contents_for_output = base::JoinString(actual_lines, "\n") + "\n";
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.h b/content/browser/accessibility/dump_accessibility_browsertest_base.h index 0dfb953b..35a8e57 100644 --- a/content/browser/accessibility/dump_accessibility_browsertest_base.h +++ b/content/browser/accessibility/dump_accessibility_browsertest_base.h
@@ -47,7 +47,8 @@ // including the load complete accessibility event. The subclass should // dump whatever that specific test wants to dump, returning the result // as a sequence of strings. - virtual std::vector<std::string> Dump() = 0; + virtual std::vector<std::string> Dump( + std::vector<std::string>& run_until) = 0; // Add the default filters that are applied to all tests. virtual void AddDefaultFilters( @@ -92,7 +93,8 @@ void ParseHtmlForExtraDirectives( const std::string& test_html, std::vector<AccessibilityTreeFormatter::Filter>* filters, - std::vector<std::string>* wait_for); + std::vector<std::string>* wait_for, + std::vector<std::string>* run_until); // Create the right AccessibilityTreeFormatter subclass. AccessibilityTreeFormatter* CreateAccessibilityTreeFormatter();
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc index 28df2b6b4..3a5dd45c 100644 --- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -69,7 +69,7 @@ base::ASCIIToUTF16("EVENT_OBJECT_FOCUS*DOCUMENT*"), Filter::DENY)); } - std::vector<std::string> Dump() override; + std::vector<std::string> Dump(std::vector<std::string>& run_until) override; void OnDiffFailed() override; void RunEventTest(const base::FilePath::CharType* file_path); @@ -79,7 +79,24 @@ base::string16 final_tree_; }; -std::vector<std::string> DumpAccessibilityEventsTest::Dump() { +bool IsRecordingComplete(AccessibilityEventRecorder& event_recorder, + std::vector<std::string>& run_until) { + // If no @RUN-UNTIL-EVENT directives, then having any events is enough. + if (run_until.empty()) + return true; + + std::vector<std::string> event_logs = event_recorder.event_logs(); + + for (size_t i = 0; i < event_logs.size(); ++i) + for (size_t j = 0; j < run_until.size(); ++j) + if (event_logs[i].find(run_until[j]) != std::string::npos) + return true; + + return false; +} + +std::vector<std::string> DumpAccessibilityEventsTest::Dump( + std::vector<std::string>& run_until) { WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( shell()->web_contents()); base::ProcessId pid = base::GetCurrentProcId(); @@ -103,9 +120,11 @@ web_contents->GetMainFrame()->ExecuteJavaScriptForTests( base::ASCIIToUTF16("go()")); - // Wait for at least one accessibility event generated in response to - // that function. - waiter->WaitForNotification(); + for (;;) { + waiter->WaitForNotification(); // Run at least once. + if (IsRecordingComplete(*event_recorder, run_until)) + break; + } // More than one accessibility event could have been generated. // To make sure we've received all accessibility events, add a @@ -269,6 +288,12 @@ RunEventTest(FILE_PATH_LITERAL("checked-state-changed.html")); } +// http:/crbug.com/889013 +IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest, + DISABLED_AccessibilityEventsCaretMove) { + RunEventTest(FILE_PATH_LITERAL("caret-move.html")); +} + IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest, AccessibilityEventsCSSDisplay) { RunEventTest(FILE_PATH_LITERAL("css-display.html"));
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 5436917..2117370 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -125,7 +125,7 @@ RunTest(test_file, "accessibility/regression"); } - std::vector<std::string> Dump() override { + std::vector<std::string> Dump(std::vector<std::string>& unused) override { std::unique_ptr<AccessibilityTreeFormatter> formatter( CreateAccessibilityTreeFormatter()); formatter->SetFilters(filters_);
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc index 04705fb..8f4f480 100644 --- a/content/browser/devtools/protocol/page_handler.cc +++ b/content/browser/devtools/protocol/page_handler.cc
@@ -175,16 +175,11 @@ media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_X, &root_scroll_offset_x); success &= frame.metadata()->GetDouble( media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_Y, &root_scroll_offset_y); -#if defined(OS_ANDROID) success &= frame.metadata()->GetDouble( media::VideoFrameMetadata::TOP_CONTROLS_HEIGHT, top_controls_height); success &= frame.metadata()->GetDouble( media::VideoFrameMetadata::TOP_CONTROLS_SHOWN_RATIO, top_controls_shown_ratio); -#else - *top_controls_height = 0.; - *top_controls_shown_ratio = 0.; -#endif // defined(OS_ANDROID) DCHECK(success); root_scroll_offset->set_x(root_scroll_offset_x); @@ -948,13 +943,11 @@ if (snapshot_size.IsEmpty()) return; - double top_controls_height = 0.; - double top_controls_shown_ratio = 0.; -#if defined(OS_ANDROID) - top_controls_height = last_compositor_frame_metadata_.top_controls_height; - top_controls_shown_ratio = + double top_controls_height = + last_compositor_frame_metadata_.top_controls_height; + double top_controls_shown_ratio = last_compositor_frame_metadata_.top_controls_shown_ratio; -#endif + std::unique_ptr<Page::ScreencastFrameMetadata> page_metadata = BuildScreencastFrameMetadata( surface_size, last_compositor_frame_metadata_.device_scale_factor,
diff --git a/content/browser/fileapi/file_system_manager_impl.cc b/content/browser/fileapi/file_system_manager_impl.cc index 9a9d1839..29f1d2d 100644 --- a/content/browser/fileapi/file_system_manager_impl.cc +++ b/content/browser/fileapi/file_system_manager_impl.cc
@@ -123,9 +123,11 @@ FileSystemManagerImpl::FileSystemManagerImpl( int process_id, + int frame_id, storage::FileSystemContext* file_system_context, scoped_refptr<ChromeBlobStorageContext> blob_storage_context) : process_id_(process_id), + frame_id_(frame_id), context_(file_system_context), security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()), blob_storage_context_(blob_storage_context), @@ -590,8 +592,7 @@ std::move(callback).Run(base::File::FILE_OK, std::move(writer)); } -void FileSystemManagerImpl::ChooseEntry(int32_t render_frame_id, - ChooseEntryCallback callback) { +void FileSystemManagerImpl::ChooseEntry(ChooseEntryCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (!base::FeatureList::IsEnabled(blink::features::kWritableFilesAPI)) { bindings_.ReportBadMessage("FSMI_WRITABLE_FILES_DISABLED"); @@ -601,7 +602,7 @@ base::PostTaskWithTraits( FROM_HERE, {BrowserThread::UI}, base::BindOnce( - &FileSystemChooser::CreateAndShow, process_id_, render_frame_id, + &FileSystemChooser::CreateAndShow, process_id_, frame_id_, std::move(callback), base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}))); }
diff --git a/content/browser/fileapi/file_system_manager_impl.h b/content/browser/fileapi/file_system_manager_impl.h index f5e4cbf..e92c5e46 100644 --- a/content/browser/fileapi/file_system_manager_impl.h +++ b/content/browser/fileapi/file_system_manager_impl.h
@@ -57,9 +57,12 @@ class CONTENT_EXPORT FileSystemManagerImpl : public blink::mojom::FileSystemManager { public: - // Used by the renderer process host on the UI thread. + // Constructed and held by the render frame host and render process host on + // the UI thread. Used by render frames (via the render frame host), workers + // and pepper (via the render process host). FileSystemManagerImpl( int process_id, + int frame_id, storage::FileSystemContext* file_system_context, scoped_refptr<ChromeBlobStorageContext> blob_storage_context); ~FileSystemManagerImpl() override; @@ -122,8 +125,7 @@ GetPlatformPathCallback callback) override; void CreateWriter(const GURL& file_path, CreateWriterCallback callback) override; - void ChooseEntry(int32_t render_frame_id, - ChooseEntryCallback callback) override; + void ChooseEntry(ChooseEntryCallback callback) override; private: class FileSystemCancellableOperationImpl; @@ -206,6 +208,7 @@ void OnConnectionErrorForOpListeners(OperationListenerID listener_id); const int process_id_; + const int frame_id_; storage::FileSystemContext* const context_; ChildProcessSecurityPolicyImpl* const security_policy_; const scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc index 5d294f8..f17c20d 100644 --- a/content/browser/frame_host/interstitial_page_impl.cc +++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -92,7 +92,7 @@ void TakeFocus(bool reverse) override; int GetTopControlsHeight() const override; int GetBottomControlsHeight() const override; - bool DoBrowserControlsShrinkBlinkSize() const override; + bool DoBrowserControlsShrinkRendererSize() const override; virtual void OnFindReply(int request_id, int number_of_matches, const gfx::Rect& selection_rect, @@ -1025,14 +1025,14 @@ } bool InterstitialPageImpl::InterstitialPageRVHDelegateView:: - DoBrowserControlsShrinkBlinkSize() const { + DoBrowserControlsShrinkRendererSize() const { if (!interstitial_page_->web_contents()) return false; WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(interstitial_page_->web_contents()); if (!web_contents || !web_contents->GetDelegateView()) return false; - return web_contents->GetDelegateView()->DoBrowserControlsShrinkBlinkSize(); + return web_contents->GetDelegateView()->DoBrowserControlsShrinkRendererSize(); } void InterstitialPageImpl::InterstitialPageRVHDelegateView::OnFindReply(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index a187e2df..93efefee 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -40,6 +40,7 @@ #include "content/browser/dom_storage/dom_storage_context_wrapper.h" #include "content/browser/download/mhtml_generation_manager.h" #include "content/browser/file_url_loader_factory.h" +#include "content/browser/fileapi/file_system_manager_impl.h" #include "content/browser/fileapi/file_system_url_loader_factory.h" #include "content/browser/frame_host/cross_process_frame_connector.h" #include "content/browser/frame_host/debug_urls.h" @@ -3594,6 +3595,15 @@ GetProcess()->GetID(), routing_id_), base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO})); + file_system_manager_.reset(new FileSystemManagerImpl( + GetProcess()->GetID(), routing_id_, + GetProcess()->GetStoragePartition()->GetFileSystemContext(), + ChromeBlobStorageContext::GetFor(GetProcess()->GetBrowserContext()))); + registry_->AddInterface( + base::BindRepeating(&FileSystemManagerImpl::BindRequest, + base::Unretained(file_system_manager_.get())), + base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO})); + if (Portal::IsEnabled()) { registry_->AddInterface(base::BindRepeating(IgnoreResult(&Portal::Create), base::Unretained(this)));
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 894ab5f2..baf6df3 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -1617,6 +1617,10 @@ // Hosts blink::mojom::PresentationService for the RenderFrame. std::unique_ptr<PresentationServiceImpl> presentation_service_; + // Hosts blink::mojom::FileSystemManager for the RenderFrame. + std::unique_ptr<FileSystemManagerImpl, BrowserThread::DeleteOnIOThread> + file_system_manager_; + #if !defined(OS_ANDROID) std::unique_ptr<AuthenticatorImpl> authenticator_impl_; #endif
diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc new file mode 100644 index 0000000..d9fa155 --- /dev/null +++ b/content/browser/renderer_host/code_cache_host_impl.cc
@@ -0,0 +1,217 @@ +// 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/renderer_host/code_cache_host_impl.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/task/post_task.h" +#include "base/threading/thread.h" +#include "build/build_config.h" +#include "content/browser/cache_storage/cache_storage_cache.h" +#include "content/browser/cache_storage/cache_storage_cache_handle.h" +#include "content/browser/cache_storage/cache_storage_context_impl.h" +#include "content/browser/cache_storage/cache_storage_manager.h" +#include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/code_cache/generated_code_cache.h" +#include "content/browser/code_cache/generated_code_cache_context.h" +#include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/browser/storage_partition_impl.h" +#include "content/public/browser/resource_context.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/common/content_features.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "net/base/io_buffer.h" +#include "url/gurl.h" +#include "url/origin.h" + +using blink::mojom::CacheStorageError; + +namespace content { + +namespace { + +void NoOpCacheStorageErrorCallback(CacheStorageCacheHandle cache_handle, + CacheStorageError error) {} + +base::Optional<url::Origin> GetRendererOrigin(const GURL& url, + int render_process_id) { + GURL requesting_url = + ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock( + render_process_id); + + if (!requesting_url.is_valid() || !url.is_valid()) + return base::nullopt; + + url::Origin origin = url::Origin::Create(requesting_url); + + // Don't cache the code corresponding to unique origins. The same-origin + // checks should always fail for unique origins but the serialized value of + // unique origins does not ensure this. + if (origin.unique()) + return base::nullopt; + + return origin; +} + +} // namespace + +CodeCacheHostImpl::CodeCacheHostImpl( + int render_process_id, + scoped_refptr<CacheStorageContextImpl> cache_storage_context, + scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context) + : render_process_id_(render_process_id), + cache_storage_context_(std::move(cache_storage_context)), + generated_code_cache_context_(std::move(generated_code_cache_context)), + weak_ptr_factory_(this) {} + +CodeCacheHostImpl::~CodeCacheHostImpl() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); +} + +// static +void CodeCacheHostImpl::Create( + int render_process_id, + scoped_refptr<CacheStorageContextImpl> cache_storage_context, + scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, + blink::mojom::CodeCacheHostRequest request) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + mojo::MakeStrongBinding( + std::make_unique<CodeCacheHostImpl>( + render_process_id, std::move(cache_storage_context), + std::move(generated_code_cache_context)), + std::move(request)); +} + +void CodeCacheHostImpl::DidGenerateCacheableMetadata( + const GURL& url, + base::Time expected_response_time, + const std::vector<uint8_t>& data) { + if (!url.SchemeIsHTTPOrHTTPS()) { + mojo::ReportBadMessage("Invalid URL scheme for code cache."); + return; + } + + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (!base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&CodeCacheHostImpl::DidGenerateCacheableMetadataOnUI, + render_process_id_, url, expected_response_time, data)); + } else { + if (!generated_code_cache_context_ || + !generated_code_cache_context_->generated_code_cache()) + return; + + base::Optional<url::Origin> requesting_origin = + GetRendererOrigin(url, render_process_id_); + if (!requesting_origin) + return; + + generated_code_cache_context_->generated_code_cache()->WriteData( + url, *requesting_origin, expected_response_time, data); + } +} + +void CodeCacheHostImpl::FetchCachedCode(const GURL& url, + FetchCachedCodeCallback callback) { + if (!generated_code_cache_context_ || + !generated_code_cache_context_->generated_code_cache()) { + std::move(callback).Run(base::Time(), std::vector<uint8_t>()); + return; + } + + base::Optional<url::Origin> requesting_origin = + GetRendererOrigin(url, render_process_id_); + if (!requesting_origin) { + std::move(callback).Run(base::Time(), std::vector<uint8_t>()); + return; + } + + auto read_callback = base::BindRepeating( + &CodeCacheHostImpl::OnReceiveCachedCode, weak_ptr_factory_.GetWeakPtr(), + base::Passed(&callback)); + generated_code_cache_context_->generated_code_cache()->FetchEntry( + url, *requesting_origin, read_callback); +} + +void CodeCacheHostImpl::ClearCodeCacheEntry(const GURL& url) { + if (!generated_code_cache_context_ || + !generated_code_cache_context_->generated_code_cache()) + return; + + base::Optional<url::Origin> requesting_origin = + GetRendererOrigin(url, render_process_id_); + if (!requesting_origin) + return; + + generated_code_cache_context_->generated_code_cache()->DeleteEntry( + url, *requesting_origin); +} + +void CodeCacheHostImpl::DidGenerateCacheableMetadataInCacheStorage( + const GURL& url, + base::Time expected_response_time, + const std::vector<uint8_t>& data, + const url::Origin& cache_storage_origin, + const std::string& cache_storage_cache_name) { + scoped_refptr<net::IOBuffer> buf = + base::MakeRefCounted<net::IOBuffer>(data.size()); + if (!data.empty()) + memcpy(buf->data(), &data.front(), data.size()); + + cache_storage_context_->cache_manager()->OpenCache( + cache_storage_origin, CacheStorageOwner::kCacheAPI, + cache_storage_cache_name, + base::BindOnce(&CodeCacheHostImpl::OnCacheStorageOpenCallback, + weak_ptr_factory_.GetWeakPtr(), url, + expected_response_time, buf, data.size())); +} + +void CodeCacheHostImpl::OnReceiveCachedCode(FetchCachedCodeCallback callback, + const base::Time& response_time, + const std::vector<uint8_t>& data) { + // TODO(crbug.com/867848): Pass the data as a mojo data pipe instead + // of vector<uint8> + std::move(callback).Run(response_time, data); +} + +void CodeCacheHostImpl::OnCacheStorageOpenCallback( + const GURL& url, + base::Time expected_response_time, + scoped_refptr<net::IOBuffer> buf, + int buf_len, + CacheStorageCacheHandle cache_handle, + CacheStorageError error) { + if (error != CacheStorageError::kSuccess || !cache_handle.value()) + return; + CacheStorageCache* cache = cache_handle.value(); + cache->WriteSideData( + base::BindOnce(&NoOpCacheStorageErrorCallback, std::move(cache_handle)), + url, expected_response_time, buf, buf_len); +} + +// static +void CodeCacheHostImpl::DidGenerateCacheableMetadataOnUI( + int render_process_id, + const GURL& url, + base::Time expected_response_time, + const std::vector<uint8_t>& data) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + RenderProcessHost* host = RenderProcessHost::FromID(render_process_id); + if (!host) + return; + + // Use the same priority for the metadata write as for script + // resources (see defaultPriorityForResourceType() in WebKit's + // CachedResource.cpp). Note that WebURLRequest::PriorityMedium + // corresponds to net::LOW (see ConvertWebKitPriorityToNetPriority() + // in weburlloader_impl.cc). + const net::RequestPriority kPriority = net::LOW; + host->GetStoragePartition()->GetNetworkContext()->WriteCacheMetadata( + url, kPriority, expected_response_time, data); +} + +} // namespace content
diff --git a/content/browser/renderer_host/code_cache_host_impl.h b/content/browser/renderer_host/code_cache_host_impl.h new file mode 100644 index 0000000..18e9b4ba --- /dev/null +++ b/content/browser/renderer_host/code_cache_host_impl.h
@@ -0,0 +1,98 @@ +// 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_RENDERER_HOST_CODE_CACHE_HOST_IMPL_H_ +#define CONTENT_BROWSER_RENDERER_HOST_CODE_CACHE_HOST_IMPL_H_ + +#include <string> + +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/strings/string16.h" +#include "build/build_config.h" +#include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "third_party/blink/public/mojom/loader/code_cache.mojom.h" +#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h" + +class GURL; + +namespace net { +class IOBuffer; +} + +namespace url { +class Origin; +} + +namespace content { + +class CacheStorageContextImpl; +class CacheStorageCacheHandle; +class GeneratedCodeCacheContext; + +// The implementation of a CodeCacheHost, which stores and retrieves resource +// metadata, either bytecode or native code, generated by a renderer process. +// Instances of this class are owned by by the Mojo pipe that's passed to the +// renderer process via StrongBinding. +// Instances of this class must be created and used on the IO thread. +class CONTENT_EXPORT CodeCacheHostImpl : public blink::mojom::CodeCacheHost { + public: + CodeCacheHostImpl( + int render_process_id, + scoped_refptr<CacheStorageContextImpl> cache_storage_context, + scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context); + ~CodeCacheHostImpl() override; + + static void Create( + int render_process_id, + scoped_refptr<CacheStorageContextImpl> cache_storage_context, + scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, + blink::mojom::CodeCacheHostRequest request); + + private: + // blink::mojom::CodeCacheHost implementation. + void DidGenerateCacheableMetadata(const GURL& url, + base::Time expected_response_time, + const std::vector<uint8_t>& data) override; + void FetchCachedCode(const GURL& url, FetchCachedCodeCallback) override; + void ClearCodeCacheEntry(const GURL& url) override; + void DidGenerateCacheableMetadataInCacheStorage( + const GURL& url, + base::Time expected_response_time, + const std::vector<uint8_t>& data, + const url::Origin& cache_storage_origin, + const std::string& cache_storage_cache_name) override; + + // Helpers. + void OnReceiveCachedCode(FetchCachedCodeCallback callback, + const base::Time& response_time, + const std::vector<uint8_t>& data); + void OnCacheStorageOpenCallback(const GURL& url, + base::Time expected_response_time, + scoped_refptr<net::IOBuffer> buf, + int buf_len, + CacheStorageCacheHandle cache_handle, + blink::mojom::CacheStorageError error); + static void DidGenerateCacheableMetadataOnUI( + int render_process_id, + const GURL& url, + base::Time expected_response_time, + const std::vector<uint8_t>& data); + + // Our render process host ID, used to bind to the correct render process. + const int render_process_id_; + + scoped_refptr<CacheStorageContextImpl> cache_storage_context_; + + scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_; + + base::WeakPtrFactory<CodeCacheHostImpl> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(CodeCacheHostImpl); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_CODE_CACHE_HOST_IMPL_H_
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index c550ca0..b52eed53 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -184,15 +184,16 @@ // Set up a callback to automatically re-connect if we lose our // connection. host_frame_sink_manager.SetConnectionLostCallback(base::BindRepeating( - []() { CompositorDependencies::Get().OnVizFrameSinkManagerLost(); })); + []() { CompositorDependencies::Get().CreateVizFrameSinkManager(); })); - BrowserMainLoop::GetInstance() - ->gpu_channel_establish_factory() - ->EstablishGpuChannel(base::BindOnce( - &CompositorDependencies:: - OnReadyToConnectVizFrameSinkManagerOnMainThread, - base::Unretained(this), std::move(frame_sink_manager_request), - frame_sink_manager_client.PassInterface())); + pending_connect_viz_on_main_thread_ = base::BindOnce( + &CompositorDependencies:: + OnReadyToConnectVizFrameSinkManagerOnMainThread, + base::Unretained(this), std::move(frame_sink_manager_request), + frame_sink_manager_client.PassInterface()); + + // Will connect using the above callback if we are foreground. + TryEstablishVizConnectionIfNeeded(); } SingleThreadTaskGraphRunner task_graph_runner; @@ -274,18 +275,14 @@ } } - void OnVizFrameSinkManagerLost() { - needs_recreate_viz_frame_sink_manager_ = true; - TryRecreateVizFrameSinkManagerIfNeeded(); - } - - void TryRecreateVizFrameSinkManagerIfNeeded() { - // We don't recreate the frame sink manager if backgrounded, as the OS may + void TryEstablishVizConnectionIfNeeded() { + // We don't connect to the viz process if backgrounded, as the OS may // repeatedly kill the resulting process. Instead wait until we come to the // foreground. - if (needs_recreate_viz_frame_sink_manager_ && application_is_foreground_) { - needs_recreate_viz_frame_sink_manager_ = false; - CreateVizFrameSinkManager(); + if (pending_connect_viz_on_main_thread_ && application_is_foreground_) { + BrowserMainLoop::GetInstance() + ->gpu_channel_establish_factory() + ->EstablishGpuChannel(std::move(pending_connect_viz_on_main_thread_)); } } @@ -333,7 +330,7 @@ SendOnForegroundedToGpuService(); low_end_background_cleanup_task_.Cancel(); application_is_foreground_ = true; - TryRecreateVizFrameSinkManagerIfNeeded(); + TryEstablishVizConnectionIfNeeded(); break; case base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES: case base::android::APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES: @@ -351,7 +348,7 @@ // An instance of Android AppListener. std::unique_ptr<base::android::ApplicationStatusListener> app_listener_; bool application_is_foreground_ = true; - bool needs_recreate_viz_frame_sink_manager_ = false; + gpu::GpuChannelEstablishedCallback pending_connect_viz_on_main_thread_; }; const unsigned int kMaxDisplaySwapBuffers = 1U;
diff --git a/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc b/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc index d51f881..ffd3651 100644 --- a/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc +++ b/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
@@ -51,6 +51,10 @@ virtual_device) override { NOTIMPLEMENTED(); } + void RegisterVirtualDevicesChangedObserver( + video_capture::mojom::DevicesChangedObserverPtr observer) override { + NOTIMPLEMENTED(); + } MOCK_METHOD1(DoGetDeviceInfos, void(GetDeviceInfosCallback& callback)); MOCK_METHOD3(DoCreateDevice,
diff --git a/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc b/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc index 0b5aecf..2467c35 100644 --- a/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc +++ b/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
@@ -80,6 +80,10 @@ virtual_device) override { NOTIMPLEMENTED(); } + void RegisterVirtualDevicesChangedObserver( + video_capture::mojom::DevicesChangedObserverPtr observer) override { + NOTIMPLEMENTED(); + } MOCK_METHOD1(DoGetDeviceInfos, void(GetDeviceInfosCallback& callback)); MOCK_METHOD3(DoCreateDevice,
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index 0b441d6..96f0ddc 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc
@@ -25,13 +25,7 @@ #include "content/browser/bad_message.h" #include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/browser/browser_main_loop.h" -#include "content/browser/cache_storage/cache_storage_cache.h" -#include "content/browser/cache_storage/cache_storage_cache_handle.h" -#include "content/browser/cache_storage/cache_storage_context_impl.h" -#include "content/browser/cache_storage/cache_storage_manager.h" #include "content/browser/child_process_security_policy_impl.h" -#include "content/browser/code_cache/generated_code_cache.h" -#include "content/browser/code_cache/generated_code_cache_context.h" #include "content/browser/gpu/gpu_data_manager_impl.h" #include "content/browser/gpu/gpu_process_host.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" @@ -62,7 +56,6 @@ #include "net/base/io_buffer.h" #include "net/base/mime_util.h" #include "net/base/request_priority.h" -#include "net/http/http_cache.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" #include "services/network/public/mojom/network_context.mojom.h" @@ -85,36 +78,11 @@ #include "base/threading/platform_thread.h" #endif -using blink::mojom::CacheStorageError; - namespace content { namespace { const uint32_t kRenderFilteredMessageClasses[] = {ViewMsgStart}; -void NoOpCacheStorageErrorCallback(CacheStorageCacheHandle cache_handle, - CacheStorageError error) {} - -base::Optional<url::Origin> GetRendererOrigin(const GURL& url, - int render_process_id) { - GURL requesting_url = - ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock( - render_process_id); - - if (!requesting_url.is_valid() || !url.is_valid()) - return base::nullopt; - - url::Origin origin = url::Origin::Create(requesting_url); - - // Don't cache the code corresponding to unique origins. The same-origin - // checks should always fail for unique origins but the serialized value of - // unique origins does not ensure this. - if (origin.unique()) - return base::nullopt; - - return origin; -} - } // namespace RenderMessageFilter::RenderMessageFilter( @@ -122,9 +90,7 @@ BrowserContext* browser_context, net::URLRequestContextGetter* request_context, RenderWidgetHelper* render_widget_helper, - MediaInternals* media_internals, - CacheStorageContextImpl* cache_storage_context, - GeneratedCodeCacheContext* generated_code_cache_context) + MediaInternals* media_internals) : BrowserMessageFilter(kRenderFilteredMessageClasses, arraysize(kRenderFilteredMessageClasses)), BrowserAssociatedInterface<mojom::RenderMessageFilter>(this, this), @@ -134,8 +100,6 @@ render_widget_helper_(render_widget_helper), render_process_id_(render_process_id), media_internals_(media_internals), - cache_storage_context_(cache_storage_context), - generated_code_cache_context_(generated_code_cache_context), weak_ptr_factory_(this) { DCHECK(request_context_.get()); @@ -227,118 +191,6 @@ } #endif -void RenderMessageFilter::DidGenerateCacheableMetadata( - const GURL& url, - base::Time expected_response_time, - const std::vector<uint8_t>& data) { - if (!url.SchemeIsHTTPOrHTTPS()) { - bad_message::ReceivedBadMessage( - this, bad_message::RMF_BAD_URL_CACHEABLE_METADATA); - return; - } - - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - if (!base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) { - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&RenderMessageFilter::DidGenerateCacheableMetadataOnUI, - this, url, expected_response_time, data)); - } else { - if (!generated_code_cache_context_ || - !generated_code_cache_context_->generated_code_cache()) - return; - - base::Optional<url::Origin> requesting_origin = - GetRendererOrigin(url, render_process_id_); - if (!requesting_origin) - return; - - generated_code_cache_context_->generated_code_cache()->WriteData( - url, *requesting_origin, expected_response_time, data); - } -} - -void RenderMessageFilter::FetchCachedCode(const GURL& url, - FetchCachedCodeCallback callback) { - if (!generated_code_cache_context_ || - !generated_code_cache_context_->generated_code_cache()) { - std::move(callback).Run(base::Time(), std::vector<uint8_t>()); - return; - } - - base::Optional<url::Origin> requesting_origin = - GetRendererOrigin(url, render_process_id_); - if (!requesting_origin) { - std::move(callback).Run(base::Time(), std::vector<uint8_t>()); - return; - } - - base::RepeatingCallback<void(const base::Time&, const std::vector<uint8_t>&)> - read_callback = base::BindRepeating( - &RenderMessageFilter::OnReceiveCachedCode, - weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)); - generated_code_cache_context_->generated_code_cache()->FetchEntry( - url, *requesting_origin, read_callback); -} - -void RenderMessageFilter::OnReceiveCachedCode( - FetchCachedCodeCallback callback, - const base::Time& response_time, - const std::vector<uint8_t>& data) { - // TODO(crbug.com/867848): Pass the data as a mojo data pipe instead - // of vector<uint8> - std::move(callback).Run(response_time, data); -} - -void RenderMessageFilter::ClearCodeCacheEntry(const GURL& url) { - if (!generated_code_cache_context_ || - !generated_code_cache_context_->generated_code_cache()) - return; - - base::Optional<url::Origin> requesting_origin = - GetRendererOrigin(url, render_process_id_); - if (!requesting_origin) - return; - - generated_code_cache_context_->generated_code_cache()->DeleteEntry( - url, *requesting_origin); -} - -void RenderMessageFilter::DidGenerateCacheableMetadataInCacheStorage( - const GURL& url, - base::Time expected_response_time, - const std::vector<uint8_t>& data, - const url::Origin& cache_storage_origin, - const std::string& cache_storage_cache_name) { - scoped_refptr<net::IOBuffer> buf = - base::MakeRefCounted<net::IOBuffer>(data.size()); - if (!data.empty()) - memcpy(buf->data(), &data.front(), data.size()); - - cache_storage_context_->cache_manager()->OpenCache( - cache_storage_origin, CacheStorageOwner::kCacheAPI, - cache_storage_cache_name, - base::BindOnce(&RenderMessageFilter::OnCacheStorageOpenCallback, - weak_ptr_factory_.GetWeakPtr(), url, - expected_response_time, buf, data.size())); -} - -void RenderMessageFilter::OnCacheStorageOpenCallback( - const GURL& url, - base::Time expected_response_time, - scoped_refptr<net::IOBuffer> buf, - int buf_len, - CacheStorageCacheHandle cache_handle, - CacheStorageError error) { - if (error != CacheStorageError::kSuccess || !cache_handle.value()) - return; - CacheStorageCache* cache = cache_handle.value(); - cache->WriteSideData( - base::BindOnce(&NoOpCacheStorageErrorCallback, std::move(cache_handle)), - url, expected_response_time, buf, buf_len); -} - void RenderMessageFilter::OnMediaLogEvents( const std::vector<media::MediaLogEvent>& events) { // OnMediaLogEvents() is always dispatched to the UI thread for handling. @@ -352,23 +204,4 @@ GpuProcessHost::GetHasGpuProcess(std::move(callback)); } -void RenderMessageFilter::DidGenerateCacheableMetadataOnUI( - const GURL& url, - base::Time expected_response_time, - const std::vector<uint8_t>& data) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - RenderProcessHost* host = RenderProcessHost::FromID(render_process_id_); - if (!host) - return; - - // Use the same priority for the metadata write as for script - // resources (see defaultPriorityForResourceType() in WebKit's - // CachedResource.cpp). Note that WebURLRequest::PriorityMedium - // corresponds to net::LOW (see ConvertWebKitPriorityToNetPriority() - // in weburlloader_impl.cc). - const net::RequestPriority kPriority = net::LOW; - host->GetStoragePartition()->GetNetworkContext()->WriteCacheMetadata( - url, kPriority, expected_response_time, data); -} - } // namespace content
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h index 58aa169..925508c 100644 --- a/content/browser/renderer_host/render_message_filter.h +++ b/content/browser/renderer_host/render_message_filter.h
@@ -42,23 +42,15 @@ } namespace net { -class IOBuffer; class URLRequestContextGetter; } -namespace url { -class Origin; -} - namespace content { class BrowserContext; -class CacheStorageContextImpl; -class CacheStorageCacheHandle; class MediaInternals; class RenderWidgetHelper; class ResourceContext; class ResourceDispatcherHostImpl; -class GeneratedCodeCacheContext; // This class filters out incoming IPC messages for the renderer process on the // IPC thread. @@ -72,9 +64,7 @@ BrowserContext* browser_context, net::URLRequestContextGetter* request_context, RenderWidgetHelper* render_widget_helper, - MediaInternals* media_internals, - CacheStorageContextImpl* cache_storage_context, - GeneratedCodeCacheContext* generated_code_cache_context); + MediaInternals* media_internals); // BrowserMessageFilter methods: bool OnMessageReceived(const IPC::Message& message) override; @@ -101,17 +91,6 @@ void CreateFullscreenWidget(int opener_id, mojom::WidgetPtr widget, CreateFullscreenWidgetCallback callback) override; - void DidGenerateCacheableMetadata(const GURL& url, - base::Time expected_response_time, - const std::vector<uint8_t>& data) override; - void FetchCachedCode(const GURL& url, FetchCachedCodeCallback) override; - void ClearCodeCacheEntry(const GURL& url) override; - void DidGenerateCacheableMetadataInCacheStorage( - const GURL& url, - base::Time expected_response_time, - const std::vector<uint8_t>& data, - const url::Origin& cache_storage_origin, - const std::string& cache_storage_cache_name) override; void HasGpuProcess(HasGpuProcessCallback callback) override; #if defined(OS_LINUX) void SetThreadPriority(int32_t ns_tid, @@ -125,25 +104,11 @@ base::ThreadPriority priority); #endif - void OnReceiveCachedCode(FetchCachedCodeCallback callback, - const base::Time& response_time, - const std::vector<uint8_t>& data); - void OnCacheStorageOpenCallback(const GURL& url, - base::Time expected_response_time, - scoped_refptr<net::IOBuffer> buf, - int buf_len, - CacheStorageCacheHandle cache_handle, - blink::mojom::CacheStorageError error); void OnMediaLogEvents(const std::vector<media::MediaLogEvent>&); bool CheckBenchmarkingEnabled() const; bool CheckPreparsedJsCachingEnabled() const; - // NetworkContext must be called from the UI thread. - void DidGenerateCacheableMetadataOnUI(const GURL& url, - base::Time expected_response_time, - const std::vector<uint8_t>& data); - // Cached resource request dispatcher host, guaranteed to be non-null. We do // not own it; it is managed by the BrowserProcess, which has a wider scope // than we do. @@ -160,11 +125,6 @@ int render_process_id_; MediaInternals* media_internals_; - CacheStorageContextImpl* cache_storage_context_; - - // TODO(crbug.com/867347): Consider registering its own Mojo interface rather - // than going through RenderMessageFilter. - GeneratedCodeCacheContext* generated_code_cache_context_; base::WeakPtrFactory<RenderMessageFilter> weak_ptr_factory_;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index ceeeff4..295511e 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -85,6 +85,8 @@ #include "content/browser/cache_storage/cache_storage_context_impl.h" #include "content/browser/cache_storage/cache_storage_dispatcher_host.h" #include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/code_cache/generated_code_cache.h" +#include "content/browser/code_cache/generated_code_cache_context.h" #include "content/browser/compositor/surface_utils.h" #include "content/browser/dom_storage/dom_storage_context_wrapper.h" #include "content/browser/dom_storage/dom_storage_message_filter.h" @@ -112,6 +114,7 @@ #include "content/browser/permissions/permission_service_impl.h" #include "content/browser/push_messaging/push_messaging_manager.h" #include "content/browser/renderer_host/clipboard_host_impl.h" +#include "content/browser/renderer_host/code_cache_host_impl.h" #include "content/browser/renderer_host/embedded_frame_sink_provider_impl.h" #include "content/browser/renderer_host/file_utilities_host_impl.h" #include "content/browser/renderer_host/media/media_stream_manager.h" @@ -1955,14 +1958,10 @@ scoped_refptr<net::URLRequestContextGetter> request_context( storage_partition_impl_->GetURLRequestContext()); - // TODO(crbug.com/867347): Consider registering Mojo interface for - // GeneratedCodeCache rather than going through RenderMessageFilter. scoped_refptr<RenderMessageFilter> render_message_filter = base::MakeRefCounted<RenderMessageFilter>( GetID(), GetBrowserContext(), request_context.get(), - widget_helper_.get(), media_internals, - storage_partition_impl_->GetCacheStorageContext(), - storage_partition_impl_->GetGeneratedCodeCacheContext()); + widget_helper_.get(), media_internals); AddFilter(render_message_filter.get()); render_frame_message_filter_ = new RenderFrameMessageFilter( @@ -2046,6 +2045,16 @@ origin)); } +void RenderProcessHostImpl::BindFileSystemManager( + blink::mojom::FileSystemManagerRequest request) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&FileSystemManagerImpl::BindRequest, + base::Unretained(file_system_manager_impl_.get()), + std::move(request))); +} + void RenderProcessHostImpl::CancelProcessShutdownDelayForUnload() { if (IsKeepAliveRefCountDisabled()) return; @@ -2162,8 +2171,14 @@ base::Unretained(push_messaging_manager_.get()))); file_system_manager_impl_.reset(new FileSystemManagerImpl( - GetID(), storage_partition_impl_->GetFileSystemContext(), + GetID(), MSG_ROUTING_NONE, + storage_partition_impl_->GetFileSystemContext(), ChromeBlobStorageContext::GetFor(GetBrowserContext()))); + // This interface is still exposed by the RenderProcessHost's registry so + // that it can be accessed by PepperFileSystemHost. Blink accesses this + // interface through RenderFrameHost/RendererInterfaceBinders. + // TODO(https://crbug.com/873661): Make PepperFileSystemHost access this with + // the RenderFrameHost's registry, and remove this registration. registry->AddInterface( base::BindRepeating(&FileSystemManagerImpl::BindRequest, base::Unretained(file_system_manager_impl_.get()))); @@ -2203,6 +2218,12 @@ registry->AddInterface( base::Bind(&metrics::CreateSingleSampleMetricsProvider)); + registry->AddInterface(base::BindRepeating( + &CodeCacheHostImpl::Create, GetID(), + base::RetainedRef(storage_partition_impl_->GetCacheStorageContext()), + base::RetainedRef( + storage_partition_impl_->GetGeneratedCodeCacheContext()))); + #if BUILDFLAG(ENABLE_REPORTING) registry->AddInterface( base::Bind(&CreateReportingServiceProxy, storage_partition_impl_));
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index f49cb41..5778c10 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -59,6 +59,7 @@ #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" #include "third_party/blink/public/mojom/associated_interfaces/associated_interfaces.mojom.h" #include "third_party/blink/public/mojom/dom_storage/storage_partition_service.mojom.h" +#include "third_party/blink/public/mojom/filesystem/file_system.mojom.h" #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h" #include "ui/gfx/gpu_memory_buffer.h" #include "ui/gl/gpu_switching_observer.h" @@ -448,6 +449,9 @@ // before the process shuts down. void DelayProcessShutdownForUnload(const base::TimeDelta& timeout); + // Binds request to the FileSystemManager instance owned by the render process + // host, and is used by workers via RendererInterfaceBinders. + void BindFileSystemManager(blink::mojom::FileSystemManagerRequest request); FileSystemManagerImpl* GetFileSystemManagerForTesting() { return file_system_manager_impl_.get(); }
diff --git a/content/browser/renderer_host/render_view_host_delegate_view.cc b/content/browser/renderer_host/render_view_host_delegate_view.cc index 746ea59..ac2f6c6 100644 --- a/content/browser/renderer_host/render_view_host_delegate_view.cc +++ b/content/browser/renderer_host/render_view_host_delegate_view.cc
@@ -21,7 +21,7 @@ return 0; } -bool RenderViewHostDelegateView::DoBrowserControlsShrinkBlinkSize() const { +bool RenderViewHostDelegateView::DoBrowserControlsShrinkRendererSize() const { return false; }
diff --git a/content/browser/renderer_host/render_view_host_delegate_view.h b/content/browser/renderer_host/render_view_host_delegate_view.h index 62e97446..3b77252 100644 --- a/content/browser/renderer_host/render_view_host_delegate_view.h +++ b/content/browser/renderer_host/render_view_host_delegate_view.h
@@ -80,8 +80,8 @@ // Returns the height of the bottom controls in DIP. virtual int GetBottomControlsHeight() const; - // Returns true if the browser controls resize Blink's view size. - virtual bool DoBrowserControlsShrinkBlinkSize() const; + // Returns true if the browser controls resize the renderer's view size. + virtual bool DoBrowserControlsShrinkRendererSize() const; // Do post-event tasks for gesture events. virtual void GestureEventAck(const blink::WebGestureEvent& event,
diff --git a/content/browser/renderer_host/render_widget_host_delegate.cc b/content/browser/renderer_host/render_widget_host_delegate.cc index e5ea12e..82ce021 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.cc +++ b/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -12,6 +12,10 @@ namespace content { +bool RenderWidgetHostDelegate::DoBrowserControlsShrinkRendererSize() const { + return false; +} + int RenderWidgetHostDelegate::GetTopControlsHeight() const { return 0; }
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h index fb8cf2e..477dcc3 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.h +++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -59,6 +59,7 @@ // Functions for controlling the browser top controls slide behavior with page // gesture scrolling. virtual void SetTopControlsShownRatio(float ratio) {} + virtual bool DoBrowserControlsShrinkRendererSize() const; virtual int GetTopControlsHeight() const; virtual void SetTopControlsGestureScrollInProgress(bool in_progress) {}
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 9d5cd65..0b14202 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -812,7 +812,7 @@ visual_properties->bottom_controls_height *= device_scale; } visual_properties->browser_controls_shrink_blink_size = - view_->DoBrowserControlsShrinkBlinkSize(); + view_->DoBrowserControlsShrinkRendererSize(); visual_properties->visible_viewport_size = view_->GetVisibleViewportSize(); // TODO(ccameron): GetLocalSurfaceId is not synchronized with the device // scale factor of the surface. Fix this.
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index c0460f0..4e3782f 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -514,9 +514,9 @@ return view_.GetPhysicalBackingSize(); } -bool RenderWidgetHostViewAndroid::DoBrowserControlsShrinkBlinkSize() const { +bool RenderWidgetHostViewAndroid::DoBrowserControlsShrinkRendererSize() const { auto* delegate_view = GetRenderViewHostDelegateView(); - return delegate_view ? delegate_view->DoBrowserControlsShrinkBlinkSize() + return delegate_view ? delegate_view->DoBrowserControlsShrinkRendererSize() : false; } @@ -1566,7 +1566,7 @@ void RenderWidgetHostViewAndroid::TransformPointToRootSurface( gfx::PointF* point) { *point += gfx::Vector2d( - 0, DoBrowserControlsShrinkBlinkSize() ? GetTopControlsHeight() : 0); + 0, DoBrowserControlsShrinkRendererSize() ? GetTopControlsHeight() : 0); } // TODO(jrg): Find out the implications and answer correctly here,
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 6d3920e..286904c 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -119,7 +119,7 @@ base::OnceCallback<void(const SkBitmap&)> callback) override; void EnsureSurfaceSynchronizedForLayoutTest() override; uint32_t GetCaptureSequenceNumber() const override; - bool DoBrowserControlsShrinkBlinkSize() const override; + bool DoBrowserControlsShrinkRendererSize() const override; float GetTopControlsHeight() const override; float GetBottomControlsHeight() const override; int GetMouseWheelMinimumGranularity() const override;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 3df0ea6..95444b0 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -838,9 +838,9 @@ return latest_capture_sequence_number_; } -bool RenderWidgetHostViewAura::DoBrowserControlsShrinkBlinkSize() const { - return !top_controls_gesture_scroll_in_progress_ && - top_controls_shown_ratio_ > 0; +bool RenderWidgetHostViewAura::DoBrowserControlsShrinkRendererSize() const { + return host()->delegate() && + host()->delegate()->DoBrowserControlsShrinkRendererSize(); } float RenderWidgetHostViewAura::GetTopControlsHeight() const { @@ -996,11 +996,9 @@ const blink::WebInputEvent::Type event_type = event.GetType(); if (event_type == blink::WebGestureEvent::kGestureScrollBegin || event_type == blink::WebGestureEvent::kGestureScrollEnd) { - top_controls_gesture_scroll_in_progress_ = - event_type == blink::WebGestureEvent::kGestureScrollBegin; if (host()->delegate()) { host()->delegate()->SetTopControlsGestureScrollInProgress( - top_controls_gesture_scroll_in_progress_); + event_type == blink::WebGestureEvent::kGestureScrollBegin); } } @@ -2094,9 +2092,10 @@ const cc::RenderFrameMetadata& metadata) { DCHECK(window_); - top_controls_shown_ratio_ = metadata.top_controls_shown_ratio; - if (host()->delegate()) - host()->delegate()->SetTopControlsShownRatio(top_controls_shown_ratio_); + if (host()->delegate()) { + host()->delegate()->SetTopControlsShownRatio( + metadata.top_controls_shown_ratio); + } SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(), metadata.local_surface_id);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index f9625ed..cfb4918a 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -137,7 +137,7 @@ void SetTooltipText(const base::string16& tooltip_text) override; void DisplayTooltipText(const base::string16& tooltip_text) override; uint32_t GetCaptureSequenceNumber() const override; - bool DoBrowserControlsShrinkBlinkSize() const override; + bool DoBrowserControlsShrinkRendererSize() const override; float GetTopControlsHeight() const override; bool IsSurfaceAvailableForCopy() const override; void CopyFromSurface( @@ -569,9 +569,6 @@ // Tracks the ancestors of the RWHVA window for window location changes. std::unique_ptr<WindowAncestorObserver> ancestor_window_observer_; - float top_controls_shown_ratio_ = 0.f; - bool top_controls_gesture_scroll_in_progress_ = false; - // Are we in the process of closing? Tracked so fullscreen views can avoid // sending a second shutdown request to the host when they lose the focus // after requesting shutdown for another reason (e.g. Escape key).
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 7c8f4aab..dd63f89 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -125,7 +125,7 @@ GetDeviceScaleFactor()); } -bool RenderWidgetHostViewBase::DoBrowserControlsShrinkBlinkSize() const { +bool RenderWidgetHostViewBase::DoBrowserControlsShrinkRendererSize() const { return false; }
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 fe8db96..31fbb90 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -229,9 +229,9 @@ // The size of the view's backing surface in non-DPI-adjusted pixels. virtual gfx::Size GetCompositorViewportPixelSize() const; - // Whether or not Blink's viewport size should be shrunk by the height of the - // URL-bar. - virtual bool DoBrowserControlsShrinkBlinkSize() const; + // Whether or not the renderer's viewport size should be shrunk by the height + // of the URL-bar. + virtual bool DoBrowserControlsShrinkRendererSize() const; // The height of the URL-bar browser controls. virtual float GetTopControlsHeight() const;
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc index c3a8bdc..f017a37 100644 --- a/content/browser/renderer_interface_binders.cc +++ b/content/browser/renderer_interface_binders.cc
@@ -149,6 +149,13 @@ static_cast<RenderProcessHostImpl*>(host)->BindCacheStorage( std::move(request), origin); })); + // TODO(https://crbug.com/873661): Pass origin to FileSystemMananger. + parameterized_binder_registry_.AddInterface(base::BindRepeating( + [](blink::mojom::FileSystemManagerRequest request, + RenderProcessHost* host, const url::Origin& origin) { + static_cast<RenderProcessHostImpl*>(host)->BindFileSystemManager( + std::move(request)); + })); parameterized_binder_registry_.AddInterface( base::Bind([](blink::mojom::PermissionServiceRequest request, RenderProcessHost* host, const url::Origin& origin) {
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 09f197b..1dbfe83 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -22,11 +22,13 @@ #include "base/memory/ref_counted.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" +#include "base/no_destructor.h" #include "base/process/process.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" @@ -2104,6 +2106,10 @@ delegate_->SetTopControlsShownRatio(this, ratio); } +bool WebContentsImpl::DoBrowserControlsShrinkRendererSize() const { + return delegate_ && delegate_->DoBrowserControlsShrinkRendererSize(this); +} + int WebContentsImpl::GetTopControlsHeight() const { return delegate_ ? delegate_->GetTopControlsHeight() : 0; } @@ -5085,6 +5091,31 @@ context_menu_params); } +namespace { +// Normalizes the line endings: \r\n -> \n, lone \r -> \n. +base::string16 NormalizeLineBreaks(const base::string16& source) { + static const base::NoDestructor<base::string16> kReturnNewline( + base::ASCIIToUTF16("\r\n")); + static const base::NoDestructor<base::string16> kReturn( + base::ASCIIToUTF16("\r")); + static const base::NoDestructor<base::string16> kNewline( + base::ASCIIToUTF16("\n")); + + std::vector<base::StringPiece16> pieces; + + for (const auto& rn_line : base::SplitStringPieceUsingSubstr( + source, *kReturnNewline, base::KEEP_WHITESPACE, + base::SPLIT_WANT_ALL)) { + auto r_lines = base::SplitStringPieceUsingSubstr( + rn_line, *kReturn, base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + std::move(std::begin(r_lines), std::end(r_lines), + std::back_inserter(pieces)); + } + + return base::JoinString(pieces, *kNewline); +} +} // namespace + void WebContentsImpl::RunJavaScriptDialog(RenderFrameHost* render_frame_host, const base::string16& message, const base::string16& default_prompt, @@ -5134,16 +5165,19 @@ is_showing_javascript_dialog_ = true; + base::string16 normalized_message = NormalizeLineBreaks(message); + for (auto* handler : page_handlers) { handler->DidRunJavaScriptDialog( - render_frame_host->GetLastCommittedURL(), message, default_prompt, - dialog_type, has_non_devtools_handlers, + render_frame_host->GetLastCommittedURL(), normalized_message, + default_prompt, dialog_type, has_non_devtools_handlers, base::BindOnce(&CloseDialogCallbackWrapper::Run, wrapper, false)); } if (dialog_manager_) { dialog_manager_->RunJavaScriptDialog( - this, render_frame_host, dialog_type, message, default_prompt, + this, render_frame_host, dialog_type, normalized_message, + default_prompt, base::BindOnce(&CloseDialogCallbackWrapper::Run, wrapper, false), &suppress_this_message); }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 1260b590..511f9db 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -694,6 +694,7 @@ ukm::SourceId GetUkmSourceIdForLastCommittedSource() const override; void SetTopControlsShownRatio(float ratio) override; + bool DoBrowserControlsShrinkRendererSize() const override; int GetTopControlsHeight() const override; void SetTopControlsGestureScrollInProgress(bool in_progress) override; void RenderWidgetCreated(RenderWidgetHostImpl* render_widget_host) override; @@ -1038,6 +1039,8 @@ FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, JavaScriptDialogsInMainAndSubframes); FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, + JavaScriptDialogsNormalizeText); + FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, DialogsFromJavaScriptEndFullscreen); FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, DialogsFromJavaScriptEndFullscreenEvenInInnerWC);
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index 8a65a08..13e32d0 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -1730,6 +1730,26 @@ } IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, + JavaScriptDialogsNormalizeText) { + WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents()); + TestWCDelegateForDialogsAndFullscreen test_delegate; + wc->SetDelegate(&test_delegate); + + GURL url("about:blank"); + EXPECT_TRUE(NavigateToURL(shell(), url)); + + // A dialog with mixed linebreaks. + std::string alert = "alert('1\\r2\\r\\n3\\n4')"; + test_delegate.WillWaitForDialog(); + EXPECT_TRUE(content::ExecuteScript(wc, alert)); + test_delegate.Wait(); + EXPECT_EQ("1\n2\n3\n4", test_delegate.last_message()); + + wc->SetDelegate(nullptr); + wc->SetJavaScriptDialogManagerForTesting(nullptr); +} + +IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, CreateWebContentsWithRendererProcess) { ASSERT_TRUE(embedded_test_server()->Start()); WebContents* base_web_contents = shell()->web_contents();
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc index 58f0a9d..097eb03 100644 --- a/content/browser/web_contents/web_contents_view_android.cc +++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -521,9 +521,10 @@ return delegate ? delegate->GetBottomControlsHeight() : 0; } -bool WebContentsViewAndroid::DoBrowserControlsShrinkBlinkSize() const { +bool WebContentsViewAndroid::DoBrowserControlsShrinkRendererSize() const { auto* delegate = web_contents_->GetDelegate(); - return delegate ? delegate->DoBrowserControlsShrinkBlinkSize() : false; + return delegate && + delegate->DoBrowserControlsShrinkRendererSize(web_contents_); } bool WebContentsViewAndroid::OnTouchEvent(const ui::MotionEventAndroid& event) {
diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h index 58bb78c..37358129 100644 --- a/content/browser/web_contents/web_contents_view_android.h +++ b/content/browser/web_contents/web_contents_view_android.h
@@ -107,7 +107,7 @@ void TakeFocus(bool reverse) override; int GetTopControlsHeight() const override; int GetBottomControlsHeight() const override; - bool DoBrowserControlsShrinkBlinkSize() const override; + bool DoBrowserControlsShrinkRendererSize() const override; // ui::EventHandlerAndroid implementation. bool OnTouchEvent(const ui::MotionEventAndroid& event) override;
diff --git a/content/common/common_param_traits_unittest.cc b/content/common/common_param_traits_unittest.cc index 4d4ee04..7c395a8 100644 --- a/content/common/common_param_traits_unittest.cc +++ b/content/common/common_param_traits_unittest.cc
@@ -256,9 +256,9 @@ content::RenderWidgetSurfaceProperties input; input.size = gfx::Size(23, 45); input.device_scale_factor = 0.8; -#ifdef OS_ANDROID input.top_controls_height = 16.5; input.top_controls_shown_ratio = 0.4; +#ifdef OS_ANDROID input.bottom_controls_height = 23.4; input.bottom_controls_shown_ratio = 0.8; input.selection.start.set_type(gfx::SelectionBound::Type::CENTER); @@ -275,9 +275,9 @@ EXPECT_EQ(input.size, output.size); EXPECT_EQ(input.device_scale_factor, output.device_scale_factor); -#ifdef OS_ANDROID EXPECT_EQ(input.top_controls_height, output.top_controls_height); EXPECT_EQ(input.top_controls_shown_ratio, output.top_controls_shown_ratio); +#ifdef OS_ANDROID EXPECT_EQ(input.bottom_controls_height, output.bottom_controls_height); EXPECT_EQ(input.bottom_controls_shown_ratio, output.bottom_controls_shown_ratio);
diff --git a/content/common/content_param_traits_macros.h b/content/common/content_param_traits_macros.h index f9bbe75..a2c4c7a 100644 --- a/content/common/content_param_traits_macros.h +++ b/content/common/content_param_traits_macros.h
@@ -69,9 +69,9 @@ IPC_STRUCT_TRAITS_BEGIN(content::RenderWidgetSurfaceProperties) IPC_STRUCT_TRAITS_MEMBER(size) IPC_STRUCT_TRAITS_MEMBER(device_scale_factor) -#ifdef OS_ANDROID IPC_STRUCT_TRAITS_MEMBER(top_controls_height) IPC_STRUCT_TRAITS_MEMBER(top_controls_shown_ratio) +#ifdef OS_ANDROID IPC_STRUCT_TRAITS_MEMBER(bottom_controls_height) IPC_STRUCT_TRAITS_MEMBER(bottom_controls_shown_ratio) IPC_STRUCT_TRAITS_MEMBER(selection)
diff --git a/content/common/font_cache_dispatcher_win.cc b/content/common/font_cache_dispatcher_win.cc index 9337781..680062d 100644 --- a/content/common/font_cache_dispatcher_win.cc +++ b/content/common/font_cache_dispatcher_win.cc
@@ -12,6 +12,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/strings/string16.h" +#include "base/thread_annotations.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "services/service_manager/public/cpp/bind_source_info.h" @@ -125,8 +126,8 @@ FontCache() { } - std::map<base::string16, CacheElement> cache_; - DispatcherToFontNames dispatcher_font_map_; + std::map<base::string16, CacheElement> cache_ GUARDED_BY(mutex_); + DispatcherToFontNames dispatcher_font_map_ GUARDED_BY(mutex_); base::Lock mutex_; DISALLOW_COPY_AND_ASSIGN(FontCache);
diff --git a/content/common/plugin_list.h b/content/common/plugin_list.h index 35ff2d0..a76f0a6 100644 --- a/content/common/plugin_list.h +++ b/content/common/plugin_list.h
@@ -15,6 +15,7 @@ #include "base/lazy_instance.h" #include "base/macros.h" #include "base/synchronization/lock.h" +#include "base/thread_annotations.h" #include "build/build_config.h" #include "content/common/content_export.h" #include "content/public/common/webplugininfo.h" @@ -122,7 +123,8 @@ // Removes |plugin_path| from the list of extra plugin paths. Should only be // called while holding |lock_|. - void RemoveExtraPluginPathLocked(const base::FilePath& plugin_path); + void RemoveExtraPluginPathLocked(const base::FilePath& plugin_path) + EXCLUSIVE_LOCKS_REQUIRED(lock_); // Creates a WebPluginInfo structure given a plugin's path. On success // returns true, with the information being put into "info". @@ -142,19 +144,19 @@ // States whether we will load the plugin list the next time we try to access // it, whether we are currently in the process of loading it, or whether we // consider it up to date. - LoadingState loading_state_; + LoadingState loading_state_ GUARDED_BY(lock_); // Extra plugin paths that we want to search when loading. - std::vector<base::FilePath> extra_plugin_paths_; + std::vector<base::FilePath> extra_plugin_paths_ GUARDED_BY(lock_); // Holds information about internal plugins. - std::vector<WebPluginInfo> internal_plugins_; + std::vector<WebPluginInfo> internal_plugins_ GUARDED_BY(lock_); // A list holding all plugins. - std::vector<WebPluginInfo> plugins_list_; + std::vector<WebPluginInfo> plugins_list_ GUARDED_BY(lock_); // Callback that is invoked whenever the PluginList will reload the plugins. - base::Closure will_load_plugins_callback_; + base::Closure will_load_plugins_callback_ GUARDED_BY(lock_); // Need synchronization for the above members since this object can be // accessed on multiple threads.
diff --git a/content/common/render_message_filter.mojom b/content/common/render_message_filter.mojom index c31715ab..c83c5d0 100644 --- a/content/common/render_message_filter.mojom +++ b/content/common/render_message_filter.mojom
@@ -25,25 +25,6 @@ [Sync] CreateFullscreenWidget(int32 opener_id, Widget widget) => (int32 route_id); - // Requests that the browser cache |data| associated with |url| and |expected_response_time|. - // TODO(https://crbug.com/779444): Verify or remove |url| and |cache_storage_origin|. - DidGenerateCacheableMetadata(url.mojom.Url url, - mojo_base.mojom.Time expected_response_time, - array<uint8> data); - - // TODO(crbug.com/867848) Pass the data as mojo data_pipe instead of - // array<unit8>. - FetchCachedCode(url.mojom.Url url) => (mojo_base.mojom.Time response_time, - array<uint8> data); - - ClearCodeCacheEntry(url.mojom.Url url); - - // Requests that the browser cache |data| for the specified CacheStorage entry. - DidGenerateCacheableMetadataInCacheStorage( - url.mojom.Url url, mojo_base.mojom.Time expected_response_time, - array<uint8> data, url.mojom.Origin cache_storage_origin, - string cache_storage_cache_name); - // A renderer sends this when it wants to know whether a gpu process exists. [Sync] HasGpuProcess() => (bool has_gpu_process);
diff --git a/content/common/render_widget_surface_properties.cc b/content/common/render_widget_surface_properties.cc index 2848b01..09a9a0d 100644 --- a/content/common/render_widget_surface_properties.cc +++ b/content/common/render_widget_surface_properties.cc
@@ -13,9 +13,9 @@ RenderWidgetSurfaceProperties properties; properties.size = frame.size_in_pixels(); properties.device_scale_factor = frame.device_scale_factor(); -#ifdef OS_ANDROID properties.top_controls_height = frame.metadata.top_controls_height; properties.top_controls_shown_ratio = frame.metadata.top_controls_shown_ratio; +#ifdef OS_ANDROID properties.bottom_controls_height = frame.metadata.bottom_controls_height; properties.bottom_controls_shown_ratio = frame.metadata.bottom_controls_shown_ratio; @@ -39,9 +39,9 @@ bool RenderWidgetSurfaceProperties::operator==( const RenderWidgetSurfaceProperties& other) const { return other.device_scale_factor == device_scale_factor && -#ifdef OS_ANDROID other.top_controls_height == top_controls_height && other.top_controls_shown_ratio == top_controls_shown_ratio && +#ifdef OS_ANDROID other.bottom_controls_height == bottom_controls_height && other.bottom_controls_shown_ratio == bottom_controls_shown_ratio && other.selection == selection && @@ -77,7 +77,6 @@ ++changed_properties; } -#ifdef OS_ANDROID if (top_controls_height != other.top_controls_height) { if (changed_properties > 0) stream << ", "; @@ -94,6 +93,8 @@ ++changed_properties; } +#ifdef OS_ANDROID + if (bottom_controls_height != other.bottom_controls_height) { if (changed_properties > 0) stream << ", ";
diff --git a/content/common/render_widget_surface_properties.h b/content/common/render_widget_surface_properties.h index da357db..c30cf77e 100644 --- a/content/common/render_widget_surface_properties.h +++ b/content/common/render_widget_surface_properties.h
@@ -30,9 +30,9 @@ gfx::Size size; float device_scale_factor = 0; -#ifdef OS_ANDROID float top_controls_height = 0; float top_controls_shown_ratio = 0; +#ifdef OS_ANDROID float bottom_controls_height = 0; float bottom_controls_shown_ratio = 0; viz::Selection<gfx::SelectionBound> selection;
diff --git a/content/common/service_manager/service_manager_connection_impl.cc b/content/common/service_manager/service_manager_connection_impl.cc index dac316d..5c5eca5 100644 --- a/content/common/service_manager/service_manager_connection_impl.cc +++ b/content/common/service_manager/service_manager_connection_impl.cc
@@ -14,6 +14,7 @@ #include "base/lazy_instance.h" #include "base/macros.h" #include "base/message_loop/message_loop_current.h" +#include "base/thread_annotations.h" #include "base/threading/thread_checker.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" @@ -339,14 +340,15 @@ std::unique_ptr<service_manager::ServiceContext> service_context_; mojo::BindingSet<service_manager::mojom::ServiceFactory> factory_bindings_; - int next_filter_id_ = kInvalidConnectionFilterId; // Not owned. MessageLoopObserver* message_loop_observer_ = nullptr; - // Guards |connection_filters_|. + // Guards |connection_filters_| and |next_filter_id_|. base::Lock lock_; - std::map<int, std::unique_ptr<ConnectionFilter>> connection_filters_; + std::map<int, std::unique_ptr<ConnectionFilter>> connection_filters_ + GUARDED_BY(lock_); + int next_filter_id_ GUARDED_BY(lock_) = kInvalidConnectionFilterId; std::map<std::string, std::unique_ptr<service_manager::EmbeddedServiceRunner>> embedded_services_;
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json index 0ccb69f..03d96205 100644 --- a/content/public/app/mojo/content_browser_manifest.json +++ b/content/public/app/mojo/content_browser_manifest.json
@@ -43,6 +43,7 @@ "blink.mojom.BlobRegistry", "blink.mojom.BroadcastChannelProvider", "blink.mojom.ClipboardHost", + "blink.mojom.CodeCacheHost", "blink.mojom.FontUniqueNameLookup", "blink.mojom.EmbeddedFrameSinkProvider", "blink.mojom.FileUtilitiesHost", @@ -162,6 +163,7 @@ "blink.mojom.CredentialManager", "blink.mojom.DisplayCutoutHost", "blink.mojom.DedicatedWorkerFactory", + "blink.mojom.FileSystemManager", "blink.mojom.LockManager", "blink.mojom.GeolocationService", "blink.mojom.InsecureInputService", @@ -227,6 +229,7 @@ "renderer": [ "blink.mojom.CacheStorage", "blink.mojom.DedicatedWorkerFactory", + "blink.mojom.FileSystemManager", "blink.mojom.LockManager", "blink.mojom.NotificationService", "blink.mojom.PermissionService", @@ -263,6 +266,7 @@ "provides": { "renderer": [ "blink.mojom.CacheStorage", + "blink.mojom.FileSystemManager", "blink.mojom.LockManager", "blink.mojom.NotificationService", "blink.mojom.PermissionService",
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json index 4ae4abe..d048cbc 100644 --- a/content/public/app/mojo/content_renderer_manifest.json +++ b/content/public/app/mojo/content_renderer_manifest.json
@@ -5,6 +5,7 @@ "service_manager:connector": { "provides": { "browser": [ + "blink.mojom.CodeCacheHost", "blink.mojom.CrashMemoryMetricsReporter", "blink.mojom.LeakDetector", "blink.mojom.OomIntervention",
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc index c7cf40ef..86ec98a 100644 --- a/content/public/browser/web_contents_delegate.cc +++ b/content/public/browser/web_contents_delegate.cc
@@ -256,7 +256,8 @@ return 0; } -bool WebContentsDelegate::DoBrowserControlsShrinkBlinkSize() const { +bool WebContentsDelegate::DoBrowserControlsShrinkRendererSize( + const WebContents* web_contents) const { return false; }
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h index 23107c8..1c9c817 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h
@@ -563,7 +563,8 @@ // needed by embedder because it's always accompanied by view size change. virtual int GetTopControlsHeight() const; virtual int GetBottomControlsHeight() const; - virtual bool DoBrowserControlsShrinkBlinkSize() const; + virtual bool DoBrowserControlsShrinkRendererSize( + const WebContents* web_contents) const; // Propagates to the browser that gesture scrolling has changed state. This is // used by the browser to assist in controlling the behavior of sliding the
diff --git a/content/public/test/android/dom_utils.cc b/content/public/test/android/dom_utils.cc index f6b3f75..71f8059a 100644 --- a/content/public/test/android/dom_utils.cc +++ b/content/public/test/android/dom_utils.cc
@@ -24,7 +24,7 @@ // Android obtains the top control size via WebContentsDelegate. WebContentsDelegate* delegate = web_contents->GetDelegate(); float scale = web_contents->GetNativeView()->GetDipScale(); - return delegate && delegate->DoBrowserControlsShrinkBlinkSize() + return delegate && delegate->DoBrowserControlsShrinkRendererSize(web_contents) ? delegate->GetTopControlsHeight() * scale : 0; }
diff --git a/content/public/test/browsing_data_remover_test_util.cc b/content/public/test/browsing_data_remover_test_util.cc index 3d6492c..2ea2ab6 100644 --- a/content/public/test/browsing_data_remover_test_util.cc +++ b/content/public/test/browsing_data_remover_test_util.cc
@@ -6,12 +6,14 @@ #include "base/bind.h" #include "base/task/task_scheduler/task_scheduler.h" +#include "base/threading/thread_task_runner_handle.h" namespace content { BrowsingDataRemoverCompletionObserver::BrowsingDataRemoverCompletionObserver( BrowsingDataRemover* remover) - : observer_(this) { + : observer_(this), + origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) { observer_.Add(remover); } @@ -20,10 +22,7 @@ void BrowsingDataRemoverCompletionObserver::BlockUntilCompletion() { base::TaskScheduler::GetInstance()->FlushAsyncForTesting(base::BindOnce( - [](BrowsingDataRemoverCompletionObserver* observer) { - observer->flush_for_testing_complete_ = true; - observer->QuitRunLoopWhenTasksComplete(); - }, + &BrowsingDataRemoverCompletionObserver::FlushForTestingComplete, base::Unretained(this))); run_loop_.Run(); } @@ -34,6 +33,19 @@ QuitRunLoopWhenTasksComplete(); } +void BrowsingDataRemoverCompletionObserver::FlushForTestingComplete() { + if (origin_task_runner_->RunsTasksInCurrentSequence()) { + flush_for_testing_complete_ = true; + QuitRunLoopWhenTasksComplete(); + return; + } + origin_task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + &BrowsingDataRemoverCompletionObserver::FlushForTestingComplete, + base::Unretained(this))); +} + void BrowsingDataRemoverCompletionObserver::QuitRunLoopWhenTasksComplete() { if (!flush_for_testing_complete_ || !browsing_data_remover_done_) return; @@ -43,7 +55,9 @@ BrowsingDataRemoverCompletionInhibitor::BrowsingDataRemoverCompletionInhibitor( BrowsingDataRemover* remover) - : remover_(remover), run_loop_(new base::RunLoop) { + : remover_(remover), + run_loop_(new base::RunLoop), + origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) { DCHECK(remover); remover_->SetWouldCompleteCallbackForTesting( base::Bind(&BrowsingDataRemoverCompletionInhibitor:: @@ -66,10 +80,7 @@ void BrowsingDataRemoverCompletionInhibitor::BlockUntilNearCompletion() { base::TaskScheduler::GetInstance()->FlushAsyncForTesting(base::BindOnce( - [](BrowsingDataRemoverCompletionInhibitor* inhibitor) { - inhibitor->flush_for_testing_complete_ = true; - inhibitor->QuitRunLoopWhenTasksComplete(); - }, + &BrowsingDataRemoverCompletionInhibitor::FlushForTestingComplete, base::Unretained(this))); run_loop_->Run(); run_loop_ = std::make_unique<base::RunLoop>(); @@ -91,6 +102,19 @@ QuitRunLoopWhenTasksComplete(); } +void BrowsingDataRemoverCompletionInhibitor::FlushForTestingComplete() { + if (origin_task_runner_->RunsTasksInCurrentSequence()) { + flush_for_testing_complete_ = true; + QuitRunLoopWhenTasksComplete(); + return; + } + origin_task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + &BrowsingDataRemoverCompletionInhibitor::FlushForTestingComplete, + base::Unretained(this))); +} + void BrowsingDataRemoverCompletionInhibitor::QuitRunLoopWhenTasksComplete() { if (!flush_for_testing_complete_ || !browsing_data_remover_would_complete_done_) {
diff --git a/content/public/test/browsing_data_remover_test_util.h b/content/public/test/browsing_data_remover_test_util.h index 4d31980..eaf96d7 100644 --- a/content/public/test/browsing_data_remover_test_util.h +++ b/content/public/test/browsing_data_remover_test_util.h
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/run_loop.h" #include "base/scoped_observer.h" +#include "base/sequenced_task_runner.h" #include "content/public/browser/browsing_data_remover.h" namespace content { @@ -29,6 +30,7 @@ void OnBrowsingDataRemoverDone() override; private: + void FlushForTestingComplete(); void QuitRunLoopWhenTasksComplete(); // Tracks when the Task Scheduler task flushing is done. @@ -40,6 +42,7 @@ base::RunLoop run_loop_; ScopedObserver<BrowsingDataRemover, BrowsingDataRemover::Observer> observer_; + scoped_refptr<base::SequencedTaskRunner> origin_task_runner_; DISALLOW_COPY_AND_ASSIGN(BrowsingDataRemoverCompletionObserver); }; @@ -66,6 +69,7 @@ const base::Closure& continue_to_completion); private: + void FlushForTestingComplete(); void QuitRunLoopWhenTasksComplete(); // Tracks when the Task Scheduler task flushing is done. @@ -80,6 +84,7 @@ std::unique_ptr<base::RunLoop> run_loop_; base::Closure continue_to_completion_callback_; + scoped_refptr<base::SequencedTaskRunner> origin_task_runner_; DISALLOW_COPY_AND_ASSIGN(BrowsingDataRemoverCompletionInhibitor); };
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc index 53f3b5b..a546049 100644 --- a/content/public/test/mock_render_thread.cc +++ b/content/public/test/mock_render_thread.cc
@@ -64,28 +64,6 @@ NOTREACHED(); } - void DidGenerateCacheableMetadata(const GURL& url, - base::Time expected_response_time, - const std::vector<uint8_t>& data) override { - NOTREACHED(); - } - - void FetchCachedCode(const GURL& url, - FetchCachedCodeCallback callback) override { - NOTREACHED(); - } - - void ClearCodeCacheEntry(const GURL& url) override { NOTREACHED(); } - - void DidGenerateCacheableMetadataInCacheStorage( - const GURL& url, - base::Time expected_response_time, - const std::vector<uint8_t>& data, - const url::Origin& cache_storage_origin, - const std::string& cache_storage_cache_name) override { - NOTREACHED(); - } - void HasGpuProcess(HasGpuProcessCallback callback) override { std::move(callback).Run(false); }
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc index f7b9445..70cb730 100644 --- a/content/public/test/render_view_test.cc +++ b/content/public/test/render_view_test.cc
@@ -170,7 +170,10 @@ } RenderViewTest::RenderViewTest() { - RenderFrameImpl::InstallCreateHook(&TestRenderFrame::CreateTestRenderFrame); + // Overrides creation of RenderFrameImpl, but does not need to + // override behaviour of WebWidgetClient. + RenderFrameImpl::InstallCreateHook(&TestRenderFrame::CreateTestRenderFrame, + nullptr, nullptr); } RenderViewTest::~RenderViewTest() {
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index 7baa128..2a06cc4 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -109,10 +109,6 @@ "fetchers/multi_resolution_image_resource_fetcher.h", "fetchers/resource_fetcher_impl.cc", "fetchers/resource_fetcher_impl.h", - "fileapi/file_system_dispatcher.cc", - "fileapi/file_system_dispatcher.h", - "fileapi/webfilesystem_impl.cc", - "fileapi/webfilesystem_impl.h", "frame_blame_context.cc", "frame_blame_context.h", "frame_owner_properties.cc",
diff --git a/content/renderer/fileapi/OWNERS b/content/renderer/fileapi/OWNERS deleted file mode 100644 index 6269c8b3..0000000 --- a/content/renderer/fileapi/OWNERS +++ /dev/null
@@ -1,4 +0,0 @@ -file://content/browser/fileapi/OWNERS - -# TEAM: storage-dev@chromium.org -# COMPONENT: Blink>Storage>FileSystem
diff --git a/content/renderer/fileapi/file_system_dispatcher.cc b/content/renderer/fileapi/file_system_dispatcher.cc deleted file mode 100644 index d8cd6a7..0000000 --- a/content/renderer/fileapi/file_system_dispatcher.cc +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/fileapi/file_system_dispatcher.h" - -#include <memory> -#include <utility> - -#include "base/callback.h" -#include "base/files/file_util.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/no_destructor.h" -#include "base/process/process.h" -#include "components/services/filesystem/public/interfaces/types.mojom.h" -#include "content/child/child_thread_impl.h" -#include "content/public/common/service_names.mojom.h" -#include "content/public/renderer/worker_thread.h" -#include "services/service_manager/public/cpp/connector.h" -#include "storage/common/fileapi/file_system_info.h" -#include "storage/common/fileapi/file_system_type_converters.h" - -namespace content { - -FileSystemDispatcher::FileSystemDispatcher( - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) - : main_thread_task_runner_(std::move(main_thread_task_runner)) {} - -FileSystemDispatcher::~FileSystemDispatcher() = default; - -blink::mojom::FileSystemManager& FileSystemDispatcher::GetFileSystemManager() { - auto BindInterfaceOnMainThread = - [](blink::mojom::FileSystemManagerRequest request) { - DCHECK(ChildThreadImpl::current()); - ChildThreadImpl::current()->GetConnector()->BindInterface( - mojom::kBrowserServiceName, std::move(request)); - }; - if (!file_system_manager_ptr_) { - if (WorkerThread::GetCurrentId()) { - blink::mojom::FileSystemManagerRequest request = - mojo::MakeRequest(&file_system_manager_ptr_); - main_thread_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(BindInterfaceOnMainThread, std::move(request))); - } else { - BindInterfaceOnMainThread(mojo::MakeRequest(&file_system_manager_ptr_)); - } - } - return *file_system_manager_ptr_; -} - -void FileSystemDispatcher::ChooseEntry( - int render_frame_id, - std::unique_ptr<ChooseEntryCallbacks> callbacks) { - GetFileSystemManager().ChooseEntry( - render_frame_id, - base::BindOnce( - [](std::unique_ptr<ChooseEntryCallbacks> callbacks, - base::File::Error result, - std::vector<blink::mojom::FileSystemEntryPtr> entries) { - if (result != base::File::FILE_OK) { - callbacks->OnError(result); - } else { - blink::WebVector<blink::WebFileSystem::FileSystemEntry> - web_entries(entries.size()); - for (size_t i = 0; i < entries.size(); ++i) { - web_entries[i].file_system_id = - blink::WebString::FromASCII(entries[i]->file_system_id); - web_entries[i].base_name = - blink::WebString::FromASCII(entries[i]->base_name); - } - callbacks->OnSuccess(std::move(web_entries)); - } - }, - std::move(callbacks))); -} - -} // namespace content
diff --git a/content/renderer/fileapi/file_system_dispatcher.h b/content/renderer/fileapi/file_system_dispatcher.h deleted file mode 100644 index b5df614..0000000 --- a/content/renderer/fileapi/file_system_dispatcher.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_FILEAPI_FILE_SYSTEM_DISPATCHER_H_ -#define CONTENT_RENDERER_FILEAPI_FILE_SYSTEM_DISPATCHER_H_ - -#include "base/memory/scoped_refptr.h" -#include "third_party/blink/public/mojom/filesystem/file_system.mojom.h" -#include "third_party/blink/public/platform/web_file_system.h" - -namespace base { -class SingleThreadTaskRunner; -} // namespace base - -namespace content { - -// Dispatches and sends file system related messages sent to/from a child -// process from/to the main browser process. There is an instance held by -// each WebFileSystemImpl object. -// TODO(adithyas): Move functionality to blink::FileSystemDispatcher and -// remove this class. -class FileSystemDispatcher { - public: - explicit FileSystemDispatcher( - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner); - ~FileSystemDispatcher(); - - using ChooseEntryCallbacks = blink::WebFileSystem::ChooseEntryCallbacks; - void ChooseEntry(int render_frame_id, - std::unique_ptr<ChooseEntryCallbacks> callbacks); - - private: - blink::mojom::FileSystemManager& GetFileSystemManager(); - - blink::mojom::FileSystemManagerPtr file_system_manager_ptr_; - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(FileSystemDispatcher); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_FILEAPI_FILE_SYSTEM_DISPATCHER_H_
diff --git a/content/renderer/fileapi/webfilesystem_impl.cc b/content/renderer/fileapi/webfilesystem_impl.cc deleted file mode 100644 index b471ad4..0000000 --- a/content/renderer/fileapi/webfilesystem_impl.cc +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/fileapi/webfilesystem_impl.h" - -#include "base/lazy_instance.h" -#include "base/threading/thread_local.h" -#include "base/threading/thread_task_runner_handle.h" -#include "content/public/renderer/render_frame.h" -#include "content/renderer/fileapi/file_system_dispatcher.h" -#include "content/renderer/render_thread_impl.h" -#include "third_party/blink/public/web/web_frame.h" - -namespace content { - -namespace { - -base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl>>::Leaky - g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER; - -enum CallbacksUnregisterMode { - UNREGISTER_CALLBACKS, - DO_NOT_UNREGISTER_CALLBACKS, -}; - -} // namespace - -//----------------------------------------------------------------------------- -// WebFileSystemImpl - -WebFileSystemImpl* WebFileSystemImpl::ThreadSpecificInstance( - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) { - if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_task_runner) - return g_webfilesystem_tls.Pointer()->Get(); - WebFileSystemImpl* filesystem = - new WebFileSystemImpl(std::move(main_thread_task_runner)); - if (WorkerThread::GetCurrentId()) - WorkerThread::AddObserver(filesystem); - return filesystem; -} - -void WebFileSystemImpl::DeleteThreadSpecificInstance() { - DCHECK(!WorkerThread::GetCurrentId()); - if (g_webfilesystem_tls.Pointer()->Get()) - delete g_webfilesystem_tls.Pointer()->Get(); -} - -WebFileSystemImpl::WebFileSystemImpl( - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) - : main_thread_task_runner_(main_thread_task_runner), - file_system_dispatcher_(std::move(main_thread_task_runner)) { - g_webfilesystem_tls.Pointer()->Set(this); -} - -WebFileSystemImpl::~WebFileSystemImpl() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - g_webfilesystem_tls.Pointer()->Set(nullptr); -} - -void WebFileSystemImpl::WillStopCurrentWorkerThread() { - delete this; -} - -void WebFileSystemImpl::ChooseEntry( - blink::WebFrame* frame, - std::unique_ptr<ChooseEntryCallbacks> callbacks) { - file_system_dispatcher_.ChooseEntry( - RenderFrame::GetRoutingIdForWebFrame(frame), std::move(callbacks)); -} - -} // namespace content
diff --git a/content/renderer/fileapi/webfilesystem_impl.h b/content/renderer/fileapi/webfilesystem_impl.h deleted file mode 100644 index a3c2ecf86..0000000 --- a/content/renderer/fileapi/webfilesystem_impl.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_FILEAPI_WEBFILESYSTEM_IMPL_H_ -#define CONTENT_RENDERER_FILEAPI_WEBFILESYSTEM_IMPL_H_ - -#include "base/memory/ref_counted.h" -#include "base/threading/thread_checker.h" -#include "content/public/renderer/worker_thread.h" -#include "content/renderer/fileapi/file_system_dispatcher.h" -#include "third_party/blink/public/platform/web_file_system.h" - -namespace base { -class SingleThreadTaskRunner; -} - -namespace content { - -// TODO(adithyas): Move functionality to blink::FileSystemDispatcher and remove -// this class. -class WebFileSystemImpl : public blink::WebFileSystem, - public WorkerThread::Observer { - public: - // Returns thread-specific instance. If non-null |main_thread_loop| - // is given and no thread-specific instance has been created it may - // create a new instance. - static WebFileSystemImpl* ThreadSpecificInstance( - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner); - - // Deletes thread-specific instance (if exists). For workers it deletes - // itself in WillStopCurrentWorkerThread(), but for an instance created on the - // main thread this method must be called. - static void DeleteThreadSpecificInstance(); - - explicit WebFileSystemImpl( - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner); - ~WebFileSystemImpl() override; - - // WorkerThread::Observer implementation. - void WillStopCurrentWorkerThread() override; - - void ChooseEntry(blink::WebFrame* frame, - std::unique_ptr<ChooseEntryCallbacks>) override; - - private: - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; - FileSystemDispatcher file_system_dispatcher_; - - // Thread-affine per use of TLS in impl. - THREAD_CHECKER(thread_checker_); - - DISALLOW_COPY_AND_ASSIGN(WebFileSystemImpl); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_FILEAPI_WEBFILESYSTEM_IMPL_H_
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc index ec157e0..7f9420a 100644 --- a/content/renderer/gpu/gpu_benchmarking_extension.cc +++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -457,8 +457,10 @@ if (!base::PathIsWritable(path.DirName())) { std::string msg("Path is not writable: "); msg.append(path.DirName().MaybeAsASCII()); - isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( - isolate, msg.c_str(), v8::String::kNormalString, msg.length()))); + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, msg.c_str(), + v8::NewStringType::kNormal, msg.length()) + .ToLocalChecked())); return; } SkFILEWStream wStream(path.MaybeAsASCII().c_str()); @@ -607,8 +609,10 @@ PrintDocumentTofile(isolate, filename, &MakeXPSDocument); #else std::string msg("PrintPagesToXPS is unsupported."); - isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( - isolate, msg.c_str(), v8::String::kNormalString, msg.length()))); + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, msg.c_str(), v8::NewStringType::kNormal, + msg.length()) + .ToLocalChecked())); #endif } @@ -627,8 +631,10 @@ !base::PathIsWritable(dirpath)) { std::string msg("Path is not writable: "); msg.append(dirpath.MaybeAsASCII()); - isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( - isolate, msg.c_str(), v8::String::kNormalString, msg.length()))); + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, msg.c_str(), + v8::NewStringType::kNormal, msg.length()) + .ToLocalChecked())); return; }
diff --git a/content/renderer/pepper/pepper_file_system_host.cc b/content/renderer/pepper/pepper_file_system_host.cc index 53915df..2622490 100644 --- a/content/renderer/pepper/pepper_file_system_host.cc +++ b/content/renderer/pepper/pepper_file_system_host.cc
@@ -10,7 +10,6 @@ #include "content/public/common/service_names.mojom.h" #include "content/public/renderer/render_view.h" #include "content/public/renderer/renderer_ppapi_host.h" -#include "content/renderer/fileapi/file_system_dispatcher.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "content/renderer/render_thread_impl.h" #include "ppapi/c/pp_errors.h"
diff --git a/content/renderer/pepper/v8_var_converter.cc b/content/renderer/pepper/v8_var_converter.cc index 5c4319d..93cdbdc 100644 --- a/content/renderer/pepper/v8_var_converter.cc +++ b/content/renderer/pepper/v8_var_converter.cc
@@ -130,8 +130,10 @@ // in the sense that string primitives in JavaScript can't be referenced // in the same way that string vars can in pepper. But that information // isn't very useful and primitive strings are a more expected form in JS. - *result = v8::String::NewFromUtf8( - isolate, value.c_str(), v8::String::kNormalString, value.size()); + *result = + v8::String::NewFromUtf8(isolate, value.c_str(), + v8::NewStringType::kNormal, value.size()) + .ToLocalChecked(); break; } case PP_VARTYPE_ARRAY_BUFFER: { @@ -419,10 +421,11 @@ if (did_create && CanHaveChildren(child_var)) stack.push_back(child_var); v8::TryCatch try_catch(isolate); - v8_object->Set( - v8::String::NewFromUtf8( - isolate, key.c_str(), v8::String::kNormalString, key.length()), - child_v8); + v8_object->Set(v8::String::NewFromUtf8(isolate, key.c_str(), + v8::NewStringType::kInternalized, + key.length()) + .ToLocalChecked(), + child_v8); if (try_catch.HasCaught()) { LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " << "exception.";
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 8bc7bb1..381b4a9 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -585,6 +585,10 @@ RenderFrameImpl::CreateRenderFrameImplFunction g_create_render_frame_impl = nullptr; +RenderFrameImpl::CreateRenderWidgetForChildLocalRootFunction + g_create_render_widget = nullptr; +RenderFrameImpl::RenderWidgetForChildLocalRootInitializedCallback + g_render_widget_initialized = nullptr; WebString ConvertRelativePathToHtmlAttribute(const base::FilePath& path) { DCHECK(!path.IsAbsolute()); @@ -1285,12 +1289,25 @@ replicated_state.frame_policy.sandbox_flags); if (has_committed_real_load) web_frame->SetCommittedFirstRealLoad(); - render_frame->render_widget_ = RenderWidget::CreateForFrame( - widget_routing_id, hidden, screen_info, compositor_deps, web_frame); - // TODO(avi): This DCHECK is to track cleanup for https://crbug.com/545684 - DCHECK_EQ(render_view->GetWidget(), render_frame->render_widget_) - << "Main frame is no longer reusing the RenderView as its widget! " - << "Does the RenderFrame need to register itself with the RenderWidget?"; + + // The RenderViewImpl and its RenderWidget already exist by the time we get + // here. + // TODO(crbug.com/419087): We probably want to create the RenderWidget here + // though (when we make the WebFrameWidget?). + RenderWidget* render_widget = render_view->GetWidget(); + + // Non-owning pointer that is self-referencing and destroyed by calling + // Close(). The RenderViewImpl has a RenderWidget already, but not a + // WebFrameWidget, which is now attached here. + auto* web_frame_widget = blink::WebFrameWidget::CreateForMainFrame( + render_view->WidgetClient(), web_frame); + render_view->AttachWebFrameWidget(web_frame_widget); + // TODO(crbug.com/419087): This was added in 6ccadf770766e89c3 to prevent an + // empty ScreenInfo, but the WebView has already been created and initialized + // by RenderViewImpl, so this is surely redundant? + render_widget->UpdateWebViewWithDeviceScaleFactor(); + + render_frame->render_widget_ = render_widget; render_frame->in_frame_tree_ = true; return render_frame; } @@ -1309,8 +1326,12 @@ const mojom::CreateFrameWidgetParams& widget_params, const FrameOwnerProperties& frame_owner_properties, bool has_committed_real_load) { - blink::WebLocalFrame* web_frame; - RenderFrameImpl* render_frame; + // TODO(danakj): Split this method into two pieces. The first block makes a + // WebLocalFrame and collects the RenderView and RenderFrame for it. The + // second block uses that to make/setup a RenderWidget, if needed. + RenderViewImpl* render_view = nullptr; + RenderFrameImpl* render_frame = nullptr; + blink::WebLocalFrame* web_frame = nullptr; if (proxy_routing_id == MSG_ROUTING_NONE) { // TODO(alexmos): This path is currently used only: // 1) When recreating a RenderFrame after a crash. @@ -1332,6 +1353,7 @@ if (previous_sibling_proxy) previous_sibling_web_frame = previous_sibling_proxy->web_frame(); + render_view = parent_proxy->render_view(); // Create the RenderFrame and WebLocalFrame, linking the two. render_frame = RenderFrameImpl::Create( parent_proxy->render_view(), routing_id, std::move(interface_provider), @@ -1362,7 +1384,15 @@ if (!proxy) return; - render_frame = RenderFrameImpl::Create(proxy->render_view(), routing_id, + // This path is creating a local frame. It may or may not be a local root, + // depending if the frame's parent is local or remote. It may also be the + // main frame, as in the case where a navigation to the current process' + // origin replaces a remote main frame (the proxy's web_frame()) with a + // local one. + const bool proxy_is_main_frame = !proxy->web_frame()->Parent(); + + render_view = proxy->render_view(); + render_frame = RenderFrameImpl::Create(render_view, routing_id, std::move(interface_provider), devtools_frame_token); render_frame->InitializeBlameContext(nullptr); @@ -1372,16 +1402,119 @@ render_frame, render_frame->blink_interface_registry_.get(), proxy->web_frame(), replicated_state.frame_policy.sandbox_flags, replicated_state.frame_policy.container_policy); + // The new |web_frame| is a main frame iff the proxy's frame was. + DCHECK_EQ(proxy_is_main_frame, !web_frame->Parent()); } - CHECK(parent_routing_id != MSG_ROUTING_NONE || !web_frame->Parent()); - if (widget_params.routing_id != MSG_ROUTING_NONE) { - // TODO(fsamuel): It's not clear if we should be passing in the - // web ScreenInfo or the original ScreenInfo here. - render_frame->render_widget_ = RenderWidget::CreateForFrame( - widget_params.routing_id, widget_params.hidden, - render_frame->render_view_->GetWebScreenInfo(), compositor_deps, - web_frame); + DCHECK(render_view); + DCHECK(render_frame); + DCHECK(web_frame); + + const bool is_main_frame = !web_frame->Parent(); + + // Child frames require there to be a |parent_routing_id| present, for the + // remote parent frame. Though it is only used if the |proxy_routing_id| is + // not given, which happens in some corner cases. + if (!is_main_frame) + DCHECK_NE(parent_routing_id, MSG_ROUTING_NONE); + + // We now have a WebLocalFrame for the new frame. The next step is to set + // up a RenderWidget for it, if it is needed. + // + // If there is no widget routing id, then the new frame is not a local root, + // and does not need a RenderWidget. In that case we'll do nothing. Otherwise + // it does. + if (is_main_frame) { + // For a main frame, we use the RenderWidget already attached to the + // RenderView (this is being changed by https://crbug.com/419087). + + // Main frames are always local roots, so they should always have a routing + // id. Surprisingly, this routing id is *not* used though, as the routing id + // on the existing RenderWidget is not changed. (I don't know why.) + // TODO(crbug.com/888105): It's a bug that the RenderWidget is not using + // this routing id. + DCHECK_NE(widget_params.routing_id, MSG_ROUTING_NONE); + + // The RenderViewImpl and its RenderWidget already exist by the time we + // get here (we get them from the RenderFrameProxy). + // TODO(crbug.com/419087): We probably want to create the RenderWidget + // here though (when we make the WebFrameWidget?). + RenderWidget* render_widget = render_view->GetWidget(); + + // Non-owning pointer that is self-referencing and destroyed by calling + // Close(). The RenderViewImpl has a RenderWidget already, but not a + // WebFrameWidget, which is now attached here. + auto* web_frame_widget = blink::WebFrameWidget::CreateForMainFrame( + render_view->WidgetClient(), web_frame); + render_view->AttachWebFrameWidget(web_frame_widget); + // TODO(crbug.com/419087): This was added in 6ccadf770766e89c3 to prevent + // an empty ScreenInfo, but the WebView has already been created and + // initialized by RenderViewImpl, so this is surely redundant? It will be + // pulling the device scale factor off the WebView itself. + render_widget->UpdateWebViewWithDeviceScaleFactor(); + + render_frame->render_widget_ = render_widget; + } else if (widget_params.routing_id != MSG_ROUTING_NONE) { + // This frame is a child local root, so we require a separate RenderWidget + // for it from any other frames in the frame tree. Each local root defines + // a separate context/coordinate space/world for compositing, painting, + // input, etc. And each local root has a RenderWidget which provides + // such services independent from other RenderWidgets. + // Notably, we do not attempt to reuse the main frame's RenderWidget (if the + // main frame in this frame tree is local) as that RenderWidget is + // functioning in a different local root. Because this is a child local + // root, it implies there is some remote frame ancestor between this frame + // and the main frame, thus its coordinate space etc is not known relative + // to the main frame. + + // TODO(crbug.com/419087): This is grabbing something off the view's + // widget but if the main frame is remote this widget would not be valid? + const ScreenInfo& screen_info_from_main_frame = + render_view->GetWidget()->GetWebScreenInfo(); + + // Makes a new RenderWidget for the child local root. It provides the + // local root with a new compositing, painting, and input coordinate + // space/context. + scoped_refptr<RenderWidget> render_widget; + if (g_create_render_widget) { + // LayoutTest hooks inject a different type (subclass) for RenderWidget, + // allowing it to override the behaviour of the WebWidgetClient which + // RenderWidget provides. + render_widget = g_create_render_widget( + widget_params.routing_id, compositor_deps, WidgetType::kFrame, + screen_info_from_main_frame, blink::kWebDisplayModeUndefined, + /*swapped_out=*/false, widget_params.hidden, + /*never_visible=*/false); + } else { + render_widget = base::MakeRefCounted<RenderWidget>( + widget_params.routing_id, compositor_deps, WidgetType::kFrame, + screen_info_from_main_frame, blink::kWebDisplayModeUndefined, + /*swapped_out=*/false, widget_params.hidden, + /*never_visible=*/false); + } + + // Non-owning pointer that is self-referencing and destroyed by calling + // Close(). We use the new RenderWidget as the client for this + // WebFrameWidget, *not* the RenderWidget of the MainFrame, which is + // accessible from the RenderViewImpl. + auto* web_frame_widget = blink::WebFrameWidget::CreateForChildLocalRoot( + render_widget.get(), web_frame); + + // Adds a reference on RenderWidget, making it self-referencing. So it + // will not be destroyed by scoped_refptr unless Close() has been called + // and run. + render_widget->InitForChildLocalRoot(web_frame_widget); + // TODO(crbug.com/419087): This was added in 6ccadf770766e89c3 to prevent + // an empty ScreenInfo, but the WebView has already been created and + // initialized by RenderViewImpl, so this is surely redundant? It will be + // pulling the device scale factor off the WebView itself. + render_widget->UpdateWebViewWithDeviceScaleFactor(); + + // LayoutTest hooks to set up the injected type for RenderWidget. + if (g_render_widget_initialized) + g_render_widget_initialized(render_widget.get()); + + render_frame->render_widget_ = std::move(render_widget); } if (has_committed_real_load) @@ -1425,9 +1558,15 @@ // static void RenderFrameImpl::InstallCreateHook( - CreateRenderFrameImplFunction create_render_frame_impl) { - CHECK(!g_create_render_frame_impl); - g_create_render_frame_impl = create_render_frame_impl; + CreateRenderFrameImplFunction create_frame, + CreateRenderWidgetForChildLocalRootFunction create_widget, + RenderWidgetForChildLocalRootInitializedCallback widget_initialized) { + DCHECK(!g_create_render_frame_impl); + DCHECK(!g_create_render_widget); + DCHECK(!g_render_widget_initialized); + g_create_render_frame_impl = create_frame; + g_create_render_widget = create_widget; + g_render_widget_initialized = widget_initialized; } // static
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 8323fa2..67a3f40d 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -47,6 +47,7 @@ #include "content/public/common/renderer_preferences.h" #include "content/public/common/resource_type.h" #include "content/public/common/stop_find_action.h" +#include "content/public/common/widget_type.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/websocket_handshake_throttle_provider.h" #include "content/renderer/content_security_policy_util.h" @@ -270,8 +271,25 @@ }; using CreateRenderFrameImplFunction = RenderFrameImpl* (*)(CreateParams); + using CreateRenderWidgetForChildLocalRootFunction = + RenderWidget* (*)(int32_t, + CompositorDependencies*, + WidgetType, + const ScreenInfo&, + blink::WebDisplayMode display_mode, + bool, + bool, + bool); + using RenderWidgetForChildLocalRootInitializedCallback = + void (*)(RenderWidget*); + + // LayoutTests override the creation of RenderFrames and RenderWidgets in + // order to inject their own (subclass) type and change behaviour inside the + // tests. static void InstallCreateHook( - CreateRenderFrameImplFunction create_render_frame_impl); + CreateRenderFrameImplFunction create_frame, + CreateRenderWidgetForChildLocalRootFunction create_widget, + RenderWidgetForChildLocalRootInitializedCallback widget_initialized); // Looks up and returns the WebFrame corresponding to a given opener frame // routing ID.
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 23c95140..dd6dc88 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -88,8 +88,6 @@ #include "content/renderer/dom_storage/webstoragearea_impl.h" #include "content/renderer/dom_storage/webstoragenamespace_impl.h" #include "content/renderer/effective_connection_type_helper.h" -#include "content/renderer/fileapi/file_system_dispatcher.h" -#include "content/renderer/fileapi/webfilesystem_impl.h" #include "content/renderer/gpu/frame_swap_message_queue.h" #include "content/renderer/indexed_db/indexed_db_dispatcher.h" #include "content/renderer/input/widget_input_handler_manager.h" @@ -1011,7 +1009,6 @@ void RenderThreadImpl::Shutdown() { ChildThreadImpl::Shutdown(); - WebFileSystemImpl::DeleteThreadSpecificInstance(); // In a multi-process mode, we immediately exit the renderer. // Historically we had a graceful shutdown sequence here but it was // 1) a waste of performance and 2) a source of lots of complicated
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 7036d48..beee71f 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -534,6 +534,10 @@ ApplyBlinkSettings(command_line, webview()->GetSettings()); + // We have either a main frame or a proxy routing id. + DCHECK_NE(params->main_frame_routing_id != MSG_ROUTING_NONE, + params->proxy_routing_id != MSG_ROUTING_NONE); + if (params->main_frame_routing_id != MSG_ROUTING_NONE) { CHECK(params->main_frame_interface_provider.is_valid()); service_manager::mojom::InterfaceProviderPtr main_frame_interface_provider( @@ -545,12 +549,9 @@ GetWidget()->GetWebScreenInfo(), GetWidget()->compositor_deps(), opener_frame, params->devtools_main_frame_token, params->replicated_frame_state, params->has_committed_real_load); - } - // TODO(dcheng): Shouldn't these be mutually exclusive at this point? See - // https://crbug.com/720116 where the browser is apparently sending both - // routing IDs... - if (params->proxy_routing_id != MSG_ROUTING_NONE) { + main_render_frame_->Initialize(); + } else { CHECK(params->swapped_out); RenderFrameProxy::CreateFrameProxy(params->proxy_routing_id, GetRoutingID(), opener_frame, MSG_ROUTING_NONE, @@ -558,9 +559,6 @@ params->devtools_main_frame_token); } - if (main_render_frame_) - main_render_frame_->Initialize(); - // If this RenderView's creation was initiated by an opener page in this // process, (e.g. window.open()), we won't be visible until we ask the opener, // via |show_callback|, to make us visible. Otherwise, we went through a @@ -1086,19 +1084,6 @@ webview()->SetIsActive(active); } -void RenderViewImpl::SetBackgroundOpaqueForWidget(bool opaque) { - if (!frame_widget_) - return; - - if (opaque) { - frame_widget_->ClearBaseBackgroundColorOverride(); - frame_widget_->ClearBackgroundColorOverride(); - } else { - frame_widget_->SetBaseBackgroundColorOverride(SK_ColorTRANSPARENT); - frame_widget_->SetBackgroundColorOverride(SK_ColorTRANSPARENT); - } -} - bool RenderViewImpl::SupportsMultipleWindowsForWidget() { return webkit_preferences_.supports_multiple_windows; }
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index cd13b43..4338420 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -379,7 +379,6 @@ bool RenderWidgetWillHandleMouseEventForWidget( const blink::WebMouseEvent& event) override; void SetActiveForWidget(bool active) override; - void SetBackgroundOpaqueForWidget(bool opaque) override; bool SupportsMultipleWindowsForWidget() override; void DidHandleGestureEventForWidget( const blink::WebGestureEvent& event) override;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index f335a3c6..77f9bd6 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -335,12 +335,6 @@ return result; } -content::RenderWidget::CreateRenderWidgetFunction g_create_render_widget = - nullptr; - -content::RenderWidget::RenderWidgetInitializedCallback - g_render_widget_initialized = nullptr; - ui::TextInputType ConvertWebTextInputType(blink::WebTextInputType type) { // Check the type is in the range representable by ui::TextInputType. DCHECK_LE(type, static_cast<int>(ui::TEXT_INPUT_TYPE_MAX)) @@ -388,7 +382,7 @@ RenderWidget::RenderWidget(int32_t widget_routing_id, CompositorDependencies* compositor_deps, - WidgetType popup_type, + WidgetType widget_type, const ScreenInfo& screen_info, blink::WebDisplayMode display_mode, bool swapped_out, @@ -415,7 +409,7 @@ next_previous_flags_(kInvalidNextPreviousFlagsValue), can_compose_inline_(true), composition_range_(gfx::Range::InvalidRange()), - popup_type_(popup_type), + widget_type_(widget_type), pending_window_rect_count_(0), screen_info_(screen_info), monitor_composition_info_(false), @@ -473,15 +467,6 @@ } // static -void RenderWidget::InstallCreateHook( - CreateRenderWidgetFunction create_render_widget, - RenderWidgetInitializedCallback render_widget_initialized) { - CHECK(!g_create_render_widget && !g_render_widget_initialized); - g_create_render_widget = create_render_widget; - g_render_widget_initialized = render_widget_initialized; -} - -// static RenderWidget* RenderWidget::FromRoutingID(int32_t routing_id) { RoutingIDWidgetMap* widgets = g_routing_id_widget_map.Pointer(); RoutingIDWidgetMap::iterator it = widgets->find(routing_id); @@ -519,57 +504,12 @@ return widget.get(); } -// static -RenderWidget* RenderWidget::CreateForFrame( - int widget_routing_id, - bool hidden, - const ScreenInfo& screen_info, - CompositorDependencies* compositor_deps, - blink::WebLocalFrame* frame) { - CHECK_NE(widget_routing_id, MSG_ROUTING_NONE); - RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame); - // For the mainframe, the RenderWidget is attached to the RenderView. - // TODO(ajwong): Remove this when the widget is always attached to a frame. - // https://crbug.com/545684 - if (!frame->Parent()) { - RenderViewImpl* view = - static_cast<RenderViewImpl*>(render_frame->GetRenderView()); - // Use the WidgetClient() from the RenderViewImpl, rather than getting its - // RenderWidget directly. Layout tests may inject a different - // WebWidgetClient on the RenderViewImpl that intercepts calls before they - // get to the RenderWidget. - view->AttachWebFrameWidget( - RenderWidget::CreateWebFrameWidget(view->WidgetClient(), frame)); - view->GetWidget()->UpdateWebViewWithDeviceScaleFactor(); - return view->GetWidget(); - } - scoped_refptr<RenderWidget> widget( - g_create_render_widget - ? g_create_render_widget(widget_routing_id, compositor_deps, - WidgetType::kFrame, screen_info, - blink::kWebDisplayModeUndefined, false, - hidden, false) - : new RenderWidget(widget_routing_id, compositor_deps, - WidgetType::kFrame, screen_info, - blink::kWebDisplayModeUndefined, false, hidden, - false)); - widget->for_oopif_ = true; - // Init increments the reference count on |widget|, keeping it alive after - // this function returns. - widget->Init(base::NullCallback(), - RenderWidget::CreateWebFrameWidget(widget.get(), frame)); - widget->UpdateWebViewWithDeviceScaleFactor(); - - if (g_render_widget_initialized) - g_render_widget_initialized(widget.get()); - return widget.get(); -} - -// static -blink::WebFrameWidget* RenderWidget::CreateWebFrameWidget( - blink::WebWidgetClient* widget_client, - blink::WebLocalFrame* frame) { - return blink::WebFrameWidget::Create(widget_client, frame); +void RenderWidget::InitForChildLocalRoot( + blink::WebFrameWidget* web_frame_widget) { + for_oopif_ = true; + // Init() increments the reference count on |this|, making it + // self-referencing. + Init(base::NullCallback(), web_frame_widget); } void RenderWidget::CloseForFrame() { @@ -972,8 +912,24 @@ } void RenderWidget::OnSetBackgroundOpaque(bool opaque) { - if (owner_delegate_) - owner_delegate_->SetBackgroundOpaqueForWidget(opaque); + // Background opaque-ness modification is only supported for the main frame. + // The |owner_delegate_| is used as proxy for this RenderWidget being attached + // to the main frame. + if (!owner_delegate_) + return; + + blink::WebWidget* web_widget = GetWebWidget(); + // This is true since we only do this for RenderWidgets attached to the main + // frame. + DCHECK(web_widget->IsWebFrameWidget()); + auto* web_frame_widget = static_cast<blink::WebFrameWidget*>(web_widget); + if (opaque) { + web_frame_widget->ClearBaseBackgroundColorOverride(); + web_frame_widget->ClearBackgroundColorOverride(); + } else { + web_frame_widget->SetBaseBackgroundColorOverride(SK_ColorTRANSPARENT); + web_frame_widget->SetBackgroundColorOverride(SK_ColorTRANSPARENT); + } } void RenderWidget::OnSetFocus(bool enable) { @@ -1797,7 +1753,7 @@ // Popups don't get size updates back from the browser so just store the set // values. - if (popup_type_ != WidgetType::kFrame) { + if (widget_type_ != WidgetType::kFrame) { window_screen_rect_ = rect; view_screen_rect_ = rect; } @@ -2001,7 +1957,7 @@ const gfx::Rect& compositor_visible_rect, bool occluded_or_obscured) { if (auto* frame_widget = GetFrameWidget()) { - DCHECK_EQ(popup_type_, WidgetType::kFrame); + DCHECK_EQ(widget_type_, WidgetType::kFrame); compositor_visible_rect_ = compositor_visible_rect; frame_widget->SetRemoteViewportIntersection(viewport_intersection, occluded_or_obscured); @@ -2011,7 +1967,7 @@ void RenderWidget::OnSetIsInert(bool inert) { if (auto* frame_widget = GetFrameWidget()) { - DCHECK_EQ(popup_type_, WidgetType::kFrame); + DCHECK_EQ(widget_type_, WidgetType::kFrame); frame_widget->SetIsInert(inert); } } @@ -2019,7 +1975,7 @@ void RenderWidget::OnSetInheritedEffectiveTouchAction( cc::TouchAction touch_action) { if (auto* frame_widget = GetFrameWidget()) { - DCHECK_EQ(popup_type_, WidgetType::kFrame); + DCHECK_EQ(widget_type_, WidgetType::kFrame); frame_widget->SetInheritedEffectiveTouchAction(touch_action); } } @@ -2027,7 +1983,7 @@ void RenderWidget::OnUpdateRenderThrottlingStatus(bool is_throttled, bool subtree_throttled) { if (auto* frame_widget = GetFrameWidget()) { - DCHECK_EQ(popup_type_, WidgetType::kFrame); + DCHECK_EQ(widget_type_, WidgetType::kFrame); frame_widget->UpdateRenderThrottlingStatus(is_throttled, subtree_throttled); } }
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index 8ce7c73..5a3c9a8 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -151,34 +151,32 @@ TTFAP_5MIN_AFTER_BACKGROUNDED, }; + // An Init*() method must be called after creating a RenderWidget, which will + // make the RenderWidget self-referencing. Then it can be deleted by calling + // Close(). + RenderWidget(int32_t widget_routing_id, + CompositorDependencies* compositor_deps, + WidgetType widget_type, + const ScreenInfo& screen_info, + blink::WebDisplayMode display_mode, + bool swapped_out, + bool hidden, + bool never_visible, + mojom::WidgetRequest widget_request = nullptr); + // Creates a new RenderWidget for a popup. |opener| is the RenderView that // this widget lives inside. + // TODO(danakj): Change this to InitForPopup() and use the public constructor + // from RenderViewImpl, moving code specific to that class out of the method. static RenderWidget* CreateForPopup(RenderViewImpl* opener, CompositorDependencies* compositor_deps, const ScreenInfo& screen_info); - // Creates a new RenderWidget that will be attached to a RenderFrame. - static RenderWidget* CreateForFrame(int widget_routing_id, - bool hidden, - const ScreenInfo& screen_info, - CompositorDependencies* compositor_deps, - blink::WebLocalFrame* frame); - - // Used by content_layouttest_support to hook into the creation of - // RenderWidgets. - using CreateRenderWidgetFunction = - RenderWidget* (*)(int32_t, - CompositorDependencies*, - WidgetType, - const ScreenInfo&, - blink::WebDisplayMode display_mode, - bool, - bool, - bool); - using RenderWidgetInitializedCallback = void (*)(RenderWidget*); - static void InstallCreateHook( - CreateRenderWidgetFunction create_render_widget, - RenderWidgetInitializedCallback render_widget_initialized_callback); + // Initialize a new RenderWidget that will be attached to a RenderFrame (via + // the WebFrameWidget), for a frame that is a local root, but not the main + // frame. This method increments the reference count on the RenderWidget, + // making it self-referencing, which can be released by calling Close(). + void InitForChildLocalRoot(blink::WebFrameWidget* web_frame_widget); void set_owner_delegate(RenderWidgetOwnerDelegate* owner_delegate) { DCHECK(!owner_delegate_); @@ -531,23 +529,8 @@ base::WeakPtr<RenderWidget> AsWeakPtr(); protected: - RenderWidget(int32_t widget_routing_id, - CompositorDependencies* compositor_deps, - WidgetType popup_type, - const ScreenInfo& screen_info, - blink::WebDisplayMode display_mode, - bool swapped_out, - bool hidden, - bool never_visible, - mojom::WidgetRequest widget_request = nullptr); - - // Avoid making RenderWidget other than as a refptr. ~RenderWidget() override; - static blink::WebFrameWidget* CreateWebFrameWidget( - blink::WebWidgetClient* widget_client, - blink::WebLocalFrame* frame); - // Called by Create() functions and subclasses to finish initialization. // |show_callback| will be invoked once WebWidgetClient::Show() occurs, and // should be null if Show() won't be triggered for this widget. @@ -885,7 +868,7 @@ gfx::Range composition_range_; // The kind of popup this widget represents, NONE if not a popup. - WidgetType popup_type_; + WidgetType widget_type_; // While we are waiting for the browser to update window sizes, we track the // pending size temporarily.
diff --git a/content/renderer/render_widget_owner_delegate.h b/content/renderer/render_widget_owner_delegate.h index 2365a39..0b4a8af 100644 --- a/content/renderer/render_widget_owner_delegate.h +++ b/content/renderer/render_widget_owner_delegate.h
@@ -33,9 +33,6 @@ // See comment in RenderWidgetHost::SetActive(). virtual void SetActiveForWidget(bool active) = 0; - // See comment in RenderWidgetHostImpl::SetBackgroundOpaque(). - virtual void SetBackgroundOpaqueForWidget(bool opaque) = 0; - // Returns whether multiple windows are allowed for the widget. If true, then // Show() may be called more than once. virtual bool SupportsMultipleWindowsForWidget() = 0;
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc index 5fc7683e..cd4ee4a 100644 --- a/content/renderer/render_widget_unittest.cc +++ b/content/renderer/render_widget_unittest.cc
@@ -468,7 +468,6 @@ return false; } void SetActiveForWidget(bool active) override {} - void SetBackgroundOpaqueForWidget(bool opaque) override {} bool SupportsMultipleWindowsForWidget() override { return true; } void DidHandleGestureEventForWidget( const blink::WebGestureEvent& event) override {}
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 1b677f4..20e975e 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -33,7 +33,6 @@ #include "content/child/thread_safe_sender.h" #include "content/common/frame_messages.h" #include "content/common/gpu_stream_constants.h" -#include "content/common/render_message_filter.mojom.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/common/service_manager_connection.h" @@ -47,7 +46,6 @@ #include "content/renderer/dom_storage/local_storage_namespace.h" #include "content/renderer/dom_storage/session_web_storage_namespace_impl.h" #include "content/renderer/dom_storage/webstoragenamespace_impl.h" -#include "content/renderer/fileapi/webfilesystem_impl.h" #include "content/renderer/image_capture/image_capture_frame_grabber.h" #include "content/renderer/indexed_db/webidbfactory_impl.h" #include "content/renderer/loader/child_url_loader_factory_bundle.h" @@ -144,7 +142,6 @@ using blink::WebBlobRegistry; using blink::WebCanvasCaptureHandler; using blink::WebDatabaseObserver; -using blink::WebFileSystem; using blink::WebIDBFactory; using blink::WebImageCaptureFrameGrabber; using blink::WebMediaPlayer; @@ -294,10 +291,11 @@ GetInterfaceProvider()->GetInterface( mojo::MakeRequest(&web_database_host_info_)); + GetInterfaceProvider()->GetInterface( + mojo::MakeRequest(&code_cache_host_info_)); } RendererBlinkPlatformImpl::~RendererBlinkPlatformImpl() { - WebFileSystemImpl::DeleteThreadSpecificInstance(); main_thread_scheduler_->SetTopLevelBlameContext(nullptr); } @@ -463,22 +461,18 @@ // browser may cache it and return it on subsequent responses to speed // the processing of this resource. std::vector<uint8_t> copy(data, data + size); - RenderThreadImpl::current() - ->render_message_filter() - ->DidGenerateCacheableMetadata(url, response_time, copy); + GetCodeCacheHost().DidGenerateCacheableMetadata(url, response_time, copy); } void RendererBlinkPlatformImpl::FetchCachedCode( const GURL& url, base::OnceCallback<void(base::Time, const std::vector<uint8_t>&)> callback) { - RenderThreadImpl::current()->render_message_filter()->FetchCachedCode( - url, std::move(callback)); + GetCodeCacheHost().FetchCachedCode(url, std::move(callback)); } void RendererBlinkPlatformImpl::ClearCodeCacheEntry(const GURL& url) { - RenderThreadImpl::current()->render_message_filter()->ClearCodeCacheEntry( - url); + GetCodeCacheHost().ClearCodeCacheEntry(url); } void RendererBlinkPlatformImpl::CacheMetadataInCacheStorage( @@ -492,11 +486,9 @@ // CacheStorage. The browser may cache it and return it on subsequent // responses to speed the processing of this resource. std::vector<uint8_t> copy(data, data + size); - RenderThreadImpl::current() - ->render_message_filter() - ->DidGenerateCacheableMetadataInCacheStorage( - url, response_time, copy, cacheStorageOrigin, - cacheStorageCacheName.Utf8()); + GetCodeCacheHost().DidGenerateCacheableMetadataInCacheStorage( + url, response_time, copy, cacheStorageOrigin, + cacheStorageCacheName.Utf8()); } WebString RendererBlinkPlatformImpl::DefaultLocale() { @@ -582,10 +574,6 @@ //------------------------------------------------------------------------------ -WebFileSystem* RendererBlinkPlatformImpl::FileSystem() { - return WebFileSystemImpl::ThreadSpecificInstance(default_task_runner_.get()); -} - WebString RendererBlinkPlatformImpl::FileSystemCreateOriginIdentifier( const blink::WebSecurityOrigin& origin) { return WebString::FromUTF8( @@ -1214,4 +1202,14 @@ return **web_database_host_; } +blink::mojom::CodeCacheHost& RendererBlinkPlatformImpl::GetCodeCacheHost() { + if (!code_cache_host_) { + code_cache_host_ = blink::mojom::ThreadSafeCodeCacheHostPtr::Create( + std::move(code_cache_host_info_), + base::CreateSequencedTaskRunnerWithTraits( + {base::WithBaseSyncPrimitives()})); + } + return **code_cache_host_; +} + } // namespace content
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h index 5dd2ccd..02866eea 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h
@@ -25,6 +25,7 @@ #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/common/screen_orientation/web_screen_orientation_type.h" +#include "third_party/blink/public/mojom/loader/code_cache.mojom.h" #include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h" #include "third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h" #include "third_party/blink/public/platform/modules/webdatabase/web_database.mojom.h" @@ -124,7 +125,6 @@ bool IsLockedToSite() const override; std::unique_ptr<blink::WebIDBFactory> CreateIdbFactory() override; - blink::WebFileSystem* FileSystem() override; blink::WebString FileSystemCreateOriginIdentifier( const blink::WebSecurityOrigin& origin) override; @@ -223,6 +223,7 @@ std::unique_ptr<blink::WebURLLoaderFactory> CreateDefaultURLLoaderFactory() override; std::unique_ptr<blink::CodeCacheLoader> CreateCodeCacheLoader() override; + std::unique_ptr<blink::WebURLLoaderFactory> WrapURLLoaderFactory( mojo::ScopedMessagePipeHandle url_loader_factory_handle) override; std::unique_ptr<blink::WebURLLoaderFactory> WrapSharedURLLoaderFactory( @@ -262,6 +263,9 @@ // Return the mojo interface for making WebDatabaseHost calls. blink::mojom::WebDatabaseHost& GetWebDatabaseHost(); + // Return the mojo interface for making CodeCache calls. + blink::mojom::CodeCacheHost& GetCodeCacheHost(); + blink::scheduler::WebThreadBase* compositor_thread_; std::unique_ptr<blink::WebThread> main_thread_; @@ -301,6 +305,9 @@ blink::mojom::WebDatabaseHostPtrInfo web_database_host_info_; scoped_refptr<blink::mojom::ThreadSafeWebDatabaseHostPtr> web_database_host_; + blink::mojom::CodeCacheHostPtrInfo code_cache_host_info_; + scoped_refptr<blink::mojom::ThreadSafeCodeCacheHostPtr> code_cache_host_; + #if defined(OS_LINUX) sk_sp<font_service::FontLoader> font_loader_; #endif
diff --git a/content/renderer/skia_benchmarking_extension.cc b/content/renderer/skia_benchmarking_extension.cc index 40200bb..ae5dd66b 100644 --- a/content/renderer/skia_benchmarking_extension.cc +++ b/content/renderer/skia_benchmarking_extension.cc
@@ -285,9 +285,14 @@ } v8::Local<v8::Object> result = v8::Object::New(isolate); - result->Set(v8::String::NewFromUtf8(isolate, "total_time"), + result->Set(v8::String::NewFromUtf8(isolate, "total_time", + v8::NewStringType::kInternalized) + .ToLocalChecked(), v8::Number::New(isolate, total_time.InMillisecondsF())); - result->Set(v8::String::NewFromUtf8(isolate, "cmd_times"), op_times); + result->Set(v8::String::NewFromUtf8(isolate, "cmd_times", + v8::NewStringType::kInternalized) + .ToLocalChecked(), + op_times); args->Return(result); } @@ -303,9 +308,13 @@ return; v8::Local<v8::Object> result = v8::Object::New(isolate); - result->Set(v8::String::NewFromUtf8(isolate, "width"), + result->Set(v8::String::NewFromUtf8(isolate, "width", + v8::NewStringType::kInternalized) + .ToLocalChecked(), v8::Number::New(isolate, picture->layer_rect.width())); - result->Set(v8::String::NewFromUtf8(isolate, "height"), + result->Set(v8::String::NewFromUtf8(isolate, "height", + v8::NewStringType::kInternalized) + .ToLocalChecked(), v8::Number::New(isolate, picture->layer_rect.height())); args->Return(result);
diff --git a/content/renderer/v8_value_converter_impl.cc b/content/renderer/v8_value_converter_impl.cc index 13f3e8a4..1afe31ed3 100644 --- a/content/renderer/v8_value_converter_impl.cc +++ b/content/renderer/v8_value_converter_impl.cc
@@ -258,8 +258,9 @@ case base::Value::Type::STRING: { std::string val; CHECK(value->GetAsString(&val)); - return v8::String::NewFromUtf8( - isolate, val.c_str(), v8::String::kNormalString, val.length()); + return v8::String::NewFromUtf8(isolate, val.c_str(), + v8::NewStringType::kNormal, val.length()) + .ToLocalChecked(); } case base::Value::Type::LIST: @@ -325,8 +326,9 @@ v8::Maybe<bool> maybe = result->CreateDataProperty( context, - v8::String::NewFromUtf8(isolate, key.c_str(), v8::String::kNormalString, - key.length()), + v8::String::NewFromUtf8(isolate, key.c_str(), + v8::NewStringType::kNormal, key.length()) + .ToLocalChecked(), child_v8); if (!maybe.IsJust() || !maybe.FromJust()) LOG(ERROR) << "Failed to set property with key " << key;
diff --git a/content/shell/test_runner/gc_controller.cc b/content/shell/test_runner/gc_controller.cc index 4ef63bd2..dd8a74a 100644 --- a/content/shell/test_runner/gc_controller.cc +++ b/content/shell/test_runner/gc_controller.cc
@@ -63,11 +63,15 @@ } void GCController::AsyncCollectAll(const gin::Arguments& args) { - if (args.PeekNext().IsEmpty()) { - NOTREACHED() << "AsyncCollectAll should be called with callback argument."; + v8::HandleScope scope(args.isolate()); + + if (args.PeekNext().IsEmpty() || !args.PeekNext()->IsFunction()) { + args.ThrowTypeError( + "asyncCollectAll should be called with a callback argument being a " + "v8::Function."); + return; } - v8::HandleScope scope(args.isolate()); v8::UniquePersistent<v8::Function> func( args.isolate(), v8::Local<v8::Function>::Cast(args.PeekNext()));
diff --git a/content/test/data/accessibility/event/aria-combo-box-focus.html b/content/test/data/accessibility/event/aria-combo-box-focus.html index 58eb56a..7f95c02 100644 --- a/content/test/data/accessibility/event/aria-combo-box-focus.html +++ b/content/test/data/accessibility/event/aria-combo-box-focus.html
@@ -1,6 +1,7 @@ <!-- This line is to unflake the test, but may not be necessary (crbug.com/c/791268): @WIN-DENY:EVENT_OBJECT_LOCATIONCHANGE* +@WIN-DENY:EVENT_OBJECT_SHOW* --> <!DOCTYPE html> <html>
diff --git a/content/test/data/accessibility/event/caret-move-expected-win.txt b/content/test/data/accessibility/event/caret-move-expected-win.txt new file mode 100644 index 0000000..ce8ad57 --- /dev/null +++ b/content/test/data/accessibility/event/caret-move-expected-win.txt
@@ -0,0 +1,8 @@ +EVENT_OBJECT_FOCUS on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE +EVENT_OBJECT_HIDE role=ROLE_SYSTEM_CARET INVISIBLE window_class=Chrome_WidgetWin_0 +EVENT_OBJECT_LOCATIONCHANGE role=ROLE_SYSTEM_CARET window_class=Chrome_WidgetWin_0 +EVENT_OBJECT_LOCATIONCHANGE role=ROLE_SYSTEM_CARET window_class=Chrome_WidgetWin_0 +EVENT_OBJECT_SHOW role=ROLE_SYSTEM_CARET window_class=Chrome_WidgetWin_0 +EVENT_OBJECT_VALUECHANGE on <input#in1> role=ROLE_SYSTEM_TEXT value="end" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE +IA2_EVENT_TEXT_CARET_MOVED on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE +IA2_EVENT_TEXT_CARET_MOVED on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
diff --git a/content/test/data/accessibility/event/caret-move.html b/content/test/data/accessibility/event/caret-move.html new file mode 100644 index 0000000..a4b641b --- /dev/null +++ b/content/test/data/accessibility/event/caret-move.html
@@ -0,0 +1,25 @@ +<!-- +@RUN-UNTIL-EVENT:EVENT_OBJECT_VALUECHANGE +@WIN-DENY:IA2_EVENT_TEXT_INSERTED* +@WIN-DENY:IA2_EVENT_TEXT_REMOVED* +--> +<!DOCTYPE html> +<html> +<body> +<input id="in1" type="text" value="abcde"> +<script> + function go() { + const inp = document.getElementById('in1'); + inp.focus(); + inp.setSelectionRange(0, 0); + setTimeout(() => { + inp.setSelectionRange(1, 1); + setTimeout(() => { + inp.blur(); + inp.value = 'end'; // Trigger test end. + }, 50); + }, 50); +} +</script> +</body> +</html> \ No newline at end of file
diff --git a/content/test/data/accessibility/readme.md b/content/test/data/accessibility/readme.md index 893dc47..05e1f46 100644 --- a/content/test/data/accessibility/readme.md +++ b/content/test/data/accessibility/readme.md
@@ -85,8 +85,8 @@ Normally the system waits for the document to finish loading before dumping the accessibility tree. -Occasionally you may need to write a test that makes some changes to the -document before it runs the test. In that case you can use a special +Occasionally you may need to write a dump tree test that makes some changes to +the document before it runs the test. In that case you can use a special @WAIT-FOR: directive. It should be in an HTML comment, just like @ALLOW-WIN: directives. The WAIT-FOR directive just specifies a text substring that should be present in the dump when the document is ready. The system @@ -95,6 +95,16 @@ You can add as many @WAIT-FOR: directives as you want, the test won't finish until all strings appear. +Or, you may need to write an event test that keeps dumping events until a +specific event line. In this case, use @RUN-UNTIL-EVENT with a substring that +should occur in the event log, e.g. @RUN-UNTIL-EVENT:IA2_EVENT_TEXT_CARET_MOVED. +Note that @RUN-UNTIL-EVENT is only used in dump events tests, and not used in +dump tree tests. + +If you add multiple @RUN-UNTIL-EVENT directives, the test will finish once any +of them are satisfied. Note that any other events that come along with the last +event will also be logged. + To skip dumping a particular element, make its accessible name equal to @NO_DUMP, for example <div aria-label="@NO_DUMP"></div>.
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc index 5b5dc75b..abed7a9 100644 --- a/content/test/layouttest_support.cc +++ b/content/test/layouttest_support.cc
@@ -237,9 +237,9 @@ void EnableWebTestProxyCreation() { RenderViewImpl::InstallCreateHook(CreateWebViewTestProxy); - RenderWidget::InstallCreateHook(CreateWebWidgetTestProxy, - RenderWidgetInitialized); - RenderFrameImpl::InstallCreateHook(CreateWebFrameTestProxy); + RenderFrameImpl::InstallCreateHook(CreateWebFrameTestProxy, + CreateWebWidgetTestProxy, + RenderWidgetInitialized); } void FetchManifest(blink::WebView* view, FetchManifestCallback callback) {
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc index 0ce610e..5f04949 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -677,18 +677,17 @@ void WebRequestProxyingURLLoaderFactory::OnTargetFactoryError() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); target_factory_.reset(); - if (proxy_bindings_.empty()) { - // Deletes |this|. - proxies_->RemoveProxy(this); - } + proxy_bindings_.CloseAllBindings(); + + MaybeRemoveProxy(); } void WebRequestProxyingURLLoaderFactory::OnProxyBindingError() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - if (proxy_bindings_.empty() && !target_factory_.is_bound()) { - // Deletes |this|. - proxies_->RemoveProxy(this); - } + if (proxy_bindings_.empty()) + target_factory_.reset(); + + MaybeRemoveProxy(); } void WebRequestProxyingURLLoaderFactory::RemoveRequest( @@ -701,6 +700,18 @@ this, content::GlobalRequestID(render_process_id_, network_service_request_id)); } + + MaybeRemoveProxy(); +} + +void WebRequestProxyingURLLoaderFactory::MaybeRemoveProxy() { + // Even if all URLLoaderFactory pipes connected to this object have been + // closed it has to stay alive until all active requests have completed. + if (target_factory_.is_bound() || !requests_.empty()) + return; + + // Deletes |this|. + proxies_->RemoveProxy(this); } } // namespace extensions
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h index 534b3e12..6be29d07 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -193,6 +193,7 @@ void OnTargetFactoryError(); void OnProxyBindingError(); void RemoveRequest(int32_t network_service_request_id, uint64_t request_id); + void MaybeRemoveProxy(); void* const browser_context_; content::ResourceContext* const resource_context_;
diff --git a/extensions/browser/updater/update_service_unittest.cc b/extensions/browser/updater/update_service_unittest.cc index 35b60939..5364e93 100644 --- a/extensions/browser/updater/update_service_unittest.cc +++ b/extensions/browser/updater/update_service_unittest.cc
@@ -311,7 +311,7 @@ scoped_refptr<Extension> extension1 = ExtensionBuilder("Foo") - .SetManifestKey("version", "1.0") + .SetVersion("1.0") .SetID(crx_file::id_util::GenerateId("foo_extension")) .SetPath(temp_dir.GetPath()) .Build(); @@ -409,11 +409,11 @@ // Build 3 extensions. scoped_refptr<Extension> extension1 = - ExtensionBuilder("1").SetManifestKey("version", "1.2").Build(); + ExtensionBuilder("1").SetVersion("1.2").Build(); scoped_refptr<Extension> extension2 = - ExtensionBuilder("2").SetManifestKey("version", "2.3").Build(); + ExtensionBuilder("2").SetVersion("2.3").Build(); scoped_refptr<Extension> extension3 = - ExtensionBuilder("3").SetManifestKey("version", "3.4").Build(); + ExtensionBuilder("3").SetVersion("3.4").Build(); EXPECT_TRUE(extension1->id() != extension2->id() && extension1->id() != extension3->id() && extension2->id() != extension3->id());
diff --git a/extensions/common/extension_builder.cc b/extensions/common/extension_builder.cc index 48d256f..37b4de0 100644 --- a/extensions/common/extension_builder.cc +++ b/extensions/common/extension_builder.cc
@@ -19,6 +19,7 @@ std::vector<std::string> permissions; base::Optional<ActionType> action; base::Optional<BackgroundPage> background_page; + base::Optional<std::string> version; // A ContentScriptEntry includes a string name, and a vector of string // match patterns. @@ -31,7 +32,7 @@ DictionaryBuilder manifest; manifest.Set("name", name) .Set("manifest_version", 2) - .Set("version", "0.1") + .Set("version", version.value_or("0.1")) .Set("description", "some description"); switch (type) { @@ -185,6 +186,12 @@ return *this; } +ExtensionBuilder& ExtensionBuilder::SetVersion(const std::string& version) { + CHECK(manifest_data_); + manifest_data_->version = version; + return *this; +} + ExtensionBuilder& ExtensionBuilder::SetPath(const base::FilePath& path) { path_ = path; return *this;
diff --git a/extensions/common/extension_builder.h b/extensions/common/extension_builder.h index c4af57e..3bd3544a 100644 --- a/extensions/common/extension_builder.h +++ b/extensions/common/extension_builder.h
@@ -95,6 +95,11 @@ const std::string& script_name, const std::vector<std::string>& match_patterns); + // Shortcut for setting a specific manifest version. Typically we'd use + // SetManifestKey() or SetManifestPath() for these, but provide a faster + // route for version, since it's so central. + ExtensionBuilder& SetVersion(const std::string& version); + // Shortcuts to setting values on the manifest dictionary without needing to // go all the way through MergeManifest(). Sample usage: // ExtensionBuilder("name").SetManifestKey("version", "0.2").Build();
diff --git a/extensions/common/extension_builder_unittest.cc b/extensions/common/extension_builder_unittest.cc index f446231..bb8bcac 100644 --- a/extensions/common/extension_builder_unittest.cc +++ b/extensions/common/extension_builder_unittest.cc
@@ -224,4 +224,11 @@ } } +TEST(ExtensionBuilderTest, SetVersion) { + constexpr char kVersion[] = "42.0.99.1"; + scoped_refptr<const Extension> extension = + ExtensionBuilder("foo").SetVersion(kVersion).Build(); + EXPECT_EQ(kVersion, extension->VersionString()); +} + } // namespace extensions
diff --git a/extensions/renderer/activity_log_converter_strategy.cc b/extensions/renderer/activity_log_converter_strategy.cc index 1663d15..d4612a4 100644 --- a/extensions/renderer/activity_log_converter_strategy.cc +++ b/extensions/renderer/activity_log_converter_strategy.cc
@@ -22,25 +22,35 @@ v8::TryCatch try_catch(isolate); v8::Isolate::DisallowJavascriptExecutionScope scope( isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); - v8::Local<v8::String> name = v8::String::NewFromUtf8(isolate, "["); + v8::Local<v8::String> name = + v8::String::NewFromUtf8(isolate, "[", v8::NewStringType::kNormal) + .ToLocalChecked(); if (object->IsFunction()) { - name = v8::String::Concat(isolate, name, - v8::String::NewFromUtf8(isolate, "Function")); + name = v8::String::Concat( + isolate, name, + v8::String::NewFromUtf8(isolate, "Function", v8::NewStringType::kNormal) + .ToLocalChecked()); v8::Local<v8::Value> fname = v8::Local<v8::Function>::Cast(object)->GetName(); if (fname->IsString() && v8::Local<v8::String>::Cast(fname)->Length()) { - name = v8::String::Concat(isolate, name, - v8::String::NewFromUtf8(isolate, " ")); + name = v8::String::Concat( + isolate, name, + v8::String::NewFromUtf8(isolate, " ", v8::NewStringType::kNormal) + .ToLocalChecked()); name = v8::String::Concat(isolate, name, v8::Local<v8::String>::Cast(fname)); - name = v8::String::Concat(isolate, name, - v8::String::NewFromUtf8(isolate, "()")); + name = v8::String::Concat( + isolate, name, + v8::String::NewFromUtf8(isolate, "()", v8::NewStringType::kNormal) + .ToLocalChecked()); } } else { name = v8::String::Concat(isolate, name, object->GetConstructorName()); } - name = - v8::String::Concat(isolate, name, v8::String::NewFromUtf8(isolate, "]")); + name = v8::String::Concat( + isolate, name, + v8::String::NewFromUtf8(isolate, "]", v8::NewStringType::kNormal) + .ToLocalChecked()); if (try_catch.HasCaught()) { return std::unique_ptr<base::Value>(
diff --git a/extensions/renderer/blob_native_handler.cc b/extensions/renderer/blob_native_handler.cc index 0a0e5e8..32fc9a6 100644 --- a/extensions/renderer/blob_native_handler.cc +++ b/extensions/renderer/blob_native_handler.cc
@@ -15,8 +15,10 @@ void GetBlobUuid(const v8::FunctionCallbackInfo<v8::Value>& args) { CHECK_EQ(1, args.Length()); blink::WebBlob blob = blink::WebBlob::FromV8Value(args[0]); - args.GetReturnValue().Set( - v8::String::NewFromUtf8(args.GetIsolate(), blob.Uuid().Utf8().data())); + args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(), + blob.Uuid().Utf8().data(), + v8::NewStringType::kNormal) + .ToLocalChecked()); } } // namespace
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 60a59aac..875ff26 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -172,7 +172,9 @@ void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) { // Check for the chrome property. If one doesn't exist, create one. v8::Local<v8::String> chrome_string( - v8::String::NewFromUtf8(context()->isolate(), "chrome")); + v8::String::NewFromUtf8(context()->isolate(), "chrome", + v8::NewStringType::kInternalized) + .ToLocalChecked()); v8::Local<v8::Object> global(context()->v8_context()->Global()); v8::Local<v8::Value> chrome(global->Get(chrome_string)); if (chrome->IsUndefined()) {
diff --git a/extensions/renderer/display_source_custom_bindings.cc b/extensions/renderer/display_source_custom_bindings.cc index 4cea79d6..88f64ec 100644 --- a/extensions/renderer/display_source_custom_bindings.cc +++ b/extensions/renderer/display_source_custom_bindings.cc
@@ -91,8 +91,10 @@ CHECK(sink_id_val->IsInt32()); const int sink_id = sink_id_val->ToInt32(isolate)->Value(); if (GetDisplaySession(sink_id)) { - isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( - isolate, kSessionAlreadyStarted))); + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, kSessionAlreadyStarted, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -104,7 +106,9 @@ if ((video_stream_val->IsNull() || video_stream_val->IsUndefined()) && (audio_stream_val->IsNull() || audio_stream_val->IsUndefined())) { isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); + v8::String::NewFromUtf8(isolate, kInvalidStreamArgs, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -116,7 +120,9 @@ .Component(); if (video_track.IsNull()) { isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); + v8::String::NewFromUtf8(isolate, kInvalidStreamArgs, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } } @@ -126,7 +132,9 @@ .Component(); if (audio_track.IsNull()) { isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); + v8::String::NewFromUtf8(isolate, kInvalidStreamArgs, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } } @@ -155,8 +163,10 @@ std::unique_ptr<DisplaySourceSession> session = DisplaySourceSessionFactory::CreateSession(session_params); if (!session) { - isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( - isolate, kErrorNotSupported))); + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, kErrorNotSupported, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -187,8 +197,10 @@ int sink_id = args[0]->ToInt32(args.GetIsolate())->Value(); DisplaySourceSession* session = GetDisplaySession(sink_id); if (!session) { - isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( - isolate, kSessionNotFound))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kSessionNotFound, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -197,14 +209,18 @@ if (state == DisplaySourceSession::Establishing) { // 'session started' callback has not yet been invoked. // This session is not existing for the user. - isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kSessionNotFound))); + isolate->ThrowException( + v8::Exception::Error(v8::String::NewFromUtf8(isolate, kSessionNotFound, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } if (state == DisplaySourceSession::Terminating) { - isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( - isolate, kSessionAlreadyTerminating))); + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, kSessionAlreadyTerminating, + v8::NewStringType::kNormal) + .ToLocalChecked())); return; } @@ -232,7 +248,9 @@ if (success) callback_args[1] = v8::Null(isolate); else - callback_args[1] = v8::String::NewFromUtf8(isolate, error_message.c_str()); + callback_args[1] = v8::String::NewFromUtf8(isolate, error_message.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked(); module_system->CallModuleMethodSafe("displaySource", "callCompletionCallback", 2, callback_args);
diff --git a/extensions/renderer/file_system_natives.cc b/extensions/renderer/file_system_natives.cc index f4a7cd8..1d906b6 100644 --- a/extensions/renderer/file_system_natives.cc +++ b/extensions/renderer/file_system_natives.cc
@@ -120,7 +120,8 @@ args.GetReturnValue().Set( v8::String::NewFromUtf8(isolate, filesystem_id.c_str(), - v8::String::kNormalString, filesystem_id.size())); + v8::NewStringType::kNormal, filesystem_id.size()) + .ToLocalChecked()); } } // namespace extensions
diff --git a/extensions/renderer/i18n_custom_bindings.cc b/extensions/renderer/i18n_custom_bindings.cc index 4a1b298..f43e993f 100644 --- a/extensions/renderer/i18n_custom_bindings.cc +++ b/extensions/renderer/i18n_custom_bindings.cc
@@ -57,8 +57,11 @@ void I18NCustomBindings::GetL10nUILanguage( const v8::FunctionCallbackInfo<v8::Value>& args) { - args.GetReturnValue().Set(v8::String::NewFromUtf8( - args.GetIsolate(), content::RenderThread::Get()->GetLocale().c_str())); + args.GetReturnValue().Set( + v8::String::NewFromUtf8(args.GetIsolate(), + content::RenderThread::Get()->GetLocale().c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); } void I18NCustomBindings::DetectTextLanguage(
diff --git a/extensions/renderer/js_extension_bindings_system.cc b/extensions/renderer/js_extension_bindings_system.cc index 1a6ff74f..783fa0c 100644 --- a/extensions/renderer/js_extension_bindings_system.cc +++ b/extensions/renderer/js_extension_bindings_system.cc
@@ -37,7 +37,10 @@ v8::Local<v8::Object> GetOrCreateObject(const v8::Local<v8::Object>& object, const std::string& field, v8::Isolate* isolate) { - v8::Local<v8::String> key = v8::String::NewFromUtf8(isolate, field.c_str()); + v8::Local<v8::String> key = + v8::String::NewFromUtf8(isolate, field.c_str(), + v8::NewStringType::kInternalized) + .ToLocalChecked(); // If the object has a callback property, it is assumed it is an unavailable // API, so it is safe to delete. This is checked before GetOrCreateObject is // called. @@ -60,7 +63,9 @@ // an empty object. v8::Local<v8::Object> GetOrCreateChrome(ScriptContext* context) { v8::Local<v8::String> chrome_string( - v8::String::NewFromUtf8(context->isolate(), "chrome")); + v8::String::NewFromUtf8(context->isolate(), "chrome", + v8::NewStringType::kInternalized) + .ToLocalChecked()); v8::Local<v8::Object> global(context->v8_context()->Global()); v8::Local<v8::Value> chrome(global->Get(chrome_string)); if (chrome->IsUndefined()) { @@ -280,7 +285,9 @@ return; v8::Local<v8::String> v8_bind_name = - v8::String::NewFromUtf8(context->isolate(), bind_name.c_str()); + v8::String::NewFromUtf8(context->isolate(), bind_name.c_str(), + v8::NewStringType::kInternalized) + .ToLocalChecked(); if (bind_object->HasRealNamedProperty(v8_bind_name)) { // The bind object may already have the property if the API has been // registered before (or if the extension has put something there already,
diff --git a/extensions/renderer/object_backed_native_handler.cc b/extensions/renderer/object_backed_native_handler.cc index 7cd3ca6..9242b20 100644 --- a/extensions/renderer/object_backed_native_handler.cc +++ b/extensions/renderer/object_backed_native_handler.cc
@@ -204,10 +204,13 @@ v8::Local<v8::Object> obj, const char* key, v8::Local<v8::Value> value) { - obj->SetPrivate(context, v8::Private::ForApi(context->GetIsolate(), - v8::String::NewFromUtf8( - context->GetIsolate(), key)), - value) + obj->SetPrivate( + context, + v8::Private::ForApi(context->GetIsolate(), + v8::String::NewFromUtf8(context->GetIsolate(), key, + v8::NewStringType::kNormal) + .ToLocalChecked()), + value) .FromJust(); } @@ -222,10 +225,12 @@ v8::Local<v8::Object> obj, const char* key, v8::Local<v8::Value>* result) { - return obj->GetPrivate(context, - v8::Private::ForApi(context->GetIsolate(), - v8::String::NewFromUtf8( - context->GetIsolate(), key))) + return obj + ->GetPrivate(context, v8::Private::ForApi(context->GetIsolate(), + v8::String::NewFromUtf8( + context->GetIsolate(), key, + v8::NewStringType::kNormal) + .ToLocalChecked())) .ToLocal(result); } @@ -238,10 +243,12 @@ void ObjectBackedNativeHandler::DeletePrivate(v8::Local<v8::Context> context, v8::Local<v8::Object> obj, const char* key) { - obj->DeletePrivate(context, - v8::Private::ForApi( - context->GetIsolate(), - v8::String::NewFromUtf8(context->GetIsolate(), key))) + obj->DeletePrivate( + context, + v8::Private::ForApi(context->GetIsolate(), + v8::String::NewFromUtf8(context->GetIsolate(), key, + v8::NewStringType::kNormal) + .ToLocalChecked())) .FromJust(); }
diff --git a/extensions/renderer/process_info_native_handler.cc b/extensions/renderer/process_info_native_handler.cc index 7b3287d..224c9d48 100644 --- a/extensions/renderer/process_info_native_handler.cc +++ b/extensions/renderer/process_info_native_handler.cc
@@ -61,14 +61,18 @@ void ProcessInfoNativeHandler::GetExtensionId( const v8::FunctionCallbackInfo<v8::Value>& args) { - args.GetReturnValue().Set( - v8::String::NewFromUtf8(args.GetIsolate(), extension_id_.c_str())); + args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(), + extension_id_.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); } void ProcessInfoNativeHandler::GetContextType( const v8::FunctionCallbackInfo<v8::Value>& args) { args.GetReturnValue().Set( - v8::String::NewFromUtf8(args.GetIsolate(), context_type_.c_str())); + v8::String::NewFromUtf8(args.GetIsolate(), context_type_.c_str(), + v8::NewStringType::kInternalized) + .ToLocalChecked()); } void ProcessInfoNativeHandler::InIncognitoContext( @@ -89,10 +93,13 @@ void ProcessInfoNativeHandler::IsSendRequestDisabled( const v8::FunctionCallbackInfo<v8::Value>& args) { if (send_request_disabled_) { - args.GetReturnValue().Set(v8::String::NewFromUtf8( - args.GetIsolate(), - "sendRequest and onRequest are obsolete." - " Please use sendMessage and onMessage instead.")); + args.GetReturnValue().Set( + v8::String::NewFromUtf8( + args.GetIsolate(), + "sendRequest and onRequest are obsolete." + " Please use sendMessage and onMessage instead.", + v8::NewStringType::kNormal) + .ToLocalChecked()); } }
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc index 329803a..69feec88 100644 --- a/extensions/renderer/script_context.cc +++ b/extensions/renderer/script_context.cc
@@ -353,11 +353,15 @@ v8::Local<v8::Value> argv[] = { v8::Integer::New(isolate(), request_id), - v8::String::NewFromUtf8(isolate(), name.c_str()), + v8::String::NewFromUtf8(isolate(), name.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked(), v8::Boolean::New(isolate(), success), content::V8ValueConverter::Create()->ToV8Value( &response, v8::Local<v8::Context>::New(isolate(), v8_context_)), - v8::String::NewFromUtf8(isolate(), error.c_str())}; + v8::String::NewFromUtf8(isolate(), error.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()}; module_system()->CallModuleMethodSafe("sendRequest", "handleResponse", arraysize(argv), argv); @@ -398,14 +402,18 @@ "%s cannot be used within a sandboxed frame."; std::string error_msg = base::StringPrintf(kMessage, name.c_str()); isolate()->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate(), error_msg.c_str()))); + v8::String::NewFromUtf8(isolate(), error_msg.c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; } Feature::Availability availability = GetAvailability(name); if (!availability.is_available()) { isolate()->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate(), availability.message().c_str()))); + v8::String::NewFromUtf8(isolate(), availability.message().c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked())); return false; }
diff --git a/extensions/renderer/set_icon_natives.cc b/extensions/renderer/set_icon_natives.cc index bc29330..45fd2f1 100644 --- a/extensions/renderer/set_icon_natives.cc +++ b/extensions/renderer/set_icon_natives.cc
@@ -44,18 +44,30 @@ v8::Local<v8::Context> v8_context = context()->v8_context(); v8::Isolate* isolate = v8_context->GetIsolate(); v8::Local<v8::Object> data = - image_data->Get(v8::String::NewFromUtf8(isolate, "data")) + image_data + ->Get(v8::String::NewFromUtf8(isolate, "data", + v8::NewStringType::kInternalized) + .ToLocalChecked()) ->ToObject(isolate); - int width = image_data->Get(v8::String::NewFromUtf8(isolate, "width")) + int width = image_data + ->Get(v8::String::NewFromUtf8( + isolate, "width", v8::NewStringType::kInternalized) + .ToLocalChecked()) ->Int32Value(v8_context) .FromMaybe(0); - int height = image_data->Get(v8::String::NewFromUtf8(isolate, "height")) - ->Int32Value(v8_context) - .FromMaybe(0); + int height = + image_data + ->Get(v8::String::NewFromUtf8(isolate, "height", + v8::NewStringType::kInternalized) + .ToLocalChecked()) + ->Int32Value(v8_context) + .FromMaybe(0); if (width <= 0 || height <= 0) { isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidDimensions))); + v8::String::NewFromUtf8(isolate, kInvalidDimensions, + v8::NewStringType::kInternalized) + .ToLocalChecked())); return false; } @@ -64,23 +76,32 @@ int max_width = (std::numeric_limits<int>::max() / 4) / height; if (width > max_width) { isolate->ThrowException(v8::Exception::Error( - v8::String::NewFromUtf8(isolate, kInvalidDimensions))); + v8::String::NewFromUtf8(isolate, kInvalidDimensions, + v8::NewStringType::kInternalized) + .ToLocalChecked())); return false; } - int data_length = data->Get(v8::String::NewFromUtf8(isolate, "length")) - ->Int32Value(v8_context) - .FromMaybe(0); + int data_length = + data->Get(v8::String::NewFromUtf8(isolate, "length", + v8::NewStringType::kInternalized) + .ToLocalChecked()) + ->Int32Value(v8_context) + .FromMaybe(0); if (data_length != 4 * width * height) { - isolate->ThrowException( - v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidData))); + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, kInvalidData, + v8::NewStringType::kInternalized) + .ToLocalChecked())); return false; } SkBitmap bitmap; if (!bitmap.tryAllocN32Pixels(width, height)) { - isolate->ThrowException( - v8::Exception::Error(v8::String::NewFromUtf8(isolate, kNoMemory))); + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, kNoMemory, + v8::NewStringType::kInternalized) + .ToLocalChecked())); return false; } bitmap.eraseARGB(0, 0, 0, 0); @@ -128,7 +149,10 @@ v8::Local<v8::Object>* bitmap_set_value) { v8::Isolate* isolate = context()->v8_context()->GetIsolate(); v8::Local<v8::Object> image_data_set = - details->Get(v8::String::NewFromUtf8(isolate, "imageData")) + details + ->Get(v8::String::NewFromUtf8(isolate, "imageData", + v8::NewStringType::kInternalized) + .ToLocalChecked()) ->ToObject(isolate); DCHECK(bitmap_set_value); @@ -160,12 +184,16 @@ return; v8::Local<v8::Object> dict(v8::Object::New(args.GetIsolate())); - dict->Set(v8::String::NewFromUtf8(args.GetIsolate(), "imageData"), + dict->Set(v8::String::NewFromUtf8(args.GetIsolate(), "imageData", + v8::NewStringType::kInternalized) + .ToLocalChecked(), bitmap_set_value); - if (details->Has(v8::String::NewFromUtf8(args.GetIsolate(), "tabId"))) { - dict->Set( - v8::String::NewFromUtf8(args.GetIsolate(), "tabId"), - details->Get(v8::String::NewFromUtf8(args.GetIsolate(), "tabId"))); + v8::Local<v8::String> tabId = + v8::String::NewFromUtf8(args.GetIsolate(), "tabId", + v8::NewStringType::kInternalized) + .ToLocalChecked(); + if (details->Has(tabId)) { + dict->Set(tabId, details->Get(tabId)); } args.GetReturnValue().Set(dict); }
diff --git a/extensions/renderer/v8_context_native_handler.cc b/extensions/renderer/v8_context_native_handler.cc index 1ae5ef69..b7e6653c 100644 --- a/extensions/renderer/v8_context_native_handler.cc +++ b/extensions/renderer/v8_context_native_handler.cc
@@ -35,11 +35,19 @@ v8::Maybe<bool> maybe = ret->SetPrototype(context_->v8_context(), v8::Null(isolate)); CHECK(maybe.IsJust() && maybe.FromJust()); - ret->Set(v8::String::NewFromUtf8(isolate, "is_available"), + ret->Set(v8::String::NewFromUtf8(isolate, "is_available", + v8::NewStringType::kInternalized) + .ToLocalChecked(), v8::Boolean::New(isolate, availability.is_available())); - ret->Set(v8::String::NewFromUtf8(isolate, "message"), - v8::String::NewFromUtf8(isolate, availability.message().c_str())); - ret->Set(v8::String::NewFromUtf8(isolate, "result"), + ret->Set(v8::String::NewFromUtf8(isolate, "message", + v8::NewStringType::kInternalized) + .ToLocalChecked(), + v8::String::NewFromUtf8(isolate, availability.message().c_str(), + v8::NewStringType::kNormal) + .ToLocalChecked()); + ret->Set(v8::String::NewFromUtf8(isolate, "result", + v8::NewStringType::kInternalized) + .ToLocalChecked(), v8::Integer::New(isolate, availability.result())); args.GetReturnValue().Set(ret); }
diff --git a/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc b/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc index a0f169a..b77ad682 100644 --- a/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc +++ b/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc
@@ -33,10 +33,7 @@ scoped_refptr<Extension> BuildExtension(const std::string& name, const std::string& version, const std::string& id) { - return ExtensionBuilder(name) - .SetManifestKey("version", version) - .SetID(id) - .Build(); + return ExtensionBuilder(name).SetVersion(version).SetID(id).Build(); } void OnSystemLogsResponse(
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index fc6e9ebc..a4c6b245 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -214,7 +214,6 @@ "//ios/chrome/browser/ui/first_run", "//ios/chrome/browser/ui/history", "//ios/chrome/browser/ui/main", - "//ios/chrome/browser/ui/main:feature_flags", "//ios/chrome/browser/ui/main:tab_switcher", "//ios/chrome/browser/ui/promos", "//ios/chrome/browser/ui/settings",
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index 2ea71bd4..a9ad838 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -119,10 +119,8 @@ #import "ios/chrome/browser/ui/first_run/first_run_util.h" #import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h" #include "ios/chrome/browser/ui/history/history_coordinator.h" -#import "ios/chrome/browser/ui/history/history_panel_view_controller.h" #import "ios/chrome/browser/ui/main/browser_view_wrangler.h" #import "ios/chrome/browser/ui/main/main_coordinator.h" -#import "ios/chrome/browser/ui/main/main_feature_flags.h" #import "ios/chrome/browser/ui/main/tab_switcher.h" #import "ios/chrome/browser/ui/main/view_controller_swapping.h" #import "ios/chrome/browser/ui/orientation_limiting_navigation_controller.h" @@ -391,9 +389,6 @@ // Cached launchOptions from -didFinishLaunchingWithOptions. NSDictionary* _launchOptions; - // View controller for displaying the legacy history panel. - UIViewController* _historyPanelViewController; - // Coordinator for displaying history. HistoryCoordinator* _historyCoordinator; @@ -1425,23 +1420,12 @@ } - (void)showHistory { - if (IsUIRefreshPhase1Enabled()) { - // New History UIReboot coordinator. - _historyCoordinator = [[HistoryCoordinator alloc] - initWithBaseViewController:self.currentBVC - browserState:_mainBrowserState]; - _historyCoordinator.loader = self.currentBVC; - _historyCoordinator.dispatcher = self.mainBVC.dispatcher; - [_historyCoordinator start]; - } else { - _historyPanelViewController = [[HistoryPanelViewController alloc] - initWithLoader:self.currentBVC - browserState:_mainBrowserState - dispatcher:self.mainBVC.dispatcher]; - [self.currentBVC presentViewController:_historyPanelViewController - animated:YES - completion:nil]; - } + _historyCoordinator = + [[HistoryCoordinator alloc] initWithBaseViewController:self.currentBVC + browserState:_mainBrowserState]; + _historyCoordinator.loader = self.currentBVC; + _historyCoordinator.dispatcher = self.mainBVC.dispatcher; + [_historyCoordinator start]; } - (void)closeSettingsUIAndOpenURL:(OpenNewTabCommand*)command { @@ -1476,18 +1460,6 @@ } } -- (void)showClearBrowsingDataSettingsFromViewController: - (UIViewController*)baseViewController { - if (_settingsNavigationController) - return; - _settingsNavigationController = [SettingsNavigationController - newClearBrowsingDataController:_mainBrowserState - delegate:self]; - [baseViewController presentViewController:_settingsNavigationController - animated:YES - completion:nil]; -} - // TODO(crbug.com/779791) : Remove showing settings from MainController. - (void)showAutofillSettingsFromViewController: (UIViewController*)baseViewController { @@ -1953,45 +1925,69 @@ ->SetSnapshotCoalescingEnabled(false); })); - // Capture metrics on snapshotting. - ShowTabSwitcherSnapshotResult snapshotResult = - ShowTabSwitcherSnapshotResult::kSnapshotSucceeded; - if (currentTab.webState->IsLoading()) { - // Do not take a snapshot if the web state is loading, since it will be - // stale. - snapshotResult = ShowTabSwitcherSnapshotResult:: - kSnapshotNotAttemptedBecausePageIsLoading; - SnapshotTabHelper::FromWebState(currentTab.webState)->RemoveSnapshot(); - // TODO(crbug.com/869256) : It is possible that the navigation completes - // in the time it takes to animate to the tab grid. The navigation - // completion will trigger another snapshot. But that snapshot may have - // the previous webpage because the rendering is not guaranteed to have - // been completed at navigation completion. It is better to have a blank - // snapshot than the wrong snapshot. We pause snapshotting here, and - // resume once we have animated to the tab grid. - SnapshotTabHelper::FromWebState(currentTab.webState)->PauseSnapshotting(); - } else { - // TODO(crbug.com/869256) : There is a very small possibility that the - // navigation has already completed, but the new webpage has not been - // rendered yet, so we may take a snapshot of the previous webpage. The - // reason for this is that rendering is not guaranteed at page loaded. But - // the possibility of this happening in this codepath is very small, and - // is not easily reproducible. - UIImage* snapshot = SnapshotTabHelper::FromWebState(currentTab.webState) - ->UpdateSnapshot(/*with_overlays=*/true, - /*visible_frame_only=*/true); - // TODO(crbug.com/711455) : Snapshot generation can fail for certain - // websites that have video somewhere on the page. If the snapshot - // generation fails, the stale snapshot should be removed so as not to - // display an old snapshot. - if (snapshot == SnapshotTabHelper::GetDefaultSnapshotImage()) { - snapshotResult = - ShowTabSwitcherSnapshotResult::kSnapshotAttemptedAndFailed; - SnapshotTabHelper::FromWebState(currentTab.webState)->RemoveSnapshot(); + if (IsWKWebViewSnapshotsEnabled()) { + if (currentTab.webState->IsLoading()) { + UMA_HISTOGRAM_ENUMERATION( + "IOS.ShowTabSwitcherSnapshotResult", + ShowTabSwitcherSnapshotResult:: + kSnapshotNotAttemptedBecausePageIsLoading); + } else { + SnapshotTabHelper::FromWebState(currentTab.webState) + ->UpdateSnapshotWithCallback(^(UIImage* snapshot) { + if (snapshot == SnapshotTabHelper::GetDefaultSnapshotImage()) { + UMA_HISTOGRAM_ENUMERATION( + "IOS.ShowTabSwitcherSnapshotResult", + ShowTabSwitcherSnapshotResult::kSnapshotAttemptedAndFailed); + } else { + UMA_HISTOGRAM_ENUMERATION( + "IOS.ShowTabSwitcherSnapshotResult", + ShowTabSwitcherSnapshotResult::kSnapshotSucceeded); + } + }); } + } else { + // Capture metrics on snapshotting. + ShowTabSwitcherSnapshotResult snapshotResult = + ShowTabSwitcherSnapshotResult::kSnapshotSucceeded; + if (currentTab.webState->IsLoading()) { + // Do not take a snapshot if the web state is loading, since it will be + // stale. + snapshotResult = ShowTabSwitcherSnapshotResult:: + kSnapshotNotAttemptedBecausePageIsLoading; + SnapshotTabHelper::FromWebState(currentTab.webState)->RemoveSnapshot(); + // TODO(crbug.com/869256) : It is possible that the navigation completes + // in the time it takes to animate to the tab grid. The navigation + // completion will trigger another snapshot. But that snapshot may have + // the previous webpage because the rendering is not guaranteed to have + // been completed at navigation completion. It is better to have a blank + // snapshot than the wrong snapshot. We pause snapshotting here, and + // resume once we have animated to the tab grid. + SnapshotTabHelper::FromWebState(currentTab.webState) + ->PauseSnapshotting(); + } else { + // TODO(crbug.com/869256) : There is a very small possibility that the + // navigation has already completed, but the new webpage has not been + // rendered yet, so we may take a snapshot of the previous webpage. The + // reason for this is that rendering is not guaranteed at page loaded. + // But the possibility of this happening in this codepath is very small, + // and is not easily reproducible. + UIImage* snapshot = SnapshotTabHelper::FromWebState(currentTab.webState) + ->UpdateSnapshot(/*with_overlays=*/true, + /*visible_frame_only=*/true); + // TODO(crbug.com/711455) : Snapshot generation can fail for certain + // websites that have video somewhere on the page. If the snapshot + // generation fails, the stale snapshot should be removed so as not to + // display an old snapshot. + if (snapshot == SnapshotTabHelper::GetDefaultSnapshotImage()) { + snapshotResult = + ShowTabSwitcherSnapshotResult::kSnapshotAttemptedAndFailed; + SnapshotTabHelper::FromWebState(currentTab.webState) + ->RemoveSnapshot(); + } + } + UMA_HISTOGRAM_ENUMERATION("IOS.ShowTabSwitcherSnapshotResult", + snapshotResult); } - UMA_HISTOGRAM_ENUMERATION("IOS.ShowTabSwitcherSnapshotResult", - snapshotResult); } DCHECK(_tabSwitcher); @@ -2103,30 +2099,15 @@ self.currentBVC = targetBVC; // The call to set currentBVC above does not actually display the BVC, because - // _dismissingTabSwitcher is YES. When the presentation experiment is - // enabled, force the BVC transition to start. - if (TabSwitcherPresentsBVCEnabled()) { - [self displayCurrentBVCAndFocusOmnibox:focusOmnibox]; - } + // _dismissingTabSwitcher is YES. So: Force the BVC transition to start. + [self displayCurrentBVCAndFocusOmnibox:focusOmnibox]; } - (void)finishDismissingTabSwitcher { - // The tab switcher presentation experiment modifies the app's VC hierarchy. - // As a result, the "active" VC when the animation completes differs based on - // the experiment state. - if (TabSwitcherPresentsBVCEnabled()) { - // When the experiment is enabled, the tab switcher dismissal animation runs - // as part of the BVC presentation process. The BVC is presented before the - // animations begin, so it is the current active VC at this point. - DCHECK_EQ(self.viewControllerSwapper.activeViewController, self.currentBVC); - } else { - // Without the experiment, the BVC is added as a child and made visible in - // the call to |displayCurrentBVC| below, after the tab switcher dismissal - // animation is complete. At this point in the process, the tab switcher is - // still the active VC. - DCHECK_EQ(self.viewControllerSwapper.activeViewController, - [_tabSwitcher viewController]); - } + // The tab switcher dismissal animation runs + // as part of the BVC presentation process. The BVC is presented before the + // animations begin, so it should be the current active VC at this point. + DCHECK_EQ(self.viewControllerSwapper.activeViewController, self.currentBVC); if (_modeToDisplayOnTabSwitcherDismissal == TabSwitcherDismissalMode::NORMAL) {
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn index d245b44..ca998b9 100644 --- a/ios/chrome/browser/BUILD.gn +++ b/ios/chrome/browser/BUILD.gn
@@ -132,8 +132,6 @@ "//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/external_search:feature_flags", "//ios/chrome/browser/ui/fullscreen:feature_flags", - "//ios/chrome/browser/ui/history:feature_flags", - "//ios/chrome/browser/ui/main:feature_flags", "//ios/chrome/browser/ui/omnibox", "//ios/chrome/browser/ui/toolbar/public:feature_flags", "//ios/chrome/browser/ui/toolbar_container:feature_flags",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm index b8241082..57fddf5 100644 --- a/ios/chrome/browser/about_flags.mm +++ b/ios/chrome/browser/about_flags.mm
@@ -36,6 +36,7 @@ #include "components/payments/core/features.h" #include "components/search_provider_logos/switches.h" #include "components/security_state/core/features.h" +#include "components/signin/core/browser/account_reconcilor.h" #include "components/signin/core/browser/signin_switches.h" #include "components/strings/grit/components_strings.h" #include "components/sync/driver/sync_driver_switches.h" @@ -52,8 +53,6 @@ #include "ios/chrome/browser/ssl/captive_portal_features.h" #include "ios/chrome/browser/ui/external_search/features.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h" -#import "ios/chrome/browser/ui/history/features.h" -#include "ios/chrome/browser/ui/main/main_feature_flags.h" #import "ios/chrome/browser/ui/toolbar/public/features.h" #import "ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h" #include "ios/chrome/browser/ui/ui_feature_flags.h" @@ -189,17 +188,9 @@ {"drag_and_drop", flag_descriptions::kDragAndDropName, flag_descriptions::kDragAndDropDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kDragAndDrop)}, - {"tab_switcher_presents_bvc", - flag_descriptions::kTabSwitcherPresentsBVCName, - flag_descriptions::kTabSwitcherPresentsBVCDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(kTabSwitcherPresentsBVC)}, {"external-search", flag_descriptions::kExternalSearchName, flag_descriptions::kExternalSearchDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kExternalSearch)}, - {"history-batch-updates-filter", - flag_descriptions::kHistoryBatchUpdatesFilterName, - flag_descriptions::kHistoryBatchUpdatesFilterDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(kHistoryBatchUpdatesFilter)}, {"slim-navigation-manager", flag_descriptions::kSlimNavigationManagerName, flag_descriptions::kSlimNavigationManagerDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(web::features::kSlimNavigationManager)}, @@ -395,6 +386,9 @@ {"custom-search-engines", flag_descriptions::kCustomSearchEnginesName, flag_descriptions::kCustomSearchEnginesDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kCustomSearchEngines)}, + {"use-multilogin-endpoint", flag_descriptions::kUseMultiloginEndpointName, + flag_descriptions::kUseMultiloginEndpointDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(kUseMultiloginEndpoint)}, }; // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/autofill/automation/automation_action.mm b/ios/chrome/browser/autofill/automation/automation_action.mm index 3b35cff..a9bdcfa 100644 --- a/ios/chrome/browser/autofill/automation/automation_action.mm +++ b/ios/chrome/browser/autofill/automation/automation_action.mm
@@ -249,11 +249,23 @@ @implementation AutomationActionAutofill -static const char PROFILE_NAME_FULL[] = "Yuki Nagato"; -static const char PROFILE_HOME_LINE1[] = "1600 Amphitheatre Parkway"; -static const char PROFILE_HOME_CITY[] = "Mountain View"; -static const char PROFILE_HOME_STATE[] = "CA"; -static const char PROFILE_HOME_ZIP[] = "94043"; +static const char PROFILE_NAME_FULL[] = "Milton C. Waddams"; +static const char PROFILE_NAME_FIRST[] = "Milton"; +static const char PROFILE_NAME_MIDDLE[] = "C."; +static const char PROFILE_NAME_LAST[] = "Waddams"; +static const char PROFILE_HOME_LINE1[] = "4120 Freidrich Lane"; +static const char PROFILE_HOME_LINE2[] = "Apt 8"; +static const char PROFILE_HOME_CITY[] = "Austin"; +static const char PROFILE_HOME_STATE[] = "Texas"; +static const char PROFILE_COMPANY_NAME[] = "Initech"; +static const char PROFILE_EMAIL_ADDRESS[] = "red.swingline@initech.com"; +static const char PROFILE_HOME_ZIP[] = "78744"; +static const char PROFILE_PHONE_HOME_CITY_CODE[] = "512"; +static const char PROFILE_PHONE_HOME_WHOLE[] = "5125551234"; +static const char PROFILE_CREDIT_CARD_NUMBER[] = "9621327911759602"; +static const char PROFILE_CREDIT_CARD_NAME_FULL[] = "Milton Waddams"; +static const char PROFILE_CREDIT_CARD_EXP_MONTH[] = "5"; +static const char PROFILE_CREDIT_CARD_EXP_4_DIGIT_YEAR[] = "2027"; // Loads the predefined autofill profile into the personal data manager, so that // autofill actions will be suggested when tapping on an autofillable form. @@ -268,15 +280,43 @@ autofill::AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); profile.SetRawInfo(autofill::NAME_FULL, base::UTF8ToUTF16(PROFILE_NAME_FULL)); + profile.SetRawInfo(autofill::NAME_FIRST, + base::UTF8ToUTF16(PROFILE_NAME_FIRST)); + profile.SetRawInfo(autofill::NAME_MIDDLE, + base::UTF8ToUTF16(PROFILE_NAME_MIDDLE)); + profile.SetRawInfo(autofill::NAME_LAST, base::UTF8ToUTF16(PROFILE_NAME_LAST)); profile.SetRawInfo(autofill::ADDRESS_HOME_LINE1, base::UTF8ToUTF16(PROFILE_HOME_LINE1)); + profile.SetRawInfo(autofill::ADDRESS_HOME_LINE2, + base::UTF8ToUTF16(PROFILE_HOME_LINE2)); profile.SetRawInfo(autofill::ADDRESS_HOME_CITY, base::UTF8ToUTF16(PROFILE_HOME_CITY)); profile.SetRawInfo(autofill::ADDRESS_HOME_STATE, base::UTF8ToUTF16(PROFILE_HOME_STATE)); + profile.SetRawInfo(autofill::COMPANY_NAME, + base::UTF8ToUTF16(PROFILE_COMPANY_NAME)); + profile.SetRawInfo(autofill::EMAIL_ADDRESS, + base::UTF8ToUTF16(PROFILE_EMAIL_ADDRESS)); profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP, base::UTF8ToUTF16(PROFILE_HOME_ZIP)); + profile.SetRawInfo(autofill::PHONE_HOME_CITY_CODE, + base::UTF8ToUTF16(PROFILE_PHONE_HOME_CITY_CODE)); + profile.SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER, + base::UTF8ToUTF16(PROFILE_PHONE_HOME_WHOLE)); personal_data_manager->SaveImportedProfile(profile); + + autofill::CreditCard credit_card(base::GenerateGUID(), + "https://www.example.com/"); + credit_card.SetRawInfo(autofill::CREDIT_CARD_NUMBER, + base::UTF8ToUTF16(PROFILE_CREDIT_CARD_NUMBER)); + credit_card.SetRawInfo(autofill::CREDIT_CARD_NAME_FULL, + base::UTF8ToUTF16(PROFILE_CREDIT_CARD_NAME_FULL)); + credit_card.SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH, + base::UTF8ToUTF16(PROFILE_CREDIT_CARD_EXP_MONTH)); + credit_card.SetRawInfo( + autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, + base::UTF8ToUTF16(PROFILE_CREDIT_CARD_EXP_4_DIGIT_YEAR)); + personal_data_manager->AddCreditCard(credit_card); } - (void)execute {
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc index d094f76..fa622a8a 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -250,12 +250,6 @@ const char kSSOWithWKWebViewDescription[] = "Using WKWebView instead of UIWebView in SSO"; -const char kTabSwitcherPresentsBVCName[] = "TabSwitcher Presents BVC"; -const char kTabSwitcherPresentsBVCDescription[] = - "When enabled, the tab switcher will present the BVC, so that when the " - "BVC is visible, the tab switcher will remain in the VC hierarchy " - "underneath it."; - const char kToolbarContainerName[] = "Use Toolbar Containers"; const char kToolbarContainerDescription[] = "When enabled, the toolbars and their fullscreen animations will be " @@ -267,6 +261,10 @@ "features. This includes new confirmation screens and improved settings " "pages."; +const char kUseMultiloginEndpointName[] = "Use Multilogin endpoint."; +const char kUseMultiloginEndpointDescription[] = + "Use Gaia OAuth multilogin for identity consistency."; + const char kForceUnifiedConsentBumpName[] = "Force Unified Consent Bump"; const char kForceUnifiedConsentBumpDescription[] = "Force the unified consent bump UI to be shown on every start-up. This "
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h index a9803ee..6efd1f8 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -207,11 +207,6 @@ extern const char kSSOWithWKWebViewName[]; extern const char kSSOWithWKWebViewDescription[]; -// Title and description for the flag to enable the TabSwitcher to present the -// BVC. -extern const char kTabSwitcherPresentsBVCName[]; -extern const char kTabSwitcherPresentsBVCDescription[]; - // Title and description for the flag to enable the toolbar container // implementation. extern const char kToolbarContainerName[]; @@ -221,6 +216,11 @@ extern const char kUnifiedConsentName[]; extern const char kUnifiedConsentDescription[]; +// Title and description for the flag to enable Gaia Auth Mutlilogin endpoint +// for identity consistency. +extern const char kUseMultiloginEndpointName[]; +extern const char kUseMultiloginEndpointDescription[]; + // Title and description for the flag to force the consent bump. extern const char kForceUnifiedConsentBumpName[]; extern const char kForceUnifiedConsentBumpDescription[];
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc b/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc index fbbf586d..af1b2ce7 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc +++ b/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc
@@ -99,7 +99,7 @@ LOG(WARNING) << "Could not initialize password store."; return nullptr; } - password_manager_util::DeleteBlacklistedDuplicates( + password_manager_util::RemoveUselessCredentials( store, ios::ChromeBrowserState::FromBrowserState(context)->GetPrefs(), 60); return store;
diff --git a/ios/chrome/browser/prefs/BUILD.gn b/ios/chrome/browser/prefs/BUILD.gn index e3e3a6b..9f414ac 100644 --- a/ios/chrome/browser/prefs/BUILD.gn +++ b/ios/chrome/browser/prefs/BUILD.gn
@@ -53,6 +53,7 @@ "//components/signin/core/browser", "//components/strings", "//components/sync", + "//components/sync_sessions", "//components/translate/core/browser", "//components/translate/core/common", "//components/unified_consent",
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm index a23789d3..f1a0702 100644 --- a/ios/chrome/browser/prefs/browser_prefs.mm +++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -34,6 +34,7 @@ #include "components/signin/core/browser/signin_pref_names.h" #include "components/strings/grit/components_locale_settings.h" #include "components/sync/base/sync_prefs.h" +#include "components/sync_sessions/session_sync_prefs.h" #include "components/translate/core/browser/translate_pref_names.h" #include "components/translate/core/browser/translate_prefs.h" #include "components/unified_consent/unified_consent_service.h" @@ -116,6 +117,7 @@ payments::RegisterProfilePrefs(registry); PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry); RegisterVoiceSearchBrowserStatePrefs(registry); + sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry); syncer::SyncPrefs::RegisterProfilePrefs(registry); TemplateURLPrepopulateData::RegisterProfilePrefs(registry); translate::TranslatePrefs::RegisterProfilePrefs(registry);
diff --git a/ios/chrome/browser/snapshots/BUILD.gn b/ios/chrome/browser/snapshots/BUILD.gn index 3026311..3cab42f 100644 --- a/ios/chrome/browser/snapshots/BUILD.gn +++ b/ios/chrome/browser/snapshots/BUILD.gn
@@ -41,6 +41,7 @@ "//ios/chrome/browser/web:tab_id_tab_helper", "//ios/chrome/browser/web_state_list", "//ios/web/public", + "//ui/gfx", ] libs = [ "QuartzCore.framework",
diff --git a/ios/chrome/browser/snapshots/snapshot_generator.h b/ios/chrome/browser/snapshots/snapshot_generator.h index 2e7fc84d..b2e01f6c 100644 --- a/ios/chrome/browser/snapshots/snapshot_generator.h +++ b/ios/chrome/browser/snapshots/snapshot_generator.h
@@ -47,16 +47,20 @@ - (void)retrieveGreySnapshot:(void (^)(UIImage*))callback; // Invalidates the cached snapshot for the current page, generates and caches -// a new snapshot. Returns the snapshot with or without the overlayed views -// (e.g. infobar, voice search button, etc.), and either of the visible frame -// or of the full screen. +// a new snapshot. Returns the snapshot with or without the overlaid views +// (e.g. infobar), and either of the visible frame or of the full screen. - (UIImage*)updateSnapshotWithOverlays:(BOOL)shouldAddOverlay visibleFrameOnly:(BOOL)visibleFrameOnly; +// Invalidates the cached snapshot for the current page, generates and caches +// a new snapshot. Calls |completion| with a snapshot with overlaid views (e.g. +// infobar) of the visible frame. This method should only be called if the web +// state has a valid web view. +- (void)updateWebViewSnapshotWithCompletion:(void (^)(UIImage*))completion; + // Generates a new snapshot for the current page including optional infobars. -// Returns the snapshot with or without the overlayed views (e.g. infobar, -// voice search button, etc.), and either of the visible frame or of the full -// screen. +// Returns the snapshot with or without the overlaid views (e.g. infobar), and +// either of the visible frame or of the full screen. - (UIImage*)generateSnapshotWithOverlays:(BOOL)shouldAddOverlay visibleFrameOnly:(BOOL)visibleFrameOnly;
diff --git a/ios/chrome/browser/snapshots/snapshot_generator.mm b/ios/chrome/browser/snapshots/snapshot_generator.mm index 5e450a22..a12504d 100644 --- a/ios/chrome/browser/snapshots/snapshot_generator.mm +++ b/ios/chrome/browser/snapshots/snapshot_generator.mm
@@ -22,6 +22,7 @@ #import "ios/web/public/features.h" #import "ios/web/public/web_state/web_state.h" #import "ios/web/public/web_state/web_state_observer_bridge.h" +#include "ui/gfx/image/image.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -102,6 +103,12 @@ withRect:(CGRect)rect overlays:(NSArray<SnapshotOverlay*>*)overlays; +// Returns an image of the |snapshot| overlaid with |overlays| with the given +// |frame|. +- (UIImage*)snapshotWithOverlays:(NSArray<SnapshotOverlay*>*)overlays + snapshot:(UIImage*)snapshot + frame:(CGRect)frame; + // Property providing access to the snapshot's cache. May be nil. @property(nonatomic, readonly) SnapshotCache* snapshotCache; @@ -206,6 +213,45 @@ return snapshot; } +- (void)updateWebViewSnapshotWithCompletion:(void (^)(UIImage*))completion { + DCHECK(_webState); + CGRect frame = [self snapshotFrameVisibleFrameOnly:YES]; + if (CGRectIsEmpty(frame)) + return; + NSArray<SnapshotOverlay*>* overlays = + [_delegate snapshotOverlaysForWebState:_webState]; + UIImage* snapshot = + [_coalescingSnapshotContext cachedSnapshotWithOverlays:overlays + visibleFrameOnly:YES]; + if (snapshot) { + if (completion) + completion(snapshot); + return; + } + + [_delegate willUpdateSnapshotForWebState:_webState]; + __weak SnapshotGenerator* weakSelf = self; + _webState->TakeSnapshot(base::BindOnce(^(gfx::Image image) { + SnapshotGenerator* strongSelf = weakSelf; + if (!strongSelf) + return; + UIImage* snapshot = image.ToUIImage(); + if (overlays.count > 0) { + snapshot = [strongSelf snapshotWithOverlays:overlays + snapshot:snapshot + frame:frame]; + } + [strongSelf.snapshotCache setImage:snapshot + withSessionID:_snapshotSessionId]; + [_coalescingSnapshotContext setCachedSnapshot:snapshot + withOverlays:overlays + visibleFrameOnly:YES]; + [_delegate didUpdateSnapshotForWebState:_webState withImage:snapshot]; + if (completion) + completion(snapshot); + })); +} + - (UIImage*)generateSnapshotWithOverlays:(BOOL)shouldAddOverlay visibleFrameOnly:(BOOL)visibleFrameOnly { CGRect frame = [self snapshotFrameVisibleFrameOnly:visibleFrameOnly]; @@ -351,6 +397,37 @@ return image; } +- (UIImage*)snapshotWithOverlays:(NSArray<SnapshotOverlay*>*)overlays + snapshot:(UIImage*)snapshot + frame:(CGRect)frame { + CGSize size = frame.size; + DCHECK(std::isnormal(size.width) && (size.width > 0)) + << ": size.width=" << size.width; + DCHECK(std::isnormal(size.height) && (size.height > 0)) + << ": size.height=" << size.height; + const CGFloat kScale = + std::max<CGFloat>(1.0, [self.snapshotCache snapshotScaleForDevice]); + UIGraphicsBeginImageContextWithOptions(size, YES, kScale); + CGContext* context = UIGraphicsGetCurrentContext(); + DCHECK(context); + CGContextSaveGState(context); + [snapshot drawAtPoint:CGPointZero]; + for (SnapshotOverlay* overlay in overlays) { + // Render the overlay view at the desired offset. It is achieved + // by shifting origin of context because view frame is ignored when + // drawing to context. + CGContextSaveGState(context); + CGContextTranslateCTM(context, 0, overlay.yOffset - frame.origin.y); + [overlay.view drawViewHierarchyInRect:overlay.view.bounds + afterScreenUpdates:YES]; + CGContextRestoreGState(context); + } + UIImage* snapshotWithOverlays = UIGraphicsGetImageFromCurrentImageContext(); + CGContextRestoreGState(context); + UIGraphicsEndImageContext(); + return snapshotWithOverlays; +} + #pragma mark - Properties. - (SnapshotCache*)snapshotCache {
diff --git a/ios/chrome/browser/snapshots/snapshot_tab_helper.h b/ios/chrome/browser/snapshots/snapshot_tab_helper.h index 44f507d..3a43b15 100644 --- a/ios/chrome/browser/snapshots/snapshot_tab_helper.h +++ b/ios/chrome/browser/snapshots/snapshot_tab_helper.h
@@ -10,6 +10,7 @@ #import <UIKit/UIKit.h> #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "components/infobars/core/infobar_manager.h" #import "ios/web/public/web_state/web_state_observer.h" #import "ios/web/public/web_state/web_state_user_data.h" @@ -50,14 +51,20 @@ void RetrieveGreySnapshot(void (^callback)(UIImage*)); // Invalidates the cached snapshot for the current page and forces the + // generation of a more recent snapshot. Runs |callback| with a snapshot with + // overlaid views (e.g. infobar) of the visible frame. In iOS 11+, snapshots + // of a valid web view are taken using WKWebView's snapshotting API. + void UpdateSnapshotWithCallback(void (^callback)(UIImage*)); + + // Invalidates the cached snapshot for the current page and forces the // generation of a more recent snapshot. Returns the snapshot with or - // without the overlayed views (e.g. infobar, voice search button, ...) - // and either of the visible frame or of the full screen. + // without the overlaid views (e.g. infobar) and either of the visible frame + // or of the full screen. UIImage* UpdateSnapshot(bool with_overlays, bool visible_frame_only); // Generates a snapshot for the current page. Returns the snapshot with - // or without the overlayed views (e.g. infobar, voice search button, ...) - // and either of the visible frame of of the full screen. + // or without the overlaid views (e.g. infobar) and either of the visible + // frame of of the full screen. UIImage* GenerateSnapshot(bool with_overlays, bool visible_frame_only); // When snapshot coalescing is enabled, multiple calls to generate a @@ -83,6 +90,7 @@ SnapshotTabHelper(web::WebState* web_state, NSString* session_id); // web::WebStateObserver implementation. + void DidStartLoading(web::WebState* web_state) override; void PageLoaded( web::WebState* web_state, web::PageLoadCompletionStatus load_completion_status) override; @@ -94,6 +102,10 @@ bool ignore_next_load_ = false; bool pause_snapshotting_ = false; + // Used to ensure |UpdateSnapshotWithCallback()| is not run when this object + // is destroyed. + base::WeakPtrFactory<SnapshotTabHelper> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(SnapshotTabHelper); };
diff --git a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm index 7bcdeca..6a9c642 100644 --- a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm +++ b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
@@ -4,11 +4,16 @@ #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" +#include "base/bind.h" #include "base/logging.h" #include "base/memory/ptr_util.h" +#include "base/task/post_task.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/infobars/infobar_manager_impl.h" #import "ios/chrome/browser/snapshots/snapshot_generator.h" +#include "ios/chrome/browser/ui/ui_util.h" +#include "ios/web/public/web_task_traits.h" +#include "ios/web/public/web_thread.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -122,6 +127,23 @@ [snapshot_generator_ retrieveGreySnapshot:callback]; } +void SnapshotTabHelper::UpdateSnapshotWithCallback(void (^callback)(UIImage*)) { + if (IsWKWebViewSnapshotsEnabled() && web_state_->ContentIsHTML()) { + if (@available(iOS 11, *)) { + [snapshot_generator_ updateWebViewSnapshotWithCompletion:callback]; + return; + } + } + // Pre-iOS 11 and native content cannot utilize the WKWebView snapshotting + // API. + UIImage* image = + UpdateSnapshot(/*with_overlays=*/true, /*visible_frame_only=*/true); + dispatch_async(dispatch_get_main_queue(), ^{ + if (callback) + callback(image); + }); +} + UIImage* SnapshotTabHelper::UpdateSnapshot(bool with_overlays, bool visible_frame_only) { return [snapshot_generator_ updateSnapshotWithOverlays:with_overlays @@ -162,7 +184,7 @@ SnapshotTabHelper::SnapshotTabHelper(web::WebState* web_state, NSString* session_id) - : web_state_(web_state) { + : web_state_(web_state), weak_ptr_factory_(this) { snapshot_generator_ = [[SnapshotGenerator alloc] initWithWebState:web_state_ snapshotSessionId:session_id]; @@ -176,11 +198,28 @@ web_state_->AddObserver(this); } +void SnapshotTabHelper::DidStartLoading(web::WebState* web_state) { + if (IsWKWebViewSnapshotsEnabled()) + RemoveSnapshot(); +} + void SnapshotTabHelper::PageLoaded( web::WebState* web_state, web::PageLoadCompletionStatus load_completion_status) { if (!ignore_next_load_ && !pause_snapshotting_ && load_completion_status == web::PageLoadCompletionStatus::SUCCESS) { + if (IsWKWebViewSnapshotsEnabled() && web_state->ContentIsHTML()) { + if (@available(iOS 11, *)) { + base::PostDelayedTaskWithTraits( + FROM_HERE, {web::WebThread::UI}, + base::BindOnce(&SnapshotTabHelper::UpdateSnapshotWithCallback, + weak_ptr_factory_.GetWeakPtr(), /*callback=*/nil), + base::TimeDelta::FromSeconds(1)); + return; + } + } + // Pre-iOS 11 and native content cannot utilize the WKWebView snapshotting + // API. UpdateSnapshot(/*with_overlays=*/true, /*visible_frame_only=*/true); } ignore_next_load_ = false;
diff --git a/ios/chrome/browser/sync/BUILD.gn b/ios/chrome/browser/sync/BUILD.gn index c55af33..17c2bda 100644 --- a/ios/chrome/browser/sync/BUILD.gn +++ b/ios/chrome/browser/sync/BUILD.gn
@@ -21,6 +21,8 @@ "model_type_store_service_factory.h", "profile_sync_service_factory.cc", "profile_sync_service_factory.h", + "session_sync_service_factory.cc", + "session_sync_service_factory.h", "sync_observer_bridge.h", "sync_observer_bridge.mm", "sync_setup_service.cc", @@ -121,12 +123,14 @@ testonly = true sources = [ "profile_sync_service_factory_unittest.cc", + "session_sync_service_factory_unittest.cc", ] deps = [ ":sync", "//base", "//components/browser_sync", "//components/sync", + "//ios/chrome/browser", "//ios/chrome/browser/browser_state:test_support", "//ios/web/public/test", "//testing/gtest",
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.h b/ios/chrome/browser/sync/ios_chrome_sync_client.h index 988b4f2..803901d 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.h +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.h
@@ -45,6 +45,7 @@ bookmarks::BookmarkModel* GetBookmarkModel() override; favicon::FaviconService* GetFaviconService() override; history::HistoryService* GetHistoryService() override; + sync_sessions::SessionSyncService* GetSessionSyncService() override; bool HasPasswordStore() override; base::Closure GetPasswordStateChangedCallback() override; syncer::DataTypeController::TypeVector CreateDataTypeControllers( @@ -53,7 +54,6 @@ invalidation::InvalidationService* GetInvalidationService() override; BookmarkUndoService* GetBookmarkUndoServiceIfExists() override; scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override; - sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override; base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType( syncer::ModelType type) override; base::WeakPtr<syncer::ModelTypeControllerDelegate> @@ -84,8 +84,6 @@ // The task runner for the |web_data_service_|, if any. scoped_refptr<base::SingleThreadTaskRunner> db_thread_; - std::unique_ptr<sync_sessions::SyncSessionsClient> sync_sessions_client_; - DISALLOW_COPY_AND_ASSIGN(IOSChromeSyncClient); };
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm index 689158ca..014c4a50 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -36,7 +36,6 @@ #include "components/reading_list/core/reading_list_model.h" #include "components/search_engines/search_engine_data_type_controller.h" #include "components/sync/base/report_unrecoverable_error.h" -#include "components/sync/device_info/local_device_info_provider.h" #include "components/sync/driver/sync_api_component_factory.h" #include "components/sync/driver/sync_util.h" #include "components/sync/engine/passive_model_worker.h" @@ -45,17 +44,13 @@ #include "components/sync/user_events/user_event_service.h" #include "components/sync_preferences/pref_service_syncable.h" #include "components/sync_sessions/favicon_cache.h" -#include "components/sync_sessions/local_session_event_router.h" -#include "components/sync_sessions/session_sync_bridge.h" -#include "components/sync_sessions/sync_sessions_client.h" -#include "components/sync_sessions/synced_window_delegates_getter.h" +#include "components/sync_sessions/session_sync_service.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/bookmarks/bookmark_sync_service_factory.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" -#include "ios/chrome/browser/chrome_url_constants.h" #include "ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h" #include "ios/chrome/browser/favicon/favicon_service_factory.h" #include "ios/chrome/browser/history/history_service_factory.h" @@ -64,12 +59,10 @@ #include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/reading_list/reading_list_model_factory.h" #include "ios/chrome/browser/sync/consent_auditor_factory.h" -#include "ios/chrome/browser/sync/glue/sync_start_util.h" #include "ios/chrome/browser/sync/ios_user_event_service_factory.h" #include "ios/chrome/browser/sync/model_type_store_service_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" -#include "ios/chrome/browser/sync/sessions/ios_chrome_local_session_event_router.h" -#include "ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h" +#include "ios/chrome/browser/sync/session_sync_service_factory.h" #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h" #include "ios/chrome/browser/web_data_service_factory.h" #include "ios/chrome/common/channel_info.h" @@ -91,80 +84,10 @@ return syncer::ModelTypeSetFromString(disabled_types_str); } -// iOS implementation of SyncSessionsClient. Needs to be in a separate class -// due to possible multiple inheritance issues, wherein IOSChromeSyncClient -// might inherit from other interfaces with same methods. -class SyncSessionsClientImpl : public sync_sessions::SyncSessionsClient { - public: - explicit SyncSessionsClientImpl(ios::ChromeBrowserState* browser_state) - : browser_state_(browser_state), - window_delegates_getter_( - std::make_unique<TabModelSyncedWindowDelegatesGetter>()), - local_session_event_router_( - std::make_unique<IOSChromeLocalSessionEventRouter>( - browser_state_, - this, - ios::sync_start_util::GetFlareForSyncableService( - browser_state_->GetStatePath()))) {} - - ~SyncSessionsClientImpl() override {} - - // SyncSessionsClient implementation. - favicon::FaviconService* GetFaviconService() override { - DCHECK_CURRENTLY_ON(web::WebThread::UI); - return ios::FaviconServiceFactory::GetForBrowserState( - browser_state_, ServiceAccessType::IMPLICIT_ACCESS); - } - - history::HistoryService* GetHistoryService() override { - DCHECK_CURRENTLY_ON(web::WebThread::UI); - return ios::HistoryServiceFactory::GetForBrowserState( - browser_state_, ServiceAccessType::EXPLICIT_ACCESS); - } - - const syncer::DeviceInfo* GetLocalDeviceInfo() override { - DCHECK_CURRENTLY_ON(web::WebThread::UI); - return ProfileSyncServiceFactory::GetForBrowserState(browser_state_) - ->GetLocalDeviceInfoProvider() - ->GetLocalDeviceInfo(); - } - - bool ShouldSyncURL(const GURL& url) const override { - if (url == kChromeUIHistoryURL) { - // The history page is treated specially as we want it to trigger syncable - // events for UI purposes. - return true; - } - return url.is_valid() && !url.SchemeIs(kChromeUIScheme) && - !url.SchemeIsFile(); - } - - sync_sessions::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter() - override { - return window_delegates_getter_.get(); - } - - sync_sessions::LocalSessionEventRouter* GetLocalSessionEventRouter() - override { - return local_session_event_router_.get(); - } - - private: - ios::ChromeBrowserState* const browser_state_; - const std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter> - window_delegates_getter_; - const std::unique_ptr<IOSChromeLocalSessionEventRouter> - local_session_event_router_; - - DISALLOW_COPY_AND_ASSIGN(SyncSessionsClientImpl); -}; - } // namespace IOSChromeSyncClient::IOSChromeSyncClient(ios::ChromeBrowserState* browser_state) - : browser_state_(browser_state), - sync_sessions_client_( - std::make_unique<SyncSessionsClientImpl>(browser_state)) { + : browser_state_(browser_state) { profile_web_data_service_ = ios::WebDataServiceFactory::GetAutofillWebDataForBrowserState( browser_state_, ServiceAccessType::IMPLICIT_ACCESS); @@ -231,6 +154,12 @@ browser_state_, ServiceAccessType::EXPLICIT_ACCESS); } +sync_sessions::SessionSyncService* +IOSChromeSyncClient::GetSessionSyncService() { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + return SessionSyncServiceFactory::GetForBrowserState(browser_state_); +} + bool IOSChromeSyncClient::HasPasswordStore() { DCHECK_CURRENTLY_ON(web::WebThread::UI); return password_store_ != nullptr; @@ -276,11 +205,6 @@ return nullptr; } -sync_sessions::SyncSessionsClient* -IOSChromeSyncClient::GetSyncSessionsClient() { - return sync_sessions_client_.get(); -} - base::WeakPtr<syncer::SyncableService> IOSChromeSyncClient::GetSyncableServiceForType(syncer::ModelType type) { switch (type) { @@ -320,7 +244,7 @@ case syncer::FAVICON_IMAGES: case syncer::FAVICON_TRACKING: { sync_sessions::FaviconCache* favicons = - ProfileSyncServiceFactory::GetForBrowserState(browser_state_) + SessionSyncServiceFactory::GetForBrowserState(browser_state_) ->GetFaviconCache(); return favicons ? favicons->AsWeakPtr() : base::WeakPtr<syncer::SyncableService>(); @@ -333,8 +257,8 @@ return base::WeakPtr<syncer::SyncableService>(); } case syncer::SESSIONS: { - return ProfileSyncServiceFactory::GetForBrowserState(browser_state_) - ->GetSessionsSyncableService() + return SessionSyncServiceFactory::GetForBrowserState(browser_state_) + ->GetSyncableService() ->AsWeakPtr(); } case syncer::PASSWORDS: { @@ -368,9 +292,6 @@ ->GetSyncBridge() ->change_processor() ->GetControllerDelegate(); - case syncer::SESSIONS: - return ProfileSyncServiceFactory::GetForBrowserState(browser_state_) - ->GetSessionSyncControllerDelegate(); // We don't exercise this function for certain datatypes, because their // controllers get the delegate elsewhere. @@ -379,6 +300,7 @@ case syncer::AUTOFILL_WALLET_DATA: case syncer::AUTOFILL_WALLET_METADATA: case syncer::BOOKMARKS: + case syncer::SESSIONS: case syncer::TYPED_URLS: NOTREACHED(); return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
diff --git a/ios/chrome/browser/sync/ios_user_event_service_factory.cc b/ios/chrome/browser/sync/ios_user_event_service_factory.cc index 3469d25..cfd41c5 100644 --- a/ios/chrome/browser/sync/ios_user_event_service_factory.cc +++ b/ios/chrome/browser/sync/ios_user_event_service_factory.cc
@@ -17,10 +17,12 @@ #include "components/sync/user_events/no_op_user_event_service.h" #include "components/sync/user_events/user_event_service_impl.h" #include "components/sync/user_events/user_event_sync_bridge.h" +#include "components/sync_sessions/session_sync_service.h" #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/sync/model_type_store_service_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" +#include "ios/chrome/browser/sync/session_sync_service_factory.h" #include "ios/chrome/common/channel_info.h" #include "ios/web/public/browser_state.h" @@ -41,6 +43,7 @@ "UserEventService", BrowserStateDependencyManager::GetInstance()) { DependsOn(ModelTypeStoreServiceFactory::GetInstance()); + DependsOn(SessionSyncServiceFactory::GetInstance()); } IOSUserEventServiceFactory::~IOSUserEventServiceFactory() {} @@ -66,7 +69,8 @@ std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( syncer::USER_EVENTS, /*dump_stack=*/base::BindRepeating( &syncer::ReportUnrecoverableError, ::GetChannel())), - sync_service->GetGlobalIdMapper()); + SessionSyncServiceFactory::GetForBrowserState(browser_state) + ->GetGlobalIdMapper()); return std::make_unique<syncer::UserEventServiceImpl>(sync_service, std::move(bridge)); }
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc index 8d2d3b1..b11737b 100644 --- a/ios/chrome/browser/sync/profile_sync_service_factory.cc +++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -34,6 +34,7 @@ #include "ios/chrome/browser/sync/consent_auditor_factory.h" #include "ios/chrome/browser/sync/ios_chrome_sync_client.h" #include "ios/chrome/browser/sync/model_type_store_service_factory.h" +#include "ios/chrome/browser/sync/session_sync_service_factory.h" #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h" #include "ios/chrome/browser/web_data_service_factory.h" #include "ios/chrome/common/channel_info.h" @@ -113,6 +114,7 @@ DependsOn(IOSChromeProfileInvalidationProviderFactory::GetInstance()); DependsOn(ModelTypeStoreServiceFactory::GetInstance()); DependsOn(ReadingListModelFactory::GetInstance()); + DependsOn(SessionSyncServiceFactory::GetInstance()); } ProfileSyncServiceFactory::~ProfileSyncServiceFactory() {}
diff --git a/ios/chrome/browser/sync/session_sync_service_factory.cc b/ios/chrome/browser/sync/session_sync_service_factory.cc new file mode 100644 index 0000000..bb4f64e --- /dev/null +++ b/ios/chrome/browser/sync/session_sync_service_factory.cc
@@ -0,0 +1,172 @@ +// 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 "ios/chrome/browser/sync/session_sync_service_factory.h" + +#include <utility> + +#include "base/memory/singleton.h" +#include "base/task/post_task.h" +#include "base/time/time.h" +#include "components/browser_sync/profile_sync_service.h" +#include "components/keyed_service/core/service_access_type.h" +#include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "components/sync/device_info/local_device_info_provider.h" +#include "components/sync/model/model_type_store_service.h" +#include "components/sync_sessions/local_session_event_router.h" +#include "components/sync_sessions/session_sync_prefs.h" +#include "components/sync_sessions/session_sync_service.h" +#include "components/sync_sessions/sync_sessions_client.h" +#include "components/sync_sessions/synced_window_delegates_getter.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/chrome_url_constants.h" +#include "ios/chrome/browser/favicon/favicon_service_factory.h" +#include "ios/chrome/browser/history/history_service_factory.h" +#include "ios/chrome/browser/sync/glue/sync_start_util.h" +#include "ios/chrome/browser/sync/model_type_store_service_factory.h" +#include "ios/chrome/browser/sync/profile_sync_service_factory.h" +#include "ios/chrome/browser/sync/sessions/ios_chrome_local_session_event_router.h" +#include "ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h" +#include "ios/chrome/common/channel_info.h" +#include "ios/web/public/web_thread.h" +#include "url/gurl.h" + +using sync_sessions::SessionSyncService; + +namespace { + +bool ShouldSyncURLImpl(const GURL& url) { + if (url == kChromeUIHistoryURL) { + // Whitelist the chrome history page, home for "Tabs from other devices", + // so it can trigger starting up the sync engine. + return true; + } + return url.is_valid() && !url.SchemeIs(kChromeUIScheme) && + !url.SchemeIsFile(); +} + +// iOS implementation of SyncSessionsClient. Needs to be in a separate class +// due to possible multiple inheritance issues, wherein IOSChromeSyncClient +// might inherit from other interfaces with same methods. +class SyncSessionsClientImpl : public sync_sessions::SyncSessionsClient { + public: + explicit SyncSessionsClientImpl(ios::ChromeBrowserState* browser_state) + : browser_state_(browser_state), + window_delegates_getter_( + std::make_unique<TabModelSyncedWindowDelegatesGetter>()), + local_session_event_router_( + std::make_unique<IOSChromeLocalSessionEventRouter>( + browser_state_, + this, + ios::sync_start_util::GetFlareForSyncableService( + browser_state_->GetStatePath()))), + session_sync_prefs_(browser_state->GetPrefs()) {} + + ~SyncSessionsClientImpl() override {} + + // SyncSessionsClient implementation. + favicon::FaviconService* GetFaviconService() override { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + return ios::FaviconServiceFactory::GetForBrowserState( + browser_state_, ServiceAccessType::IMPLICIT_ACCESS); + } + + history::HistoryService* GetHistoryService() override { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + return ios::HistoryServiceFactory::GetForBrowserState( + browser_state_, ServiceAccessType::EXPLICIT_ACCESS); + } + + sync_sessions::SessionSyncPrefs* GetSessionSyncPrefs() override { + return &session_sync_prefs_; + } + + syncer::RepeatingModelTypeStoreFactory GetStoreFactory() override { + return ModelTypeStoreServiceFactory::GetForBrowserState(browser_state_) + ->GetStoreFactory(); + } + + const syncer::DeviceInfo* GetLocalDeviceInfo() override { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + browser_sync::ProfileSyncService* profile_sync_service = + ProfileSyncServiceFactory::GetForBrowserStateIfExists(browser_state_); + if (!profile_sync_service) { + return nullptr; + } + return profile_sync_service->GetLocalDeviceInfoProvider() + ->GetLocalDeviceInfo(); + } + + bool ShouldSyncURL(const GURL& url) const override { + return ShouldSyncURLImpl(url); + } + + sync_sessions::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter() + override { + return window_delegates_getter_.get(); + } + + sync_sessions::LocalSessionEventRouter* GetLocalSessionEventRouter() + override { + return local_session_event_router_.get(); + } + + void NotifyForeignSessionUpdated() override { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + browser_sync::ProfileSyncService* profile_sync_service = + ProfileSyncServiceFactory::GetForBrowserStateIfExists(browser_state_); + if (profile_sync_service) { + profile_sync_service->NotifyForeignSessionUpdated(); + } + } + + private: + ios::ChromeBrowserState* const browser_state_; + const std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter> + window_delegates_getter_; + const std::unique_ptr<IOSChromeLocalSessionEventRouter> + local_session_event_router_; + sync_sessions::SessionSyncPrefs session_sync_prefs_; + + DISALLOW_COPY_AND_ASSIGN(SyncSessionsClientImpl); +}; + +} // namespace + +// static +SessionSyncServiceFactory* SessionSyncServiceFactory::GetInstance() { + return base::Singleton<SessionSyncServiceFactory>::get(); +} + +// static +bool SessionSyncServiceFactory::ShouldSyncURLForTesting(const GURL& url) { + return ShouldSyncURLImpl(url); +} + +// static +SessionSyncService* SessionSyncServiceFactory::GetForBrowserState( + ios::ChromeBrowserState* browser_state) { + return static_cast<SessionSyncService*>( + GetInstance()->GetServiceForBrowserState(browser_state, true)); +} + +SessionSyncServiceFactory::SessionSyncServiceFactory() + : BrowserStateKeyedServiceFactory( + "SessionSyncService", + BrowserStateDependencyManager::GetInstance()) { + DependsOn(ios::FaviconServiceFactory::GetInstance()); + DependsOn(ios::HistoryServiceFactory::GetInstance()); + DependsOn(ModelTypeStoreServiceFactory::GetInstance()); +} + +SessionSyncServiceFactory::~SessionSyncServiceFactory() {} + +std::unique_ptr<KeyedService> +SessionSyncServiceFactory::BuildServiceInstanceFor( + web::BrowserState* context) const { + ios::ChromeBrowserState* browser_state = + ios::ChromeBrowserState::FromBrowserState(context); + return std::make_unique<sync_sessions::SessionSyncService>( + ::GetChannel(), std::make_unique<SyncSessionsClientImpl>(browser_state)); +}
diff --git a/ios/chrome/browser/sync/session_sync_service_factory.h b/ios/chrome/browser/sync/session_sync_service_factory.h new file mode 100644 index 0000000..552fa15 --- /dev/null +++ b/ios/chrome/browser/sync/session_sync_service_factory.h
@@ -0,0 +1,52 @@ +// 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 IOS_CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_ +#define IOS_CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_ + +#include <memory> + +#include "base/macros.h" +#include "components/keyed_service/ios/browser_state_keyed_service_factory.h" + +class GURL; + +namespace base { +template <typename T> +struct DefaultSingletonTraits; +} // namespace base + +namespace sync_sessions { +class SessionSyncService; +} // namespace sync_sessions + +namespace ios { +class ChromeBrowserState; +} // namespace ios + +// Singleton that owns all SessionSyncService and associates them with +// ios::ChromeBrowserState. +class SessionSyncServiceFactory : public BrowserStateKeyedServiceFactory { + public: + static sync_sessions::SessionSyncService* GetForBrowserState( + ios::ChromeBrowserState* browser_state); + + static SessionSyncServiceFactory* GetInstance(); + + static bool ShouldSyncURLForTesting(const GURL& url); + + private: + friend struct base::DefaultSingletonTraits<SessionSyncServiceFactory>; + + SessionSyncServiceFactory(); + ~SessionSyncServiceFactory() override; + + // BrowserStateKeyedServiceFactory implementation. + std::unique_ptr<KeyedService> BuildServiceInstanceFor( + web::BrowserState* context) const override; + + DISALLOW_COPY_AND_ASSIGN(SessionSyncServiceFactory); +}; + +#endif // IOS_CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/sync/session_sync_service_factory_unittest.cc b/ios/chrome/browser/sync/session_sync_service_factory_unittest.cc new file mode 100644 index 0000000..d43dc1e --- /dev/null +++ b/ios/chrome/browser/sync/session_sync_service_factory_unittest.cc
@@ -0,0 +1,35 @@ +// 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 "ios/chrome/browser/sync/session_sync_service_factory.h" + +#include "ios/chrome/browser/chrome_url_constants.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace { + +const char kValidUrl[] = "http://www.example.com"; +const char kInvalidUrl[] = "invalid.url"; + +TEST(SessionSyncServiceFactoryTest, ShouldSyncURL) { + EXPECT_TRUE( + SessionSyncServiceFactory::ShouldSyncURLForTesting(GURL(kValidUrl))); + EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL("other://anything"))); + EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL("chrome-other://anything"))); + + EXPECT_FALSE( + SessionSyncServiceFactory::ShouldSyncURLForTesting(GURL(kInvalidUrl))); + EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL("file://anything"))); + EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL("chrome://anything"))); + + EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting( + GURL(kChromeUIHistoryURL))); +} + +} // namespace
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm index 129c6658..934e7a0 100644 --- a/ios/chrome/browser/tabs/tab.mm +++ b/ios/chrome/browser/tabs/tab.mm
@@ -100,6 +100,7 @@ #include "net/cert/x509_certificate.h" #include "net/http/http_response_headers.h" #include "net/url_request/url_fetcher.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/page_transition_types.h" #include "url/origin.h" @@ -462,8 +463,8 @@ - (OpenInController*)openInController { if (!_openInController) { _openInController = [[OpenInController alloc] - initWithRequestContext:_browserState->GetRequestContext() - webController:self.webController]; + initWithURLLoaderFactory:_browserState->GetSharedURLLoaderFactory() + webController:self.webController]; _openInController.baseView = self.view; } return _openInController;
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm index 3caf654..6c82084 100644 --- a/ios/chrome/browser/tabs/tab_model_unittest.mm +++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -7,6 +7,7 @@ #include "base/files/file_path.h" #include "base/run_loop.h" #include "base/strings/sys_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h" #include "ios/chrome/browser/chrome_url_constants.h" @@ -29,6 +30,7 @@ #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h" #import "ios/web/navigation/navigation_manager_impl.h" #import "ios/web/public/crw_session_storage.h" +#include "ios/web/public/features.h" #import "ios/web/public/navigation_manager.h" #include "ios/web/public/referrer.h" #import "ios/web/public/serializable_user_data_manager.h" @@ -72,7 +74,16 @@ const char kURL1[] = "https://www.some.url.com"; const char kURL2[] = "https://www.some.url2.com"; -class TabModelTest : public PlatformTest { +// TabModelTest is parameterized on this enum to test both +// LegacyNavigationManager and WKBasedNavigationManager. +enum class NavigationManagerChoice { + LEGACY, + WK_BASED, +}; + +class TabModelTest + : public PlatformTest, + public ::testing::WithParamInterface<NavigationManagerChoice> { public: TabModelTest() : scoped_browser_state_manager_( @@ -80,6 +91,14 @@ web_client_(std::make_unique<ChromeWebClient>()) { DCHECK_CURRENTLY_ON(web::WebThread::UI); + if (GetParam() == NavigationManagerChoice::LEGACY) { + scoped_feature_list_.InitAndDisableFeature( + web::features::kSlimNavigationManager); + } else { + scoped_feature_list_.InitAndEnableFeature( + web::features::kSlimNavigationManager); + } + TestChromeBrowserState::Builder test_cbs_builder; chrome_browser_state_ = test_cbs_builder.Build(); @@ -147,9 +166,10 @@ std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; WebStateListWebUsageEnabler* web_usage_enabler_; TabModel* tab_model_; + base::test::ScopedFeatureList scoped_feature_list_; }; -TEST_F(TabModelTest, IsEmpty) { +TEST_P(TabModelTest, IsEmpty) { EXPECT_EQ([tab_model_ count], 0U); EXPECT_TRUE([tab_model_ isEmpty]); [tab_model_ insertTabWithURL:GURL(kURL1) @@ -163,7 +183,7 @@ EXPECT_FALSE([tab_model_ isEmpty]); } -TEST_F(TabModelTest, InsertUrlSingle) { +TEST_P(TabModelTest, InsertUrlSingle) { Tab* tab = [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -175,7 +195,7 @@ EXPECT_NSEQ(tab, [tab_model_ tabAtIndex:0]); } -TEST_F(TabModelTest, InsertUrlMultiple) { +TEST_P(TabModelTest, InsertUrlMultiple) { Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -204,7 +224,7 @@ EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:2]); } -TEST_F(TabModelTest, AppendUrlSingle) { +TEST_P(TabModelTest, AppendUrlSingle) { Tab* tab = [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -216,7 +236,7 @@ EXPECT_NSEQ(tab, [tab_model_ tabAtIndex:0]); } -TEST_F(TabModelTest, AppendUrlMultiple) { +TEST_P(TabModelTest, AppendUrlMultiple) { Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -245,7 +265,7 @@ EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:2]); } -TEST_F(TabModelTest, CloseTabAtIndexBeginning) { +TEST_P(TabModelTest, CloseTabAtIndexBeginning) { [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -275,7 +295,7 @@ EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]); } -TEST_F(TabModelTest, CloseTabAtIndexMiddle) { +TEST_P(TabModelTest, CloseTabAtIndexMiddle) { Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -305,7 +325,7 @@ EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]); } -TEST_F(TabModelTest, CloseTabAtIndexLast) { +TEST_P(TabModelTest, CloseTabAtIndexLast) { Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -335,7 +355,7 @@ EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:1]); } -TEST_F(TabModelTest, CloseTabAtIndexOnlyOne) { +TEST_P(TabModelTest, CloseTabAtIndexOnlyOne) { [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -349,7 +369,12 @@ EXPECT_EQ(0U, [tab_model_ count]); } -TEST_F(TabModelTest, RestoreSessionOnNTPTest) { +TEST_P(TabModelTest, RestoreSessionOnNTPTest) { + // TODO(crbug.com/888674): migrate this to EG test so it can be tested with + // WKBasedNavigationManager. + if (web_client_.Get()->IsSlimNavigationManagerEnabled()) + return; + Tab* tab = [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -370,7 +395,12 @@ EXPECT_NSNE(tab, [tab_model_ tabAtIndex:2]); } -TEST_F(TabModelTest, RestoreSessionOn2NtpTest) { +TEST_P(TabModelTest, RestoreSessionOn2NtpTest) { + // TODO(crbug.com/888674): migrate this to EG test so it can be tested with + // WKBasedNavigationManager. + if (web_client_.Get()->IsSlimNavigationManagerEnabled()) + return; + Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -405,7 +435,12 @@ EXPECT_NSNE(tab1, [tab_model_ tabAtIndex:4]); } -TEST_F(TabModelTest, RestoreSessionOnAnyTest) { +TEST_P(TabModelTest, RestoreSessionOnAnyTest) { + // TODO(crbug.com/888674): migrate this to EG test so it can be tested with + // WKBasedNavigationManager. + if (web_client_.Get()->IsSlimNavigationManagerEnabled()) + return; + Tab* tab = [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -427,7 +462,7 @@ EXPECT_NSNE(tab, [tab_model_ tabAtIndex:3]); } -TEST_F(TabModelTest, CloseAllTabs) { +TEST_P(TabModelTest, CloseAllTabs) { [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -455,13 +490,13 @@ EXPECT_EQ(0U, [tab_model_ count]); } -TEST_F(TabModelTest, CloseAllTabsWithNoTabs) { +TEST_P(TabModelTest, CloseAllTabsWithNoTabs) { [tab_model_ closeAllTabs]; EXPECT_EQ(0U, [tab_model_ count]); } -TEST_F(TabModelTest, InsertWithSessionController) { +TEST_P(TabModelTest, InsertWithSessionController) { EXPECT_EQ([tab_model_ count], 0U); EXPECT_TRUE([tab_model_ isEmpty]); @@ -479,7 +514,7 @@ EXPECT_TRUE(current_tab); } -TEST_F(TabModelTest, AddWithOrderController) { +TEST_P(TabModelTest, AddWithOrderController) { // Create a few tabs with the controller at the front. Tab* parent = [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() @@ -559,7 +594,7 @@ EXPECT_EQ([tab_model_ indexOfTab:tab4], [tab_model_ indexOfTab:tab3] + 1); } -TEST_F(TabModelTest, MoveTabs) { +TEST_P(TabModelTest, MoveTabs) { Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1) referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED @@ -643,7 +678,7 @@ [tab_model_ removeObserver:tab_model_observer]; } -TEST_F(TabModelTest, ParentTabModel) { +TEST_P(TabModelTest, ParentTabModel) { std::unique_ptr<web::WebState> web_state = web::WebState::Create( web::WebState::CreateParams(chrome_browser_state_.get())); AttachTabHelpers(web_state.get(), /*for_prerender=*/false); @@ -657,7 +692,7 @@ EXPECT_NSEQ(tab_model_, [tab parentTabModel]); } -TEST_F(TabModelTest, TabCreatedOnInsertion) { +TEST_P(TabModelTest, TabCreatedOnInsertion) { std::unique_ptr<web::WebState> web_state = web::WebState::Create( web::WebState::CreateParams(chrome_browser_state_.get())); @@ -670,7 +705,7 @@ EXPECT_NSNE(nil, LegacyTabHelper::GetTabForWebState(web_state_ptr)); } -TEST_F(TabModelTest, PersistSelectionChange) { +TEST_P(TabModelTest, PersistSelectionChange) { NSString* stashPath = base::SysUTF8ToNSString(chrome_browser_state_->GetStatePath().value()); @@ -729,4 +764,9 @@ error:nullptr]); } +INSTANTIATE_TEST_CASE_P(ProgrammaticTabModelTest, + TabModelTest, + ::testing::Values(NavigationManagerChoice::LEGACY, + NavigationManagerChoice::WK_BASED)); + } // anonymous namespace
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn index 12d09e83..d9f651b 100644 --- a/ios/chrome/browser/ui/BUILD.gn +++ b/ios/chrome/browser/ui/BUILD.gn
@@ -156,6 +156,7 @@ "//ios/web/public/test/fakes", "//net", "//net:test_support", + "//services/network:test_support", "//testing/gmock", "//testing/gtest", "//third_party/ocmock", @@ -369,7 +370,6 @@ "//ios/chrome/browser/ui/history", "//ios/chrome/browser/ui/image_util", "//ios/chrome/browser/ui/keyboard", - "//ios/chrome/browser/ui/main:feature_flags", "//ios/chrome/browser/ui/main:tab_switcher", "//ios/chrome/browser/ui/main_content:main_content_ui", "//ios/chrome/browser/ui/main_content:main_content_ui_broadcasting_util",
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm index 55ab424..e527160 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm
@@ -9,6 +9,7 @@ #import "ios/chrome/browser/autofill/form_input_accessory_view_controller.h" #import "ios/chrome/browser/ui/autofill/form_input_accessory_mediator.h" #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h" +#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h" #import "ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -30,6 +31,11 @@ @property(nonatomic, strong) ManualFillAccessoryViewController* manualFillAccessoryViewController; +// The object in charge of interacting with the web view. Used to fill the data +// in the forms. +@property(nonatomic, strong) + ManualFillInjectionHandler* manualFillInjectionHandler; + // The WebStateList for this instance. Used to instantiate the child // coordinators lazily. @property(nonatomic, assign) WebStateList* webStateList; @@ -44,6 +50,7 @@ @synthesize manualFillAccessoryViewController = _manualFillAccessoryViewController; @synthesize webStateList = _webStateList; +@synthesize manualFillInjectionHandler = _manualFillInjectionHandler; - (instancetype)initWithBaseViewController:(UIViewController*)viewController browserState: @@ -56,6 +63,9 @@ if (self) { _webStateList = webStateList; + _manualFillInjectionHandler = + [[ManualFillInjectionHandler alloc] initWithWebStateList:webStateList]; + _formInputAccessoryViewController = [[FormInputAccessoryViewController alloc] init]; @@ -91,7 +101,8 @@ [[ManualFillPasswordCoordinator alloc] initWithBaseViewController:self.baseViewController browserState:self.browserState - webStateList:self.webStateList]; + webStateList:self.webStateList + injectionHandler:self.manualFillInjectionHandler]; [self.formInputAccessoryViewController presentView:passwordCoordinator.viewController.view]; [self.childCoordinators addObject:passwordCoordinator];
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn index 63ebd30..056cd39b 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn +++ b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
@@ -8,6 +8,8 @@ sources = [ "credential_password_form.h", "credential_password_form.mm", + "form_observer_helper.h", + "form_observer_helper.mm", "manual_fill_injection_handler.h", "manual_fill_injection_handler.mm", "password_coordinator.h", @@ -19,6 +21,7 @@ "//base", "//components/autofill/core/common", "//components/autofill/ios/browser", + "//components/autofill/ios/form_util", "//components/keyed_service/core:core", "//components/password_manager/core/browser", "//ios/chrome/app/strings:ios_strings_grit", @@ -83,13 +86,20 @@ sources = [ "credential_password_form_unittest.mm", "credential_unittest.mm", + "form_observer_helper_unittest.mm", ] deps = [ ":manual_fill", ":manual_fill_ui", "//base:base", "//components/autofill/core/common:common", + "//components/autofill/ios/form_util:form_util", + "//components/autofill/ios/form_util:test_support", + "//ios/chrome/browser/web_state_list:test_support", + "//ios/chrome/browser/web_state_list:web_state_list", + "//ios/web/public/test/fakes:fakes", "//testing/gtest:gtest", + "//third_party/ocmock:ocmock", "//url:url", ] }
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h new file mode 100644 index 0000000..60e4f928 --- /dev/null +++ b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h
@@ -0,0 +1,28 @@ +// 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 IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_FORM_OBSERVER_HELPER_H_ +#define IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_FORM_OBSERVER_HELPER_H_ + +#import <Foundation/Foundation.h> + +@protocol FormActivityObserver; +class WebStateList; + +// Convenience object to observe updates in forms. It abstracts all the logic +// to observe a web state list and its web states. +@interface FormObserverHelper : NSObject + +// The delegate interested in the form activity. +@property(nonatomic, weak) id<FormActivityObserver> delegate; + +// Returns a fresh object observing the active web state for the passed list. +- (instancetype)initWithWebStateList:(WebStateList*)webStateList; + +// Not available. Use |initWithWebStateList:|. +- (instancetype)init NS_UNAVAILABLE; + +@end + +#endif // IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_FORM_OBSERVER_HELPER_H_
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm new file mode 100644 index 0000000..6d9026c --- /dev/null +++ b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm
@@ -0,0 +1,125 @@ +// 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. + +#import "ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h" + +#import "components/autofill/ios/form_util/form_activity_observer_bridge.h" +#import "ios/chrome/browser/web_state_list/web_state_list.h" +#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h" +#include "ios/web/public/web_state/web_state.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface FormObserverHelper ()<FormActivityObserver, WebStateListObserving> +// The WebStateList this instance is observing in order to update the +// active WebState. +@property(nonatomic, assign) WebStateList* webStateList; + +// The WebState this instance is observing. Can be nullptr. +@property(nonatomic, assign) web::WebState* webState; + +@end + +@implementation FormObserverHelper { + // Bridge to observe the web state list from Objective-C. + std::unique_ptr<WebStateListObserverBridge> _webStateListObserver; + + // Bridge to observe form activity in |_webState|. + std::unique_ptr<autofill::FormActivityObserverBridge> + _formActivityObserverBridge; +} + +@synthesize delegate = _delegate; + +- (instancetype)initWithWebStateList:(WebStateList*)webStateList { + DCHECK(webStateList); + self = [super init]; + if (self) { + _webStateList = webStateList; + _webStateListObserver = std::make_unique<WebStateListObserverBridge>(self); + _webStateList->AddObserver(_webStateListObserver.get()); + web::WebState* webState = webStateList->GetActiveWebState(); + if (webState) { + _webState = webState; + _formActivityObserverBridge = + std::make_unique<autofill::FormActivityObserverBridge>(_webState, + self); + } + } + return self; +} + +- (void)dealloc { + if (_webState) { + _formActivityObserverBridge.reset(); + _webState = nullptr; + } + if (_webStateList) { + _webStateList->RemoveObserver(_webStateListObserver.get()); + _webStateListObserver.reset(); + _webStateList = nullptr; + } + _formActivityObserverBridge.reset(); +} + +#pragma mark - FormActivityObserver + +- (void)webState:(web::WebState*)webState + didRegisterFormActivity:(const autofill::FormActivityParams&)params + inFrame:(web::WebFrame*)frame { + if ([self.delegate respondsToSelector:@selector + (webState:didRegisterFormActivity:inFrame:)]) { + [self.delegate webState:webState + didRegisterFormActivity:params + inFrame:frame]; + } +} + +- (void)webState:(web::WebState*)webState + didSubmitDocumentWithFormNamed:(const std::string&)formName + withData:(const std::string&)formData + hasUserGesture:(BOOL)hasUserGesture + formInMainFrame:(BOOL)formInMainFrame + inFrame:(web::WebFrame*)frame { + if ([self.delegate respondsToSelector:@selector + (webState:didSubmitDocumentWithFormNamed:withData + :hasUserGesture:formInMainFrame:inFrame:)]) { + [self.delegate webState:webState + didSubmitDocumentWithFormNamed:formName + withData:formData + hasUserGesture:hasUserGesture + formInMainFrame:formInMainFrame + inFrame:frame]; + } +} + +#pragma mark - CRWWebStateListObserver + +- (void)webStateList:(WebStateList*)webStateList + didChangeActiveWebState:(web::WebState*)newWebState + oldWebState:(web::WebState*)oldWebState + atIndex:(int)atIndex + reason:(int)reason { + self.webState = newWebState; +} + +#pragma mark - Setters + +// Sets the new web state and detaches from the previous web state. +- (void)setWebState:(web::WebState*)webState { + if (_webState) { + _formActivityObserverBridge.reset(); + } + + _webState = webState; + + if (_webState) { + _formActivityObserverBridge = + std::make_unique<autofill::FormActivityObserverBridge>(_webState, self); + } +} + +@end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper_unittest.mm b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper_unittest.mm new file mode 100644 index 0000000..3d7c609e --- /dev/null +++ b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper_unittest.mm
@@ -0,0 +1,154 @@ +// 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. + +#import "ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h" + +#import "components/autofill/ios/form_util/form_activity_observer_bridge.h" +#include "components/autofill/ios/form_util/form_activity_params.h" +#include "components/autofill/ios/form_util/test_form_activity_tab_helper.h" +#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h" +#import "ios/chrome/browser/web_state_list/web_state_list.h" +#import "ios/chrome/browser/web_state_list/web_state_opener.h" +#import "ios/web/public/test/fakes/test_web_state.h" +#include "testing/platform_test.h" +#import "third_party/ocmock/OCMock/OCMock.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +class ManualFillFormObserverHelperiOSTest : public PlatformTest { + public: + ManualFillFormObserverHelperiOSTest() + : web_state_list_(&web_state_list_delegate_) {} + + ~ManualFillFormObserverHelperiOSTest() override {} + + void SetUp() override { + PlatformTest::SetUp(); + _helper = + [[FormObserverHelper alloc] initWithWebStateList:&web_state_list_]; + _mockDelegate = OCMProtocolMock(@protocol(FormActivityObserver)); + _helper.delegate = _mockDelegate; + } + + void TearDown() override { + _helper = nil; + _mockDelegate = nil; + PlatformTest::TearDown(); + } + + protected: + FakeWebStateListDelegate web_state_list_delegate_; + WebStateList web_state_list_; + FormObserverHelper* _helper; + OCMockObject<FormActivityObserver>* _mockDelegate; + + std::unique_ptr<web::TestWebState> CreateWebState(const char* url) { + auto test_web_state = std::make_unique<web::TestWebState>(); + test_web_state->SetCurrentURL(GURL(url)); + return test_web_state; + } + + void AppendNewWebState(const char* url) { + AppendNewWebState(url, WebStateOpener()); + } + + void AppendNewWebState(const char* url, WebStateOpener opener) { + web_state_list_.InsertWebState(WebStateList::kInvalidIndex, + CreateWebState(url), + WebStateList::INSERT_NO_FLAGS, opener); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ManualFillFormObserverHelperiOSTest); +}; + +// Tests that an observer is correctly created and set up. +TEST_F(ManualFillFormObserverHelperiOSTest, Creation) {} + +// Test that the observer delegates one active web state callbacks. +TEST_F(ManualFillFormObserverHelperiOSTest, ObservesWebState) { + AppendNewWebState("https://example.com"); + web_state_list_.ActivateWebStateAt(0); + + autofill::FormActivityParams params; + params.form_name = "form"; + params.field_name = "field"; + params.field_identifier = "field_id"; + params.field_type = "text"; + params.type = "blur"; + params.value = "value"; + params.input_missing = false; + + OCMExpect([_mockDelegate + webState:static_cast<web::WebState*>([OCMArg anyPointer]) + didRegisterFormActivity:params + inFrame:static_cast<web::WebFrame*>( + [OCMArg anyPointer])]); + + autofill::TestFormActivityTabHelper test_form_activity_tab_helper( + web_state_list_.GetActiveWebState()); + test_form_activity_tab_helper.FormActivityRegistered(nullptr, params); + @try { + [_mockDelegate verify]; + } @catch (NSException* exception) { + ADD_FAILURE(); + } +} + +// Test that the observer delegates the callbacks with multiple active web +// state. +TEST_F(ManualFillFormObserverHelperiOSTest, ObservesMultipleWebStates) { + AppendNewWebState("https://example.com"); + AppendNewWebState("https://chrome.com"); + + autofill::TestFormActivityTabHelper test_form_activity_tab_helper0( + web_state_list_.GetWebStateAt(0)); + autofill::TestFormActivityTabHelper test_form_activity_tab_helper1( + web_state_list_.GetWebStateAt(1)); + + web_state_list_.ActivateWebStateAt(0); + + autofill::FormActivityParams params; + params.form_name = "form"; + params.field_name = "field"; + params.field_identifier = "field_id"; + params.field_type = "text"; + params.type = "focus"; + params.value = "value"; + params.input_missing = false; + + @try { + OCMExpect([_mockDelegate + webState:static_cast<web::WebState*>([OCMArg anyPointer]) + didRegisterFormActivity:params + inFrame:static_cast<web::WebFrame*>( + [OCMArg anyPointer])]); + + test_form_activity_tab_helper0.FormActivityRegistered(nullptr, params); + [_mockDelegate verify]; + + web_state_list_.ActivateWebStateAt(1); + + OCMExpect([_mockDelegate + webState:static_cast<web::WebState*>([OCMArg anyPointer]) + didRegisterFormActivity:params + inFrame:static_cast<web::WebFrame*>( + [OCMArg anyPointer])]); + test_form_activity_tab_helper1.FormActivityRegistered(nullptr, params); + [_mockDelegate verify]; + + web_state_list_.ActivateWebStateAt(0); + OCMExpect([_mockDelegate + webState:static_cast<web::WebState*>([OCMArg anyPointer]) + didRegisterFormActivity:params + inFrame:static_cast<web::WebFrame*>( + [OCMArg anyPointer])]); + test_form_activity_tab_helper0.FormActivityRegistered(nullptr, params); + [_mockDelegate verify]; + } @catch (NSException* exception) { + ADD_FAILURE(); + } +}
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm index 791db91..6d1c7e5 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm
@@ -6,47 +6,75 @@ #include "base/mac/foundation_util.h" #import "components/autofill/ios/browser/js_suggestion_manager.h" +#import "components/autofill/ios/form_util/form_activity_observer_bridge.h" +#include "components/autofill/ios/form_util/form_activity_params.h" #import "ios/chrome/browser/autofill/form_input_accessory_view_handler.h" +#import "ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" #include "ios/web/public/web_state/web_state.h" +#include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -@interface ManualFillInjectionHandler () -// The WebStateList with the relevant active web state for the injection. -@property(nonatomic, assign) WebStateList* webStateList; +@interface ManualFillInjectionHandler ()<FormActivityObserver> +// The object in charge of listening to form events and reporting back. +@property(nonatomic, strong) FormObserverHelper* formHelper; // Convenience getter for the current injection reciever. @property(nonatomic, readonly) CRWJSInjectionReceiver* injectionReceiver; // Convenience getter for the current suggestion manager. @property(nonatomic, readonly) JsSuggestionManager* suggestionManager; +// The WebStateList with the relevant active web state for the injection. +@property(nonatomic, assign) WebStateList* webStateList; +// YES if the last focused element is secure within its web frame. To be secure +// means it has a password type, the web is https and the URL can trusted. +@property(nonatomic, assign) BOOL lastActiveElementIsSecure; @end @implementation ManualFillInjectionHandler - +@synthesize formHelper = _formHelper; +@synthesize lastActiveElementIsSecure = _lastActiveElementIsSecure; @synthesize webStateList = _webStateList; - (instancetype)initWithWebStateList:(WebStateList*)webStateList { self = [super init]; if (self) { _webStateList = webStateList; + _formHelper = + [[FormObserverHelper alloc] initWithWebStateList:webStateList]; + _formHelper.delegate = self; } return self; } - #pragma mark - ManualFillViewDelegate - (void)userDidPickContent:(NSString*)content isSecure:(BOOL)isSecure { - if (isSecure) { - // TODO:(https://crbug.com/878388) implement secure manual fill for - // passwords. + if (isSecure && !self.lastActiveElementIsSecure) { return; } [self fillLastSelectedFieldWithString:content]; } +#pragma mark - FormActivityObserver + +- (void)webState:(web::WebState*)webState + didRegisterFormActivity:(const autofill::FormActivityParams&)params + inFrame:(web::WebFrame*)frame { + if (params.type != "focus") { + return; + } + web::URLVerificationTrustLevel trustLevel; + const GURL pageURL(webState->GetCurrentURL(&trustLevel)); + self.lastActiveElementIsSecure = YES; + if (trustLevel != web::URLVerificationTrustLevel::kAbsolute || + !pageURL.SchemeIs(url::kHttpsScheme) || !webState->ContentIsHTML() || + params.field_type != "password") { + self.lastActiveElementIsSecure = NO; + } +} + #pragma mark - Getters - (CRWJSInjectionReceiver*)injectionReceiver {
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h index b6f2d7b..3f4ca71 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h
@@ -7,6 +7,7 @@ #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" +@class ManualFillInjectionHandler; class WebStateList; // Creates and manages a view controller to present passwords to the user. @@ -17,12 +18,13 @@ // The view controller of this coordinator. @property(nonatomic, readonly) UIViewController* viewController; -// Creates a coordinator that uses a |viewController| a |browserState| and -// a |webStateList|. -- (instancetype)initWithBaseViewController:(UIViewController*)viewController - browserState: - (ios::ChromeBrowserState*)browserState - webStateList:(WebStateList*)webStateList; +// Creates a coordinator that uses a |viewController|, |browserState|, +// |webStateList| and an |injectionHandler|. +- (instancetype) +initWithBaseViewController:(UIViewController*)viewController + browserState:(ios::ChromeBrowserState*)browserState + webStateList:(WebStateList*)webStateList + injectionHandler:(ManualFillInjectionHandler*)injectionHandler; // Unavailable, use -initWithBaseViewController:browserState:webStateList:. - (instancetype)initWithBaseViewController:(UIViewController*)viewController
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm index b40d5d5..ab89d264 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm
@@ -39,22 +39,22 @@ @implementation ManualFillPasswordCoordinator @synthesize allPasswordsViewController = _allPasswordsViewController; +@synthesize manualFillInjectionHandler = _manualFillInjectionHandler; @synthesize passwordMediator = _passwordMediator; @synthesize passwordViewController = _passwordViewController; -@synthesize manualFillInjectionHandler = _manualFillInjectionHandler; -- (instancetype)initWithBaseViewController:(UIViewController*)viewController - browserState: - (ios::ChromeBrowserState*)browserState - webStateList:(WebStateList*)webStateList { +- (instancetype) +initWithBaseViewController:(UIViewController*)viewController + browserState:(ios::ChromeBrowserState*)browserState + webStateList:(WebStateList*)webStateList + injectionHandler:(ManualFillInjectionHandler*)injectionHandler { self = [super initWithBaseViewController:viewController browserState:browserState]; if (self) { _passwordViewController = [[PasswordViewController alloc] initWithSearchController:nil]; - _manualFillInjectionHandler = - [[ManualFillInjectionHandler alloc] initWithWebStateList:webStateList]; + _manualFillInjectionHandler = injectionHandler; auto passwordStore = IOSChromePasswordStoreFactory::GetForBrowserState( browserState, ServiceAccessType::EXPLICIT_ACCESS);
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn index 94b17ba6..f3b50cf 100644 --- a/ios/chrome/browser/ui/bookmarks/BUILD.gn +++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -105,7 +105,6 @@ "//ios/chrome/browser/ui/image_util", "//ios/chrome/browser/ui/keyboard", "//ios/chrome/browser/ui/list_model", - "//ios/chrome/browser/ui/main:feature_flags", "//ios/chrome/browser/ui/material_components", "//ios/chrome/browser/ui/ntp", "//ios/chrome/browser/ui/signin_interaction/public",
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index af19d18a..6e57b50b 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -162,7 +162,6 @@ #import "ios/chrome/browser/ui/image_util/image_saver.h" #import "ios/chrome/browser/ui/key_commands_provider.h" #import "ios/chrome/browser/ui/location_bar_notification_names.h" -#import "ios/chrome/browser/ui/main/main_feature_flags.h" #import "ios/chrome/browser/ui/main_content/main_content_ui.h" #import "ios/chrome/browser/ui/main_content/main_content_ui_broadcasting_util.h" #import "ios/chrome/browser/ui/main_content/main_content_ui_state.h" @@ -1442,13 +1441,11 @@ }; [self setLastTapPointFromCommand:originPoint]; - // When the tab switcher presentation experiment is enabled, the new tab can - // be opened before BVC has been made visible onscreen. Test for this case by - // checking if the parent container VC is currently in the process of being - // presented. + // The new tab can be opened before BVC has been made visible onscreen. Test + // for this case by checking if the parent container VC is currently in the + // process of being presented. DCHECK(self.visible || self.dismissingModal || - (TabSwitcherPresentsBVCEnabled() && - self.parentViewController.isBeingPresented)); + self.parentViewController.isBeingPresented); // In most cases, we want to take a snapshot of the current tab before opening // a new tab. However, if the current tab is not fully visible (did not finish @@ -1565,7 +1562,7 @@ // // To ensure the completion is called, nil is passed to the call to dismiss, // and the completion is called explicitly below. - if (!TabSwitcherPresentsBVCEnabled() || !self.dismissingModal) { + if (!self.dismissingModal) { [self dismissViewControllerAnimated:NO completion:nil]; } // Dismissed controllers will be so after a delay. Queue the completion @@ -1911,7 +1908,7 @@ - (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)())completion { - if (TabSwitcherPresentsBVCEnabled() && !self.presentedViewController) { + if (!self.presentedViewController) { // TODO(crbug.com/801165): On iOS10, UIDocumentMenuViewController and // WKFileUploadPanel somehow combine to call dismiss twice instead of once. // The second call would dismiss the BVC itself, so look for that case and @@ -1928,16 +1925,13 @@ } // Some calling code invokes |dismissViewControllerAnimated:completion:| - // multiple times. When the BVC is displayed using VC containment, multiple - // calls are effectively idempotent because only the first call has any effect - // and subsequent calls do nothing. However, when the BVC is presented, - // subsequent calls end up dismissing the BVC itself. This is never what we - // want, so check for this case and return early. It is not enough to check + // multiple times. Because the BVC is presented, subsequent calls end up + // dismissing the BVC itself. This is never what should happen, so check for + // this case and return early. It is not enough to check // |self.dismissingModal| because some dismissals do not go through // -[BrowserViewController dismissViewControllerAnimated:completion:|. // TODO(crbug.com/782338): Fix callers and remove this early return. - if (TabSwitcherPresentsBVCEnabled() && - (self.dismissingModal || self.presentedViewController.isBeingDismissed)) { + if (self.dismissingModal || self.presentedViewController.isBeingDismissed) { return; }
diff --git a/ios/chrome/browser/ui/collection_view/collection_view_controller.mm b/ios/chrome/browser/ui/collection_view/collection_view_controller.mm index ac2f8f3..f933dd8 100644 --- a/ios/chrome/browser/ui/collection_view/collection_view_controller.mm +++ b/ios/chrome/browser/ui/collection_view/collection_view_controller.mm
@@ -45,6 +45,12 @@ self.collectionView; // After all other views have been registered. [self addChildViewController:_appBarViewController]; + // Match the width of the parent view. + CGRect frame = self.appBarViewController.view.frame; + frame.origin.x = 0; + frame.size.width = + self.appBarViewController.parentViewController.view.bounds.size.width; + self.appBarViewController.view.frame = frame; [self.view addSubview:self.appBarViewController.view]; [self.appBarViewController didMoveToParentViewController:self]; }
diff --git a/ios/chrome/browser/ui/commands/application_commands.h b/ios/chrome/browser/ui/commands/application_commands.h index 4c82ecf..0d3cd20 100644 --- a/ios/chrome/browser/ui/commands/application_commands.h +++ b/ios/chrome/browser/ui/commands/application_commands.h
@@ -79,10 +79,6 @@ // Shows the TabSwitcher UI. - (void)displayTabSwitcher; -// Shows the Clear Browsing Data Settings UI (part of Settings). -- (void)showClearBrowsingDataSettingsFromViewController: - (UIViewController*)baseViewController; - // TODO(crbug.com/779791) : Do not pass baseViewController through dispatcher. // Shows the Autofill Settings UI, presenting from |baseViewController|. - (void)showAutofillSettingsFromViewController:
diff --git a/ios/chrome/browser/ui/first_run/static_file_view_controller.mm b/ios/chrome/browser/ui/first_run/static_file_view_controller.mm index 25f33a0..e241e306 100644 --- a/ios/chrome/browser/ui/first_run/static_file_view_controller.mm +++ b/ios/chrome/browser/ui/first_run/static_file_view_controller.mm
@@ -83,6 +83,12 @@ // Add the app bar at the end. [self addChildViewController:_appBarViewController]; + // Match the width of the parent view. + CGRect frame = _appBarViewController.view.frame; + frame.origin.x = 0; + frame.size.width = + _appBarViewController.parentViewController.view.bounds.size.width; + _appBarViewController.view.frame = frame; [self.view addSubview:_appBarViewController.view]; [_appBarViewController didMoveToParentViewController:self];
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn index 5dc33c6..24ca9b3 100644 --- a/ios/chrome/browser/ui/history/BUILD.gn +++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -5,80 +5,28 @@ source_set("history") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "clear_browsing_bar.h", - "clear_browsing_bar.mm", - "favicon_view.h", - "favicon_view.mm", - "favicon_view_provider.h", - "favicon_view_provider.mm", "history_coordinator.h", "history_coordinator.mm", "history_mediator.h", "history_mediator.mm", - "history_panel_view_controller.h", - "history_panel_view_controller.mm", - "history_search_view.h", - "history_search_view.mm", - "history_search_view_controller.h", - "history_search_view_controller.mm", "ios_browsing_history_driver.h", "ios_browsing_history_driver.mm", - "legacy_history_collection_view_controller.h", - "legacy_history_collection_view_controller.mm", - "legacy_history_entries_status_item.h", - "legacy_history_entries_status_item.mm", - "legacy_history_entry_item.h", - "legacy_history_entry_item.mm", ] deps = [ ":clear_browsing_data", - ":feature_flags", ":history_ui", "//base", - "//base:i18n", "//components/browser_sync", "//components/browsing_data/core", - "//components/favicon/core", - "//components/favicon_base", "//components/history/core/browser", "//components/keyed_service/core", - "//components/prefs", - "//components/query_parser", - "//components/strings", - "//components/sync/protocol", - "//components/url_formatter", - "//ios/chrome/app/strings", - "//ios/chrome/browser", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/favicon", "//ios/chrome/browser/history", - "//ios/chrome/browser/metrics:metrics_internal", - "//ios/chrome/browser/signin", "//ios/chrome/browser/sync", "//ios/chrome/browser/ui", - "//ios/chrome/browser/ui/collection_view", - "//ios/chrome/browser/ui/colors", - "//ios/chrome/browser/ui/commands", - "//ios/chrome/browser/ui/context_menu", "//ios/chrome/browser/ui/coordinators:chrome_coordinators", - "//ios/chrome/browser/ui/icons", - "//ios/chrome/browser/ui/keyboard", - "//ios/chrome/browser/ui/list_model", - "//ios/chrome/browser/ui/material_components", - "//ios/chrome/browser/ui/ntp/recent_tabs/views", - "//ios/chrome/browser/ui/popup_menu", - "//ios/chrome/browser/ui/settings", "//ios/chrome/browser/ui/table_view", - "//ios/chrome/browser/ui/table_view/cells", - "//ios/chrome/browser/ui/util", - "//ios/chrome/common", - "//ios/third_party/material_components_ios", - "//ios/third_party/material_roboto_font_loader_ios", - "//ios/web", - "//net", - "//skia", - "//ui/base", - "//url", ] libs = [ "MobileCoreServices.framework", @@ -161,80 +109,22 @@ ] } -source_set("feature_flags") { - configs += [ "//build/config/compiler:enable_arc" ] - sources = [ - "features.cc", - "features.h", - ] - deps = [ - "//base", - ] -} - source_set("unit_tests") { configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ - "favicon_view_provider_unittest.mm", "history_entry_inserter_unittest.mm", - "history_search_view_controller_unittest.mm", - "legacy_history_entries_status_item_unittest.mm", - "legacy_history_entry_item_unittest.mm", ] deps = [ - ":history", ":history_ui", - ":resources_unit_tests", "//base", "//base/test:test_support", - "//components/browser_sync", - "//components/favicon/core", - "//components/favicon/core/test:test_support", - "//components/favicon_base", "//components/history/core/browser", - "//components/keyed_service/core", - "//components/sessions", - "//components/strings", - "//ios/chrome/app/strings", - "//ios/chrome/browser", - "//ios/chrome/browser/browser_state:test_support", - "//ios/chrome/browser/history", - "//ios/chrome/browser/signin", - "//ios/chrome/browser/signin:test_support", - "//ios/chrome/browser/sync:sync", - "//ios/chrome/browser/sync:test_support", "//ios/chrome/browser/ui", - "//ios/chrome/browser/ui:feature_flags", - "//ios/chrome/browser/ui/collection_view", "//ios/chrome/browser/ui/list_model", - "//ios/chrome/browser/ui/util", - "//ios/chrome/common", "//ios/chrome/test:test_support", - "//ios/web", - "//ios/web/public/test", - "//skia", - "//testing/gmock", "//testing/gtest", "//third_party/ocmock", - "//ui/base", - "//ui/gfx", - "//url", - ] -} - -bundle_data("resources_unit_tests") { - visibility = [ - ":unit_tests", - ":unit_tests_arc", - ] - testonly = true - sources = [ - "//ios/chrome/test/data/favicon/test_favicon.png", - ] - outputs = [ - "{{bundle_resources_dir}}/" + - "ios/chrome/test/data/favicon/{{source_file_part}}", ] }
diff --git a/ios/chrome/browser/ui/history/clear_browsing_bar.h b/ios/chrome/browser/ui/history/clear_browsing_bar.h deleted file mode 100644 index d2bf263f..0000000 --- a/ios/chrome/browser/ui/history/clear_browsing_bar.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_CLEAR_BROWSING_BAR_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_CLEAR_BROWSING_BAR_H_ - -#import <UIKit/UIKit.h> - -// View at the bottom of the history panel that presents options to clear -// browsing data or enter edit mode. When in edit mode, the bar displays a -// delete button and a cancel button instead. -@interface ClearBrowsingBar : UIView - -// Yes if in edit mode. Setting to |editing| ClearBrowsingBar for edit -// mode or non-edit mode accordingly. -@property(nonatomic, getter=isEditing) BOOL editing; -// Yes if the edit button is enabled. Setting |editButtonEnabled| enables or -// disables the edit button accordingly. -@property(nonatomic, getter=isEditButtonEnabled) BOOL editButtonEnabled; -// Yes if the delete button is enabled. Setting |deleteButtonEnabled| enables or -// disables the delete button accordingly. -@property(nonatomic, getter=isDeleteButtonEnabled) BOOL deleteButtonEnabled; - -// Sets the target/action of the "Clear Browsing Data..." button. -- (void)setClearBrowsingDataTarget:(id)target action:(SEL)action; -// Sets the target/action of the "Edit" button. -- (void)setEditTarget:(id)target action:(SEL)action; -// Sets the target/action of the "Delete" button. -- (void)setDeleteTarget:(id)taret action:(SEL)action; -// Sets the target/action of the "Cancel" button. -- (void)setCancelTarget:(id)target action:(SEL)action; -// Updates the height of the ClearBrowsingBar. -- (void)updateHeight; - -@end -#endif // IOS_CHROME_BROWSER_UI_HISTORY_CLEAR_BROWSING_BAR_H_
diff --git a/ios/chrome/browser/ui/history/clear_browsing_bar.mm b/ios/chrome/browser/ui/history/clear_browsing_bar.mm deleted file mode 100644 index e14ce2b..0000000 --- a/ios/chrome/browser/ui/history/clear_browsing_bar.mm +++ /dev/null
@@ -1,305 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/clear_browsing_bar.h" - -#include "base/logging.h" -#include "components/strings/grit/components_strings.h" -#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" -#import "ios/chrome/browser/ui/history/history_ui_constants.h" -#include "ios/chrome/browser/ui/rtl_geometry.h" -#import "ios/chrome/browser/ui/uikit_ui_util.h" -#import "ios/chrome/common/ui_util/constraints_ui_util.h" -#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h" -#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" -#include "ui/base/l10n/l10n_util_mac.h" -#import "ui/gfx/ios/NSString+CrStringDrawing.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { -// Shadow opacity for the clear browsing bar. -const CGFloat kShadowOpacity = 0.12f; -// Shadow radius for the clear browsing bar. -const CGFloat kShadowRadius = 12.0f; -// Horizontal margin and spacing for the contents of clear browsing bar. -const CGFloat kHorizontalMargin = 16.0f; -// Vertical margin for the contents of clear browsing bar. -const CGFloat kVerticalMargin = 8.0f; -// Horizontal spacing between the buttons inside clear browsing bar. -const CGFloat kHorizontalSpacing = 8.0f; -// Height of the toolbar in normal state. -const CGFloat kToolbarNormalHeight = 48.0f; -// Height of the expanded toolbar (buttons on multiple lines). -const CGFloat kToolbarExpandedHeight = 58.0f; -// Maximum proportion of the width of a button in the toolbar. -const CGFloat kMaxButtonWidthRatio = 0.52f; -// Enum to specify button position in the clear browsing bar. -typedef NS_ENUM(BOOL, ButtonPlacement) { Leading, Trailing }; -} // namespace - -@interface ClearBrowsingBar () - -// Button that displays "Clear Browsing Data...". -@property(nonatomic, strong) UIButton* clearBrowsingDataButton; -@property(nonatomic, strong) UIView* clearButtonContainer; -// Button that displays "Edit". -@property(nonatomic, strong) UIButton* editButton; -@property(nonatomic, strong) UIView* editButtonContainer; -// Button that displays "Delete". -@property(nonatomic, strong) UIButton* deleteButton; -@property(nonatomic, strong) UIView* deleteButtonContainer; -// Button that displays "Cancel". -@property(nonatomic, strong) UIButton* cancelButton; -@property(nonatomic, strong) UIView* cancelButtonContainer; -// Stack view for arranging the buttons. -@property(nonatomic, strong) UIStackView* stackView; -// Height constraint for the stack view containing the buttons. -@property(nonatomic, strong) NSLayoutConstraint* heightConstraint; - -// Styles button for Leading or Trailing placement. Leading buttons have red -// text that is aligned to the leading edge. Trailing buttons have blue text -// that is aligned to the trailing edge. -- (void)styleButton:(UIButton*)button forPlacement:(ButtonPlacement)placement; - -@end - -@implementation ClearBrowsingBar - -@synthesize editing = _editing; -@synthesize clearBrowsingDataButton = _clearBrowsingDataButton; -@synthesize clearButtonContainer = _clearButtonContainer; -@synthesize editButton = _editButton; -@synthesize editButtonContainer = _editButtonContainer; -@synthesize deleteButton = _deleteButton; -@synthesize deleteButtonContainer = _deleteButtonContainer; -@synthesize cancelButton = _cancelButton; -@synthesize cancelButtonContainer = _cancelButtonContainer; -@synthesize stackView = _stackView; -@synthesize heightConstraint = _heightConstraint; - -- (instancetype)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - NSDictionary* views = nil; - NSArray* constraints = nil; - - _clearBrowsingDataButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [_clearBrowsingDataButton - setTitle:l10n_util::GetNSStringWithFixup( - IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG) - forState:UIControlStateNormal]; - _clearBrowsingDataButton.accessibilityIdentifier = - kHistoryToolbarClearBrowsingButtonIdentifier; - - [self styleButton:_clearBrowsingDataButton forPlacement:Leading]; - _clearButtonContainer = [[UIView alloc] init]; - [_clearButtonContainer addSubview:_clearBrowsingDataButton]; - views = @{@"button" : _clearBrowsingDataButton}; - constraints = @[ @"V:|[button]|", @"H:|[button]" ]; - ApplyVisualConstraints(constraints, views); - [_clearBrowsingDataButton.trailingAnchor - constraintLessThanOrEqualToAnchor:_clearButtonContainer.trailingAnchor] - .active = YES; - - _editButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [_editButton - setTitle:l10n_util::GetNSString(IDS_HISTORY_START_EDITING_BUTTON) - forState:UIControlStateNormal]; - _editButton.accessibilityIdentifier = kHistoryToolbarEditButtonIdentifier; - - [self styleButton:_editButton forPlacement:Trailing]; - _editButtonContainer = [[UIView alloc] init]; - [_editButtonContainer addSubview:_editButton]; - views = @{@"button" : _editButton}; - constraints = @[ @"V:|[button]|", @"H:[button]|" ]; - ApplyVisualConstraints(constraints, views); - [_editButton.leadingAnchor - constraintGreaterThanOrEqualToAnchor:_editButtonContainer.leadingAnchor] - .active = YES; - - _deleteButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [_deleteButton setTitle:l10n_util::GetNSString( - IDS_HISTORY_DELETE_SELECTED_ENTRIES_BUTTON) - forState:UIControlStateNormal]; - _deleteButton.accessibilityIdentifier = - kHistoryToolbarDeleteButtonIdentifier; - [self styleButton:_deleteButton forPlacement:Leading]; - _deleteButtonContainer = [[UIView alloc] init]; - [_deleteButtonContainer addSubview:_deleteButton]; - views = @{@"button" : _deleteButton}; - constraints = @[ @"V:|[button]|", @"H:|[button]" ]; - ApplyVisualConstraints(constraints, views); - [_deleteButton.trailingAnchor - constraintLessThanOrEqualToAnchor:_deleteButtonContainer.trailingAnchor] - .active = YES; - - _cancelButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [_cancelButton - setTitle:l10n_util::GetNSString(IDS_HISTORY_CANCEL_EDITING_BUTTON) - forState:UIControlStateNormal]; - _cancelButton.accessibilityIdentifier = - kHistoryToolbarCancelButtonIdentifier; - [self styleButton:_cancelButton forPlacement:Trailing]; - _cancelButtonContainer = [[UIView alloc] init]; - [_cancelButtonContainer addSubview:_cancelButton]; - views = @{@"button" : _cancelButton}; - constraints = @[ @"V:|[button]|", @"H:[button]|" ]; - ApplyVisualConstraints(constraints, views); - [_cancelButton.leadingAnchor - constraintGreaterThanOrEqualToAnchor:_cancelButtonContainer - .leadingAnchor] - .active = YES; - - _stackView = [[UIStackView alloc] initWithArrangedSubviews:@[ - _clearButtonContainer, _editButtonContainer, _deleteButtonContainer, - _cancelButtonContainer - ]]; - _stackView.alignment = UIStackViewAlignmentCenter; - _stackView.distribution = UIStackViewDistributionEqualSpacing; - _stackView.axis = UILayoutConstraintAxisHorizontal; - - [self addSubview:_stackView]; - _stackView.translatesAutoresizingMaskIntoConstraints = NO; - - PinToSafeArea(_stackView, self); - _heightConstraint = [_stackView.heightAnchor - constraintEqualToConstant:kToolbarNormalHeight]; - _heightConstraint.active = YES; - _stackView.layoutMarginsRelativeArrangement = YES; - _stackView.layoutMargins = UIEdgeInsetsMake( - kVerticalMargin, kHorizontalMargin, kVerticalMargin, kHorizontalMargin); - _stackView.spacing = kHorizontalSpacing; - - for (UIButton* button in @[ - _clearBrowsingDataButton, _editButton, _deleteButton, _cancelButton - ]) { - [button.widthAnchor - constraintLessThanOrEqualToAnchor:_stackView.widthAnchor - multiplier:kMaxButtonWidthRatio] - .active = YES; - } - - [self setBackgroundColor:[UIColor whiteColor]]; - [[self layer] setShadowOpacity:kShadowOpacity]; - [[self layer] setShadowRadius:kShadowRadius]; - [self setEditing:NO]; - } - return self; -} - -#pragma mark Public Methods - -- (void)setEditing:(BOOL)editing { - _editing = editing; - self.clearButtonContainer.hidden = editing; - self.editButtonContainer.hidden = editing; - self.deleteButtonContainer.hidden = !editing; - self.cancelButtonContainer.hidden = !editing; - - [self updateHeight]; -} - -- (BOOL)isEditButtonEnabled { - return self.editButton.enabled; -} - -- (void)setEditButtonEnabled:(BOOL)editButtonEnabled { - self.editButton.enabled = editButtonEnabled; -} - -- (BOOL)isDeleteButtonEnabled { - return self.deleteButton.enabled; -} - -- (void)setDeleteButtonEnabled:(BOOL)deleteButtonEnabled { - self.deleteButton.enabled = deleteButtonEnabled; -} - -- (void)setClearBrowsingDataTarget:(id)target action:(SEL)action { - [self.clearBrowsingDataButton addTarget:target - action:action - forControlEvents:UIControlEventTouchUpInside]; -} - -- (void)setEditTarget:(id)target action:(SEL)action { - [self.editButton addTarget:target - action:action - forControlEvents:UIControlEventTouchUpInside]; -} - -- (void)setDeleteTarget:(id)target action:(SEL)action { - [self.deleteButton addTarget:target - action:action - forControlEvents:UIControlEventTouchUpInside]; -} - -- (void)setCancelTarget:(id)target action:(SEL)action { - [self.cancelButton addTarget:target - action:action - forControlEvents:UIControlEventTouchUpInside]; -} - -- (void)updateHeight { - NSArray* buttons = - @[ _clearBrowsingDataButton, _editButton, _deleteButton, _cancelButton ]; - - CGFloat buttonMaxWidth = self.frame.size.width * kMaxButtonWidthRatio; - CGFloat availableWidth = self.frame.size.width - kHorizontalMargin * 2; - NSUInteger visibleCount = 0; - - // Count the number of visible buttons and deduct the button spacings from - // availableWidth. - for (UIButton* button in buttons) { - if (!button.superview.hidden) { - visibleCount++; - if (visibleCount > 1) { - availableWidth -= kHorizontalSpacing; - } - } - } - - // Expand toolbar height in case word wrapping happens. - for (UIButton* button in buttons) { - if (!button.superview.hidden) { - CGFloat rect = [button.titleLabel.text - cr_pixelAlignedSizeWithFont:button.titleLabel.font] - .width; - if (rect > availableWidth || rect > buttonMaxWidth) { - self.heightConstraint.constant = kToolbarExpandedHeight; - return; - } - availableWidth -= rect; - } - } - - // Use the normal height when there is no word wrapping. - self.heightConstraint.constant = kToolbarNormalHeight; -} - -#pragma mark Private Methods - -- (void)styleButton:(UIButton*)button forPlacement:(ButtonPlacement)placement { - BOOL leading = placement == Leading; - BOOL alignmentLeft = leading ^ UseRTLLayout(); - [button setBackgroundColor:[UIColor whiteColor]]; - UIColor* textColor = leading ? [[MDCPalette cr_redPalette] tint500] - : [[MDCPalette cr_bluePalette] tint500]; - [button setTitleColor:textColor forState:UIControlStateNormal]; - [button setTitleColor:[[MDCPalette greyPalette] tint500] - forState:UIControlStateDisabled]; - [[button titleLabel] setFont:[MDCTypography subheadFont]]; - button.titleLabel.textAlignment = - alignmentLeft ? NSTextAlignmentLeft : NSTextAlignmentRight; - button.contentHorizontalAlignment = - alignmentLeft ? UIControlContentHorizontalAlignmentLeft - : UIControlContentHorizontalAlignmentRight; - [button setTranslatesAutoresizingMaskIntoConstraints:NO]; - button.titleLabel.numberOfLines = 2; - button.titleLabel.adjustsFontSizeToFitWidth = YES; -} - -@end
diff --git a/ios/chrome/browser/ui/history/favicon_view.h b/ios/chrome/browser/ui/history/favicon_view.h deleted file mode 100644 index 3a0ce2e..0000000 --- a/ios/chrome/browser/ui/history/favicon_view.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_H_ - -#import <UIKit/UIKit.h> - -// View for displaying the favicon of a history entry. -@interface FaviconView : UIView - -// Size for the favicon. -@property(nonatomic) CGFloat size; -// Image view for the favicon. -@property(nonatomic, strong) UIImageView* faviconImage; -// Label for fallback favicon placeholder. -@property(nonatomic, strong) UILabel* faviconFallbackLabel; - -@end - -#endif // IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_H_
diff --git a/ios/chrome/browser/ui/history/favicon_view.mm b/ios/chrome/browser/ui/history/favicon_view.mm deleted file mode 100644 index 2b0288b..0000000 --- a/ios/chrome/browser/ui/history/favicon_view.mm +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/favicon_view.h" - -#import "ios/chrome/common/ui_util/constraints_ui_util.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { -// Default corner radius for the favicon image view. -const CGFloat kDefaultCornerRadius = 3; -} - -@interface FaviconView () { - // Property releaser for FaviconView. -} -// Size constraints for the favicon views. -@property(nonatomic, copy) NSArray* faviconSizeConstraints; -@end - -@implementation FaviconView - -@synthesize size = _size; -@synthesize faviconImage = _faviconImage; -@synthesize faviconFallbackLabel = _faviconFallbackLabel; -@synthesize faviconSizeConstraints = _faviconSizeConstraints; - -- (instancetype)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - _faviconImage = [[UIImageView alloc] init]; - _faviconImage.clipsToBounds = YES; - _faviconImage.layer.cornerRadius = kDefaultCornerRadius; - _faviconImage.image = nil; - - _faviconFallbackLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - _faviconFallbackLabel.backgroundColor = [UIColor clearColor]; - _faviconFallbackLabel.textAlignment = NSTextAlignmentCenter; - _faviconFallbackLabel.isAccessibilityElement = NO; - _faviconFallbackLabel.text = nil; - - [self addSubview:_faviconImage]; - [self addSubview:_faviconFallbackLabel]; - - [_faviconImage setTranslatesAutoresizingMaskIntoConstraints:NO]; - [_faviconFallbackLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; - AddSameConstraints(_faviconImage, self); - AddSameConstraints(_faviconFallbackLabel, self); - _faviconSizeConstraints = @[ - [self.widthAnchor constraintEqualToConstant:0], - [self.heightAnchor constraintEqualToConstant:0], - ]; - [NSLayoutConstraint activateConstraints:_faviconSizeConstraints]; - } - return self; -} - -- (void)setSize:(CGFloat)size { - _size = size; - for (NSLayoutConstraint* constraint in self.faviconSizeConstraints) { - constraint.constant = size; - } -} - -@end
diff --git a/ios/chrome/browser/ui/history/favicon_view_provider.h b/ios/chrome/browser/ui/history/favicon_view_provider.h deleted file mode 100644 index 83c70b0..0000000 --- a/ios/chrome/browser/ui/history/favicon_view_provider.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_PROVIDER_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_PROVIDER_H_ - -#import <UIKit/UIKit.h> - -namespace favicon { -class LargeIconService; -} // namespace favicon - -@class FaviconView; -@class FaviconViewProvider; -class GURL; - -// Delegate protocol for FaviconViewProvider. -@protocol FaviconViewProviderDelegate<NSObject> -// Called when favicon or fallback format has been fetched. -- (void)faviconViewProviderFaviconDidLoad:(FaviconViewProvider*)provider; -@end - -// Object to fetch and configure the view for a favicon, or a fallback icon if -// there is no favicon image available with large enough resolution. -@interface FaviconViewProvider : NSObject -// A favicon or fallback format associated with |URL| will be fetched using -// |largeIconService|. The favicon will be rendered with height and width equal -// to |faviconSize|, and the image will be fetched if the source size is greater -// than or equal to |minFaviconSize|. The |delegate| is notified when the -// favicon has been loaded, and may be nil. -- (instancetype)initWithURL:(const GURL&)URL - faviconSize:(CGFloat)faviconSize - minFaviconSize:(CGFloat)minFaviconSize - largeIconService:(favicon::LargeIconService*)largeIconService - delegate:(id<FaviconViewProviderDelegate>)delegate - NS_DESIGNATED_INITIALIZER; -- (instancetype)init NS_UNAVAILABLE; - -// View that displays a favicon or fallback icon. -@property(strong, nonatomic, readonly) FaviconView* faviconView; - -@end - -#endif // IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_PROVIDER_H_
diff --git a/ios/chrome/browser/ui/history/favicon_view_provider.mm b/ios/chrome/browser/ui/history/favicon_view_provider.mm deleted file mode 100644 index 444cda4..0000000 --- a/ios/chrome/browser/ui/history/favicon_view_provider.mm +++ /dev/null
@@ -1,155 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/favicon_view_provider.h" - -#include "base/bind.h" -#include "base/i18n/case_conversion.h" -#import "base/mac/foundation_util.h" -#include "base/memory/ref_counted_memory.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/task/cancelable_task_tracker.h" -#include "components/favicon/core/fallback_url_util.h" -#include "components/favicon/core/large_icon_service.h" -#include "components/favicon_base/fallback_icon_style.h" -#include "components/favicon_base/favicon_types.h" -#import "ios/chrome/browser/ui/history/favicon_view.h" -#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" -#include "net/base/registry_controlled_domains/registry_controlled_domain.h" -#include "skia/ext/skia_utils_ios.h" -#include "url/gurl.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface FaviconViewProvider () { - // Delegate for handling completion of favicon load. - __weak id<FaviconViewProviderDelegate> _delegate; - // Used to cancel tasks for the LargeIconService. - base::CancelableTaskTracker _faviconTaskTracker; -} - -// Size to render the favicon. -@property(nonatomic, assign) CGFloat faviconSize; -// Favicon image for the favicon view. -@property(nonatomic, strong) UIImage* favicon; -// Fallback text for the favicon view if there is no appropriately sized -// favicon availabile. -@property(nonatomic, copy) NSString* fallbackText; -// Fallback background color for the favicon view if there is no appropriately -// sized favicon available. -@property(nonatomic, strong) UIColor* fallbackBackgroundColor; -// Fallback text color for the favicon view if there is no appropriately -// sized favicon available. -@property(nonatomic, strong) UIColor* fallbackTextColor; - -// Fetches favicon for |URL| from |faviconService|. Notifies delegate when -// favicon is retrieved. -- (void)fetchFaviconForURL:(const GURL&)URL - size:(CGFloat)size - minSize:(CGFloat)minSize - service:(favicon::LargeIconService*)faviconService; - -@end - -@implementation FaviconViewProvider - -@synthesize faviconSize = _faviconSize; -@synthesize favicon = _favicon; -@synthesize fallbackText = _fallbackText; -@synthesize fallbackBackgroundColor = _fallbackBackgroundColor; -@synthesize fallbackTextColor = _fallbackTextColor; -@synthesize faviconView = _faviconView; - -- (instancetype)initWithURL:(const GURL&)URL - faviconSize:(CGFloat)faviconSize - minFaviconSize:(CGFloat)minFaviconSize - largeIconService:(favicon::LargeIconService*)largeIconService - delegate:(id<FaviconViewProviderDelegate>)delegate { - self = [super init]; - if (self) { - _faviconSize = faviconSize; - _delegate = delegate; - _fallbackBackgroundColor = [UIColor grayColor]; - _fallbackTextColor = [UIColor whiteColor]; - [self fetchFaviconForURL:URL - size:faviconSize - minSize:minFaviconSize - service:largeIconService]; - } - return self; -} - -- (instancetype)init { - NOTREACHED(); - return nil; -} - -- (void)fetchFaviconForURL:(const GURL&)URL - size:(CGFloat)size - minSize:(CGFloat)minSize - service:(favicon::LargeIconService*)largeIconService { - if (!largeIconService) - return; - __weak FaviconViewProvider* weakSelf = self; - GURL blockURL(URL); - void (^faviconBlock)(const favicon_base::LargeIconResult&) = ^( - const favicon_base::LargeIconResult& result) { - FaviconViewProvider* strongSelf = weakSelf; - if (!strongSelf) - return; - if (result.bitmap.is_valid()) { - scoped_refptr<base::RefCountedMemory> data = - result.bitmap.bitmap_data.get(); - [strongSelf - setFavicon:[UIImage - imageWithData:[NSData dataWithBytes:data->front() - length:data->size()]]]; - } else if (result.fallback_icon_style) { - [strongSelf setFallbackBackgroundColor:skia::UIColorFromSkColor( - result.fallback_icon_style - ->background_color)]; - [strongSelf - setFallbackTextColor:skia::UIColorFromSkColor( - result.fallback_icon_style->text_color)]; - [strongSelf setFallbackText:base::SysUTF16ToNSString( - favicon::GetFallbackIconText(blockURL))]; - } - [strongSelf->_delegate faviconViewProviderFaviconDidLoad:strongSelf]; - }; - - // Always call LargeIconService in case the favicon was updated. - CGFloat faviconSize = [UIScreen mainScreen].scale * size; - CGFloat minFaviconSize = [UIScreen mainScreen].scale * minSize; - largeIconService->GetLargeIconOrFallbackStyle( - URL, minFaviconSize, faviconSize, base::BindRepeating(faviconBlock), - &_faviconTaskTracker); -} - -- (FaviconView*)faviconView { - if (!_faviconView) { - _faviconView = [[FaviconView alloc] initWithFrame:CGRectZero]; - } - _faviconView.size = _faviconSize; - // Update favicon view with current properties. - if (self.favicon) { - _faviconView.faviconImage.image = self.favicon; - _faviconView.faviconImage.backgroundColor = [UIColor whiteColor]; - _faviconView.faviconFallbackLabel.text = nil; - } else { - _faviconView.faviconImage.image = nil; - _faviconView.faviconImage.backgroundColor = self.fallbackBackgroundColor; - _faviconView.faviconFallbackLabel.text = self.fallbackText; - _faviconView.faviconFallbackLabel.textColor = self.fallbackTextColor; - - CGFloat fontSize = floorf(_faviconSize / 2); - _faviconView.faviconFallbackLabel.font = - [[MDCTypography fontLoader] regularFontOfSize:fontSize]; - } - return _faviconView; -} - -@end
diff --git a/ios/chrome/browser/ui/history/favicon_view_provider_unittest.mm b/ios/chrome/browser/ui/history/favicon_view_provider_unittest.mm deleted file mode 100644 index e745e03d..0000000 --- a/ios/chrome/browser/ui/history/favicon_view_provider_unittest.mm +++ /dev/null
@@ -1,154 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/favicon_view_provider.h" - -#include <memory> - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/location.h" -#include "base/path_service.h" -#include "base/strings/sys_string_conversions.h" -#include "base/task/cancelable_task_tracker.h" -#include "components/favicon/core/large_icon_service.h" -#include "components/favicon/core/test/mock_favicon_service.h" -#include "components/favicon_base/fallback_icon_style.h" -#include "components/favicon_base/favicon_types.h" -#include "ios/chrome/browser/chrome_paths.h" -#include "ios/web/public/test/test_web_thread.h" -#include "ios/web/public/test/test_web_thread_bundle.h" -#include "skia/ext/skia_utils_ios.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest_mac.h" -#include "testing/platform_test.h" -#include "third_party/ocmock/OCMock/OCMock.h" -#include "third_party/ocmock/gtest_support.h" -#include "third_party/skia/include/core/SkColor.h" -#include "url/gurl.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface FaviconViewProvider (Testing) -@property(nonatomic, retain) UIImage* favicon; -@property(nonatomic, copy) NSString* fallbackText; -@property(nonatomic, retain) UIColor* fallbackBackgroundColor; -@property(nonatomic, retain) UIColor* fallbackTextColor; -@end - -namespace { - -using favicon::PostReply; -using testing::_; - -// Dummy URL for the favicon case. -const char kTestFaviconURL[] = "http://test/favicon"; -// Dummy URL for the fallback case. -const char kTestFallbackURL[] = "http://test/fallback"; -// Dummy icon URL. -const char kTestFaviconIconURL[] = "http://test/icons/favicon"; - -// Size of dummy favicon image. -const CGFloat kTestFaviconSize = 57; - -favicon_base::FaviconRawBitmapResult CreateTestBitmap() { - favicon_base::FaviconRawBitmapResult result; - result.expired = false; - base::FilePath favicon_path; - base::PathService::Get(ios::DIR_TEST_DATA, &favicon_path); - favicon_path = - favicon_path.Append(FILE_PATH_LITERAL("favicon/test_favicon.png")); - NSData* favicon_data = [NSData - dataWithContentsOfFile:base::SysUTF8ToNSString(favicon_path.value())]; - scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes( - static_cast<const unsigned char*>([favicon_data bytes]), - [favicon_data length])); - - result.bitmap_data = data; - CGFloat scaled_size = [UIScreen mainScreen].scale * kTestFaviconSize; - result.pixel_size = gfx::Size(scaled_size, scaled_size); - result.icon_url = GURL(kTestFaviconIconURL); - result.icon_type = favicon_base::IconType::kTouchIcon; - CHECK(result.is_valid()); - return result; -} - -class FaviconViewProviderTest : public PlatformTest { - protected: - void SetUp() override { - DCHECK_CURRENTLY_ON(web::WebThread::UI); - PlatformTest::SetUp(); - large_icon_service_.reset(new favicon::LargeIconService( - &mock_favicon_service_, /*image_fetcher=*/nullptr)); - - EXPECT_CALL(mock_favicon_service_, GetLargestRawFaviconForPageURL( - GURL(kTestFaviconURL), _, _, _, _)) - .WillRepeatedly(PostReply<5>(CreateTestBitmap())); - } - - web::TestWebThreadBundle thread_bundle_; - testing::StrictMock<favicon::MockFaviconService> mock_favicon_service_; - std::unique_ptr<favicon::LargeIconService> large_icon_service_; - base::CancelableTaskTracker cancelable_task_tracker_; -}; - -// Tests that image is set when a favicon is returned from LargeIconService. -TEST_F(FaviconViewProviderTest, Favicon) { - id mock_delegate = - [OCMockObject mockForProtocol:@protocol(FaviconViewProviderDelegate)]; - FaviconViewProvider* viewProvider = - [[FaviconViewProvider alloc] initWithURL:GURL(kTestFaviconURL) - faviconSize:kTestFaviconSize - minFaviconSize:kTestFaviconSize - largeIconService:large_icon_service_.get() - delegate:mock_delegate]; - void (^confirmationBlock)(NSInvocation*) = ^(NSInvocation* invocation) { - __unsafe_unretained FaviconViewProvider* viewProvider; - [invocation getArgument:&viewProvider atIndex:2]; - EXPECT_NSNE(nil, viewProvider.favicon); - }; - [[[mock_delegate stub] andDo:confirmationBlock] - faviconViewProviderFaviconDidLoad:viewProvider]; - EXPECT_OCMOCK_VERIFY(mock_delegate); -} - -// Tests that fallback data is set when no favicon is returned from -// LargeIconService. -TEST_F(FaviconViewProviderTest, FallbackIcon) { - EXPECT_CALL(mock_favicon_service_, GetLargestRawFaviconForPageURL( - GURL(kTestFallbackURL), _, _, _, _)) - .WillRepeatedly(PostReply<5>(favicon_base::FaviconRawBitmapResult())); - - id mock_delegate = - [OCMockObject mockForProtocol:@protocol(FaviconViewProviderDelegate)]; - FaviconViewProvider* item = - [[FaviconViewProvider alloc] initWithURL:GURL(kTestFallbackURL) - faviconSize:kTestFaviconSize - minFaviconSize:kTestFaviconSize - largeIconService:large_icon_service_.get() - delegate:mock_delegate]; - - // Confirm that fallback text and color have been set before delegate call. - void (^confirmationBlock)(NSInvocation*) = ^(NSInvocation* invocation) { - __unsafe_unretained FaviconViewProvider* viewProvider; - [invocation getArgument:&viewProvider atIndex:2]; - // Fallback text is the first letter of the URL. - NSString* defaultText = @"T"; - // Default colors are defined in - // components/favicon_base/fallback_icon_style.h. - UIColor* defaultTextColor = skia::UIColorFromSkColor(SK_ColorWHITE); - UIColor* defaultBackgroundColor = - skia::UIColorFromSkColor(SkColorSetRGB(0x78, 0x78, 0x78)); - EXPECT_NSEQ(defaultText, viewProvider.fallbackText); - EXPECT_NSEQ(defaultTextColor, viewProvider.fallbackTextColor); - EXPECT_NSEQ(defaultBackgroundColor, viewProvider.fallbackBackgroundColor); - }; - [[[mock_delegate stub] andDo:confirmationBlock] - faviconViewProviderFaviconDidLoad:item]; - EXPECT_OCMOCK_VERIFY(mock_delegate); -} - -} // namespace
diff --git a/ios/chrome/browser/ui/history/features.cc b/ios/chrome/browser/ui/history/features.cc deleted file mode 100644 index 3e66cc0..0000000 --- a/ios/chrome/browser/ui/history/features.cc +++ /dev/null
@@ -1,8 +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. - -#import "ios/chrome/browser/ui/history/features.h" - -const base::Feature kHistoryBatchUpdatesFilter{ - "HistoryBatchUpdatesFilter", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/history/features.h b/ios/chrome/browser/ui/history/features.h deleted file mode 100644 index 902b0e4..0000000 --- a/ios/chrome/browser/ui/history/features.h +++ /dev/null
@@ -1,13 +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. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_FEATURES_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_FEATURES_H_ - -#include "base/feature_list.h" - -// Feature to choose wether history filtering will use one BatchUpdates block. -extern const base::Feature kHistoryBatchUpdatesFilter; - -#endif // IOS_CHROME_BROWSER_UI_HISTORY_FEATURES_H_
diff --git a/ios/chrome/browser/ui/history/history_coordinator.mm b/ios/chrome/browser/ui/history/history_coordinator.mm index 423e625b..59b0548 100644 --- a/ios/chrome/browser/ui/history/history_coordinator.mm +++ b/ios/chrome/browser/ui/history/history_coordinator.mm
@@ -7,10 +7,8 @@ #include "components/browser_sync/profile_sync_service.h" #include "components/history/core/browser/browsing_history_service.h" #include "components/keyed_service/core/service_access_type.h" -#include "ios/chrome/browser/experimental_flags.h" #include "ios/chrome/browser/history/history_service_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" -#import "ios/chrome/browser/ui/commands/application_commands.h" #import "ios/chrome/browser/ui/history/history_clear_browsing_data_coordinator.h" #include "ios/chrome/browser/ui/history/history_local_commands.h" #import "ios/chrome/browser/ui/history/history_mediator.h" @@ -132,7 +130,6 @@ } - (void)displayPrivacySettings { - if (IsUIRefreshPhase1Enabled()) { self.historyClearBrowsingDataCoordinator = [[HistoryClearBrowsingDataCoordinator alloc] initWithBaseViewController:self.historyNavigationController @@ -143,10 +140,6 @@ self.historyClearBrowsingDataCoordinator.loader = self.loader; self.historyClearBrowsingDataCoordinator.dispatcher = self.dispatcher; [self.historyClearBrowsingDataCoordinator start]; - } else { - [self.dispatcher showClearBrowsingDataSettingsFromViewController: - self.historyNavigationController]; - } } @end
diff --git a/ios/chrome/browser/ui/history/history_entry_inserter.mm b/ios/chrome/browser/ui/history/history_entry_inserter.mm index 8ef149ef..e65882f 100644 --- a/ios/chrome/browser/ui/history/history_entry_inserter.mm +++ b/ios/chrome/browser/ui/history/history_entry_inserter.mm
@@ -129,20 +129,13 @@ NSInteger insertionIndex = _firstSectionIndex + index; [_listModel insertSectionWithIdentifier:sectionIdentifier atIndex:insertionIndex]; - if (IsUIRefreshPhase1Enabled()) { + TableViewTextHeaderFooterItem* header = [[TableViewTextHeaderFooterItem alloc] initWithType:kItemTypeEnumZero]; header.text = base::SysUTF16ToNSString(history::GetRelativeDateLocalized(timestamp)); [_listModel setHeader:header forSectionWithIdentifier:sectionIdentifier]; - } else { - CollectionViewTextItem* header = - [[CollectionViewTextItem alloc] initWithType:kItemTypeEnumZero]; - header.text = - base::SysUTF16ToNSString(history::GetRelativeDateLocalized(timestamp)); - [_listModel setHeader:header forSectionWithIdentifier:sectionIdentifier]; - } [self.delegate historyEntryInserter:self didInsertSectionAtIndex:insertionIndex]; return sectionIdentifier;
diff --git a/ios/chrome/browser/ui/history/history_entry_inserter_unittest.mm b/ios/chrome/browser/ui/history/history_entry_inserter_unittest.mm index 4f2db2c..b6f431b 100644 --- a/ios/chrome/browser/ui/history/history_entry_inserter_unittest.mm +++ b/ios/chrome/browser/ui/history/history_entry_inserter_unittest.mm
@@ -4,11 +4,14 @@ #import "ios/chrome/browser/ui/history/history_entry_inserter.h" +#include "base/i18n/time_formatting.h" #import "base/mac/foundation_util.h" +#include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "components/history/core/browser/browsing_history_service.h" -#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h" +#import "ios/chrome/browser/ui/history/history_entry_item.h" +#include "ios/chrome/browser/ui/history/history_util.h" #import "ios/chrome/browser/ui/list_model/list_model.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest_mac.h" @@ -22,16 +25,23 @@ using history::BrowsingHistoryService; -LegacyHistoryEntryItem* TestHistoryEntryItem(base::Time timestamp, - const std::string& name) { +HistoryEntryItem* TestHistoryEntryItem(base::Time timestamp, + const std::string& name) { BrowsingHistoryService::HistoryEntry entry( BrowsingHistoryService::HistoryEntry::LOCAL_ENTRY, GURL(("http://" + name).c_str()), base::UTF8ToUTF16(name.c_str()), timestamp, std::string(), false, base::string16(), false); - return [[LegacyHistoryEntryItem alloc] initWithType:kItemTypeEnumZero - historyEntry:entry - browserState:nil - delegate:nil]; + HistoryEntryItem* item = + [[HistoryEntryItem alloc] initWithType:kItemTypeEnumZero + accessibilityDelegate:nil]; + item.text = [history::FormattedTitle(entry.title, entry.url) copy]; + item.detailText = + [base::SysUTF8ToNSString(entry.url.GetOrigin().spec()) copy]; + item.timeText = + [base::SysUTF16ToNSString(base::TimeFormatTimeOfDay(entry.time)) copy]; + item.URL = entry.url; + item.timestamp = entry.time; + return item; } // Test fixture for HistoryEntryInserter. @@ -58,10 +68,9 @@ base::Time today = base::Time::Now().LocalMidnight() + base::TimeDelta::FromHours(1); base::TimeDelta minute = base::TimeDelta::FromMinutes(1); - LegacyHistoryEntryItem* entry1 = TestHistoryEntryItem(today, "entry1"); - LegacyHistoryEntryItem* entry2 = - TestHistoryEntryItem(today - minute, "entry2"); - LegacyHistoryEntryItem* entry3 = + HistoryEntryItem* entry1 = TestHistoryEntryItem(today, "entry1"); + HistoryEntryItem* entry2 = TestHistoryEntryItem(today - minute, "entry2"); + HistoryEntryItem* entry3 = TestHistoryEntryItem(today - 2 * (minute), "entry3"); OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_; @@ -89,8 +98,8 @@ EXPECT_EQ(0, [model_ numberOfItemsInSection:0]); EXPECT_EQ(3, [model_ numberOfItemsInSection:1]); - NSArray<LegacyHistoryEntryItem*>* section_1 = - base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + NSArray<HistoryEntryItem*>* section_1 = + base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:kSectionIdentifierEnumZero + 1]); EXPECT_NSEQ(@"entry1", section_1[0].text); EXPECT_NSEQ(@"entry2", section_1[1].text); @@ -105,12 +114,12 @@ base::Time::Now().LocalMidnight() + base::TimeDelta::FromHours(12); base::TimeDelta day = base::TimeDelta::FromDays(1); base::TimeDelta minute = base::TimeDelta::FromMinutes(1); - LegacyHistoryEntryItem* day1 = TestHistoryEntryItem(today, "day1"); - LegacyHistoryEntryItem* day2_entry1 = + HistoryEntryItem* day1 = TestHistoryEntryItem(today, "day1"); + HistoryEntryItem* day2_entry1 = TestHistoryEntryItem(today - day, "day2_entry1"); - LegacyHistoryEntryItem* day2_entry2 = + HistoryEntryItem* day2_entry2 = TestHistoryEntryItem(today - day - minute, "day2_entry2"); - LegacyHistoryEntryItem* day3 = TestHistoryEntryItem(today - 2 * day, "day3"); + HistoryEntryItem* day3 = TestHistoryEntryItem(today - 2 * day, "day3"); OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_; @@ -124,8 +133,8 @@ EXPECT_EQ(2, [model_ numberOfSections]); EXPECT_EQ(0, [model_ numberOfItemsInSection:0]); EXPECT_EQ(1, [model_ numberOfItemsInSection:1]); - NSArray<LegacyHistoryEntryItem*>* section_1 = - base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + NSArray<HistoryEntryItem*>* section_1 = + base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:day2_identifier]); EXPECT_NSEQ(@"day2_entry2", section_1[0].text); EXPECT_OCMOCK_VERIFY(mock_delegate); @@ -141,11 +150,11 @@ EXPECT_EQ(0, [model_ numberOfItemsInSection:0]); EXPECT_EQ(1, [model_ numberOfItemsInSection:1]); EXPECT_EQ(1, [model_ numberOfItemsInSection:2]); - section_1 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + section_1 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:day1_identifier]); EXPECT_NSEQ(@"day1", section_1[0].text); - NSArray<LegacyHistoryEntryItem*>* section_2 = - base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + NSArray<HistoryEntryItem*>* section_2 = + base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:day2_identifier]); EXPECT_NSEQ(@"day2_entry2", section_2[0].text); EXPECT_OCMOCK_VERIFY(mock_delegate); @@ -162,14 +171,14 @@ EXPECT_EQ(1, [model_ numberOfItemsInSection:1]); EXPECT_EQ(1, [model_ numberOfItemsInSection:2]); EXPECT_EQ(1, [model_ numberOfItemsInSection:3]); - section_1 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + section_1 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:day1_identifier]); EXPECT_NSEQ(@"day1", section_1[0].text); - section_2 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + section_2 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:day2_identifier]); EXPECT_NSEQ(@"day2_entry2", section_2[0].text); - NSArray<LegacyHistoryEntryItem*>* section_3 = - base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + NSArray<HistoryEntryItem*>* section_3 = + base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:day3_identifier]); EXPECT_NSEQ(@"day3", section_3[0].text); EXPECT_OCMOCK_VERIFY(mock_delegate); @@ -183,14 +192,14 @@ EXPECT_EQ(1, [model_ numberOfItemsInSection:1]); EXPECT_EQ(2, [model_ numberOfItemsInSection:2]); EXPECT_EQ(1, [model_ numberOfItemsInSection:3]); - section_1 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + section_1 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:day1_identifier]); EXPECT_NSEQ(@"day1", section_1[0].text); - section_2 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + section_2 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:day2_identifier]); EXPECT_NSEQ(@"day2_entry1", section_2[0].text); EXPECT_NSEQ(@"day2_entry2", section_2[1].text); - section_3 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + section_3 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:day3_identifier]); EXPECT_NSEQ(@"day3", section_3[0].text); EXPECT_OCMOCK_VERIFY(mock_delegate); @@ -199,8 +208,8 @@ // Tests that items are only ever added once. TEST_F(HistoryEntryInserterTest, AddDuplicateItems) { base::Time today = base::Time::Now(); - LegacyHistoryEntryItem* entry1 = TestHistoryEntryItem(today, "entry"); - LegacyHistoryEntryItem* entry2 = TestHistoryEntryItem(today, "entry"); + HistoryEntryItem* entry1 = TestHistoryEntryItem(today, "entry"); + HistoryEntryItem* entry2 = TestHistoryEntryItem(today, "entry"); OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_; [[mock_delegate expect] historyEntryInserter:inserter_ @@ -215,8 +224,8 @@ EXPECT_EQ(0, [model_ numberOfItemsInSection:0]); EXPECT_EQ(1, [model_ numberOfItemsInSection:1]); - NSArray<LegacyHistoryEntryItem*>* section_1 = - base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>( + NSArray<HistoryEntryItem*>* section_1 = + base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>( [model_ itemsInSectionWithIdentifier:kSectionIdentifierEnumZero + 1]); EXPECT_NSEQ(@"entry", section_1[0].text); EXPECT_OCMOCK_VERIFY(mock_delegate); @@ -227,8 +236,8 @@ base::Time today = base::Time::Now().LocalMidnight() + base::TimeDelta::FromHours(1); base::TimeDelta day = base::TimeDelta::FromDays(1); - LegacyHistoryEntryItem* day1 = TestHistoryEntryItem(today, "day1"); - LegacyHistoryEntryItem* day2 = TestHistoryEntryItem(today - day, "day2"); + HistoryEntryItem* day1 = TestHistoryEntryItem(today, "day1"); + HistoryEntryItem* day2 = TestHistoryEntryItem(today - day, "day2"); OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_;
diff --git a/ios/chrome/browser/ui/history/history_panel_view_controller.h b/ios/chrome/browser/ui/history/history_panel_view_controller.h deleted file mode 100644 index a2c4743..0000000 --- a/ios/chrome/browser/ui/history/history_panel_view_controller.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_PANEL_VIEW_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_PANEL_VIEW_CONTROLLER_H_ - -#import <UIKit/UIKit.h> - -namespace ios { -class ChromeBrowserState; -} - -@protocol ApplicationCommands; -@protocol UrlLoader; - -// View controller for displaying the history panel. -@interface HistoryPanelViewController : UIViewController - -- (instancetype)initWithLoader:(id<UrlLoader>)loader - browserState:(ios::ChromeBrowserState*)browserState - dispatcher:(id<ApplicationCommands>)dispatcher - NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithNibName:(NSString*)nibNameOrNil - bundle:(NSBundle*)nibBundleOrNil NS_UNAVAILABLE; -- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; - -@end -#endif // IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_PANEL_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/history/history_panel_view_controller.mm b/ios/chrome/browser/ui/history/history_panel_view_controller.mm deleted file mode 100644 index 8730241..0000000 --- a/ios/chrome/browser/ui/history/history_panel_view_controller.mm +++ /dev/null
@@ -1,407 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/history_panel_view_controller.h" - -#include <memory> - -#include "base/ios/block_types.h" -#include "base/metrics/user_metrics.h" -#include "base/metrics/user_metrics_action.h" -#include "components/browser_sync/profile_sync_service.h" -#include "components/history/core/browser/browsing_history_service.h" -#include "components/keyed_service/core/service_access_type.h" -#include "components/strings/grit/components_strings.h" -#include "ios/chrome/browser/history/history_service_factory.h" -#include "ios/chrome/browser/sync/profile_sync_service_factory.h" -#import "ios/chrome/browser/ui/commands/application_commands.h" -#import "ios/chrome/browser/ui/history/clear_browsing_bar.h" -#import "ios/chrome/browser/ui/history/history_search_view_controller.h" -#include "ios/chrome/browser/ui/history/ios_browsing_history_driver.h" -#import "ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h" -#import "ios/chrome/browser/ui/icons/chrome_icon.h" -#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h" -#import "ios/chrome/browser/ui/material_components/utils.h" -#import "ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.h" -#import "ios/chrome/browser/ui/uikit_ui_util.h" -#import "ios/chrome/browser/ui/url_loader.h" -#import "ios/chrome/common/ui_util/constraints_ui_util.h" -#include "ios/chrome/grit/ios_strings.h" -#import "ios/third_party/material_components_ios/src/components/AppBar/src/MDCAppBarViewController.h" -#import "ios/third_party/material_components_ios/src/components/NavigationBar/src/MaterialNavigationBar.h" -#include "ui/base/l10n/l10n_util_mac.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { -// Shadow opacity for the clear browsing button and the header when scrolling. -CGFloat kShadowOpacity = 0.2f; -} // namespace - -@interface HistoryPanelViewController ()< - LegacyHistoryCollectionViewControllerDelegate, - HistorySearchViewControllerDelegate> { - // Controller for collection view that displays history entries. - LegacyHistoryCollectionViewController* _historyCollectionController; - // Bar at the bottom of the history panel the displays options for entry - // deletion, including "Clear Browsing Data..." which takes the user to - // Privacy settings, or "Edit" for entering a mode for deleting individual - // entries. When in edit mode, the bar displays options to Delete or Cancel. - ClearBrowsingBar* _clearBrowsingBar; - // View controller for the search bar. - HistorySearchViewController* _searchViewController; - // Container view for history collection and clear browsing button to enable - // use of autolayout in conjunction with Material App Bar. - UIView* _containerView; - // The header view controller. - MDCAppBarViewController* _appBarViewController; - // Left bar button item for Search. - UIBarButtonItem* _leftBarButtonItem; - // Right bar button item for Dismiss history action. - UIBarButtonItem* _rightBarButtonItem; - // YES if NSLayoutConstraits were added. - BOOL _addedConstraints; - // Provides dependencies and funnels callbacks from BrowsingHistoryService. - std::unique_ptr<IOSBrowsingHistoryDriver> _browsingHistoryDriver; - // Abstraction to communicate with HistoryService and WebHistoryService. - std::unique_ptr<history::BrowsingHistoryService> _browsingHistoryService; -} -// Closes history. -- (void)closeHistory; -// Closes history, invoking completionHandler once dismissal is complete. -- (void)closeHistoryWithCompletion:(ProceduralBlock)completionHandler; -// Opens Privacy settings. -- (void)openPrivacySettings; -// Configure view for editing mode. -- (void)enterEditingMode; -// Configure view for non-editing mode. -- (void)exitEditingMode; -// Deletes selected history entries. -- (void)deleteSelectedItems; -// Displays a search bar for searching history entries. -- (void)enterSearchMode; -// Dismisses the search bar. -- (void)exitSearchMode; -// Configures navigation bar for current state of the history collection. -- (void)configureNavigationBar; -// Configures the clear browsing data bar for the current state of the history -// collection. -- (void)configureClearBrowsingBar; - -// The dispatcher used by this ViewController. -@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher; - -@end - -@implementation HistoryPanelViewController - -@synthesize dispatcher = _dispatcher; - -- (instancetype)initWithLoader:(id<UrlLoader>)loader - browserState:(ios::ChromeBrowserState*)browserState - dispatcher:(id<ApplicationCommands>)dispatcher { - self = [super initWithNibName:nil bundle:nil]; - if (self) { - _historyCollectionController = - [[LegacyHistoryCollectionViewController alloc] - initWithLoader:loader - browserState:browserState - delegate:self]; - - _browsingHistoryDriver = std::make_unique<IOSBrowsingHistoryDriver>( - browserState, _historyCollectionController); - - _browsingHistoryService = std::make_unique<history::BrowsingHistoryService>( - _browsingHistoryDriver.get(), - ios::HistoryServiceFactory::GetForBrowserState( - browserState, ServiceAccessType::EXPLICIT_ACCESS), - ProfileSyncServiceFactory::GetForBrowserState(browserState)); - - _historyCollectionController.historyService = _browsingHistoryService.get(); - - _dispatcher = dispatcher; - - // Configure modal presentation. - [self setModalPresentationStyle:UIModalPresentationFormSheet]; - [self setModalTransitionStyle:UIModalTransitionStyleCoverVertical]; - - // Add and configure header. - _appBarViewController = [[MDCAppBarViewController alloc] init]; - } - return self; -} - -- (instancetype)initWithNibName:(NSString*)nibNameOrNil - bundle:(NSBundle*)nibBundleOrNil { - NOTREACHED(); - return nil; -} - -- (instancetype)initWithCoder:(NSCoder*)aDecoder { - NOTREACHED(); - return nil; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - [self setTitle:l10n_util::GetNSString(IDS_HISTORY_TITLE)]; - - _containerView = [[UIView alloc] initWithFrame:self.view.frame]; - [_containerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | - UIViewAutoresizingFlexibleHeight]; - [self.view addSubview:_containerView]; - - [[_historyCollectionController view] - setTranslatesAutoresizingMaskIntoConstraints:NO]; - [_historyCollectionController willMoveToParentViewController:self]; - [_containerView addSubview:[_historyCollectionController view]]; - [self addChildViewController:_historyCollectionController]; - [_historyCollectionController didMoveToParentViewController:self]; - - _clearBrowsingBar = [[ClearBrowsingBar alloc] initWithFrame:CGRectZero]; - [_clearBrowsingBar setClearBrowsingDataTarget:self - action:@selector(openPrivacySettings)]; - [_clearBrowsingBar setEditTarget:self action:@selector(enterEditingMode)]; - [_clearBrowsingBar setCancelTarget:self action:@selector(exitEditingMode)]; - [_clearBrowsingBar setDeleteTarget:self - action:@selector(deleteSelectedItems)]; - [_clearBrowsingBar setTranslatesAutoresizingMaskIntoConstraints:NO]; - [_containerView addSubview:_clearBrowsingBar]; - [self configureClearBrowsingBar]; - - ConfigureAppBarViewControllerWithCardStyle(_appBarViewController); - [self addChildViewController:_appBarViewController]; - _appBarViewController.headerView.trackingScrollView = - [_historyCollectionController collectionView]; - [self.view addSubview:_appBarViewController.view]; - [_appBarViewController didMoveToParentViewController:self]; - // Prevent the touch events on appBar from being forwarded to the - // collectionView. See https://crbug.com/773580 - [_appBarViewController.headerView - stopForwardingTouchEventsForView:_appBarViewController.navigationBar]; - - // Add navigation bar buttons. - _leftBarButtonItem = - [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon searchIcon] - target:self - action:@selector(enterSearchMode)]; - self.navigationItem.leftBarButtonItem = _leftBarButtonItem; - _rightBarButtonItem = [[UIBarButtonItem alloc] - initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON) - style:UIBarButtonItemStylePlain - target:self - action:@selector(closeHistory)]; - self.navigationItem.rightBarButtonItem = _rightBarButtonItem; - [self configureNavigationBar]; -} - -- (void)updateViewConstraints { - if (!_addedConstraints) { - NSDictionary* views = @{ - @"collectionView" : [_historyCollectionController view], - @"clearBrowsingBar" : _clearBrowsingBar, - }; - NSArray* constraints = @[ - @"V:|[collectionView][clearBrowsingBar]|", @"H:|[collectionView]|", - @"H:|[clearBrowsingBar]|" - ]; - ApplyVisualConstraints(constraints, views); - _addedConstraints = YES; - } - [super updateViewConstraints]; -} - -- (BOOL)disablesAutomaticKeyboardDismissal { - return NO; -} - -- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)orient { - [super didRotateFromInterfaceOrientation:orient]; - [_clearBrowsingBar updateHeight]; -} - -#pragma mark - HistoryCollectionViewControllerDelegate - -- (void)historyCollectionViewController: - (LegacyHistoryCollectionViewController*)collectionViewcontroller - shouldCloseWithCompletion:(ProceduralBlock)completionHandler { - [self closeHistoryWithCompletion:completionHandler]; -} - -- (void)historyCollectionViewController: - (LegacyHistoryCollectionViewController*)controller - didScrollToOffset:(CGPoint)offset { - // Display a shadow on the header when the collection is scrolled. - MDCFlexibleHeaderView* headerView = _appBarViewController.headerView; - headerView.visibleShadowOpacity = - offset.y > -CGRectGetHeight(headerView.frame) ? kShadowOpacity : 0.0f; -} - -- (void)historyCollectionViewControllerDidChangeEntries: - (LegacyHistoryCollectionViewController*)controller { - // Reconfigure the navigation and clear browsing bars to reflect currently - // displayed entries. - [self configureNavigationBar]; - [self configureClearBrowsingBar]; -} - -- (void)historyCollectionViewControllerDidChangeEntrySelection: - (LegacyHistoryCollectionViewController*)controller { - // Reconfigure the clear browsing bar to reflect current availability of - // entries for deletion. - [self configureClearBrowsingBar]; -} - -#pragma mark - HistorySearchViewControllerDelegate - -- (void)historySearchViewController: - (HistorySearchViewController*)searchViewController - didRequestSearchForTerm:(NSString*)searchTerm { - [_historyCollectionController showHistoryMatchingQuery:searchTerm]; -} - -- (void)historySearchViewControllerDidCancel: - (HistorySearchViewController*)searchViewController { - DCHECK([_searchViewController isEqual:searchViewController]); - [self exitSearchMode]; -} - -#pragma mark UIAccessibilityAction - -- (BOOL)accessibilityPerformEscape { - [self closeHistory]; - return YES; -} - -#pragma mark - Private methods - -- (void)closeHistory { - [self closeHistoryWithCompletion:nil]; -} - -- (void)closeHistoryWithCompletion:(ProceduralBlock)completion { - [self.presentingViewController dismissViewControllerAnimated:YES - completion:completion]; -} - -- (void)openPrivacySettings { - // Ignore the button tap if view controller presenting. - if ([self presentedViewController]) { - return; - } - [self exitSearchMode]; - base::RecordAction( - base::UserMetricsAction("HistoryPage_InitClearBrowsingData")); - [self.dispatcher showClearBrowsingDataSettingsFromViewController:self]; -} - -- (void)enterEditingMode { - // Ignore the button tap if view controller presenting. - if ([self presentedViewController]) { - return; - } - [_historyCollectionController setEditing:YES]; - [_clearBrowsingBar setEditing:YES]; - if (_historyCollectionController.searching) { - [_searchViewController setEnabled:NO]; - } - DCHECK([_historyCollectionController isEditing]); - [self configureNavigationBar]; -} - -- (void)exitEditingMode { - [_historyCollectionController setEditing:NO]; - [_clearBrowsingBar setEditing:NO]; - if (_historyCollectionController.searching) { - [_searchViewController setEnabled:YES]; - } - DCHECK(![_historyCollectionController isEditing]); - [self configureNavigationBar]; -} - -- (void)deleteSelectedItems { - [_historyCollectionController deleteSelectedItemsFromHistory]; - base::RecordAction(base::UserMetricsAction("HistoryPage_RemoveSelected")); - [self exitEditingMode]; -} -- (void)enterSearchMode { - if (!_searchViewController) { - _searchViewController = [[HistorySearchViewController alloc] init]; - [_searchViewController setDelegate:self]; - } - - UIView* searchBarView = [_searchViewController view]; - [_searchViewController willMoveToParentViewController:self]; - [self.view addSubview:searchBarView]; - _historyCollectionController.searching = YES; - [_searchViewController didMoveToParentViewController:self]; - base::RecordAction(base::UserMetricsAction("HistoryPage_Search")); - - // Constraints to make search bar cover header. - [searchBarView setTranslatesAutoresizingMaskIntoConstraints:NO]; - MDCFlexibleHeaderView* headerView = _appBarViewController.headerView; - NSArray* constraints = @[ - [[searchBarView topAnchor] constraintEqualToAnchor:headerView.topAnchor], - [[searchBarView leadingAnchor] - constraintEqualToAnchor:headerView.leadingAnchor], - [[searchBarView heightAnchor] - constraintEqualToAnchor:headerView.heightAnchor], - [[searchBarView widthAnchor] constraintEqualToAnchor:headerView.widthAnchor] - ]; - [NSLayoutConstraint activateConstraints:constraints]; - // Workaround so navigationItems are not voice-over selectable while hidden by - // the search view. We might have to re factor the view hierarchy in order to - // properly solve this issue. See: https://codereview.chromium.org/2605023002/ - self.navigationItem.leftBarButtonItem = nil; - self.navigationItem.rightBarButtonItem = nil; -} - -- (void)exitSearchMode { - if (_historyCollectionController.searching) { - // Resets the navigation items to their initial state. - self.navigationItem.leftBarButtonItem = _leftBarButtonItem; - self.navigationItem.rightBarButtonItem = _rightBarButtonItem; - [self configureNavigationBar]; - - [[_searchViewController view] removeFromSuperview]; - [_searchViewController removeFromParentViewController]; - _historyCollectionController.searching = NO; - [_historyCollectionController showHistoryMatchingQuery:nil]; - } -} - -- (void)configureNavigationBar { - // The search button should only be enabled if there are history entries to - // search, and if history is not in edit mode. - self.navigationItem.leftBarButtonItem.enabled = - ![_historyCollectionController isEmpty] && - ![_historyCollectionController isEditing]; -} - -- (void)configureClearBrowsingBar { - _clearBrowsingBar.editing = _historyCollectionController.editing; - _clearBrowsingBar.deleteButtonEnabled = - [_historyCollectionController hasSelectedEntries]; - _clearBrowsingBar.editButtonEnabled = ![_historyCollectionController isEmpty]; -} - -#pragma mark - UIResponder - -- (BOOL)canBecomeFirstResponder { - return YES; -} - -- (NSArray*)keyCommands { - __weak HistoryPanelViewController* weakSelf = self; - return @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape - modifierFlags:Cr_UIKeyModifierNone - title:nil - action:^{ - [weakSelf closeHistory]; - }] ]; -} - -@end
diff --git a/ios/chrome/browser/ui/history/history_search_view.h b/ios/chrome/browser/ui/history/history_search_view.h deleted file mode 100644 index 6628cda..0000000 --- a/ios/chrome/browser/ui/history/history_search_view.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_H_ - -#import <UIKit/UIKit.h> - -// View for displaying a search bar in history. -@interface HistorySearchView : UIView - -// YES if the search view is in an enabled state. When not enabled, the search -// view text is greyed out, the clear button is removed, and the cancel button -// is disabled. -@property(nonatomic, getter=isEnabled) BOOL enabled; - -// Sets the target/action of the cancel button. -- (void)setCancelTarget:(id)target action:(SEL)action; - -// Sets the delegate of the search bar. -- (void)setSearchBarDelegate:(id<UITextFieldDelegate>)delegate; - -// Clears the search bar text. -- (void)clearText; - -@end - -#endif // IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_H_
diff --git a/ios/chrome/browser/ui/history/history_search_view.mm b/ios/chrome/browser/ui/history/history_search_view.mm deleted file mode 100644 index 1e06e2754..0000000 --- a/ios/chrome/browser/ui/history/history_search_view.mm +++ /dev/null
@@ -1,134 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/history_search_view.h" - -#include "components/strings/grit/components_strings.h" -#include "ios/chrome/browser/ui/uikit_ui_util.h" -#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" -#include "ui/base/l10n/l10n_util_mac.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { -// Shadow opacity for the search view. -CGFloat kShadowOpacity = 0.2f; -// Margin for the search view. -CGFloat kHorizontalMargin = 16.0f; -} // namespace - -@interface HistorySearchView () - -// Stack view for laying out the text field and cancel button. -@property(nonatomic, strong) UIStackView* stackView; -// Text field for the search view. -@property(nonatomic, strong) UITextField* textField; -// Cancel button for dismissing the search view. -@property(nonatomic, strong) UIButton* cancelButton; -// Constraint for the top anchor. -@property(nonatomic, strong) NSLayoutConstraint* topAnchorConstraint; - -@end - -@implementation HistorySearchView - -@synthesize enabled = _enabled; -@synthesize stackView = _stackView; -@synthesize textField = _textField; -@synthesize cancelButton = _cancelButton; -@synthesize topAnchorConstraint = _topAnchorConstraint; - -- (instancetype)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - [self setBackgroundColor:[UIColor whiteColor]]; - [[self layer] setShadowOpacity:kShadowOpacity]; - - _textField = [[UITextField alloc] init]; - _textField.contentVerticalAlignment = - UIControlContentVerticalAlignmentCenter; - _textField.backgroundColor = [UIColor whiteColor]; - _textField.textColor = - [UIColor colorWithWhite:0 alpha:[MDCTypography body1FontOpacity]]; - _textField.font = [MDCTypography subheadFont]; - _textField.borderStyle = UITextBorderStyleNone; - [_textField setLeftViewMode:UITextFieldViewModeNever]; - _textField.clearButtonMode = UITextFieldViewModeAlways; - _textField.placeholder = l10n_util::GetNSString(IDS_HISTORY_SEARCH_BUTTON); - - _cancelButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [_cancelButton setImage:[UIImage imageNamed:@"collapse"] - forState:UIControlStateNormal]; - [_cancelButton setImage:[UIImage imageNamed:@"collapse_pressed"] - forState:UIControlStateHighlighted]; - [_cancelButton - setContentCompressionResistancePriority:UILayoutPriorityRequired - forAxis: - UILayoutConstraintAxisHorizontal]; - [_cancelButton setContentHuggingPriority:UILayoutPriorityRequired - forAxis:UILayoutConstraintAxisHorizontal]; - [_cancelButton setAccessibilityLabel:l10n_util::GetNSString(IDS_CANCEL)]; - - _stackView = [[UIStackView alloc] - initWithArrangedSubviews:@[ _textField, _cancelButton ]]; - _stackView.alignment = UIStackViewAlignmentFill; - _stackView.axis = UILayoutConstraintAxisHorizontal; - _stackView.distribution = UIStackViewDistributionFill; - [self addSubview:_stackView]; - _stackView.translatesAutoresizingMaskIntoConstraints = NO; - _stackView.layoutMarginsRelativeArrangement = YES; - - CGFloat topAnchorConstant = IsCompactWidth() ? StatusBarHeight() : 0; - _topAnchorConstraint = - [_stackView.topAnchor constraintEqualToAnchor:self.topAnchor - constant:topAnchorConstant]; - [NSLayoutConstraint activateConstraints:@[ - _topAnchorConstraint, - [_stackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], - [_stackView.layoutMarginsGuide.leadingAnchor - constraintEqualToAnchor:self.leadingAnchor - constant:kHorizontalMargin], - [_stackView.layoutMarginsGuide.trailingAnchor - constraintEqualToAnchor:self.trailingAnchor - constant:-kHorizontalMargin], - ]]; - } - return self; -} - -- (BOOL)becomeFirstResponder { - return [self.textField becomeFirstResponder]; -} - -- (void)setEnabled:(BOOL)enabled { - _enabled = enabled; - self.cancelButton.enabled = enabled; - self.textField.enabled = enabled; - self.textField.clearButtonMode = - enabled ? UITextFieldViewModeAlways : UITextFieldViewModeNever; -} - -- (void)setCancelTarget:(id)target action:(SEL)action { - [_cancelButton addTarget:target - action:action - forControlEvents:UIControlEventTouchUpInside]; -} - -- (void)setSearchBarDelegate:(id<UITextFieldDelegate>)delegate { - [self.textField setDelegate:delegate]; -} - -- (void)clearText { - self.textField.text = nil; -} - -#pragma mark - UITraitEnvironment - -- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { - self.topAnchorConstraint.constant = IsCompactWidth() ? StatusBarHeight() : 0; -} - -@end
diff --git a/ios/chrome/browser/ui/history/history_search_view_controller.h b/ios/chrome/browser/ui/history/history_search_view_controller.h deleted file mode 100644 index 5305fd74..0000000 --- a/ios/chrome/browser/ui/history/history_search_view_controller.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_CONTROLLER_H_ - -#import <UIKit/UIKit.h> - -@class HistorySearchViewController; - -// Delegate for HistorySearchViewController. Used to pass on search bar -// interactions. -@protocol HistorySearchViewControllerDelegate<NSObject> -// Called when the search button is clicked. -- (void)historySearchViewController: - (HistorySearchViewController*)historySearchViewController - didRequestSearchForTerm:(NSString*)searchTerm; -// Called when the search view's cancel button is clicked. -- (void)historySearchViewControllerDidCancel: - (HistorySearchViewController*)historySearchViewController; -@end - -// Controller for the search bar used in the history panel. -@interface HistorySearchViewController : UIViewController - -// Delegate for forwarding interactions with the search view. -@property(nonatomic, weak) id<HistorySearchViewControllerDelegate> delegate; -// YES if the search view is enabled. Setting this property enables or disables -// the search view, as appropriate. -@property(nonatomic, getter=isEnabled) BOOL enabled; -@end - -#endif // IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/history/history_search_view_controller.mm b/ios/chrome/browser/ui/history/history_search_view_controller.mm deleted file mode 100644 index 653e5b7..0000000 --- a/ios/chrome/browser/ui/history/history_search_view_controller.mm +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/history_search_view_controller.h" - -#import "ios/chrome/browser/ui/history/history_search_view.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface HistorySearchViewController ()<UITextFieldDelegate> { - // View displayed by the HistorySearchViewController - HistorySearchView* _searchView; -} - -// Action for the cancel button. -- (void)cancelButtonClicked:(id)sender; - -@end - -@implementation HistorySearchViewController -@synthesize delegate = _delegate; -@synthesize enabled = _enabled; - -- (void)loadView { - _searchView = [[HistorySearchView alloc] init]; - [_searchView setSearchBarDelegate:self]; - [_searchView setCancelTarget:self action:@selector(cancelButtonClicked:)]; - self.view = _searchView; -} - -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [_searchView becomeFirstResponder]; -} - -- (void)setEnabled:(BOOL)enabled { - _enabled = enabled; - [_searchView setEnabled:enabled]; -} - -- (void)cancelButtonClicked:(id)sender { - [_searchView clearText]; - [_searchView endEditing:YES]; - [self.delegate historySearchViewControllerDidCancel:self]; -} - -#pragma mark - UITextFieldDelegate - -- (BOOL)textField:(UITextField*)textField - shouldChangeCharactersInRange:(NSRange)range - replacementString:(NSString*)string { - NSMutableString* text = [NSMutableString stringWithString:[textField text]]; - [text replaceCharactersInRange:range withString:string]; - [self.delegate historySearchViewController:self didRequestSearchForTerm:text]; - return YES; -} - -- (BOOL)textFieldShouldClear:(UITextField*)textField { - [self.delegate historySearchViewController:self didRequestSearchForTerm:@""]; - return YES; -} - -- (BOOL)textFieldShouldReturn:(UITextField*)textField { - [textField resignFirstResponder]; - return YES; -} - -@end
diff --git a/ios/chrome/browser/ui/history/history_search_view_controller_unittest.mm b/ios/chrome/browser/ui/history/history_search_view_controller_unittest.mm deleted file mode 100644 index 35ecd7a7..0000000 --- a/ios/chrome/browser/ui/history/history_search_view_controller_unittest.mm +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/history_search_view_controller.h" - -#include "base/mac/foundation_util.h" -#import "ios/chrome/browser/ui/history/history_search_view.h" -#include "testing/platform_test.h" -#import "third_party/ocmock/OCMock/OCMock.h" -#import "third_party/ocmock/gtest_support.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -// HistorySearchView category to expose the text field and cancel button. -@interface HistorySearchView (Testing) -@property(nonatomic, strong) UITextField* textField; -@property(nonatomic, strong) UIButton* cancelButton; -@end - -// Test fixture for HistorySearchViewController. -class HistorySearchViewControllerTest : public PlatformTest { - public: - HistorySearchViewControllerTest() { - search_view_controller_ = [[HistorySearchViewController alloc] init]; - [search_view_controller_ loadView]; - mock_delegate_ = [OCMockObject - mockForProtocol:@protocol(HistorySearchViewControllerDelegate)]; - [search_view_controller_ setDelegate:mock_delegate_]; - } - - protected: - __strong HistorySearchViewController* search_view_controller_; - __strong id<HistorySearchViewControllerDelegate> mock_delegate_; -}; - -// Test that pressing the cancel button invokes delegate callback to cancel -// search. -TEST_F(HistorySearchViewControllerTest, DISABLED_CancelButtonPressed) { - UIButton* cancel_button = - base::mac::ObjCCastStrict<HistorySearchView>(search_view_controller_.view) - .cancelButton; - OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_; - [[mock_delegate expect] - historySearchViewControllerDidCancel:search_view_controller_]; - [cancel_button sendActionsForControlEvents:UIControlEventTouchUpInside]; - EXPECT_OCMOCK_VERIFY(mock_delegate_); -} - -// Test that invocation of -// textField:shouldChangeCharactersInRange:replacementString: on the text field -// delegate results invokes delegate callback to request search. -TEST_F(HistorySearchViewControllerTest, DISABLED_SearchButtonPressed) { - UITextField* text_field = - base::mac::ObjCCastStrict<HistorySearchView>(search_view_controller_.view) - .textField; - OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_; - [[mock_delegate expect] historySearchViewController:search_view_controller_ - didRequestSearchForTerm:@"a"]; - [text_field.delegate textField:text_field - shouldChangeCharactersInRange:NSMakeRange(0, 0) - replacementString:@"a"]; - EXPECT_OCMOCK_VERIFY(mock_delegate); -} - -// Test that disabling HistorySearchViewController disables the search view text -// field. -TEST_F(HistorySearchViewControllerTest, DISABLED_DisableSearchBar) { - UITextField* text_field = - base::mac::ObjCCastStrict<HistorySearchView>(search_view_controller_.view) - .textField; - DCHECK(text_field); - EXPECT_TRUE(text_field.enabled); - - search_view_controller_.enabled = NO; - EXPECT_FALSE(text_field.enabled); - - search_view_controller_.enabled = YES; - EXPECT_TRUE(text_field.enabled); -}
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm index 80d2c76e..95cc0a2 100644 --- a/ios/chrome/browser/ui/history/history_ui_egtest.mm +++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -18,7 +18,6 @@ #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h" #import "ios/chrome/browser/ui/authentication/signin_promo_view.h" #import "ios/chrome/browser/ui/history/history_ui_constants.h" -#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h" #import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h" #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_constants.h" @@ -66,7 +65,6 @@ NSString* url_spec_text = nil; NSString* title_text = base::SysUTF8ToNSString(title); - if (IsUIRefreshPhase1Enabled()) { url_spec_text = base::SysUTF8ToNSString(url.GetOrigin().spec()); MatchesBlock matches = ^BOOL(TableViewURLCell* cell) { @@ -85,26 +83,6 @@ [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches descriptionBlock:describe], grey_sufficientlyVisible(), nil); - } else { - url_spec_text = base::SysUTF8ToNSString(url.spec()); - - MatchesBlock matches = ^BOOL(LegacyHistoryEntryCell* cell) { - return [cell.textLabel.text isEqual:title_text] && - [cell.detailTextLabel.text isEqual:url_spec_text]; - }; - - DescribeToBlock describe = ^(id<GREYDescription> description) { - [description appendText:@"view containing URL text: "]; - [description appendText:url_spec_text]; - [description appendText:@" title text: "]; - [description appendText:title_text]; - }; - return grey_allOf( - grey_kindOfClass([LegacyHistoryEntryCell class]), - [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches - descriptionBlock:describe], - grey_sufficientlyVisible(), nil); - } } // Matcher for the history button in the tools menu. id<GREYMatcher> HistoryButton() { @@ -120,11 +98,7 @@ } // Matcher for the search button. id<GREYMatcher> SearchIconButton() { - if (IsUIRefreshPhase1Enabled()) { return grey_accessibilityID(kHistorySearchControllerSearchBarIdentifier); - } else { - return ButtonWithAccessibilityLabelId(IDS_IOS_ICON_SEARCH); - } } // Matcher for the cancel button. id<GREYMatcher> CancelButton() { @@ -256,29 +230,21 @@ [[EarlGrey selectElementWithMatcher:SearchIconButton()] performAction:grey_tap()]; - if (IsUIRefreshPhase1Enabled()) { // Verify that scrim is visible. [[EarlGrey selectElementWithMatcher:grey_accessibilityID( kHistorySearchScrimIdentifier)] assertWithMatcher:grey_notNil()]; - } NSString* searchString = [NSString stringWithFormat:@"%s", _URL1.path().c_str()]; - if (IsUIRefreshPhase1Enabled()) { - [[EarlGrey selectElementWithMatcher:SearchIconButton()] - performAction:grey_typeText(searchString)]; - } else { - [[EarlGrey selectElementWithMatcher:grey_keyWindow()] - performAction:grey_typeText(searchString)]; - } - if (IsUIRefreshPhase1Enabled()) { - // Verify that scrim is not visible. - [[EarlGrey selectElementWithMatcher:grey_accessibilityID( - kHistorySearchScrimIdentifier)] - assertWithMatcher:grey_nil()]; - } + [[EarlGrey selectElementWithMatcher:SearchIconButton()] + performAction:grey_typeText(searchString)]; + + // Verify that scrim is not visible. + [[EarlGrey selectElementWithMatcher:grey_accessibilityID( + kHistorySearchScrimIdentifier)] + assertWithMatcher:grey_nil()]; [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] assertWithMatcher:grey_notNil()]; @@ -414,14 +380,9 @@ [self openHistoryPanel]; chrome_test_util::VerifyAccessibilityForCurrentScreen(); // Close history. - if (IsUIRefreshPhase1Enabled()) { id<GREYMatcher> exitMatcher = grey_accessibilityID(kHistoryNavigationControllerDoneButtonIdentifier); [[EarlGrey selectElementWithMatcher:exitMatcher] performAction:grey_tap()]; - } else { - [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()] - performAction:grey_tap()]; - } } #pragma mark Helper Methods
diff --git a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h b/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h deleted file mode 100644 index a319554..0000000 --- a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_COLLECTION_VIEW_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_COLLECTION_VIEW_CONTROLLER_H_ - -#import "ios/chrome/browser/ui/collection_view/collection_view_controller.h" - -#include "base/ios/block_types.h" -#include "ios/chrome/browser/ui/history/history_consumer.h" - -namespace ios { -class ChromeBrowserState; -} - -@class LegacyHistoryCollectionViewController; -@protocol UrlLoader; - -// Delegate for the history collection view controller. -@protocol LegacyHistoryCollectionViewControllerDelegate<NSObject> -// Notifies the delegate that history should be dismissed. -- (void)historyCollectionViewController: - (LegacyHistoryCollectionViewController*)controller - shouldCloseWithCompletion:(ProceduralBlock)completionHandler; -// Notifies the delegate that the collection view has scrolled to |offset|. -- (void)historyCollectionViewController: - (LegacyHistoryCollectionViewController*)controller - didScrollToOffset:(CGPoint)offset; -// Notifies the delegate that history entries have been loaded or changed. -- (void)historyCollectionViewControllerDidChangeEntries: - (LegacyHistoryCollectionViewController*)controller; -// Notifies the delegate that history entries have been selected or deselected. -- (void)historyCollectionViewControllerDidChangeEntrySelection: - (LegacyHistoryCollectionViewController*)controller; -@end - -// View controller for displaying a collection of history entries. -@interface LegacyHistoryCollectionViewController - : CollectionViewController<HistoryConsumer> -// YES if the collection view is in editing mode. Setting |editing| turns -// editing mode on or off accordingly. -@property(nonatomic, assign, getter=isEditing) BOOL editing; -// YES if the the search bar is present. -@property(nonatomic, assign, getter=isSearching) BOOL searching; -// YES if collection is currently displaying no history entries. -@property(nonatomic, assign, readonly, getter=isEmpty) BOOL empty; -// YES if the collection view has selected entries while in editing mode. -@property(nonatomic, assign, readonly) BOOL hasSelectedEntries; -// Abstraction to communicate with HistoryService and WebHistoryService. -// Not owned by LegacyHistoryCollectionViewController. -@property(nonatomic, assign) history::BrowsingHistoryService* historyService; - -- (instancetype) -initWithLoader:(id<UrlLoader>)loader - browserState:(ios::ChromeBrowserState*)browserState - delegate:(id<LegacyHistoryCollectionViewControllerDelegate>)delegate - NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithLayout:(UICollectionViewLayout*)layout - style:(CollectionViewControllerStyle)style - NS_UNAVAILABLE; - -// Search history for text |query| and display the results. |query| may be nil. -// If query is empty, show all history. -- (void)showHistoryMatchingQuery:(NSString*)query; - -// Deletes selected items from browser history and removes them from the -// collection. -- (void)deleteSelectedItemsFromHistory; - -@end - -#endif // IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_COLLECTION_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm b/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm deleted file mode 100644 index 3bcfddc5..0000000 --- a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm +++ /dev/null
@@ -1,911 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h" - -#import <MobileCoreServices/MobileCoreServices.h> - -#include <memory> - -#include "base/callback.h" -#include "base/mac/foundation_util.h" -#include "base/metrics/user_metrics.h" -#include "base/metrics/user_metrics_action.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "components/browsing_data/core/history_notice_utils.h" -#include "components/strings/grit/components_strings.h" -#include "components/url_formatter/url_formatter.h" -#include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/chrome_url_constants.h" -#import "ios/chrome/browser/metrics/new_tab_page_uma.h" -#import "ios/chrome/browser/signin/authentication_service.h" -#include "ios/chrome/browser/signin/authentication_service_factory.h" -#include "ios/chrome/browser/sync/sync_setup_service.h" -#include "ios/chrome/browser/sync/sync_setup_service_factory.h" -#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h" -#import "ios/chrome/browser/ui/collection_view/cells/activity_indicator_cell.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h" -#import "ios/chrome/browser/ui/collection_view/collection_view_model.h" -#import "ios/chrome/browser/ui/commands/open_new_tab_command.h" -#import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h" -#import "ios/chrome/browser/ui/history/features.h" -#import "ios/chrome/browser/ui/history/history_entries_status_item_delegate.h" -#include "ios/chrome/browser/ui/history/history_entry_inserter.h" -#import "ios/chrome/browser/ui/history/history_entry_item_delegate.h" -#include "ios/chrome/browser/ui/history/history_util.h" -#include "ios/chrome/browser/ui/history/legacy_history_entries_status_item.h" -#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h" -#import "ios/chrome/browser/ui/url_loader.h" -#import "ios/chrome/browser/ui/util/pasteboard_util.h" -#import "ios/chrome/browser/ui/util/top_view_controller.h" -#include "ios/chrome/grit/ios_strings.h" -#import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MDCActivityIndicator.h" -#import "ios/third_party/material_components_ios/src/components/Collections/src/MaterialCollections.h" -#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h" -#import "ios/web/public/navigation_manager.h" -#import "ios/web/public/referrer.h" -#import "ios/web/public/web_state/context_menu_params.h" -#import "net/base/mac/url_conversions.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/l10n_util_mac.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -using history::BrowsingHistoryService; - -namespace { -typedef NS_ENUM(NSInteger, ItemType) { - ItemTypeHistoryEntry = kItemTypeEnumZero, - ItemTypeEntriesStatus, - ItemTypeActivityIndicator, -}; -// Section identifier for the header (sync information) section. -const NSInteger kEntriesStatusSectionIdentifier = kSectionIdentifierEnumZero; -// Maximum number of entries to retrieve in a single query to history service. -const int kMaxFetchCount = 100; -// Horizontal inset for item separators. -const CGFloat kSeparatorInset = 10; -} - -@interface LegacyHistoryCollectionViewController ()< - HistoryEntriesStatusItemDelegate, - HistoryEntryInserterDelegate, - HistoryEntryItemDelegate> { - // The main browser state. Not owned by HistoryCollectionViewController. - ios::ChromeBrowserState* _browserState; - // Backing ivar for delegate property. - __weak id<LegacyHistoryCollectionViewControllerDelegate> _delegate; - // Backing ivar for URLLoader property. - __weak id<UrlLoader> _URLLoader; - // Closure to request next page of history. - base::OnceClosure _query_history_continuation; -} - -// Object to manage insertion of history entries into the collection view model. -@property(nonatomic, strong) HistoryEntryInserter* entryInserter; -// Delegate for the history collection view. -@property(nonatomic, weak, readonly) - id<LegacyHistoryCollectionViewControllerDelegate> - delegate; -// UrlLoader for navigating to history entries. -@property(nonatomic, weak, readonly) id<UrlLoader> URLLoader; -// The current query for visible history entries. -@property(nonatomic, copy) NSString* currentQuery; -// Coordinator for displaying context menus for history entries. -@property(nonatomic, strong) ContextMenuCoordinator* contextMenuCoordinator; -// YES if there are no results to show. -@property(nonatomic, assign) BOOL empty; -// YES if the history panel should show a notice about additional forms of -// browsing history. -@property(nonatomic, assign) - BOOL shouldShowNoticeAboutOtherFormsOfBrowsingHistory; -// YES if there is an outstanding history query. -@property(nonatomic, assign, getter=isLoading) BOOL loading; -// YES if there are no more history entries to load. -@property(nonatomic, assign, getter=hasFinishedLoading) BOOL finishedLoading; -// YES if the collection should be filtered by the next received query result. -@property(nonatomic, assign) BOOL filterQueryResult; - -// Fetches history for search text |query|. If |query| is nil or the empty -// string, all history is fetched. If continuation is false, then the most -// recent results are fetched, otherwise the results more recent than the -// previous query will be returned. -- (void)fetchHistoryForQuery:(NSString*)query continuation:(BOOL)continuation; -// Updates various elements after history items have been deleted from the -// CollectionView. -- (void)updateCollectionViewAfterDeletingEntries; -// Updates header section to provide relevant information about the currently -// displayed history entries. -- (void)updateEntriesStatusMessage; -// Removes selected items from the visible collection, but does not delete them -// from browser history. -- (void)removeSelectedItemsFromCollection; -// Selects all items in the collection that are not included in entries. -- (void)filterForHistoryEntries:(NSArray*)entries; -// Deletes all items in the collection which indexes are included in indexArray, -// needs to be run inside a performBatchUpdates block. -- (void)deleteItemsFromCollectionViewModelWithIndex:(NSArray*)indexArray; -// Adds loading indicator to the top of the history collection, if one is not -// already present. -- (void)addLoadingIndicator; -// Displays context menu on cell pressed with gestureRecognizer. -- (void)displayContextMenuInvokedByGestureRecognizer: - (UILongPressGestureRecognizer*)gestureRecognizer; -// Opens URL in the current tab and dismisses the history view. -- (void)openURL:(const GURL&)URL; -// Opens URL in a new non-incognito tab and dismisses the history view. -- (void)openURLInNewTab:(const GURL&)URL; -// Opens URL in a new incognito tab and dismisses the history view. -- (void)openURLInNewIncognitoTab:(const GURL&)URL; -@end - -@implementation LegacyHistoryCollectionViewController - -@synthesize searching = _searching; -@synthesize entryInserter = _entryInserter; -@synthesize currentQuery = _currentQuery; -@synthesize contextMenuCoordinator = _contextMenuCoordinator; -@synthesize empty = _empty; -@synthesize shouldShowNoticeAboutOtherFormsOfBrowsingHistory = - _shouldShowNoticeAboutOtherFormsOfBrowsingHistory; -@synthesize loading = _loading; -@synthesize finishedLoading = _finishedLoading; -@synthesize filterQueryResult = _filterQueryResult; -@synthesize historyService = _historyService; - -- (instancetype) -initWithLoader:(id<UrlLoader>)loader - browserState:(ios::ChromeBrowserState*)browserState - delegate:(id<LegacyHistoryCollectionViewControllerDelegate>)delegate { - UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init]; - self = - [super initWithLayout:layout style:CollectionViewControllerStyleDefault]; - if (self) { - _browserState = browserState; - _delegate = delegate; - _URLLoader = loader; - // TODO(crbug.com/764578): -loadModel should not be called from - // initializer. A possible fix is to move this call to -viewDidLoad. - // Consider moving the other complex code out of the initializer as well. - [self loadModel]; - // Add initial info section as header. - [self.collectionViewModel - addSectionWithIdentifier:kEntriesStatusSectionIdentifier]; - _entryInserter = - [[HistoryEntryInserter alloc] initWithModel:self.collectionViewModel]; - _entryInserter.delegate = self; - _empty = YES; - } - return self; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - [self showHistoryMatchingQuery:nil]; - self.styler.cellLayoutType = MDCCollectionViewCellLayoutTypeList; - self.styler.separatorInset = - UIEdgeInsetsMake(0, kSeparatorInset, 0, kSeparatorInset); - self.styler.allowsItemInlay = NO; - - // Never adjust the content inset on iOS11 or it will create padding on top of - // the first cell. - if (@available(iOS 11, *)) { - [self.collectionView setContentInsetAdjustmentBehavior: - UIScrollViewContentInsetAdjustmentNever]; - } - - self.clearsSelectionOnViewWillAppear = NO; - self.collectionView.keyboardDismissMode = - UIScrollViewKeyboardDismissModeOnDrag; - - UILongPressGestureRecognizer* longPressRecognizer = [ - [UILongPressGestureRecognizer alloc] - initWithTarget:self - action:@selector(displayContextMenuInvokedByGestureRecognizer:)]; - [self.collectionView addGestureRecognizer:longPressRecognizer]; -} - -// Since contentInsetAdjustmentBehavior is -// UIScrollViewContentInsetAdjustmentNever on iOS11, update the horizontal -// insets manually to respect the safeArea. -- (void)viewSafeAreaInsetsDidChange { - [super viewSafeAreaInsetsDidChange]; - UIEdgeInsets collectionContentInsets = self.collectionView.contentInset; - collectionContentInsets.left = self.view.safeAreaInsets.left; - collectionContentInsets.right = self.view.safeAreaInsets.right; - self.collectionView.contentInset = collectionContentInsets; -} - -- (BOOL)isEditing { - return self.editor.isEditing; -} - -- (void)setEditing:(BOOL)editing { - [self.editor setEditing:editing animated:YES]; -} - -- (void)setSearching:(BOOL)searching { - _searching = searching; - [self updateEntriesStatusMessage]; -} - -- (BOOL)hasSelectedEntries { - return self.collectionView.indexPathsForSelectedItems.count; -} - -- (void)showHistoryMatchingQuery:(NSString*)query { - self.finishedLoading = NO; - self.currentQuery = query; - [self fetchHistoryForQuery:query continuation:false]; -} - -- (void)deleteSelectedItemsFromHistory { - NSArray* deletedIndexPaths = self.collectionView.indexPathsForSelectedItems; - std::vector<BrowsingHistoryService::HistoryEntry> entries; - for (NSIndexPath* indexPath in deletedIndexPaths) { - LegacyHistoryEntryItem* object = - base::mac::ObjCCastStrict<LegacyHistoryEntryItem>( - [self.collectionViewModel itemAtIndexPath:indexPath]); - BrowsingHistoryService::HistoryEntry entry; - entry.url = object.URL; - entry.all_timestamps.insert(object.timestamp.ToInternalValue()); - entries.push_back(entry); - } - self.historyService->RemoveVisits(entries); - [self removeSelectedItemsFromCollection]; -} - -- (id<LegacyHistoryCollectionViewControllerDelegate>)delegate { - return _delegate; -} - -- (id<UrlLoader>)URLLoader { - return _URLLoader; -} - -#pragma mark - MDCollectionViewController - -// TODO(crbug.com/653547): Remove this once the MDC adds an option for -// preventing the infobar from showing. -- (void)updateFooterInfoBarIfNecessary { - // No-op. This prevents the default infobar from showing. -} - -#pragma mark - HistoryEntriesStatusItemDelegate - -- (void)historyEntriesStatusItem:(LegacyHistoryEntriesStatusItem*)item - didRequestOpenURL:(const GURL&)URL { - [self openURLInNewTab:URL]; -} - -#pragma mark - HistoryEntryInserterDelegate - -- (void)historyEntryInserter:(HistoryEntryInserter*)inserter - didInsertItemAtIndexPath:(NSIndexPath*)indexPath { - [self.collectionView insertItemsAtIndexPaths:@[ indexPath ]]; -} - -- (void)historyEntryInserter:(HistoryEntryInserter*)inserter - didInsertSectionAtIndex:(NSInteger)sectionIndex { - [self.collectionView - insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]]; -} - -- (void)historyEntryInserter:(HistoryEntryInserter*)inserter - didRemoveSectionAtIndex:(NSInteger)sectionIndex { - [self.collectionView - deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]]; -} - -#pragma mark - LegacyHistoryEntryItemDelegate - -- (void)historyEntryItemDidRequestOpen:(LegacyHistoryEntryItem*)item { - [self openURL:item.URL]; -} - -- (void)historyEntryItemDidRequestDelete:(LegacyHistoryEntryItem*)item { - NSInteger sectionIdentifier = - [self.entryInserter sectionIdentifierForTimestamp:item.timestamp]; - if ([self.collectionViewModel - hasSectionForSectionIdentifier:sectionIdentifier] && - [self.collectionViewModel hasItem:item - inSectionWithIdentifier:sectionIdentifier]) { - NSIndexPath* indexPath = [self.collectionViewModel indexPathForItem:item]; - [self.collectionView - selectItemAtIndexPath:indexPath - animated:NO - scrollPosition:UICollectionViewScrollPositionNone]; - [self deleteSelectedItemsFromHistory]; - } -} - -- (void)historyEntryItemDidRequestCopy:(LegacyHistoryEntryItem*)item { - StoreURLInPasteboard(item.URL); -} - -- (void)historyEntryItemDidRequestOpenInNewTab:(LegacyHistoryEntryItem*)item { - [self openURLInNewTab:item.URL]; -} - -- (void)historyEntryItemDidRequestOpenInNewIncognitoTab: - (LegacyHistoryEntryItem*)item { - [self openURLInNewIncognitoTab:item.URL]; -} - -- (void)historyEntryItemShouldUpdateView:(LegacyHistoryEntryItem*)item { - NSInteger sectionIdentifier = - [self.entryInserter sectionIdentifierForTimestamp:item.timestamp]; - // If the item is still in the model, reconfigure it. - if ([self.collectionViewModel - hasSectionForSectionIdentifier:sectionIdentifier] && - [self.collectionViewModel hasItem:item - inSectionWithIdentifier:sectionIdentifier]) { - [self reconfigureCellsForItems:@[ item ]]; - } -} - -#pragma mark - HistoryConsumer - -- (void)historyQueryWasCompletedWithResults: - (const std::vector<BrowsingHistoryService::HistoryEntry>&)results - queryResultsInfo: - (const BrowsingHistoryService::QueryResultsInfo&) - queryResultsInfo - continuationClosure: - (base::OnceClosure)continuationClosure { - self.loading = NO; - _query_history_continuation = std::move(continuationClosure); - - // If history sync is enabled and there hasn't been a response from synced - // history, try fetching again. - SyncSetupService* syncSetupService = - SyncSetupServiceFactory::GetForBrowserState(_browserState); - if (syncSetupService->IsSyncEnabled() && - syncSetupService->IsDataTypeActive(syncer::HISTORY_DELETE_DIRECTIVES) && - queryResultsInfo.sync_timed_out) { - [self showHistoryMatchingQuery:_currentQuery]; - return; - } - - // If there are no results and no URLs have been loaded, report that no - // history entries were found. - if (results.empty() && self.isEmpty) { - [self updateEntriesStatusMessage]; - [self.delegate historyCollectionViewControllerDidChangeEntries:self]; - return; - } - - self.finishedLoading = queryResultsInfo.reached_beginning; - self.empty = NO; - - // Header section should be updated outside of batch updates, otherwise - // loading indicator removal will not be observed. - [self updateEntriesStatusMessage]; - - if (base::FeatureList::IsEnabled(kHistoryBatchUpdatesFilter)) { - NSMutableArray* resultsItems = [NSMutableArray array]; - NSString* searchQuery = - [base::SysUTF16ToNSString(queryResultsInfo.search_text) copy]; - [self.collectionView performBatchUpdates:^{ - // There should always be at least a header section present. - DCHECK([[self collectionViewModel] numberOfSections]); - for (const BrowsingHistoryService::HistoryEntry& entry : results) { - LegacyHistoryEntryItem* item = - [[LegacyHistoryEntryItem alloc] initWithType:ItemTypeHistoryEntry - historyEntry:entry - browserState:_browserState - delegate:self]; - [resultsItems addObject:item]; - } - [self.delegate historyCollectionViewControllerDidChangeEntries:self]; - if (([self isSearching] && [searchQuery length] > 0 && - [self.currentQuery isEqualToString:searchQuery]) || - self.filterQueryResult) { - // If in search mode, filter out entries that are not part of the - // search result. - [self filterForHistoryEntries:resultsItems]; - NSArray* deletedIndexPaths = - self.collectionView.indexPathsForSelectedItems; - [self deleteItemsFromCollectionViewModelWithIndex:deletedIndexPaths]; - self.filterQueryResult = NO; - } - // Wait to insert until after the deletions are done, this is needed - // because performBatchUpdates processes deletion indexes first, and then - // inserts. - for (LegacyHistoryEntryItem* item in resultsItems) { - [self.entryInserter insertHistoryEntryItem:item]; - } - } - completion:^(BOOL) { - [self updateCollectionViewAfterDeletingEntries]; - }]; - } else { - NSMutableArray* filterResults = [NSMutableArray array]; - NSString* searchQuery = - [base::SysUTF16ToNSString(queryResultsInfo.search_text) copy]; - [self.collectionView performBatchUpdates:^{ - // There should always be at least a header section present. - DCHECK([[self collectionViewModel] numberOfSections]); - for (const BrowsingHistoryService::HistoryEntry& entry : results) { - LegacyHistoryEntryItem* item = - [[LegacyHistoryEntryItem alloc] initWithType:ItemTypeHistoryEntry - historyEntry:entry - browserState:_browserState - delegate:self]; - [self.entryInserter insertHistoryEntryItem:item]; - if ([self isSearching] || self.filterQueryResult) { - [filterResults addObject:item]; - } - } - [self.delegate historyCollectionViewControllerDidChangeEntries:self]; - } - completion:^(BOOL) { - if (([self isSearching] && [searchQuery length] > 0 && - [self.currentQuery isEqualToString:searchQuery]) || - self.filterQueryResult) { - // If in search mode, filter out entries that are not part of the - // search result. - [self filterForHistoryEntries:filterResults]; - self.filterQueryResult = NO; - } - }]; - } -} - -- (void)showNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)shouldShowNotice { - self.shouldShowNoticeAboutOtherFormsOfBrowsingHistory = shouldShowNotice; - // Update the history entries status message if there is no query in progress. - if (!self.isLoading) { - [self updateEntriesStatusMessage]; - } -} - -- (void)historyWasDeleted { - // If history has been deleted, reload history filtering for the current - // results. This only observes local changes to history, i.e. removing - // history via the clear browsing data page. - self.filterQueryResult = YES; - [self showHistoryMatchingQuery:nil]; -} - -#pragma mark - MDCCollectionViewEditingDelegate - -- (BOOL)collectionViewAllowsEditing:(UICollectionView*)collectionView { - return YES; -} - -- (BOOL)collectionView:(UICollectionView*)collectionView - canEditItemAtIndexPath:(NSIndexPath*)indexPath { - // All items except those in the header section may be edited. - return indexPath.section; -} - -- (BOOL)collectionView:(UICollectionView*)collectionView - canSelectItemDuringEditingAtIndexPath:(NSIndexPath*)indexPath { - // All items except those in the header section may be edited. - return indexPath.section; -} - -#pragma mark - MDCCollectionViewStylingDelegate - -- (BOOL)collectionView:(UICollectionView*)collectionView - shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath { - // Display the entries status section (always the first section) without any - // background image or shadowing. - return !indexPath.section; -} - -- (BOOL)collectionView:(UICollectionView*)collectionView - hidesInkViewAtIndexPath:(NSIndexPath*)indexPath { - return [indexPath isEqual:[NSIndexPath indexPathForItem:0 inSection:0]]; -} - -- (CGFloat)collectionView:(UICollectionView*)collectionView - cellHeightAtIndexPath:(NSIndexPath*)indexPath { - if (indexPath.section) { - return MDCCellDefaultTwoLineHeight; - } else { - DCHECK([indexPath isEqual:[NSIndexPath indexPathForItem:0 inSection:0]]); - // Configure size for loading indicator and entries status cells. - CollectionViewItem* item = - [self.collectionViewModel itemAtIndexPath:indexPath]; - if ([item isKindOfClass:[CollectionViewTextItem class]]) { - return MDCCellDefaultOneLineHeight; - } - CGFloat height = [[item cellClass] - cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) - forItem:item]; - return height; - } -} - -- (MDCCollectionViewCellStyle)collectionView:(UICollectionView*)collectionView - cellStyleForSection:(NSInteger)section { - return section ? MDCCollectionViewCellStyleCard - : MDCCollectionViewCellStyleDefault; -} - -#pragma mark - UICollectionViewDelegate - -- (BOOL)collectionView:(UICollectionView*)collectionView - shouldSelectItemAtIndexPath:(NSIndexPath*)indexPath { - // The first section is not selectable. - return indexPath.section && [super collectionView:collectionView - shouldSelectItemAtIndexPath:indexPath]; -} - -- (void)collectionView:(UICollectionView*)collectionView - didSelectItemAtIndexPath:(NSIndexPath*)indexPath { - [super collectionView:collectionView didSelectItemAtIndexPath:indexPath]; - - if (self.isEditing) { - [self.delegate historyCollectionViewControllerDidChangeEntrySelection:self]; - } else { - LegacyHistoryEntryItem* item = - base::mac::ObjCCastStrict<LegacyHistoryEntryItem>( - [self.collectionViewModel itemAtIndexPath:indexPath]); - [self openURL:item.URL]; - if (self.isSearching) { - base::RecordAction( - base::UserMetricsAction("HistoryPage_SearchResultClick")); - } else { - base::RecordAction(base::UserMetricsAction("HistoryPage_EntryLinkClick")); - } - } -} - -- (void)collectionView:(UICollectionView*)collectionView - didDeselectItemAtIndexPath:(NSIndexPath*)indexPath { - [super collectionView:collectionView didDeselectItemAtIndexPath:indexPath]; - [self.delegate historyCollectionViewControllerDidChangeEntrySelection:self]; -} - -- (void)collectionView:(UICollectionView*)collectionView - didEndDisplayingCell:(UICollectionViewCell*)cell - forItemAtIndexPath:(NSIndexPath*)indexPath { - if ([cell isKindOfClass:[ActivityIndicatorCell class]]) { - [[base::mac::ObjCCast<ActivityIndicatorCell>(cell) activityIndicator] - stopAnimating]; - } -} -#pragma mark - UIScrollViewDelegate - -- (void)scrollViewDidScroll:(UIScrollView*)scrollView { - [super scrollViewDidScroll:scrollView]; - // Adjust header shadow. - [self.delegate historyCollectionViewController:self - didScrollToOffset:scrollView.contentOffset]; - - if (self.hasFinishedLoading) - return; - - CGFloat insetHeight = - scrollView.contentInset.top + scrollView.contentInset.bottom; - CGFloat contentViewHeight = scrollView.bounds.size.height - insetHeight; - CGFloat contentHeight = scrollView.contentSize.height; - CGFloat contentOffset = scrollView.contentOffset.y; - CGFloat buffer = contentViewHeight; - // If the scroll view is approaching the end of loaded history, try to fetch - // more history. Do so when the content offset is greater than the content - // height minus the view height, minus a buffer to start the fetch early. - if (contentOffset > (contentHeight - contentViewHeight) - buffer && - !self.isLoading) { - // If at end, try to grab more history. - NSInteger lastSection = [self.collectionViewModel numberOfSections] - 1; - NSInteger lastItemIndex = - [self.collectionViewModel numberOfItemsInSection:lastSection] - 1; - if (lastSection == 0 || lastItemIndex < 0) { - return; - } - - [self fetchHistoryForQuery:_currentQuery continuation:true]; - } -} - -#pragma mark - Private methods - -- (void)fetchHistoryForQuery:(NSString*)query continuation:(BOOL)continuation { - self.loading = YES; - // Add loading indicator if no items are shown. - if (self.isEmpty && !self.isSearching) { - [self addLoadingIndicator]; - } - - if (continuation) { - DCHECK(_query_history_continuation); - std::move(_query_history_continuation).Run(); - } else { - _query_history_continuation.Reset(); - - BOOL fetchAllHistory = !query || [query isEqualToString:@""]; - base::string16 queryString = - fetchAllHistory ? base::string16() : base::SysNSStringToUTF16(query); - history::QueryOptions options; - options.duplicate_policy = - fetchAllHistory ? history::QueryOptions::REMOVE_DUPLICATES_PER_DAY - : history::QueryOptions::REMOVE_ALL_DUPLICATES; - options.max_count = kMaxFetchCount; - options.matching_algorithm = - query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH; - self.historyService->QueryHistory(queryString, options); - } -} - -- (void)updateCollectionViewAfterDeletingEntries { - // If only the header section remains, there are no history entries. - if ([self.collectionViewModel numberOfSections] == 1) { - self.empty = YES; - } - [self updateEntriesStatusMessage]; - [self.delegate historyCollectionViewControllerDidChangeEntries:self]; -} - -- (void)updateEntriesStatusMessage { - CollectionViewItem* entriesStatusItem = nil; - if (self.isEmpty) { - CollectionViewTextItem* noResultsItem = - [[CollectionViewTextItem alloc] initWithType:ItemTypeEntriesStatus]; - noResultsItem.text = - self.isSearching ? l10n_util::GetNSString(IDS_HISTORY_NO_SEARCH_RESULTS) - : l10n_util::GetNSString(IDS_HISTORY_NO_RESULTS); - entriesStatusItem = noResultsItem; - } else if (self.shouldShowNoticeAboutOtherFormsOfBrowsingHistory) { - LegacyHistoryEntriesStatusItem* historyEntriesStatusItem = - [[LegacyHistoryEntriesStatusItem alloc] - initWithType:ItemTypeEntriesStatus]; - historyEntriesStatusItem.delegate = self; - historyEntriesStatusItem.hidden = self.isSearching; - entriesStatusItem = historyEntriesStatusItem; - } - // Replace the item in the first section if it exists. Then insert the new - // item if it exists. - NSArray* items = [self.collectionViewModel - itemsInSectionWithIdentifier:kEntriesStatusSectionIdentifier]; - if ([items count]) { - // There should only ever be at most one item in this section. - DCHECK([items count] <= 1); - // Only update if the item has changed. - if ([items[0] isEqual:entriesStatusItem]) { - return; - } - } - [self.collectionView performBatchUpdates:^{ - NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; - if ([items count]) { - [self.collectionViewModel - removeItemWithType:[self.collectionViewModel - itemTypeForIndexPath:indexPath] - fromSectionWithIdentifier:kEntriesStatusSectionIdentifier]; - [self.collectionView deleteItemsAtIndexPaths:@[ indexPath ]]; - } - if (entriesStatusItem) { - [self.collectionViewModel addItem:entriesStatusItem - toSectionWithIdentifier:kEntriesStatusSectionIdentifier]; - [self.collectionView insertItemsAtIndexPaths:@[ indexPath ]]; - } - } - completion:nil]; -} - -- (void)removeSelectedItemsFromCollection { - NSArray* deletedIndexPaths = self.collectionView.indexPathsForSelectedItems; - if (base::FeatureList::IsEnabled(kHistoryBatchUpdatesFilter)) { - NSArray* deletedIndexPaths = self.collectionView.indexPathsForSelectedItems; - [self.collectionView performBatchUpdates:^{ - [self deleteItemsFromCollectionViewModelWithIndex:deletedIndexPaths]; - } - completion:^(BOOL) { - [self updateCollectionViewAfterDeletingEntries]; - }]; - } else { - [self.collectionView performBatchUpdates:^{ - [self collectionView:self.collectionView - willDeleteItemsAtIndexPaths:deletedIndexPaths]; - [self.collectionView deleteItemsAtIndexPaths:deletedIndexPaths]; - - // Remove any empty sections, except the header section. - for (int section = self.collectionView.numberOfSections - 1; section > 0; - --section) { - if (![self.collectionViewModel numberOfItemsInSection:section]) { - [self.entryInserter removeSection:section]; - } - } - } - completion:^(BOOL) { - // If only the header section remains, there are no history entries. - if ([self.collectionViewModel numberOfSections] == 1) { - self.empty = YES; - } - [self updateEntriesStatusMessage]; - [self.delegate historyCollectionViewControllerDidChangeEntries:self]; - }]; - } -} - -- (void)deleteItemsFromCollectionViewModelWithIndex:(NSArray*)indexArray { - [self collectionView:self.collectionView - willDeleteItemsAtIndexPaths:indexArray]; - [self.collectionView deleteItemsAtIndexPaths:indexArray]; - - // Remove any empty sections, except the header section. - for (int section = self.collectionView.numberOfSections - 1; section > 0; - --section) { - if (![self.collectionViewModel numberOfItemsInSection:section]) { - [self.entryInserter removeSection:section]; - } - } -} - -- (void)filterForHistoryEntries:(NSArray*)entries { - self.collectionView.allowsMultipleSelection = YES; - for (int section = 1; section < [self.collectionViewModel numberOfSections]; - ++section) { - NSInteger sectionIdentifier = - [self.collectionViewModel sectionIdentifierForSection:section]; - if ([self.collectionViewModel - hasSectionForSectionIdentifier:sectionIdentifier]) { - NSArray* items = [self.collectionViewModel - itemsInSectionWithIdentifier:sectionIdentifier]; - for (id item in items) { - LegacyHistoryEntryItem* historyItem = - base::mac::ObjCCastStrict<LegacyHistoryEntryItem>(item); - if (![entries containsObject:historyItem]) { - NSIndexPath* indexPath = - [self.collectionViewModel indexPathForItem:historyItem]; - [self.collectionView - selectItemAtIndexPath:indexPath - animated:NO - scrollPosition:UICollectionViewScrollPositionNone]; - } - } - } - } - // If kHistoryBatchUpdatesFilter is not enabled the selected items will not be - // removed from the collection at this time. - if (!base::FeatureList::IsEnabled(kHistoryBatchUpdatesFilter)) - [self removeSelectedItemsFromCollection]; -} - -- (void)addLoadingIndicator { - NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; - if ([self.collectionViewModel hasItemAtIndexPath:indexPath] && - [self.collectionViewModel itemTypeForIndexPath:indexPath] == - ItemTypeActivityIndicator) { - // Do not add indicator a second time. - return; - } - - [self.collectionView performBatchUpdates:^{ - if ([self.collectionViewModel hasItemAtIndexPath:indexPath]) { - [self.collectionViewModel - removeItemWithType:[self.collectionViewModel - itemTypeForIndexPath:indexPath] - fromSectionWithIdentifier:kSectionIdentifierEnumZero]; - [self.collectionView deleteItemsAtIndexPaths:@[ indexPath ]]; - } - CollectionViewItem* loadingIndicatorItem = - [[CollectionViewItem alloc] initWithType:ItemTypeActivityIndicator]; - loadingIndicatorItem.cellClass = [ActivityIndicatorCell class]; - [self.collectionViewModel addItem:loadingIndicatorItem - toSectionWithIdentifier:kEntriesStatusSectionIdentifier]; - [self.collectionView insertItemsAtIndexPaths:@[ indexPath ]]; - } - completion:nil]; -} - -#pragma mark Context Menu - -- (void)displayContextMenuInvokedByGestureRecognizer: - (UILongPressGestureRecognizer*)gestureRecognizer { - if (gestureRecognizer.numberOfTouches != 1 || self.editing || - gestureRecognizer.state != UIGestureRecognizerStateBegan) { - return; - } - - CGPoint touchLocation = - [gestureRecognizer locationOfTouch:0 inView:self.collectionView]; - NSIndexPath* touchedItemIndexPath = - [self.collectionView indexPathForItemAtPoint:touchLocation]; - // If there's no index path, or the index path is for the header item, do not - // display a contextual menu. - if (!touchedItemIndexPath || - [touchedItemIndexPath - isEqual:[NSIndexPath indexPathForItem:0 inSection:0]]) - return; - - LegacyHistoryEntryItem* entry = - base::mac::ObjCCastStrict<LegacyHistoryEntryItem>( - [self.collectionViewModel itemAtIndexPath:touchedItemIndexPath]); - - __weak LegacyHistoryCollectionViewController* weakSelf = self; - web::ContextMenuParams params; - params.location = touchLocation; - params.view = self.collectionView; - NSString* menuTitle = - base::SysUTF16ToNSString(url_formatter::FormatUrl(entry.URL)); - params.menu_title = [menuTitle copy]; - - // Present sheet/popover using controller that is added to view hierarchy. - // TODO(crbug.com/754642): Remove TopPresentedViewController(). - UIViewController* topController = - top_view_controller::TopPresentedViewController(); - - self.contextMenuCoordinator = - [[ContextMenuCoordinator alloc] initWithBaseViewController:topController - params:params]; - - // TODO(crbug.com/606503): Refactor context menu creation code to be shared - // with BrowserViewController. - // Add "Open in New Tab" option. - NSString* openInNewTabTitle = - l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB); - ProceduralBlock openInNewTabAction = ^{ - [weakSelf openURLInNewTab:entry.URL]; - }; - [self.contextMenuCoordinator addItemWithTitle:openInNewTabTitle - action:openInNewTabAction]; - - // Add "Open in New Incognito Tab" option. - NSString* openInNewIncognitoTabTitle = l10n_util::GetNSStringWithFixup( - IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB); - ProceduralBlock openInNewIncognitoTabAction = ^{ - [weakSelf openURLInNewIncognitoTab:entry.URL]; - }; - [self.contextMenuCoordinator addItemWithTitle:openInNewIncognitoTabTitle - action:openInNewIncognitoTabAction]; - - // Add "Copy URL" option. - NSString* copyURLTitle = - l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_COPY); - ProceduralBlock copyURLAction = ^{ - StoreURLInPasteboard(entry.URL); - }; - [self.contextMenuCoordinator addItemWithTitle:copyURLTitle - action:copyURLAction]; - [self.parentViewController.view endEditing:YES]; - [self.contextMenuCoordinator start]; -} - -- (void)openURL:(const GURL&)URL { - new_tab_page_uma::RecordAction(_browserState, - new_tab_page_uma::ACTION_OPENED_HISTORY_ENTRY); - web::NavigationManager::WebLoadParams params(URL); - params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK; - [self.delegate historyCollectionViewController:self - shouldCloseWithCompletion:^{ - [self.URLLoader loadURLWithParams:params]; - }]; -} - -- (void)openURLInNewTab:(const GURL&)URL { - OpenNewTabCommand* command = - [[OpenNewTabCommand alloc] initWithURL:URL - referrer:web::Referrer() - inIncognito:NO - inBackground:NO - appendTo:kLastTab]; - [self.delegate historyCollectionViewController:self - shouldCloseWithCompletion:^{ - [self.URLLoader webPageOrderedOpen:command]; - }]; -} - -- (void)openURLInNewIncognitoTab:(const GURL&)URL { - OpenNewTabCommand* command = - [[OpenNewTabCommand alloc] initWithURL:URL - referrer:web::Referrer() - inIncognito:YES - inBackground:NO - appendTo:kLastTab]; - [self.delegate historyCollectionViewController:self - shouldCloseWithCompletion:^{ - [self.URLLoader webPageOrderedOpen:command]; - }]; -} - -@end
diff --git a/ios/chrome/browser/ui/history/legacy_history_entries_status_item.h b/ios/chrome/browser/ui/history/legacy_history_entries_status_item.h deleted file mode 100644 index 20b641d8..0000000 --- a/ios/chrome/browser/ui/history/legacy_history_entries_status_item.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRIES_STATUS_ITEM_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRIES_STATUS_ITEM_H_ - -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" - -@class LabelLinkController; -@protocol HistoryEntriesStatusItemDelegate; - -// Model item for HistoryEntriesStatusCell. Manages links added to the cell. -@interface LegacyHistoryEntriesStatusItem : CollectionViewItem -// YES if messages should be hidden. -@property(nonatomic, assign, getter=isHidden) BOOL hidden; -// Delegate for HistoryEntriesStatusItem. Is notified when a link is pressed. -@property(nonatomic, weak) id<HistoryEntriesStatusItemDelegate> delegate; -@end - -// Cell for displaying status for history entry. Provides information on whether -// local or synced entries or displays, and how to access other forms of -// browsing history, if applicable. -@interface LegacyHistoryEntriesStatusCell : CollectionViewFooterCell -@end - -@interface LegacyHistoryEntriesStatusCell (Testing) -// Link controller for entries status message. -@property(nonatomic, retain, readonly) LabelLinkController* labelLinkController; -@end - -#endif // IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRIES_STATUS_ITEM_H_
diff --git a/ios/chrome/browser/ui/history/legacy_history_entries_status_item.mm b/ios/chrome/browser/ui/history/legacy_history_entries_status_item.mm deleted file mode 100644 index 09c51cb..0000000 --- a/ios/chrome/browser/ui/history/legacy_history_entries_status_item.mm +++ /dev/null
@@ -1,126 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/legacy_history_entries_status_item.h" - -#include "base/mac/foundation_util.h" -#include "components/strings/grit/components_strings.h" -#include "ios/chrome/browser/chrome_url_constants.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h" -#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" -#import "ios/chrome/browser/ui/history/history_entries_status_item_delegate.h" -#import "ios/chrome/browser/ui/util/label_link_controller.h" -#import "ios/chrome/common/string_util.h" -#include "ios/chrome/grit/ios_strings.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/l10n_util_mac.h" -#include "url/gurl.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -// Delegate for HistoryEntriesStatusCell. -@protocol HistoryEntriesStatusCellDelegate<NSObject> -// Notifies the delegate that |URL| should be opened. -- (void)historyEntriesStatusCell:(LegacyHistoryEntriesStatusCell*)cell - didRequestOpenURL:(const GURL&)URL; -@end - -@interface LegacyHistoryEntriesStatusCell () -// Redeclare as readwrite. -@property(nonatomic, strong, readwrite) - LabelLinkController* labelLinkController; -// Delegate for the HistoryEntriesStatusCell. Is notified when a link is -// tapped. -@property(nonatomic, weak) id<HistoryEntriesStatusCellDelegate> delegate; -// Sets the browsing data url link on the cell label. -- (void)setLinkForBrowsingDataURL:(const GURL&)browsingDataURL; -@end - -@interface LegacyHistoryEntriesStatusItem ()<HistoryEntriesStatusCellDelegate> -@end - -@implementation LegacyHistoryEntriesStatusItem -@synthesize delegate = _delegate; -@synthesize hidden = _hidden; - -- (Class)cellClass { - return [LegacyHistoryEntriesStatusCell class]; -} - -- (void)configureCell:(LegacyHistoryEntriesStatusCell*)cell { - [super configureCell:cell]; - [cell setDelegate:self]; - if (self.hidden) { - cell.textLabel.text = nil; - } else { - cell.textLabel.text = - l10n_util::GetNSString(IDS_IOS_HISTORY_OTHER_FORMS_OF_HISTORY); - ; - [cell setLinkForBrowsingDataURL:GURL(kHistoryMyActivityURL)]; - } -} - -- (void)historyEntriesStatusCell:(LegacyHistoryEntriesStatusCell*)cell - didRequestOpenURL:(const GURL&)URL { - [self.delegate historyEntriesStatusItem:self didRequestOpenURL:URL]; -} - -- (BOOL)isEqualToHistoryEntriesStatusItem: - (LegacyHistoryEntriesStatusItem*)object { - return self.hidden == object.hidden; -} - -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[LegacyHistoryEntriesStatusItem class]]) { - return NO; - } - return [self - isEqualToHistoryEntriesStatusItem:base::mac::ObjCCastStrict< - LegacyHistoryEntriesStatusItem>( - object)]; -} - -@end - -@implementation LegacyHistoryEntriesStatusCell -@synthesize delegate = _delegate; -@synthesize labelLinkController = _labelLinkController; - -- (void)setLinkForBrowsingDataURL:(const GURL&)browsingDataURL { - __weak LegacyHistoryEntriesStatusCell* weakSelf = self; - self.labelLinkController = [[LabelLinkController alloc] - initWithLabel:self.textLabel - action:^(const GURL& URL) { - [[weakSelf delegate] historyEntriesStatusCell:weakSelf - didRequestOpenURL:URL]; - }]; - [self.labelLinkController setLinkColor:[[MDCPalette cr_bluePalette] tint500]]; - - // Remove link delimiter from text and get ranges for links. Must be parsed - // before being added to the controller because modifying the label text - // clears all added links. - NSRange otherBrowsingDataRange; - if (browsingDataURL.is_valid()) { - self.textLabel.text = - ParseStringWithLink(self.textLabel.text, &otherBrowsingDataRange); - DCHECK(otherBrowsingDataRange.location != NSNotFound && - otherBrowsingDataRange.length); - - [self.labelLinkController addLinkWithRange:otherBrowsingDataRange - url:browsingDataURL]; - } -} - -- (void)prepareForReuse { - [super prepareForReuse]; - self.labelLinkController = nil; - self.delegate = nil; -} - -@end
diff --git a/ios/chrome/browser/ui/history/legacy_history_entries_status_item_unittest.mm b/ios/chrome/browser/ui/history/legacy_history_entries_status_item_unittest.mm deleted file mode 100644 index ffd3e534..0000000 --- a/ios/chrome/browser/ui/history/legacy_history_entries_status_item_unittest.mm +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/legacy_history_entries_status_item.h" - -#import "base/test/ios/wait_util.h" -#include "components/strings/grit/components_strings.h" -#include "ios/chrome/browser/chrome_url_constants.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h" -#import "ios/chrome/browser/ui/history/history_entries_status_item_delegate.h" -#import "ios/chrome/browser/ui/util/label_link_controller.h" -#import "ios/chrome/common/string_util.h" -#include "ios/chrome/grit/ios_strings.h" -#include "testing/gtest/include/gtest/gtest.h" -#import "testing/gtest_mac.h" -#include "testing/platform_test.h" -#include "third_party/ocmock/OCMock/OCMock.h" -#include "third_party/ocmock/gtest_support.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/l10n_util_mac.h" -#include "url/gurl.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -// Mock delegate for HistoryEntriesStatusItem. Implement mock delegate rather -// than use OCMock because delegate method takes a GURL as a parameter. -@interface MockEntriesStatusItemDelegate - : NSObject<HistoryEntriesStatusItemDelegate> -@property(nonatomic) BOOL delegateCalledForSyncURL; -@property(nonatomic) BOOL delegateCalledForBrowsingDataURL; -@end - -@implementation MockEntriesStatusItemDelegate -@synthesize delegateCalledForSyncURL = _delegateCalledForSyncURL; -@synthesize delegateCalledForBrowsingDataURL = - _delegateCalledForBrowsingDataURL; -- (void)historyEntriesStatusItem:(LegacyHistoryEntriesStatusItem*)item - didRequestOpenURL:(const GURL&)URL { - GURL browsingDataURL(kHistoryMyActivityURL); - if (URL == browsingDataURL) { - self.delegateCalledForBrowsingDataURL = YES; - } -} -@end - -namespace { - -using LegacyHistoryEntriesStatusItemTest = PlatformTest; - -// Tests that configuring a cell for HistoryEntriesStatusItem with hidden -// property set to YES results in an empty label. -TEST_F(LegacyHistoryEntriesStatusItemTest, TestHidden) { - LegacyHistoryEntriesStatusItem* item = - [[LegacyHistoryEntriesStatusItem alloc] initWithType:0]; - item.hidden = YES; - LegacyHistoryEntriesStatusCell* cell = - [[LegacyHistoryEntriesStatusCell alloc] init]; - [item configureCell:cell]; - EXPECT_FALSE(cell.textLabel.text); -} - -// Tests that tapping on links on a configured cell invokes -// the HistoryEntriesStatusItemDelegate method. -TEST_F(LegacyHistoryEntriesStatusItemTest, TestDelegate) { - LegacyHistoryEntriesStatusItem* item = - [[LegacyHistoryEntriesStatusItem alloc] initWithType:0]; - LegacyHistoryEntriesStatusCell* cell = - [[LegacyHistoryEntriesStatusCell alloc] init]; - MockEntriesStatusItemDelegate* delegate = - [[MockEntriesStatusItemDelegate alloc] init]; - item.delegate = delegate; - item.hidden = NO; - [item configureCell:cell]; - - // Layout the cell so that links are drawn. - cell.frame = CGRectMake(0, 0, 360, 100); - [cell setNeedsLayout]; - [cell layoutIfNeeded]; - - // Tap link for more info on browsing data. - GURL browsing_data_url(kHistoryMyActivityURL); - CGRect browsing_data_rect = [[[cell.labelLinkController - tapRectsForURL:browsing_data_url] objectAtIndex:0] CGRectValue]; - [cell.labelLinkController - tapLabelAtPoint:CGPointMake(CGRectGetMidX(browsing_data_rect), - CGRectGetMidY(browsing_data_rect))]; - - base::test::ios::WaitUntilCondition(^bool() { - return delegate.delegateCalledForBrowsingDataURL; - }); -} -} // namespace
diff --git a/ios/chrome/browser/ui/history/legacy_history_entry_item.h b/ios/chrome/browser/ui/history/legacy_history_entry_item.h deleted file mode 100644 index 7c992cb..0000000 --- a/ios/chrome/browser/ui/history/legacy_history_entry_item.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRY_ITEM_H_ -#define IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRY_ITEM_H_ - -#include "components/history/core/browser/browsing_history_service.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" -#import "ios/chrome/browser/ui/history/history_entry_item_interface.h" -#import "ios/third_party/material_components_ios/src/components/Collections/src/MaterialCollections.h" - -namespace ios { -class ChromeBrowserState; -} // namespace ios - -@class FaviconView; -@protocol FaviconViewProviderDelegate; -@protocol HistoryEntryItemDelegate; - -// Model object for the cell that displays a history entry. -@interface LegacyHistoryEntryItem - : CollectionViewItem<HistoryEntryItemInterface> - -// The |delegate| is notified when the favicon has loaded, and may be nil. -- (instancetype)initWithType:(NSInteger)type - historyEntry: - (const history::BrowsingHistoryService::HistoryEntry&)entry - browserState:(ios::ChromeBrowserState*)browserState - delegate:(id<HistoryEntryItemDelegate>)delegate - NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithType:(NSInteger)type NS_UNAVAILABLE; - -@end - -// Cell that renders a history entry. -@interface LegacyHistoryEntryCell : MDCCollectionViewCell - -// View for displaying the favicon for the history entry. -@property(nonatomic, strong) UIView* faviconViewContainer; -// Text label for history entry title. -@property(nonatomic, readonly, strong) UILabel* textLabel; -// Text label for history entry URL. -@property(nonatomic, readonly, strong) UILabel* detailTextLabel; -// Text label for history entry timestamp. -@property(nonatomic, readonly, strong) UILabel* timeLabel; - -@end - -#endif // IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRY_ITEM_H_
diff --git a/ios/chrome/browser/ui/history/legacy_history_entry_item.mm b/ios/chrome/browser/ui/history/legacy_history_entry_item.mm deleted file mode 100644 index 494a6bce..0000000 --- a/ios/chrome/browser/ui/history/legacy_history_entry_item.mm +++ /dev/null
@@ -1,286 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h" - -#include "base/i18n/time_formatting.h" -#import "base/mac/foundation_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "components/history/core/browser/url_row.h" -#include "components/strings/grit/components_strings.h" -#include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h" -#import "ios/chrome/browser/ui/history/favicon_view.h" -#import "ios/chrome/browser/ui/history/favicon_view_provider.h" -#import "ios/chrome/browser/ui/history/history_entry_item_delegate.h" -#include "ios/chrome/browser/ui/history/history_util.h" -#include "ios/chrome/browser/ui/rtl_geometry.h" -#import "ios/chrome/common/ui_util/constraints_ui_util.h" -#include "ios/chrome/grit/ios_strings.h" -#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h" -#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" -#include "ui/base/l10n/l10n_util.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { -// Size at which the favicon will be displayed. -const CGFloat kFaviconSize = 24.0; -// Minimum size at which to fetch favicons. -const CGFloat kMinFaviconSize = 16.0; -// Horizontal spacing between edge of the cell and the cell content. -const CGFloat kMargin = 16.0; -// Horizontal spacing between the leading edge of the cell and the text. -const CGFloat kHeaderMargin = 56.0; -} // namespace - -#pragma mark - LegacyHistoryEntryItem - -@interface LegacyHistoryEntryItem ()<FaviconViewProviderDelegate> { - // Delegate for LegacyHistoryEntryItem. - __weak id<HistoryEntryItemDelegate> _delegate; -} - -// FaviconViewProvider to fetch the favicon and format the favicon view. -@property(nonatomic, strong) FaviconViewProvider* faviconViewProvider; - -// Custom accessibility actions for the history entry view. -- (NSArray*)accessibilityActions; -// Custom accessibility action to delete the history entry. -- (BOOL)deleteHistoryEntry; -// Custom accessibility action to open the history entry's URL in a new tab. -- (BOOL)openInNewTab; -// Custom accessibility action to open the history entry's URL in a new -// incognito tab. -- (BOOL)openInNewIncognitoTab; -// Custom accessibility action to copy the history entry's URL to the clipboard. -- (BOOL)copyURL; -@end - -@implementation LegacyHistoryEntryItem - -@synthesize faviconViewProvider = _faviconViewProvider; -@synthesize text = _text; -@synthesize detailText = _detailText; -@synthesize timeText = _timeText; -@synthesize URL = _URL; -@synthesize timestamp = _timestamp; - -- (instancetype)initWithType:(NSInteger)type - historyEntry: - (const history::BrowsingHistoryService::HistoryEntry&)entry - browserState:(ios::ChromeBrowserState*)browserState - delegate:(id<HistoryEntryItemDelegate>)delegate { - self = [super initWithType:type]; - if (self) { - self.cellClass = [LegacyHistoryEntryCell class]; - favicon::LargeIconService* largeIconService = - IOSChromeLargeIconServiceFactory::GetForBrowserState(browserState); - _faviconViewProvider = - [[FaviconViewProvider alloc] initWithURL:entry.url - faviconSize:kFaviconSize - minFaviconSize:kMinFaviconSize - largeIconService:largeIconService - delegate:self]; - _text = [history::FormattedTitle(entry.title, entry.url) copy]; - _detailText = [base::SysUTF8ToNSString(entry.url.spec()) copy]; - _timeText = - [base::SysUTF16ToNSString(base::TimeFormatTimeOfDay(entry.time)) copy]; - _URL = GURL(entry.url); - _timestamp = entry.time; - _delegate = delegate; - } - return self; -} - -- (instancetype)initWithType:(NSInteger)type { - NOTREACHED(); - return nil; -} - -- (BOOL)isEqualToHistoryEntryItem:(id<HistoryEntryItemInterface>)item { - return item && item.URL == _URL && item.timestamp == _timestamp; -} - -- (BOOL)isEqual:(id)object { - if (self == object) - return YES; - - if (![object isMemberOfClass:[LegacyHistoryEntryItem class]]) - return NO; - - return [self isEqualToHistoryEntryItem:object]; -} - -- (NSUInteger)hash { - return [base::SysUTF8ToNSString(self.URL.spec()) hash] ^ - self.timestamp.ToInternalValue(); -} - -- (NSArray*)accessibilityActions { - UIAccessibilityCustomAction* deleteAction = - [[UIAccessibilityCustomAction alloc] - initWithName:l10n_util::GetNSString( - IDS_HISTORY_ENTRY_ACCESSIBILITY_DELETE) - target:self - selector:@selector(deleteHistoryEntry)]; - UIAccessibilityCustomAction* openInNewTabAction = - [[UIAccessibilityCustomAction alloc] - initWithName:l10n_util::GetNSString( - IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB) - target:self - selector:@selector(openInNewTab)]; - UIAccessibilityCustomAction* openInNewIncognitoTabAction = - [[UIAccessibilityCustomAction alloc] - initWithName:l10n_util::GetNSString( - IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB) - target:self - selector:@selector(openInNewIncognitoTab)]; - UIAccessibilityCustomAction* copyURLAction = - [[UIAccessibilityCustomAction alloc] - initWithName:l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_COPY) - target:self - selector:@selector(copyURL)]; - return @[ - deleteAction, openInNewTabAction, openInNewIncognitoTabAction, copyURLAction - ]; -} - -- (BOOL)deleteHistoryEntry { - [_delegate historyEntryItemDidRequestDelete:self]; - return YES; -} - -- (BOOL)openInNewTab { - [_delegate historyEntryItemDidRequestOpenInNewTab:self]; - return YES; -} - -- (BOOL)openInNewIncognitoTab { - [_delegate historyEntryItemDidRequestOpenInNewIncognitoTab:self]; - return YES; -} - -- (BOOL)copyURL { - [_delegate historyEntryItemDidRequestCopy:self]; - return YES; -} - -- (void)configureCell:(LegacyHistoryEntryCell*)cell { - [super configureCell:cell]; - - // Set favicon view and constraints. - FaviconView* faviconView = self.faviconViewProvider.faviconView; - [cell.faviconViewContainer addSubview:faviconView]; - [faviconView setTranslatesAutoresizingMaskIntoConstraints:NO]; - AddSameConstraints(faviconView, cell.faviconViewContainer); - - cell.textLabel.text = self.text; - cell.detailTextLabel.text = self.detailText; - cell.timeLabel.text = self.timeText; - cell.isAccessibilityElement = YES; - cell.accessibilityCustomActions = self.accessibilityActions; - cell.accessibilityLabel = - l10n_util::GetNSStringF(IDS_HISTORY_ENTRY_ACCESSIBILITY_LABEL, - base::SysNSStringToUTF16(self.text), - base::SysNSStringToUTF16(self.detailText), - base::SysNSStringToUTF16(self.timeText)); -} - -- (void)faviconViewProviderFaviconDidLoad:(FaviconViewProvider*)provider { - [_delegate historyEntryItemShouldUpdateView:self]; -} - -@end - -#pragma mark - LegacyHistoryEntryCell - -@interface LegacyHistoryEntryCell () - -// Redeclare as readwrite. -@property(nonatomic, readwrite, strong) UILabel* textLabel; -@property(nonatomic, readwrite, strong) UILabel* detailTextLabel; -@property(nonatomic, readwrite, strong) UILabel* timeLabel; -@end - -@implementation LegacyHistoryEntryCell - -@synthesize faviconViewContainer = _faviconViewContainer; -@synthesize textLabel = _textLabel; -@synthesize detailTextLabel = _detailTextLabel; -@synthesize timeLabel = _timeLabel; - -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - _faviconViewContainer = [[UIView alloc] initWithFrame:CGRectZero]; - - _textLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - [_textLabel setFont:[[MDCTypography fontLoader] mediumFontOfSize:16]]; - [_textLabel setTextColor:[[MDCPalette greyPalette] tint900]]; - - _detailTextLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - [_detailTextLabel - setFont:[[MDCTypography fontLoader] regularFontOfSize:14]]; - [_detailTextLabel setTextColor:[[MDCPalette greyPalette] tint600]]; - - _timeLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - [_timeLabel setFont:[[MDCTypography fontLoader] mediumFontOfSize:14]]; - [_timeLabel setTextColor:[[MDCPalette greyPalette] tint600]]; - _timeLabel.textAlignment = - UseRTLLayout() ? NSTextAlignmentLeft : NSTextAlignmentRight; - - UIView* contentView = self.contentView; - [contentView addSubview:_faviconViewContainer]; - [contentView addSubview:_textLabel]; - [contentView addSubview:_detailTextLabel]; - [contentView addSubview:_timeLabel]; - - [_faviconViewContainer setTranslatesAutoresizingMaskIntoConstraints:NO]; - [_textLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; - [_detailTextLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; - [_timeLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; - - [_faviconViewContainer.widthAnchor constraintEqualToConstant:kFaviconSize]; - - NSDictionary* views = @{ - @"title" : _textLabel, - @"URL" : _detailTextLabel, - @"time" : _timeLabel, - @"favicon" : _faviconViewContainer, - }; - NSDictionary* metrics = @{ - @"margin" : @(kMargin), - @"spacing" : @(kHeaderMargin - (kMargin + kFaviconSize)), - }; - NSArray* constraints = @[ - @"H:|-margin-[favicon]-spacing-[title]-[time]-margin-|", - @"H:|-margin-[favicon]-spacing-[URL]-margin-|", - @"V:|-margin-[title][URL]-margin-|", - ]; - ApplyVisualConstraintsWithMetrics(constraints, views, metrics); - AddSameCenterYConstraint(_textLabel, _timeLabel); - AddSameCenterYConstraint(_faviconViewContainer, _textLabel); - - [_timeLabel - setContentCompressionResistancePriority:UILayoutPriorityRequired - forAxis: - UILayoutConstraintAxisHorizontal]; - } - return self; -} - -- (void)prepareForReuse { - [super prepareForReuse]; - _textLabel.text = nil; - _detailTextLabel.text = nil; - _timeLabel.text = nil; - for (UIView* subview in _faviconViewContainer.subviews) { - [subview removeFromSuperview]; - } -} - -@end
diff --git a/ios/chrome/browser/ui/history/legacy_history_entry_item_unittest.mm b/ios/chrome/browser/ui/history/legacy_history_entry_item_unittest.mm deleted file mode 100644 index 72ab6e5a..0000000 --- a/ios/chrome/browser/ui/history/legacy_history_entry_item_unittest.mm +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h" - -#include "base/i18n/time_formatting.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "components/history/core/browser/browsing_history_service.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gtest_mac.h" -#include "testing/platform_test.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -using history::BrowsingHistoryService; - -namespace { -const char kTestUrl[] = "http://test/"; -const char kTestUrl2[] = "http://test2/"; -const char kTestTitle[] = "Test"; -} - -LegacyHistoryEntryItem* GetHistoryEntryItem(const GURL& url, - const char title[], - base::Time timestamp) { - BrowsingHistoryService::HistoryEntry entry( - BrowsingHistoryService::HistoryEntry::LOCAL_ENTRY, GURL(url), - base::UTF8ToUTF16(title), timestamp, "", false, base::string16(), false); - LegacyHistoryEntryItem* item = - [[LegacyHistoryEntryItem alloc] initWithType:0 - historyEntry:entry - browserState:nil - delegate:nil]; - return item; -} - -using LegacyHistoryEntryItemTest = PlatformTest; - -// Tests that -[HistoryEntryItem configureCell:] sets the cell's textLabel text -// to the item title, the detailTextLabel text to the URL, and the timeLabel -// text to the timestamp. -TEST_F(LegacyHistoryEntryItemTest, ConfigureCell) { - base::Time timestamp = base::Time::Now(); - LegacyHistoryEntryItem* item = - GetHistoryEntryItem(GURL(kTestUrl), kTestTitle, timestamp); - - LegacyHistoryEntryCell* cell = [[[item cellClass] alloc] init]; - EXPECT_TRUE([cell isMemberOfClass:[LegacyHistoryEntryCell class]]); - [item configureCell:cell]; - EXPECT_NSEQ(base::SysUTF8ToNSString(kTestTitle), cell.textLabel.text); - EXPECT_NSEQ(base::SysUTF8ToNSString(kTestUrl), cell.detailTextLabel.text); - EXPECT_NSEQ(base::SysUTF16ToNSString(base::TimeFormatTimeOfDay(timestamp)), - cell.timeLabel.text); -} - -// Tests that -[HistoryItem isEqualToHistoryItem:] returns YES if the two items -// have the same URL and timestamp, and NO otherwise. -TEST_F(LegacyHistoryEntryItemTest, IsEqual) { - base::Time timestamp = base::Time::Now(); - base::Time timestamp2 = timestamp - base::TimeDelta::FromMinutes(1); - LegacyHistoryEntryItem* history_entry = - GetHistoryEntryItem(GURL(kTestUrl), kTestTitle, timestamp); - LegacyHistoryEntryItem* same_entry = - GetHistoryEntryItem(GURL(kTestUrl), kTestTitle, timestamp); - - LegacyHistoryEntryItem* different_time_entry = - GetHistoryEntryItem(GURL(kTestUrl), kTestTitle, timestamp2); - LegacyHistoryEntryItem* different_url_entry = - GetHistoryEntryItem(GURL(kTestUrl2), kTestTitle, timestamp); - - EXPECT_TRUE([history_entry isEqual:same_entry]); - EXPECT_FALSE([history_entry isEqual:different_time_entry]); - EXPECT_FALSE([history_entry isEqual:different_url_entry]); -}
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn index 095878b..b4d50b2 100644 --- a/ios/chrome/browser/ui/main/BUILD.gn +++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -10,8 +10,6 @@ "browser_view_wrangler.mm", "bvc_container_view_controller.h", "bvc_container_view_controller.mm", - "main_containing_view_controller.h", - "main_containing_view_controller.mm", "main_coordinator.h", "main_coordinator.mm", "main_presenting_view_controller.h", @@ -19,7 +17,6 @@ "view_controller_swapping.h", ] deps = [ - ":feature_flags", ":tab_switcher", "//base", "//ios/chrome/app/resources:launchscreen_xib", @@ -41,17 +38,6 @@ libs = [ "UIKit.framework" ] } -source_set("feature_flags") { - configs += [ "//build/config/compiler:enable_arc" ] - sources = [ - "main_feature_flags.cc", - "main_feature_flags.h", - ] - deps = [ - "//base", - ] -} - source_set("tab_switcher") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ @@ -71,7 +57,6 @@ testonly = true sources = [ "browser_view_wrangler_unittest.mm", - "main_containing_view_controller_unittest.mm", "main_coordinator_unittest.mm", "main_presenting_view_controller_unittest.mm", ]
diff --git a/ios/chrome/browser/ui/main/main_containing_view_controller.h b/ios/chrome/browser/ui/main/main_containing_view_controller.h deleted file mode 100644 index 4478138bb..0000000 --- a/ios/chrome/browser/ui/main/main_containing_view_controller.h +++ /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. - -#ifndef IOS_CHROME_BROWSER_UI_MAIN_MAIN_CONTAINING_VIEW_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_MAIN_MAIN_CONTAINING_VIEW_CONTROLLER_H_ - -#import "ios/chrome/browser/ui/main/view_controller_swapping.h" - -// A UIViewController that uses containment to display TabSwitchers and -// BrowserViewControllers.. -@interface MainContainingViewController - : UIViewController<ViewControllerSwapping> -@end - -#endif // IOS_CHROME_BROWSER_UI_MAIN_MAIN_CONTAINING_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/main/main_containing_view_controller.mm b/ios/chrome/browser/ui/main/main_containing_view_controller.mm deleted file mode 100644 index 00e825ec..0000000 --- a/ios/chrome/browser/ui/main/main_containing_view_controller.mm +++ /dev/null
@@ -1,114 +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. - -#import "ios/chrome/browser/ui/main/main_containing_view_controller.h" - -#import "base/logging.h" -#import "ios/chrome/browser/ui/main/tab_switcher.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@implementation MainContainingViewController - -- (UIViewController*)activeViewController { - return [self.childViewControllers firstObject]; -} - -- (UIViewController*)viewController { - return self; -} - -- (void)showTabSwitcher:(id<TabSwitcher>)tabSwitcher - completion:(ProceduralBlock)completion { - [self setActiveViewController:[tabSwitcher viewController] - completion:completion]; - [tabSwitcher showWithSelectedTabAnimation]; -} - -- (void)showTabViewController:(UIViewController*)viewController - completion:(ProceduralBlock)completion { - [self setActiveViewController:viewController completion:completion]; -} - -// Swaps in and displays the given view controller, replacing any other -// view controllers that may currently be visible. Runs -// the given |completion| block after the view controller is visible. -- (void)setActiveViewController:(UIViewController*)activeViewController - completion:(void (^)())completion { - DCHECK(activeViewController); - if (self.activeViewController == activeViewController) { - if (completion) { - completion(); - } - return; - } - - // TODO(crbug.com/546189): DCHECK here that there isn't a modal view - // controller showing once the known violations of that are fixed. - - // Remove the current active view controller, if any. - if (self.activeViewController) { - [self.activeViewController willMoveToParentViewController:nil]; - [self.activeViewController.view removeFromSuperview]; - [self.activeViewController removeFromParentViewController]; - } - - DCHECK_EQ(nil, self.activeViewController); - DCHECK_EQ(0U, self.view.subviews.count); - - // Add the new active view controller. - [self addChildViewController:activeViewController]; - self.activeViewController.view.frame = self.view.bounds; - [self.view addSubview:self.activeViewController.view]; - [activeViewController didMoveToParentViewController:self]; - - // Let the system know that the child has changed so appearance updates can - // be made. - [self setNeedsStatusBarAppearanceUpdate]; - - DCHECK(self.activeViewController == activeViewController); - if (completion) { - completion(); - } -} - -#pragma mark - UIViewController methods - -- (void)presentViewController:(UIViewController*)viewControllerToPresent - animated:(BOOL)flag - completion:(void (^)())completion { - // If there is no activeViewController then this call will get inadvertently - // dropped. - DCHECK(self.activeViewController); - [self.activeViewController presentViewController:viewControllerToPresent - animated:flag - completion:completion]; -} - -- (void)dismissViewControllerAnimated:(BOOL)flag - completion:(void (^)())completion { - // If there is no activeViewController then this call will get inadvertently - // dropped. - DCHECK(self.activeViewController); - [self.activeViewController dismissViewControllerAnimated:flag - completion:completion]; -} - -- (UIViewController*)childViewControllerForStatusBarHidden { - return self.activeViewController; -} - -- (UIViewController*)childViewControllerForStatusBarStyle { - return self.activeViewController; -} - -- (BOOL)shouldAutorotate { - return self.activeViewController - ? [self.activeViewController shouldAutorotate] - : [super shouldAutorotate]; -} - -@end
diff --git a/ios/chrome/browser/ui/main/main_containing_view_controller_unittest.mm b/ios/chrome/browser/ui/main/main_containing_view_controller_unittest.mm deleted file mode 100644 index c569b9a..0000000 --- a/ios/chrome/browser/ui/main/main_containing_view_controller_unittest.mm +++ /dev/null
@@ -1,187 +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. - -#import "ios/chrome/browser/ui/main/main_containing_view_controller.h" - -#import <UIKit/UIKit.h> - -#import "base/test/ios/wait_util.h" -#include "base/test/scoped_feature_list.h" -#import "ios/chrome/browser/ui/main/main_view_controller_test.h" -#import "ios/chrome/browser/ui/main/tab_switcher.h" -#import "ios/chrome/test/block_cleanup_test.h" -#include "testing/gtest_mac.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface HiddenStatusBarViewController : UIViewController -@end - -@implementation HiddenStatusBarViewController -- (BOOL)prefersStatusBarHidden { - return YES; -} -@end - -@interface MockViewController : UIViewController -@property(nonatomic, readonly) NSInteger didMoveToParentViewControllerCount; -@property(nonatomic, weak, readonly) id didMoveToParentViewControllerArgument; -@property(nonatomic, readonly) NSInteger willMoveToParentViewControllerCount; -@property(nonatomic, weak, readonly) id willMoveToParentViewControllerArgument; -@end - -@implementation MockViewController -@synthesize didMoveToParentViewControllerCount = - _didMoveToParentViewControllerCount; -@synthesize didMoveToParentViewControllerArgument = - _didMoveToParentViewControllerArgument; -@synthesize willMoveToParentViewControllerCount = - _willMoveToParentViewControllerCount; -@synthesize willMoveToParentViewControllerArgument = - _willMoveToParentViewControllerArgument; - -- (void)didMoveToParentViewController:(UIViewController*)parent { - _didMoveToParentViewControllerCount++; - _didMoveToParentViewControllerArgument = parent; -} - -- (void)willMoveToParentViewController:(UIViewController*)parent { - _willMoveToParentViewControllerCount++; - _willMoveToParentViewControllerArgument = parent; -} - -@end - -namespace { - -using MainContainingViewControllerTest = MainViewControllerTest; - -TEST_F(MainContainingViewControllerTest, ActiveVC) { - MainContainingViewController* main_view_controller = - [[MainContainingViewController alloc] init]; - id<TabSwitcher> child_tab_switcher_1 = CreateTestTabSwitcher(); - id<TabSwitcher> child_tab_switcher_2 = CreateTestTabSwitcher(); - - // Test that the active view controller is always the first child view - // controller. - EXPECT_EQ(nil, [main_view_controller activeViewController]); - [main_view_controller - addChildViewController:[child_tab_switcher_1 viewController]]; - EXPECT_EQ([child_tab_switcher_1 viewController], - [main_view_controller activeViewController]); - [main_view_controller - addChildViewController:[child_tab_switcher_2 viewController]]; - EXPECT_EQ([child_tab_switcher_1 viewController], - [main_view_controller activeViewController]); - [[child_tab_switcher_1 viewController] removeFromParentViewController]; - EXPECT_EQ([child_tab_switcher_2 viewController], - [main_view_controller activeViewController]); -} - -TEST_F(MainContainingViewControllerTest, Setters) { - MainContainingViewController* main_view_controller = - [[MainContainingViewController alloc] init]; - CGRect windowRect = CGRectMake(0, 0, 200, 200); - [main_view_controller view].frame = windowRect; - - MockViewController* child_view_controller = [[MockViewController alloc] init]; - child_view_controller.view.frame = CGRectMake(0, 0, 10, 10); - - [main_view_controller showTabViewController:child_view_controller - completion:nil]; - EXPECT_EQ(child_view_controller, - [[main_view_controller childViewControllers] firstObject]); - EXPECT_EQ(child_view_controller.view, - [[main_view_controller view].subviews firstObject]); - EXPECT_NSEQ(NSStringFromCGRect(windowRect), - NSStringFromCGRect(child_view_controller.view.frame)); - EXPECT_EQ(1, [child_view_controller didMoveToParentViewControllerCount]); - EXPECT_EQ(main_view_controller, - [child_view_controller didMoveToParentViewControllerArgument]); - // Expect there to have also been an automatic call to - // -willMoveToParentViewController. - EXPECT_EQ(1, [child_view_controller willMoveToParentViewControllerCount]); - EXPECT_EQ(main_view_controller, - [child_view_controller willMoveToParentViewControllerArgument]); - - id<TabSwitcher> child_tab_switcher = CreateTestTabSwitcher(); - [main_view_controller showTabSwitcher:child_tab_switcher completion:nil]; - EXPECT_EQ([child_tab_switcher viewController], - [[main_view_controller childViewControllers] firstObject]); - EXPECT_EQ(1U, [[main_view_controller childViewControllers] count]); - EXPECT_EQ(nil, [child_view_controller.view superview]); - EXPECT_EQ(2, [child_view_controller willMoveToParentViewControllerCount]); - EXPECT_EQ(nil, - [child_view_controller willMoveToParentViewControllerArgument]); - // Expect there to have also been an automatic call to - // -didMoveToParentViewController. - EXPECT_EQ(2, [child_view_controller willMoveToParentViewControllerCount]); - EXPECT_EQ(nil, [child_view_controller didMoveToParentViewControllerArgument]); -} - -TEST_F(MainContainingViewControllerTest, StatusBar) { - MainContainingViewController* main_view_controller = - [[MainContainingViewController alloc] init]; - SetRootViewController(main_view_controller); - - id<TabSwitcher> status_bar_visible_tab_switcher = CreateTestTabSwitcher(); - [main_view_controller showTabSwitcher:status_bar_visible_tab_switcher - completion:nil]; - // Check if the status bar is hidden by testing if the status bar rect is - // CGRectZero. - EXPECT_FALSE(CGRectEqualToRect( - [UIApplication sharedApplication].statusBarFrame, CGRectZero)); - HiddenStatusBarViewController* status_bar_hidden_view_controller = - [[HiddenStatusBarViewController alloc] init]; - [main_view_controller showTabViewController:status_bar_hidden_view_controller - completion:nil]; - EXPECT_EQ([main_view_controller childViewControllerForStatusBarHidden], - status_bar_hidden_view_controller); - EXPECT_TRUE(CGRectEqualToRect( - [UIApplication sharedApplication].statusBarFrame, CGRectZero)); -} - -// Tests that completion handlers are called properly after the new view -// controller is made active -TEST_F(MainContainingViewControllerTest, CompletionHandlers) { - MainContainingViewController* main_view_controller = - [[MainContainingViewController alloc] init]; - CGRect windowRect = CGRectMake(0, 0, 200, 200); - [main_view_controller view].frame = windowRect; - - id<TabSwitcher> child_tab_switcher_1 = CreateTestTabSwitcher(); - [[child_tab_switcher_1 viewController] view].frame = CGRectMake(0, 0, 10, 10); - - id<TabSwitcher> child_tab_switcher_2 = CreateTestTabSwitcher(); - [[child_tab_switcher_2 viewController] view].frame = - CGRectMake(20, 20, 10, 10); - - // Tests that the completion handler is called when there is no preexisting - // active view controller. - __block BOOL completion_handler_was_called = false; - [main_view_controller showTabSwitcher:child_tab_switcher_1 - completion:^{ - completion_handler_was_called = YES; - }]; - base::test::ios::WaitUntilCondition(^bool() { - return completion_handler_was_called; - }); - ASSERT_TRUE(completion_handler_was_called); - - // Tests that the completion handler is called when replacing an existing - // active view controller. - completion_handler_was_called = NO; - [main_view_controller showTabSwitcher:child_tab_switcher_2 - completion:^{ - completion_handler_was_called = YES; - }]; - base::test::ios::WaitUntilCondition(^bool() { - return completion_handler_was_called; - }); - ASSERT_TRUE(completion_handler_was_called); -} - -} // namespace
diff --git a/ios/chrome/browser/ui/main/main_coordinator.mm b/ios/chrome/browser/ui/main/main_coordinator.mm index d5c21461..4aa690c 100644 --- a/ios/chrome/browser/ui/main/main_coordinator.mm +++ b/ios/chrome/browser/ui/main/main_coordinator.mm
@@ -5,8 +5,6 @@ #import "ios/chrome/browser/ui/main/main_coordinator.h" #include "base/logging.h" -#import "ios/chrome/browser/ui/main/main_containing_view_controller.h" -#include "ios/chrome/browser/ui/main/main_feature_flags.h" #import "ios/chrome/browser/ui/main/main_presenting_view_controller.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -36,13 +34,8 @@ #pragma mark - ChromeCoordinator implementation. - (void)start { - UIViewController<ViewControllerSwapping>* mainViewController = nil; - if (TabSwitcherPresentsBVCEnabled()) { - mainViewController = [[MainPresentingViewController alloc] init]; - } else { - mainViewController = [[MainContainingViewController alloc] init]; - } - CHECK(mainViewController); + UIViewController<ViewControllerSwapping>* mainViewController = + [[MainPresentingViewController alloc] init]; _mainViewController = mainViewController; self.window.rootViewController = self.mainViewController; }
diff --git a/ios/chrome/browser/ui/main/main_feature_flags.cc b/ios/chrome/browser/ui/main/main_feature_flags.cc deleted file mode 100644 index 27b8826..0000000 --- a/ios/chrome/browser/ui/main/main_feature_flags.cc +++ /dev/null
@@ -1,12 +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. - -#include "ios/chrome/browser/ui/main/main_feature_flags.h" - -const base::Feature kTabSwitcherPresentsBVC{"TabSwitcherPresentsBVC", - base::FEATURE_ENABLED_BY_DEFAULT}; - -bool TabSwitcherPresentsBVCEnabled() { - return base::FeatureList::IsEnabled(kTabSwitcherPresentsBVC); -}
diff --git a/ios/chrome/browser/ui/main/main_feature_flags.h b/ios/chrome/browser/ui/main/main_feature_flags.h deleted file mode 100644 index 17462b0..0000000 --- a/ios/chrome/browser/ui/main/main_feature_flags.h +++ /dev/null
@@ -1,15 +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. - -#ifndef IOS_CHROME_BROWSER_UI_MAIN_MAIN_FEATURE_FLAGS_H_ -#define IOS_CHROME_BROWSER_UI_MAIN_MAIN_FEATURE_FLAGS_H_ - -#include "base/feature_list.h" - -extern const base::Feature kTabSwitcherPresentsBVC; - -// Returns whether the tab switcher will present the BVC.. -bool TabSwitcherPresentsBVCEnabled(); - -#endif // IOS_CHROME_BROWSER_UI_MAIN_MAIN_FEATURE_FLAGS_H_
diff --git a/ios/chrome/browser/ui/open_in_controller.h b/ios/chrome/browser/ui/open_in_controller.h index 50c8517..fd89aac 100644 --- a/ios/chrome/browser/ui/open_in_controller.h +++ b/ios/chrome/browser/ui/open_in_controller.h
@@ -13,8 +13,8 @@ #import "ios/chrome/browser/ui/open_in_toolbar.h" #include "url/gurl.h" -namespace net { -class URLRequestContextGetter; +namespace network { +class SharedURLLoaderFactory; } @class CRWWebController; @@ -23,8 +23,9 @@ @interface OpenInController : NSObject<UIGestureRecognizerDelegate, UIDocumentInteractionControllerDelegate> // Designated initializer. -- (id)initWithRequestContext:(net::URLRequestContextGetter*)requestContext - webController:(CRWWebController*)webController; +- (id)initWithURLLoaderFactory: + (scoped_refptr<network::SharedURLLoaderFactory>)urlLoaderFactory + webController:(CRWWebController*)webController; // Base view on which the Open In toolbar will be presented. @property(nonatomic, weak) UIView* baseView;
diff --git a/ios/chrome/browser/ui/open_in_controller.mm b/ios/chrome/browser/ui/open_in_controller.mm index db37595..6ecc569 100644 --- a/ios/chrome/browser/ui/open_in_controller.mm +++ b/ios/chrome/browser/ui/open_in_controller.mm
@@ -25,9 +25,8 @@ #include "ios/web/public/web_thread.h" #import "ios/web/web_state/ui/crw_web_controller.h" #include "net/base/load_flags.h" -#include "net/url_request/url_fetcher.h" -#include "net/url_request/url_fetcher_delegate.h" -#include "net/url_request/url_request_context_getter.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" #include "ui/base/l10n/l10n_util_mac.h" #import "ui/gfx/ios/NSString+CrStringDrawing.h" #include "url/gurl.h" @@ -41,8 +40,6 @@ // other applications. static NSString* const kDocumentsTempPath = @"OpenIn"; -static const int kHTTPResponseCodeSucceeded = 200; - // Duration of the show/hide animation for the |openInToolbar_|. const NSTimeInterval kOpenInToolbarAnimationDuration = 0.2; @@ -77,8 +74,8 @@ // updated. Used to know in which direction the scroll view is scrolling. @property(nonatomic, assign) CGFloat previousScrollViewOffset; -// URLFetcher delegate method called when |fetcher_| completes a request. -- (void)urlFetchDidComplete:(const net::URLFetcher*)source; +// SimpleURLLoader completion callback, when |urlLoader_| completes a request. +- (void)urlLoadDidComplete:(const base::FilePath&)file_path; // Ensures the destination directory is created and any contained obsolete files // are deleted. Returns YES if the directory is created successfully. + (BOOL)createDestinationDirectoryAndRemoveObsoleteFiles; @@ -120,16 +117,10 @@ // Bridge to deliver method calls from C++ to the |OpenInController| class. class OpenInControllerBridge - : public net::URLFetcherDelegate, - public base::RefCountedThreadSafe<OpenInControllerBridge> { + : public base::RefCountedThreadSafe<OpenInControllerBridge> { public: explicit OpenInControllerBridge(OpenInController* owner) : owner_(owner) {} - void OnURLFetchComplete(const net::URLFetcher* source) override { - DCHECK(owner_); - [owner_ urlFetchDidComplete:source]; - } - BOOL CreateDestinationDirectoryAndRemoveObsoleteFiles(void) { return [OpenInController createDestinationDirectoryAndRemoveObsoleteFiles]; } @@ -157,7 +148,7 @@ protected: friend base::RefCountedThreadSafe<OpenInControllerBridge>; - ~OpenInControllerBridge() override {} + virtual ~OpenInControllerBridge() {} private: __weak OpenInController* owner_; @@ -185,15 +176,15 @@ // Suggested filename for the document. NSString* suggestedFilename_; - // Fetcher used to redownload the document and save it in the sandbox. - std::unique_ptr<net::URLFetcher> fetcher_; + // Loader used to redownload the document and save it in the sandbox. + std::unique_ptr<network::SimpleURLLoader> urlLoader_; // CRWWebController used to check if the tap is not on a link and the // |openInToolbar_| should be displayed. CRWWebController* webController_; - // URLRequestContextGetter needed for the URLFetcher. - scoped_refptr<net::URLRequestContextGetter> requestContext_; + // URLLoaderFactory instance needed for URLLoader. + scoped_refptr<network::SharedURLLoaderFactory> urlLoaderFactory_; // Spinner view displayed while the file is downloading. UIView* overlayedView_; @@ -217,11 +208,12 @@ @synthesize baseView = _baseView; @synthesize previousScrollViewOffset = _previousScrollViewOffset; -- (id)initWithRequestContext:(net::URLRequestContextGetter*)requestContext - webController:(CRWWebController*)webController { +- (id)initWithURLLoaderFactory: + (scoped_refptr<network::SharedURLLoaderFactory>)urlLoaderFactory + webController:(CRWWebController*)webController { self = [super init]; if (self) { - requestContext_ = requestContext; + urlLoaderFactory_ = std::move(urlLoaderFactory); webController_ = webController; tapRecognizer_ = [[UITapGestureRecognizer alloc] initWithTarget:self @@ -261,7 +253,7 @@ [documentController_ setDelegate:nil]; documentURL_ = GURL(); suggestedFilename_ = nil; - fetcher_.reset(); + urlLoader_.reset(); } - (void)detachFromWebController { @@ -370,13 +362,17 @@ bridge_ = new OpenInControllerBridge(self); // Download the document and save it at |filePath|. - fetcher_ = net::URLFetcher::Create(0, documentURL_, net::URLFetcher::GET, - bridge_.get()); - fetcher_->SetRequestContext(requestContext_.get()); - fetcher_->SetLoadFlags(net::LOAD_SKIP_CACHE_VALIDATION); - fetcher_->SaveResponseToFileAtPath( - base::FilePath(base::SysNSStringToUTF8(filePath)), sequencedTaskRunner_); - fetcher_->Start(); + auto resourceRequest = std::make_unique<network::ResourceRequest>(); + resourceRequest->url = documentURL_; + resourceRequest->load_flags = net::LOAD_SKIP_CACHE_VALIDATION; + + urlLoader_ = network::SimpleURLLoader::Create(std::move(resourceRequest), + NO_TRAFFIC_ANNOTATION_YET); + urlLoader_->DownloadToFile(urlLoaderFactory_.get(), + base::BindOnce(^(base::FilePath filePath) { + [self urlLoadDidComplete:filePath]; + }), + base::FilePath(base::SysNSStringToUTF8(filePath))); } - (void)handleTapOnOverlayedView:(UIGestureRecognizer*)gestureRecognizer { @@ -424,9 +420,9 @@ if (!webController_) return; - if (requestContext_.get()) { - // |requestContext_| is nil only if this is called from a unit test, in - // which case the |documentController_| was set already. + if (!documentController_) { + // If this is called from a unit test, |documentController_| was set + // already. documentController_ = [UIDocumentInteractionController interactionControllerWithURL:fileURL]; } @@ -439,17 +435,15 @@ [documentController_ presentOpenInMenuFromRect:anchorLocation_ inView:[webController_ view] animated:YES]; - if (requestContext_.get()) { - [self removeOverlayedView]; - if (!success) { - if (IsIPadIdiom()) - [self hideOpenInToolbar]; - NSString* errorMessage = - l10n_util::GetNSStringWithFixup(IDS_IOS_OPEN_IN_NO_APPS_REGISTERED); - [self showErrorWithMessage:errorMessage]; - } else { - isOpenInMenuDisplayed_ = YES; - } + [self removeOverlayedView]; + if (!success) { + if (IsIPadIdiom()) + [self hideOpenInToolbar]; + NSString* errorMessage = + l10n_util::GetNSStringWithFixup(IDS_IOS_OPEN_IN_NO_APPS_REGISTERED); + [self showErrorWithMessage:errorMessage]; + } else { + isOpenInMenuDisplayed_ = YES; } } @@ -589,16 +583,8 @@ return YES; } -#pragma mark - -#pragma mark URLFetcher delegate method - -- (void)urlFetchDidComplete:(const net::URLFetcher*)fetcher { - DCHECK(fetcher); - if (requestContext_.get()) - DCHECK_CURRENTLY_ON(web::WebThread::UI); - base::FilePath filePath; - if (fetcher->GetResponseCode() == kHTTPResponseCodeSucceeded && - fetcher->GetResponseAsFilePath(true, &filePath)) { +- (void)urlLoadDidComplete:(const base::FilePath&)filePath { + if (!filePath.empty()) { NSURL* fileURL = [NSURL fileURLWithPath:base::SysUTF8ToNSString(filePath.value())]; if (downloadCanceled_) {
diff --git a/ios/chrome/browser/ui/open_in_controller_unittest.mm b/ios/chrome/browser/ui/open_in_controller_unittest.mm index 77abe37..493acb7 100644 --- a/ios/chrome/browser/ui/open_in_controller_unittest.mm +++ b/ios/chrome/browser/ui/open_in_controller_unittest.mm
@@ -6,8 +6,9 @@ #include <memory> -#include "base/message_loop/message_loop.h" +#include "base/files/file_util.h" #include "base/strings/sys_string_conversions.h" +#include "base/test/scoped_task_environment.h" #import "ios/chrome/browser/tabs/tab.h" #import "ios/chrome/browser/ui/open_in_controller.h" #import "ios/chrome/browser/ui/open_in_controller_testing.h" @@ -15,6 +16,8 @@ #import "ios/web/web_state/ui/crw_web_controller.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_fetcher_delegate.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" #include "testing/platform_test.h" #import "third_party/ocmock/OCMock/OCMock.h" #include "third_party/ocmock/gtest_support.h" @@ -27,37 +30,48 @@ class OpenInControllerTest : public PlatformTest { public: - OpenInControllerTest() { - io_thread_.reset( - new web::TestWebThread(web::WebThread::IO, &message_loop_)); - } + OpenInControllerTest() + : test_shared_url_loader_factory_( + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_)) {} void TearDown() override { PlatformTest::TearDown(); } void SetUp() override { PlatformTest::SetUp(); + + // Set up the directory it downloads the file to. + // Note that the value of kDocumentsTempPath must match the one in + // open_in_controller.mm + { + NSString* const kDocumentsTempPath = @"OpenIn"; + NSString* tempDirPath = [NSTemporaryDirectory() + stringByAppendingPathComponent:kDocumentsTempPath]; + base::FilePath directory(base::SysNSStringToUTF8(tempDirPath)); + EXPECT_TRUE(base::CreateDirectory(directory)); + } + GURL documentURL = GURL("http://www.test.com/doc.pdf"); parent_view_ = [[UIView alloc] init]; id webController = [OCMockObject niceMockForClass:[CRWWebController class]]; - open_in_controller_ = - [[OpenInController alloc] initWithRequestContext:nil - webController:webController]; + open_in_controller_ = [[OpenInController alloc] + initWithURLLoaderFactory:test_shared_url_loader_factory_ + webController:webController]; [open_in_controller_ enableWithDocumentURL:documentURL suggestedFilename:@"doc.pdf"]; } - // |TestURLFetcher| requires a |MessageLoop|. - base::MessageLoopForUI message_loop_; - // Add |io_thread_| to release |URLRequestContextGetter| in - // |URLFetcher::Core|. - std::unique_ptr<web::TestWebThread> io_thread_; - // Creates a |TestURLFetcherFactory|, which automatically sets itself as - // |URLFetcher|'s factory. + + base::test::ScopedTaskEnvironment scoped_task_environment_; + network::TestURLLoaderFactory test_url_loader_factory_; + scoped_refptr<network::SharedURLLoaderFactory> + test_shared_url_loader_factory_; + net::TestURLFetcherFactory factory_; OpenInController* open_in_controller_; UIView* parent_view_; }; -TEST_F(OpenInControllerTest, DISABLED_TestDisplayOpenInMenu) { +TEST_F(OpenInControllerTest, TestDisplayOpenInMenu) { id documentController = [OCMockObject niceMockForClass:[UIDocumentInteractionController class]]; [open_in_controller_ setDocumentInteractionController:documentController]; @@ -67,19 +81,20 @@ inView:OCMOCK_ANY animated:YES]; - net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); - DCHECK(fetcher); - DCHECK(fetcher->delegate()); - fetcher->set_response_code(200); + auto* pending_request = test_url_loader_factory_.GetPendingRequest(0); + DCHECK(pending_request); // Set the response for the set URLFetcher to be a blank PDF. NSMutableData* pdfData = [NSMutableData data]; UIGraphicsBeginPDFContextToData(pdfData, CGRectMake(0, 0, 100, 100), @{}); UIGraphicsBeginPDFPage(); UIGraphicsEndPDFContext(); unsigned char* array = (unsigned char*)[pdfData bytes]; - fetcher->SetResponseString(std::string((char*)array, sizeof(pdfData))); - fetcher->SetResponseFilePath(base::FilePath("path/to/file.pdf")); - fetcher->delegate()->OnURLFetchComplete(fetcher); + + test_url_loader_factory_.SimulateResponseForPendingRequest( + pending_request->request.url.spec(), + std::string((char*)array, sizeof(pdfData))); + scoped_task_environment_.RunUntilIdle(); + EXPECT_OCMOCK_VERIFY(documentController); }
diff --git a/ios/chrome/browser/ui/settings/cells/BUILD.gn b/ios/chrome/browser/ui/settings/cells/BUILD.gn index 28da409a..4fbac99 100644 --- a/ios/chrome/browser/ui/settings/cells/BUILD.gn +++ b/ios/chrome/browser/ui/settings/cells/BUILD.gn
@@ -30,6 +30,8 @@ "settings_collapsible_item.mm", "settings_detail_item.h", "settings_detail_item.mm", + "settings_image_detail_text_item.h", + "settings_image_detail_text_item.mm", "settings_search_item.h", "settings_search_item.mm", "settings_switch_item.h",
diff --git a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h new file mode 100644 index 0000000..0f584412 --- /dev/null +++ b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h
@@ -0,0 +1,50 @@ +// 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 IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_ + +#import <Foundation/Foundation.h> + +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h" + +// SettingsImageDetailTextItem is an item that displays an image, a title and +// a detail text (optional). This item uses multi-lines text field. It also +// contains acommand id. +// This class is intended to be used with Google services settings view. +@interface SettingsImageDetailTextItem : CollectionViewItem + +// The image to display. +@property(nonatomic, strong) UIImage* image; + +// The title text to display. +@property(nonatomic, copy) NSString* text; + +// The detail text to display. +@property(nonatomic, copy) NSString* detailText; + +@end + +// Cell representation for SettingsImageDetailTextItem. +// +--------------------------------------------------+ +// | +-------+ | +// | | image | Multiline title | +// | | | Optional multiline detail text | +// | +-------+ | +// +--------------------------------------------------+ +@interface SettingsImageDetailTextCell : MDCCollectionViewCell + +// Cell image. +@property(nonatomic, readonly, strong) UIImageView* imageView; + +// Cell title. +@property(nonatomic, readonly, strong) UILabel* textLabel; + +// Cell subtitle. +@property(nonatomic, readonly, strong) UILabel* detailTextLabel; + +@end + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
diff --git a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm new file mode 100644 index 0000000..f8b64fc --- /dev/null +++ b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm
@@ -0,0 +1,161 @@ +// 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. + +#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h" + +#include "ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h" +#import "ios/chrome/browser/ui/uikit_ui_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +// Padding used on the leading and trailing edges of the cell. +const CGFloat kHorizontalPadding = 16; + +// Padding used on the top and bottom edges of the cell. +const CGFloat kVerticalPadding = 16; + +// Image height and width. +const CGFloat kImageSize = 40; + +// Padding used between the image and text. +const CGFloat kHorizontalImagePadding = 10; + +} // namespace + +@interface SettingsImageDetailTextCell () + +// Container view which contains |self.textLabel| and |self.detailTextLabel|. +@property(nonatomic, strong) UIStackView* textStackView; + +@end + +#pragma mark - SettingsImageDetailTextItem + +@implementation SettingsImageDetailTextItem + +@synthesize image = _image; +@synthesize text = _text; +@synthesize detailText = _detailText; + +- (instancetype)initWithType:(NSInteger)type { + self = [super initWithType:type]; + if (self) { + self.cellClass = [SettingsImageDetailTextCell class]; + } + return self; +} + +- (void)configureCell:(SettingsImageDetailTextCell*)cell { + [super configureCell:cell]; + cell.isAccessibilityElement = YES; + cell.textLabel.text = self.text; + cell.detailTextLabel.text = self.detailText; + cell.imageView.image = self.image; +} + +@end + +#pragma mark - SettingsImageDetailTextCell + +@implementation SettingsImageDetailTextCell + +@synthesize imageView = _imageView; +@synthesize textLabel = _textLabel; +@synthesize detailTextLabel = _detailTextLabel; +@synthesize textStackView = _textStackView; + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + UIView* contentView = self.contentView; + + _imageView = [[UIImageView alloc] init]; + _imageView.translatesAutoresizingMaskIntoConstraints = NO; + [contentView addSubview:_imageView]; + + _textLabel = [[UILabel alloc] init]; + _textLabel.numberOfLines = 0; + _textLabel.font = [UIFont systemFontOfSize:kUIKitMainFontSize]; + _textLabel.textColor = UIColorFromRGB(kUIKitMainTextColor); + + _detailTextLabel = [[UILabel alloc] init]; + _detailTextLabel.numberOfLines = 0; + _detailTextLabel.font = + [UIFont systemFontOfSize:kUIKitMultilineDetailFontSize]; + _detailTextLabel.textColor = UIColorFromRGB(kUIKitMultilineDetailTextColor); + + _textStackView = [[UIStackView alloc] + initWithArrangedSubviews:@[ _textLabel, _detailTextLabel ]]; + _textStackView.axis = UILayoutConstraintAxisVertical; + _textStackView.translatesAutoresizingMaskIntoConstraints = NO; + [contentView addSubview:_textStackView]; + + [NSLayoutConstraint activateConstraints:@[ + // Horizontal contraints for |_imageView| and |_textStackView|. + [_imageView.heightAnchor constraintEqualToConstant:kImageSize], + [_imageView.widthAnchor constraintEqualToConstant:kImageSize], + [_imageView.leadingAnchor + constraintEqualToAnchor:contentView.leadingAnchor + constant:kHorizontalPadding], + [_textStackView.leadingAnchor + constraintEqualToAnchor:_imageView.trailingAnchor + constant:kHorizontalImagePadding], + [contentView.trailingAnchor + constraintEqualToAnchor:_textStackView.trailingAnchor + constant:kHorizontalPadding], + // Vertical contraints for |_imageView| and |_textStackView|. + [_imageView.centerYAnchor + constraintEqualToAnchor:contentView.centerYAnchor], + [_imageView.topAnchor + constraintGreaterThanOrEqualToAnchor:contentView.topAnchor + constant:kVerticalPadding], + [contentView.bottomAnchor + constraintGreaterThanOrEqualToAnchor:_imageView.bottomAnchor + constant:kVerticalPadding], + [_textStackView.centerYAnchor + constraintEqualToAnchor:contentView.centerYAnchor], + [_textStackView.topAnchor + constraintGreaterThanOrEqualToAnchor:contentView.topAnchor + constant:kVerticalPadding], + [contentView.bottomAnchor + constraintGreaterThanOrEqualToAnchor:_textStackView.bottomAnchor + constant:kVerticalPadding], + ]]; + } + return self; +} + +// Implement -layoutSubviews as per instructions in documentation for +// +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:]." +- (void)layoutSubviews { + [super layoutSubviews]; + // Adjust the text and detailText label preferredMaxLayoutWidth when the + // parent's width changes, for instance on screen rotation. + CGFloat prefferedMaxLayoutWidth = CGRectGetWidth(self.contentView.frame) - + CGRectGetWidth(self.imageView.frame) - + 2 * kHorizontalPadding - + kHorizontalImagePadding; + self.textLabel.preferredMaxLayoutWidth = prefferedMaxLayoutWidth; + self.detailTextLabel.preferredMaxLayoutWidth = prefferedMaxLayoutWidth; + + // Re-layout with the new preferred width to allow the label to adjust its + // height. + [super layoutSubviews]; +} + +#pragma mark - UIAccessibility + +- (NSString*)accessibilityLabel { + if (self.detailTextLabel.text) { + return [NSString stringWithFormat:@"%@, %@", self.textLabel.text, + self.detailTextLabel.text]; + } + return self.textLabel.text; +} + +@end
diff --git a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm index 24e2205c..d8d06fb 100644 --- a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm +++ b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
@@ -39,6 +39,7 @@ #import "ios/chrome/browser/ui/settings/cells/passphrase_error_item.h" #import "ios/chrome/browser/ui/settings/cells/password_details_item.h" #import "ios/chrome/browser/ui/settings/cells/settings_detail_item.h" +#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h" #import "ios/chrome/browser/ui/settings/cells/settings_search_item.h" #import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h" #import "ios/chrome/browser/ui/settings/cells/settings_text_item.h" @@ -115,6 +116,7 @@ ItemTypeSyncEncryptionChecked, ItemTypeSyncPassphraseError, ItemTypeContentSuggestions, + ItemTypeImageDetailTextItem, }; // Image fixed horizontal size. @@ -257,6 +259,25 @@ @"incididunt ut labore et dolore magna aliqua."; [model addItem:multilineDetailItem toSectionWithIdentifier:SectionIdentifierMultilineCell]; + [model addItem:[self settingsImageDetailTextItem] + toSectionWithIdentifier:SectionIdentifierMultilineCell]; + SettingsImageDetailTextItem* settingsImageDetailTextItem = + [self settingsImageDetailTextItem]; + settingsImageDetailTextItem.text = @"Short title"; + [model addItem:settingsImageDetailTextItem + toSectionWithIdentifier:SectionIdentifierMultilineCell]; + settingsImageDetailTextItem = [self settingsImageDetailTextItem]; + settingsImageDetailTextItem.detailText = @"Short detail text"; + [model addItem:settingsImageDetailTextItem + toSectionWithIdentifier:SectionIdentifierMultilineCell]; + settingsImageDetailTextItem = [self settingsImageDetailTextItem]; + settingsImageDetailTextItem.detailText = + @"Text multiline that works nice with a very very very very very long " + @"text Text multiline that works nice with a very very very very very " + @"long text Text multiline that works nice with a very very very very " + @"very long text"; + [model addItem:settingsImageDetailTextItem + toSectionWithIdentifier:SectionIdentifierMultilineCell]; // Switch cells. [model addSectionWithIdentifier:SectionIdentifierSwitchCell]; @@ -402,7 +423,7 @@ // Content Suggestions cells. [model addSectionWithIdentifier:SectionIdentifierContentSuggestionsCell]; - [model addItem:[self ContentSuggestionsItem] + [model addItem:[self contentSuggestionsItem] toSectionWithIdentifier:SectionIdentifierContentSuggestionsCell]; [model addItem:[self contentSuggestionsFooterItem] toSectionWithIdentifier:SectionIdentifierContentSuggestionsCell]; @@ -427,6 +448,7 @@ CollectionViewItem* item = [self.collectionViewModel itemAtIndexPath:indexPath]; switch (item.type) { + case ItemTypeImageDetailTextItem: case ItemTypeContentSuggestions: case ItemTypeFooter: case ItemTypeSwitchDynamicHeight: @@ -794,7 +816,7 @@ return footerItem; } -- (ContentSuggestionsItem*)ContentSuggestionsItem { +- (ContentSuggestionsItem*)contentSuggestionsItem { ContentSuggestionsItem* articleItem = [[ContentSuggestionsItem alloc] initWithType:ItemTypeContentSuggestions title:@"This is an incredible article, you should read it!" @@ -803,6 +825,18 @@ return articleItem; } +- (SettingsImageDetailTextItem*)settingsImageDetailTextItem { + SettingsImageDetailTextItem* settingsImageDetailTextItem = + [[SettingsImageDetailTextItem alloc] + initWithType:ItemTypeImageDetailTextItem]; + settingsImageDetailTextItem.image = + [UIImage imageNamed:@"ios_default_avatar"]; + settingsImageDetailTextItem.text = + @"Text multiline that works nice with a very very very very very long " + @"text"; + return settingsImageDetailTextItem; +} + - (ContentSuggestionsFooterItem*)contentSuggestionsFooterItem { ContentSuggestionsFooterItem* footerItem = [[ContentSuggestionsFooterItem alloc]
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.h b/ios/chrome/browser/ui/settings/settings_navigation_controller.h index d153a84..7b185f76 100644 --- a/ios/chrome/browser/ui/settings/settings_navigation_controller.h +++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.h
@@ -78,15 +78,6 @@ delegate:(id<SettingsNavigationControllerDelegate>) delegate; -// Creates a new ClearBrowsingDataCollectionViewController and the chrome around -// it. -// |browserState| is used to personalize some settings aspects and should not be -// nil. |delegate| may be nil. -+ (SettingsNavigationController*) -newClearBrowsingDataController:(ios::ChromeBrowserState*)browserState - delegate: - (id<SettingsNavigationControllerDelegate>)delegate; - // Creates a new SavePasswordsCollectionViewController and the chrome around it. // |browserState| is used to personalize some settings aspects and should not be // nil. |delegate| may be nil.
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm index d5660f2..5551c51 100644 --- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -17,7 +17,6 @@ #import "ios/chrome/browser/ui/material_components/utils.h" #import "ios/chrome/browser/ui/settings/accounts_collection_view_controller.h" #import "ios/chrome/browser/ui/settings/autofill_profile_collection_view_controller.h" -#import "ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h" #import "ios/chrome/browser/ui/settings/google_services_settings_coordinator.h" #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller.h" #import "ios/chrome/browser/ui/settings/import_data_collection_view_controller.h" @@ -182,22 +181,6 @@ } + (SettingsNavigationController*) -newClearBrowsingDataController:(ios::ChromeBrowserState*)browserState - delegate: - (id<SettingsNavigationControllerDelegate>)delegate { - ClearBrowsingDataCollectionViewController* controller = - [[ClearBrowsingDataCollectionViewController alloc] - initWithBrowserState:browserState]; - controller.dispatcher = [delegate dispatcherForSettings]; - SettingsNavigationController* nc = [[SettingsNavigationController alloc] - initWithRootViewController:controller - browserState:browserState - delegate:delegate]; - [controller navigationItem].rightBarButtonItem = [nc doneButton]; - return nc; -} - -+ (SettingsNavigationController*) newSyncEncryptionPassphraseController:(ios::ChromeBrowserState*)browserState delegate:(id<SettingsNavigationControllerDelegate>) delegate {
diff --git a/ios/chrome/browser/web/forms_egtest.mm b/ios/chrome/browser/web/forms_egtest.mm index ea3e1a3..1c992cf 100644 --- a/ios/chrome/browser/web/forms_egtest.mm +++ b/ios/chrome/browser/web/forms_egtest.mm
@@ -250,6 +250,15 @@ // Go to a new page and go back and check that the data is reposted. [ChromeEarlGrey loadURL:GetGenericUrl()]; [ChromeEarlGrey goBack]; + + // WKBasedNavigationManager doesn't triggere repost on |goForward| due to + // WKWebView's back-forward cache. Force reload to trigger repost. Not using + // [ChromeEarlGrey reload] because WKBasedNavigationManager presents repost + // confirmation dialog before loading stops. + if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { + [chrome_test_util::BrowserCommandDispatcherForMainBVC() reload]; + } + [self confirmResendWarning]; [ChromeEarlGrey waitForWebViewContainingText:kDestinationText]; [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())] @@ -271,6 +280,15 @@ [ChromeEarlGrey goBack]; [ChromeEarlGrey goForward]; + + // WKBasedNavigationManager doesn't triggere repost on |goForward| due to + // WKWebView's back-forward cache. Force reload to trigger repost. Not using + // [ChromeEarlGrey reload] because WKBasedNavigationManager presents repost + // confirmation dialog before loading stops. + if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { + [chrome_test_util::BrowserCommandDispatcherForMainBVC() reload]; + } + [self confirmResendWarning]; [ChromeEarlGrey waitForWebViewContainingText:kDestinationText]; [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())] @@ -325,16 +343,38 @@ [ChromeEarlGrey goBack]; [ChromeEarlGrey goForward]; + // WKBasedNavigationManager doesn't triggere repost on |goForward| due to + // WKWebView's back-forward cache. Force reload to trigger repost. Not using + // [ChromeEarlGrey reload] because WKBasedNavigationManager presents repost + // confirmation dialog before loading stops. + if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { + [chrome_test_util::BrowserCommandDispatcherForMainBVC() reload]; + } + [[EarlGrey selectElementWithMatcher:ElementToDismissAlert(@"Cancel")] performAction:grey_tap()]; [ChromeEarlGrey waitForPageToFinishLoading]; - // Verify that navigation was cancelled, and forward navigation is possible. - [ChromeEarlGrey waitForWebViewContainingText:kSubmitButtonLabel]; - [[EarlGrey selectElementWithMatcher:OmniboxText(GetFormUrl().GetContent())] - assertWithMatcher:grey_notNil()]; - [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()] - assertWithMatcher:grey_interactable()]; + // Expected behavior is different between the two navigation manager + // implementations. + if (!web::GetWebClient()->IsSlimNavigationManagerEnabled()) { + // LegacyNavigationManager displays repost on |goBack|. So after cancelling, + // web view should show form URL. + [ChromeEarlGrey waitForWebViewContainingText:kSubmitButtonLabel]; + [[EarlGrey selectElementWithMatcher:OmniboxText(GetFormUrl().GetContent())] + assertWithMatcher:grey_notNil()]; + [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()] + assertWithMatcher:grey_interactable()]; + } else { + // WKBasedNavigationManager displays repost on |reload|. So after + // cancelling, web view should show |destinationURL|. + [ChromeEarlGrey waitForWebViewContainingText:kDestinationText]; + [[EarlGrey + selectElementWithMatcher:OmniboxText(destinationURL.GetContent())] + assertWithMatcher:grey_notNil()]; + [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()] + assertWithMatcher:grey_interactable()]; + } } // A new navigation dismisses the repost dialog.
diff --git a/ios/chrome/test/data/favicon/test_favicon.png b/ios/chrome/test/data/favicon/test_favicon.png deleted file mode 100644 index e9100dae..0000000 --- a/ios/chrome/test/data/favicon/test_favicon.png +++ /dev/null Binary files differ
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn index 67f6ded..ee525a4 100644 --- a/ios/third_party/material_components_ios/BUILD.gn +++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -8,7 +8,9 @@ visibility = [ ":material_components_ios" ] include_dirs = [ "src/components/ActivityIndicator/src", + "src/components/Buttons/src/ShapeThemer", "src/components/AppBar/src", + "src/components/private/ShapeLibrary/src", "src/components/ButtonBar/src", "src/components/Buttons/src", "src/components/CollectionCells/src", @@ -30,6 +32,7 @@ "src/components/private/Shapes/src/", "src/components/private/UIMetrics/src", "src/components/schemes/Color/src", + "src/components/schemes/Shape/src", "src/components/schemes/Typography/src", ] } @@ -120,6 +123,11 @@ "src/components/Buttons/src/MDCRaisedButton.h", "src/components/Buttons/src/MDCRaisedButton.m", "src/components/Buttons/src/MaterialButtons.h", + "src/components/Buttons/src/ShapeThemer/MDCButtonShapeThemer.h", + "src/components/Buttons/src/ShapeThemer/MDCButtonShapeThemer.m", + "src/components/Buttons/src/ShapeThemer/MDCFloatingButtonShapeThemer.h", + "src/components/Buttons/src/ShapeThemer/MDCFloatingButtonShapeThemer.m", + "src/components/Buttons/src/ShapeThemer/MaterialButtons+ShapeThemer.h", "src/components/Buttons/src/TypographyThemer/MDCButtonTypographyThemer.h", "src/components/Buttons/src/TypographyThemer/MDCButtonTypographyThemer.m", "src/components/Buttons/src/private/MDCButton+Subclassing.h", @@ -180,6 +188,8 @@ "src/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.h", "src/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.m", "src/components/FlexibleHeader/src/MaterialFlexibleHeader.h", + "src/components/FlexibleHeader/src/private/MDCFlexibleHeaderTopSafeArea.h", + "src/components/FlexibleHeader/src/private/MDCFlexibleHeaderTopSafeArea.m", "src/components/FlexibleHeader/src/private/MDCStatusBarShifter.h", "src/components/FlexibleHeader/src/private/MDCStatusBarShifter.m", "src/components/HeaderStackView/src/MDCHeaderStackView.h", @@ -288,6 +298,14 @@ "src/components/private/Overlay/src/private/MDCOverlayObserverTransition.m", "src/components/private/Overlay/src/private/MDCOverlayUtilities.h", "src/components/private/Overlay/src/private/MDCOverlayUtilities.m", + "src/components/private/Shapes/src/MDCCornerTreatment.h", + "src/components/private/Shapes/src/MDCCornerTreatment.m", + "src/components/private/Shapes/src/MDCEdgeTreatment.h", + "src/components/private/Shapes/src/MDCEdgeTreatment.m", + "src/components/private/Shapes/src/MDCPathGenerator.h", + "src/components/private/Shapes/src/MDCPathGenerator.m", + "src/components/private/Shapes/src/MDCRectangleShapeGenerator.h", + "src/components/private/Shapes/src/MDCRectangleShapeGenerator.m", "src/components/private/Shapes/src/MDCShapedShadowLayer.h", "src/components/private/Shapes/src/MDCShapedShadowLayer.m", "src/components/private/Shapes/src/MDCShapedView.h", @@ -312,6 +330,10 @@ "src/components/schemes/Color/src/MDCSemanticColorScheme.h", "src/components/schemes/Color/src/MDCSemanticColorScheme.m", "src/components/schemes/Color/src/MaterialColorScheme.h", + "src/components/schemes/Shape/src/MDCShapeCategory.h", + "src/components/schemes/Shape/src/MDCShapeCategory.m", + "src/components/schemes/Shape/src/MDCShapeScheme.h", + "src/components/schemes/Shape/src/MDCShapeScheme.m", "src/components/schemes/Typography/src/MDCLegacyFontScheme.h", "src/components/schemes/Typography/src/MDCLegacyFontScheme.m", "src/components/schemes/Typography/src/MDCTypographyScheme.h",
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 6446d189..e344f04 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -4358,6 +4358,7 @@ decisionHandler(WKNavigationActionPolicyCancel); if (action.targetFrame.mainFrame) { [_pendingNavigationInfo setCancelled:YES]; + _webStateImpl->SetIsLoading(false); } } })); @@ -5549,6 +5550,22 @@ BOOL sameDocumentNavigation = currentItem->IsCreatedFromPushState() || currentItem->IsCreatedFromHashChange(); + if (holder->back_forward_list_item()) { + // Check if holder's WKBackForwardListItem still correctly represents + // navigation item. With LegacyNavigationManager, replaceState operation + // creates a new navigation item, leaving the old item committed. That + // old committed item will be associated with WKBackForwardListItem whose + // state was replaced. So old item won't have correct WKBackForwardListItem. + if (net::GURLWithNSURL(holder->back_forward_list_item().URL) != + currentItem->GetURL()) { + // The state was replaced for this item. The item should not be a part of + // committed items, but it's too late to remove the item. Cleaup + // WKBackForwardListItem and mark item with "state replaced" flag. + currentItem->SetHasStateBeenReplaced(true); + holder->set_back_forward_list_item(nil); + } + } + // If the request has POST data and is not a repost form, configure and // run the POST request. if (POSTData.length && !repostedForm) {
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn index e6c22bc..64f0c40 100644 --- a/ios/web_view/BUILD.gn +++ b/ios/web_view/BUILD.gn
@@ -270,6 +270,7 @@ "//components/signin/ios/browser:active_state_manager", "//components/strings:components_strings_grit", "//components/sync", + "//components/sync_sessions", "//components/translate/core/browser", "//components/translate/core/common", "//components/translate/ios/browser",
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS index 106fa0ae..7636c26 100644 --- a/ios/web_view/internal/DEPS +++ b/ios/web_view/internal/DEPS
@@ -23,6 +23,7 @@ "+components/signin/ios", "+components/strings/grit", "+components/sync", + "+components/sync_sessions", "+components/translate/core", "+components/translate/ios", "+components/version_info",
diff --git a/ios/web_view/internal/sync/web_view_sync_client.h b/ios/web_view/internal/sync/web_view_sync_client.h index 412193e..952f02167 100644 --- a/ios/web_view/internal/sync/web_view_sync_client.h +++ b/ios/web_view/internal/sync/web_view_sync_client.h
@@ -40,6 +40,7 @@ bookmarks::BookmarkModel* GetBookmarkModel() override; favicon::FaviconService* GetFaviconService() override; history::HistoryService* GetHistoryService() override; + sync_sessions::SessionSyncService* GetSessionSyncService() override; bool HasPasswordStore() override; base::RepeatingClosure GetPasswordStateChangedCallback() override; syncer::DataTypeController::TypeVector CreateDataTypeControllers( @@ -48,7 +49,6 @@ invalidation::InvalidationService* GetInvalidationService() override; BookmarkUndoService* GetBookmarkUndoServiceIfExists() override; scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override; - sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override; base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType( syncer::ModelType type) override; base::WeakPtr<syncer::ModelTypeControllerDelegate>
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm index d661a1a2..2ec1c6b 100644 --- a/ios/web_view/internal/sync/web_view_sync_client.mm +++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -120,6 +120,10 @@ return nullptr; } +sync_sessions::SessionSyncService* WebViewSyncClient::GetSessionSyncService() { + return nullptr; +} + bool WebViewSyncClient::HasPasswordStore() { return true; } @@ -162,10 +166,6 @@ return nullptr; } -sync_sessions::SyncSessionsClient* WebViewSyncClient::GetSyncSessionsClient() { - return nullptr; -} - base::WeakPtr<syncer::SyncableService> WebViewSyncClient::GetSyncableServiceForType(syncer::ModelType type) { if (!profile_web_data_service_) {
diff --git a/ios/web_view/internal/web_view_browser_state.mm b/ios/web_view/internal/web_view_browser_state.mm index e444cc1..f8d6be1 100644 --- a/ios/web_view/internal/web_view_browser_state.mm +++ b/ios/web_view/internal/web_view_browser_state.mm
@@ -24,6 +24,7 @@ #include "components/signin/ios/browser/active_state_manager.h" #include "components/sync/base/pref_names.h" #include "components/sync/base/sync_prefs.h" +#include "components/sync_sessions/session_sync_prefs.h" #include "components/translate/core/browser/translate_pref_names.h" #include "components/translate/core/browser/translate_prefs.h" #include "ios/web/public/web_task_traits.h" @@ -177,6 +178,7 @@ #if BUILDFLAG(IOS_WEB_VIEW_ENABLE_SYNC) gcm::GCMChannelStatusSyncer::RegisterProfilePrefs(pref_registry); + sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(pref_registry); syncer::SyncPrefs::RegisterProfilePrefs(pref_registry); #endif // BUILDFLAG(IOS_WEB_VIEW_ENABLE_SYNC)
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h index d1255cb..92741c3f 100644 --- a/media/base/video_frame_metadata.h +++ b/media/base/video_frame_metadata.h
@@ -130,10 +130,8 @@ PAGE_SCALE_FACTOR, ROOT_SCROLL_OFFSET_X, ROOT_SCROLL_OFFSET_Y, -#if defined(OS_ANDROID) TOP_CONTROLS_HEIGHT, TOP_CONTROLS_SHOWN_RATIO, -#endif NUM_KEYS };
diff --git a/media/gpu/windows/d3d11_video_decoder_impl.cc b/media/gpu/windows/d3d11_video_decoder_impl.cc index 4d9440e4..148a6c66 100644 --- a/media/gpu/windows/d3d11_video_decoder_impl.cc +++ b/media/gpu/windows/d3d11_video_decoder_impl.cc
@@ -32,8 +32,8 @@ D3D11VideoDecoderImpl::~D3D11VideoDecoderImpl() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (stub_ && !wait_sequence_id_.is_null()) - stub_->channel()->scheduler()->DestroySequence(wait_sequence_id_); + if (stub_) + DestroyStub(); } void D3D11VideoDecoderImpl::Initialize( @@ -55,8 +55,7 @@ return_picture_buffer_cb_ = std::move(return_picture_buffer_cb); - // TODO(liberato): see GpuVideoFrameFactory. - // stub_->AddDestructionObserver(this); + stub_->AddDestructionObserver(this); wait_sequence_id_ = stub_->channel()->scheduler()->CreateSequence( gpu::SchedulingPriority::kNormal); @@ -68,6 +67,9 @@ const gpu::SyncToken& sync_token) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (!stub_) + return; + stub_->channel()->scheduler()->ScheduleTask(gpu::Scheduler::Task( wait_sequence_id_, base::BindOnce(&D3D11VideoDecoderImpl::OnSyncTokenReleased, GetWeakPtr(), @@ -82,6 +84,21 @@ return_picture_buffer_cb_.Run(std::move(buffer)); } +void D3D11VideoDecoderImpl::OnWillDestroyStub(bool have_context) { + DestroyStub(); +} + +void D3D11VideoDecoderImpl::DestroyStub() { + DCHECK(stub_); + gpu::CommandBufferStub* stub = stub_; + stub_ = nullptr; + + stub->RemoveDestructionObserver(this); + + if (!wait_sequence_id_.is_null()) + stub->channel()->scheduler()->DestroySequence(wait_sequence_id_); +} + base::WeakPtr<D3D11VideoDecoderImpl> D3D11VideoDecoderImpl::GetWeakPtr() { // May be called from any thread. return weak_factory_.GetWeakPtr();
diff --git a/media/gpu/windows/d3d11_video_decoder_impl.h b/media/gpu/windows/d3d11_video_decoder_impl.h index c765a69c..bb71fad7 100644 --- a/media/gpu/windows/d3d11_video_decoder_impl.h +++ b/media/gpu/windows/d3d11_video_decoder_impl.h
@@ -18,6 +18,7 @@ #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" #include "gpu/command_buffer/service/sequence_id.h" +#include "gpu/ipc/service/command_buffer_stub.h" #include "media/gpu/media_gpu_export.h" namespace gpu { @@ -33,13 +34,14 @@ // Does the gpu main thread work for D3D11VideoDecoder. Except as noted, this // class lives on the GPU main thread. // TODO(liberato): Rename this class as a follow-on to this refactor. -class MEDIA_GPU_EXPORT D3D11VideoDecoderImpl { +class MEDIA_GPU_EXPORT D3D11VideoDecoderImpl + : public gpu::CommandBufferStub::DestructionObserver { public: // May be constructed on any thread. explicit D3D11VideoDecoderImpl( std::unique_ptr<MediaLog> media_log, base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb); - virtual ~D3D11VideoDecoderImpl(); + ~D3D11VideoDecoderImpl() override; using InitCB = base::OnceCallback<void(bool success)>; @@ -64,6 +66,10 @@ private: void OnSyncTokenReleased(scoped_refptr<D3D11PictureBuffer> buffer); + void OnWillDestroyStub(bool have_context) override; + + void DestroyStub(); + std::unique_ptr<MediaLog> media_log_; base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb_;
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h index 511118e..13711060 100644 --- a/pdf/pdf_engine.h +++ b/pdf/pdf_engine.h
@@ -53,10 +53,6 @@ namespace chrome_pdf { -// Zero Width Whitespace character that requires special handling in multiple -// locations. -constexpr base::char16 kZeroWidthSpace = 0x200B; - // Do one time initialization of the SDK. bool InitializeSDK(); // Tells the SDK that we're shutting down.
diff --git a/pdf/pdfium/findtext_unittest.cc b/pdf/pdfium/findtext_unittest.cc index c077b74..068c62a 100644 --- a/pdf/pdfium/findtext_unittest.cc +++ b/pdf/pdfium/findtext_unittest.cc
@@ -20,13 +20,14 @@ class TestDocumentLoader : public DocumentLoader { public: - explicit TestDocumentLoader(Client* client) : client_(client) { + TestDocumentLoader(Client* client, const base::FilePath::StringType& pdf_name) + : client_(client) { base::FilePath pdf_path; CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &pdf_path)); pdf_path = pdf_path.Append(FILE_PATH_LITERAL("pdf")) .Append(FILE_PATH_LITERAL("test")) .Append(FILE_PATH_LITERAL("data")) - .Append(FILE_PATH_LITERAL("hello_world2.pdf")); + .Append(pdf_name); CHECK(base::ReadFileToString(pdf_path, &pdf_data_)); } ~TestDocumentLoader() override = default; @@ -66,9 +67,11 @@ std::string pdf_data_; }; +const base::FilePath::CharType* g_test_pdf_name; + std::unique_ptr<DocumentLoader> CreateTestDocumentLoader( DocumentLoader::Client* client) { - return std::make_unique<TestDocumentLoader>(client); + return std::make_unique<TestDocumentLoader>(client, g_test_pdf_name); } class TestClient : public PDFEngine::Client { @@ -137,11 +140,11 @@ protected: void SetUp() override { InitializePDFium(); - PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting( - &CreateTestDocumentLoader); } + void TearDown() override { PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(nullptr); + g_test_pdf_name = nullptr; FPDF_DestroyLibrary(); } @@ -154,10 +157,18 @@ FPDF_InitLibraryWithConfig(&config); } + void SetDocumentForTest(const base::FilePath::CharType* test_pdf_name) { + g_test_pdf_name = test_pdf_name; + PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting( + &CreateTestDocumentLoader); + } + + private: DISALLOW_COPY_AND_ASSIGN(FindTextTest); }; TEST_F(FindTextTest, FindText) { + SetDocumentForTest(FILE_PATH_LITERAL("hello_world2.pdf")); pp::URLLoader dummy_loader; TestClient client; PDFiumEngine engine(&client, true); @@ -177,4 +188,24 @@ engine.StartFind("o", /*case_sensitive=*/true); } +TEST_F(FindTextTest, FindHyphenatedText) { + SetDocumentForTest(FILE_PATH_LITERAL("spanner.pdf")); + pp::URLLoader dummy_loader; + TestClient client; + PDFiumEngine engine(&client, true); + ASSERT_TRUE(engine.New("https://chromium.org/dummy.pdf", "")); + ASSERT_TRUE(engine.HandleDocumentLoad(dummy_loader)); + + { + InSequence sequence; + + EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(1, false)); + EXPECT_CALL(client, NotifySelectedFindResultChanged(0)); + for (int i = 1; i < 6; ++i) + EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(i + 1, false)); + EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(6, true)); + } + + engine.StartFind("application", /*case_sensitive=*/true); +} } // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index 25eb931f..e5d03c9 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -1918,28 +1918,65 @@ character_to_start_searching_from, text_length, data); api_string_adapter.Close(written); + base::string16 stripped_page_text; + stripped_page_text.reserve(page_text.size()); + // Values in |stripped_indices| are in the stripped text index space and + // indicate a character was removed from the page text before the given + // index. If multiple characters are removed in a row then there will be + // multiple entries with the same value. + std::vector<size_t> stripped_indices; + for (size_t i = 0; i < page_text.size(); i++) { + base::char16 c = page_text[i]; + if (IsIgnorableCharacter(c)) + stripped_indices.push_back(stripped_page_text.size()); + else + stripped_page_text.push_back(c); + } + std::vector<PDFEngine::Client::SearchStringResult> results = - client_->SearchString(page_text.c_str(), term.c_str(), case_sensitive); + client_->SearchString(stripped_page_text.c_str(), term.c_str(), + case_sensitive); for (const auto& result : results) { + // Need to convert from stripped page text start to page text start, by + // incrementing for all the characters stripped before it in the string. + auto stripped_indices_begin = std::upper_bound( + stripped_indices.begin(), stripped_indices.end(), result.start_index); + size_t page_text_result_start_index = + result.start_index + + std::distance(stripped_indices.begin(), stripped_indices_begin); + + // Need to convert the stripped page length into a page text length, since + // the matching range may have stripped characters within it. This + // conversion only cares about skipped characters in the result interval. + auto stripped_indices_end = + std::upper_bound(stripped_indices_begin, stripped_indices.end(), + result.start_index + result.length); + int term_stripped_count = + std::distance(stripped_indices_begin, stripped_indices_end); + int page_text_result_length = result.length + term_stripped_count; + // Need to map the indexes from the page text, which may have generated // characters like space etc, to character indices from the page. int text_to_start_searching_from = FPDFText_GetTextIndexFromCharIndex( pages_[current_page]->GetTextPage(), character_to_start_searching_from); - int temp_start = result.start_index + text_to_start_searching_from; + int temp_start = + page_text_result_start_index + text_to_start_searching_from; int start = FPDFText_GetCharIndexFromTextIndex( pages_[current_page]->GetTextPage(), temp_start); int end = FPDFText_GetCharIndexFromTextIndex( - pages_[current_page]->GetTextPage(), temp_start + result.length); + pages_[current_page]->GetTextPage(), + temp_start + page_text_result_length); // If |term| occurs at the end of a page, then |end| will be -1 due to the // index being out of bounds. Compensate for this case so the range // character count calculation below works out. - if (temp_start + result.length == original_text_length) { + if (temp_start + page_text_result_length == original_text_length) { DCHECK_EQ(-1, end); end = original_text_length; } DCHECK_LT(start, end); - DCHECK_EQ(term.size(), static_cast<size_t>(end - start)); + DCHECK_EQ(term.size() + term_stripped_count, + static_cast<size_t>(end - start)); AddFindResult(PDFiumRange(pages_[current_page].get(), start, end - start)); } }
diff --git a/pdf/pdfium/pdfium_range.cc b/pdf/pdfium/pdfium_range.cc index 5f10a5a..a89c428 100644 --- a/pdf/pdfium/pdfium_range.cc +++ b/pdf/pdfium/pdfium_range.cc
@@ -23,6 +23,10 @@ } // namespace +bool IsIgnorableCharacter(base::char16 c) { + return (c == kZeroWidthSpace) || (c == kPDFSoftHyphenMarker); +} + PDFiumRange::PDFiumRange(PDFiumPage* page, int char_index, int char_count) : page_(page), char_index_(char_index), char_count_(char_count) { #if DCHECK_IS_ON() @@ -105,8 +109,7 @@ api_string_adapter.Close(written); } - // Strip ignorable non-displaying whitespace - rv.erase(std::remove(rv.begin(), rv.end(), kZeroWidthSpace), rv.end()); + base::EraseIf(rv, [](base::char16 c) { return IsIgnorableCharacter(c); }); return rv; }
diff --git a/pdf/pdfium/pdfium_range.h b/pdf/pdfium/pdfium_range.h index 56b0fca..80ab37e 100644 --- a/pdf/pdfium/pdfium_range.h +++ b/pdf/pdfium/pdfium_range.h
@@ -14,6 +14,14 @@ namespace chrome_pdf { +constexpr base::char16 kZeroWidthSpace = 0x200B; +constexpr base::char16 kPDFSoftHyphenMarker = 0xFFFE; + +// Helper for identifying characters that PDFium outputs, via FPDFText_GetText, +// that have special meaning, but should not be included in things like copied +// text or when running find. +bool IsIgnorableCharacter(base::char16 c); + // Describes location of a string of characters. class PDFiumRange { public:
diff --git a/pdf/test/data/spanner.pdf b/pdf/test/data/spanner.pdf new file mode 100644 index 0000000..cf34cdb --- /dev/null +++ b/pdf/test/data/spanner.pdf Binary files differ
diff --git a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc index 15f844a..683d875 100644 --- a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc +++ b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
@@ -70,7 +70,15 @@ } void FrameCoordinationUnitImpl::SetLifecycleState(mojom::LifecycleState state) { + if (state == lifecycle_state_) + return; + + mojom::LifecycleState old_state = lifecycle_state_; lifecycle_state_ = state; + + if (process_coordination_unit_) + process_coordination_unit_->OnFrameLifecycleStateChanged(this, old_state); + // The page will have the same lifecycle state as the main frame. if (IsMainFrame() && GetPageCoordinationUnit()) { // TODO(fdoray): Store the lifecycle state as a member on the
diff --git a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.cc index d855e86..0535fdc 100644 --- a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.cc +++ b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.cc
@@ -31,7 +31,7 @@ auto* frame_cu = FrameCoordinationUnitImpl::GetCoordinationUnitByID(graph_, cu_id); if (frame_cu) - AddFrame(frame_cu); + AddFrameImpl(frame_cu); } void ProcessCoordinationUnitImpl::SetCPUUsage(double cpu_usage) { @@ -86,6 +86,18 @@ return page_cus; } +void ProcessCoordinationUnitImpl::OnFrameLifecycleStateChanged( + FrameCoordinationUnitImpl* frame_cu, + mojom::LifecycleState old_state) { + DCHECK(base::ContainsKey(frame_coordination_units_, frame_cu)); + DCHECK_NE(old_state, frame_cu->lifecycle_state()); + + if (old_state == mojom::LifecycleState::kFrozen) + DecrementNumFrozenFrames(); + else if (frame_cu->lifecycle_state() == mojom::LifecycleState::kFrozen) + IncrementNumFrozenFrames(); +} + void ProcessCoordinationUnitImpl::OnEventReceived(mojom::Event event) { for (auto& observer : observers()) observer.OnProcessEventReceived(this, event); @@ -98,17 +110,40 @@ observer.OnProcessPropertyChanged(this, property_type, value); } -void ProcessCoordinationUnitImpl::AddFrame( +void ProcessCoordinationUnitImpl::AddFrameImpl( FrameCoordinationUnitImpl* frame_cu) { const bool inserted = frame_coordination_units_.insert(frame_cu).second; - if (inserted) + if (inserted) { frame_cu->AddProcessCoordinationUnit(this); + if (frame_cu->lifecycle_state() == mojom::LifecycleState::kFrozen) + IncrementNumFrozenFrames(); + } } void ProcessCoordinationUnitImpl::RemoveFrame( FrameCoordinationUnitImpl* frame_cu) { DCHECK(base::ContainsKey(frame_coordination_units_, frame_cu)); frame_coordination_units_.erase(frame_cu); + + if (frame_cu->lifecycle_state() == mojom::LifecycleState::kFrozen) + DecrementNumFrozenFrames(); +} + +void ProcessCoordinationUnitImpl::DecrementNumFrozenFrames() { + --num_frozen_frames_; + DCHECK_GE(num_frozen_frames_, 0); +} + +void ProcessCoordinationUnitImpl::IncrementNumFrozenFrames() { + ++num_frozen_frames_; + DCHECK_LE(num_frozen_frames_, + static_cast<int>(frame_coordination_units_.size())); + + if (num_frozen_frames_ == + static_cast<int>(frame_coordination_units_.size())) { + for (auto& observer : observers()) + observer.OnAllFramesInProcessFrozen(this); + } } } // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h index c1c5504..73ef2081 100644 --- a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h +++ b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h
@@ -53,16 +53,24 @@ base::ProcessId process_id() const { return process_id_; } - private: - friend class FrameCoordinationUnitImpl; + // Removes |frame_cu| from the set of frames hosted by this process. Invoked + // from the destructor of FrameCoordinationUnitImpl. + void RemoveFrame(FrameCoordinationUnitImpl* frame_cu); + // Invoked when the state of a frame hosted by this process changes. + void OnFrameLifecycleStateChanged(FrameCoordinationUnitImpl* frame_cu, + mojom::LifecycleState old_state); + + private: // CoordinationUnitInterface implementation. void OnEventReceived(mojom::Event event) override; void OnPropertyChanged(mojom::PropertyType property_type, int64_t value) override; - void AddFrame(FrameCoordinationUnitImpl* frame_cu); - void RemoveFrame(FrameCoordinationUnitImpl* frame_cu); + void AddFrameImpl(FrameCoordinationUnitImpl* frame_cu); + + void DecrementNumFrozenFrames(); + void IncrementNumFrozenFrames(); base::TimeDelta cumulative_cpu_usage_; uint64_t private_footprint_kb_ = 0u; @@ -71,6 +79,9 @@ std::set<FrameCoordinationUnitImpl*> frame_coordination_units_; + // The number of frames hosted by this process that are frozen. + int num_frozen_frames_ = 0; + DISALLOW_COPY_AND_ASSIGN(ProcessCoordinationUnitImpl); };
diff --git a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl_unittest.cc b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl_unittest.cc index 6524cb5..b2ceb510 100644 --- a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl_unittest.cc +++ b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl_unittest.cc
@@ -3,7 +3,11 @@ // found in the LICENSE file. #include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h" + #include "services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h" +#include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h" +#include "services/resource_coordinator/coordination_unit/mock_coordination_unit_graphs.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace resource_coordinator { @@ -12,6 +16,22 @@ class ProcessCoordinationUnitImplTest : public CoordinationUnitTestHarness {}; +class MockCoordinationUnitGraphObserver : public CoordinationUnitGraphObserver { + public: + MockCoordinationUnitGraphObserver() = default; + virtual ~MockCoordinationUnitGraphObserver() = default; + + bool ShouldObserve(const CoordinationUnitBase* coordination_unit) override { + return true; + } + + MOCK_METHOD1(OnAllFramesInProcessFrozen, + void(const ProcessCoordinationUnitImpl*)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockCoordinationUnitGraphObserver); +}; + } // namespace TEST_F(ProcessCoordinationUnitImplTest, MeasureCPUUsage) { @@ -23,4 +43,32 @@ EXPECT_EQ(1, cpu_usage / 1000.0); } +TEST_F(ProcessCoordinationUnitImplTest, OnAllFramesInProcessFrozen) { + auto owned_observer = std::make_unique< + testing::StrictMock<MockCoordinationUnitGraphObserver>>(); + auto* observer = owned_observer.get(); + coordination_unit_graph()->RegisterObserver(std::move(owned_observer)); + MockMultiplePagesInSingleProcessCoordinationUnitGraph cu_graph( + coordination_unit_graph()); + + // 1/2 frame in the process is frozen. + // No call to OnAllFramesInProcessFrozen() is expected. + cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kFrozen); + + // 2/2 frames in the process are frozen. + EXPECT_CALL(*observer, OnAllFramesInProcessFrozen(cu_graph.process.get())); + cu_graph.other_frame->SetLifecycleState(mojom::LifecycleState::kFrozen); + testing::Mock::VerifyAndClear(observer); + + // A frame is unfrozen and frozen. + cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kRunning); + EXPECT_CALL(*observer, OnAllFramesInProcessFrozen(cu_graph.process.get())); + cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kFrozen); + testing::Mock::VerifyAndClear(observer); + + // A frozen frame is frozen again. + // No call to OnAllFramesInProcessFrozen() is expected. + cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kFrozen); +} + } // namespace resource_coordinator
diff --git a/services/resource_coordinator/observers/coordination_unit_graph_observer.h b/services/resource_coordinator/observers/coordination_unit_graph_observer.h index 6d5efaa..078c33f4 100644 --- a/services/resource_coordinator/observers/coordination_unit_graph_observer.h +++ b/services/resource_coordinator/observers/coordination_unit_graph_observer.h
@@ -91,6 +91,10 @@ const SystemCoordinationUnitImpl* system_cu, const mojom::Event event) {} + // Called when all the frames in a process become frozen. + virtual void OnAllFramesInProcessFrozen( + const ProcessCoordinationUnitImpl* process_cu) {} + void set_coordination_unit_graph( CoordinationUnitGraph* coordination_unit_graph) { coordination_unit_graph_ = coordination_unit_graph;
diff --git a/services/video_capture/BUILD.gn b/services/video_capture/BUILD.gn index 84c11a8..f06fa73 100644 --- a/services/video_capture/BUILD.gn +++ b/services/video_capture/BUILD.gn
@@ -87,6 +87,8 @@ "test/mock_device_test.cc", "test/mock_device_test.h", "test/mock_device_unittest.cc", + "test/mock_devices_changed_observer.cc", + "test/mock_devices_changed_observer.h", "test/mock_producer.cc", "test/mock_producer.h", "test/mock_receiver.cc",
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.cc b/services/video_capture/device_factory_media_to_mojo_adapter.cc index 1cd5fc8e..36d2c712 100644 --- a/services/video_capture/device_factory_media_to_mojo_adapter.cc +++ b/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -145,6 +145,11 @@ NOTIMPLEMENTED(); } +void DeviceFactoryMediaToMojoAdapter::RegisterVirtualDevicesChangedObserver( + mojom::DevicesChangedObserverPtr observer) { + NOTIMPLEMENTED(); +} + void DeviceFactoryMediaToMojoAdapter::CreateAndAddNewDevice( const std::string& device_id, mojom::DeviceRequest device_request,
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.h b/services/video_capture/device_factory_media_to_mojo_adapter.h index 65cde0d..0c785b7 100644 --- a/services/video_capture/device_factory_media_to_mojo_adapter.h +++ b/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -43,6 +43,8 @@ void AddTextureVirtualDevice( const media::VideoCaptureDeviceInfo& device_info, mojom::TextureVirtualDeviceRequest virtual_device) override; + void RegisterVirtualDevicesChangedObserver( + mojom::DevicesChangedObserverPtr observer) override; private: struct ActiveDeviceEntry {
diff --git a/services/video_capture/public/mojom/device_factory.mojom b/services/video_capture/public/mojom/device_factory.mojom index e79248b..558c8dd 100644 --- a/services/video_capture/public/mojom/device_factory.mojom +++ b/services/video_capture/public/mojom/device_factory.mojom
@@ -15,6 +15,10 @@ ERROR_DEVICE_NOT_FOUND }; +interface DevicesChangedObserver { + OnDevicesChanged(); +}; + // Enables access to a set of video capture devices. // Typical operation is to first call GetDeviceInfos() to obtain // information about available devices. The |device_id| of the infos can @@ -63,4 +67,10 @@ AddTextureVirtualDevice( media.mojom.VideoCaptureDeviceInfo device_info, TextureVirtualDevice& virtual_device); + + // Registered observers will get notified whenever a virtual device is added + // or removed. Note: Changes to non-virtual devices are currently being + // monitored outside the video capture service, and therefore the service + // does not offer such monitoring. + RegisterVirtualDevicesChangedObserver(DevicesChangedObserver observer); };
diff --git a/services/video_capture/test/device_factory_provider_test.cc b/services/video_capture/test/device_factory_provider_test.cc index a652c3de..f4c664e 100644 --- a/services/video_capture/test/device_factory_provider_test.cc +++ b/services/video_capture/test/device_factory_provider_test.cc
@@ -9,9 +9,18 @@ #include "services/service_manager/public/mojom/constants.mojom.h" #include "services/service_manager/public/mojom/service_manager.mojom.h" #include "services/video_capture/public/mojom/constants.mojom.h" +#include "services/video_capture/test/mock_producer.h" namespace video_capture { +DeviceFactoryProviderTest::SharedMemoryVirtualDeviceContext:: + SharedMemoryVirtualDeviceContext(mojom::ProducerRequest producer_request) + : mock_producer( + std::make_unique<MockProducer>(std::move(producer_request))) {} + +DeviceFactoryProviderTest::SharedMemoryVirtualDeviceContext:: + ~SharedMemoryVirtualDeviceContext() = default; + DeviceFactoryProviderTest::DeviceFactoryProviderTest() : service_manager::test::ServiceTest("video_capture_unittests") {} @@ -33,4 +42,29 @@ factory_provider_->ConnectToDeviceFactory(mojo::MakeRequest(&factory_)); } +std::unique_ptr<DeviceFactoryProviderTest::SharedMemoryVirtualDeviceContext> +DeviceFactoryProviderTest::AddSharedMemoryVirtualDevice( + const std::string& device_id) { + media::VideoCaptureDeviceInfo device_info; + device_info.descriptor.device_id = device_id; + mojom::ProducerPtr producer; + auto result = std::make_unique<SharedMemoryVirtualDeviceContext>( + mojo::MakeRequest(&producer)); + factory_->AddSharedMemoryVirtualDevice( + device_info, std::move(producer), + false /* send_buffer_handles_to_producer_as_raw_file_descriptors */, + mojo::MakeRequest(&result->device)); + return result; +} + +mojom::TextureVirtualDevicePtr +DeviceFactoryProviderTest::AddTextureVirtualDevice( + const std::string& device_id) { + media::VideoCaptureDeviceInfo device_info; + device_info.descriptor.device_id = device_id; + mojom::TextureVirtualDevicePtr device; + factory_->AddTextureVirtualDevice(device_info, mojo::MakeRequest(&device)); + return device; +} + } // namespace video_capture
diff --git a/services/video_capture/test/device_factory_provider_test.h b/services/video_capture/test/device_factory_provider_test.h index 16aa5857..4874e6e0 100644 --- a/services/video_capture/test/device_factory_provider_test.h +++ b/services/video_capture/test/device_factory_provider_test.h
@@ -11,6 +11,8 @@ namespace video_capture { +class MockProducer; + // Basic test fixture that sets up a connection to the fake device factory. class DeviceFactoryProviderTest : public service_manager::test::ServiceTest { public: @@ -20,6 +22,20 @@ void SetUp() override; protected: + struct SharedMemoryVirtualDeviceContext { + SharedMemoryVirtualDeviceContext(mojom::ProducerRequest producer_request); + ~SharedMemoryVirtualDeviceContext(); + + std::unique_ptr<MockProducer> mock_producer; + mojom::SharedMemoryVirtualDevicePtr device; + }; + + std::unique_ptr<SharedMemoryVirtualDeviceContext> + AddSharedMemoryVirtualDevice(const std::string& device_id); + + mojom::TextureVirtualDevicePtr AddTextureVirtualDevice( + const std::string& device_id); + mojom::DeviceFactoryProviderPtr factory_provider_; mojom::DeviceFactoryPtr factory_; base::MockCallback<mojom::DeviceFactory::GetDeviceInfosCallback>
diff --git a/services/video_capture/test/device_factory_provider_unittest.cc b/services/video_capture/test/device_factory_provider_unittest.cc index ce19244..c01b11b 100644 --- a/services/video_capture/test/device_factory_provider_unittest.cc +++ b/services/video_capture/test/device_factory_provider_unittest.cc
@@ -5,10 +5,11 @@ #include "base/memory/ref_counted.h" #include "base/run_loop.h" #include "base/test/mock_callback.h" +#include "mojo/public/cpp/bindings/binding.h" #include "services/video_capture/public/mojom/constants.mojom.h" #include "services/video_capture/public/mojom/device_factory.mojom.h" #include "services/video_capture/test/device_factory_provider_test.h" -#include "services/video_capture/test/mock_producer.h" +#include "services/video_capture/test/mock_devices_changed_observer.h" using testing::_; using testing::Exactly; @@ -56,13 +57,10 @@ // when calling GetDeviceInfos. TEST_F(VideoCaptureServiceDeviceFactoryProviderTest, VirtualDeviceEnumeratedAfterAdd) { - base::RunLoop wait_loop; const std::string virtual_device_id = "/virtual/device"; - media::VideoCaptureDeviceInfo info; - info.descriptor.device_id = virtual_device_id; - mojom::SharedMemoryVirtualDevicePtr virtual_device_proxy; - mojom::ProducerPtr producer_proxy; - MockProducer producer(mojo::MakeRequest(&producer_proxy)); + auto device_context = AddSharedMemoryVirtualDevice(virtual_device_id); + + base::RunLoop wait_loop; EXPECT_CALL(device_info_receiver_, Run(_)) .Times(Exactly(1)) .WillOnce( @@ -78,14 +76,70 @@ EXPECT_TRUE(virtual_device_enumerated); wait_loop.Quit(); })); - factory_->AddSharedMemoryVirtualDevice( - info, std::move(producer_proxy), - false /* send_buffer_handles_to_producer_as_raw_file_descriptors */, - mojo::MakeRequest(&virtual_device_proxy)); factory_->GetDeviceInfos(device_info_receiver_.Get()); wait_loop.Run(); } +TEST_F(VideoCaptureServiceDeviceFactoryProviderTest, + AddingAndRemovingVirtualDevicesRaisesDevicesChangedEvent) { + mojom::DevicesChangedObserverPtr observer; + MockDevicesChangedObserver mock_observer; + mojo::Binding<mojom::DevicesChangedObserver> observer_binding( + &mock_observer, mojo::MakeRequest(&observer)); + factory_->RegisterVirtualDevicesChangedObserver(std::move(observer)); + + std::unique_ptr<SharedMemoryVirtualDeviceContext> device_context_1; + { + base::RunLoop run_loop; + EXPECT_CALL(mock_observer, OnDevicesChanged()) + .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); })); + device_context_1 = AddSharedMemoryVirtualDevice("TestDevice1"); + run_loop.Run(); + } + + mojom::TextureVirtualDevicePtr device_context_2; + { + base::RunLoop run_loop; + EXPECT_CALL(mock_observer, OnDevicesChanged()) + .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); })); + device_context_2 = AddTextureVirtualDevice("TestDevice2"); + run_loop.Run(); + } + + { + base::RunLoop run_loop; + EXPECT_CALL(mock_observer, OnDevicesChanged()) + .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); })); + device_context_1.reset(); + run_loop.Run(); + } + + { + base::RunLoop run_loop; + EXPECT_CALL(mock_observer, OnDevicesChanged()) + .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); })); + device_context_2.reset(); + run_loop.Run(); + } +} + +// Tests that disconnecting a devices changed observer does not lead to any +// crash or bad state. +TEST_F(VideoCaptureServiceDeviceFactoryProviderTest, + AddAndRemoveVirtualDeviceAfterObserverHasDisconnected) { + mojom::DevicesChangedObserverPtr observer; + MockDevicesChangedObserver mock_observer; + mojo::Binding<mojom::DevicesChangedObserver> observer_binding( + &mock_observer, mojo::MakeRequest(&observer)); + factory_->RegisterVirtualDevicesChangedObserver(std::move(observer)); + + // Disconnect observer + observer_binding.Close(); + + auto device_context = AddTextureVirtualDevice("TestDevice"); + device_context = nullptr; +} + // Tests that VideoCaptureDeviceFactory::CreateDevice() returns an error // code when trying to create a device for an invalid descriptor. TEST_F(VideoCaptureServiceDeviceFactoryProviderTest, @@ -112,22 +166,15 @@ CreateDeviceSuccessForVirtualDevice) { base::RunLoop wait_loop; const std::string virtual_device_id = "/virtual/device"; - media::VideoCaptureDeviceInfo info; - info.descriptor.device_id = virtual_device_id; - mojom::DevicePtr device_proxy; - mojom::SharedMemoryVirtualDevicePtr virtual_device_proxy; - mojom::ProducerPtr producer_proxy; - MockProducer producer(mojo::MakeRequest(&producer_proxy)); + auto device_context = AddSharedMemoryVirtualDevice(virtual_device_id); + base::MockCallback<mojom::DeviceFactory::CreateDeviceCallback> create_device_proxy_callback; EXPECT_CALL(create_device_proxy_callback, Run(mojom::DeviceAccessResultCode::SUCCESS)) .Times(1) .WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); })); - factory_->AddSharedMemoryVirtualDevice( - info, std::move(producer_proxy), - false /* send_buffer_handles_to_producer_as_raw_file_descriptors */, - mojo::MakeRequest(&virtual_device_proxy)); + mojom::DevicePtr device_proxy; factory_->CreateDevice(virtual_device_id, mojo::MakeRequest(&device_proxy), create_device_proxy_callback.Get()); wait_loop.Run();
diff --git a/services/video_capture/test/mock_devices_changed_observer.cc b/services/video_capture/test/mock_devices_changed_observer.cc new file mode 100644 index 0000000..d571f63 --- /dev/null +++ b/services/video_capture/test/mock_devices_changed_observer.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 "services/video_capture/test/mock_devices_changed_observer.h" + +namespace video_capture { + +MockDevicesChangedObserver::MockDevicesChangedObserver() = default; + +MockDevicesChangedObserver::~MockDevicesChangedObserver() = default; + +} // namespace video_capture
diff --git a/services/video_capture/test/mock_devices_changed_observer.h b/services/video_capture/test/mock_devices_changed_observer.h new file mode 100644 index 0000000..850dfc0 --- /dev/null +++ b/services/video_capture/test/mock_devices_changed_observer.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 SERVICES_VIDEO_CAPTURE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_ +#define SERVICES_VIDEO_CAPTURE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_ + +#include "services/video_capture/public/mojom/device_factory.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace video_capture { + +class MockDevicesChangedObserver : public mojom::DevicesChangedObserver { + public: + MockDevicesChangedObserver(); + ~MockDevicesChangedObserver() override; + + // mojom::DevicesChangedObserver + MOCK_METHOD0(OnDevicesChanged, void()); +}; + +} // namespace video_capture + +#endif // SERVICES_VIDEO_CAPTURE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
diff --git a/services/video_capture/virtual_device_enabled_device_factory.cc b/services/video_capture/virtual_device_enabled_device_factory.cc index 03cb1b7..092faff 100644 --- a/services/video_capture/virtual_device_enabled_device_factory.cc +++ b/services/video_capture/virtual_device_enabled_device_factory.cc
@@ -157,6 +157,7 @@ std::move(producer_binding)); virtual_devices_by_id_.insert( std::make_pair(device_id, std::move(device_entry))); + EmitDevicesChangedEvent(); } void VirtualDeviceEnabledDeviceFactory::AddTextureVirtualDevice( @@ -183,6 +184,15 @@ std::move(producer_binding)); virtual_devices_by_id_.insert( std::make_pair(device_id, std::move(device_entry))); + EmitDevicesChangedEvent(); +} + +void VirtualDeviceEnabledDeviceFactory::RegisterVirtualDevicesChangedObserver( + mojom::DevicesChangedObserverPtr observer) { + observer.set_connection_error_handler(base::BindOnce( + &VirtualDeviceEnabledDeviceFactory::OnDevicesChangedObserverDisconnected, + weak_factory_.GetWeakPtr(), &observer)); + devices_changed_observers_.push_back(std::move(observer)); } void VirtualDeviceEnabledDeviceFactory::OnGetDeviceInfos( @@ -202,6 +212,7 @@ const std::string& device_id) { virtual_devices_by_id_.at(device_id).StopDevice(); virtual_devices_by_id_.erase(device_id); + EmitDevicesChangedEvent(); } void VirtualDeviceEnabledDeviceFactory:: @@ -210,4 +221,23 @@ virtual_devices_by_id_.at(device_id).StopDevice(); } +void VirtualDeviceEnabledDeviceFactory::EmitDevicesChangedEvent() { + for (auto& observer : devices_changed_observers_) + observer->OnDevicesChanged(); +} + +void VirtualDeviceEnabledDeviceFactory::OnDevicesChangedObserverDisconnected( + mojom::DevicesChangedObserverPtr* observer) { + auto iter = std::find_if( + devices_changed_observers_.begin(), devices_changed_observers_.end(), + [observer](const mojom::DevicesChangedObserverPtr& entry) { + return &entry == observer; + }); + if (iter == devices_changed_observers_.end()) { + DCHECK(false); + return; + } + devices_changed_observers_.erase(iter); +} + } // namespace video_capture
diff --git a/services/video_capture/virtual_device_enabled_device_factory.h b/services/video_capture/virtual_device_enabled_device_factory.h index 8761ec0..f753c00ca 100644 --- a/services/video_capture/virtual_device_enabled_device_factory.h +++ b/services/video_capture/virtual_device_enabled_device_factory.h
@@ -37,6 +37,8 @@ void AddTextureVirtualDevice( const media::VideoCaptureDeviceInfo& device_info, mojom::TextureVirtualDeviceRequest virtual_device) override; + void RegisterVirtualDevicesChangedObserver( + mojom::DevicesChangedObserverPtr observer) override; private: class VirtualDeviceEntry; @@ -49,10 +51,14 @@ const std::string& device_id); void OnVirtualDeviceConsumerConnectionErrorOrClose( const std::string& device_id); + void EmitDevicesChangedEvent(); + void OnDevicesChangedObserverDisconnected( + mojom::DevicesChangedObserverPtr* observer); std::map<std::string, VirtualDeviceEntry> virtual_devices_by_id_; const std::unique_ptr<service_manager::ServiceContextRef> service_ref_; const std::unique_ptr<mojom::DeviceFactory> device_factory_; + std::vector<mojom::DevicesChangedObserverPtr> devices_changed_observers_; base::WeakPtrFactory<VirtualDeviceEnabledDeviceFactory> weak_factory_; DISALLOW_COPY_AND_ASSIGN(VirtualDeviceEnabledDeviceFactory);
diff --git a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc index 87ac642..781e20c 100644 --- a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc +++ b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
@@ -35,12 +35,12 @@ out->request_presentation_feedback = data.request_presentation_feedback(); out->root_background_color = data.root_background_color(); out->min_page_scale_factor = data.min_page_scale_factor(); + out->top_controls_height = data.top_controls_height(); + out->top_controls_shown_ratio = data.top_controls_shown_ratio(); #if defined(OS_ANDROID) out->max_page_scale_factor = data.max_page_scale_factor(); out->root_overflow_y_hidden = data.root_overflow_y_hidden(); - out->top_controls_height = data.top_controls_height(); - out->top_controls_shown_ratio = data.top_controls_shown_ratio(); out->bottom_controls_height = data.bottom_controls_height(); out->bottom_controls_shown_ratio = data.bottom_controls_shown_ratio(); #endif
diff --git a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h index 6dc5e4c..5fc6ce9 100644 --- a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h +++ b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
@@ -101,6 +101,16 @@ return metadata.min_page_scale_factor; } + static float top_controls_height( + const viz::CompositorFrameMetadata& metadata) { + return metadata.top_controls_height; + } + + static float top_controls_shown_ratio( + const viz::CompositorFrameMetadata& metadata) { + return metadata.top_controls_shown_ratio; + } + #if defined(OS_ANDROID) static float max_page_scale_factor( const viz::CompositorFrameMetadata& metadata) { @@ -117,16 +127,6 @@ return metadata.root_overflow_y_hidden; } - static float top_controls_height( - const viz::CompositorFrameMetadata& metadata) { - return metadata.top_controls_height; - } - - static float top_controls_shown_ratio( - const viz::CompositorFrameMetadata& metadata) { - return metadata.top_controls_shown_ratio; - } - static float bottom_controls_height( const viz::CompositorFrameMetadata& metadata) { return metadata.bottom_controls_height;
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc index 0993a63..e33415f 100644 --- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc +++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -620,13 +620,13 @@ uint64_t begin_frame_ack_sequence_number = 0xdeadbeef; FrameDeadline frame_deadline(base::TimeTicks(), 4u, base::TimeDelta(), true); const float min_page_scale_factor = 3.5f; + const float top_bar_height(1234.5f); + const float top_bar_shown_ratio(1.0f); #if defined(OS_ANDROID) const float max_page_scale_factor = 4.6f; const gfx::SizeF root_layer_size(1234.5f, 5432.1f); const bool root_overflow_y_hidden = true; - const float top_bar_height(1234.5f); - const float top_bar_shown_ratio(1.0f); const float bottom_bar_height(1234.5f); const float bottom_bar_shown_ratio(1.0f); Selection<gfx::SelectionBound> selection; @@ -656,13 +656,13 @@ input.frame_token = frame_token; input.begin_frame_ack.sequence_number = begin_frame_ack_sequence_number; input.min_page_scale_factor = min_page_scale_factor; + input.top_controls_height = top_bar_height; + input.top_controls_shown_ratio = top_bar_shown_ratio; #if defined(OS_ANDROID) input.max_page_scale_factor = max_page_scale_factor; input.root_layer_size = root_layer_size; input.root_overflow_y_hidden = root_overflow_y_hidden; - input.top_controls_height = top_bar_height; - input.top_controls_shown_ratio = top_bar_shown_ratio; input.bottom_controls_height = bottom_bar_height; input.bottom_controls_shown_ratio = bottom_bar_shown_ratio; input.selection = selection; @@ -694,13 +694,13 @@ EXPECT_EQ(begin_frame_ack_sequence_number, output.begin_frame_ack.sequence_number); EXPECT_EQ(min_page_scale_factor, output.min_page_scale_factor); + EXPECT_EQ(top_bar_height, output.top_controls_height); + EXPECT_EQ(top_bar_shown_ratio, output.top_controls_shown_ratio); #if defined(OS_ANDROID) EXPECT_EQ(max_page_scale_factor, output.max_page_scale_factor); EXPECT_EQ(root_layer_size, output.root_layer_size); EXPECT_EQ(root_overflow_y_hidden, output.root_overflow_y_hidden); - EXPECT_EQ(top_bar_height, output.top_controls_height); - EXPECT_EQ(top_bar_shown_ratio, output.top_controls_shown_ratio); EXPECT_EQ(bottom_bar_height, output.bottom_controls_height); EXPECT_EQ(bottom_bar_shown_ratio, output.bottom_controls_shown_ratio); EXPECT_EQ(selection, output.selection);
diff --git a/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom b/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom index d514e55..ab78037 100644 --- a/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom +++ b/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
@@ -42,10 +42,8 @@ [EnableIf=is_android] bool root_overflow_y_hidden; - [EnableIf=is_android] float top_controls_height; - [EnableIf=is_android] float top_controls_shown_ratio; [EnableIf=is_android]
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json index dd29bb34..8016bc44a 100644 --- a/testing/buildbot/chromium.win.json +++ b/testing/buildbot/chromium.win.json
@@ -629,6 +629,18 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "vr_common_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "vr_pixeltests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "webkit_unit_tests" }, { @@ -1940,6 +1952,30 @@ } ] }, + "test": "vr_common_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, + "test": "vr_pixeltests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + }, "test": "webkit_unit_tests" }, { @@ -3928,6 +3964,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "vr_pixeltests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "webkit_unit_tests" }, { @@ -4692,6 +4734,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "vr_pixeltests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "webkit_unit_tests" }, {
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter b/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter index bb65115..ab9e88f 100644 --- a/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter +++ b/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter
@@ -15,81 +15,6 @@ -CompositedScrollingBrowserTest.Scroll3DTransformedScroller -# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496 -# There are different timeouts due the same root cause above. - -# MainThreadFrameObserver::Wait() times out. -# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496 --AccessibilityHitTestingBrowserTest.HitTestingWithPinchZoom --AutoscrollBrowserTest.AutoscrollDirectionChangeAfterFullyScrolled --AutoscrollBrowserTest.AutoscrollFlingGSBDeltaHints --AutoscrollBrowserTest.WheelScrollingWorksAfterAutoscrollCancel --BrowserSideFlingBrowserTest.TouchpadFling --BrowserSideFlingBrowserTest.TouchscreenFling --CompositorEventAckBrowserTest.MouseWheel --CompositorEventAckBrowserTest.PassiveTouchStartBlockingTouchEnd --CompositorEventAckBrowserTest.TouchStart --CompositorEventAckBrowserTest.TouchStartDuringFling --MainThreadEventQueueBrowserTest.MouseMove --MainThreadEventQueueBrowserTest.TouchMove --PointerLockBrowserTest.PointerLockEventRouting --PointerLockBrowserTest.PointerLockWheelEventRouting --PointerLockBrowserTest.PointerLockWidgetHidden --RenderWidgetHostViewBrowserTestBase.CompositorWorksWhenReusingRenderer --ScreenOrientationOOPIFBrowserTest.ScreenOrientation --ScrollLatencyBrowserTest.ScrollLatencyNotRecordedIfGSUIgnored --ScrollLatencyBrowserTest.SmoothWheelScroll --SitePerProcessBrowserTest.* --SitePerProcessGestureHitTestBrowserTest.* --SitePerProcessHitTestBrowserTest.* --SitePerProcessMouseWheelHitTestBrowserTest.* --TouchpadPinchBrowserTest.* --WheelEventListenerBrowserTest.DocumentMouseWheelEventListenersPassiveByDefault --WheelEventListenerBrowserTest.DocumentWheelEventListenersPassiveByDefault - -# DevToolsVideoConsumerTest::WaitUntilFrameReceived() times out. -# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496 --DevToolsVideoConsumerTest.SetMinAndMaxFramesChangesDimensions - -# SurfaceHitTestReadyNotifier::WaitForSurfaceReady() times out. -# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496 --SitePerProcessBrowserTouchActionTest.* --SitePerProcessEmulatedTouchBrowserTest.* --SitePerProcessHighDPIHitTestBrowserTest.* --SitePerProcessInternalsHitTestBrowserTest.* --SitePerProcessNonIntegerScaleFactorHitTestBrowserTest.* --TouchAccessibilityBrowserTest.TouchExplorationInCrossSiteIframe - -# RenderWidgetHostInputEventRouter::IsViewInMap() never true. -# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496 --RenderWidgetHostTouchEmulatorBrowserTest.TouchEmulator --TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.BasicSelectionIsolatedIframe/0 --TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.BasicSelectionIsolatedIframe/1 --TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.BasicSelectionIsolatedScrollMainframe/0 --TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.BasicSelectionIsolatedScrollMainframe/1 --WebContentsViewAuraTest.ContentWindowClose - -# RenderWidgetHostViewBrowserTest::WaitForCopySourceReady() times out. -# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496 --GLAndSoftwareCompositing/* - -# RenderFrameSubmissionObserver::Wait()/WaitForAnyFrameSubmission() times out. -# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496 --TouchActionBrowserTest.* --TouchInputBrowserTest.* - -# RenderWidgetHostViewAura::CopyFromSurface crashes. -# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496 --SnapshotBrowserTest.SingleWindowTest --WebContentsViewAuraTest.ReplaceStateReloadPushState --WebContentsViewAuraTest.ScreenshotForSwappedOutRenderViews - -# WebContentsVideoCaptureDeviceBrowserTest::WaitForFrameWithColor() times out. -# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496 --WebContentsVideoCaptureDeviceBrowserTest.* --WebContentsVideoCaptureDeviceBrowserTestP.* - - # DCHECK(!event->IsPointerEvent()) fail. https://crbug.com/884342 -MouseLatencyBrowserTest.CoalescedMouseWheelsCorrectlyTerminated @@ -100,24 +25,25 @@ # -SitePerProcessHitTestBrowserTest.CrossProcessMouseEnterAndLeaveTest/1 # -SitePerProcessInternalsHitTestBrowserTest.NestedLocalNonFastScrollableDivCoordsAreLocal/3 # -SitePerProcessNonIntegerScaleFactorHitTestBrowserTest.NestedSurfaceHitTestTest/1 +-SitePerProcessBrowserTouchActionTest.* +-SitePerProcessEmulatedTouchBrowserTest.* +-SitePerProcessGestureHitTestBrowserTest.* +-SitePerProcessHighDPIHitTestBrowserTest.* +-SitePerProcessHitTestBrowserTest.* +-SitePerProcessInternalsHitTestBrowserTest.* +-SitePerProcessMouseWheelHitTestBrowserTest.* +-SitePerProcessNonIntegerScaleFactorHitTestBrowserTest.* +-TouchAccessibilityBrowserTest.* +-TouchSelectionForCrossProcessFramesTests/* # Hit test fails. https://crbug.com/884366 -# Leaving an example of the bug. -# -SitePerProcessHitTestBrowserTest.HitTestNestedFrames/1 +-PointerLockBrowserTest.PointerLockEventRouting +-PointerLockBrowserTest.PointerLockWheelEventRouting +-SitePerProcessHitTestBrowserTest.* -SitePerProcessHitTestDataGenerationBrowserTest.* # ShowWidgetMessageFilter::Wait() times out. https://crbug.com/884369 # Leaving an example of the bug. # -SitePerProcessHitTestBrowserTest.PopupMenuTest/1 - - -# TestTouchSelectionControllerClientAura::Wait() times out. -# https://crbug.com/884389 --TouchSelectionControllerClientAuraScaleFactorTest.* --TouchSelectionControllerClientAuraTest.* - - -# The test times out. https://crbug.com/884393 --WebRtcCaptureFromElementBrowserTest.VerifyCanvasCaptureOffscreenCanvasFrames
diff --git a/testing/buildbot/filters/webui_polymer2_browser_tests.filter b/testing/buildbot/filters/webui_polymer2_browser_tests.filter index 387e218c..e6117fb 100644 --- a/testing/buildbot/filters/webui_polymer2_browser_tests.filter +++ b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
@@ -15,7 +15,6 @@ # --gtest_repeat=5, but might pass on a single invocation). # Chrome Desktop failures (Mac, Linux, Windows). --CrSettingsPeoplePageSyncAccountControlTest.All -MediaRouterElementsBrowserTest.MediaRouterContainerCastModeList -MediaRouterElementsBrowserTest.MediaRouterContainerFilterPart1 -MediaRouterElementsBrowserTest.MediaRouterContainerFirstRunFlow @@ -175,6 +174,7 @@ CrSettingsPeoplePageChangePictureTest.* CrSettingsPeoplePageManageProfileTest.* CrSettingsPeoplePageSetupPinDialogTest.* +CrSettingsPeoplePageSyncAccountControlTest.* CrSettingsPeoplePageSyncPageTest.* CrSettingsPeoplePageTest.* CrSettingsPersonalizationOptionsTest.*
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 0676c33c..69838916 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1286,23 +1286,10 @@ 'Win10 Tests x64', ], }, - 'vr_common_unittests': { - 'remove_from': [ - # chromium.win - 'Win 7 Tests x64 (1)', - 'Win10 Tests x64', - ], - }, - 'vr_pixeltests': { 'remove_from': [ # chromium.fyi 'VR Linux', - # chromium.win - 'Win 7 Tests x64 (1)', - 'Win10 Tests x64', - 'Win7 Tests (1)', - 'Win7 Tests (dbg)(1)', ], }, 'wayland_client_perftests': {
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG index ca7b95d..0d14e9a 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -497,7 +497,6 @@ crbug.com/591099 tables/mozilla/bugs/bug2973.html [ Failure ] crbug.com/591099 tables/mozilla/bugs/bug50695-2.html [ Failure ] crbug.com/591099 tables/mozilla/bugs/bug55527.html [ Failure ] -crbug.com/591099 tables/mozilla_expected_failures/bugs/bug3166-16.html [ Failure ] crbug.com/591099 transforms/3d/hit-testing/backface-no-transform-hit-test.html [ Failure ] crbug.com/591099 transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ] crbug.com/591099 transforms/3d/point-mapping/3d-point-mapping-origins.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 472ddb5..e06ff7c1 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -490,6 +490,9 @@ ### virtual/layout_ng/fast/block/margin-collapse crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/103.html [ Failure ] +### virtual/layout_ng/fast/inline +crbug.com/635619 [ Mac ] virtual/layout_ng/fast/inline/left-right-center-inline-alignment-in-ltr-and-rtl-blocks.html [ Failure ] + ### virtual/layout_ng/overflow crbug.com/724701 virtual/layout_ng/overflow/overflow-basic-004.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-tables/caption-writing-mode-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables/caption-writing-mode-001.html new file mode 100644 index 0000000..835a5116 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables/caption-writing-mode-001.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<link rel="author" title="David Grogan" href="dgrogan@chromium.org"> +<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-flows"> +<meta name="flags" content="" /> +<meta name="assert" content="caption margins are resolved against table's height when table has vertical flow" /> +<style> +x-table { + display: table; + width: 300px; + height: 200px; + writing-mode: vertical-lr; + outline: 2px dashed blue; +} +x-caption { + display: table-caption; + height: 50px; + width: 120px; + writing-mode: horizontal-tb; + outline: 1px solid black; +} +</style> + +<x-table> + <x-caption id=captionMarginLeft style="margin-left:20%">caption</x-caption> +</x-table> +<x-table> + <x-caption id=captionMarginTop style="margin:auto 0">caption</x-caption> +</x-table> +<p>This is a script test because of how ridiculously differently the current +engines render these cases.</p> + + +<script> +let caption_margin_left = getComputedStyle(id=captionMarginLeft).marginLeft; +test(() => assert_equals(caption_margin_left, "40px"), "Caption percent margins are resolved against table's height for vertical-lr tables"); +let caption_margin_top = getComputedStyle(captionMarginTop).marginTop; +test(() => assert_equals(caption_margin_top, "75px"), "Caption with auto top/bottom margins is centered vertically for vertical-lr tables"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt index b06cfa8..cb70d277 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
@@ -50,6 +50,8 @@ PASS window.cached_navigator_mediaSession.playbackState is 'none' PASS window.cached_navigator_presentation.defaultRequest is null PASS window.cached_navigator_presentation.receiver is null +PASS window.cached_navigator_serial.onconnect is null +PASS window.cached_navigator_serial.ondisconnect is null PASS window.cached_navigator_serviceWorker.controller is null PASS window.cached_navigator_serviceWorker.oncontrollerchange is null PASS window.cached_navigator_serviceWorker.onmessage is null
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt index 764bbf2..a558dde 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
@@ -50,6 +50,8 @@ PASS window.cached_navigator_mediaSession.playbackState is 'none' PASS window.cached_navigator_presentation.defaultRequest is null PASS window.cached_navigator_presentation.receiver is null +PASS window.cached_navigator_serial.onconnect is null +PASS window.cached_navigator_serial.ondisconnect is null PASS window.cached_navigator_serviceWorker.controller is null PASS window.cached_navigator_serviceWorker.oncontrollerchange is null PASS window.cached_navigator_serviceWorker.onmessage is null
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt index 0ec08c7b..e2133f2 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
@@ -50,6 +50,8 @@ PASS window.cached_navigator_mediaSession.playbackState is 'none' PASS window.cached_navigator_presentation.defaultRequest is null PASS window.cached_navigator_presentation.receiver is null +PASS window.cached_navigator_serial.onconnect is null +PASS window.cached_navigator_serial.ondisconnect is null PASS window.cached_navigator_serviceWorker.controller is null PASS window.cached_navigator_serviceWorker.oncontrollerchange is null PASS window.cached_navigator_serviceWorker.onmessage is null
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt index 24f37af..cd288669 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -56,6 +56,8 @@ PASS oldChildWindow.navigator.presentation.receiver is newChildWindow.navigator.presentation.receiver PASS oldChildWindow.navigator.product is newChildWindow.navigator.product PASS oldChildWindow.navigator.productSub is newChildWindow.navigator.productSub +PASS oldChildWindow.navigator.serial.onconnect is newChildWindow.navigator.serial.onconnect +PASS oldChildWindow.navigator.serial.ondisconnect is newChildWindow.navigator.serial.ondisconnect PASS oldChildWindow.navigator.serviceWorker.controller is newChildWindow.navigator.serviceWorker.controller PASS oldChildWindow.navigator.serviceWorker.oncontrollerchange is newChildWindow.navigator.serviceWorker.oncontrollerchange PASS oldChildWindow.navigator.serviceWorker.onmessage is newChildWindow.navigator.serviceWorker.onmessage
diff --git a/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime-expected.txt deleted file mode 100644 index c11a9111..0000000 --- a/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime-expected.txt +++ /dev/null
@@ -1,12 +0,0 @@ -Tests that HTMLOptionsCollection does not keep its owner node alive. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS observeSelect.wasCollected is true -PASS observeOption.wasCollected is true -PASS observeOptions.wasCollected is false -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime.html b/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime.html deleted file mode 100644 index 7592145..0000000 --- a/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime.html +++ /dev/null
@@ -1,24 +0,0 @@ -<!DOCTYPE html> -<script src="../../resources/js-test.js"></script> -<body> -<script> -description('Tests that HTMLOptionsCollection does not keep its owner node alive.'); - -var select = document.createElement("select"); -var option = document.createElement("option"); -select.appendChild(option); -var options = select.options; -var observeSelect = internals.observeGC(select); -var observeOption = internals.observeGC(option); -var observeOptions = internals.observeGC(options); - -select = null; -option = null; -gc(); - -shouldBeTrue('observeSelect.wasCollected'); -shouldBeTrue('observeOption.wasCollected'); -shouldBeFalse('observeOptions.wasCollected'); -</script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/layers/add-layer-with-nested-stacking-expected.png b/third_party/WebKit/LayoutTests/fast/layers/add-layer-with-nested-stacking-expected.png index 6cda17ad..130b991b 100644 --- a/third_party/WebKit/LayoutTests/fast/layers/add-layer-with-nested-stacking-expected.png +++ b/third_party/WebKit/LayoutTests/fast/layers/add-layer-with-nested-stacking-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/table/caption-margin-direction.html b/third_party/WebKit/LayoutTests/fast/table/caption-margin-direction.html new file mode 100644 index 0000000..38a1b98 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/table/caption-margin-direction.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<script src='../../resources/testharness.js'></script> +<script src='../../resources/testharnessreport.js'></script> +<style> +body { + margin: 0px; +} +x-table { + display: table; + width: 300px; + outline: 2px dotted blue; +} +x-caption { + display: table-caption; + margin-left: 20px; + outline: 1px solid black; +} +</style> + +<p>When implementing table captions in NG, there was no goal to change behavior. +This is a smoke test to ensure NG matches legacy when table captions's direction +differ from their containing tables. This exact behavior can change when we +implement table layout in NG, and probably should because Edge/FF treat captions +differently in general.</p> + +<x-table> + <x-caption dir=rtl>Lorem ipsum dolor</x-caption> +</x-table> + +<x-table dir=rtl> + <x-caption dir=ltr>Lorem ipsum dolor</x-caption> +</x-table> + +<script> +let captions = document.querySelectorAll("x-caption") +let caption_num = 0; +let expected_x = [0, 20]; +for (let i of captions) { + let rect = i.getBoundingClientRect(); + test(() => assert_equals(rect.x, expected_x[caption_num++]), "Test caption location " + caption_num); +} + +</script>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/block-no-inflow-children-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/block-no-inflow-children-expected.txt index 4354dd5..4aef2c50 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/block-no-inflow-children-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/block-no-inflow-children-expected.txt
@@ -20,12 +20,7 @@ { "object": "NGPhysicalTextFragment 'La la la la'", "rect": [0, 0, 62, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'La la la'", - "rect": [0, 0, 47, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-3509-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-3509-expected.txt index bece1d3f..366cd570 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-3509-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-3509-expected.txt
@@ -20,22 +20,12 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='im'", "rect": [11, 131, 100, 100], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='im'", - "rect": [11, 131, 50, 100], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment '\u00A0'", "rect": [11, 131, 4, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment '\u00A0'", - "rect": [11, 131, 4, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-5699-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-5699-expected.txt index e7cc49e..a944ff4 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-5699-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-5699-expected.txt
@@ -20,22 +20,22 @@ { "object": "NGPhysicalTextFragment 'Hello'", "rect": [8, 184, 35, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Hello'", "rect": [8, 156, 35, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment '\u00A0'", "rect": [8, 150, 4, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment '\u00A0'", "rect": [8, 136, 4, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt index 5bf2fb40..5650d9c 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [10, 138, 292, 160], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow DIV", @@ -28,39 +28,39 @@ "reason": "geometry" }, { - "object": "NGPhysicalTextFragment 'fringilla orci nibh sed neque. Quisque eu nulla'", + "object": "NGPhysicalTextFragment 'vel fringilla orci nibh sed neque.'", "rect": [10, 178, 291, 19], - "reason": "disappeared" + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment 'non nisi molestie accumsan. Etiam tellus urna,'", + "object": "NGPhysicalTextFragment 'Quisque eu nulla non nisi molestie'", "rect": [10, 198, 290, 19], - "reason": "disappeared" + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment 'Phasellus vehicula, sem at posuere vehicula,'", + "object": "NGPhysicalTextFragment 'ac, laoreet non, suscipit sed, sapien.'", "rect": [10, 238, 278, 19], - "reason": "disappeared" + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment 'laoreet ac, laoreet non, suscipit sed, sapien.'", + "object": "NGPhysicalTextFragment 'accumsan. Etiam tellus urna, laoreet'", "rect": [10, 218, 270, 19], - "reason": "disappeared" + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment 'augue nibh molestie nisl, nec ullamcorper'", + "object": "NGPhysicalTextFragment 'Phasellus vehicula, sem at posuere'", "rect": [10, 258, 262, 19], - "reason": "disappeared" + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment 'malesuada, est libero feugiat libero, vel'", + "object": "NGPhysicalTextFragment 'malesuada, est libero feugiat libero,'", "rect": [10, 158, 246, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [10, 138, 242, 200], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow DIV", @@ -75,12 +75,7 @@ { "object": "NGPhysicalTextFragment 'Curabitur pretium, quam quis semper'", "rect": [10, 138, 235, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Curabitur pretium, quam quis semper'", - "rect": [10, 138, 235, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'nec ullamcorper lacus ante vulputate'", @@ -88,44 +83,9 @@ "reason": "appeared" }, { - "object": "NGPhysicalTextFragment 'accumsan. Etiam tellus urna, laoreet'", - "rect": [10, 218, 227, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'ac, laoreet non, suscipit sed, sapien.'", - "rect": [10, 238, 224, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'malesuada, est libero feugiat libero,'", - "rect": [10, 158, 222, 19], - "reason": "appeared" - }, - { "object": "NGPhysicalTextFragment 'vehicula, augue nibh molestie nisl,'", "rect": [10, 278, 217, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Phasellus vehicula, sem at posuere'", - "rect": [10, 258, 217, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Quisque eu nulla non nisi molestie'", - "rect": [10, 198, 217, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'vel fringilla orci nibh sed neque.'", - "rect": [10, 178, 203, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'lacus ante vulputate pede.'", - "rect": [10, 278, 162, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGTableCell TD id='col1'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-7235-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-7235-expected.txt index ae0ad79..42f778e 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-7235-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-7235-expected.txt
@@ -25,12 +25,7 @@ { "object": "NGPhysicalTextFragment '\u00A0'", "rect": [8, 156, 4, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment '\u00A0'", - "rect": [8, 156, 4, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-expected.txt index a182ed6c..37f42ba0 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-expected.txt
@@ -33,12 +33,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'", "rect": [0, 0, 100, 100], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'", - "rect": [0, 0, 100, 100], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-individual-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-individual-expected.txt index a182ed6c..37f42ba0 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-individual-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-individual-expected.txt
@@ -33,12 +33,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'", "rect": [0, 0, 100, 100], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'", - "rect": [0, 0, 100, 100], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-expected.txt index a3e1272..2dc02c3f 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-expected.txt
@@ -34,12 +34,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'", "rect": [0, 0, 100, 100], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'", - "rect": [0, 0, 100, 100], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-individual-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-individual-expected.txt index 0760b24..2b3a86d1 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-individual-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-individual-expected.txt
@@ -35,12 +35,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'", "rect": [0, 0, 100, 100], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'", - "rect": [0, 0, 100, 100], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt index 534046b7..7df064b2 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -36,12 +36,7 @@ { "object": "NGPhysicalTextFragment 'test1'", "rect": [8, 508, 29, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'test1'", - "rect": [8, 508, 29, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutView #document",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt index c5998c4..fb89cd4 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='inline-block-2' class='item'", "rect": [0, 200, 100, 100], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='inline-block-1' class='item'", @@ -30,7 +30,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='inline-block-2' class='item'", "rect": [0, 100, 100, 100], - "reason": "appeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt index c1cccda..67515c7 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt
@@ -30,77 +30,77 @@ { "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'", "rect": [138, 168, 636, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'", "rect": [148, 168, 635, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'", "rect": [148, 168, 635, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'", "rect": [138, 128, 635, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'", "rect": [148, 128, 634, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'", "rect": [148, 128, 634, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'", "rect": [138, 188, 627, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'", "rect": [148, 188, 626, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'", "rect": [148, 188, 626, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'", "rect": [138, 148, 619, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'", "rect": [148, 148, 618, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'", "rect": [148, 148, 618, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'", "rect": [138, 208, 573, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'", "rect": [148, 208, 572, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'", "rect": [148, 208, 572, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow DIV id='content'", @@ -113,9 +113,9 @@ "reason": "incremental" }, { - "object": "NGPhysicalTextFragment 'ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'", + "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'", "rect": [400, 208, 391, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id'", @@ -123,9 +123,9 @@ "reason": "disappeared" }, { - "object": "NGPhysicalTextFragment 'ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis'", + "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'", "rect": [400, 168, 385, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'sapien, in condimentum leo neque sed nulla. Nunc quis porta'", @@ -133,9 +133,9 @@ "reason": "disappeared" }, { - "object": "NGPhysicalTextFragment 'Aenean laoreet dolor id urna eleifend aliquet. Nulla vel dolor'", + "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'", "rect": [400, 148, 384, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis'", @@ -143,16 +143,6 @@ "reason": "disappeared" }, { - "object": "NGPhysicalTextFragment 'natoque penatibus et magnis dis parturient montes, nascetur'", - "rect": [400, 188, 374, 19], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'", - "rect": [400, 128, 347, 19], - "reason": "disappeared" - }, - { "object": "LayoutNGBlockFlow DIV id='left'", "rect": [148, 128, 252, 180], "reason": "incremental"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/gradients-em-stops-repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/gradients-em-stops-repaint-expected.txt index 2249e2cb..c499a4f 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/gradients-em-stops-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/gradients-em-stops-repaint-expected.txt
@@ -40,12 +40,7 @@ { "object": "NGPhysicalTextFragment ' '", "rect": [330, 135, 4, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment ' '", - "rect": [330, 135, 4, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt index 28e9da91..59be8f7 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt
@@ -20,47 +20,47 @@ { "object": "NGPhysicalTextFragment 'AAAAA AAAA AAAA'", "rect": [0, 120, 300, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'A A A A A AA AA'", "rect": [0, 0, 300, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AA AA AA A A A'", "rect": [0, 160, 280, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AAA AAA AAA AA'", "rect": [0, 140, 280, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AAAAAA AAAAAAA'", "rect": [0, 80, 280, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AAA AAAA AAAA'", "rect": [0, 40, 260, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AA AA AAA AAA'", "rect": [0, 20, 260, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AAAAAA AAAAA'", "rect": [0, 100, 240, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AAAAA AAAAA'", "rect": [0, 60, 220, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AA AA AA A'", @@ -78,29 +78,9 @@ "reason": "disappeared" }, { - "object": "NGPhysicalTextFragment 'AAAA AAAAA'", - "rect": [0, 80, 200, 20], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'AA AAA AAA'", - "rect": [0, 40, 200, 20], - "reason": "disappeared" - }, - { "object": "NGPhysicalTextFragment 'A A A A A'", "rect": [0, 300, 180, 20], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'A A A A A'", - "rect": [0, 300, 180, 20], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'A A A A A'", - "rect": [0, 0, 180, 20], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AAAA AAA'", @@ -108,49 +88,14 @@ "reason": "disappeared" }, { - "object": "NGPhysicalTextFragment 'AAA AAAA'", - "rect": [0, 60, 160, 20], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'AA AA AA'", - "rect": [0, 20, 160, 20], - "reason": "disappeared" - }, - { "object": "NGPhysicalTextFragment 'A A A A'", "rect": [0, 280, 140, 20], "reason": "disappeared" }, { - "object": "NGPhysicalTextFragment 'AAAAAAA'", - "rect": [0, 140, 140, 20], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'AAAAAA'", - "rect": [0, 160, 120, 20], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'AAAAAA'", - "rect": [0, 120, 120, 20], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'AAAAA'", - "rect": [0, 180, 100, 20], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'AAAAA'", - "rect": [0, 100, 100, 20], - "reason": "disappeared" - }, - { "object": "NGPhysicalTextFragment 'A A'", - "rect": [0, 180, 60, 20], - "reason": "appeared" + "rect": [0, 180, 100, 20], + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt index 0692436b..bb2ed58 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt
@@ -20,312 +20,282 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow P", "rect": [8, 74, 418, 526], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow P", - "rect": [8, 74, 418, 526], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'", "rect": [14, 541, 407, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'", "rect": [14, 540, 407, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'", "rect": [14, 521, 407, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'", "rect": [14, 520, 407, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'", "rect": [14, 581, 406, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'", "rect": [14, 580, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'", "rect": [14, 561, 406, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'", "rect": [14, 560, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'", "rect": [14, 341, 406, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'", "rect": [14, 340, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'", "rect": [14, 321, 406, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'", "rect": [14, 320, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'", "rect": [14, 301, 406, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'", "rect": [14, 300, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'", "rect": [14, 281, 406, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'", "rect": [14, 280, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'", "rect": [14, 261, 406, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'", "rect": [14, 260, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'", "rect": [14, 221, 406, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'", "rect": [14, 220, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'", "rect": [14, 201, 406, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'", "rect": [14, 200, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'", "rect": [14, 481, 355, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'", "rect": [14, 480, 355, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'", "rect": [14, 461, 355, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'", "rect": [14, 460, 355, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'", "rect": [14, 160, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'", - "rect": [14, 160, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'", "rect": [14, 140, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'", - "rect": [14, 140, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'", "rect": [14, 120, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'", - "rect": [14, 120, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'", "rect": [14, 100, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'", - "rect": [14, 100, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'", "rect": [14, 80, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'", - "rect": [14, 80, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '", "rect": [65, 361, 306, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '", "rect": [65, 360, 306, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'", "rect": [65, 421, 305, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'", "rect": [65, 420, 305, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'The players all played at once without waiting'", "rect": [65, 401, 305, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'The players all played at once without waiting'", "rect": [65, 400, 305, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '", "rect": [14, 441, 289, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '", "rect": [14, 440, 289, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'head down, and was going to '", "rect": [14, 241, 230, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'head down, and was going to '", "rect": [14, 240, 230, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '", "rect": [14, 180, 225, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '", "rect": [14, 181, 222, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'begin again, it was very'", "rect": [243, 241, 178, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'begin again, it was very'", "rect": [243, 240, 178, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'about once in a minute.'", "rect": [14, 501, 147, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'about once in a minute.'", "rect": [14, 500, 147, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment ' twist itself round and'", "rect": [277, 180, 144, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment ' twist itself round and'", "rect": [279, 181, 142, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'game indeed.'", "rect": [65, 381, 85, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'game indeed.'", "rect": [65, 380, 85, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'the Queen'", "rect": [302, 441, 68, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'the Queen'", "rect": [302, 440, 68, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'difficult'", "rect": [371, 361, 50, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'difficult'", "rect": [371, 360, 50, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'", @@ -350,12 +320,7 @@ { "object": "NGPhysicalTextFragment 'would'", "rect": [235, 180, 46, 20], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'would'", - "rect": [238, 180, 41, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "VerticalScrollbar",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt index bc4e148..4e005c89 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -20,22 +20,17 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow P", "rect": [8, 74, 418, 526], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow P", - "rect": [8, 74, 418, 526], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'", "rect": [14, 540, 407, 19], - "reason": "appeared" + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'", + "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'", "rect": [14, 540, 407, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'", @@ -43,99 +38,64 @@ "reason": "appeared" }, { - "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'", + "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'", "rect": [14, 520, 407, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'", "rect": [14, 580, 406, 19], - "reason": "appeared" + "reason": "subtree" + }, + { + "object": "NGPhysicalTextFragment 'here; the great wonder is, that there\u2018s any one left alive!\u2019'", + "rect": [14, 580, 406, 19], + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'", - "rect": [14, 580, 406, 19], - "reason": "disappeared" + "rect": [14, 560, 406, 19], + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'", "rect": [14, 560, 406, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'", - "rect": [14, 560, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'", "rect": [14, 340, 406, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'", - "rect": [14, 340, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'", "rect": [14, 320, 406, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'", - "rect": [14, 320, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'", "rect": [14, 300, 406, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'", - "rect": [14, 300, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'", "rect": [14, 280, 406, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'", - "rect": [14, 280, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'", "rect": [14, 260, 406, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'", - "rect": [14, 260, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'", "rect": [14, 220, 406, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'", - "rect": [14, 220, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'", "rect": [14, 200, 406, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'", - "rect": [14, 200, 406, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'passion, and went stamping about, and shouting \u2018Off'", @@ -143,19 +103,19 @@ "reason": "appeared" }, { - "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'", + "object": "NGPhysicalTextFragment 'minute.'", "rect": [14, 480, 355, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'with his head!\u2019 or \u2018Off with her head!\u2019 about once in a'", "rect": [14, 480, 355, 19], - "reason": "appeared" + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'", + "object": "NGPhysicalTextFragment 'with his head!\u2019 or \u2018Off with her head!\u2019 about once in a'", "rect": [14, 460, 355, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'quarrelling all the while, and fighting for the hedgehogs;'", @@ -165,52 +125,27 @@ { "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'", "rect": [14, 160, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'", - "rect": [14, 160, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'", "rect": [14, 140, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'", - "rect": [14, 140, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'", "rect": [14, 120, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'", - "rect": [14, 120, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'", "rect": [14, 100, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'", - "rect": [14, 100, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'", "rect": [14, 80, 354, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'", - "rect": [14, 80, 354, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '", @@ -223,9 +158,9 @@ "reason": "disappeared" }, { - "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'", + "object": "NGPhysicalTextFragment 'and in a very short time '", "rect": [65, 420, 305, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'The players all played at once without waiting'", @@ -245,37 +180,22 @@ { "object": "NGPhysicalTextFragment 'head down, and was going to '", "rect": [14, 240, 230, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'head down, and was going to '", - "rect": [14, 240, 230, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '", "rect": [14, 180, 225, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '", - "rect": [14, 180, 225, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'begin again, it was very'", "rect": [243, 240, 178, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'begin again, it was very'", - "rect": [243, 240, 178, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'and in a very short time '", "rect": [14, 440, 171, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'about once in a minute.'", @@ -285,12 +205,7 @@ { "object": "NGPhysicalTextFragment ' twist itself round and'", "rect": [277, 180, 144, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment ' twist itself round and'", - "rect": [277, 180, 144, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment ' was in a furious'", @@ -340,7 +255,7 @@ { "object": "NGPhysicalTextFragment 'minute.'", "rect": [14, 500, 47, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'indeed.'", @@ -350,12 +265,7 @@ { "object": "NGPhysicalTextFragment 'would'", "rect": [238, 180, 41, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'would'", - "rect": [238, 180, 41, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/lines-with-layout-delta-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/lines-with-layout-delta-expected.txt index 06d32f20..d67b02d 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/lines-with-layout-delta-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/lines-with-layout-delta-expected.txt
@@ -20,12 +20,7 @@ { "object": "NGPhysicalTextFragment 'PASS'", "rect": [8, 58, 38, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'FAIL'", - "rect": [8, 58, 35, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-expected.txt index 3ee6ef35..c1004c3 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-expected.txt
@@ -20,12 +20,12 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='outer'", "rect": [61, 537, 62, 37], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='outer'", "rect": [61, 531, 62, 37], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow DIV class='outer'", @@ -160,32 +160,32 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 504, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 498, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 465, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 459, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 426, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 420, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutBlockFlow DIV", @@ -200,52 +200,52 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 177, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 171, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 138, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 132, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 99, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 93, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 60, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 54, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 21, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [67, 15, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGTableCell TD",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-right-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-right-expected.txt index 38d59d5..1cf8fa6 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-right-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-right-expected.txt
@@ -20,12 +20,12 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='outer'", "rect": [677, 537, 62, 37], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='outer'", "rect": [677, 531, 62, 37], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow DIV class='outer'", @@ -160,32 +160,32 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 504, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 498, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 465, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 459, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 426, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 420, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutBlockFlow DIV", @@ -200,52 +200,52 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 177, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 171, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 138, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 132, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 99, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 93, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 60, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 54, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 21, 50, 10], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV", "rect": [683, 15, 50, 10], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutNGTableCell TD",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt index 6d25268..9a35008 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt
@@ -18,29 +18,19 @@ "backgroundColor": "#FFFFFF", "paintInvalidations": [ { - "object": "NGPhysicalTextFragment 'velit. Integer sollicitudin nisi ut'", - "rect": [8, 182, 195, 19], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'adipiscing, enim in scelerisque'", - "rect": [8, 102, 192, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'adipiscing, enim in scelerisque'", - "rect": [8, 102, 192, 19], - "reason": "disappeared" - }, - { "object": "NGPhysicalTextFragment 'sollicitudin nisi ut urna blandit'", - "rect": [8, 182, 191, 19], - "reason": "appeared" + "rect": [8, 182, 195, 19], + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment 'at sagittis eros leo pulvinar'", + "object": "NGPhysicalTextFragment 'adipiscing, enim in scelerisque'", + "rect": [8, 102, 192, 19], + "reason": "subtree" + }, + { + "object": "NGPhysicalTextFragment 'pulvinar velit. Integer'", "rect": [8, 162, 168, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'lacus, at sagittis eros leo'", @@ -48,34 +38,19 @@ "reason": "appeared" }, { - "object": "NGPhysicalTextFragment 'urna blandit convallis.'", + "object": "NGPhysicalTextFragment 'convallis.'", "rect": [8, 202, 139, 19], - "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment 'pulvinar velit. Integer'", - "rect": [8, 162, 136, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Cras faucibus. Nunc'", "rect": [8, 82, 129, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Cras faucibus. Nunc'", - "rect": [8, 82, 129, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'convallis, augue '", "rect": [8, 122, 106, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'convallis, augue'", - "rect": [8, 122, 102, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment ' eleifend lacus,'", @@ -83,11 +58,6 @@ "reason": "disappeared" }, { - "object": "NGPhysicalTextFragment 'convallis.'", - "rect": [8, 202, 60, 19], - "reason": "appeared" - }, - { "object": "NGPhysicalTextFragment ' eleifend'", "rect": [149, 122, 54, 19], "reason": "appeared"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/inline-relative-positioned-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/inline-relative-positioned-expected.txt index e442014..4c78beaa4 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/inline-relative-positioned-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/inline-relative-positioned-expected.txt
@@ -20,22 +20,12 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'", "rect": [8, 88, 100, 100], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'", - "rect": [8, 88, 100, 100], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'a'", "rect": [8, 88, 100, 100], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'p'", - "rect": [8, 88, 100, 100], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/layout-state-relative-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/layout-state-relative-expected.txt index cade5a7..b8eaf48f 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/layout-state-relative-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/layout-state-relative-expected.txt
@@ -20,12 +20,7 @@ { "object": "NGPhysicalTextFragment 'PASS'", "rect": [8, 152, 38, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'FAIL'", - "rect": [8, 152, 35, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/positioned-document-element-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/positioned-document-element-expected.txt index 385babf..10591c3 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/positioned-document-element-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/positioned-document-element-expected.txt
@@ -25,12 +25,12 @@ { "object": "NGPhysicalTextFragment 'Tests that the entire viewport is painted with a floated html element.'", "rect": [108, 116, 424, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Tests that the entire viewport is painted with a floated html element.'", "rect": [8, 16, 424, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/push-block-with-first-line-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/push-block-with-first-line-expected.txt index 1d053c6..c579c1b 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/push-block-with-first-line-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/push-block-with-first-line-expected.txt
@@ -20,22 +20,22 @@ { "object": "NGPhysicalBoxFragment LayoutInline (anonymous)", "rect": [8, 68, 140, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'JOCULAR'", "rect": [8, 68, 140, 20], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutInline (anonymous)", "rect": [8, 8, 140, 20], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'JOCULAR'", "rect": [8, 8, 140, 20], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/quotes-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/quotes-expected.txt index e0d2e56..1cf08b7 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/quotes-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/quotes-expected.txt
@@ -20,32 +20,27 @@ { "object": "NGPhysicalTextFragment 'quote 2'", "rect": [17, 28, 47, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'quote 2'", "rect": [16, 28, 47, 19], - "reason": "appeared" + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment '\u003E'", + "object": "NGPhysicalTextFragment '}'", "rect": [64, 28, 9, 19], - "reason": "disappeared" + "reason": "subtree" }, { - "object": "NGPhysicalTextFragment '\u003C'", + "object": "NGPhysicalTextFragment '{'", "rect": [8, 28, 9, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment '}'", "rect": [63, 28, 8, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment '{'", - "rect": [8, 28, 8, 19], - "reason": "appeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-with-rotation-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-with-rotation-expected.txt index 2993677a..84282575 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-with-rotation-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-with-rotation-expected.txt
@@ -20,22 +20,12 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'", "rect": [22, 50, 226, 167], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'", - "rect": [22, 50, 226, 167], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'PASS'", "rect": [23, 51, 72, 110], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'FAIL'", - "rect": [23, 51, 69, 109], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/remove-inline-after-layout-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/remove-inline-after-layout-expected.txt index 997a52b..d8501e0 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/remove-inline-after-layout-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/remove-inline-after-layout-expected.txt
@@ -40,12 +40,7 @@ { "object": "NGPhysicalTextFragment ' '", "rect": [108, 193, 4, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment ' '", - "rect": [108, 193, 4, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/resize-iframe-text-expected.txt index d3bb216..b011069 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/resize-iframe-text-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/resize-iframe-text-expected.txt
@@ -25,12 +25,7 @@ { "object": "NGPhysicalTextFragment 'Test passes if you see \"Success\" after window resizes.'", "rect": [8, 8, 341, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Test passes if you see \"Success\" after window resizes.'", - "rect": [8, 8, 341, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow HTML",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt index 5315e639..68aed29 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt
@@ -18,14 +18,9 @@ "backgroundColor": "#FFFFFF", "paintInvalidations": [ { - "object": "NGPhysicalTextFragment 'before'", - "rect": [100, 120, 40, 19], - "reason": "disappeared" - }, - { "object": "NGPhysicalTextFragment 'after'", - "rect": [100, 120, 29, 19], - "reason": "appeared" + "rect": [100, 120, 40, 19], + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt index dc02775b..703745e5 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt
@@ -18,14 +18,9 @@ "backgroundColor": "#FFFFFF", "paintInvalidations": [ { - "object": "NGPhysicalTextFragment 'before'", - "rect": [102, 122, 40, 19], - "reason": "disappeared" - }, - { "object": "NGPhysicalTextFragment 'after'", - "rect": [102, 122, 29, 19], - "reason": "appeared" + "rect": [102, 122, 40, 19], + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt index a91b26a..7f3fde7 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt
@@ -18,14 +18,9 @@ "backgroundColor": "#FFFFFF", "paintInvalidations": [ { - "object": "NGPhysicalTextFragment 'before'", - "rect": [100, 120, 34, 19], - "reason": "disappeared" - }, - { "object": "NGPhysicalTextFragment 'after'", - "rect": [100, 120, 29, 19], - "reason": "appeared" + "rect": [100, 120, 34, 19], + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt index 55f3ded..1004caf 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt
@@ -18,14 +18,9 @@ "backgroundColor": "#FFFFFF", "paintInvalidations": [ { - "object": "NGPhysicalTextFragment ' FAIL .'", - "rect": [8, 8, 100, 19], - "reason": "disappeared" - }, - { "object": "NGPhysicalTextFragment ' PASS .'", "rect": [8, 8, 100, 19], - "reason": "appeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt index 046b972..b9963ee2 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt
@@ -20,42 +20,22 @@ { "object": "NGPhysicalTextFragment 'Bug 36461 - No vertical scrollbar after the CSS class change'", "rect": [124, 52, 383, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Bug 36461 - No vertical scrollbar after the CSS class change'", - "rect": [124, 52, 383, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'You should see both vertical and horizontal scrollbars.'", "rect": [8, 16, 340, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'You should see both vertical and horizontal scrollbars.'", - "rect": [8, 16, 340, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'This is the test for '", "rect": [8, 52, 116, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'This is the test for '", - "rect": [8, 52, 116, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment '.'", "rect": [507, 52, 4, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment '.'", - "rect": [507, 52, 4, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-delete-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-delete-expected.txt index fd754cf..652e1ed 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-delete-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-delete-expected.txt
@@ -20,12 +20,7 @@ { "object": "NGPhysicalTextFragment 'Passed'", "rect": [8, 136, 43, 17], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Failed'", - "rect": [8, 136, 39, 17], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt index f4113aee..0244c652f 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt
@@ -20,27 +20,17 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='firstLine'", "rect": [8, 8, 100, 200], - "reason": "disappeared" + "reason": "subtree" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='firstLine'", - "rect": [8, 8, 100, 100], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'FAIL: Test did'", + "object": "NGPhysicalTextFragment '\u00A0'", "rect": [8, 8, 97, 100], - "reason": "disappeared" + "reason": "selection" }, { "object": "NGPhysicalTextFragment 'not run'", "rect": [8, 108, 49, 100], "reason": "disappeared" - }, - { - "object": "NGPhysicalTextFragment '\u00A0'", - "rect": [8, 8, 8, 100], - "reason": "appeared" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/subtree-root-skipped-expected.txt index d62bef6..bb8d30e 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/subtree-root-skipped-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/subtree-root-skipped-expected.txt
@@ -25,12 +25,7 @@ { "object": "NGPhysicalTextFragment 'Selection is here'", "rect": [8, 30, 103, 19], - "reason": "chunk appeared" - }, - { - "object": "NGPhysicalTextFragment 'Selection is here'", - "rect": [8, 30, 103, 19], - "reason": "chunk disappeared" + "reason": "subtree" }, { "object": "InlineTextBox 'PASS'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt index 84b34ed5..a5251b5 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 52, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGRect rect", @@ -33,11 +33,6 @@ "reason": "paint property change" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 52, 102, 402], - "reason": "disappeared" - }, - { "object": "LayoutSVGRect rect", "rect": [17, 219, 84, 68], "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt index 1750a47..b0ae2a6 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 8, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutEmbeddedObject object", @@ -33,11 +33,6 @@ "reason": "paint property change" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 8, 202, 402], - "reason": "disappeared" - }, - { "object": "LayoutSVGRoot svg", "rect": [9, 109, 200, 200], "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-expected.txt index 697f1cd..754b7bd9 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 72, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGRect rect id='targetRect'", @@ -31,11 +31,6 @@ "object": "LayoutSVGRoot svg", "rect": [109, 73, 300, 400], "reason": "incremental" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 72, 102, 402], - "reason": "disappeared" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt index b4f0ce0..8d6d90d 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 72, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGEllipse circle", @@ -48,11 +48,6 @@ "reason": "subtree" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 72, 102, 402], - "reason": "disappeared" - }, - { "object": "LayoutSVGRoot svg", "rect": [8, 154, 39, 238], "reason": "incremental"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt index a614a650..8d51dcc0 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 72, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGContainer g id='targetUse'", @@ -28,11 +28,6 @@ "reason": "paint property change" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 72, 102, 402], - "reason": "disappeared" - }, - { "object": "LayoutSVGContainer g id='targetUse'", "rect": [59, 273, 50, 200], "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-image-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-image-expected.txt index 47af164..74f9763 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-image-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-image-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 72, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGImage image", @@ -31,11 +31,6 @@ "object": "LayoutSVGRoot svg", "rect": [109, 73, 300, 400], "reason": "incremental" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 72, 102, 402], - "reason": "disappeared" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-inner-svg-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-inner-svg-expected.txt index 00da7a5..0f22050 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-inner-svg-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-inner-svg-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 52, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGViewportContainer svg", @@ -28,11 +28,6 @@ "reason": "paint property change" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 52, 102, 402], - "reason": "disappeared" - }, - { "object": "LayoutSVGViewportContainer svg", "rect": [13, 207, 92, 92], "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-expected.txt index de82b6bb..691ecca 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 72, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGContainer use", @@ -38,11 +38,6 @@ "reason": "incremental" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 72, 102, 402], - "reason": "disappeared" - }, - { "object": "LayoutSVGContainer use", "rect": [59, 273, 50, 200], "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol-expected.txt index 3c8a60d..0871040f 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 72, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGViewportContainer svg id='targetSymbol'", @@ -28,11 +28,6 @@ "reason": "paint property change" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 72, 102, 402], - "reason": "disappeared" - }, - { "object": "LayoutSVGViewportContainer svg id='targetSymbol'", "rect": [9, 223, 100, 100], "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-on-symbol-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-on-symbol-expected.txt index 5a9dbe2..cee2e38c 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-on-symbol-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-on-symbol-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 52, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGViewportContainer svg id='gamesBorder'", @@ -28,11 +28,6 @@ "reason": "paint property change" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 52, 102, 402], - "reason": "disappeared" - }, - { "object": "LayoutSVGViewportContainer svg id='gamesBorder'", "rect": [18, 211, 82, 83], "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-without-attributes-on-symbol-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-without-attributes-on-symbol-expected.txt index 16083937..ccf8816 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-without-attributes-on-symbol-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-without-attributes-on-symbol-expected.txt
@@ -20,7 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 52, 402, 402], - "reason": "appeared" + "reason": "subtree" }, { "object": "LayoutSVGViewportContainer svg id='gamesBorder'", @@ -28,11 +28,6 @@ "reason": "paint property change" }, { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 52, 102, 402], - "reason": "disappeared" - }, - { "object": "LayoutSVGViewportContainer svg id='gamesBorder'", "rect": [13, 207, 92, 92], "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt index d8c4ee1e..98809e7 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -20,22 +20,12 @@ { "object": "NGPhysicalTextFragment 'pservers-pattern-01-b \u2190'", "rect": [208, 972, 173, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'pservers-pattern-01-b \u2190'", - "rect": [208, 972, 173, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment '\u2192 script-handle-01-b'", "rect": [427, 972, 150, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment '\u2192 script-handle-01-b'", - "rect": [427, 972, 150, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalBoxFragment LayoutInline A", @@ -55,22 +45,12 @@ { "object": "NGPhysicalTextFragment ' '", "rect": [423, 972, 5, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment ' '", - "rect": [423, 972, 5, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment ' '", "rect": [380, 972, 5, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment ' '", - "rect": [380, 972, 5, 19], - "reason": "disappeared" + "reason": "subtree" } ], "transform": 1
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/svg-image-change-content-size-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/svg-image-change-content-size-expected.txt index d16d1e6..24c5036 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/svg-image-change-content-size-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/svg-image-change-content-size-expected.txt
@@ -20,12 +20,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", "rect": [8, 52, 602, 422], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'", - "rect": [8, 52, 422, 422], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutImage img",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt index ec37fdcc..cca9c8b 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt
@@ -35,22 +35,22 @@ { "object": "NGPhysicalTextFragment 'ROW2'", "rect": [3, 400, 46, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'ROW1'", "rect": [3, 161, 46, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'ROW2'", "rect": [3, 115, 46, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'ROW1'", "rect": [3, 66, 46, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-vertical-align-cell-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-vertical-align-cell-expected.txt index 5e05214..a306b2df 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-vertical-align-cell-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-vertical-align-cell-expected.txt
@@ -20,12 +20,12 @@ { "object": "NGPhysicalTextFragment 'MIDDLE'", "rect": [3, 280, 63, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'MIDDLE'", "rect": [3, 90, 63, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-row-repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-row-repaint-expected.txt index 4eabd0a..1a9c202bb 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-row-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-row-repaint-expected.txt
@@ -20,12 +20,12 @@ { "object": "NGPhysicalTextFragment 'MIDDLE'", "rect": [3, 192, 63, 19], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'MIDDLE'", "rect": [3, 142, 63, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/table-collapsed-border-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/table-collapsed-border-expected.txt index c0d3760..7e709bd 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/table-collapsed-border-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/table-collapsed-border-expected.txt
@@ -80,42 +80,22 @@ { "object": "NGPhysicalTextFragment 'sit amet'", "rect": [23, 339, 49, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'sit amet'", - "rect": [23, 339, 49, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'sit amet'", "rect": [23, 155, 49, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'sit amet'", - "rect": [23, 155, 49, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Lorem'", "rect": [23, 295, 43, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Lorem'", - "rect": [23, 295, 43, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Lorem'", "rect": [23, 111, 43, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Lorem'", - "rect": [23, 111, 43, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'dolor'", @@ -125,22 +105,12 @@ { "object": "NGPhysicalTextFragment '\u00A0'", "rect": [17, 225, 4, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment '\u00A0'", - "rect": [17, 225, 4, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment '\u00A0'", "rect": [17, 133, 4, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment '\u00A0'", - "rect": [17, 133, 4, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt index 9ff61e6..9723c5a 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt
@@ -20,72 +20,37 @@ { "object": "NGPhysicalTextFragment 'sagittis aliquam nunc. Nullam pharetra molestie eros. Donec tempus purus ut ligula. Phasellus non nisl. Etiam eu mauris.'", "rect": [8, 144, 756, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'sagittis aliquam nunc. Nullam pharetra molestie eros. Donec tempus purus ut ligula. Phasellus non nisl. Etiam eu mauris.'", - "rect": [8, 144, 756, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'laoreet feugiat. Phasellus mollis pulvinar mi. Etiam ut neque sed eros egestas laoreet. Vestibulum ullamcorper, nulla non'", "rect": [8, 84, 751, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'laoreet feugiat. Phasellus mollis pulvinar mi. Etiam ut neque sed eros egestas laoreet. Vestibulum ullamcorper, nulla non'", - "rect": [8, 84, 751, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'pellentesque cursus. Proin vitae nulla. Vivamus in ipsum. Etiam mi. Nam malesuada purus in sem. Sed eget elit vel erat'", "rect": [8, 64, 749, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'pellentesque cursus. Proin vitae nulla. Vivamus in ipsum. Etiam mi. Nam malesuada purus in sem. Sed eget elit vel erat'", - "rect": [8, 64, 749, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse placerat. Morbi tristique. Mauris eu lacus sed felis'", "rect": [8, 44, 744, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse placerat. Morbi tristique. Mauris eu lacus sed felis'", - "rect": [8, 44, 744, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'fermentum ut, tortor. Sed rhoncus. Quisque enim metus, luctus tincidunt, vestibulum eu, vestibulum eu, libero. Mauris'", "rect": [8, 124, 740, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'fermentum ut, tortor. Sed rhoncus. Quisque enim metus, luctus tincidunt, vestibulum eu, vestibulum eu, libero. Mauris'", - "rect": [8, 124, 740, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'feugiat molestie, mi lorem bibendum leo, ac gravida orci nunc nec nulla. Nunc nunc lorem, rhoncus et, rutrum ac,'", "rect": [8, 104, 713, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'feugiat molestie, mi lorem bibendum leo, ac gravida orci nunc nec nulla. Nunc nunc lorem, rhoncus et, rutrum ac,'", - "rect": [8, 104, 713, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Curabitur a velit.'", "rect": [8, 164, 106, 19], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'Curabitur a velit'", - "rect": [8, 164, 103, 19], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt index d21e8cb..67fffa9a 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt
@@ -18,9 +18,9 @@ "backgroundColor": "#FFFFFF", "paintInvalidations": [ { - "object": "NGPhysicalTextFragment 'To be changed: findme (Manual testing:'", + "object": "NGPhysicalTextFragment 'After change'", "rect": [18, 130, 251, 19], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'Find-in-page 'findme', then click here)'", @@ -28,11 +28,6 @@ "reason": "disappeared" }, { - "object": "NGPhysicalTextFragment 'After change'", - "rect": [18, 130, 82, 19], - "reason": "appeared" - }, - { "object": "VerticalScrollbar", "rect": [295, 102, 15, 400], "reason": "scroll control"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/transform/transform-layout-repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/transform/transform-layout-repaint-expected.txt index e96fb00..cfe119e 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/transform/transform-layout-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/transform/transform-layout-repaint-expected.txt
@@ -20,22 +20,12 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'", "rect": [40, 50, 208, 118], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'", - "rect": [40, 50, 208, 118], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'PASS'", "rect": [52, 51, 43, 32], - "reason": "appeared" - }, - { - "object": "NGPhysicalTextFragment 'FAIL'", - "rect": [52, 51, 40, 31], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt index 5d62e69..afb9717 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt
@@ -25,12 +25,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'", "rect": [0, 0, 6, 250], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'", - "rect": [0, 0, 6, 250], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'", @@ -68,12 +63,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'", "rect": [0, 0, 6, 250], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'", - "rect": [0, 0, 6, 250], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'", @@ -116,12 +106,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'", "rect": [0, 0, 6, 600], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'", - "rect": [0, 0, 6, 250], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'", @@ -169,12 +154,7 @@ { "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'", "rect": [0, 0, 6, 600], - "reason": "appeared" - }, - { - "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'", - "rect": [0, 0, 6, 600], - "reason": "disappeared" + "reason": "subtree" }, { "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt index 4531371..e7eba6e 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt
@@ -135,52 +135,52 @@ { "object": "NGPhysicalTextFragment 'GGGG HHHH IIII JJJJ'", "rect": [581, 8, 68, 561], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'GGGG HHHH IIII JJJJ'", "rect": [181, 8, 68, 561], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'KKKK LLLL MMMM'", "rect": [510, 8, 68, 560], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'KKKK LLLL MMMM'", "rect": [110, 8, 68, 560], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AAAA BBBB CCCC'", "rect": [723, 8, 68, 519], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'AAAA BBBB CCCC'", "rect": [323, 8, 68, 519], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'DDDD EEEE FFFF'", "rect": [652, 8, 68, 482], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'DDDD EEEE FFFF'", "rect": [252, 8, 68, 482], - "reason": "disappeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'NNNN'", "rect": [439, 8, 68, 172], - "reason": "appeared" + "reason": "subtree" }, { "object": "NGPhysicalTextFragment 'NNNN'", "rect": [39, 8, 68, 172], - "reason": "disappeared" + "reason": "subtree" } ] }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/sibling-positioning-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/sibling-positioning-expected.png deleted file mode 100644 index 6928cbc..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/sibling-positioning-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.png deleted file mode 100644 index b56cf3c..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.txt index 1c4cbcc9..d787aec 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.txt
@@ -6,8 +6,8 @@ LayoutBlockFlow (anonymous) at (0,0) size 784x60 LayoutText {#text} at (0,0) size 741x39 text run at (0,0) width 741: "This test is for a bug we had with clipping transparency layers. The bug is visual, so the pixel test is more worthwhile." - text run at (0,20) width 644: "Below, \"Peach,\" \"Plum,\" and \"Pear\" should appear. Before, we were clipping out \"Plum\" and \"Pear.\"" - LayoutBR {BR} at (644,35) size 0x0 + text run at (0,20) width 643: "Below, \"Peach,\" \"Plum,\" and \"Pear\" should appear. Before, we were clipping out \"Plum\" and \"Pear.\"" + LayoutBR {BR} at (643,35) size 0x0 LayoutBR {BR} at (0,40) size 0x19 layer at (8,68) size 784x20 transparent LayoutBlockFlow {DIV} at (0,60) size 784x20
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers-expected.png deleted file mode 100644 index 0d0f2d7..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers2-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers2-expected.png deleted file mode 100644 index c057c97..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers2-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/dynamic/anonymous-block-layer-lost-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/dynamic/anonymous-block-layer-lost-expected.png deleted file mode 100644 index f87d11b..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/dynamic/anonymous-block-layer-lost-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/layers/opacity-stacking-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/layers/opacity-stacking-expected.png deleted file mode 100644 index 8f9b429..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/layers/opacity-stacking-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.png deleted file mode 100644 index bbfd888..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.txt index 7c34ca6..d6de78b7 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.txt
@@ -40,26 +40,26 @@ text run at (26,0) width 74: "PASS: First" text run at (5,20) width 116: "Caption aligned to" text run at (29,40) width 68: "the bottom" -layer at (10,172) size 228x20 - LayoutBlockFlow (positioned) {caption} at (10,172) size 228x20 - LayoutText {#text} at (0,0) size 228x19 - text run at (0,0) width 228: "PASS: Caption with a fixed position" +layer at (10,172) size 229x20 + LayoutBlockFlow (positioned) {caption} at (10,172) size 229x20 + LayoutText {#text} at (0,0) size 229x19 + text run at (0,0) width 229: "PASS: Caption with a fixed position" layer at (8,8) size 126x40 transparent LayoutBlockFlow {caption} at (0,0) size 126x40 LayoutText {#text} at (15,0) size 102x39 text run at (15,0) width 96: "PASS: Caption" text run at (12,20) width 102: "with opacity 0.7" -layer at (10,216) size 329x20 transparent - LayoutBlockFlow (positioned) {caption} at (10,216) size 329x20 - LayoutText {#text} at (0,0) size 329x19 - text run at (0,0) width 329: "PASS: Caption with a fixed position and opacity 0.6" +layer at (10,216) size 330x20 transparent + LayoutBlockFlow (positioned) {caption} at (10,216) size 330x20 + LayoutText {#text} at (0,0) size 330x19 + text run at (0,0) width 330: "PASS: Caption with a fixed position and opacity 0.6" layer at (8,88) size 118x59 transparent LayoutInline {a} at (0,0) size 118x59 LayoutText {#text} at (15,0) size 118x59 text run at (15,0) width 96: "PASS: Caption" text run at (4,20) width 118: "with opacity 0.5 in" text run at (14,40) width 98: "one of its child." -layer at (71,148) size 441x20 transparent - LayoutBlockFlow (positioned) {a} at (71,148) size 441x20 - LayoutText {#text} at (0,0) size 441x19 - text run at (0,0) width 441: "PASS: Caption with opacity 0.4 and fixed position of one of the child." +layer at (71,148) size 442x20 transparent + LayoutBlockFlow (positioned) {a} at (71,148) size 442x20 + LayoutText {#text} at (0,0) size 442x19 + text run at (0,0) width 442: "PASS: Caption with opacity 0.4 and fixed position of one of the child."
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.png deleted file mode 100644 index 8279354a..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.txt index 1e38f2329..75ac12ce 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.txt
@@ -37,30 +37,29 @@ LayoutText {#text} at (504,7) size 6x29 text run at (504,7) width 6: " " LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,82) size 784x30 - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (590,0) size 53x29 - text run at (590,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" - LayoutText {#text} at (584,0) size 6x29 - text run at (584,0) width 6 RTL: " " - LayoutText {#text} at (525,0) size 6x29 - text run at (525,0) width 6 RTL: " " - LayoutText {#text} at (466,0) size 6x29 - text run at (466,0) width 6 RTL: " " - LayoutText {#text} at (407,0) size 6x29 - text run at (407,0) width 6 RTL: " " - LayoutText {#text} at (348,0) size 6x29 - text run at (348,0) width 6 RTL: " " - LayoutText {#text} at (289,0) size 6x29 - text run at (289,0) width 6 RTL: " " - LayoutText {#text} at (230,0) size 6x29 - text run at (230,0) width 6 RTL: " " - LayoutText {#text} at (171,0) size 6x29 - text run at (171,0) width 6 RTL: " " - LayoutText {#text} at (112,0) size 6x29 - text run at (112,0) width 6 RTL: " " - LayoutText {#text} at (53,0) size 6x29 - text run at (53,0) width 6 RTL: " " + LayoutBlockFlow {DIV} at (0,82) size 784x60 + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (693,0) size 71x29 + text run at (693,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" + LayoutText {#text} at (687,0) size 6x29 + text run at (687,0) width 6 RTL: " " + LayoutText {#text} at (610,0) size 6x29 + text run at (610,0) width 6 RTL: " " + LayoutText {#text} at (533,0) size 6x29 + text run at (533,0) width 6 RTL: " " + LayoutText {#text} at (456,0) size 6x29 + text run at (456,0) width 6 RTL: " " + LayoutText {#text} at (379,0) size 6x29 + text run at (379,0) width 6 RTL: " " + LayoutText {#text} at (302,0) size 6x29 + text run at (302,0) width 6 RTL: " " + LayoutText {#text} at (225,0) size 6x29 + text run at (225,0) width 6 RTL: " " + LayoutText {#text} at (148,0) size 6x29 + text run at (148,0) width 6 RTL: " " + LayoutText {#text} at (71,0) size 6x29 + text run at (71,0) width 6 RTL: " " + LayoutText {#text} at (0,0) size 0x0 LayoutText {#text} at (0,0) size 0x0 layer at (8,44) size 45x29 transparent LayoutInline {SPAN} at (0,0) size 45x29 @@ -102,43 +101,43 @@ LayoutInline {SPAN} at (0,0) size 45x29 LayoutText {#text} at (510,7) size 45x29 text run at (510,7) width 45: "\x{916}\x{94B}\x{91C}\x{947}\x{902}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (531,0) size 53x29 - text run at (531,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (472,0) size 53x29 - text run at (472,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (413,0) size 53x29 - text run at (413,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (354,0) size 53x29 - text run at (354,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (295,0) size 53x29 - text run at (295,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (236,0) size 53x29 - text run at (236,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (177,0) size 53x29 - text run at (177,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (118,0) size 53x29 - text run at (118,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (59,0) size 53x29 - text run at (59,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" -layer at (8,90) size 53x29 transparent - LayoutInline {SPAN} at (0,0) size 53x29 - LayoutText {#text} at (0,0) size 53x29 - text run at (0,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (616,0) size 71x29 + text run at (616,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (539,0) size 71x29 + text run at (539,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (462,0) size 71x29 + text run at (462,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (385,0) size 71x29 + text run at (385,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (308,0) size 71x29 + text run at (308,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (231,0) size 71x29 + text run at (231,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (154,0) size 71x29 + text run at (154,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (77,0) size 71x29 + text run at (77,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (0,0) size 71x29 + text run at (0,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}" +layer at (8,90) size 71x29 transparent + LayoutInline {SPAN} at (0,0) size 71x29 + LayoutText {#text} at (0,30) size 71x29 + text run at (0,30) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index f8f2536b..15ab539 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -3473,6 +3473,7 @@ getter permissions getter platform getter product + getter serial getter storage getter usb getter userAgent
diff --git a/third_party/WebKit/LayoutTests/netinfo/gc-frame-listeners.html b/third_party/WebKit/LayoutTests/netinfo/gc-frame-listeners.html index 0c601e27..b825cc4 100644 --- a/third_party/WebKit/LayoutTests/netinfo/gc-frame-listeners.html +++ b/third_party/WebKit/LayoutTests/netinfo/gc-frame-listeners.html
@@ -1,5 +1,6 @@ <!DOCTYPE html> <head> +<script src="../resources/gc.js"></script> <script src="../resources/js-test.js"></script> <script src="resources/netinfo_common.js"></script> </head> @@ -31,22 +32,22 @@ childConnection.addEventListener('typechange', callback); })(); -gc(); -(() => {childFrame.contentWindow.gc();})() -shouldBeFalse('childFrameObserver.wasCollected'); -shouldBeFalse('childConnectionObserver.wasCollected'); -shouldBeFalse('callbackObserver.wasCollected'); +asyncGC().then(() => { + shouldBeFalse('childFrameObserver.wasCollected'); + shouldBeFalse('childConnectionObserver.wasCollected'); + shouldBeFalse('callbackObserver.wasCollected'); -// Access objects in an inner function to avoid references to objects -// remaining live on this function's stack frame (http://crbug.com/595672/). -(() => {document.body.removeChild(childFrame);})(); -(() => {childFrame = null;})(); -gc(); -shouldBeTrue('childFrameObserver.wasCollected'); -shouldBeTrue('childConnectionObserver.wasCollected'); -shouldBeTrue('callbackObserver.wasCollected'); + document.body.removeChild(childFrame); + childFrame = null; -finishJSTest(); + return asyncGC(); +}).then(() => { + shouldBeTrue('childFrameObserver.wasCollected'); + shouldBeTrue('childConnectionObserver.wasCollected'); + shouldBeTrue('callbackObserver.wasCollected'); + + finishJSTest(); +}); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/layers/remove-layer-with-nested-stacking-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/layers/remove-layer-with-nested-stacking-expected.png index a1f4763..9a8cc14 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/layers/remove-layer-with-nested-stacking-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/layers/remove-layer-with-nested-stacking-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/table/overflowHidden-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/table/overflowHidden-expected.png index f5ef6c2..32c54d6 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/table/overflowHidden-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/table/overflowHidden-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png index b32ef85..85d4f5d 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png index 69192ad4..d46ec31 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png index 4b8d324..3af4d8b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png index 986a358a..1887e224 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png index 3422961a..9d1dd316 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png index 69192ad4..d46ec31 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png index 4b8d324..3af4d8b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png index 986a358a..1887e224 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png index 3422961a..9d1dd316 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.png deleted file mode 100644 index 20c1f44..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.txt deleted file mode 100644 index 9dc59f4e..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.txt +++ /dev/null
@@ -1,33 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x170 - LayoutBlockFlow {HTML} at (0,0) size 800x170 - LayoutBlockFlow {BODY} at (8,8) size 784x154 - LayoutText {#text} at (0,0) size 0x0 -layer at (8,8) size 300x150 - LayoutVideo {VIDEO} at (0,0) size 300x150 -layer at (8,8) size 300x150 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x150 - LayoutBlockFlow {DIV} at (0,118) size 300x32 -layer at (8,8) size 300x108 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108 -layer at (8,126) size 300x32 scrollHeight 40 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA] - LayoutButton {INPUT} at (0,0) size 32x32 - LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A] - LayoutBlockFlow (anonymous) at (0,0) size 23.36x32 - LayoutText {#text} at (0,9) size 24x14 - text run at (0,9) width 24: "0:07" - LayoutFlexibleBox {DIV} at (55.36,0) size 34.69x32 [color=#5A5A5A] - LayoutBlockFlow (anonymous) at (4,0) size 30.69x32 - LayoutText {#text} at (0,9) size 31x14 - text run at (0,9) width 31: "/ 0:07" - LayoutSlider {INPUT} at (108.05,15) size 80.95x2 - LayoutFlexibleBox {DIV} at (0,0) size 80.95x2 - LayoutBlockFlow {DIV} at (-18,-23) size 116.95x48 - LayoutBlockFlow {DIV} at (80.95,0) size 36x48 - LayoutButton {INPUT} at (207,0) size 32x32 - LayoutSlider {INPUT} at (257,15) size 25x2 - LayoutFlexibleBox {DIV} at (0,0) size 25x2 - LayoutBlockFlow {DIV} at (-18,-23) size 61x48 - LayoutBlockFlow {DIV} at (25,0) size 36x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png index 8632660..e773d1c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png index f5eb453..60349c2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png index 58e0c726..ae76971 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png index 6349b3fe..8cc5110 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png index ed55197a1..d3317d4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png index f5eb453..60349c2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png index 58e0c726..ae76971 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png index 6349b3fe..8cc5110 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png index ed55197a1..d3317d4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.png deleted file mode 100644 index 20c1f44..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.txt deleted file mode 100644 index 9dc59f4e..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.txt +++ /dev/null
@@ -1,33 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x170 - LayoutBlockFlow {HTML} at (0,0) size 800x170 - LayoutBlockFlow {BODY} at (8,8) size 784x154 - LayoutText {#text} at (0,0) size 0x0 -layer at (8,8) size 300x150 - LayoutVideo {VIDEO} at (0,0) size 300x150 -layer at (8,8) size 300x150 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x150 - LayoutBlockFlow {DIV} at (0,118) size 300x32 -layer at (8,8) size 300x108 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108 -layer at (8,126) size 300x32 scrollHeight 40 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA] - LayoutButton {INPUT} at (0,0) size 32x32 - LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A] - LayoutBlockFlow (anonymous) at (0,0) size 23.36x32 - LayoutText {#text} at (0,9) size 24x14 - text run at (0,9) width 24: "0:07" - LayoutFlexibleBox {DIV} at (55.36,0) size 34.69x32 [color=#5A5A5A] - LayoutBlockFlow (anonymous) at (4,0) size 30.69x32 - LayoutText {#text} at (0,9) size 31x14 - text run at (0,9) width 31: "/ 0:07" - LayoutSlider {INPUT} at (108.05,15) size 80.95x2 - LayoutFlexibleBox {DIV} at (0,0) size 80.95x2 - LayoutBlockFlow {DIV} at (-18,-23) size 116.95x48 - LayoutBlockFlow {DIV} at (80.95,0) size 36x48 - LayoutButton {INPUT} at (207,0) size 32x32 - LayoutSlider {INPUT} at (257,15) size 25x2 - LayoutFlexibleBox {DIV} at (0,0) size 25x2 - LayoutBlockFlow {DIV} at (-18,-23) size 61x48 - LayoutBlockFlow {DIV} at (25,0) size 36x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/layers/remove-layer-with-nested-stacking-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/layers/remove-layer-with-nested-stacking-expected.png index 415932d..ba79e8b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/layers/remove-layer-with-nested-stacking-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/layers/remove-layer-with-nested-stacking-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/table/overflowHidden-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/table/overflowHidden-expected.png index 6c0e46ea..f2ff84c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/table/overflowHidden-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/table/overflowHidden-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png index 66559c4..6e13f8ee 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png index dde8996..b985e1a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png index cc6a03b..0862e85 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png index af3dfcb7..e08b5ba 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png index 58ac52c..2f29279 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/layers/remove-layer-with-nested-stacking-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/layers/remove-layer-with-nested-stacking-expected.png index cf0cddf8..e9ccb63 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/layers/remove-layer-with-nested-stacking-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/layers/remove-layer-with-nested-stacking-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/table/overflowHidden-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/table/overflowHidden-expected.png index c2f4564..6a149cfd 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/table/overflowHidden-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/table/overflowHidden-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png index e06b88e..15254408 100644 --- a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png index 90899719..fdefc931 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png index 09cfc341..efe724818 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png index 960cb4e0..81bcf379 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png index 51748e6b..99f13f1 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.png deleted file mode 100644 index d9b7beff..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.txt deleted file mode 100644 index fb7f6a4..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.txt +++ /dev/null
@@ -1,33 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x170 - LayoutBlockFlow {HTML} at (0,0) size 800x170 - LayoutBlockFlow {BODY} at (8,8) size 784x154 - LayoutText {#text} at (0,0) size 0x0 -layer at (8,8) size 300x150 - LayoutVideo {VIDEO} at (0,0) size 300x150 -layer at (8,8) size 300x150 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x150 - LayoutBlockFlow {DIV} at (0,118) size 300x32 -layer at (8,8) size 300x108 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108 -layer at (8,126) size 300x32 scrollHeight 40 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA] - LayoutButton {INPUT} at (0,0) size 32x32 - LayoutFlexibleBox {DIV} at (32,0) size 17.73x32 [color=#5A5A5A] - LayoutBlockFlow (anonymous) at (0,0) size 17.73x32 - LayoutText {#text} at (0,9) size 18x14 - text run at (0,9) width 18: "0:07" - LayoutFlexibleBox {DIV} at (49.73,0) size 28.27x32 [color=#5A5A5A] - LayoutBlockFlow (anonymous) at (4,0) size 24.27x32 - LayoutText {#text} at (0,9) size 25x14 - text run at (0,9) width 25: "/ 0:07" - LayoutSlider {INPUT} at (96,15) size 89.13x2 - LayoutFlexibleBox {DIV} at (0,0) size 89.13x2 - LayoutBlockFlow {DIV} at (-18,-23) size 125.13x48 - LayoutBlockFlow {DIV} at (89.13,0) size 36x48 - LayoutButton {INPUT} at (203.13,0) size 32x32 - LayoutSlider {INPUT} at (253.13,15) size 28.88x2 - LayoutFlexibleBox {DIV} at (0,0) size 28.88x2 - LayoutBlockFlow {DIV} at (-18,-23) size 64.88x48 - LayoutBlockFlow {DIV} at (28.88,0) size 36x48
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt index ce030b6..3102855e8 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1041,6 +1041,21 @@ [Worker] method formData [Worker] method json [Worker] method text +[Worker] interface Serial : EventTarget +[Worker] attribute @@toStringTag +[Worker] getter onconnect +[Worker] getter ondisconnect +[Worker] method constructor +[Worker] method getPorts +[Worker] setter onconnect +[Worker] setter ondisconnect +[Worker] interface SerialPort +[Worker] attribute @@toStringTag +[Worker] getter in +[Worker] getter out +[Worker] method close +[Worker] method constructor +[Worker] method open [Worker] interface ServiceWorkerRegistration : EventTarget [Worker] attribute @@toStringTag [Worker] getter active @@ -3485,6 +3500,7 @@ [Worker] getter permissions [Worker] getter platform [Worker] getter product +[Worker] getter serial [Worker] getter storage [Worker] getter usb [Worker] getter userAgent
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index 0fc50c6..45157a1 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4693,6 +4693,7 @@ getter presentation getter product getter productSub + getter serial getter serviceWorker getter storage getter usb @@ -6944,6 +6945,22 @@ attribute @@toStringTag getter error method constructor +interface Serial : EventTarget + attribute @@toStringTag + getter onconnect + getter ondisconnect + method constructor + method getPorts + method requestPort + setter onconnect + setter ondisconnect +interface SerialPort + attribute @@toStringTag + getter in + getter out + method close + method constructor + method open interface ServiceWorker : EventTarget attribute @@toStringTag getter onerror
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt index ba9b3d5..e47ddc02 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -3372,6 +3372,7 @@ [Worker] getter permissions [Worker] getter platform [Worker] getter product +[Worker] getter serial [Worker] getter storage [Worker] getter usb [Worker] getter userAgent
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index aeb5c2a..739444e9 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -245,7 +245,6 @@ "platform/web_encrypted_media_key_information.h", "platform/web_encrypted_media_request.h", "platform/web_encrypted_media_types.h", - "platform/web_file_system.h", "platform/web_file_system_type.h", "platform/web_file_utilities.h", "platform/web_float_point.h",
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index 60ab65d..ebb56c7 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -32,6 +32,7 @@ "frame/find_in_page.mojom", "indexeddb/indexeddb.mojom", "leak_detector/leak_detector.mojom", + "loader/code_cache.mojom", "loader/navigation_predictor.mojom", "loader/pause_subresource_loading_handle.mojom", "loader/previews_resource_loading_hints.mojom",
diff --git a/third_party/blink/public/mojom/filesystem/file_system.mojom b/third_party/blink/public/mojom/filesystem/file_system.mojom index 8a03eb6..d33a4ee 100644 --- a/third_party/blink/public/mojom/filesystem/file_system.mojom +++ b/third_party/blink/public/mojom/filesystem/file_system.mojom
@@ -219,9 +219,7 @@ // success. // TODO(https://crbug.com/878581): Add more options to this method to support // multiple files, directories, "open" vs "save" dialogs, etc. - // TODO(https://crbug.com/873661): Make interface per frame/worker and remove - // |render_frame_id|. - ChooseEntry(int32 render_frame_id) => + ChooseEntry() => (mojo_base.mojom.FileError error_code, array<FileSystemEntry> entries); };
diff --git a/third_party/blink/public/mojom/loader/code_cache.mojom b/third_party/blink/public/mojom/loader/code_cache.mojom new file mode 100644 index 0000000..7bd7041 --- /dev/null +++ b/third_party/blink/public/mojom/loader/code_cache.mojom
@@ -0,0 +1,36 @@ +// 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. + +module blink.mojom; + +import "mojo/public/mojom/base/time.mojom"; +import "url/mojom/origin.mojom"; +import "url/mojom/url.mojom"; + +// Interface to the code cache in the browser process. Renderer processes +// can use this interface to persistently store and retrieve executable code +// generated for a URL. +interface CodeCacheHost { + // Requests that the browser cache |data| associated with |url| and + // |expected_response_time|. + DidGenerateCacheableMetadata(url.mojom.Url url, + mojo_base.mojom.Time expected_response_time, + array<uint8> data); + + // TODO(crbug.com/867848) Pass the data as mojo data_pipe instead of + // array<unit8>. + FetchCachedCode(url.mojom.Url url) => (mojo_base.mojom.Time response_time, + array<uint8> data); + + ClearCodeCacheEntry(url.mojom.Url url); + + // Requests that the browser cache |data| for the specified CacheStorage entry. + // TODO(https://crbug.com/779444): Verify or remove |cache_storage_origin|. + // TODO(kinuko): Consider making the renderer-side code directly call into the + // origin's CacheStoragePtr. + DidGenerateCacheableMetadataInCacheStorage( + url.mojom.Url url, mojo_base.mojom.Time expected_response_time, + array<uint8> data, url.mojom.Origin cache_storage_origin, + string cache_storage_cache_name); +};
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h index 4128909..e98560a 100644 --- a/third_party/blink/public/platform/platform.h +++ b/third_party/blink/public/platform/platform.h
@@ -102,7 +102,6 @@ class WebCookieJar; class WebCrypto; class WebDatabaseObserver; -class WebFileSystem; class WebGraphicsContext3DProvider; class WebImageCaptureFrameGrabber; class WebLocalFrame; @@ -279,9 +278,6 @@ // FileSystem ---------------------------------------------------------- - // Must return non-null. - virtual WebFileSystem* FileSystem() { return nullptr; } - // Return a filename-friendly identifier for an origin. virtual WebString FileSystemCreateOriginIdentifier( const WebSecurityOrigin& origin) {
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom index 379a9fe8..9ca5760a 100644 --- a/third_party/blink/public/platform/web_feature.mojom +++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1995,6 +1995,10 @@ kPaymentAddressLanguageCode = 2542, kDocumentDomainBlockedCrossOriginAccess = 2543, kDocumentDomainEnabledCrossOriginAccess = 2544, + kSerialGetPorts = 2545, + kSerialRequestPort = 2546, + kSerialPortOpen = 2547, + kSerialPortClose = 2548, // 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/blink/public/platform/web_file_system.h b/third_party/blink/public/platform/web_file_system.h deleted file mode 100644 index 87a373ac..0000000 --- a/third_party/blink/public/platform/web_file_system.h +++ /dev/null
@@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_FILE_SYSTEM_H_ -#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_FILE_SYSTEM_H_ - -#include "base/files/file.h" -#include "mojo/public/cpp/system/message_pipe.h" -#include "third_party/blink/public/platform/web_callbacks.h" -#include "third_party/blink/public/platform/web_common.h" -#include "third_party/blink/public/platform/web_file_system_type.h" -#include "third_party/blink/public/platform/web_url.h" -#include "third_party/blink/public/platform/web_vector.h" - -namespace blink { - -class WebFrame; - -class WebFileSystem { - public: - struct FileSystemEntry { - WebString file_system_id; - WebString base_name; - }; - - // Prompts the user to select a file from the native filesystem. Returns an - // error code if something failed, or a list of the selected entries on - // success. - using ChooseEntryCallbacks = - WebCallbacks<WebVector<FileSystemEntry>, base::File::Error>; - virtual void ChooseEntry(WebFrame* frame, - std::unique_ptr<ChooseEntryCallbacks>) = 0; - - protected: - virtual ~WebFileSystem() = default; -}; - -} // namespace blink - -#endif
diff --git a/third_party/blink/public/web/web_dom_file_system.h b/third_party/blink/public/web/web_dom_file_system.h index 77ed4b6..f277aed 100644 --- a/third_party/blink/public/web/web_dom_file_system.h +++ b/third_party/blink/public/web/web_dom_file_system.h
@@ -31,7 +31,7 @@ #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_DOM_FILE_SYSTEM_H_ #include "third_party/blink/public/platform/web_common.h" -#include "third_party/blink/public/platform/web_file_system.h" +#include "third_party/blink/public/platform/web_file_system_type.h" #include "third_party/blink/public/platform/web_private_ptr.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/platform/web_url.h"
diff --git a/third_party/blink/public/web/web_frame_widget.h b/third_party/blink/public/web/web_frame_widget.h index 5c1a414a..9837a3b 100644 --- a/third_party/blink/public/web/web_frame_widget.h +++ b/third_party/blink/public/web/web_frame_widget.h
@@ -47,7 +47,16 @@ class WebFrameWidget : public WebWidget { public: - BLINK_EXPORT static WebFrameWidget* Create(WebWidgetClient*, WebLocalFrame*); + // Makes a WebFrameWidget that wraps a pre-existing WebWidget from the + // RenderView/WebView, for a new local main frame. + BLINK_EXPORT static WebFrameWidget* CreateForMainFrame( + WebWidgetClient*, + WebLocalFrame* main_frame); + // Makes a WebFrameWidget that wraps a WebLocalFrame that is not a main frame, + // providing a WebWidget to interact with the child local root frame. + BLINK_EXPORT static WebFrameWidget* CreateForChildLocalRoot( + WebWidgetClient*, + WebLocalFrame* local_root); // Sets the visibility of the WebFrameWidget. // We still track page-level visibility, but additionally we need to notify a
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h index 7d18e0c..cb74488 100644 --- a/third_party/blink/public/web/web_local_frame_client.h +++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -47,7 +47,6 @@ #include "third_party/blink/public/platform/web_content_security_policy_struct.h" #include "third_party/blink/public/platform/web_content_settings_client.h" #include "third_party/blink/public/platform/web_effective_connection_type.h" -#include "third_party/blink/public/platform/web_file_system.h" #include "third_party/blink/public/platform/web_file_system_type.h" #include "third_party/blink/public/platform/web_insecure_request_policy.h" #include "third_party/blink/public/platform/web_loading_behavior_flag.h"
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index d289d9ec..92e43fd 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -2028,6 +2028,7 @@ "layout/ng/ng_block_node_test.cc", "layout/ng/ng_column_layout_algorithm_test.cc", "layout/ng/ng_constraint_space_builder_test.cc", + "layout/ng/ng_fieldset_layout_algorithm_test.cc", "layout/ng/ng_inline_layout_test.cc", "layout/ng/ng_layout_test.h", "layout/ng/ng_length_utils_test.cc",
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc index 9dc15cb..f74801ce 100644 --- a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc +++ b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -54,7 +54,7 @@ const PropertyRegistry* registry, const Document& document) : registry_(registry) { - allow_all_animations_ = document.GetFrame()->IsFeatureEnabled( + allow_all_animations_ = document.GetFrame()->DeprecatedIsFeatureEnabled( blink::mojom::FeaturePolicyFeature::kAnimations); }
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index c085865c..7be10e9 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -6217,9 +6217,9 @@ if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) { return true; } - if (!frame_ || - frame_->IsFeatureEnabled(mojom::FeaturePolicyFeature::kDocumentWrite, - ReportOptions::kReportOnFailure)) { + if (!frame_ || frame_->DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature::kDocumentWrite, + ReportOptions::kReportOnFailure)) { return true; }
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc index 5421536..f701e233 100644 --- a/third_party/blink/renderer/core/exported/web_view_test.cc +++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -2542,7 +2542,7 @@ WebLocalFrame* local_frame = WebLocalFrame::CreateMainFrame( web_view, &web_frame_client, nullptr, nullptr); web_frame_client.Bind(local_frame); - blink::WebFrameWidget::Create(&web_widget_client, local_frame); + blink::WebFrameWidget::CreateForMainFrame(&web_widget_client, local_frame); WebGestureEvent event(WebInputEvent::kGestureTap, WebInputEvent::kNoModifiers, WebInputEvent::GetStaticTimeStampForTests(),
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc index 3b3ae4d..2ecc05c 100644 --- a/third_party/blink/renderer/core/frame/deprecation.cc +++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -746,7 +746,7 @@ return; // If the feature is allowed, don't log a warning. - if (frame->IsFeatureEnabled(feature)) + if (frame->DeprecatedIsFeatureEnabled(feature)) return; // If the feature is disabled, log a warning but only if the request is from a
diff --git a/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc b/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc index 3138b17..5fd0ecc 100644 --- a/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc +++ b/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc
@@ -98,7 +98,7 @@ return false; return std::all_of(features.begin(), features.end(), [frame](mojom::FeaturePolicyFeature feature) { - return frame->IsFeatureEnabled(feature); + return frame->DeprecatedIsFeatureEnabled(feature); }); }
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc index 87c4fdd..6e74b71 100644 --- a/third_party/blink/renderer/core/frame/frame.cc +++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -256,8 +256,8 @@ : UserGestureIndicator::ConsumeUserGesture(); } -bool Frame::IsFeatureEnabled(mojom::FeaturePolicyFeature feature, - ReportOptions report_on_failure) const { +bool Frame::DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature feature, + ReportOptions report_on_failure) const { FeaturePolicy* feature_policy = GetSecurityContext()->GetFeaturePolicy(); // The policy should always be initialized before checking it to ensure we // properly inherit the parent policy. @@ -266,7 +266,7 @@ if (feature_policy->IsFeatureEnabled(feature)) return true; if (report_on_failure == ReportOptions::kReportOnFailure) - ReportFeaturePolicyViolation(feature); + DeprecatedReportFeaturePolicyViolation(feature); return false; }
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h index 3c1c079..9e2e1bf 100644 --- a/third_party/blink/renderer/core/frame/frame.h +++ b/third_party/blink/renderer/core/frame/frame.h
@@ -230,11 +230,12 @@ // Optionally sends a report to any registered reporting observers or // Report-To endpoints, via ReportFeaturePolicyViolation(), if the feature is // disabled. - bool IsFeatureEnabled( + // TODO(iclelland): Replace these with methods on SecurityContext/Document + bool DeprecatedIsFeatureEnabled( mojom::FeaturePolicyFeature, ReportOptions report_on_failure = ReportOptions::kDoNotReport) const; - virtual void ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature) const { - } + virtual void DeprecatedReportFeaturePolicyViolation( + mojom::FeaturePolicyFeature) const {} // Called to make a frame inert or non-inert. A frame is inert when there // is a modal dialog displayed within an ancestor frame, and this frame
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc index e0ab5fd..8ab6a37 100644 --- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc +++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -179,7 +179,8 @@ WebLocalFrameImpl* CreateLocalChild(WebLocalFrame& parent, WebTreeScopeType scope, TestWebFrameClient* client) { - auto owned_client = CreateDefaultClientIfNeeded(client); + std::unique_ptr<TestWebFrameClient> owned_client = + CreateDefaultClientIfNeeded(client); WebLocalFrameImpl* frame = ToWebLocalFrameImpl(parent.CreateLocalChild(scope, client, nullptr)); client->Bind(frame, std::move(owned_client)); @@ -200,34 +201,33 @@ WebLocalFrameImpl* CreateProvisional(WebRemoteFrame& old_frame, TestWebFrameClient* client) { - auto owned_client = CreateDefaultClientIfNeeded(client); + std::unique_ptr<TestWebFrameClient> owned_client = + CreateDefaultClientIfNeeded(client); WebLocalFrameImpl* frame = ToWebLocalFrameImpl(WebLocalFrame::CreateProvisional( client, nullptr, &old_frame, WebSandboxFlags::kNone, ParsedFeaturePolicy())); client->Bind(frame, std::move(owned_client)); // Create a local root, if necessary. - std::unique_ptr<WebWidgetClient> owned_widget_client; - WebWidgetClient* widget_client = nullptr; if (!frame->Parent()) { // TODO(dcheng): The main frame widget currently has a special case. // Eliminate this once WebView is no longer a WebWidget. - widget_client = frame->ViewImpl()->Client()->WidgetClient(); + WebWidgetClient* widget_client = + frame->ViewImpl()->Client()->WidgetClient(); + WebFrameWidget::CreateForMainFrame(widget_client, frame); } else if (frame->Parent()->IsWebRemoteFrame()) { - owned_widget_client = std::make_unique<TestWebWidgetClient>(); - widget_client = owned_widget_client.get(); + auto widget_client = std::make_unique<TestWebWidgetClient>(); + WebFrameWidget* frame_widget = + WebFrameWidget::CreateForChildLocalRoot(widget_client.get(), frame); + frame_widget->Resize(WebSize()); + client->BindWidgetClient(std::move(widget_client)); } - if (widget_client) { - WebFrameWidget::Create(widget_client, frame); - if (frame->Parent()) - frame->FrameWidget()->Resize(WebSize()); - } - client->BindWidgetClient(std::move(owned_widget_client)); return frame; } WebRemoteFrameImpl* CreateRemote(TestWebRemoteFrameClient* client) { - auto owned_client = CreateDefaultClientIfNeeded(client); + std::unique_ptr<TestWebRemoteFrameClient> owned_client = + CreateDefaultClientIfNeeded(client); auto* frame = WebRemoteFrameImpl::Create(WebTreeScopeType::kDocument, client); client->Bind(frame, std::move(owned_client)); return frame; @@ -239,14 +239,16 @@ WebFrame* previous_sibling, TestWebFrameClient* client, TestWebWidgetClient* widget_client) { - auto owned_client = CreateDefaultClientIfNeeded(client); - auto* frame = ToWebLocalFrameImpl(parent.CreateLocalChild( + std::unique_ptr<TestWebFrameClient> owned_client = + CreateDefaultClientIfNeeded(client); + WebLocalFrameImpl* frame = ToWebLocalFrameImpl(parent.CreateLocalChild( WebTreeScopeType::kDocument, name, WebSandboxFlags::kNone, client, nullptr, previous_sibling, ParsedFeaturePolicy(), properties, nullptr)); client->Bind(frame, std::move(owned_client)); - auto owned_widget_client = CreateDefaultClientIfNeeded(widget_client); - WebFrameWidget::Create(widget_client, frame); + std::unique_ptr<TestWebWidgetClient> owned_widget_client = + CreateDefaultClientIfNeeded(widget_client); + WebFrameWidget::CreateForChildLocalRoot(widget_client, frame); // Set an initial size for subframes. if (frame->Parent()) frame->FrameWidget()->Resize(WebSize()); @@ -259,7 +261,8 @@ const WebString& name, scoped_refptr<SecurityOrigin> security_origin, TestWebRemoteFrameClient* client) { - auto owned_client = CreateDefaultClientIfNeeded(client); + std::unique_ptr<TestWebRemoteFrameClient> owned_client = + CreateDefaultClientIfNeeded(client); auto* frame = ToWebRemoteFrameImpl(parent.CreateRemoteChild( WebTreeScopeType::kDocument, name, WebSandboxFlags::kNone, ParsedFeaturePolicy(), client, nullptr)); @@ -289,7 +292,8 @@ if (update_settings_func) update_settings_func(web_view_->GetSettings()); - auto owned_web_frame_client = CreateDefaultClientIfNeeded(web_frame_client); + std::unique_ptr<TestWebFrameClient> owned_web_frame_client = + CreateDefaultClientIfNeeded(web_frame_client); WebLocalFrame* frame = WebLocalFrame::CreateMainFrame( web_view_, web_frame_client, nullptr, opener); web_frame_client->Bind(frame, std::move(owned_web_frame_client)); @@ -299,7 +303,7 @@ WebWidgetClient* web_widget_client = test_web_widget_client; if (!web_widget_client) web_widget_client = test_web_view_client_->WidgetClient(); - blink::WebFrameWidget::Create(web_widget_client, frame); + blink::WebFrameWidget::CreateForMainFrame(web_widget_client, frame); // Set an initial size for subframes. if (frame->Parent()) frame->FrameWidget()->Resize(WebSize()); @@ -338,7 +342,7 @@ InitializeWebView(web_view_client, nullptr); - auto owned_web_remote_frame_client = + std::unique_ptr<TestWebRemoteFrameClient> owned_web_remote_frame_client = CreateDefaultClientIfNeeded(web_remote_frame_client); WebRemoteFrameImpl* frame = WebRemoteFrameImpl::CreateMainFrame( web_view_, web_remote_frame_client, nullptr);
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 81ec5c9..345caf6 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1441,7 +1441,7 @@ return reporting_service_; } -void LocalFrame::ReportFeaturePolicyViolation( +void LocalFrame::DeprecatedReportFeaturePolicyViolation( mojom::FeaturePolicyFeature feature) const { if (!RuntimeEnabledFeatures::FeaturePolicyReportingEnabled()) return;
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h index 6a53c3dd..ef70673 100644 --- a/third_party/blink/renderer/core/frame/local_frame.h +++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -372,7 +372,9 @@ SmoothScrollSequencer& GetSmoothScrollSequencer(); - void ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature) const override; + // TODO(iclelland): Replace this with a method on Document + void DeprecatedReportFeaturePolicyViolation( + mojom::FeaturePolicyFeature) const override; private: friend class FrameNavigationDisabler;
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index aa6d50c69..eeee21c 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -104,26 +104,41 @@ // WebFrameWidget ------------------------------------------------------------ -WebFrameWidget* WebFrameWidget::Create(WebWidgetClient* client, - WebLocalFrame* local_root) { +WebFrameWidget* WebFrameWidget::CreateForMainFrame(WebWidgetClient* client, + WebLocalFrame* main_frame) { DCHECK(client) << "A valid WebWidgetClient must be supplied."; - WebFrameWidgetBase* widget; - if (!local_root->Parent()) { - // Note: this isn't a leak, as the object has a self-reference that the - // caller needs to release by calling Close(). - WebLocalFrameImpl& main_frame = ToWebLocalFrameImpl(*local_root); - DCHECK(main_frame.ViewImpl()); - // Note: this can't DCHECK that the view's main frame points to - // |main_frame|, as provisional frames violate this precondition. - // TODO(dcheng): Remove the special bridge class for main frame widgets. - widget = new WebViewFrameWidget(*client, *main_frame.ViewImpl()); - } else { - DCHECK(local_root->Parent()->IsWebRemoteFrame()) - << "Only local roots can have web frame widgets."; - // Note: this isn't a leak, as the object has a self-reference that the - // caller needs to release by calling Close(). - widget = WebFrameWidgetImpl::Create(*client); - } + DCHECK(!main_frame->Parent()); // This is the main frame. + + // Grabs the WebViewImpl associated with the |main_frame|, which will then + // be wrapped by the WebViewFrameWidget, with calls being forwarded to the + // |main_frame|'s WebViewImpl. + // Note: this can't DCHECK that the view's main frame points to + // |main_frame|, as provisional frames violate this precondition. + WebLocalFrameImpl& main_frame_impl = ToWebLocalFrameImpl(*main_frame); + DCHECK(main_frame_impl.ViewImpl()); + WebViewImpl& web_view_impl = *main_frame_impl.ViewImpl(); + + // Note: this isn't a leak, as the object has a self-reference that the + // caller needs to release by calling Close(). + // TODO(dcheng): Remove the special bridge class for main frame widgets. + WebFrameWidgetBase* widget = new WebViewFrameWidget(*client, web_view_impl); + widget->BindLocalRoot(*main_frame); + return widget; +} + +WebFrameWidget* WebFrameWidget::CreateForChildLocalRoot( + WebWidgetClient* client, + WebLocalFrame* local_root) { + DCHECK(client) << "A valid WebWidgetClient must be supplied."; + DCHECK(local_root->Parent()); // This is not the main frame. + // Frames whose direct ancestor is a remote frame are local roots. Verify this + // is one. Other frames should be using the widget for their nearest local + // root. + DCHECK(local_root->Parent()->IsWebRemoteFrame()); + + // Note: this isn't a leak, as the object has a self-reference that the + // caller needs to release by calling Close(). + WebFrameWidgetBase* widget = WebFrameWidgetImpl::Create(*client); widget->BindLocalRoot(*local_root); return widget; }
diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/third_party/blink/renderer/core/fullscreen/fullscreen.cc index 8d0606f..a6f9e01 100644 --- a/third_party/blink/renderer/core/fullscreen/fullscreen.cc +++ b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
@@ -215,8 +215,8 @@ // 2. If Feature Policy is enabled, return the policy for "fullscreen" // feature. - return frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kFullscreen, - report_on_failure); + return frame->DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature::kFullscreen, report_on_failure); } bool AllowedToRequestFullscreen(Document& document) {
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics.cc b/third_party/blink/renderer/core/html/anchor_element_metrics.cc index b980a75b..7a2ec806 100644 --- a/third_party/blink/renderer/core/html/anchor_element_metrics.cc +++ b/third_party/blink/renderer/core/html/anchor_element_metrics.cc
@@ -212,6 +212,7 @@ const HTMLAnchorElement* anchor_element) { if (!base::FeatureList::IsEnabled(features::kRecordAnchorMetricsClicked) || !anchor_element->Href().ProtocolIsInHTTPFamily() || + !GetRootDocument(*anchor_element)->Url().ProtocolIsInHTTPFamily() || !anchor_element->GetDocument().BaseURL().ProtocolIsInHTTPFamily()) { return base::nullopt; } @@ -235,6 +236,7 @@ DCHECK(document.GetFrame()); if (!base::FeatureList::IsEnabled(features::kRecordAnchorMetricsVisible) || document.ParentDocument() || !document.View() || + !document.Url().ProtocolIsInHTTPFamily() || !document.BaseURL().ProtocolIsInHTTPFamily()) { return; }
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc b/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc index e5a6bef..f318644 100644 --- a/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc +++ b/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
@@ -310,4 +310,44 @@ EXPECT_GT(10.2, feature3.GetRatioDistanceRootBottom()); } +TEST_F(AnchorElementMetricsTest, AnchorFeatureInIframeNonHttp) { + SimRequest main_resource("content://example.com/page1", "text/html"); + SimRequest iframe_resource("https://example.com/iframe.html", "text/html"); + SimRequest image_resource("https://example.com/cat.png", "image/png"); + + LoadURL("content://example.com/page1"); + + main_resource.Complete(String::Format( + R"HTML( + <body style='margin: 0px'> + <div style='height: %dpx;'></div> + <iframe id='iframe' src='https://example.com/iframe.html' + style='width: 300px; height: %dpx; + border-style: none; padding: 0px; margin: 0px;'></iframe> + <div style='height: %dpx;'></div> + </body>)HTML", + 2 * kViewportHeight, kViewportHeight / 2, 10 * kViewportHeight)); + + iframe_resource.Complete(String::Format( + R"HTML( + <body style='margin: 0px'> + <div style='height: %dpx;'></div> + <a id='anchor' href="https://example.com/page2">example</a> + <div style='height: %dpx;'></div> + </body>)HTML", + kViewportHeight / 2, 5 * kViewportHeight)); + + Element* iframe = GetDocument().getElementById("iframe"); + HTMLIFrameElement* iframe_element = ToHTMLIFrameElement(iframe); + Frame* sub = iframe_element->ContentFrame(); + LocalFrame* subframe = ToLocalFrame(sub); + + Element* anchor = subframe->GetDocument()->getElementById("anchor"); + HTMLAnchorElement* anchor_element = ToHTMLAnchorElement(anchor); + + EXPECT_FALSE( + AnchorElementMetrics::MaybeReportClickedMetricsOnClick(anchor_element) + .has_value()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc index d67b997..b0f63fb 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -23,7 +23,6 @@ #include "third_party/blink/renderer/platform/web_task_runner.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/time.h" -#include "third_party/skia/include/core/SkColorSpaceXform.h" #include "third_party/skia/include/core/SkSurface.h" namespace blink { @@ -234,42 +233,36 @@ skia_image = SkImage::MakeFromRaster(src_data_, nullptr, nullptr); } DCHECK(skia_image->colorSpace()); - skia_image = skia_image->makeColorSpace(blob_color_space); image_ = StaticBitmapImage::Create(skia_image); + image_ = image_->ConvertToColorSpace(blob_color_space, + skia_image->colorType()); + skia_image = image_->PaintImageForCurrentFrame().GetSkImage(); } - if (skia_image->peekPixels(&src_data_)) + if (skia_image->peekPixels(&src_data_)) { static_bitmap_image_loaded_ = true; - // If the source image is 8 bit per channel but the blob is requested in - // 16 bpc PNG, we need to ensure the color type of the pixmap is - // kRGBA_F16_SkColorType to kick in 16 bit encoding in SkPngEncoder. Since - // SkPixmap only holds a pointer to data, we need a helper data member here. - if (mime_type_ == kMimeTypePng && - encode_options_.pixelFormat() == kRGBA16ImagePixelFormatName && - src_data_.colorType() == kN32_SkColorType) { - size_t data_length = src_data_.width() * src_data_.height() * - SkColorTypeBytesPerPixel(kRGBA_F16_SkColorType); - png_16bit_data_helper_ = SkData::MakeUninitialized(data_length); - SkColorSpaceXform::ColorFormat src_format = - SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat; - if (kN32_SkColorType == kBGRA_8888_SkColorType) - src_format = SkColorSpaceXform::ColorFormat::kBGRA_8888_ColorFormat; - if (SkColorSpaceXform::Apply( - src_data_.colorSpace(), - SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat, - png_16bit_data_helper_->writable_data(), src_data_.colorSpace(), - src_format, src_data_.addr(), - src_data_.width() * src_data_.height(), - SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp)) { + // If the source image is 8 bit per channel but the blob is requested in + // 16 bpc PNG, we need to ensure the color type of the pixmap is + // kRGBA_F16_SkColorType to kick in 16 bit encoding in SkPngEncoder. Since + // SkPixmap only holds a pointer to data, we need a helper data member + // here. + if (mime_type_ == kMimeTypePng && + encode_options_.pixelFormat() == kRGBA16ImagePixelFormatName && + src_data_.colorType() == kN32_SkColorType) { + size_t data_length = src_data_.width() * src_data_.height() * + SkColorTypeBytesPerPixel(kRGBA_F16_SkColorType); + png_16bit_data_helper_ = SkData::MakeUninitialized(data_length); SkImageInfo info = SkImageInfo::Make( src_data_.width(), src_data_.height(), kRGBA_F16_SkColorType, src_data_.alphaType(), src_data_.info().refColorSpace()); - src_data_.reset(info, png_16bit_data_helper_->data(), - info.minRowBytes()); + SkPixmap src_data_f16(info, png_16bit_data_helper_->data(), + info.minRowBytes()); + src_data_.readPixels(src_data_f16); + src_data_ = src_data_f16; + skia_image = SkImage::MakeFromRaster(src_data_, nullptr, nullptr); + image_ = StaticBitmapImage::Create(skia_image); } - skia_image = SkImage::MakeFromRaster(src_data_, nullptr, nullptr); - image_ = StaticBitmapImage::Create(skia_image); } }
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc index 52892e8..bc915b3 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
@@ -265,8 +265,6 @@ // The maximum difference locally observed is 3. const unsigned uint8_color_tolerance = 5; const float f16_color_tolerance = 0.01; - // The maximum difference locally observed has the order of e^-6. - const float xyz_d50_color_space_component_tolerance = 0.001; for (auto color_space_param : color_space_params) { for (auto blob_mime_type : blob_mime_types) { @@ -306,8 +304,7 @@ bool compare_alpha = (blob_mime_type != "image/jpeg"); ASSERT_TRUE(ColorCorrectionTestUtils::MatchSkImages( ref_image, decoded_img, uint8_color_tolerance, - f16_color_tolerance, xyz_d50_color_space_component_tolerance, - compare_alpha)); + f16_color_tolerance, compare_alpha)); } } }
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc index e365835..47970055 100644 --- a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -30,7 +30,9 @@ #include "third_party/blink/renderer/core/html/forms/html_legend_element.h" #include "third_party/blink/renderer/core/html/html_collection.h" #include "third_party/blink/renderer/core/html_names.h" -#include "third_party/blink/renderer/core/layout/layout_fieldset.h" +#include "third_party/blink/renderer/core/layout/layout_block.h" +#include "third_party/blink/renderer/core/layout/layout_object_factory.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" namespace blink { @@ -115,8 +117,13 @@ return fieldset; } -LayoutObject* HTMLFieldSetElement::CreateLayoutObject(const ComputedStyle&) { - return new LayoutFieldset(this); +LayoutObject* HTMLFieldSetElement::CreateLayoutObject( + const ComputedStyle& style) { + return LayoutObjectFactory::CreateFieldset(*this, style); +} + +bool HTMLFieldSetElement::ShouldForceLegacyLayout() const { + return !RuntimeEnabledFeatures::LayoutNGFieldsetEnabled(); } HTMLLegendElement* HTMLFieldSetElement::Legend() const {
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.h b/third_party/blink/renderer/core/html/forms/html_field_set_element.h index 7e19e79..3895f75 100644 --- a/third_party/blink/renderer/core/html/forms/html_field_set_element.h +++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.h
@@ -48,7 +48,7 @@ bool IsEnumeratable() const override { return true; } bool SupportsFocus() const override; LayoutObject* CreateLayoutObject(const ComputedStyle&) override; - bool ShouldForceLegacyLayout() const final { return true; } + bool ShouldForceLegacyLayout() const final; const AtomicString& FormControlType() const override; bool RecalcWillValidate() const override { return false; } int tabIndex() const final;
diff --git a/third_party/blink/renderer/core/html/media/autoplay_policy.cc b/third_party/blink/renderer/core/html/media/autoplay_policy.cc index a3c2d7b..c06cabb4 100644 --- a/third_party/blink/renderer/core/html/media/autoplay_policy.cc +++ b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
@@ -122,7 +122,8 @@ return true; } - if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kAutoplay)) { + if (!frame->DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature::kAutoplay)) { return false; } } @@ -445,7 +446,8 @@ break; } - if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kAutoplay)) + if (!frame->DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature::kAutoplay)) break; } }
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc index ff797505..b931294 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -3805,20 +3805,16 @@ } } -unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const { +uint64_t HTMLMediaElement::webkitAudioDecodedByteCount() const { if (!GetWebMediaPlayer()) return 0; - // TODO(dtapuska): https://crbug.com/887593 Should the IDL change to be a - // unsigned long long? - return static_cast<unsigned>(GetWebMediaPlayer()->AudioDecodedByteCount()); + return GetWebMediaPlayer()->AudioDecodedByteCount(); } -unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const { +uint64_t HTMLMediaElement::webkitVideoDecodedByteCount() const { if (!GetWebMediaPlayer()) return 0; - // TODO(dtapuska): https://crbug.com/887593 Should the IDL change to be a - // unsigned long long? - return static_cast<unsigned>(GetWebMediaPlayer()->VideoDecodedByteCount()); + return GetWebMediaPlayer()->VideoDecodedByteCount(); } bool HTMLMediaElement::IsURLAttribute(const Attribute& attribute) const {
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.h b/third_party/blink/renderer/core/html/media/html_media_element.h index bb753a53..5bd47e1d 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.h +++ b/third_party/blink/renderer/core/html/media/html_media_element.h
@@ -204,8 +204,8 @@ void FlingingStopped(); // statistics - unsigned webkitAudioDecodedByteCount() const; - unsigned webkitVideoDecodedByteCount() const; + uint64_t webkitAudioDecodedByteCount() const; + uint64_t webkitVideoDecodedByteCount() const; // media source extensions void CloseMediaSource();
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.idl b/third_party/blink/renderer/core/html/media/html_media_element.idl index 61972ef..3fa256d76 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.idl +++ b/third_party/blink/renderer/core/html/media/html_media_element.idl
@@ -92,6 +92,6 @@ // Non-standard APIs // The number of bytes consumed by the media decoder. - [MeasureAs=PrefixedAudioDecodedByteCount] readonly attribute unsigned long webkitAudioDecodedByteCount; - [MeasureAs=PrefixedVideoDecodedByteCount] readonly attribute unsigned long webkitVideoDecodedByteCount; + [MeasureAs=PrefixedAudioDecodedByteCount] readonly attribute unsigned long long webkitAudioDecodedByteCount; + [MeasureAs=PrefixedVideoDecodedByteCount] readonly attribute unsigned long long webkitVideoDecodedByteCount; };
diff --git a/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc b/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc index 0bf662c..d79dddb 100644 --- a/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc +++ b/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
@@ -29,8 +29,10 @@ } bool IsUnsizedMediaEnabled(const Document& document) { - if (auto* frame = document.GetFrame()) - return frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kUnsizedMedia); + if (auto* frame = document.GetFrame()) { + return frame->DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature::kUnsizedMedia); + } // Unsized media is by default enabled every where, so when the frame is not // available return default policy (true). return true; @@ -75,7 +77,7 @@ const ComputedStyle& style = layout_object->StyleRef(); if (!style.LogicalWidth().IsSpecified() && !style.LogicalHeight().IsSpecified() && layout_object->GetFrame()) { - layout_object->GetFrame()->ReportFeaturePolicyViolation( + layout_object->GetFrame()->DeprecatedReportFeaturePolicyViolation( mojom::FeaturePolicyFeature::kUnsizedMedia); } }
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc index 2627856..29fbfa1 100644 --- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc +++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
@@ -312,47 +312,6 @@ } } -enum class ColorSpaceConversion : uint8_t { - NONE = 0, - DEFAULT_COLOR_CORRECTED = 1, - PRESERVE = 2, - SRGB = 3, - LINEAR_RGB = 4, - P3 = 5, - REC2020 = 6, - - LAST = REC2020 -}; - -static ImageBitmapOptions PrepareBitmapOptions( - const ColorSpaceConversion& color_space_conversion) { - // Set the color space conversion in ImageBitmapOptions - ImageBitmapOptions options; - static const Vector<String> kConversions = { - "none", "default", "preserve", "srgb", "linear-rgb", "p3", "rec2020"}; - options.setColorSpaceConversion( - kConversions[static_cast<uint8_t>(color_space_conversion)]); - return options; -} - -static sk_sp<SkColorSpace> GetColorSpaceForColorSpaceConversion( - ColorSpaceConversion conversion) { - sk_sp<SkColorSpace> color_space = nullptr; - if (conversion == ColorSpaceConversion::DEFAULT_COLOR_CORRECTED || - conversion == ColorSpaceConversion::SRGB) { - color_space = SkColorSpace::MakeSRGB(); - } else if (conversion == ColorSpaceConversion::LINEAR_RGB) { - color_space = SkColorSpace::MakeSRGBLinear(); - } else if (conversion == ColorSpaceConversion::P3) { - color_space = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kDCIP3_D65_Gamut); - } else if (conversion == ColorSpaceConversion::REC2020) { - color_space = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kRec2020_Gamut); - } - return color_space; -} - TEST_F(ImageBitmapTest, ImageBitmapColorSpaceConversionHTMLImageElement) { HTMLImageElement* image_element = HTMLImageElement::Create(*Document::CreateForTest()); @@ -377,13 +336,13 @@ base::Optional<IntRect> crop_rect = IntRect(0, 0, source_image->width(), source_image->height()); - for (uint8_t i = - static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED); - i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) { - ColorSpaceConversion color_space_conversion = - static_cast<ColorSpaceConversion>(i); - ImageBitmapOptions options = - PrepareBitmapOptions(color_space_conversion); + for (int conversion_iterator = kColorSpaceConversion_Default; + conversion_iterator <= kColorSpaceConversion_Last; + conversion_iterator++) { + ImageBitmapOptions options; + options.setColorSpaceConversion( + ColorCorrectionTestUtils::ColorSpaceConversionToString( + static_cast<ColorSpaceConversion>(conversion_iterator))); ImageBitmap* image_bitmap = ImageBitmap::Create( image_element, crop_rect, &(image_element->GetDocument()), options); ASSERT_TRUE(image_bitmap); @@ -393,7 +352,7 @@ converted_image->peekPixels(&converted_pixmap); unsigned num_pixels = source_image->width() * source_image->height(); - if (color_space_conversion == ColorSpaceConversion::PRESERVE) { + if (conversion_iterator == kColorSpaceConversion_Preserve) { EXPECT_TRUE( SkColorSpace::Equals(colorspin.get(), converted_image->colorSpace())); ColorCorrectionTestUtils::CompareColorCorrectedPixels( @@ -401,7 +360,8 @@ kPixelFormat_8888, kAlphaMultiplied, kUnpremulRoundTripTolerance); } else { sk_sp<SkColorSpace> color_space = - GetColorSpaceForColorSpaceConversion(color_space_conversion); + ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace( + static_cast<ColorSpaceConversion>(conversion_iterator)); EXPECT_TRUE(SkColorSpace::Equals(color_space.get(), converted_image->colorSpace())); @@ -412,8 +372,7 @@ expected_image_info.makeColorType(kRGBA_F16_SkColorType); } SkBitmap expected_bitmap; - EXPECT_TRUE(expected_bitmap.tryAllocPixels( - expected_image_info, expected_image_info.minRowBytes())); + EXPECT_TRUE(expected_bitmap.tryAllocPixels(expected_image_info)); source_image->readPixels(expected_bitmap.pixmap(), 0, 0); ColorCorrectionTestUtils::CompareColorCorrectedPixels( @@ -439,18 +398,20 @@ base::Optional<IntRect> crop_rect = IntRect(0, 0, source_image->width(), source_image->height()); - ImageBitmapOptions options = - PrepareBitmapOptions(ColorSpaceConversion::PRESERVE); + ImageBitmapOptions options; + options.setColorSpaceConversion( + ColorCorrectionTestUtils::ColorSpaceConversionToString( + kColorSpaceConversion_Preserve)); ImageBitmap* source_image_bitmap = ImageBitmap::Create( StaticBitmapImage::Create(source_image), crop_rect, options); ASSERT_TRUE(source_image_bitmap); - for (uint8_t i = - static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED); - i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) { - ColorSpaceConversion color_space_conversion = - static_cast<ColorSpaceConversion>(i); - options = PrepareBitmapOptions(color_space_conversion); + for (int conversion_iterator = kColorSpaceConversion_Default; + conversion_iterator <= kColorSpaceConversion_Last; + conversion_iterator++) { + options.setColorSpaceConversion( + ColorCorrectionTestUtils::ColorSpaceConversionToString( + static_cast<ColorSpaceConversion>(conversion_iterator))); ImageBitmap* image_bitmap = ImageBitmap::Create(source_image_bitmap, crop_rect, options); ASSERT_TRUE(image_bitmap); @@ -460,7 +421,7 @@ converted_image->peekPixels(&converted_pixmap); unsigned num_pixels = source_image->width() * source_image->height(); - if (color_space_conversion == ColorSpaceConversion::PRESERVE) { + if (conversion_iterator == kColorSpaceConversion_Preserve) { EXPECT_TRUE( SkColorSpace::Equals(colorspin.get(), converted_image->colorSpace())); ColorCorrectionTestUtils::CompareColorCorrectedPixels( @@ -468,7 +429,8 @@ kPixelFormat_8888, kAlphaMultiplied, kUnpremulRoundTripTolerance); } else { sk_sp<SkColorSpace> color_space = - GetColorSpaceForColorSpaceConversion(color_space_conversion); + ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace( + static_cast<ColorSpaceConversion>(conversion_iterator)); EXPECT_TRUE(SkColorSpace::Equals(color_space.get(), converted_image->colorSpace())); @@ -479,8 +441,7 @@ expected_image_info.makeColorType(kRGBA_F16_SkColorType); } SkBitmap expected_bitmap; - EXPECT_TRUE(expected_bitmap.tryAllocPixels( - expected_image_info, expected_image_info.minRowBytes())); + EXPECT_TRUE(expected_bitmap.tryAllocPixels(expected_image_info)); source_image->readPixels(expected_bitmap.pixmap(), 0, 0); ColorCorrectionTestUtils::CompareColorCorrectedPixels( @@ -507,13 +468,13 @@ base::Optional<IntRect> crop_rect = IntRect(0, 0, source_image->width(), source_image->height()); - for (uint8_t i = - static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED); - i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) { - ColorSpaceConversion color_space_conversion = - static_cast<ColorSpaceConversion>(i); - ImageBitmapOptions options = - PrepareBitmapOptions(color_space_conversion); + for (int conversion_iterator = kColorSpaceConversion_Default; + conversion_iterator <= kColorSpaceConversion_Last; + conversion_iterator++) { + ImageBitmapOptions options; + options.setColorSpaceConversion( + ColorCorrectionTestUtils::ColorSpaceConversionToString( + static_cast<ColorSpaceConversion>(conversion_iterator))); ImageBitmap* image_bitmap = ImageBitmap::Create( StaticBitmapImage::Create(source_image), crop_rect, options); ASSERT_TRUE(image_bitmap); @@ -523,7 +484,7 @@ converted_image->peekPixels(&converted_pixmap); unsigned num_pixels = source_image->width() * source_image->height(); - if (color_space_conversion == ColorSpaceConversion::PRESERVE) { + if (conversion_iterator == kColorSpaceConversion_Preserve) { EXPECT_TRUE( SkColorSpace::Equals(colorspin.get(), converted_image->colorSpace())); ColorCorrectionTestUtils::CompareColorCorrectedPixels( @@ -531,7 +492,8 @@ kPixelFormat_8888, kAlphaMultiplied, kUnpremulRoundTripTolerance); } else { sk_sp<SkColorSpace> color_space = - GetColorSpaceForColorSpaceConversion(color_space_conversion); + ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace( + static_cast<ColorSpaceConversion>(conversion_iterator)); EXPECT_TRUE(SkColorSpace::Equals(color_space.get(), converted_image->colorSpace())); @@ -542,8 +504,7 @@ expected_image_info.makeColorType(kRGBA_F16_SkColorType); } SkBitmap expected_bitmap; - EXPECT_TRUE(expected_bitmap.tryAllocPixels( - expected_image_info, expected_image_info.minRowBytes())); + EXPECT_TRUE(expected_bitmap.tryAllocPixels(expected_image_info)); source_image->readPixels(expected_bitmap.pixmap(), 0, 0); ColorCorrectionTestUtils::CompareColorCorrectedPixels( @@ -565,21 +526,20 @@ SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, SkColorSpace::MakeSRGB()); SkBitmap source_bitmap; - EXPECT_TRUE( - source_bitmap.tryAllocPixels(image_info, image_info.minRowBytes())); + EXPECT_TRUE(source_bitmap.tryAllocPixels(image_info)); SkPixmap source_pixmap; source_pixmap = source_bitmap.pixmap(); memcpy(source_pixmap.writable_addr(), image_data->BufferBase()->Data(), 4); base::Optional<IntRect> crop_rect = IntRect(0, 0, 1, 1); - for (uint8_t i = - static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED); - i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) { - ColorSpaceConversion color_space_conversion = - static_cast<ColorSpaceConversion>(i); - ImageBitmapOptions options = - PrepareBitmapOptions(color_space_conversion); + for (int conversion_iterator = kColorSpaceConversion_Default; + conversion_iterator <= kColorSpaceConversion_Last; + conversion_iterator++) { + ImageBitmapOptions options; + options.setColorSpaceConversion( + ColorCorrectionTestUtils::ColorSpaceConversionToString( + static_cast<ColorSpaceConversion>(conversion_iterator))); ImageBitmap* image_bitmap = ImageBitmap::Create(image_data, crop_rect, options); ASSERT_TRUE(image_bitmap); @@ -589,13 +549,12 @@ converted_image->peekPixels(&converted_pixmap); unsigned num_pixels = converted_image->width() * converted_image->height(); - if (color_space_conversion == ColorSpaceConversion::PRESERVE) { + if (conversion_iterator == kColorSpaceConversion_Preserve) { // crbug.com/886999 // EXPECT_TRUE(SkColorSpace::Equals(SkColorSpace::MakeSRGB().get(), // converted_image->colorSpace())); SkBitmap expected_bitmap; - EXPECT_TRUE(expected_bitmap.tryAllocPixels( - converted_pixmap.info(), converted_pixmap.info().minRowBytes())); + EXPECT_TRUE(expected_bitmap.tryAllocPixels(converted_pixmap.info())); source_pixmap.readPixels(expected_bitmap.pixmap(), 0, 0); ColorCorrectionTestUtils::CompareColorCorrectedPixels( @@ -603,13 +562,13 @@ kPixelFormat_8888, kAlphaMultiplied, kUnpremulRoundTripTolerance); } else { sk_sp<SkColorSpace> color_space = - GetColorSpaceForColorSpaceConversion(color_space_conversion); + ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace( + static_cast<ColorSpaceConversion>(conversion_iterator)); // crbug.com/886999 // EXPECT_TRUE(SkColorSpace::Equals(color_space.get(), // converted_image->colorSpace())); SkBitmap expected_bitmap; - EXPECT_TRUE(expected_bitmap.tryAllocPixels( - converted_pixmap.info(), converted_pixmap.info().minRowBytes())); + EXPECT_TRUE(expected_bitmap.tryAllocPixels(converted_pixmap.info())); source_pixmap.readPixels(expected_bitmap.pixmap(), 0, 0); ColorCorrectionTestUtils::CompareColorCorrectedPixels( @@ -699,12 +658,13 @@ ImageData* image_data = ImageData::CreateForTest(IntSize(v8::TypedArray::kMaxLength / 16, 1)); DCHECK(image_data); - ImageBitmapOptions options = - PrepareBitmapOptions(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED); + ImageBitmapOptions options; + options.setColorSpaceConversion( + ColorCorrectionTestUtils::ColorSpaceConversionToString( + kColorSpaceConversion_Default)); ImageBitmap* image_bitmap = ImageBitmap::Create( image_data, IntRect(IntPoint(0, 0), image_data->Size()), options); DCHECK(image_bitmap); } -#undef MAYBE_ImageBitmapColorSpaceConversionHTMLImageElement } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/BUILD.gn b/third_party/blink/renderer/core/layout/BUILD.gn index cdd86e7..c3229c1 100644 --- a/third_party/blink/renderer/core/layout/BUILD.gn +++ b/third_party/blink/renderer/core/layout/BUILD.gn
@@ -377,6 +377,8 @@ "ng/inline/ng_text_fragment_builder.h", "ng/layout_ng_block_flow.cc", "ng/layout_ng_block_flow.h", + "ng/layout_ng_fieldset.cc", + "ng/layout_ng_fieldset.h", "ng/layout_ng_flexible_box.cc", "ng/layout_ng_flexible_box.h", "ng/layout_ng_mixin.cc", @@ -419,6 +421,8 @@ "ng/ng_constraint_space_builder.h", "ng/ng_container_fragment_builder.cc", "ng/ng_container_fragment_builder.h", + "ng/ng_fieldset_layout_algorithm.cc", + "ng/ng_fieldset_layout_algorithm.h", "ng/ng_flex_layout_algorithm.cc", "ng/ng_flex_layout_algorithm.h", "ng/ng_floats_utils.cc",
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 3322348e5..a978ab44 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -5204,16 +5204,6 @@ return ToLayoutCustom(Parent())->Phase() == LayoutCustomPhase::kCustom; } -bool LayoutBox::IsRenderedLegend() const { - if (!IsHTMLLegendElement(GetNode())) - return false; - if (IsFloatingOrOutOfFlowPositioned()) - return false; - const auto* parent = Parent(); - return parent && parent->IsFieldset() && - ToLayoutFieldset(parent)->FindInFlowLegend() == this; -} - void LayoutBox::AddVisualEffectOverflow() { if (!StyleRef().HasVisualOverflowingEffect()) return;
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h index 41ac33b..7c3658c 100644 --- a/third_party/blink/renderer/core/layout/layout_box.h +++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1213,11 +1213,6 @@ bool IsGridItem() const { return Parent() && Parent()->IsLayoutGrid(); } - // Return true if this is the "rendered legend" of a fieldset. They get - // special treatment, in that they establish a new formatting context, and - // shrink to fit if no logical width is specified. - bool IsRenderedLegend() const; - LayoutUnit LineHeight( bool first_line, LineDirectionMode,
diff --git a/third_party/blink/renderer/core/layout/layout_fieldset.cc b/third_party/blink/renderer/core/layout/layout_fieldset.cc index 2d661fb..d4089429 100644 --- a/third_party/blink/renderer/core/layout/layout_fieldset.cc +++ b/third_party/blink/renderer/core/layout/layout_fieldset.cc
@@ -27,6 +27,7 @@ #include "third_party/blink/renderer/core/html/forms/html_legend_element.h" #include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/paint/fieldset_painter.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" namespace blink { @@ -136,8 +137,19 @@ return legend; } -LayoutBox* LayoutFieldset::FindInFlowLegend() const { - for (LayoutObject* legend = FirstChild(); legend; +LayoutBox* LayoutFieldset::FindInFlowLegend(const LayoutBlock& fieldset) { + DCHECK(fieldset.IsFieldset() || fieldset.IsLayoutNGFieldset()); + const LayoutBlock* parent = &fieldset; + if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled()) { + if (fieldset.IsLayoutNGFieldset()) { + // If there is a rendered legend, it will be found inside the anonymous + // fieldset wrapper. + parent = ToLayoutBlock(fieldset.FirstChild()); + if (!parent) + return nullptr; + } + } + for (LayoutObject* legend = parent->FirstChild(); legend; legend = legend->NextSibling()) { if (legend->IsFloatingOrOutOfFlowPositioned()) continue;
diff --git a/third_party/blink/renderer/core/layout/layout_fieldset.h b/third_party/blink/renderer/core/layout/layout_fieldset.h index 4d38cd0..f0218778 100644 --- a/third_party/blink/renderer/core/layout/layout_fieldset.h +++ b/third_party/blink/renderer/core/layout/layout_fieldset.h
@@ -32,7 +32,8 @@ public: explicit LayoutFieldset(Element*); - LayoutBox* FindInFlowLegend() const; + static LayoutBox* FindInFlowLegend(const LayoutBlock& fieldset); + LayoutBox* FindInFlowLegend() const { return FindInFlowLegend(*this); } const char* GetName() const override { return "LayoutFieldset"; }
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc index a74fcf6..710f7f9 100644 --- a/third_party/blink/renderer/core/layout/layout_image.cc +++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -58,7 +58,7 @@ // Invert the image if the document does not have the 'legacy-image-formats' // feature enabled, and the image is not one of the allowed formats. if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() && - !frame.IsFeatureEnabled( + !frame.DeprecatedIsFeatureEnabled( mojom::FeaturePolicyFeature::kLegacyImageFormats)) { if (!new_image->IsAcceptableContentType()) { return true; @@ -67,7 +67,8 @@ // Invert the image if the document does not have the image-compression' // feature enabled and the image is not sufficiently-well-compressed. if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() && - !frame.IsFeatureEnabled(mojom::FeaturePolicyFeature::kImageCompression)) { + !frame.DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature::kImageCompression)) { if (!new_image->IsAcceptableCompressionRatio()) return true; } @@ -79,7 +80,8 @@ LayoutImage* layout_image) { DCHECK(new_image); if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() || - frame.IsFeatureEnabled(mojom::FeaturePolicyFeature::kMaxDownscalingImage)) + frame.DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature::kMaxDownscalingImage)) return false; if (auto* image = new_image->GetImage()) { // Invert the image if the image's size is more than 2 times bigger than the
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index 8df9cbb2..f3bff39 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -63,6 +63,7 @@ #include "third_party/blink/renderer/core/layout/layout_counter.h" #include "third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h" #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" +#include "third_party/blink/renderer/core/layout/layout_fieldset.h" #include "third_party/blink/renderer/core/layout/layout_flexible_box.h" #include "third_party/blink/renderer/core/layout/layout_flow_thread.h" #include "third_party/blink/renderer/core/layout/layout_grid.h" @@ -485,6 +486,23 @@ return false; } +bool LayoutObject::IsRenderedLegend() const { + if (!IsBox() || !IsHTMLLegendElement(GetNode())) + return false; + if (IsFloatingOrOutOfFlowPositioned()) + return false; + const auto* parent = Parent(); + if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled()) { + // If there is a rendered legend, it will be found inside the anonymous + // fieldset wrapper. + if (parent->IsAnonymous() && parent->Parent()->IsLayoutNGFieldset()) + parent = parent->Parent(); + } + return parent && parent->IsLayoutBlock() && + IsHTMLFieldSetElement(parent->GetNode()) && + LayoutFieldset::FindInFlowLegend(*ToLayoutBlock(parent)) == this; +} + LayoutObject* LayoutObject::NextInPreOrderAfterChildren() const { LayoutObject* o = NextSibling(); if (!o) {
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index e1eab26..0e7bece 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -554,6 +554,7 @@ return IsOfType(kLayoutObjectEmbeddedObject); } bool IsFieldset() const { return IsOfType(kLayoutObjectFieldset); } + bool IsLayoutNGFieldset() const { return IsOfType(kLayoutObjectNGFieldset); } bool IsFileUploadControl() const { return IsOfType(kLayoutObjectFileUploadControl); } @@ -949,6 +950,11 @@ return bitfields_.IsEffectiveRootScroller(); } + // Return true if this is the "rendered legend" of a fieldset. They get + // special treatment, in that they establish a new formatting context, and + // shrink to fit if no logical width is specified. + bool IsRenderedLegend() const; + // The pseudo element style can be cached or uncached. Use the cached method // if the pseudo element doesn't respect any pseudo classes (and therefore // has no concept of changing state). @@ -2108,6 +2114,7 @@ kLayoutObjectMedia, kLayoutObjectMenuList, kLayoutObjectNGBlockFlow, + kLayoutObjectNGFieldset, kLayoutObjectNGFlexibleBox, kLayoutObjectNGMixin, kLayoutObjectNGListItem,
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.cc b/third_party/blink/renderer/core/layout/layout_object_factory.cc index 2450739..064ed12 100644 --- a/third_party/blink/renderer/core/layout/layout_object_factory.cc +++ b/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -6,12 +6,14 @@ #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/layout/layout_block_flow.h" +#include "third_party/blink/renderer/core/layout/layout_fieldset.h" #include "third_party/blink/renderer/core/layout/layout_flexible_box.h" #include "third_party/blink/renderer/core/layout/layout_list_item.h" #include "third_party/blink/renderer/core/layout/layout_table_caption.h" #include "third_party/blink/renderer/core/layout/layout_table_cell.h" #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" +#include "third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h" @@ -92,4 +94,14 @@ return new LayoutTableCell(element); } +LayoutBlock* LayoutObjectFactory::CreateFieldset(Node& node, + const ComputedStyle& style) { + Element* element = GetElementForLayoutObject(node); + if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled() && + ShouldUseNewLayout(node.GetDocument(), style)) { + return new LayoutNGFieldset(element); + } + return new LayoutFieldset(element); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.h b/third_party/blink/renderer/core/layout/layout_object_factory.h index 5e99c9a..0a22e84 100644 --- a/third_party/blink/renderer/core/layout/layout_object_factory.h +++ b/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -5,15 +5,16 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_OBJECT_FACTORY_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_OBJECT_FACTORY_H_ -#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" namespace blink { +class ComputedStyle; class LayoutBlock; class LayoutBlockFlow; class LayoutTableCaption; class LayoutTableCell; +class Node; // Helper class for creation of certain LayoutObject-derived objects that may // need to be of different types, depending on whether or not LayoutNG is to be @@ -32,6 +33,7 @@ static LayoutBlockFlow* CreateListItem(Node&, const ComputedStyle&); static LayoutTableCaption* CreateTableCaption(Node&, const ComputedStyle&); static LayoutTableCell* CreateTableCell(Node&, const ComputedStyle&); + static LayoutBlock* CreateFieldset(Node&, const ComputedStyle&); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc index f90bd1a..0f40644 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -743,27 +743,24 @@ Vector<NGPositionedFloat> positioned_floats; NGUnpositionedFloatVector unpositioned_floats; - scoped_refptr<NGInlineBreakToken> break_token; NGExclusionSpace empty_exclusion_space; NGLineLayoutOpportunity line_opportunity(available_inline_size); LayoutUnit result; LayoutUnit previous_floats_inline_size = input.float_left_inline_size + input.float_right_inline_size; DCHECK_GE(previous_floats_inline_size, 0); - while (!break_token || !break_token->IsFinished()) { + NGLineBreaker line_breaker( + node, mode, space, &positioned_floats, &unpositioned_floats, + nullptr /* container_builder */, &empty_exclusion_space, 0u, + line_opportunity, nullptr /* break_token */); + do { unpositioned_floats.clear(); NGLineInfo line_info; - NGLineBreaker line_breaker( - node, mode, space, &positioned_floats, &unpositioned_floats, - nullptr /* container_builder */, &empty_exclusion_space, 0u, - line_opportunity, break_token.get()); line_breaker.NextLine(&line_info); - if (line_info.Results().IsEmpty()) break; - break_token = line_breaker.CreateBreakToken(line_info, nullptr); LayoutUnit inline_size = line_info.Width(); DCHECK_EQ(inline_size, line_info.ComputeWidth().ClampNegativeToZero()); @@ -829,7 +826,7 @@ // NOTE: floats_inline_size will be zero for the min-content calculation, // and will just take the inline size of the un-breakable line. result = std::max(result, inline_size + floats_inline_size); - } + } while (!line_breaker.IsFinished()); return result; }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc index 4f5c87e..9d1e8d81 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -81,7 +81,7 @@ item_index_ = break_token->ItemIndex(); offset_ = break_token->TextOffset(); break_iterator_.SetStartOffset(offset_); - previous_line_had_forced_break_ = break_token->IsForcedBreak(); + is_after_forced_break_ = break_token->IsForcedBreak(); items_data_.AssertOffset(item_index_, offset_); ignore_floats_ = break_token->IgnoreFloats(); } @@ -147,6 +147,14 @@ // avoid rare code path. DCHECK(item_results_->IsEmpty()); + if (item_index_) { + // We're past the first line + previous_line_had_forced_break_ = is_after_forced_break_; + is_after_forced_break_ = false; + is_first_formatted_line_ = false; + use_first_line_style_ = false; + } + line_info_->SetStartOffset(offset_); line_info_->SetLineStyle(node_, items_data_, constraint_space_, is_first_formatted_line_, use_first_line_style_,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h index 238da9b..8961787 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -51,6 +51,8 @@ // the line. void NextLine(NGLineInfo*); + bool IsFinished() const { return item_index_ >= Items().size(); } + // Create an NGInlineBreakToken for the last line returned by NextLine(). scoped_refptr<NGInlineBreakToken> CreateBreakToken( const NGLineInfo&,
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc new file mode 100644 index 0000000..862f6ad --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.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 "third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h" + +#include "third_party/blink/renderer/core/layout/layout_object_factory.h" + +namespace blink { + +LayoutNGFieldset::LayoutNGFieldset(Element* element) + : LayoutNGBlockFlow(element) { + SetChildrenInline(false); +} + +void LayoutNGFieldset::AddChild(LayoutObject* new_child, + LayoutObject* before_child) { + LayoutBlock* fieldset_content = ToLayoutBlock(FirstChild()); + if (!fieldset_content) { + // We wrap everything inside an anonymous child, which will take care of the + // fieldset contents. This parent will only be responsible for the fieldset + // border and the rendered legend, if there is one. Everything else will be + // done by the anonymous child. This includes display type, multicol, + // scrollbars, and even padding. Note that the rendered legend (if any) will + // also be a child of the anonymous object, although it'd be more natural to + // have it as the first child of this object. The reason is that our layout + // object tree builder cannot handle such discrepancies between DOM tree and + // layout tree. Inserting anonymous wrappers is one thing (that is + // supported). Removing it from its actual DOM siblings and putting it + // elsewhere, on the other hand, does not work well. + + scoped_refptr<ComputedStyle> new_style = + ComputedStyle::CreateAnonymousStyleWithDisplay(StyleRef(), + EDisplay::kFlowRoot); + new_style->SetOverflowX(StyleRef().OverflowX()); + new_style->SetOverflowY(StyleRef().OverflowY()); + + new_style->SetPaddingTop(StyleRef().PaddingTop()); + new_style->SetPaddingRight(StyleRef().PaddingRight()); + new_style->SetPaddingBottom(StyleRef().PaddingBottom()); + new_style->SetPaddingLeft(StyleRef().PaddingLeft()); + + if (StyleRef().SpecifiesColumns()) { + new_style->SetColumnCount(StyleRef().ColumnCount()); + new_style->SetColumnWidth(StyleRef().ColumnWidth()); + } else { + new_style->SetHasAutoColumnCount(); + new_style->SetHasAutoColumnWidth(); + } + new_style->SetColumnGap(StyleRef().ColumnGap()); + new_style->SetColumnFill(StyleRef().GetColumnFill()); + + new_style->SetFlexDirection(StyleRef().FlexDirection()); + new_style->SetJustifyContent(StyleRef().JustifyContent()); + + // TODO(mstensho): Inherit all properties listed here: + // https://html.spec.whatwg.org/multipage/rendering.html#the-fieldset-and-legend-elements + + // We need to enter legacy layout from this point on, if ... + if (!RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled() && + new_style->SpecifiesColumns()) + new_style->SetForceLegacyLayout(true); + + fieldset_content = LayoutBlock::CreateAnonymousWithParentAndDisplay( + this, new_style->Display()); + fieldset_content->SetStyle(std::move(new_style)); + LayoutBox::AddChild(fieldset_content); + } + fieldset_content->AddChild(new_child, before_child); +} + +// TODO(mstensho): Should probably remove the anonymous child if it becomes +// childless. While an empty anonymous child should have no effect, it doesn't +// seem right to leave it around. + +bool LayoutNGFieldset::IsOfType(LayoutObjectType type) const { + return type == kLayoutObjectNGFieldset || LayoutNGBlockFlow::IsOfType(type); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h new file mode 100644 index 0000000..e549fc8 --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h
@@ -0,0 +1,30 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FIELDSET_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FIELDSET_H_ + +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" + +namespace blink { + +class CORE_EXPORT LayoutNGFieldset final : public LayoutNGBlockFlow { + public: + explicit LayoutNGFieldset(Element*); + + const char* GetName() const override { return "LayoutNGFieldset"; } + + void AddChild(LayoutObject* new_child, + LayoutObject* before_child = nullptr) override; + + protected: + bool IsOfType(LayoutObjectType) const override; +}; + +DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGFieldset, IsLayoutNGFieldset()); + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FIELDSET_H_
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc index 176a4413..a9a72e99 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -249,19 +249,20 @@ template <typename Base> void LayoutNGMixin<Base>::SetPaintFragment( - NGPaintFragment* last_paint_fragment, - scoped_refptr<NGPaintFragment> paint_fragment) { - if (paint_fragment) { + scoped_refptr<const NGPhysicalFragment> fragment, + NGPhysicalOffset offset, + scoped_refptr<NGPaintFragment>* current) { + DCHECK(current); + + if (fragment) { // When paint fragment is replaced, the subtree needs paint invalidation to // re-compute paint properties in NGPaintFragment. Base::SetSubtreeShouldDoFullPaintInvalidation(); } - if (last_paint_fragment) { - last_paint_fragment->SetNext(std::move(paint_fragment)); - } else { - paint_fragment_ = std::move(paint_fragment); - } + *current = fragment ? NGPaintFragment::Create(std::move(fragment), offset, + std::move(*current)) + : nullptr; } template <typename Base> @@ -272,19 +273,9 @@ // TODO(kojii): There are cases where the first call has break_token. // Investigate why and handle appropriately. // DCHECK(!break_token || paint_fragment_); - NGPaintFragment* last_paint_fragment = nullptr; - if (break_token && paint_fragment_) { - last_paint_fragment = paint_fragment_->Last(*break_token); - // TODO(kojii): Sometimes an unknown break_token is given. Need to - // investigate why, and handle appropriately. For now, just keep it to avoid - // crashes and use-after-free. - if (!last_paint_fragment) - last_paint_fragment = paint_fragment_->Last(); - DCHECK(last_paint_fragment); - } - SetPaintFragment( - last_paint_fragment, - fragment ? NGPaintFragment::Create(fragment, offset) : nullptr); + scoped_refptr<NGPaintFragment>* current = + NGPaintFragment::Find(&paint_fragment_, break_token); + SetPaintFragment(std::move(fragment), offset, current); } template <typename Base> @@ -296,29 +287,12 @@ // TODO(kojii): There are cases where the first call has break_token. // Investigate why and handle appropriately. // DCHECK(!break_token || paint_fragment_); - NGPaintFragment* paint_fragment = nullptr; - NGPaintFragment* last_paint_fragment = nullptr; - if (!break_token) { - paint_fragment = paint_fragment_.get(); - } else if (paint_fragment_) { - last_paint_fragment = paint_fragment_->Last(*break_token); - // TODO(kojii): Sometimes an unknown break_token is given. Need to - // investigate why, and handle appropriately. For now, just keep it to avoid - // crashes and use-after-free. - if (!last_paint_fragment) - last_paint_fragment = paint_fragment_->Last(); - DCHECK(last_paint_fragment); - paint_fragment = last_paint_fragment->Next(); - } - - if (!paint_fragment) { - SetPaintFragment( - last_paint_fragment, - NGPaintFragment::Create(std::move(fragment), fragment_offset)); - return; - } - - paint_fragment->UpdatePhysicalFragmentFromCachedLayoutResult(fragment); + scoped_refptr<NGPaintFragment>* current = + NGPaintFragment::Find(&paint_fragment_, break_token); + DCHECK(current); + DCHECK(*current); + (*current)->UpdateFromCachedLayoutResult(std::move(fragment), + fragment_offset); } template <typename Base>
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h index bd059b88..3673e5c 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -88,8 +88,9 @@ private: void AddScrollingOverflowFromChildren(); - void SetPaintFragment(NGPaintFragment* last_paint_fragment, - scoped_refptr<NGPaintFragment>); + void SetPaintFragment(scoped_refptr<const NGPhysicalFragment> fragment, + NGPhysicalOffset offset, + scoped_refptr<NGPaintFragment>* current); protected: void AddOutlineRects(Vector<LayoutRect>&,
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc index 04e53b0..12689da 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
@@ -6,8 +6,10 @@ #include "third_party/blink/renderer/core/layout/layout_analyzer.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h" +#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" +#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" @@ -16,6 +18,39 @@ LayoutNGTableCaption::LayoutNGTableCaption(Element* element) : LayoutNGMixin<LayoutTableCaption>(element) {} +void LayoutNGTableCaption::CalculateAndSetMargins( + const NGConstraintSpace& constraint_space, + const NGPhysicalFragment& physical_fragment) { + const ComputedStyle& containing_block_style = ContainingBlock()->StyleRef(); + + NGBoxFragment box_fragment(containing_block_style.GetWritingMode(), + containing_block_style.Direction(), + ToNGPhysicalBoxFragment(physical_fragment)); + + NGPhysicalBoxStrut physical_margins = + ComputePhysicalMargins(constraint_space, StyleRef()); + + NGBoxStrut logical_margins = + physical_margins.ConvertToLogical(containing_block_style.GetWritingMode(), + containing_block_style.Direction()); + + LayoutUnit caption_inline_size_in_cb_writing_mode = box_fragment.InlineSize(); + + LayoutUnit available_inline_size_in_cb_writing_mode = + constraint_space.AvailableSize() + .ConvertToPhysical(constraint_space.GetWritingMode()) + .ConvertToLogical(containing_block_style.GetWritingMode()) + .inline_size; + + ResolveInlineMargins(StyleRef(), containing_block_style, + available_inline_size_in_cb_writing_mode, + caption_inline_size_in_cb_writing_mode, + &logical_margins); + SetMargin( + logical_margins.ConvertToPhysical(containing_block_style.GetWritingMode(), + containing_block_style.Direction())); +} + void LayoutNGTableCaption::UpdateBlockLayout(bool relayout_children) { LayoutAnalyzer::BlockScope analyzer(*this); @@ -27,6 +62,8 @@ scoped_refptr<NGLayoutResult> result = NGBlockNode(this).Layout(constraint_space); + CalculateAndSetMargins(constraint_space, *result->PhysicalFragment()); + // Tell legacy layout there were abspos descendents we couldn't place. We know // we have to pass up to legacy here because this method is legacy's entry // point to LayoutNG. If our parent were LayoutNG, it wouldn't have called
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h index cacadfd..1ea6e59 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h
@@ -19,6 +19,10 @@ void UpdateBlockLayout(bool relayout_children) override; const char* GetName() const override { return "LayoutNGTableCaption"; } + + private: + void CalculateAndSetMargins(const NGConstraintSpace&, + const NGPhysicalFragment&); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc index 88ccb44..bba0d68 100644 --- a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc +++ b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc
@@ -20,6 +20,11 @@ return nullptr; if (child->IsLayoutFlowThread()) return ToLayoutBlockFlow(child)->FirstChild(); + // The rendered legend is a child of the anonymous wrapper inside the fieldset + // container. If we find it, skip it. As far as NG is concerned, the rendered + // legend is a child of the fieldset container. + if (UNLIKELY(child->IsRenderedLegend())) + return child->NextSibling(); return child; } @@ -32,11 +37,30 @@ LayoutObject* parent = object->Parent(); if (!parent) return nullptr; + + // The parent of the rendered legend is the fieldset container, as far as NG + // is concerned. Skip the anonymous wrapper in-between. + if (UNLIKELY(object->IsRenderedLegend())) + return parent->Parent(); + if (parent->IsLayoutFlowThread()) return parent->Parent(); return parent; } +LayoutObject* GetLayoutObjectForNextSiblingNode(LayoutObject* object) { + // We don't expect to walk the layout tree starting at the rendered legend, + // and we'll skip over it if we find it. The renderered legend will be handled + // by a special algorithm, and should be invisible among siblings. + DCHECK(!object->IsRenderedLegend()); + LayoutObject* next = object->NextSibling(); + if (!next) + return nullptr; + if (UNLIKELY(next->IsRenderedLegend())) + return next->NextSibling(); + return next; +} + bool AreNGBlockFlowChildrenInline(const LayoutBlock* block) { if (block->ChildrenInline()) return true;
diff --git a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h index 79bf10c..bd52a27 100644 --- a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h +++ b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
@@ -20,6 +20,11 @@ // are certain layout objects that should be skipped for NG. LayoutObject* GetLayoutObjectForParentNode(LayoutObject*); +// Return the layout object that should be the sibling NGLayoutInputNode of +// |object|. Normally this will just be the next sibling layout object, but +// there are certain layout objects that should be skipped for NG. +LayoutObject* GetLayoutObjectForNextSiblingNode(LayoutObject*); + // Return true if the NGLayoutInputNode children of the NGLayoutInputNode // established by |block| will be inline; see LayoutObject::ChildrenInline(). bool AreNGBlockFlowChildrenInline(const LayoutBlock*);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc index 8b8010a..f5c1a3d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/html/html_marquee_element.h" #include "third_party/blink/renderer/core/layout/layout_block_flow.h" +#include "third_party/blink/renderer/core/layout/layout_fieldset.h" #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h" #include "third_party/blink/renderer/core/layout/layout_multi_column_set.h" #include "third_party/blink/renderer/core/layout/min_max_size.h" @@ -21,6 +22,7 @@ #include "third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h" +#include "third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h" #include "third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h" #include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h" @@ -52,6 +54,8 @@ const ComputedStyle& style = node.Style(); \ if (node.GetLayoutBox()->IsLayoutNGFlexibleBox()) \ return NGFlexLayoutAlgorithm(node, space, token).func args; \ + if (node.GetLayoutBox()->IsLayoutNGFieldset()) \ + return NGFieldsetLayoutAlgorithm(node, space, token).func args; \ /* If there's a legacy layout box, we can only do block fragmentation if \ * we would have done block fragmentation with the legacy engine. \ * Otherwise writing data back into the legacy tree will fail. Look for \ @@ -433,7 +437,7 @@ } NGLayoutInputNode NGBlockNode::NextSibling() const { - LayoutObject* next_sibling = box_->NextSibling(); + LayoutObject* next_sibling = GetLayoutObjectForNextSiblingNode(box_); if (next_sibling) { DCHECK(!next_sibling->IsInline()); return NGBlockNode(ToLayoutBox(next_sibling)); @@ -451,6 +455,21 @@ return NGBlockNode(ToLayoutBox(child)); } +NGBlockNode NGBlockNode::GetRenderedLegend() const { + if (!IsFieldsetContainer()) + return nullptr; + return NGBlockNode(LayoutFieldset::FindInFlowLegend(*ToLayoutBlock(box_))); +} + +NGBlockNode NGBlockNode::GetFieldsetContent() const { + if (!IsFieldsetContainer()) + return nullptr; + auto* child = GetLayoutObjectForFirstChildNode(ToLayoutBlock(box_)); + if (!child) + return nullptr; + return NGBlockNode(ToLayoutBox(child)); +} + bool NGBlockNode::CanUseNewLayout(const LayoutBox& box) { DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled()); if (box.StyleRef().ForceLegacyLayout())
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.h b/third_party/blink/renderer/core/layout/ng/ng_block_node.h index 74bb0ee..bf88b69 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.h +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
@@ -31,6 +31,8 @@ public: explicit NGBlockNode(LayoutBox* box) : NGLayoutInputNode(box, kBlock) {} + NGBlockNode(std::nullptr_t) : NGLayoutInputNode(nullptr) {} + scoped_refptr<NGLayoutResult> Layout( const NGConstraintSpace& constraint_space, NGBreakToken* break_token = nullptr); @@ -64,6 +66,9 @@ NGLayoutInputNode FirstChild() const; + NGBlockNode GetRenderedLegend() const; + NGBlockNode GetFieldsetContent() const; + bool IsInlineLevel() const; bool IsAtomicInlineLevel() const;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc new file mode 100644 index 0000000..8c3010b --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
@@ -0,0 +1,171 @@ +// 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 "third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h" + +#include "third_party/blink/renderer/core/layout/layout_fieldset.h" +#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h" +#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h" +#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h" +#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h" +#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h" +#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" +#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h" +#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h" +#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" + +namespace blink { + +NGFieldsetLayoutAlgorithm::NGFieldsetLayoutAlgorithm( + NGBlockNode node, + const NGConstraintSpace& space, + NGBreakToken* break_token) + : NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)) {} + +scoped_refptr<NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() { + // TODO(mstensho): Support block fragmentation. + DCHECK(!BreakToken()); + + // Layout of a fieldset container consists of two parts: Create a child + // fragment for the rendered legend (if any), and create a child fragment for + // the fieldset contents anonymous box (if any). Fieldset scrollbars and + // padding will not be applied to the fieldset container itself, but rather to + // the fieldset contents anonymous child box. The reason for this is that the + // rendered legend shouldn't be part of the scrollport; the legend is + // essentially a part of the block-start border, and should not scroll along + // with the actual fieldset contents. Since scrollbars are handled by the + // anonymous child box, and since padding is inside the scrollport, padding + // also needs to be handled by the anonymous child. + NGBoxStrut borders = ComputeBorders(ConstraintSpace(), Style()); + NGBoxStrut padding = ComputePadding(ConstraintSpace(), Style()); + NGLogicalSize border_box_size = + CalculateBorderBoxSize(ConstraintSpace(), Node()); + const auto writing_mode = ConstraintSpace().GetWritingMode(); + LayoutUnit block_start_padding_edge = borders.block_start; + + if (NGBlockNode legend = Node().GetRenderedLegend()) { + // Lay out the legend. While the fieldset container normally ignores its + // padding, the legend is laid out within what would have been the content + // box had the fieldset been a regular block with no weirdness. + NGBoxStrut borders_padding = borders + padding; + NGLogicalSize content_box_size = + ShrinkAvailableSize(border_box_size, borders_padding); + auto legend_space = + CreateConstraintSpaceForLegend(legend, content_box_size); + auto result = legend.Layout(legend_space, BreakToken()); + NGBoxStrut legend_margins = + ComputeMarginsFor(legend_space, legend.Style(), ConstraintSpace()); + NGFragment logical_fragment(writing_mode, *result->PhysicalFragment()); + // If the margin box of the legend is at least as tall as the fieldset + // block-start border width, it will start at the block-start border edge of + // the fieldset. As a paint effect, the block-start border will be pushed so + // that the center of the border will be flush with the center of the + // border-box of the legend. + // TODO(mstensho): inline alignment + NGLogicalOffset legend_offset = NGLogicalOffset( + borders_padding.inline_start + legend_margins.inline_start, + legend_margins.block_start); + LayoutUnit legend_margin_box_block_size = + logical_fragment.BlockSize() + legend_margins.BlockSum(); + LayoutUnit space_left = borders.block_start - legend_margin_box_block_size; + if (space_left > LayoutUnit()) { + // If the border is the larger one, though, it will stay put at the + // border-box block-start edge of the fieldset. Then it's the legend that + // needs to be pushed. We'll center the margin box in this case, to make + // sure that both margins remain within the area occupied by the border + // also after adjustment. + legend_offset.block_offset += space_left / 2; + } else { + // If the legend is larger than the width of the fieldset block-start + // border, the actual padding edge of the fieldset will be moved + // accordingly. This will be the block-start offset for the fieldset + // contents anonymous box. + block_start_padding_edge = legend_margin_box_block_size; + } + + container_builder_.AddChild(*result, legend_offset); + } + + NGBoxStrut borders_with_legend = borders; + borders_with_legend.block_start = block_start_padding_edge; + LayoutUnit intrinsic_block_size = borders_with_legend.BlockSum(); + + // Proceed with normal fieldset children (excluding the rendered legend). They + // all live inside an anonymous child box of the fieldset container. + if (auto fieldset_content = Node().GetFieldsetContent()) { + NGLogicalSize adjusted_padding_box_size = + ShrinkAvailableSize(border_box_size, borders_with_legend); + auto child_space = + CreateConstraintSpaceForFieldsetContent(adjusted_padding_box_size); + auto result = fieldset_content.Layout(child_space, BreakToken()); + container_builder_.AddChild(*result, borders_with_legend.StartOffset()); + + NGFragment logical_fragment(writing_mode, *result->PhysicalFragment()); + intrinsic_block_size += logical_fragment.BlockSize(); + } else { + // There was no anonymous child to provide the padding, so we have to add it + // ourselves. + intrinsic_block_size += padding.BlockSum(); + } + + // Recompute the block-axis size now that we know our content size. + border_box_size.block_size = ComputeBlockSizeForFragment( + ConstraintSpace(), Style(), intrinsic_block_size); + + // The above computation utility knows nothing about fieldset weirdness. The + // legend may eat from the available content box block size. Make room for + // that if necessary. + LayoutUnit minimum_border_box_block_size = + borders_with_legend.BlockSum() + padding.BlockSum(); + border_box_size.block_size = + std::max(border_box_size.block_size, minimum_border_box_block_size); + + container_builder_.SetInlineSize(border_box_size.inline_size); + container_builder_.SetIntrinsicBlockSize(intrinsic_block_size); + container_builder_.SetBlockSize(border_box_size.block_size); + container_builder_.SetBorders(borders); + container_builder_.SetPadding(padding); + + NGOutOfFlowLayoutPart(&container_builder_, Node().IsAbsoluteContainer(), + Node().IsFixedContainer(), borders_with_legend, + ConstraintSpace(), Style()) + .Run(); + + return container_builder_.ToBoxFragment(); +} + +base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize( + const MinMaxSizeInput& input) const { + // TODO(mstensho): Implement min/max + return MinMaxSize(); +} + +const NGConstraintSpace +NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForLegend( + NGBlockNode legend, + NGLogicalSize available_size) { + NGConstraintSpaceBuilder builder(ConstraintSpace()); + builder.SetAvailableSize(available_size); + NGLogicalSize percentage_size = + CalculateChildPercentageSize(ConstraintSpace(), Node(), available_size); + builder.SetPercentageResolutionSize(percentage_size); + builder.SetIsNewFormattingContext(true); + builder.SetIsShrinkToFit(true); + builder.SetTextDirection(legend.Style().Direction()); + return builder.ToConstraintSpace(legend.Style().GetWritingMode()); +} + +const NGConstraintSpace +NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForFieldsetContent( + NGLogicalSize padding_box_size) { + NGConstraintSpaceBuilder builder(ConstraintSpace()); + builder.SetPercentageResolutionSize( + ConstraintSpace().PercentageResolutionSize()); + builder.SetAvailableSize(padding_box_size); + builder.SetIsFixedSizeBlock(padding_box_size.block_size != NGSizeIndefinite); + builder.SetIsNewFormattingContext(true); + return builder.ToConstraintSpace(ConstraintSpace().GetWritingMode()); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h new file mode 100644 index 0000000..cfad7de91 --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h
@@ -0,0 +1,42 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FIELDSET_LAYOUT_ALGORITHM_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FIELDSET_LAYOUT_ALGORITHM_H_ + +#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h" + +#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h" +#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h" + +namespace blink { + +class NGBlockBreakToken; +class NGBreakToken; +class NGConstraintSpace; + +class CORE_EXPORT NGFieldsetLayoutAlgorithm + : public NGLayoutAlgorithm<NGBlockNode, + NGFragmentBuilder, + NGBlockBreakToken> { + public: + NGFieldsetLayoutAlgorithm(NGBlockNode node, + const NGConstraintSpace& space, + NGBreakToken* break_token = nullptr); + + scoped_refptr<NGLayoutResult> Layout() override; + + base::Optional<MinMaxSize> ComputeMinMaxSize( + const MinMaxSizeInput&) const override; + + const NGConstraintSpace CreateConstraintSpaceForLegend( + NGBlockNode legend, + NGLogicalSize available_size); + const NGConstraintSpace CreateConstraintSpaceForFieldsetContent( + NGLogicalSize padding_box_size); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FIELDSET_LAYOUT_ALGORITHM_H_
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc new file mode 100644 index 0000000..f964d04 --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
@@ -0,0 +1,442 @@ +// 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 "third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h" + +#include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h" +#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h" +#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" + +namespace blink { +namespace { + +class NGFieldsetLayoutAlgorithmTest : public NGBaseLayoutAlgorithmTest { + protected: + void SetUp() override { + NGBaseLayoutAlgorithmTest::SetUp(); + style_ = ComputedStyle::Create(); + was_fieldset_enabled_ = RuntimeEnabledFeatures::LayoutNGFieldsetEnabled(); + was_block_fragmentation_enabled_ = + RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled(); + RuntimeEnabledFeatures::SetLayoutNGFieldsetEnabled(true); + RuntimeEnabledFeatures::SetLayoutNGBlockFragmentationEnabled(true); + } + + void TearDown() override { + RuntimeEnabledFeatures::SetLayoutNGFieldsetEnabled(was_fieldset_enabled_); + RuntimeEnabledFeatures::SetLayoutNGBlockFragmentationEnabled( + was_block_fragmentation_enabled_); + } + + scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm( + const NGConstraintSpace& space, + NGBlockNode node) { + scoped_refptr<NGLayoutResult> result = + NGBlockLayoutAlgorithm(node, space).Layout(); + + return ToNGPhysicalBoxFragment(result->PhysicalFragment().get()); + } + + scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm( + Element* element) { + NGBlockNode container(ToLayoutBox(element->GetLayoutObject())); + NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace( + WritingMode::kHorizontalTb, TextDirection::kLtr, + NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite)); + return RunBlockLayoutAlgorithm(space, container); + } + + String DumpFragmentTree(const NGPhysicalBoxFragment* fragment) { + NGPhysicalFragment::DumpFlags flags = + NGPhysicalFragment::DumpHeaderText | NGPhysicalFragment::DumpSubtree | + NGPhysicalFragment::DumpIndentation | NGPhysicalFragment::DumpOffset | + NGPhysicalFragment::DumpSize; + + return fragment->DumpFragmentTree(flags); + } + + String DumpFragmentTree(Element* element) { + auto fragment = RunBlockLayoutAlgorithm(element); + return DumpFragmentTree(fragment.get()); + } + + scoped_refptr<ComputedStyle> style_; + bool was_fieldset_enabled_ = false; + bool was_block_fragmentation_enabled_ = false; +}; + +TEST_F(NGFieldsetLayoutAlgorithmTest, Empty) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { margin:0; border:3px solid; padding:10px; width:100px; } + </style> + <div id="container"> + <fieldset></fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x26 + offset:0,0 size:126x26 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGFieldsetLayoutAlgorithmTest, NoLegend) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { margin:0; border:3px solid; padding:10px; width:100px; } + </style> + <div id="container"> + <fieldset> + <div style="height:100px;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x126 + offset:0,0 size:126x126 + offset:3,3 size:120x120 + offset:10,10 size:100x100 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGFieldsetLayoutAlgorithmTest, Legend) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { margin:0; border:3px solid; padding:10px; width:100px; } + </style> + <div id="container"> + <fieldset> + <legend style="padding:0; width:50px; height:200px;"></legend> + <div style="height:100px;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x323 + offset:0,0 size:126x323 + offset:13,0 size:50x200 + offset:3,200 size:120x120 + offset:10,10 size:100x100 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGFieldsetLayoutAlgorithmTest, SmallLegendLargeBorder) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { margin:0; border:40px solid; padding:10px; width:100px; } + legend { padding:0; width:10px; height:10px; + margin-top:5px; margin-bottom:15px; } + </style> + <div id="container"> + <fieldset> + <legend></legend> + <div style="height:100px;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x200 + offset:0,0 size:200x200 + offset:50,10 size:10x10 + offset:40,40 size:120x120 + offset:10,10 size:100x100 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGFieldsetLayoutAlgorithmTest, LegendOrthogonalWritingMode) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { margin:0; border:3px solid; padding:10px; width:100px; } + legend { writing-mode:vertical-rl; padding:0; margin:10px 15px 20px 30px; + width:10px; height:50px; } + </style> + <div id="container"> + <fieldset> + <legend></legend> + <div style="height:100px;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x203 + offset:0,0 size:126x203 + offset:43,10 size:10x50 + offset:3,80 size:120x120 + offset:10,10 size:100x100 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGFieldsetLayoutAlgorithmTest, VerticalLr) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { writing-mode:vertical-lr; margin:0; border:3px solid; + padding:10px; height:100px; } + legend { padding:0; margin:10px 15px 20px 30px; width:10px; height:50px; } + </style> + <div id="container"> + <fieldset> + <legend></legend> + <div style="width:100px;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x126 + offset:0,0 size:178x126 + offset:30,23 size:10x50 + offset:55,3 size:120x120 + offset:10,10 size:100x100 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGFieldsetLayoutAlgorithmTest, VerticalRl) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { writing-mode:vertical-rl; margin:0; border:3px solid; + padding:10px; height:100px; } + legend { padding:0; margin:10px 15px 20px 30px; width:10px; height:50px; } + </style> + <div id="container"> + <fieldset> + <legend></legend> + <div style="width:100px;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x126 + offset:0,0 size:178x126 + offset:153,23 size:10x50 + offset:3,3 size:120x120 + offset:10,10 size:100x100 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAutoSize) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { margin:0; border:3px solid; padding:10px; width:100px; } + </style> + <div id="container"> + <fieldset> + <legend style="padding:0;"> + <div style="float:left; width:25px; height:200px;"></div> + <div style="float:left; width:25px; height:200px;"></div> + </legend> + <div style="height:100px;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x323 + offset:0,0 size:126x323 + offset:13,0 size:50x200 + offset:0,0 size:25x200 + offset:25,0 size:25x200 + offset:50,0 size:0x0 + offset:3,200 size:120x120 + offset:10,10 size:100x100 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +TEST_F(NGFieldsetLayoutAlgorithmTest, PercentageHeightChild) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { + margin:0; border:3px solid; padding:10px; width:100px; height:100px; + } + </style> + <div id="container"> + <fieldset> + <legend style="padding:0; width:30px; height:30px;"></legend> + <div style="height:100%;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x126 + offset:0,0 size:126x126 + offset:13,0 size:30x30 + offset:3,30 size:120x93 + offset:10,10 size:100x73 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +// Disabled because out-of-flow positioned objects enter legacy code (regardless +// of the out-of-flow positioned object being laid out by NG or not). Invoking +// layout on our own outside of the lifecycle machinery will eventually fail a +// CHECK in SubtreeLayoutScope::SubtreeLayoutScope(). +TEST_F(NGFieldsetLayoutAlgorithmTest, DISABLED_AbsposChild) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { + position:relative; margin:0; border:3px solid; padding:10px; + width:100px; height:100px; + } + </style> + <div id="container"> + <fieldset> + <legend style="padding:0; width:30px; height:30px;"></legend> + <div style="position:absolute; top:0; right:0; bottom:0; left:0;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x126 + offset:0,0 size:126x126 + offset:13,0 size:30x30 + offset:3,30 size:120x93 + offset:3,30 size:120x93 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +// Used height needs to be adjusted to encompass the legend, if specified height +// requests a lower height than that. +TEST_F(NGFieldsetLayoutAlgorithmTest, ZeroHeight) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { + margin:0; border:3px solid; padding:10px; width:100px; height:0; + } + </style> + <div id="container"> + <fieldset> + <legend style="padding:0; width:30px; height:30px;"></legend> + <div style="height:200px;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x53 + offset:0,0 size:126x53 + offset:13,0 size:30x30 + offset:3,30 size:120x0 + offset:10,10 size:100x200 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +// Used height needs to be adjusted to encompass the legend, if specified height +// requests a lower max-height than that. +TEST_F(NGFieldsetLayoutAlgorithmTest, ZeroMaxHeight) { + SetBodyInnerHTML(R"HTML( + <style> + fieldset { + margin:0; border:3px solid; padding:10px; width:100px; max-height:0; + } + </style> + <div id="container"> + <fieldset> + <legend style="padding:0; width:30px; height:30px;"></legend> + <div style="height:200px;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x53 + offset:0,0 size:126x53 + offset:13,0 size:30x30 + offset:3,30 size:120x220 + offset:10,10 size:100x200 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +// Things inside legends and fieldsets are treated as if there was no fieldsets +// and legends involved, as far as the percentage height quirk is concerned. +TEST_F(NGFieldsetLayoutAlgorithmTest, PercentHeightQuirks) { + GetDocument().SetCompatibilityMode(Document::kQuirksMode); + SetBodyInnerHTML(R"HTML( + <style> + fieldset { + margin:0; border:3px solid; padding:10px; width:100px; + } + </style> + <div id="container" style="height:200px;"> + <fieldset> + <legend style="padding:0;"> + <div style="width:100px; height:50%;"></div> + </legend> + <div style="width:40px; height:20%;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x200 + offset:0,0 size:126x163 + offset:13,0 size:100x100 + offset:0,0 size:100x100 + offset:3,100 size:120x60 + offset:10,10 size:40x40 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +// Legends are treated as regular elements, as far as the percentage height +// quirk is concerned. +TEST_F(NGFieldsetLayoutAlgorithmTest, LegendPercentHeightQuirks) { + GetDocument().SetCompatibilityMode(Document::kQuirksMode); + SetBodyInnerHTML(R"HTML( + <style> + fieldset { + margin:0; border:3px solid; padding:10px; width:100px; + } + </style> + <div id="container" style="height:200px;"> + <fieldset> + <legend style="padding:0; width:100px; height:50%;"></legend> + <div style="width:40px; height:20%;"></div> + </fieldset> + </div> + )HTML"); + + String dump = DumpFragmentTree(GetElementById("container")); + String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. + offset:unplaced size:1000x200 + offset:0,0 size:126x163 + offset:13,0 size:100x100 + offset:3,100 size:120x60 + offset:10,10 size:40x40 +)DUMP"; + EXPECT_EQ(expectation, dump); +} + +} // anonymous namespace +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc index 1e7e015..08c9990 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
@@ -107,6 +107,10 @@ return IsBlock() && box_->IsTableCell(); } +bool NGLayoutInputNode::IsFieldsetContainer() const { + return IsBlock() && box_->IsLayoutNGFieldset(); +} + bool NGLayoutInputNode::IsAnonymousBlock() const { return box_->IsAnonymousBlock(); }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h index 0402f88..55d1494 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -73,6 +73,7 @@ bool IsListMarker() const; bool ListMarkerOccupiesWholeLine() const; bool IsTableCell() const; + bool IsFieldsetContainer() const; bool IsAnonymousBlock() const; // If the node is a quirky container for margin collapsing, see:
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h index 71c02828..06f060ca 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h +++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
@@ -210,6 +210,8 @@ // values and over-constrainedness. This uses the available size from the // constraint space and inline size to compute the margins that are auto, if // any, and adjusts the given NGBoxStrut accordingly. +// available_inline_size, inline_size, and margins are all in the +// containing_block's writing mode. CORE_EXPORT void ResolveInlineMargins( const ComputedStyle& child_style, const ComputedStyle& containing_block_style,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc index 042f065..4353b24 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
@@ -27,6 +27,7 @@ #include "third_party/blink/renderer/core/layout/layout_box_model_object.h" #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" #include "third_party/blink/renderer/core/paint/paint_info.h" +#include "third_party/blink/renderer/core/svg/svg_clip_path_element.h" #include "third_party/blink/renderer/core/svg/svg_geometry_element.h" #include "third_party/blink/renderer/core/svg/svg_use_element.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_record.h" @@ -214,6 +215,13 @@ } } +SVGUnitTypes::SVGUnitType LayoutSVGResourceClipper::ClipPathUnits() const { + return ToSVGClipPathElement(GetElement()) + ->clipPathUnits() + ->CurrentValue() + ->EnumValue(); +} + AffineTransform LayoutSVGResourceClipper::CalculateClipTransform( const FloatRect& reference_box) const { AffineTransform transform =
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h index 4a265c56..b7913ab 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
@@ -21,11 +21,13 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_CLIPPER_H_ #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h" -#include "third_party/blink/renderer/core/svg/svg_clip_path_element.h" +#include "third_party/blink/renderer/core/svg/svg_unit_types.h" #include "third_party/skia/include/core/SkRefCnt.h" namespace blink { +class SVGClipPathElement; + class LayoutSVGResourceClipper final : public LayoutSVGResourceContainer { public: explicit LayoutSVGResourceClipper(SVGClipPathElement*); @@ -42,12 +44,7 @@ bool HitTestClipContent(const FloatRect&, const FloatPoint&); - SVGUnitTypes::SVGUnitType ClipPathUnits() const { - return ToSVGClipPathElement(GetElement()) - ->clipPathUnits() - ->CurrentValue() - ->EnumValue(); - } + SVGUnitTypes::SVGUnitType ClipPathUnits() const; AffineTransform CalculateClipTransform(const FloatRect& reference_box) const; base::Optional<Path> AsPath();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc index a9559a57..74444393 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
@@ -85,13 +85,10 @@ } FloatRect LayoutSVGResourceFilter::ResourceBoundingBox( - const LayoutObject* object) { - if (SVGFilterElement* element = ToSVGFilterElement(GetElement())) - return SVGLengthContext::ResolveRectangle<SVGFilterElement>( - element, element->filterUnits()->CurrentValue()->EnumValue(), - object->ObjectBoundingBox()); - - return FloatRect(); + const FloatRect& reference_box) const { + const auto* filter_element = ToSVGFilterElement(GetElement()); + return SVGLengthContext::ResolveRectangle(filter_element, FilterUnits(), + reference_box); } SVGUnitTypes::SVGUnitType LayoutSVGResourceFilter::FilterUnits() const {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h index 23372b07..0152f3e 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
@@ -82,7 +82,7 @@ void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override; bool RemoveClientFromCache(SVGResourceClient&) override; - FloatRect ResourceBoundingBox(const LayoutObject*); + FloatRect ResourceBoundingBox(const FloatRect& reference_box) const; SVGUnitTypes::SVGUnitType FilterUnits() const; SVGUnitTypes::SVGUnitType PrimitiveUnits() const;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc index ae7d043..62810559 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
@@ -23,6 +23,7 @@ #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" #include "third_party/blink/renderer/core/paint/svg_object_painter.h" #include "third_party/blink/renderer/core/svg/svg_element.h" +#include "third_party/blink/renderer/core/svg/svg_mask_element.h" #include "third_party/blink/renderer/platform/graphics/graphics_context.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_record.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h" @@ -49,11 +50,7 @@ AffineTransform& content_transformation, const FloatRect& target_bounding_box, GraphicsContext& context) { - SVGUnitTypes::SVGUnitType content_units = ToSVGMaskElement(GetElement()) - ->maskContentUnits() - ->CurrentValue() - ->EnumValue(); - if (content_units == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { + if (MaskContentUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { content_transformation.Translate(target_bounding_box.X(), target_bounding_box.Y()); content_transformation.ScaleNonUniform(target_bounding_box.Width(), @@ -98,16 +95,27 @@ } } +SVGUnitTypes::SVGUnitType LayoutSVGResourceMasker::MaskUnits() const { + return ToSVGMaskElement(GetElement()) + ->maskUnits() + ->CurrentValue() + ->EnumValue(); +} + +SVGUnitTypes::SVGUnitType LayoutSVGResourceMasker::MaskContentUnits() const { + return ToSVGMaskElement(GetElement()) + ->maskContentUnits() + ->CurrentValue() + ->EnumValue(); +} + FloatRect LayoutSVGResourceMasker::ResourceBoundingBox( - const LayoutObject* object) { + const FloatRect& reference_box) { SVGMaskElement* mask_element = ToSVGMaskElement(GetElement()); DCHECK(mask_element); - FloatRect object_bounding_box = object->ObjectBoundingBox(); - FloatRect mask_boundaries = - SVGLengthContext::ResolveRectangle<SVGMaskElement>( - mask_element, mask_element->maskUnits()->CurrentValue()->EnumValue(), - object_bounding_box); + FloatRect mask_boundaries = SVGLengthContext::ResolveRectangle( + mask_element, MaskUnits(), reference_box); // Resource was not layouted yet. Give back clipping rect of the mask. if (SelfNeedsLayout()) @@ -117,12 +125,10 @@ CalculateMaskContentVisualRect(); FloatRect mask_rect = mask_content_boundaries_; - if (mask_element->maskContentUnits()->CurrentValue()->Value() == - SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { + if (MaskContentUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { AffineTransform transform; - transform.Translate(object_bounding_box.X(), object_bounding_box.Y()); - transform.ScaleNonUniform(object_bounding_box.Width(), - object_bounding_box.Height()); + transform.Translate(reference_box.X(), reference_box.Y()); + transform.ScaleNonUniform(reference_box.Width(), reference_box.Height()); mask_rect = transform.MapRect(mask_rect); }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h index eea70d1..70442a2 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
@@ -21,7 +21,6 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_MASKER_H_ #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h" -#include "third_party/blink/renderer/core/svg/svg_mask_element.h" #include "third_party/blink/renderer/core/svg/svg_unit_types.h" #include "third_party/blink/renderer/platform/geometry/float_rect.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -30,6 +29,7 @@ class AffineTransform; class GraphicsContext; +class SVGMaskElement; class LayoutSVGResourceMasker final : public LayoutSVGResourceContainer { public: @@ -40,20 +40,10 @@ void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override; - FloatRect ResourceBoundingBox(const LayoutObject*); + FloatRect ResourceBoundingBox(const FloatRect& reference_box); - SVGUnitTypes::SVGUnitType MaskUnits() const { - return ToSVGMaskElement(GetElement()) - ->maskUnits() - ->CurrentValue() - ->EnumValue(); - } - SVGUnitTypes::SVGUnitType MaskContentUnits() const { - return ToSVGMaskElement(GetElement()) - ->maskContentUnits() - ->CurrentValue() - ->EnumValue(); - } + SVGUnitTypes::SVGUnitType MaskUnits() const; + SVGUnitTypes::SVGUnitType MaskContentUnits() const; static const LayoutSVGResourceType kResourceType = kMaskerResourceType; LayoutSVGResourceType ResourceType() const override { return kResourceType; }
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc index 76eb82d..2fb3a01 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -41,6 +41,7 @@ #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/style/shape_clip_path_operation.h" #include "third_party/blink/renderer/core/svg/svg_element.h" +#include "third_party/blink/renderer/core/svg/svg_length_context.h" #include "third_party/blink/renderer/platform/graphics/stroke_data.h" #include "third_party/blink/renderer/platform/transforms/transform_state.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" @@ -391,16 +392,20 @@ if (!resources) return; - if (LayoutSVGResourceFilter* filter = resources->Filter()) - visual_rect = filter->ResourceBoundingBox(&layout_object); + if (LayoutSVGResourceFilter* filter = resources->Filter()) { + visual_rect = + filter->ResourceBoundingBox(layout_object.ObjectBoundingBox()); + } if (LayoutSVGResourceClipper* clipper = resources->Clipper()) { visual_rect.Intersect( clipper->ResourceBoundingBox(layout_object.ObjectBoundingBox())); } - if (LayoutSVGResourceMasker* masker = resources->Masker()) - visual_rect.Intersect(masker->ResourceBoundingBox(&layout_object)); + if (LayoutSVGResourceMasker* masker = resources->Masker()) { + visual_rect.Intersect( + masker->ResourceBoundingBox(layout_object.ObjectBoundingBox())); + } } bool SVGLayoutSupport::HasFilterResource(const LayoutObject& object) {
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc index 6b685d8..c77274e 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
@@ -735,6 +735,7 @@ SVGResourcesCache::CachedResourcesForLayoutObject(object); if (!resources) return; + const FloatRect reference_box = object.ObjectBoundingBox(); const ComputedStyle& style = object.StyleRef(); TreeScope& tree_scope = object.GetDocument(); if (LayoutSVGResourceMasker* masker = resources->Masker()) { @@ -744,7 +745,7 @@ tree_scope); ts << " "; WriteStandardPrefix(ts, *masker, 0); - ts << " " << masker->ResourceBoundingBox(&object) << "\n"; + ts << " " << masker->ResourceBoundingBox(reference_box) << "\n"; } if (LayoutSVGResourceClipper* clipper = resources->Clipper()) { DCHECK(style.ClipPath()); @@ -758,8 +759,7 @@ WriteNameAndQuotedValue(ts, "clipPath", id); ts << " "; WriteStandardPrefix(ts, *clipper, 0); - ts << " " << clipper->ResourceBoundingBox(object.ObjectBoundingBox()) - << "\n"; + ts << " " << clipper->ResourceBoundingBox(reference_box) << "\n"; } if (LayoutSVGResourceFilter* filter = resources->Filter()) { DCHECK(style.HasFilter()); @@ -775,7 +775,7 @@ WriteNameAndQuotedValue(ts, "filter", id); ts << " "; WriteStandardPrefix(ts, *filter, 0); - ts << " " << filter->ResourceBoundingBox(&object) << "\n"; + ts << " " << filter->ResourceBoundingBox(reference_box) << "\n"; } }
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources.cc b/third_party/blink/renderer/core/layout/svg/svg_resources.cc index 2d2add6f..8b287a35 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_resources.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
@@ -291,15 +291,8 @@ if (!HasResourceData()) return 0; - if (linked_resource_) { - DCHECK(!clipper_filter_masker_data_); - DCHECK(!marker_data_); - DCHECK(!fill_stroke_data_); - linked_resource_->RemoveClientFromCache(client); - // The only linked resources are gradients and patterns, i.e - // always a paint server. - return SVGResourceClient::kPaintInvalidation; - } + // We never call this method for the elements where this would be non-null. + DCHECK(!linked_resource_); InvalidationModeMask invalidation_flags = RemoveClientFromCacheAffectingObjectBounds(client);
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc index 9cc13bbf..37932071f 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
@@ -32,7 +32,7 @@ SVGResourcesCache::~SVGResourcesCache() = default; -void SVGResourcesCache::AddResourcesFromLayoutObject( +bool SVGResourcesCache::AddResourcesFromLayoutObject( LayoutObject& object, const ComputedStyle& style) { DCHECK(!cache_.Contains(&object)); @@ -41,10 +41,7 @@ std::unique_ptr<SVGResources> new_resources = SVGResources::BuildResources(object, style); if (!new_resources) - return; - - // The new resource may cause new paint property nodes. - object.SetNeedsPaintPropertyUpdate(); + return false; // Put object in cache. SVGResources* resources = @@ -59,15 +56,20 @@ if (solver.FindCycle(resource_container)) resources->ClearReferencesTo(resource_container); } + return true; } -void SVGResourcesCache::RemoveResourcesFromLayoutObject(LayoutObject& object) { +bool SVGResourcesCache::RemoveResourcesFromLayoutObject(LayoutObject& object) { std::unique_ptr<SVGResources> resources = cache_.Take(&object); - if (!resources) - return; + return !!resources; +} - // Removal of the resource may cause removal of paint property nodes. - object.SetNeedsPaintPropertyUpdate(); +bool SVGResourcesCache::UpdateResourcesFromLayoutObject( + LayoutObject& object, + const ComputedStyle& new_style) { + bool did_update = RemoveResourcesFromLayoutObject(object); + did_update |= AddResourcesFromLayoutObject(object, new_style); + return did_update; } static inline SVGResourcesCache& ResourcesCache(Document& document) { @@ -135,8 +137,8 @@ // rebuild individual resources, instead of all of them. if (LayoutObjectCanHaveResources(layout_object)) { SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument()); - cache.RemoveResourcesFromLayoutObject(layout_object); - cache.AddResourcesFromLayoutObject(layout_object, new_style); + if (cache.UpdateResourcesFromLayoutObject(layout_object, new_style)) + layout_object.SetNeedsPaintPropertyUpdate(); } // If this layoutObject is the child of ResourceContainer and it require @@ -162,8 +164,10 @@ DCHECK(LayoutObjectCanHaveResources(layout_object)); SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument()); - cache.RemoveResourcesFromLayoutObject(layout_object); - cache.AddResourcesFromLayoutObject(layout_object, layout_object.StyleRef()); + if (cache.UpdateResourcesFromLayoutObject(layout_object, + layout_object.StyleRef())) { + layout_object.SetNeedsPaintPropertyUpdate(); + } LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation( layout_object, true); @@ -179,7 +183,8 @@ if (!LayoutObjectCanHaveResources(layout_object)) return; SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument()); - cache.AddResourcesFromLayoutObject(layout_object, new_style); + if (cache.AddResourcesFromLayoutObject(layout_object, new_style)) + layout_object.SetNeedsPaintPropertyUpdate(); } void SVGResourcesCache::ClientWillBeRemovedFromTree( @@ -192,7 +197,8 @@ if (!LayoutObjectCanHaveResources(layout_object)) return; SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument()); - cache.RemoveResourcesFromLayoutObject(layout_object); + if (cache.RemoveResourcesFromLayoutObject(layout_object)) + layout_object.SetNeedsPaintPropertyUpdate(); } void SVGResourcesCache::ClientDestroyed(LayoutObject& layout_object) { @@ -228,8 +234,7 @@ const ComputedStyle& style) { DCHECK(!styles_are_equal_); SVGResourcesCache& cache = ResourcesCache(layout_object_.GetDocument()); - cache.RemoveResourcesFromLayoutObject(layout_object_); - cache.AddResourcesFromLayoutObject(layout_object_, style); + cache.UpdateResourcesFromLayoutObject(layout_object_, style); } } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h index eec4f65..42b85c7e 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h +++ b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
@@ -84,8 +84,9 @@ }; private: - void AddResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&); - void RemoveResourcesFromLayoutObject(LayoutObject&); + bool AddResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&); + bool RemoveResourcesFromLayoutObject(LayoutObject&); + bool UpdateResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&); typedef HashMap<const LayoutObject*, std::unique_ptr<SVGResources>> CacheMap; CacheMap cache_;
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc index c863077..8c00d17 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -32,6 +32,7 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/frame/visual_viewport.h" #include "third_party/blink/renderer/core/html/html_area_element.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" #include "third_party/blink/renderer/core/html/html_image_element.h" @@ -712,32 +713,27 @@ : nullptr; }; -// The rect of the visual viewport given in the root frame's coordinate space. +// The visual viewport's rect (given in the root frame's coordinate space). LayoutRect RootViewport(const LocalFrame* current_frame) { - LocalFrameView* root_frame_view = current_frame->LocalFrameRoot().View(); - const LayoutRect root_doc_rect( - root_frame_view->GetScrollableArea()->VisibleContentRect()); - // Convert the root frame's visible rect from document space -> frame space. - // For the root frame, frame space == root frame space, obviously. - LayoutRect frame_rect = root_frame_view->DocumentToFrame(root_doc_rect); - return frame_rect; + return LayoutRect( + current_frame->GetPage()->GetVisualViewport().VisibleRect()); } // Spatnav uses this rectangle to measure distances to focus candidates. // The search origin is either activeElement F itself, if it's being at least // partially visible, or else, its first [partially] visible scroller. If both // F and its enclosing scroller are completely off-screen, we recurse to the -// scroller’s scroller ... all the way up unil the root frame's document. +// scroller’s scroller ... all the way up until the root frame's document. // The root frame's document is a good base case because it's, per definition, // a visible scrollable area. -LayoutRect SearchOrigin(const LayoutRect visible_root_frame, +LayoutRect SearchOrigin(const LayoutRect viewport_rect_of_root_frame, Node* focus_node, const WebFocusType direction) { if (!focus_node) { // Search from one of the visual viewport's edges towards the navigated // direction. For example, UP makes spatnav search upwards, starting at the // visual viewport's bottom. - return OppositeEdge(direction, visible_root_frame); + return OppositeEdge(direction, viewport_rect_of_root_frame); } LayoutRect box_in_root_frame; @@ -759,16 +755,17 @@ // We found the first box that encloses focus and is [partially] visible. if (area_element || IsScrollableAreaOrDocument(focus_node)) { // When searching a container, we start from one of its sides. - return OppositeEdge(direction, - Intersection(box_in_root_frame, visible_root_frame), - thickness); + return OppositeEdge( + direction, + Intersection(box_in_root_frame, viewport_rect_of_root_frame), + thickness); } - return Intersection(box_in_root_frame, visible_root_frame); + return Intersection(box_in_root_frame, viewport_rect_of_root_frame); } // Try a higher "focus-enclosing" scroller. Node* container = ScrollableAreaOrDocumentOf(focus_node); - return SearchOrigin(visible_root_frame, container, direction); + return SearchOrigin(viewport_rect_of_root_frame, container, direction); } } // namespace blink
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_test.cc b/third_party/blink/renderer/core/page/spatial_navigation_test.cc index 1cdc0112..2b33e2dc 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_test.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation_test.cc
@@ -46,6 +46,23 @@ } }; +TEST_F(SpatialNavigationTest, RootFramesVisualViewport) { + // Test RootViewport with a pinched viewport. + VisualViewport& visual_viewport = GetFrame().GetPage()->GetVisualViewport(); + visual_viewport.SetScale(2); + visual_viewport.SetLocation(FloatPoint(200, 200)); + + LocalFrameView* root_frame_view = GetFrame().LocalFrameRoot().View(); + const LayoutRect roots_visible_doc_rect( + root_frame_view->GetScrollableArea()->VisibleContentRect()); + // Convert the root frame's visible rect from document space -> frame space. + // For the root frame, frame space == root frame space, obviously. + LayoutRect viewport_rect_of_root_frame = + root_frame_view->DocumentToFrame(roots_visible_doc_rect); + + EXPECT_EQ(viewport_rect_of_root_frame, RootViewport(&GetFrame())); +} + TEST_F(SpatialNavigationTest, FindContainerWhenEnclosingContainerIsDocument) { SetBodyInnerHTML( "<!DOCTYPE html>"
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc index d11dde3..32f33ec 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -427,7 +427,8 @@ bool will_have_foreground_layer = false; bool needs_recursion_for_composited_scrolling_plus_fixed_or_sticky = - layer->HasDescendantWithStickyOrFixed() && + (layer->HasFixedPositionDescendant() || + layer->HasStickyPositionDescendant()) && (has_non_root_composited_scrolling_ancestor || (layer->GetScrollableArea() && layer->GetScrollableArea()->NeedsCompositedScrolling()));
diff --git a/third_party/blink/renderer/core/paint/css_mask_painter.cc b/third_party/blink/renderer/core/paint/css_mask_painter.cc index 1fa15cb..5f092f0d 100644 --- a/third_party/blink/renderer/core/paint/css_mask_painter.cc +++ b/third_party/blink/renderer/core/paint/css_mask_painter.cc
@@ -22,8 +22,10 @@ SVGResources* resources = SVGResourcesCache::CachedResourcesForLayoutObject(object); LayoutSVGResourceMasker* masker = resources ? resources->Masker() : nullptr; - if (masker) - return EnclosingIntRect(masker->ResourceBoundingBox(&object)); + if (masker) { + return EnclosingIntRect( + masker->ResourceBoundingBox(object.ObjectBoundingBox())); + } } if (object.IsSVGChild() && !object.IsSVGForeignObject())
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc index 59551bc..7edc072 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -165,23 +165,67 @@ NGPaintFragment::~NGPaintFragment() = default; -scoped_refptr<NGPaintFragment> NGPaintFragment::Create( +scoped_refptr<NGPaintFragment> NGPaintFragment::CreateOrReuse( scoped_refptr<const NGPhysicalFragment> fragment, - NGPhysicalOffset offset) { + NGPhysicalOffset offset, + NGPaintFragment* parent, + scoped_refptr<NGPaintFragment> previous_instance, + bool* populate_children) { DCHECK(fragment); - scoped_refptr<NGPaintFragment> paint_fragment = - base::AdoptRef(new NGPaintFragment(std::move(fragment), offset, nullptr)); + // If the previous instance is given, check if it is re-usable. + // Re-using NGPaintFragment allows the paint system to identify objects. + if (previous_instance) { + DCHECK_EQ(previous_instance->parent_, parent); - HashMap<const LayoutObject*, NGPaintFragment*> last_fragment_map; - paint_fragment->PopulateDescendants(NGPhysicalOffset(), - &last_fragment_map); + // If the physical fragment was re-used, re-use the paint fragment as well. + if (&previous_instance->PhysicalFragment() == fragment.get()) { + previous_instance->offset_ = offset; + previous_instance->next_for_same_layout_object_ = nullptr; + // No need to re-populate children because NGPhysicalFragment is + // immutable and thus children should not have been changed. + *populate_children = false; + return previous_instance; + } + + // If the LayoutObject are the same, the new paint fragment should have the + // same DisplayItemClient identity as the previous instance. + if (previous_instance->GetLayoutObject() == fragment->GetLayoutObject()) { + previous_instance->physical_fragment_ = std::move(fragment); + previous_instance->offset_ = offset; + previous_instance->next_for_same_layout_object_ = nullptr; + if (!*populate_children) + previous_instance->children_.clear(); + return previous_instance; + } + } + + return base::AdoptRef( + new NGPaintFragment(std::move(fragment), offset, parent)); +} + +scoped_refptr<NGPaintFragment> NGPaintFragment::Create( + scoped_refptr<const NGPhysicalFragment> fragment, + NGPhysicalOffset offset, + scoped_refptr<NGPaintFragment> previous_instance) { + DCHECK(fragment); + + bool populate_children = fragment->IsContainer(); + scoped_refptr<NGPaintFragment> paint_fragment = + CreateOrReuse(std::move(fragment), offset, nullptr, + std::move(previous_instance), &populate_children); + + if (populate_children) { + HashMap<const LayoutObject*, NGPaintFragment*> last_fragment_map; + paint_fragment->PopulateDescendants(NGPhysicalOffset(), &last_fragment_map); + } return paint_fragment; } -void NGPaintFragment::UpdatePhysicalFragmentFromCachedLayoutResult( - scoped_refptr<const NGPhysicalFragment> fragment) { +void NGPaintFragment::UpdateFromCachedLayoutResult( + scoped_refptr<const NGPhysicalFragment> fragment, + NGPhysicalOffset offset) { DCHECK(fragment); #if DCHECK_IS_ON() @@ -196,7 +240,9 @@ } #endif - physical_fragment_ = fragment; + DCHECK_EQ(physical_fragment_.get(), fragment.get()); + physical_fragment_ = std::move(fragment); + offset_ = offset; } NGPaintFragment* NGPaintFragment::Last(const NGBreakToken& break_token) { @@ -217,6 +263,29 @@ } } +scoped_refptr<NGPaintFragment>* NGPaintFragment::Find( + scoped_refptr<NGPaintFragment>* fragment, + const NGBreakToken* break_token) { + DCHECK(fragment); + + if (!break_token) + return fragment; + + while (true) { + // TODO(kojii): Sometimes an unknown break_token is given. Need to + // investigate why, and handle appropriately. For now, just keep it to avoid + // crashes and use-after-free. + if (!*fragment) + return fragment; + + scoped_refptr<NGPaintFragment>* next = &(*fragment)->next_fragmented_; + if ((*fragment)->PhysicalFragment().BreakToken() == break_token) + return next; + fragment = next; + } + NOTREACHED(); +} + void NGPaintFragment::SetNext(scoped_refptr<NGPaintFragment> fragment) { next_fragmented_ = std::move(fragment); } @@ -258,17 +327,21 @@ void NGPaintFragment::PopulateDescendants( const NGPhysicalOffset inline_offset_to_container_box, HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map) { - DCHECK(children_.IsEmpty()); const NGPhysicalFragment& fragment = PhysicalFragment(); - if (!fragment.IsContainer()) - return; + DCHECK(fragment.IsContainer()); const NGPhysicalContainerFragment& container = ToNGPhysicalContainerFragment(fragment); children_.ReserveCapacity(container.Children().size()); - for (const auto& child_fragment : container.Children()) { - scoped_refptr<NGPaintFragment> child = base::AdoptRef(new NGPaintFragment( - child_fragment.get(), child_fragment.Offset(), this)); + unsigned child_index = 0; + for (const NGLink& child_fragment : container.Children()) { + bool populate_children = child_fragment->IsContainer() && + !child_fragment->IsBlockFormattingContextRoot(); + scoped_refptr<NGPaintFragment> child = CreateOrReuse( + child_fragment.get(), child_fragment.Offset(), this, + child_index < children_.size() ? std::move(children_[child_index]) + : nullptr, + &populate_children); if (!child_fragment->IsFloating() && !child_fragment->IsOutOfFlowPositioned() && @@ -281,18 +354,20 @@ inline_offset_to_container_box + child_fragment.Offset(); } - // Recurse children, except when this is a block formatting context root. - // TODO(kojii): At the block formatting context root, children may be for - // NGPaint, LayoutNG but not for NGPaint, or legacy. In order to get the - // maximum test coverage, split the NGPaintFragment tree at all possible - // engine boundaries. - if (!child_fragment->IsBlockFormattingContextRoot()) { + if (populate_children) { child->PopulateDescendants(child->inline_offset_to_container_box_, last_fragment_map); } - children_.push_back(std::move(child)); + if (child_index < children_.size()) + children_[child_index] = std::move(child); + else + children_.push_back(std::move(child)); + ++child_index; } + + if (child_index < children_.size()) + children_.resize(child_index); } // Add to a linked list for each LayoutObject. @@ -300,6 +375,7 @@ LayoutObject* layout_object, HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map) { DCHECK(layout_object); + DCHECK(!next_for_same_layout_object_); // TODO(kojii): The LayoutObject is inline, except for column container // fragment. We should have better way to distinguish it, probably after we
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h index d14d746..d2fafd8 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h +++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -46,20 +46,24 @@ static scoped_refptr<NGPaintFragment> Create( scoped_refptr<const NGPhysicalFragment>, - NGPhysicalOffset offset); + NGPhysicalOffset offset, + scoped_refptr<NGPaintFragment> previous_instance = nullptr); const NGPhysicalFragment& PhysicalFragment() const { return *physical_fragment_; } - void UpdatePhysicalFragmentFromCachedLayoutResult( - scoped_refptr<const NGPhysicalFragment>); + void UpdateFromCachedLayoutResult( + scoped_refptr<const NGPhysicalFragment> fragment, + NGPhysicalOffset offset); // Next/last fragment for when this is fragmented. NGPaintFragment* Next() { return next_fragmented_.get(); } void SetNext(scoped_refptr<NGPaintFragment>); NGPaintFragment* Last(); NGPaintFragment* Last(const NGBreakToken&); + static scoped_refptr<NGPaintFragment>* Find(scoped_refptr<NGPaintFragment>*, + const NGBreakToken*); // The parent NGPaintFragment. This is nullptr for a root; i.e., when parent // is not for NGPaint. In the first phase, this means that this is a root of @@ -245,6 +249,12 @@ static bool FlippedLocalVisualRectFor(const LayoutObject*, LayoutRect*); private: + static scoped_refptr<NGPaintFragment> CreateOrReuse( + scoped_refptr<const NGPhysicalFragment> fragment, + NGPhysicalOffset offset, + NGPaintFragment* parent, + scoped_refptr<NGPaintFragment> previous_instance, + bool* populate_children); void PopulateDescendants( const NGPhysicalOffset inline_offset_to_container_box, HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map);
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index 816f943..3902dd4b 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -163,7 +163,8 @@ previous_paint_phase_descendant_block_backgrounds_was_empty_(false), has_descendant_with_clip_path_(false), has_non_isolated_descendant_with_blend_mode_(false), - has_descendant_with_sticky_or_fixed_(false), + has_fixed_position_descendant_(false), + has_sticky_position_descendant_(false), has_non_contained_absolute_position_descendant_(false), self_painting_status_changed_(false), filter_on_effect_node_dirty_(false), @@ -711,7 +712,8 @@ has_visible_descendant_ = false; has_non_isolated_descendant_with_blend_mode_ = false; has_descendant_with_clip_path_ = false; - has_descendant_with_sticky_or_fixed_ = false; + has_fixed_position_descendant_ = false; + has_sticky_position_descendant_ = false; has_non_contained_absolute_position_descendant_ = false; has_self_painting_layer_descendant_ = false; is_non_stacked_with_in_flow_stacked_descendant_ = false; @@ -740,10 +742,12 @@ has_descendant_with_clip_path_ |= child->HasDescendantWithClipPath() || child->GetLayoutObject().HasClipPath(); - has_descendant_with_sticky_or_fixed_ |= - child->HasDescendantWithStickyOrFixed() || - child_style.GetPosition() == EPosition::kSticky || + has_fixed_position_descendant_ |= + child->HasFixedPositionDescendant() || child_style.GetPosition() == EPosition::kFixed; + has_sticky_position_descendant_ |= + child->HasStickyPositionDescendant() || + child_style.GetPosition() == EPosition::kSticky; if (!can_contain_abs) { has_non_contained_absolute_position_descendant_ |=
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h index 9bbbd78..982e962 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.h +++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -830,9 +830,13 @@ DCHECK(!needs_descendant_dependent_flags_update_); return has_descendant_with_clip_path_; } - bool HasDescendantWithStickyOrFixed() const { + bool HasFixedPositionDescendant() const { DCHECK(!needs_descendant_dependent_flags_update_); - return has_descendant_with_sticky_or_fixed_; + return has_fixed_position_descendant_; + } + bool HasStickyPositionDescendant() const { + DCHECK(!needs_descendant_dependent_flags_update_); + return has_sticky_position_descendant_; } bool HasNonContainedAbsolutePositionDescendant() const { DCHECK(!needs_descendant_dependent_flags_update_); @@ -1298,7 +1302,8 @@ // inputs. unsigned has_descendant_with_clip_path_ : 1; unsigned has_non_isolated_descendant_with_blend_mode_ : 1; - unsigned has_descendant_with_sticky_or_fixed_ : 1; + unsigned has_fixed_position_descendant_ : 1; + unsigned has_sticky_position_descendant_ : 1; unsigned has_non_contained_absolute_position_descendant_ : 1; unsigned self_painting_status_changed_ : 1;
diff --git a/third_party/blink/renderer/core/paint/paint_layer_test.cc b/third_party/blink/renderer/core/paint/paint_layer_test.cc index efdd0c3..a56863c 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_test.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -312,7 +312,7 @@ EXPECT_TRUE(parent->HasVisibleDescendant()); } -TEST_P(PaintLayerTest, HasDescendantWithSticky) { +TEST_P(PaintLayerTest, HasStickyPositionDescendant) { SetBodyInnerHTML(R"HTML( <div id='parent' style='isolation: isolate'> <div id='child' style='position: sticky'> @@ -321,18 +321,18 @@ )HTML"); PaintLayer* parent = GetPaintLayerByElementId("parent"); PaintLayer* child = GetPaintLayerByElementId("child"); - EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child->HasDescendantWithStickyOrFixed()); + EXPECT_TRUE(parent->HasStickyPositionDescendant()); + EXPECT_FALSE(child->HasStickyPositionDescendant()); GetDocument().getElementById("child")->setAttribute(HTMLNames::styleAttr, "position: relative"); GetDocument().View()->UpdateAllLifecyclePhases(); - EXPECT_FALSE(parent->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child->HasDescendantWithStickyOrFixed()); + EXPECT_FALSE(parent->HasStickyPositionDescendant()); + EXPECT_FALSE(child->HasStickyPositionDescendant()); } -TEST_P(PaintLayerTest, HasDescendantWithFixed) { +TEST_P(PaintLayerTest, HasFixedPositionDescendant) { SetBodyInnerHTML(R"HTML( <div id='parent' style='isolation: isolate'> <div id='child' style='position: fixed'> @@ -341,18 +341,18 @@ )HTML"); PaintLayer* parent = GetPaintLayerByElementId("parent"); PaintLayer* child = GetPaintLayerByElementId("child"); - EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child->HasDescendantWithStickyOrFixed()); + EXPECT_TRUE(parent->HasFixedPositionDescendant()); + EXPECT_FALSE(child->HasFixedPositionDescendant()); GetDocument().getElementById("child")->setAttribute(HTMLNames::styleAttr, "position: relative"); GetDocument().View()->UpdateAllLifecyclePhases(); - EXPECT_FALSE(parent->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child->HasDescendantWithStickyOrFixed()); + EXPECT_FALSE(parent->HasFixedPositionDescendant()); + EXPECT_FALSE(child->HasFixedPositionDescendant()); } -TEST_P(PaintLayerTest, HasDescendantWithFixedAndSticky) { +TEST_P(PaintLayerTest, HasFixedAndStickyPositionDescendant) { SetBodyInnerHTML(R"HTML( <div id='parent' style='isolation: isolate'> <div id='child1' style='position: sticky'> @@ -364,25 +364,34 @@ PaintLayer* parent = GetPaintLayerByElementId("parent"); PaintLayer* child1 = GetPaintLayerByElementId("child1"); PaintLayer* child2 = GetPaintLayerByElementId("child2"); - EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child1->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child2->HasDescendantWithStickyOrFixed()); + EXPECT_TRUE(parent->HasFixedPositionDescendant()); + EXPECT_FALSE(child1->HasFixedPositionDescendant()); + EXPECT_FALSE(child2->HasFixedPositionDescendant()); + EXPECT_TRUE(parent->HasStickyPositionDescendant()); + EXPECT_FALSE(child1->HasStickyPositionDescendant()); + EXPECT_FALSE(child2->HasStickyPositionDescendant()); GetDocument().getElementById("child1")->setAttribute(HTMLNames::styleAttr, "position: relative"); GetDocument().View()->UpdateAllLifecyclePhases(); - EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child1->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child2->HasDescendantWithStickyOrFixed()); + EXPECT_TRUE(parent->HasFixedPositionDescendant()); + EXPECT_FALSE(child1->HasFixedPositionDescendant()); + EXPECT_FALSE(child2->HasFixedPositionDescendant()); + EXPECT_FALSE(parent->HasStickyPositionDescendant()); + EXPECT_FALSE(child1->HasStickyPositionDescendant()); + EXPECT_FALSE(child2->HasStickyPositionDescendant()); GetDocument().getElementById("child2")->setAttribute(HTMLNames::styleAttr, "position: relative"); GetDocument().View()->UpdateAllLifecyclePhases(); - EXPECT_FALSE(parent->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child1->HasDescendantWithStickyOrFixed()); - EXPECT_FALSE(child2->HasDescendantWithStickyOrFixed()); + EXPECT_FALSE(parent->HasFixedPositionDescendant()); + EXPECT_FALSE(child1->HasFixedPositionDescendant()); + EXPECT_FALSE(child2->HasFixedPositionDescendant()); + EXPECT_FALSE(parent->HasStickyPositionDescendant()); + EXPECT_FALSE(child1->HasStickyPositionDescendant()); + EXPECT_FALSE(child2->HasStickyPositionDescendant()); } TEST_P(PaintLayerTest, HasNonContainedAbsolutePositionDescendant) {
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc index 37edff6..1db6d50 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -732,6 +732,32 @@ return false; } +// An effect node can use the current clip as its output clip if the clip won't +// end before the effect ends. Having explicit output clip can let the later +// stages use more optimized code path. +static bool EffectCanUseCurrentClipAsOutputClip(const LayoutObject& object) { + DCHECK(NeedsEffect(object)); + + if (!object.HasLayer()) { + // An SVG object's effect never interleaves with clips. + DCHECK(object.IsSVG()); + return true; + } + + const auto* layer = ToLayoutBoxModelObject(object).Layer(); + // Out-of-flow descendants not contained by this object may escape clips. + if (layer->HasNonContainedAbsolutePositionDescendant()) + return false; + if (layer->HasFixedPositionDescendant() && + !object.CanContainFixedPositionObjects()) + return false; + // Some descendants under a pagination container (e.g. composited objects + // in SPv1 and column spanners) may escape fragment clips. + if (layer->EnclosingPaginationLayer()) + return false; + return true; +} + void FragmentPaintPropertyTreeBuilder::UpdateEffect() { DCHECK(properties_); const ComputedStyle& style = object_.StyleRef(); @@ -765,10 +791,9 @@ clip_path_clip = IntRect(); } - // Use the current clip as output_clip for SVG children because their - // effects never interleave with clips. - const auto* output_clip = - object_.IsSVGChild() ? context_.current.clip : nullptr; + const auto* output_clip = EffectCanUseCurrentClipAsOutputClip(object_) + ? context_.current.clip + : nullptr; if (mask_clip || clip_path_clip) { IntRect combined_clip = mask_clip ? *mask_clip : *clip_path_clip;
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc index 73c7521..196a6985 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -902,7 +902,8 @@ const ObjectPaintProperties* node_with_opacity_properties = node_with_opacity->FirstFragment().PaintProperties(); EXPECT_EQ(0.6f, node_with_opacity_properties->Effect()->Opacity()); - EXPECT_EQ(nullptr, node_with_opacity_properties->Effect()->OutputClip()); + EXPECT_EQ(DocContentClip(), + node_with_opacity_properties->Effect()->OutputClip()); EXPECT_NE(nullptr, node_with_opacity_properties->Effect()->Parent()); EXPECT_EQ(nullptr, node_with_opacity_properties->Transform()); CHECK_EXACT_VISUAL_RECT(LayoutRect(8, 8, 100, 200), node_with_opacity, @@ -923,7 +924,7 @@ const ObjectPaintProperties* grand_child_with_opacity_properties = grand_child_with_opacity->FirstFragment().PaintProperties(); EXPECT_EQ(0.4f, grand_child_with_opacity_properties->Effect()->Opacity()); - EXPECT_EQ(nullptr, + EXPECT_EQ(DocContentClip(), grand_child_with_opacity_properties->Effect()->OutputClip()); EXPECT_EQ(node_with_opacity_properties->Effect(), grand_child_with_opacity_properties->Effect()->Parent()); @@ -970,7 +971,7 @@ const ObjectPaintProperties* grand_child_with_opacity_properties = grand_child_with_opacity->FirstFragment().PaintProperties(); EXPECT_EQ(0.4f, grand_child_with_opacity_properties->Effect()->Opacity()); - EXPECT_EQ(nullptr, + EXPECT_EQ(DocContentClip(), grand_child_with_opacity_properties->Effect()->OutputClip()); EXPECT_EQ(node_with_opacity_properties->Effect(), grand_child_with_opacity_properties->Effect()->Parent()); @@ -1041,13 +1042,15 @@ const auto* div_with_opacity_properties = PaintPropertiesForElement("divWithOpacity"); EXPECT_EQ(0.2f, div_with_opacity_properties->Effect()->Opacity()); - EXPECT_EQ(nullptr, div_with_opacity_properties->Effect()->OutputClip()); + EXPECT_EQ(DocContentClip(), + div_with_opacity_properties->Effect()->OutputClip()); EXPECT_NE(nullptr, div_with_opacity_properties->Effect()->Parent()); const auto* svg_root_with_opacity_properties = PaintPropertiesForElement("svgRootWithOpacity"); EXPECT_EQ(0.3f, svg_root_with_opacity_properties->Effect()->Opacity()); - EXPECT_EQ(nullptr, svg_root_with_opacity_properties->Effect()->OutputClip()); + EXPECT_EQ(DocContentClip(), + svg_root_with_opacity_properties->Effect()->OutputClip()); EXPECT_EQ(div_with_opacity_properties->Effect(), svg_root_with_opacity_properties->Effect()->Parent()); @@ -1074,7 +1077,8 @@ const auto* svg_root_with_opacity_properties = PaintPropertiesForElement("svgRootWithOpacity"); EXPECT_EQ(0.3f, svg_root_with_opacity_properties->Effect()->Opacity()); - EXPECT_EQ(nullptr, svg_root_with_opacity_properties->Effect()->OutputClip()); + EXPECT_EQ(DocContentClip(), + svg_root_with_opacity_properties->Effect()->OutputClip()); EXPECT_NE(nullptr, svg_root_with_opacity_properties->Effect()->Parent()); const auto* foreign_object_with_opacity_properties = @@ -1088,7 +1092,8 @@ const auto* span_with_opacity_properties = PaintPropertiesForElement("spanWithOpacity"); EXPECT_EQ(0.5f, span_with_opacity_properties->Effect()->Opacity()); - EXPECT_EQ(nullptr, span_with_opacity_properties->Effect()->OutputClip()); + EXPECT_EQ(svg_root_with_opacity_properties->OverflowClip(), + span_with_opacity_properties->Effect()->OutputClip()); EXPECT_EQ(foreign_object_with_opacity_properties->Effect(), span_with_opacity_properties->Effect()->Parent()); }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc index 1d3af47c..b5389d8 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -1338,4 +1338,33 @@ gfx::RectF(100, 700, 200, 200)); } +TEST_P(PaintPropertyTreeUpdateTest, + EffectAndClipWithNonContainedOutOfFlowDescendant) { + SetBodyInnerHTML(R"HTML( + <div id="clip" style="overflow: hidden; width: 100px; height: 100px"> + <div id="effect" style="opacity: 0.5"> + <div id="descendant" style="position: fixed">Fixed</div> + </div> + </div> + )HTML"); + + const auto* clip_properties = PaintPropertiesForElement("clip"); + EXPECT_NE(nullptr, clip_properties->OverflowClip()); + const auto* effect_properties = PaintPropertiesForElement("effect"); + ASSERT_NE(nullptr, effect_properties->Effect()); + // The effect's OutputClip is nullptr because of the fixed descendant. + EXPECT_EQ(nullptr, effect_properties->Effect()->OutputClip()); + + auto* descendant = GetDocument().getElementById("descendant"); + descendant->setAttribute(HTMLNames::styleAttr, "position: relative"); + GetDocument().View()->UpdateAllLifecyclePhases(); + EXPECT_EQ(clip_properties->OverflowClip(), + effect_properties->Effect()->OutputClip()); + + descendant->setAttribute(HTMLNames::styleAttr, "position: absolute"); + GetDocument().View()->UpdateAllLifecyclePhases(); + // The effect's OutputClip is nullptr because of the absolute descendant. + EXPECT_EQ(nullptr, effect_properties->Effect()->OutputClip()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/svg_mask_painter.cc b/third_party/blink/renderer/core/paint/svg_mask_painter.cc index 9e2863a..1920d70 100644 --- a/third_party/blink/renderer/core/paint/svg_mask_painter.cc +++ b/third_party/blink/renderer/core/paint/svg_mask_painter.cc
@@ -20,12 +20,7 @@ SECURITY_DCHECK(!mask_.NeedsLayout()); mask_.ClearInvalidationMask(); - - FloatRect visual_rect = object.VisualRectInLocalSVGCoordinates(); - if (visual_rect.IsEmpty() || !mask_.GetElement()->HasChildren()) - return false; - - return true; + return mask_.GetElement()->HasChildren(); } void SVGMaskPainter::FinishEffect(const LayoutObject& object,
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc index 5241e714..cf2477e 100644 --- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc +++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -746,7 +746,7 @@ if (!async_) { if (GetExecutionContext()->IsDocument() && - !GetDocument()->GetFrame()->IsFeatureEnabled( + !GetDocument()->GetFrame()->DeprecatedIsFeatureEnabled( mojom::FeaturePolicyFeature::kSyncXHR, ReportOptions::kReportOnFailure)) { LogConsoleError(GetExecutionContext(),
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn index 90ac2e9..0bd9a1f 100644 --- a/third_party/blink/renderer/modules/BUILD.gn +++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -143,6 +143,7 @@ "//third_party/blink/renderer/modules/remoteplayback", "//third_party/blink/renderer/modules/screen_orientation", "//third_party/blink/renderer/modules/sensor", + "//third_party/blink/renderer/modules/serial", "//third_party/blink/renderer/modules/service_worker", "//third_party/blink/renderer/modules/shapedetection", "//third_party/blink/renderer/modules/speech",
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc index 32aeb52..e9e23221 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -35,10 +35,8 @@ #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h" #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" -#include "third_party/skia/include/core/SkColorSpaceXform.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkSurface.h" -#include "third_party/skia/include/core/SkSwizzle.h" using testing::_; using testing::InSequence; @@ -811,29 +809,6 @@ Mock::VerifyAndClearExpectations(surface_ptr); } -enum class ColorSpaceConversion : uint8_t { - NONE = 0, - DEFAULT_COLOR_CORRECTED = 1, - SRGB = 2, - LINEAR_RGB = 3, - P3 = 4, - REC2020 = 5, - - LAST = REC2020 -}; - -static ImageBitmapOptions PrepareBitmapOptionsAndSetRuntimeFlags( - const ColorSpaceConversion& color_space_conversion) { - // Set the color space conversion in ImageBitmapOptions - ImageBitmapOptions options; - static const Vector<String> kConversions = { - "none", "default", "srgb", "linear-rgb", "p3", "rec2020"}; - options.setColorSpaceConversion( - kConversions[static_cast<uint8_t>(color_space_conversion)]); - - return options; -} - TEST_F(CanvasRenderingContext2DTest, ImageBitmapColorSpaceConversion) { Persistent<HTMLCanvasElement> canvas = Persistent<HTMLCanvasElement>(CanvasElement()); @@ -845,89 +820,62 @@ StringOrCanvasGradientOrCanvasPattern fill_style; fill_style.SetString("#FFC08040"); // 255,192,128,64 context->setFillStyle(fill_style); - context->fillRect(0, 0, 4, 4); - NonThrowableExceptionState exception_state; - uint8_t* src_pixel = - context->getImageData(2, 2, 1, 1, exception_state)->data()->Data(); + context->fillRect(0, 0, 1, 1); + scoped_refptr<StaticBitmapImage> snapshot = + canvas->Snapshot(kFrontBuffer, kPreferNoAcceleration); + ASSERT_TRUE(snapshot); + sk_sp<SkImage> source_image = + snapshot->PaintImageForCurrentFrame().GetSkImage(); + SkPixmap source_pixmap; + source_image->peekPixels(&source_pixmap); // Create and test the ImageBitmap objects. - base::Optional<IntRect> crop_rect = IntRect(0, 0, 4, 4); - sk_sp<SkColorSpace> color_space = nullptr; - SkColorType color_type = SkColorType::kRGBA_8888_SkColorType; - SkColorSpaceXform::ColorFormat color_format32 = - SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat; - SkColorSpaceXform::ColorFormat color_format = color_format32; - sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB(); - - for (uint8_t i = - static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED); - i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) { - ColorSpaceConversion color_space_conversion = - static_cast<ColorSpaceConversion>(i); - - switch (color_space_conversion) { - case ColorSpaceConversion::NONE: - NOTREACHED(); - break; - case ColorSpaceConversion::DEFAULT_COLOR_CORRECTED: - case ColorSpaceConversion::SRGB: - color_space = SkColorSpace::MakeSRGB(); - color_format = color_format32; - break; - case ColorSpaceConversion::LINEAR_RGB: - color_space = SkColorSpace::MakeSRGBLinear(); - color_type = SkColorType::kRGBA_F16_SkColorType; - color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat; - break; - case ColorSpaceConversion::P3: - color_space = - SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kDCIP3_D65_Gamut); - color_type = SkColorType::kRGBA_F16_SkColorType; - color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat; - break; - case ColorSpaceConversion::REC2020: - color_space = - SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kRec2020_Gamut); - color_type = SkColorType::kRGBA_F16_SkColorType; - color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat; - break; - default: - NOTREACHED(); - } - + base::Optional<IntRect> crop_rect = IntRect(0, 0, 1, 1); + for (int conversion_iterator = kColorSpaceConversion_Default; + conversion_iterator <= kColorSpaceConversion_Last; + conversion_iterator++) { // Color convert using ImageBitmap - ImageBitmapOptions options = - PrepareBitmapOptionsAndSetRuntimeFlags(color_space_conversion); + ImageBitmapOptions options; + options.setColorSpaceConversion( + ColorCorrectionTestUtils::ColorSpaceConversionToString( + static_cast<ColorSpaceConversion>(conversion_iterator))); ImageBitmap* image_bitmap = ImageBitmap::Create(canvas, crop_rect, options); ASSERT_TRUE(image_bitmap); sk_sp<SkImage> converted_image = image_bitmap->BitmapImage()->PaintImageForCurrentFrame().GetSkImage(); ASSERT_TRUE(converted_image); - SkImageInfo image_info = - SkImageInfo::Make(1, 1, color_type, SkAlphaType::kUnpremul_SkAlphaType, - converted_image->refColorSpace()); - std::unique_ptr<uint8_t[]> converted_pixel( - new uint8_t[image_info.bytesPerPixel()]()); - EXPECT_TRUE(converted_image->readPixels(image_info, converted_pixel.get(), - image_info.minRowBytes(), 2, 2)); + SkPixmap converted_pixmap; + converted_image->peekPixels(&converted_pixmap); - // Transform the source pixel and check if the image bitmap color conversion - // is done correctly. - std::unique_ptr<SkColorSpaceXform> color_space_xform = - SkColorSpaceXform::New(src_rgb_color_space.get(), color_space.get()); - std::unique_ptr<uint8_t[]> transformed_pixel( - new uint8_t[image_info.bytesPerPixel()]()); - EXPECT_TRUE(color_space_xform->apply(color_format, transformed_pixel.get(), - color_format32, src_pixel, 1, - SkAlphaType::kUnpremul_SkAlphaType)); + // Manual color convert for testing + sk_sp<SkColorSpace> color_space = + ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace( + static_cast<ColorSpaceConversion>(conversion_iterator)); + if (conversion_iterator == kColorSpaceConversion_Preserve) + color_space = SkColorSpace::MakeSRGB(); + + // TODO: crbug.com/768855: Remove if statement when CanvasResourceProvider + // does not use SkColorSpaceXformCanvas (which rips off sRGB from + // ImageBitmap). + if (!color_space->isSRGB()) { + EXPECT_TRUE(SkColorSpace::Equals(color_space.get(), + converted_image->colorSpace())); + } + + SkColorType color_type = SkColorType::kN32_SkColorType; + if (color_space && color_space->gammaIsLinear()) + color_type = kRGBA_F16_SkColorType; + SkImageInfo image_info = SkImageInfo::Make( + 1, 1, color_type, SkAlphaType::kPremul_SkAlphaType, color_space); + SkBitmap manual_converted_bitmap; + EXPECT_TRUE(manual_converted_bitmap.tryAllocPixels(image_info)); + source_pixmap.readPixels(manual_converted_bitmap.pixmap(), 0, 0); ColorCorrectionTestUtils::CompareColorCorrectedPixels( - converted_pixel.get(), transformed_pixel.get(), 1, - (color_type == kRGBA_8888_SkColorType) ? kPixelFormat_8888 - : kPixelFormat_hhhh, - kAlphaUnmultiplied, kUnpremulRoundTripTolerance); + converted_pixmap.addr(), manual_converted_bitmap.pixmap().addr(), 1, + (color_type == kN32_SkColorType) ? kPixelFormat_8888 + : kPixelFormat_hhhh, + kAlphaMultiplied, kNoUnpremulRoundTripTolerance); } }
diff --git a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc index 22e969f3..6bdb1ba 100644 --- a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc +++ b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -303,7 +303,7 @@ Document* document = ToDocument(execution_context); if (!document->GetFrame() || - !document->GetFrame()->IsFeatureEnabled( + !document->GetFrame()->DeprecatedIsFeatureEnabled( mojom::FeaturePolicyFeature::kEncryptedMedia)) { UseCounter::Count(document, WebFeature::kEncryptedMediaDisabledByFeaturePolicy);
diff --git a/third_party/blink/renderer/modules/event_target_modules_names.json5 b/third_party/blink/renderer/modules/event_target_modules_names.json5 index 38ae796..433fd83 100644 --- a/third_party/blink/renderer/modules/event_target_modules_names.json5 +++ b/third_party/blink/renderer/modules/event_target_modules_names.json5
@@ -41,6 +41,7 @@ "modules/remoteplayback/RemotePlayback", "modules/screen_orientation/ScreenOrientation", "modules/sensor/Sensor", + "modules/serial/Serial", "modules/service_worker/ServiceWorker", "modules/service_worker/ServiceWorkerContainer", "modules/service_worker/ServiceWorkerGlobalScope",
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_system.cc b/third_party/blink/renderer/modules/filesystem/dom_file_system.cc index 34cd458..9d079872 100644 --- a/third_party/blink/renderer/modules/filesystem/dom_file_system.cc +++ b/third_party/blink/renderer/modules/filesystem/dom_file_system.cc
@@ -33,7 +33,6 @@ #include <memory> #include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_file_system.h" #include "third_party/blink/public/platform/web_security_origin.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/modules/filesystem/directory_entry.h" @@ -150,7 +149,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks = FileWriterCallbacks::Create(file_writer, success_callback, error_callback, context_); - FileSystemDispatcher::GetThreadSpecificInstance().InitializeFileWriter( + FileSystemDispatcher::From(context_).InitializeFileWriter( CreateFileSystemURL(file_entry), std::move(callbacks)); } @@ -160,7 +159,7 @@ ErrorCallbackBase* error_callback) { KURL file_system_url = CreateFileSystemURL(file_entry); - FileSystemDispatcher::GetThreadSpecificInstance().CreateSnapshotFile( + FileSystemDispatcher::From(context_).CreateSnapshotFile( file_system_url, SnapshotFileCallback::Create(this, file_entry->name(), file_system_url, success_callback, error_callback, context_));
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc b/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc index 0dc350b..98e1a65 100644 --- a/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc +++ b/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc
@@ -32,7 +32,6 @@ #include <memory> #include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_file_system.h" #include "third_party/blink/public/platform/web_security_origin.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fileapi/file.h" @@ -73,13 +72,6 @@ ScriptWrappable::Trace(visitor); } -WebFileSystem* DOMFileSystemBase::FileSystem() const { - Platform* platform = Platform::Current(); - if (!platform) - return nullptr; - return platform->FileSystem(); -} - const SecurityOrigin* DOMFileSystemBase::GetSecurityOrigin() const { return context_->GetSecurityOrigin(); } @@ -219,8 +211,7 @@ SynchronousType synchronous_type) { std::unique_ptr<AsyncFileSystemCallbacks> callbacks(MetadataCallbacks::Create( success_callback, error_callback, context_, this)); - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); if (synchronous_type == kSynchronous) { dispatcher.ReadMetadataSync(CreateFileSystemURL(entry), @@ -285,8 +276,7 @@ success_callback, error_callback, context_, parent->filesystem(), destination_path, source->isDirectory())); - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); const KURL& src = CreateFileSystemURL(source); const KURL& dest = parent->filesystem()->CreateFileSystemURL(destination_path); @@ -317,8 +307,7 @@ const KURL& src = CreateFileSystemURL(source); const KURL& dest = parent->filesystem()->CreateFileSystemURL(destination_path); - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); if (synchronous_type == kSynchronous) dispatcher.CopySync(src, dest, std::move(callbacks)); else @@ -340,8 +329,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks( VoidCallbacks::Create(success_callback, error_callback, context_, this)); const KURL& url = CreateFileSystemURL(entry); - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); if (synchronous_type == kSynchronous) dispatcher.RemoveSync(url, /*recursive=*/false, std::move(callbacks)); else @@ -364,8 +352,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks( VoidCallbacks::Create(success_callback, error_callback, context_, this)); const KURL& url = CreateFileSystemURL(entry); - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); if (synchronous_type == kSynchronous) dispatcher.RemoveSync(url, /*recursive=*/true, std::move(callbacks)); else @@ -379,7 +366,7 @@ DCHECK(entry); String path = DOMFilePath::GetDirectory(entry->fullPath()); - FileSystemDispatcher::GetThreadSpecificInstance().Exists( + FileSystemDispatcher::From(context_).Exists( CreateFileSystemURL(path), /*is_directory=*/true, EntryCallbacks::Create(success_callback, error_callback, context_, this, path, true)); @@ -401,8 +388,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::Create( success_callback, error_callback, context_, this, absolute_path, false)); const KURL& url = CreateFileSystemURL(absolute_path); - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); if (flags.createFlag()) { if (synchronous_type == kSynchronous) @@ -434,8 +420,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::Create( success_callback, error_callback, context_, this, absolute_path, true)); const KURL& url = CreateFileSystemURL(absolute_path); - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); if (flags.createFlag()) { if (synchronous_type == kSynchronous) { @@ -464,8 +449,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntriesCallbacks::Create( success_callback, error_callback, context_, reader, path)); - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); const KURL& url = CreateFileSystemURL(path); if (synchronous_type == kSynchronous) { dispatcher.ReadDirectorySync(url, std::move(callbacks));
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h b/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h index 643929f..83452e2 100644 --- a/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h +++ b/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h
@@ -42,10 +42,6 @@ #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { -class WebFileSystem; -} // namespace blink - -namespace blink { class DirectoryReaderBase; class EntryBase; @@ -83,7 +79,6 @@ const String& name() const { return name_; } mojom::blink::FileSystemType GetType() const { return type_; } KURL RootURL() const { return filesystem_root_url_; } - WebFileSystem* FileSystem() const; const SecurityOrigin* GetSecurityOrigin() const; // The clonable flag is used in the structured clone algorithm to test
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc b/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc index 08b3747..1d1b6e1 100644 --- a/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc +++ b/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc
@@ -33,7 +33,6 @@ #include <memory> #include "base/memory/ptr_util.h" -#include "third_party/blink/public/platform/web_file_system.h" #include "third_party/blink/renderer/core/fileapi/file.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" #include "third_party/blink/renderer/modules/filesystem/directory_entry_sync.h" @@ -140,7 +139,7 @@ KURL file_system_url = CreateFileSystemURL(file_entry); CreateFileHelper::CreateFileResult* result( CreateFileHelper::CreateFileResult::Create()); - FileSystemDispatcher::GetThreadSpecificInstance().CreateSnapshotFileSync( + FileSystemDispatcher::From(context_).CreateSnapshotFileSync( file_system_url, CreateFileHelper::Create(result, file_entry->name(), file_system_url, GetType())); if (result->failed_) { @@ -157,7 +156,7 @@ ExceptionState& exception_state) { DCHECK(file_entry); - FileWriterSync* file_writer = FileWriterSync::Create(); + FileWriterSync* file_writer = FileWriterSync::Create(context_); FileWriterCallbacksSyncHelper* sync_helper = FileWriterCallbacksSyncHelper::Create(); @@ -166,7 +165,7 @@ sync_helper->GetSuccessCallback(), sync_helper->GetErrorCallback(), context_); - FileSystemDispatcher::GetThreadSpecificInstance().InitializeFileWriterSync( + FileSystemDispatcher::From(context_).InitializeFileWriterSync( CreateFileSystemURL(file_entry), std::move(callbacks)); FileWriterBase* success = sync_helper->GetResultOrThrow(exception_state);
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc index 1130460b..ec80085 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc +++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
@@ -5,9 +5,10 @@ #include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" #include "build/build_config.h" +#include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/platform/file_path_conversion.h" -#include "third_party/blink/public/platform/interface_provider.h" #include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -68,23 +69,34 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks_; }; -FileSystemDispatcher::FileSystemDispatcher() : next_operation_id_(1) {} +FileSystemDispatcher::FileSystemDispatcher(ExecutionContext& context) + : Supplement<ExecutionContext>(context), next_operation_id_(1) {} // static -FileSystemDispatcher& FileSystemDispatcher::GetThreadSpecificInstance() { - DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<FileSystemDispatcher>, - file_system_dispatcher, ()); - return *file_system_dispatcher; +const char FileSystemDispatcher::kSupplementName[] = "FileSystemDispatcher"; + +// static +FileSystemDispatcher& FileSystemDispatcher::From(ExecutionContext* context) { + DCHECK(context); + FileSystemDispatcher* dispatcher = + Supplement<ExecutionContext>::From<FileSystemDispatcher>(context); + if (!dispatcher) { + dispatcher = new FileSystemDispatcher(*context); + Supplement<ExecutionContext>::ProvideTo(*context, dispatcher); + } + return *dispatcher; } +FileSystemDispatcher::~FileSystemDispatcher() = default; + void FileSystemDispatcher::OpenFileSystem( const KURL& origin_url, mojom::blink::FileSystemType type, std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().Open( origin_url, type, - WTF::Bind(&FileSystemDispatcher::DidOpenFileSystem, WTF::Unretained(this), - std::move(callbacks))); + WTF::Bind(&FileSystemDispatcher::DidOpenFileSystem, + WrapWeakPersistent(this), std::move(callbacks))); } void FileSystemDispatcher::OpenFileSystemSync( @@ -103,8 +115,9 @@ const KURL& filesystem_url, std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().ResolveURL( - filesystem_url, WTF::Bind(&FileSystemDispatcher::DidResolveURL, - WTF::Unretained(this), std::move(callbacks))); + filesystem_url, + WTF::Bind(&FileSystemDispatcher::DidResolveURL, WrapWeakPersistent(this), + std::move(callbacks))); } void FileSystemDispatcher::ResolveURLSync( @@ -126,7 +139,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().Move( src_path, dest_path, - WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this), + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), std::move(callbacks))); } @@ -145,7 +158,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().Copy( src_path, dest_path, - WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this), + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), std::move(callbacks))); } @@ -164,7 +177,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().Remove( path, recursive, - WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this), + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), std::move(callbacks))); } @@ -182,7 +195,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().ReadMetadata( path, WTF::Bind(&FileSystemDispatcher::DidReadMetadata, - WTF::Unretained(this), std::move(callbacks))); + WrapWeakPersistent(this), std::move(callbacks))); } void FileSystemDispatcher::ReadMetadataSync( @@ -200,7 +213,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().Create( path, exclusive, /*is_directory=*/false, /*is_recursive=*/false, - WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this), + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), std::move(callbacks))); } @@ -221,7 +234,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().Create( path, exclusive, /*is_directory=*/true, recursive, - WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this), + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), std::move(callbacks))); } @@ -242,7 +255,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().Exists( path, is_directory, - WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this), + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), std::move(callbacks))); } @@ -284,7 +297,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().ReadMetadata( path, WTF::Bind(&FileSystemDispatcher::InitializeFileWriterCallback, - WTF::Unretained(this), path, std::move(callbacks))); + WrapWeakPersistent(this), path, std::move(callbacks))); } void FileSystemDispatcher::InitializeFileWriterSync( @@ -307,11 +320,11 @@ int operation_id = next_operation_id_++; op_ptr.set_connection_error_handler( WTF::Bind(&FileSystemDispatcher::RemoveOperationPtr, - WTF::Unretained(this), operation_id)); + WrapWeakPersistent(this), operation_id)); cancellable_operations_.insert(operation_id, std::move(op_ptr)); GetFileSystemManager().Truncate( path, offset, std::move(op_request), - WTF::Bind(&FileSystemDispatcher::DidTruncate, WTF::Unretained(this), + WTF::Bind(&FileSystemDispatcher::DidTruncate, WrapWeakPersistent(this), operation_id, std::move(callback))); if (request_id_out) @@ -338,7 +351,7 @@ int operation_id = next_operation_id_++; op_ptr.set_connection_error_handler( WTF::Bind(&FileSystemDispatcher::RemoveOperationPtr, - WTF::Unretained(this), operation_id)); + WrapWeakPersistent(this), operation_id)); cancellable_operations_.insert(operation_id, std::move(op_ptr)); mojom::blink::FileSystemOperationListenerPtr listener_ptr; @@ -379,7 +392,7 @@ } cancellable_operations_.find(request_id_to_cancel) ->value->Cancel(WTF::Bind(&FileSystemDispatcher::DidCancel, - WTF::Unretained(this), std::move(callback), + WrapWeakPersistent(this), std::move(callback), request_id_to_cancel)); } @@ -388,7 +401,7 @@ std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { GetFileSystemManager().CreateSnapshotFile( file_path, WTF::Bind(&FileSystemDispatcher::DidCreateSnapshotFile, - WTF::Unretained(this), std::move(callbacks))); + WrapWeakPersistent(this), std::move(callbacks))); } void FileSystemDispatcher::CreateSnapshotFileSync( @@ -422,9 +435,24 @@ std::move(callbacks))); } +void FileSystemDispatcher::ChooseEntry( + std::unique_ptr<ChooseEntryCallbacks> callbacks) { + GetFileSystemManager().ChooseEntry(WTF::Bind( + [](std::unique_ptr<ChooseEntryCallbacks> callbacks, + base::File::Error result, + Vector<mojom::blink::FileSystemEntryPtr> entries) { + if (result != base::File::FILE_OK) { + callbacks->OnError(result); + } else { + callbacks->OnSuccess(std::move(entries)); + } + }, + std::move(callbacks))); +} + mojom::blink::FileSystemManager& FileSystemDispatcher::GetFileSystemManager() { if (!file_system_manager_ptr_) { - Platform::Current()->GetInterfaceProvider()->GetInterface( + GetSupplementable()->GetInterfaceProvider()->GetInterface( mojo::MakeRequest(&file_system_manager_ptr_)); } return *file_system_manager_ptr_;
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h index 2b3b33a..d8a899a 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h +++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
@@ -10,6 +10,7 @@ #include "third_party/blink/public/platform/web_callbacks.h" #include "third_party/blink/renderer/platform/async_file_system_callbacks.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/supplementable.h" namespace WTF { class String; @@ -18,18 +19,25 @@ namespace blink { class KURL; +class ExecutionContext; // Sends messages via mojo to the blink::mojom::FileSystemManager service -// running in the browser process. It is currently created and stored in a -// thread local variable. A thread specific instance can be obtained using -// GetThreadSpecificInstance(). -class FileSystemDispatcher { +// running in the browser process. It is owned by ExecutionContext, and +// instances are created lazily by calling FileSystemDispatcher::From(). +class FileSystemDispatcher + : public GarbageCollectedFinalized<FileSystemDispatcher>, + public Supplement<ExecutionContext> { + USING_GARBAGE_COLLECTED_MIXIN(FileSystemDispatcher); + public: using StatusCallback = base::OnceCallback<void(base::File::Error error)>; using WriteCallback = base::RepeatingCallback<void(int64_t bytes, bool complete)>; - static FileSystemDispatcher& GetThreadSpecificInstance(); + static const char kSupplementName[]; + + static FileSystemDispatcher& From(ExecutionContext* context); + virtual ~FileSystemDispatcher(); void OpenFileSystem(const KURL& url, mojom::blink::FileSystemType type, @@ -133,12 +141,15 @@ void CreateFileWriter(const KURL& file_path, std::unique_ptr<CreateFileWriterCallbacks>); + using ChooseEntryCallbacks = + WebCallbacks<Vector<mojom::blink::FileSystemEntryPtr>, base::File::Error>; + void ChooseEntry(std::unique_ptr<ChooseEntryCallbacks> callbacks); + private: class WriteListener; class ReadDirectoryListener; - friend class WTF::ThreadSpecific<FileSystemDispatcher>; - FileSystemDispatcher(); + explicit FileSystemDispatcher(ExecutionContext& context); mojom::blink::FileSystemManager& GetFileSystemManager();
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc b/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc index 5775e5c..2b66212 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc +++ b/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc
@@ -60,9 +60,9 @@ ScriptPromise FileSystemFileHandle::createWriter(ScriptState* script_state) { auto* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise result = resolver->Promise(); - FileSystemDispatcher::GetThreadSpecificInstance().CreateFileWriter( - filesystem()->CreateFileSystemURL(this), - std::make_unique<CreateWriterCallbacks>(resolver)); + FileSystemDispatcher::From(ExecutionContext::From(script_state)) + .CreateFileWriter(filesystem()->CreateFileSystemURL(this), + std::make_unique<CreateWriterCallbacks>(resolver)); return result; } @@ -70,12 +70,13 @@ auto* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise result = resolver->Promise(); KURL file_system_url = filesystem()->CreateFileSystemURL(this); - FileSystemDispatcher::GetThreadSpecificInstance().CreateSnapshotFile( - file_system_url, - SnapshotFileCallback::Create(filesystem(), name(), file_system_url, - new OnDidCreateSnapshotFilePromise(resolver), - new PromiseErrorCallback(resolver), - ExecutionContext::From(script_state))); + FileSystemDispatcher::From(ExecutionContext::From(script_state)) + .CreateSnapshotFile(file_system_url, + SnapshotFileCallback::Create( + filesystem(), name(), file_system_url, + new OnDidCreateSnapshotFilePromise(resolver), + new PromiseErrorCallback(resolver), + ExecutionContext::From(script_state))); return result; }
diff --git a/third_party/blink/renderer/modules/filesystem/file_writer.cc b/third_party/blink/renderer/modules/filesystem/file_writer.cc index 56e910f..427f69d 100644 --- a/third_party/blink/renderer/modules/filesystem/file_writer.cc +++ b/third_party/blink/renderer/modules/filesystem/file_writer.cc
@@ -225,23 +225,25 @@ } void FileWriter::DoTruncate(const KURL& path, int64_t offset) { - FileSystemDispatcher::GetThreadSpecificInstance().Truncate( - path, offset, &request_id_, - WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this))); + FileSystemDispatcher::From(GetExecutionContext()) + .Truncate(path, offset, &request_id_, + WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this))); } void FileWriter::DoWrite(const KURL& path, const String& blob_id, int64_t offset) { - FileSystemDispatcher::GetThreadSpecificInstance().Write( - path, blob_id, offset, &request_id_, - WTF::BindRepeating(&FileWriter::DidWrite, WrapWeakPersistent(this)), - WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this))); + FileSystemDispatcher::From(GetExecutionContext()) + .Write( + path, blob_id, offset, &request_id_, + WTF::BindRepeating(&FileWriter::DidWrite, WrapWeakPersistent(this)), + WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this))); } void FileWriter::DoCancel() { - FileSystemDispatcher::GetThreadSpecificInstance().Cancel( - request_id_, WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this))); + FileSystemDispatcher::From(GetExecutionContext()) + .Cancel(request_id_, + WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this))); } void FileWriter::CompleteAbort() { @@ -328,6 +330,8 @@ DoOperation(kOperationAbort); ready_state_ = kDone; } + // Prevents any queued operations from running after abort completes. + queued_operation_ = kOperationNone; } void FileWriter::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc b/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc index 3242da55..e9c20b16 100644 --- a/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc +++ b/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc
@@ -98,26 +98,33 @@ } void FileWriterSync::DoTruncate(const KURL& path, int64_t offset) { - FileSystemDispatcher::GetThreadSpecificInstance().TruncateSync( - path, offset, - WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this))); + if (!GetExecutionContext()) + return; + FileSystemDispatcher::From(GetExecutionContext()) + .TruncateSync( + path, offset, + WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this))); } void FileWriterSync::DoWrite(const KURL& path, const String& blob_id, int64_t offset) { - FileSystemDispatcher::GetThreadSpecificInstance().WriteSync( - path, blob_id, offset, - WTF::BindRepeating(&FileWriterSync::DidWrite, WrapWeakPersistent(this)), - WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this))); + if (!GetExecutionContext()) + return; + FileSystemDispatcher::From(GetExecutionContext()) + .WriteSync( + path, blob_id, offset, + WTF::BindRepeating(&FileWriterSync::DidWrite, + WrapWeakPersistent(this)), + WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this))); } void FileWriterSync::DoCancel() { NOTREACHED(); } -FileWriterSync::FileWriterSync() - : error_(base::File::FILE_OK), complete_(true) {} +FileWriterSync::FileWriterSync(ExecutionContext* context) + : ContextClient(context), error_(base::File::FILE_OK), complete_(true) {} void FileWriterSync::PrepareForWrite() { DCHECK(complete_); @@ -130,6 +137,7 @@ void FileWriterSync::Trace(blink::Visitor* visitor) { ScriptWrappable::Trace(visitor); FileWriterBase::Trace(visitor); + ContextClient::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/filesystem/file_writer_sync.h b/third_party/blink/renderer/modules/filesystem/file_writer_sync.h index 4a8002a..6561606 100644 --- a/third_party/blink/renderer/modules/filesystem/file_writer_sync.h +++ b/third_party/blink/renderer/modules/filesystem/file_writer_sync.h
@@ -31,6 +31,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_WRITER_SYNC_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_WRITER_SYNC_H_ +#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" #include "third_party/blink/renderer/modules/filesystem/file_writer_base.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -41,12 +42,16 @@ class Blob; class ExceptionState; -class FileWriterSync final : public ScriptWrappable, public FileWriterBase { +class FileWriterSync final : public ScriptWrappable, + public FileWriterBase, + public ContextClient { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(FileWriterSync); public: - static FileWriterSync* Create() { return new FileWriterSync(); } + static FileWriterSync* Create(ExecutionContext* context) { + return new FileWriterSync(context); + } ~FileWriterSync() override; void Trace(blink::Visitor*) override; @@ -65,7 +70,7 @@ void DoCancel() override; private: - FileWriterSync(); + explicit FileWriterSync(ExecutionContext* context); void PrepareForWrite(); base::File::Error error_;
diff --git a/third_party/blink/renderer/modules/filesystem/local_file_system.cc b/third_party/blink/renderer/modules/filesystem/local_file_system.cc index 0a7e003..29c34b3 100644 --- a/third_party/blink/renderer/modules/filesystem/local_file_system.cc +++ b/third_party/blink/renderer/modules/filesystem/local_file_system.cc
@@ -35,7 +35,6 @@ #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" -#include "third_party/blink/public/platform/web_file_system.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" @@ -116,12 +115,14 @@ namespace { -class ChooseEntryCallbacks : public WebFileSystem::ChooseEntryCallbacks { +class ChooseEntryCallbacks + : public WebCallbacks<Vector<mojom::blink::FileSystemEntryPtr>, + base::File::Error> { public: ChooseEntryCallbacks(ScriptPromiseResolver* resolver, bool return_multiple) : resolver_(resolver), return_multiple_(return_multiple) {} - void OnSuccess(WebVector<WebFileSystem::FileSystemEntry> entries) override { + void OnSuccess(Vector<mojom::blink::FileSystemEntryPtr> entries) override { ScriptState::Scope scope(resolver_->GetScriptState()); if (return_multiple_) { Vector<ScriptPromise> result; @@ -141,15 +142,16 @@ } private: - ScriptPromise CreateFileHandle(const WebFileSystem::FileSystemEntry& entry) { + ScriptPromise CreateFileHandle( + const mojom::blink::FileSystemEntryPtr& entry) { auto* new_resolver = ScriptPromiseResolver::Create(resolver_->GetScriptState()); ScriptPromise result = new_resolver->Promise(); auto* fs = DOMFileSystem::CreateIsolatedFileSystem( - resolver_->GetExecutionContext(), entry.file_system_id); + resolver_->GetExecutionContext(), entry->file_system_id); // TODO(mek): Try to create handle directly rather than having to do more // IPCs to get the actual entries. - fs->GetFile(fs->root(), entry.base_name, FileSystemFlags(), + fs->GetFile(fs->root(), entry->base_name, FileSystemFlags(), new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver), new PromiseErrorCallback(new_resolver)); return result; @@ -168,24 +170,8 @@ return; } - WebFileSystem* file_system = GetFileSystem(); - if (!file_system) { - resolver->Reject( - FileError::CreateDOMException(base::File::FILE_ERROR_ABORT)); - return; - } - - file_system->ChooseEntry( - Supplement<LocalFrame>::GetSupplementable()->Client()->GetWebFrame(), - std::make_unique<ChooseEntryCallbacks>(resolver, false)); -} - -WebFileSystem* LocalFileSystem::GetFileSystem() const { - Platform* platform = Platform::Current(); - if (!platform) - return nullptr; - - return platform->FileSystem(); + FileSystemDispatcher::From(resolver->GetExecutionContext()) + .ChooseEntry(std::make_unique<ChooseEntryCallbacks>(resolver, false)); } void LocalFileSystem::RequestFileSystemAccessInternal( @@ -230,8 +216,7 @@ KURL(NullURL(), context->GetSecurityOrigin()->ToString()); std::unique_ptr<AsyncFileSystemCallbacks> async_callbacks = callbacks->Release(); - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context); if (sync_type == kSynchronous) { dispatcher.OpenFileSystemSync(storage_partition, type, std::move(async_callbacks)); @@ -245,8 +230,7 @@ const KURL& file_system_url, CallbackWrapper* callbacks, SynchronousType sync_type) { - FileSystemDispatcher& dispatcher = - FileSystemDispatcher::GetThreadSpecificInstance(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context); std::unique_ptr<AsyncFileSystemCallbacks> async_callbacks = callbacks->Release(); if (sync_type == kSynchronous) {
diff --git a/third_party/blink/renderer/modules/filesystem/local_file_system.h b/third_party/blink/renderer/modules/filesystem/local_file_system.h index b3e2823b..b137d0e9 100644 --- a/third_party/blink/renderer/modules/filesystem/local_file_system.h +++ b/third_party/blink/renderer/modules/filesystem/local_file_system.h
@@ -49,7 +49,6 @@ class ExecutionContext; class KURL; class ScriptPromiseResolver; -class WebFileSystem; class LocalFileSystem final : public GarbageCollectedFinalized<LocalFileSystem>, public Supplement<LocalFrame>, @@ -87,7 +86,6 @@ const char* NameInHeapSnapshot() const override { return "LocalFileSystem"; } private: - WebFileSystem* GetFileSystem() const; void FileSystemNotAvailable(ExecutionContext*, CallbackWrapper*); void RequestFileSystemAccessInternal(ExecutionContext*,
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation.cc b/third_party/blink/renderer/modules/geolocation/geolocation.cc index b5b0363..c0eda1e 100644 --- a/third_party/blink/renderer/modules/geolocation/geolocation.cc +++ b/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -224,8 +224,9 @@ return; } - if (!GetFrame()->IsFeatureEnabled(mojom::FeaturePolicyFeature::kGeolocation, - ReportOptions::kReportOnFailure)) { + if (!GetFrame()->DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature::kGeolocation, + ReportOptions::kReportOnFailure)) { UseCounter::Count(GetDocument(), WebFeature::kGeolocationDisabledByFeaturePolicy); GetDocument()->AddConsoleMessage(ConsoleMessage::Create(
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc index 64361af..09a493d 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc +++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -492,7 +492,7 @@ // Feature policy deprecation messages. if (Audio()) { - if (!document->GetFrame()->IsFeatureEnabled( + if (!document->GetFrame()->DeprecatedIsFeatureEnabled( mojom::FeaturePolicyFeature::kMicrophone, ReportOptions::kReportOnFailure)) { UseCounter::Count( @@ -500,7 +500,7 @@ } } if (Video()) { - if (!document->GetFrame()->IsFeatureEnabled( + if (!document->GetFrame()->DeprecatedIsFeatureEnabled( mojom::FeaturePolicyFeature::kCamera, ReportOptions::kReportOnFailure)) { UseCounter::Count(document,
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index eccdc9d..928eb865 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -272,6 +272,8 @@ "sensor/relative_orientation_sensor.idl", "sensor/sensor.idl", "sensor/sensor_error_event.idl", + "serial/serial.idl", + "serial/serial_port.idl", "service_worker/client.idl", "service_worker/clients.idl", "service_worker/extendable_event.idl", @@ -635,6 +637,8 @@ "sensor/sensor_error_event_init.idl", "sensor/sensor_options.idl", "sensor/spatial_sensor_options.idl", + "serial/serial_options.idl", + "serial/serial_port_request_options.idl", "service_worker/client_query_options.idl", "service_worker/extendable_event_init.idl", "service_worker/extendable_message_event_init.idl", @@ -777,6 +781,8 @@ "quota/worker_navigator_storage_quota.idl", "remoteplayback/html_media_element_remote_playback.idl", "screen_orientation/screen_screen_orientation.idl", + "serial/navigator_serial.idl", + "serial/worker_navigator_serial.idl", "service_worker/navigator_service_worker.idl", "speech/window_speech.idl", "speech/window_speech_synthesis.idl",
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc index 295bb34..1fbfcaf 100644 --- a/third_party/blink/renderer/modules/payments/payment_request.cc +++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -750,8 +750,8 @@ return false; // 2. If Feature Policy is enabled, return the policy for "payment" feature. - return frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kPayment, - ReportOptions::kReportOnFailure); + return frame->DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature::kPayment, ReportOptions::kReportOnFailure); } void WarnIgnoringQueryQuotaForCanMakePayment(
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc index 96bf1c6..ed942e0e 100644 --- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc +++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -54,7 +54,7 @@ // If document is not allowed to use the policy-controlled feature named // "picture-in-picture", return kDisabledByFeaturePolicy status. if (RuntimeEnabledFeatures::PictureInPictureAPIEnabled() && - !frame->IsFeatureEnabled( + !frame->DeprecatedIsFeatureEnabled( blink::mojom::FeaturePolicyFeature::kPictureInPicture)) { return Status::kDisabledByFeaturePolicy; }
diff --git a/third_party/blink/renderer/modules/sensor/sensor.cc b/third_party/blink/renderer/modules/sensor/sensor.cc index e3f40710..2c96cf8 100644 --- a/third_party/blink/renderer/modules/sensor/sensor.cc +++ b/third_party/blink/renderer/modules/sensor/sensor.cc
@@ -26,7 +26,7 @@ const Vector<mojom::FeaturePolicyFeature>& features) { return std::all_of(features.begin(), features.end(), [frame](mojom::FeaturePolicyFeature feature) { - return frame->IsFeatureEnabled(feature); + return frame->DeprecatedIsFeatureEnabled(feature); }); }
diff --git a/third_party/blink/renderer/modules/serial/BUILD.gn b/third_party/blink/renderer/modules/serial/BUILD.gn new file mode 100644 index 0000000..f135be8 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/BUILD.gn
@@ -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. + +import("//third_party/blink/renderer/modules/modules.gni") + +blink_modules_sources("serial") { + sources = [ + "navigator_serial.cc", + "navigator_serial.h", + "serial.cc", + "serial.h", + "serial_port.cc", + "serial_port.h", + "worker_navigator_serial.cc", + "worker_navigator_serial.h", + ] +}
diff --git a/third_party/blink/renderer/modules/serial/navigator_serial.cc b/third_party/blink/renderer/modules/serial/navigator_serial.cc new file mode 100644 index 0000000..e9f8bd4 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/navigator_serial.cc
@@ -0,0 +1,42 @@ +// 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 "third_party/blink/renderer/modules/serial/navigator_serial.h" + +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/modules/serial/serial.h" + +namespace blink { + +const char NavigatorSerial::kSupplementName[] = "NavigatorSerial"; + +NavigatorSerial& NavigatorSerial::From(Navigator& navigator) { + NavigatorSerial* supplement = + Supplement<Navigator>::From<NavigatorSerial>(navigator); + if (!supplement) { + supplement = new NavigatorSerial(navigator); + ProvideTo(navigator, supplement); + } + return *supplement; +} + +Serial* NavigatorSerial::serial(Navigator& navigator) { + return NavigatorSerial::From(navigator).serial(); +} + +void NavigatorSerial::Trace(blink::Visitor* visitor) { + visitor->Trace(serial_); + Supplement<Navigator>::Trace(visitor); +} + +NavigatorSerial::NavigatorSerial(Navigator& navigator) + : Supplement<Navigator>(navigator) { + if (navigator.GetFrame()) { + DCHECK(navigator.GetFrame()->GetDocument()); + serial_ = Serial::Create(*navigator.GetFrame()->GetDocument()); + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/serial/navigator_serial.h b/third_party/blink/renderer/modules/serial/navigator_serial.h new file mode 100644 index 0000000..7267c35 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/navigator_serial.h
@@ -0,0 +1,38 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_ + +#include "third_party/blink/renderer/core/frame/navigator.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/supplementable.h" + +namespace blink { + +class Serial; + +class NavigatorSerial final : public GarbageCollected<NavigatorSerial>, + public Supplement<Navigator> { + USING_GARBAGE_COLLECTED_MIXIN(NavigatorSerial); + + public: + static const char kSupplementName[]; + + static NavigatorSerial& From(Navigator&); + + static Serial* serial(Navigator&); + Serial* serial() { return serial_; } + + void Trace(Visitor*) override; + + private: + explicit NavigatorSerial(Navigator&); + + Member<Serial> serial_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_
diff --git a/third_party/blink/renderer/modules/serial/navigator_serial.idl b/third_party/blink/renderer/modules/serial/navigator_serial.idl new file mode 100644 index 0000000..380dbca --- /dev/null +++ b/third_party/blink/renderer/modules/serial/navigator_serial.idl
@@ -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. + +// https://wicg.github.io/serial + +[ + ImplementedAs=NavigatorSerial, + RuntimeEnabled=Serial, + SecureContext +] partial interface Navigator { + [SameObject] readonly attribute Serial serial; +};
diff --git a/third_party/blink/renderer/modules/serial/serial.cc b/third_party/blink/renderer/modules/serial/serial.cc new file mode 100644 index 0000000..8c3a640 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/serial.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 "third_party/blink/renderer/modules/serial/serial.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/modules/event_target_modules_names.h" + +namespace blink { + +// static +Serial* Serial::Create(ExecutionContext& execution_context) { + return new Serial(execution_context); +} + +ExecutionContext* Serial::GetExecutionContext() const { + return ContextLifecycleObserver::GetExecutionContext(); +} + +const AtomicString& Serial::InterfaceName() const { + return EventTargetNames::Serial; +} + +ScriptPromise Serial::getPorts(ScriptState* script_state) { + return ScriptPromise::RejectWithDOMException( + script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError)); +} + +ScriptPromise Serial::requestPort(ScriptState* script_state, + const SerialPortRequestOptions& options) { + return ScriptPromise::RejectWithDOMException( + script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError)); +} + +void Serial::Trace(Visitor* visitor) { + EventTargetWithInlineData::Trace(visitor); + ContextLifecycleObserver::Trace(visitor); +} + +Serial::Serial(ExecutionContext& execution_context) + : ContextLifecycleObserver(&execution_context) {} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/serial/serial.h b/third_party/blink/renderer/modules/serial/serial.h new file mode 100644 index 0000000..ead1ec0 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/serial.h
@@ -0,0 +1,46 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/dom/events/event_target.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/handle.h" + +namespace blink { + +class ExecutionContext; +class ScriptState; +class SerialPortRequestOptions; + +class Serial final : public EventTargetWithInlineData, + public ContextLifecycleObserver { + DEFINE_WRAPPERTYPEINFO(); + USING_GARBAGE_COLLECTED_MIXIN(Serial); + + public: + static Serial* Create(ExecutionContext& executionContext); + + // EventTarget + ExecutionContext* GetExecutionContext() const override; + const AtomicString& InterfaceName() const override; + + DEFINE_ATTRIBUTE_EVENT_LISTENER(connect); + DEFINE_ATTRIBUTE_EVENT_LISTENER(disconnect); + ScriptPromise getPorts(ScriptState*); + ScriptPromise requestPort(ScriptState*, const SerialPortRequestOptions&); + + void Trace(Visitor*) override; + + private: + explicit Serial(ExecutionContext&); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_
diff --git a/third_party/blink/renderer/modules/serial/serial.idl b/third_party/blink/renderer/modules/serial/serial.idl new file mode 100644 index 0000000..b883b8e0 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/serial.idl
@@ -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. + +// https://wicg.github.io/serial + +[ + Exposed(Window Serial,DedicatedWorker Serial), + SecureContext +] interface Serial : EventTarget { + attribute EventHandler onconnect; + attribute EventHandler ondisconnect; + + [CallWith=ScriptState, MeasureAs=SerialGetPorts] + Promise<sequence<SerialPort>> getPorts(); + + [CallWith=ScriptState, MeasureAs=SerialRequestPort, Exposed=Window] + Promise<SerialPort> requestPort(SerialPortRequestOptions options); +};
diff --git a/third_party/blink/renderer/modules/serial/serial_options.idl b/third_party/blink/renderer/modules/serial/serial_options.idl new file mode 100644 index 0000000..ccb1446 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/serial_options.idl
@@ -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. + +// https://wicg.github.io/serial + +enum ParityType { + "none", + "even", + "odd", +}; + +dictionary SerialOptions { + long baudrate = 9600; + octet databits = 8; + octet stopbits = 1; + ParityType parity = "none"; + long buffersize = 255; + boolean rtscts = false; +};
diff --git a/third_party/blink/renderer/modules/serial/serial_port.cc b/third_party/blink/renderer/modules/serial/serial_port.cc new file mode 100644 index 0000000..10739a4d --- /dev/null +++ b/third_party/blink/renderer/modules/serial/serial_port.cc
@@ -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. + +#include "third_party/blink/renderer/modules/serial/serial_port.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" + +namespace blink { + +ScriptValue SerialPort::in(ScriptState* script_state) { + return ScriptValue::CreateNull(script_state); +} + +ScriptValue SerialPort::out(ScriptState* script_state) { + return ScriptValue::CreateNull(script_state); +} + +ScriptPromise SerialPort::open(ScriptState* script_state, + const SerialOptions& options) { + return ScriptPromise::RejectWithDOMException( + script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError)); +} + +ScriptPromise SerialPort::close(ScriptState* script_state) { + return ScriptPromise::RejectWithDOMException( + script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError)); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/serial/serial_port.h b/third_party/blink/renderer/modules/serial/serial_port.h new file mode 100644 index 0000000..baadd7b06 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/serial_port.h
@@ -0,0 +1,30 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/heap/handle.h" + +namespace blink { + +class ScriptState; +class SerialOptions; + +class SerialPort final : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + ScriptValue in(ScriptState*); + ScriptValue out(ScriptState*); + + ScriptPromise open(ScriptState*, const SerialOptions& options); + ScriptPromise close(ScriptState*); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_
diff --git a/third_party/blink/renderer/modules/serial/serial_port.idl b/third_party/blink/renderer/modules/serial/serial_port.idl new file mode 100644 index 0000000..794b9875 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/serial_port.idl
@@ -0,0 +1,22 @@ +// 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. + +// https://wicg.github.io/serial + +[ + Exposed(Window Serial,DedicatedWorker Serial), + SecureContext +] interface SerialPort { + // TODO(https://crbug.com/888165): "any" is used here because the IDL + // processor does not recognize ReadableStream or WritableStream when + // implemented with V8 extras. + [CallWith=ScriptState] readonly attribute any in; + [CallWith=ScriptState] readonly attribute any out; + + [CallWith=ScriptState, MeasureAs=SerialPortOpen] + Promise<void> open(SerialOptions options); + + [CallWith=ScriptState, MeasureAs=SerialPortClose] + Promise<void> close(); +};
diff --git a/third_party/blink/renderer/modules/serial/serial_port_request_options.idl b/third_party/blink/renderer/modules/serial/serial_port_request_options.idl new file mode 100644 index 0000000..8e9c05c --- /dev/null +++ b/third_party/blink/renderer/modules/serial/serial_port_request_options.idl
@@ -0,0 +1,8 @@ +// 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. + +// https://wicg.github.io/serial + +dictionary SerialPortRequestOptions { +};
diff --git a/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc b/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc new file mode 100644 index 0000000..a5a6b08 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
@@ -0,0 +1,49 @@ +// 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 "third_party/blink/renderer/modules/serial/worker_navigator_serial.h" + +#include "third_party/blink/renderer/modules/serial/serial.h" + +namespace blink { + +const char WorkerNavigatorSerial::kSupplementName[] = "WorkerNavigatorSerial"; + +WorkerNavigatorSerial& WorkerNavigatorSerial::From(WorkerNavigator& navigator) { + WorkerNavigatorSerial* supplement = + Supplement<WorkerNavigator>::From<WorkerNavigatorSerial>(navigator); + if (!supplement) { + supplement = new WorkerNavigatorSerial(navigator); + ProvideTo(navigator, supplement); + } + return *supplement; +} + +Serial* WorkerNavigatorSerial::serial(ScriptState* script_state, + WorkerNavigator& navigator) { + return WorkerNavigatorSerial::From(navigator).serial(script_state); +} + +Serial* WorkerNavigatorSerial::serial(ScriptState* script_state) { + if (!serial_) { + auto* execution_context = ExecutionContext::From(script_state); + DCHECK(execution_context); + + // TODO(https://crbug.com/839117): Remove this check once the Exposed + // attribute is fixed to only expose this property in dedicated workers. + if (execution_context->IsDedicatedWorkerGlobalScope()) + serial_ = Serial::Create(*execution_context); + } + return serial_; +} + +void WorkerNavigatorSerial::Trace(blink::Visitor* visitor) { + visitor->Trace(serial_); + Supplement<WorkerNavigator>::Trace(visitor); +} + +WorkerNavigatorSerial::WorkerNavigatorSerial(WorkerNavigator& navigator) + : Supplement<WorkerNavigator>(navigator) {} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/serial/worker_navigator_serial.h b/third_party/blink/renderer/modules/serial/worker_navigator_serial.h new file mode 100644 index 0000000..8ff078d --- /dev/null +++ b/third_party/blink/renderer/modules/serial/worker_navigator_serial.h
@@ -0,0 +1,40 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_ + +#include "third_party/blink/renderer/core/workers/worker_navigator.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/supplementable.h" + +namespace blink { + +class ScriptState; +class Serial; + +class WorkerNavigatorSerial final + : public GarbageCollected<WorkerNavigatorSerial>, + public Supplement<WorkerNavigator> { + USING_GARBAGE_COLLECTED_MIXIN(WorkerNavigatorSerial); + + public: + static const char kSupplementName[]; + + static WorkerNavigatorSerial& From(WorkerNavigator&); + + static Serial* serial(ScriptState*, WorkerNavigator&); + Serial* serial(ScriptState*); + + void Trace(Visitor*) override; + + private: + explicit WorkerNavigatorSerial(WorkerNavigator&); + + Member<Serial> serial_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_
diff --git a/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl b/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl new file mode 100644 index 0000000..c95d2b0 --- /dev/null +++ b/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl
@@ -0,0 +1,14 @@ +// 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. + +// https://wicg.github.io/serial + +[ + Exposed=DedicatedWorker, + ImplementedAs=WorkerNavigatorSerial, + RuntimeEnabled=Serial, + SecureContext +] partial interface WorkerNavigator { + [CallWith=ScriptState, SameObject] readonly attribute Serial serial; +};
diff --git a/third_party/blink/renderer/modules/vr/navigator_vr.cc b/third_party/blink/renderer/modules/vr/navigator_vr.cc index 8eec6dee..01dae7eb 100644 --- a/third_party/blink/renderer/modules/vr/navigator_vr.cc +++ b/third_party/blink/renderer/modules/vr/navigator_vr.cc
@@ -144,8 +144,8 @@ script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError, kNotAssociatedWithDocumentMessage)); } - if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr, - ReportOptions::kReportOnFailure)) { + if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr, + ReportOptions::kReportOnFailure)) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError, kFeaturePolicyBlockedMessage));
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.h b/third_party/blink/renderer/modules/webaudio/base_audio_context.h index a29a9b6..48bae6f 100644 --- a/third_party/blink/renderer/modules/webaudio/base_audio_context.h +++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
@@ -353,6 +353,16 @@ const String& Uuid() const { return uuid_; } + // The audio thread relies on the main thread to perform some operations + // over the objects that it owns and controls; |ScheduleMainThreadCleanup()| + // posts the task to initiate those. + void ScheduleMainThreadCleanup(); + + // Handles promise resolving, stopping and finishing up of audio source nodes + // etc. Actions that should happen, but can happen asynchronously to the + // audio thread making rendering progress. + void PerformCleanupOnMainThread(); + private: friend class AudioContextAutoplayTest; @@ -392,18 +402,6 @@ // these Promises. void ResolvePromisesForUnpause(); - // The audio thread relies on the main thread to perform some operations - // over the objects that it owns and controls; |ScheduleMainThreadCleanup()| - // posts the task to initiate those. - // - // That is, we combine all those sub-tasks into one task action for - // convenience and performance, |PerformCleanupOnMainThread()|. It handles - // promise resolving, stopping and finishing up of audio source nodes etc. - // Actions that should happen, but can happen asynchronously to the - // audio thread making rendering progress. - void ScheduleMainThreadCleanup(); - void PerformCleanupOnMainThread(); - // When the context is going away, reject any pending script promise // resolvers. virtual void RejectPendingResolvers();
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc index fa3c1d6..576b7a4 100644 --- a/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc +++ b/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
@@ -379,6 +379,8 @@ } is_rendering_started_ = false; + + PerformCleanupOnMainThread(); } bool OfflineAudioContext::HandlePreOfflineRenderTasks() {
diff --git a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc index 4d08522c..21ff4de 100644 --- a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc +++ b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
@@ -102,7 +102,7 @@ UseCounter::CountCrossOriginIframe( document, WebFeature::kRequestMIDIAccessIframe_ObscuredByFootprinting); - if (!document.GetFrame()->IsFeatureEnabled( + if (!document.GetFrame()->DeprecatedIsFeatureEnabled( mojom::FeaturePolicyFeature::kMidiFeature, ReportOptions::kReportOnFailure)) { UseCounter::Count(document, WebFeature::kMidiDisabledByFeaturePolicy);
diff --git a/third_party/blink/renderer/modules/webusb/usb.cc b/third_party/blink/renderer/modules/webusb/usb.cc index c15089f..b911b99 100644 --- a/third_party/blink/renderer/modules/webusb/usb.cc +++ b/third_party/blink/renderer/modules/webusb/usb.cc
@@ -115,7 +115,8 @@ if (execution_context && execution_context->IsDocument()) { ToDocument(execution_context) ->GetFrame() - ->ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature::kUsb); + ->DeprecatedReportFeaturePolicyViolation( + mojom::FeaturePolicyFeature::kUsb); } return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError, @@ -139,8 +140,8 @@ DOMException::Create(DOMExceptionCode::kNotSupportedError)); } - if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kUsb, - ReportOptions::kReportOnFailure)) { + if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kUsb, + ReportOptions::kReportOnFailure)) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError, kFeaturePolicyBlocked));
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc index 287e88c0..8cb4dbb 100644 --- a/third_party/blink/renderer/modules/xr/xr.cc +++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -73,8 +73,8 @@ did_log_requestDevice_ = true; } - if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr, - ReportOptions::kReportOnFailure)) { + if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr, + ReportOptions::kReportOnFailure)) { // Only allow the call to be made if the appropraite feature policy is in // place. return ScriptPromise::RejectWithDOMException(
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc index 6ec3f41..e7c2c29 100644 --- a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc +++ b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
@@ -162,6 +162,13 @@ data->active_script_wrappables_.Clear(); // Detach V8's garbage collector. + if (RuntimeEnabledFeatures::HeapUnifiedGarbageCollectionEnabled()) { + // Need to finalize an already running garbage collection as otherwise + // callbacks are missing and state gets out of sync. + ThreadState::Current()->FinishIncrementalMarkingIfRunning( + BlinkGC::kHeapPointersOnStack, BlinkGC::kAtomicMarking, + BlinkGC::kEagerSweeping, BlinkGC::GCReason::kThreadTerminationGC); + } isolate->SetEmbedderHeapTracer(nullptr); if (data->script_wrappable_visitor_->WrapperTracingInProgress()) data->script_wrappable_visitor_->AbortTracing();
diff --git a/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc b/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc index c48be7b..8616bf8 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc
@@ -7,7 +7,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/graphics/color_correction_test_utils.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" -#include "third_party/skia/include/core/SkColorSpaceXform.h" #include "ui/gfx/color_space.h" namespace blink { @@ -17,56 +16,20 @@ // to the canvas, the target gfx::ColorSpace is returned by CanvasColorParams:: // GetStorageGfxColorSpace(). This test verifies that the two different color // spaces are approximately the same for different CanvasColorParam objects. -// This test does not use SkColorSpace::Equals() since it is sensitive to -// rounding issues (floats don't round-trip perfectly through ICC fixed point). -// Instead, it color converts a pixel and compares the result. Furthermore, this -// test does not include sRGB as target color space since we use -// SkColorSpaceXformCanvas for sRGB targets and GetSkColorSpaceForSkSurfaces() -// returns nullptr for the surface. TEST(CanvasColorParamsTest, MatchSkColorSpaceWithGfxColorSpace) { - sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB(); - std::unique_ptr<uint8_t[]> src_pixel(new uint8_t[4]{32, 96, 160, 255}); - CanvasColorSpace canvas_color_spaces[] = { kSRGBCanvasColorSpace, kRec2020CanvasColorSpace, kP3CanvasColorSpace, }; - for (int iter_color_space = 0; iter_color_space < 3; iter_color_space++) { CanvasColorParams color_params(canvas_color_spaces[iter_color_space], kF16CanvasPixelFormat, kNonOpaque); - - std::unique_ptr<SkColorSpaceXform> color_space_xform_canvas = - SkColorSpaceXform::New(src_rgb_color_space.get(), - color_params.GetSkColorSpace().get()); - std::unique_ptr<SkColorSpaceXform> color_space_xform_media = - SkColorSpaceXform::New( - src_rgb_color_space.get(), - color_params.GetStorageGfxColorSpace().ToSkColorSpace().get()); - - std::unique_ptr<uint8_t[]> transformed_pixel_canvas( - new uint8_t[color_params.BytesPerPixel()]()); - std::unique_ptr<uint8_t[]> transformed_pixel_media( - new uint8_t[color_params.BytesPerPixel()]()); - - SkColorSpaceXform::ColorFormat transformed_color_format = - color_params.BytesPerPixel() == 4 - ? SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat - : SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat; - - EXPECT_TRUE(color_space_xform_canvas->apply( - transformed_color_format, transformed_pixel_canvas.get(), - SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat, src_pixel.get(), - 1, SkAlphaType::kPremul_SkAlphaType)); - - EXPECT_TRUE(color_space_xform_media->apply( - transformed_color_format, transformed_pixel_media.get(), - SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat, src_pixel.get(), - 1, SkAlphaType::kPremul_SkAlphaType)); - - ColorCorrectionTestUtils::CompareColorCorrectedPixels( - transformed_pixel_canvas.get(), transformed_pixel_media.get(), 1, - kPixelFormat_hhhh, kAlphaMultiplied, kUnpremulRoundTripTolerance); - } + sk_sp<SkColorSpace> canvas_drawing_color_space = + color_params.GetSkColorSpace(); + sk_sp<SkColorSpace> canvas_media_color_space = + color_params.GetStorageGfxColorSpace().ToSkColorSpace(); + ASSERT_TRUE(ColorCorrectionTestUtils::MatchColorSpace( + canvas_drawing_color_space, canvas_media_color_space)); + } } } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc b/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc index a7b1c89..25fdcaa 100644 --- a/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc +++ b/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
@@ -6,6 +6,7 @@ #include "base/sys_byteorder.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/third_party/skcms/skcms.h" namespace blink { @@ -66,6 +67,33 @@ return SkColorSpace::Make(colorspin_profile); } +sk_sp<SkColorSpace> +ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace( + ColorSpaceConversion conversion) { + if (conversion == kColorSpaceConversion_Default || + conversion == kColorSpaceConversion_SRGB) { + return SkColorSpace::MakeSRGB(); + } + if (conversion == kColorSpaceConversion_LinearRGB) + return SkColorSpace::MakeSRGBLinear(); + if (conversion == kColorSpaceConversion_P3) { + return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, + SkColorSpace::kDCIP3_D65_Gamut); + } + if (conversion == kColorSpaceConversion_Rec2020) { + return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, + SkColorSpace::kRec2020_Gamut); + } + return nullptr; +} + +String ColorCorrectionTestUtils::ColorSpaceConversionToString( + ColorSpaceConversion color_space_conversion) { + static const Vector<String> kConversions = { + "none", "default", "preserve", "srgb", "linear-rgb", "p3", "rec2020"}; + return kConversions[static_cast<uint8_t>(color_space_conversion)]; +} + void ColorCorrectionTestUtils::CompareColorCorrectedPixels( const void* actual_pixels, const void* expected_pixels, @@ -227,32 +255,23 @@ } bool ColorCorrectionTestUtils::MatchColorSpace( - SkColorSpace* src_color_space, - SkColorSpace* dst_color_space, - float xyz_d50_component_tolerance) { + sk_sp<SkColorSpace> src_color_space, + sk_sp<SkColorSpace> dst_color_space) { if ((!src_color_space && dst_color_space) || (src_color_space && !dst_color_space)) return false; - if (src_color_space) { - const SkMatrix44* src_matrix = src_color_space->toXYZD50(); - const SkMatrix44* dst_matrix = dst_color_space->toXYZD50(); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - if (fabs(src_matrix->get(i, j) - dst_matrix->get(i, j)) > - xyz_d50_component_tolerance) { - return false; - } - } - } - } - return true; + if (!src_color_space && !dst_color_space) + return true; + skcms_ICCProfile src_profile, dst_profile; + src_color_space->toProfile(&src_profile); + dst_color_space->toProfile(&dst_profile); + return skcms_ApproximatelyEqualProfiles(&src_profile, &dst_profile); } bool ColorCorrectionTestUtils::MatchSkImages(sk_sp<SkImage> src_image, sk_sp<SkImage> dst_image, unsigned uint8_tolerance, float f16_tolerance, - float xyz_d50_component_tolerance, bool compare_alpha) { if ((!src_image && dst_image) || (src_image && !dst_image)) return false; @@ -265,8 +284,10 @@ if (compare_alpha && src_image->alphaType() != dst_image->alphaType()) return false; - if (!MatchColorSpace(src_image->colorSpace(), dst_image->colorSpace(), - xyz_d50_component_tolerance)) { + // Color type is not checked since the decoded image does not have a specific + // color type, unless it is drawn onto a surface or readPixels() is called. + if (!MatchColorSpace(src_image->refColorSpace(), + dst_image->refColorSpace())) { return false; }
diff --git a/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h b/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h index 486f07f..1f79335 100644 --- a/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h +++ b/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h
@@ -9,8 +9,8 @@ #include "third_party/blink/renderer/platform/graphics/graphics_types.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/skia/include/core/SkImage.h" -#include "third_party/skia/third_party/skcms/skcms.h" namespace blink { @@ -31,9 +31,25 @@ kUnpremulRoundTripTolerance, }; +enum ColorSpaceConversion { + kColorSpaceConversion_None, + kColorSpaceConversion_Default, + kColorSpaceConversion_Preserve, + kColorSpaceConversion_SRGB, + kColorSpaceConversion_LinearRGB, + kColorSpaceConversion_P3, + kColorSpaceConversion_Rec2020, + kColorSpaceConversion_Last = kColorSpaceConversion_Rec2020, +}; + class ColorCorrectionTestUtils { public: + // ImageBitmap color space conversion test utils static sk_sp<SkColorSpace> ColorSpinSkColorSpace(); + static sk_sp<SkColorSpace> ColorSpaceConversionToSkColorSpace( + ColorSpaceConversion conversion); + static String ColorSpaceConversionToString( + ColorSpaceConversion color_space_conversion); static void CompareColorCorrectedPixels( const void* actual_pixels, @@ -53,15 +69,13 @@ std::unique_ptr<uint8_t[]>& converted_pixels, PixelFormat pixel_format_for_f16_canvas); - static bool MatchColorSpace(SkColorSpace* src_color_space, - SkColorSpace* dst_color_space, - float xyz_d50_component_tolerance); + static bool MatchColorSpace(sk_sp<SkColorSpace> src_color_space, + sk_sp<SkColorSpace> dst_color_space); static bool MatchSkImages(sk_sp<SkImage> src_image, sk_sp<SkImage> dst_image, unsigned uint8_tolerance, float f16_tolerance, - float xyz_d50_component_tolerance, bool compare_alpha); private:
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc index b04c567..45a3ce6 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -57,7 +57,7 @@ #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h" -#include "third_party/skia/include/core/SkColorSpaceXform.h" +#include "third_party/skia/include/core/SkPixmap.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/skia/include/gpu/gl/GrGLTypes.h" @@ -1367,15 +1367,15 @@ } if (op == WebGLImageConversion::kAlphaDoPremultiply) { - std::unique_ptr<SkColorSpaceXform> xform = - SkColorSpaceXform::New(SkColorSpace::MakeSRGBLinear().get(), - SkColorSpace::MakeSRGBLinear().get()); - SkColorSpaceXform::ColorFormat color_format = - SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat; + auto color_type = kRGBA_8888_SkColorType; if (data_type != GL_UNSIGNED_BYTE) - color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat; - xform->apply(color_format, pixels, color_format, pixels, width * height, - kPremul_SkAlphaType); + color_type = kRGBA_F16_SkColorType; + const auto src = + SkImageInfo::Make(width, height, color_type, kUnpremul_SkAlphaType); + const auto dst = + SkImageInfo::Make(width, height, color_type, kPremul_SkAlphaType); + SkPixmap{src, pixels, src.minRowBytes()}.readPixels( + SkPixmap{dst, pixels, dst.minRowBytes()}); } else if (op != WebGLImageConversion::kAlphaDoNothing) { NOTREACHED(); }
diff --git a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc index 2e601824..a9bf22f 100644 --- a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc +++ b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
@@ -63,8 +63,8 @@ constexpr int kMaxMismatches = 10; for (int y = 0; y < bounds.Height(); ++y) { for (int x = 0; x < bounds.Width(); ++x) { - SkPMColor pixel1 = *bitmap1.getAddr32(x, y); - SkPMColor pixel2 = *bitmap2.getAddr32(x, y); + SkColor pixel1 = bitmap1.getColor(x, y); + SkColor pixel2 = bitmap2.getColor(x, y); if (pixel1 != pixel2) { if (!RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) return false;
diff --git a/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc b/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc index 895dc591..4f3e4ac3 100644 --- a/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc +++ b/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc
@@ -14,7 +14,6 @@ #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h" -#include "third_party/skia/include/core/SkColorPriv.h" namespace blink { @@ -160,11 +159,11 @@ return abs(c1 - c2) > 2; } -static bool PMColorsDiffer(SkPMColor p1, SkPMColor p2) { - return PixelComponentsDiffer(SkGetPackedA32(p1), SkGetPackedA32(p2)) || - PixelComponentsDiffer(SkGetPackedR32(p1), SkGetPackedR32(p2)) || - PixelComponentsDiffer(SkGetPackedG32(p1), SkGetPackedG32(p2)) || - PixelComponentsDiffer(SkGetPackedB32(p1), SkGetPackedB32(p2)); +static bool PixelsDiffer(SkColor p1, SkColor p2) { + return PixelComponentsDiffer(SkColorGetA(p1), SkColorGetA(p2)) || + PixelComponentsDiffer(SkColorGetR(p1), SkColorGetR(p2)) || + PixelComponentsDiffer(SkColorGetG(p1), SkColorGetG(p2)) || + PixelComponentsDiffer(SkColorGetB(p1), SkColorGetB(p2)); } void RasterInvalidationTracking::CheckUnderInvalidations( @@ -216,9 +215,9 @@ int layer_y = bitmap_y + rect.Y(); for (int bitmap_x = 0; bitmap_x < rect.Width(); ++bitmap_x) { int layer_x = bitmap_x + rect.X(); - SkPMColor old_pixel = *old_bitmap.getAddr32(bitmap_x, bitmap_y); - SkPMColor new_pixel = *new_bitmap.getAddr32(bitmap_x, bitmap_y); - if (PMColorsDiffer(old_pixel, new_pixel) && + SkColor old_pixel = old_bitmap.getColor(bitmap_x, bitmap_y); + SkColor new_pixel = new_bitmap.getColor(bitmap_x, bitmap_y); + if (PixelsDiffer(old_pixel, new_pixel) && !invalidation_region.Contains(IntPoint(layer_x, layer_y))) { if (mismatching_pixels < kMaxMismatchesToReport) { RasterUnderInvalidation under_invalidation = {layer_x, layer_y,
diff --git a/third_party/blink/renderer/platform/image-decoders/image_frame_test.cc b/third_party/blink/renderer/platform/image-decoders/image_frame_test.cc index 908a772..2b63ae6e 100644 --- a/third_party/blink/renderer/platform/image-decoders/image_frame_test.cc +++ b/third_party/blink/renderer/platform/image-decoders/image_frame_test.cc
@@ -5,7 +5,7 @@ #include "third_party/blink/renderer/platform/image-decoders/image_frame.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkColorSpaceXform.h" +#include "third_party/skia/third_party/skcms/skcms.h" namespace blink { namespace { @@ -26,20 +26,16 @@ src_8888 = SkPackARGB32(src_8888_a, src_8888_r, src_8888_g, src_8888_b); dst_8888 = SkPackARGB32(0xA0, 0x60, 0x70, 0x80); - typedef SkColorSpaceXform::ColorFormat ColorFormat; - color_format_8888 = ColorFormat::kBGRA_8888_ColorFormat; + pixel_format_n32 = skcms_PixelFormat_RGBA_8888; if (kN32_SkColorType == kRGBA_8888_SkColorType) - color_format_8888 = ColorFormat::kRGBA_8888_ColorFormat; - color_format_f16 = ColorFormat::kRGBA_F16_ColorFormat; - color_format_f32 = ColorFormat::kRGBA_F32_ColorFormat; + pixel_format_n32 = skcms_PixelFormat_BGRA_8888; - sk_sp<SkColorSpace> srgb_linear = SkColorSpace::MakeSRGBLinear(); - SkColorSpaceXform::Apply(srgb_linear.get(), color_format_f16, &src_f16, - srgb_linear.get(), color_format_8888, &src_8888, 1, - SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp); - SkColorSpaceXform::Apply(srgb_linear.get(), color_format_f16, &dst_f16, - srgb_linear.get(), color_format_8888, &dst_8888, 1, - SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp); + skcms_Transform(&src_8888, pixel_format_n32, skcms_AlphaFormat_Unpremul, + nullptr, &src_f16, skcms_PixelFormat_RGBA_hhhh, + skcms_AlphaFormat_Unpremul, nullptr, 1); + skcms_Transform(&dst_8888, pixel_format_n32, skcms_AlphaFormat_Unpremul, + nullptr, &dst_f16, skcms_PixelFormat_RGBA_hhhh, + skcms_AlphaFormat_Unpremul, nullptr, 1); } protected: @@ -47,21 +43,19 @@ unsigned src_8888_a, src_8888_r, src_8888_g, src_8888_b; ImageFrame::PixelData src_8888, dst_8888; ImageFrame::PixelDataF16 src_f16, dst_f16; - SkColorSpaceXform::ColorFormat color_format_8888, color_format_f16, - color_format_f32; + skcms_PixelFormat pixel_format_n32; void ConvertN32ToF32(float* dst, ImageFrame::PixelData src) { - sk_sp<SkColorSpace> srgb_linear = SkColorSpace::MakeSRGBLinear(); - SkColorSpaceXform::Apply(srgb_linear.get(), color_format_f32, dst, - srgb_linear.get(), color_format_8888, &src, 1, - SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp); + skcms_Transform(&src, pixel_format_n32, skcms_AlphaFormat_Unpremul, nullptr, + dst, skcms_PixelFormat_RGBA_ffff, + skcms_AlphaFormat_Unpremul, nullptr, 1); } void ConvertF16ToF32(float* dst, ImageFrame::PixelDataF16 src) { - sk_sp<SkColorSpace> srgb_linear = SkColorSpace::MakeSRGBLinear(); - SkColorSpaceXform::Apply(srgb_linear.get(), color_format_f32, dst, - srgb_linear.get(), color_format_f16, &src, 1, - SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp); + skcms_Transform(&src, skcms_PixelFormat_RGBA_hhhh, + skcms_AlphaFormat_Unpremul, nullptr, dst, + skcms_PixelFormat_RGBA_ffff, skcms_AlphaFormat_Unpremul, + nullptr, 1); } };
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 9bd5f954..5313537 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -637,12 +637,15 @@ }, { name: "LayoutNG", - implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFlexBox", "EditingNG"], + implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFieldset", "LayoutNGFlexBox", "EditingNG"], }, { name: "LayoutNGBlockFragmentation", }, { + name: "LayoutNGFieldset", + }, + { name: "LayoutNGFlexBox", }, { @@ -1133,6 +1136,10 @@ status: "experimental", }, { + name: "Serial", + status: "experimental", + }, + { name: "ServiceWorkerScriptFullCodeCache", }, {
diff --git a/tools/binary_size/diagnose_bloat.py b/tools/binary_size/diagnose_bloat.py index 6092a3c..3ec9b63 100755 --- a/tools/binary_size/diagnose_bloat.py +++ b/tools/binary_size/diagnose_bloat.py
@@ -847,32 +847,6 @@ atexit.register(_GenRestoreFunc(subrepo)) -# Used by binary size trybot. -def _DiffMain(args): - parser = argparse.ArgumentParser() - parser.add_argument('--before-dir', required=True) - parser.add_argument('--after-dir', required=True) - parser.add_argument('--apk-name', required=True) - parser.add_argument('--diff-type', required=True, choices=['native', 'sizes']) - parser.add_argument('--diff-output', required=True) - args = parser.parse_args(args) - - is_native_diff = args.diff_type == 'native' - if is_native_diff: - supersize_path = os.path.join(_BINARY_SIZE_DIR, 'supersize') - diff = NativeDiff(args.apk_name + '.size', supersize_path) - else: - diff = ResourceSizesDiff(args.apk_name) - - diff.ProduceDiff(args.before_dir, args.after_dir) - lines = diff.DetailedResults() if is_native_diff else diff.Summary() - - with open(args.diff_output, 'w') as f: - f.writelines(l + '\n' for l in lines) - stat = diff.summary_stat - f.write('\n{}={}\n'.format(*stat[:2])) - - def main(): parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) @@ -965,8 +939,6 @@ if len(sys.argv) == 1: parser.print_help() return 1 - if sys.argv[1] == 'diff': - return _DiffMain(sys.argv[2:]) args = parser.parse_args() log_level = logging.DEBUG if args.verbose else logging.INFO
diff --git a/tools/binary_size/libsupersize/canned_queries.py b/tools/binary_size/libsupersize/canned_queries.py index 1d9a5770..4aeeeb5b 100644 --- a/tools/binary_size/libsupersize/canned_queries.py +++ b/tools/binary_size/libsupersize/canned_queries.py
@@ -5,6 +5,7 @@ """Contains a set of Chrome-specific size queries.""" import logging + import models
diff --git a/tools/binary_size/libsupersize/console.py b/tools/binary_size/libsupersize/console.py index 0517acf9..455314b 100644 --- a/tools/binary_size/libsupersize/console.py +++ b/tools/binary_size/libsupersize/console.py
@@ -153,17 +153,7 @@ """ before = before if before is not None else self._size_infos[0] after = after if after is not None else self._size_infos[1] - ret = diff.Diff(before, after) - if sort: - syms = ret.symbols # Triggers clustering. - logging.debug('Grouping') - # Group path aliases so that functions defined in headers will be sorted - # by their actual size rather than shown as many small symbols. - syms = syms.GroupedByAliases(same_name_only=True) - logging.debug('Sorting') - ret.symbols = syms.Sorted() - logging.debug('Diff complete') - return ret + return diff.Diff(before, after, sort=sort) def _PrintFunc(self, obj=None, verbose=False, summarize=True, recursive=False, use_pager=None, to_file=None):
diff --git a/tools/binary_size/libsupersize/diff.py b/tools/binary_size/libsupersize/diff.py index 0915f99..2a0b9601 100644 --- a/tools/binary_size/libsupersize/diff.py +++ b/tools/binary_size/libsupersize/diff.py
@@ -121,7 +121,7 @@ return models.DeltaSymbolGroup(all_deltas) -def Diff(before, after): +def Diff(before, after, sort=False): """Diffs two SizeInfo objects. Returns a DeltaSizeInfo.""" assert isinstance(before, models.SizeInfo) assert isinstance(after, models.SizeInfo) @@ -132,4 +132,15 @@ section_sizes[k] = v symbol_diff = _DiffSymbolGroups(before.raw_symbols, after.raw_symbols) - return models.DeltaSizeInfo(before, after, section_sizes, symbol_diff) + ret = models.DeltaSizeInfo(before, after, section_sizes, symbol_diff) + + if sort: + syms = ret.symbols # Triggers clustering. + logging.debug('Grouping') + # Group path aliases so that functions defined in headers will be sorted + # by their actual size rather than shown as many small symbols. + syms = syms.GroupedByAliases(same_name_only=True) + logging.debug('Sorting') + ret.symbols = syms.Sorted() + logging.debug('Diff complete') + return ret
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py index fa8873b..f2d8a4a0 100644 --- a/tools/binary_size/libsupersize/html_report.py +++ b/tools/binary_size/libsupersize/html_report.py
@@ -191,38 +191,28 @@ return meta, file_nodes.values() -def BuildReport(out_file, size_file, before_size_file=(None, None), - all_symbols=False): +def BuildReportFromSizeInfo(out_path, size_info, all_symbols=False): """Builds a .ndjson report for a .size file. Args: - out_file: File object to save JSON report to. - size_file: Size file to use as input. Tuple of path and file object. - before_size_file: If used, creates a diff report where |size_file| is the - newer .size file. Tuple of path and file object. + out_path: Path to save JSON report to. + size_info: A SizeInfo or DeltaSizeInfo to use for the report. all_symbols: If true, all symbols will be included in the report rather than truncated. """ logging.info('Reading .size file') - diff_mode = any(before_size_file) - - size_info = archive.LoadAndPostProcessSizeInfo(*size_file) - if diff_mode: - before_size_info = archive.LoadAndPostProcessSizeInfo(*before_size_file) - after_size_info = size_info - - size_info = diff.Diff(before_size_info, after_size_info) - symbols = size_info.raw_symbols + symbols = size_info.raw_symbols + is_diff = symbols.IsDelta() + if is_diff: symbols = symbols.WhereDiffStatusIs(models.DIFF_STATUS_UNCHANGED).Inverted() - else: - symbols = size_info.raw_symbols meta, tree_nodes = _MakeTreeViewList(symbols, all_symbols) + logging.info('Created %d tree nodes', len(tree_nodes)) meta.update({ - 'diff_mode': diff_mode, + 'diff_mode': is_diff, 'section_sizes': size_info.section_sizes, }) - if diff_mode: + if is_diff: meta.update({ 'before_metadata': size_info.before.metadata, 'after_metadata': size_info.after.metadata, @@ -239,13 +229,14 @@ 'check_circular': False, } - json.dump(meta, out_file, **json_dump_args) - out_file.write('\n') - - for tree_node in tree_nodes: - json.dump(tree_node, out_file, **json_dump_args) + with codecs.open(out_path, 'w', encoding='ascii') as out_file: + json.dump(meta, out_file, **json_dump_args) out_file.write('\n') + for tree_node in tree_nodes: + json.dump(tree_node, out_file, **json_dump_args) + out_file.write('\n') + def _MakeDirIfDoesNotExist(rel_path): """Ensures a directory exists.""" @@ -278,13 +269,13 @@ if not args.output_report_file.endswith('.ndjson'): parser.error('Output must end with ".ndjson"') - with codecs.open(args.output_report_file, 'w', encoding='ascii') as out_file: - BuildReport( - out_file, - size_file=(args.input_size_file, None), - before_size_file=(args.diff_with, None), - all_symbols=args.all_symbols - ) + size_info = archive.LoadAndPostProcessSizeInfo(args.input_size_file) + if args.diff_with: + before_size_info = archive.LoadAndPostProcessSizeInfo(args.diff_with) + size_info = diff.Diff(before_size_info, size_info) + + BuildReportFromSizeInfo( + args.output_report_file, size_info, all_symbols=args.all_symbols) msg = [ 'Done!',
diff --git a/tools/binary_size/trybot_commit_size_checker.py b/tools/binary_size/trybot_commit_size_checker.py index 664be05..d93b46ae 100755 --- a/tools/binary_size/trybot_commit_size_checker.py +++ b/tools/binary_size/trybot_commit_size_checker.py
@@ -3,46 +3,192 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""Fails if a try job increases binary size unexpectedly.""" +"""Creates several files used by the size trybot to monitor size regressions.""" import argparse +import collections +import json +import logging +import os import sys +sys.path.append(os.path.join(os.path.dirname(__file__), 'libsupersize')) +import archive +import diagnose_bloat +import diff +import describe +import html_report +import models -_MAX_UNNOTICED_INCREASE = 16 * 1024 +_MAX_DEX_METHOD_COUNT_INCREASE = 50 +_MAX_NORMALIZED_INCREASE = 16 * 1024 +_MAX_PAK_INCREASE = 1024 + +_NORMALIZED_APK_SIZE_DETAILS = ( + 'See https://chromium.googlesource.com/chromium/src/+/master/docs/speed/' + 'binary_size/metrics.md#Normalized-APK-Size ' + 'for an explanation of Normalized APK Size') + + +class _SizeDelta(collections.namedtuple( + 'SizeDelta', ['name', 'units', 'expected', 'actual', 'details'])): + + @property + def explanation(self): + return '{}: expected max: {} {}, got {} {}\n{}'.format( + self.name, self.expected, self.units, self.actual, self.units, + self.details) + + def _IsAllowable(self): + return self.actual <= self.expected + + def __cmp__(self, other): + return cmp(self.name, other.name) + + +def _CreateAndWriteMethodCountDelta(symbols, output_path): + dex_symbols = symbols.WhereInSection(models.SECTION_DEX_METHOD) + dex_added = dex_symbols.WhereDiffStatusIs(models.DIFF_STATUS_ADDED) + dex_removed = dex_symbols.WhereDiffStatusIs(models.DIFF_STATUS_REMOVED) + dex_added_count, dex_removed_count = len(dex_added), len(dex_removed) + dex_net_added = dex_added_count - dex_removed_count + + dex_expl = 'Added: {}\n{}\n\nRemoved: {}\n{}'.format( + dex_added_count, + '\n'.join(s.name for s in dex_added.SortedByName()), + dex_removed_count, + '\n'.join(s.name for s in dex_removed.SortedByName())) + + with open(output_path, 'w') as f: + f.writelines(dex_expl) + + return _SizeDelta('Dex Methods', 'methods', _MAX_DEX_METHOD_COUNT_INCREASE, + dex_net_added, dex_expl) + + +def _CreateAndWriteResourceSizesDelta(apk_name, before_dir, after_dir, + output_path): + sizes_diff = diagnose_bloat.ResourceSizesDiff(apk_name) + sizes_diff.ProduceDiff(before_dir, after_dir) + + with open(output_path, 'w') as f: + f.writelines(l + '\n' for l in sizes_diff.Summary()) + + return _SizeDelta('Normalized APK Size', 'bytes', _MAX_NORMALIZED_INCREASE, + sizes_diff.summary_stat.value, _NORMALIZED_APK_SIZE_DETAILS) + + +def _CreateAndWriteSupersizeDiff(apk_name, before_dir, after_dir, output_path): + before_size_path = os.path.join(before_dir, apk_name + '.size') + after_size_path = os.path.join(after_dir, apk_name + '.size') + before = archive.LoadAndPostProcessSizeInfo(before_size_path) + after = archive.LoadAndPostProcessSizeInfo(after_size_path) + size_info_delta = diff.Diff(before, after, sort=True) + + with open(output_path, 'w') as f: + f.writelines(l + '\n' for l in describe.GenerateLines(size_info_delta)) + + return size_info_delta + + +def _CreateUncompressedPakSizeDeltas(symbols): + pak_symbols = symbols.Filter(lambda s: + s.size > 0 and + bool(s.flags & models.FLAG_UNCOMPRESSED) and + s.section_name == models.SECTION_PAK_NONTRANSLATED) + return [_SizeDelta('Uncompressed Pak Entry', 'bytes', _MAX_PAK_INCREASE, + pak.after_symbol.size, pak.full_name) + for pak in pak_symbols] def main(): parser = argparse.ArgumentParser() - parser.add_argument('--author', help='CL author') - parser.add_argument('--resource-sizes-diff', - help='Path to resource sizes diff produced by ' - '"diagnose_bloat.py diff sizes".') + parser.add_argument('--author', required=True, help='CL author') + parser.add_argument('--apk-name', required=True, + help='Name of the apk (ex. Name.apk)') + parser.add_argument('--before-dir', required=True, + help='Directory containing the APK from reference build.') + parser.add_argument('--after-dir', required=True, + help='Directory containing APK for the new build.') + parser.add_argument('--resource-sizes-diff-path', required=True, + help='Output path for the resource_sizes.py diff.') + parser.add_argument('--supersize-diff-path', required=True, + help='Output path for the Supersize diff.') + parser.add_argument('--dex-method-count-diff-path', required=True, + help='Output path for the dex method count diff.') + parser.add_argument('--ndjson-path', required=True, + help='Output path for the Supersize HTML report.') + parser.add_argument('--results-path', required=True, + help='Output path for the trybot result .json file.') + parser.add_argument('-v', '--verbose', action='store_true') args = parser.parse_args() - # Last line looks like: - # MonochromePublic.apk_Specifics normalized apk size=1234 - with open(args.resource_sizes_diff) as f: - last_line = f.readlines()[-1] - size_delta = int(last_line.partition('=')[2]) + if args.verbose: + logging.basicConfig(level=logging.INFO) + + logging.info('Creating Supersize diff') + delta_size_info = _CreateAndWriteSupersizeDiff( + args.apk_name, args.before_dir, args.after_dir, args.supersize_diff_path) + changed_symbols = delta_size_info.raw_symbols.WhereDiffStatusIs( + models.DIFF_STATUS_UNCHANGED).Inverted() + + # Monitor dex method growth since this correlates closely with APK size and + # may affect our dex file structure. + logging.info('Checking dex symbols') + size_deltas = set() + size_deltas.add( + _CreateAndWriteMethodCountDelta( + changed_symbols, args.dex_method_count_diff_path)) + + # Check for uncompressed .pak file entries being added to avoid unnecessary + # bloat. + logging.info('Checking pak symbols') + size_deltas.update(_CreateUncompressedPakSizeDeltas(changed_symbols)) + + # Normalized APK Size is the main metric we use to monitor binary size. + logging.info('Creating sizes diff') + size_deltas.add( + _CreateAndWriteResourceSizesDelta( + args.apk_name, args.before_dir, args.after_dir, + args.resource_sizes_diff_path)) + + # .ndjson can be consumed by the html viewer. + logging.info('Creating HTML Report') + html_report.BuildReportFromSizeInfo( + args.ndjson_path, delta_size_info, all_symbols=True) is_roller = '-autoroll' in args.author # Useful for bot debugging to have these printed out: - print 'Is Roller:', is_roller - print 'Increase:', size_delta + for delta in sorted(size_deltas): + print '{}\n\n'.format(delta.explanation) - if size_delta > _MAX_UNNOTICED_INCREASE and not is_roller: - # Failure message printed to stderr, so flush first. - sys.stdout.flush() - failure_message = """ + passing_deltas = set(m for m in size_deltas if m._IsAllowable()) + failing_deltas = size_deltas - passing_deltas -Binary size increase is non-trivial (where "non-trivial" means the normalized \ -size increased by more than {} bytes). + result = 'passed' if is_roller or len(failing_deltas) == 0 else 'failed' + message = """ -Please look at the symbol diffs from the "Show Resource Sizes Diff" and the \ -"Show Supersize Diff" bot steps. Try and understand the growth and see if it \ -can be mitigated. There is guidance at: +Binary size checks {}. + +******************************************************************************* +FAILING: + +{} + +******************************************************************************* + +PASSING: + +{} + +******************************************************************************* + +Please look at the symbol diffs from the "Show Resource Sizes Diff", +"Show Supersize Diff", and "Dex Method Count", and "Supersize HTML Report" bot +steps. Try and understand the growth and see if it can be mitigated. + +There is guidance at: https://chromium.googlesource.com/chromium/src/+/master/docs/speed/apk_size_regressions.md#Debugging-Apk-Size-Increase @@ -59,11 +205,14 @@ Binary-Size: Increase needed to reduce runtime of a common user flow. Binary-Size: Increase needed to implement a feature, and I've already spent a non-trivial amount of time trying to reduce its size. -""".format(_MAX_UNNOTICED_INCREASE) - # Make blank lines not blank prevent them from being stripped. - # https://crbug.com/855671 - failure_message.replace('\n\n', '\n.\n') - sys.exit(failure_message) +""".format(result, + '\n\n'.join(d.explanation for d in sorted(failing_deltas)), + '\n\n'.join(d.explanation for d in sorted(passing_deltas))) + # Make blank lines not blank prevent them from being stripped. + # https://crbug.com/855671 + message.replace('\n\n', '\n.\n') + with open(args.results_path, 'w') as f: + json.dump({'status_code': len(failing_deltas), 'details': message}, f) if __name__ == '__main__':
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 424cafec..00f565b 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -20222,6 +20222,10 @@ <int value="2542" label="PaymentAddressLanguageCode"/> <int value="2543" label="DocumentDomainBlockedCrossOriginAccess"/> <int value="2544" label="DocumentDomainEnabledCrossOriginAccess"/> + <int value="2545" label="SerialGetPorts"/> + <int value="2546" label="SerialRequestPort"/> + <int value="2547" label="SerialPortOpen"/> + <int value="2548" label="SerialPortClose"/> </enum> <enum name="FeaturePolicyFeature"> @@ -43739,14 +43743,13 @@ </enum> <enum name="SBDownloadFeedbackUploadResult"> - <int value="0" label="SUCCESS"/> - <int value="1" label="UPLOAD_SUCCESS"/> - <int value="2" label="UPLOAD_CANCELLED"/> - <int value="3" label="UPLOAD_METADATA_NET_ERROR"/> - <int value="4" label="UPLOAD_METADATA_RESPONSE_ERROR"/> - <int value="5" label="UPLOAD_FILE_NET_ERROR"/> - <int value="6" label="UPLOAD_FILE_RESPONSE_ERROR"/> - <int value="7" label="UPLOAD_COMPLETE_RESPONSE_ERROR"/> + <int value="0" label="UPLOAD_SUCCESS"/> + <int value="1" label="UPLOAD_CANCELLED"/> + <int value="2" label="UPLOAD_METADATA_NET_ERROR"/> + <int value="3" label="UPLOAD_METADATA_RESPONSE_ERROR"/> + <int value="4" label="UPLOAD_FILE_NET_ERROR"/> + <int value="5" label="UPLOAD_FILE_RESPONSE_ERROR"/> + <int value="6" label="UPLOAD_COMPLETE_RESPONSE_ERROR"/> </enum> <enum name="SBFileTypeUpdateResult">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index f5501002..a9cb875 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -72530,6 +72530,17 @@ </summary> </histogram> +<histogram name="PasswordManager.InvalidtHttpsCredentialsNeedToBeCleared" + enum="BooleanNeedsClearing" expires_after="M73"> + <owner>vabr@chromium.org</owner> + <owner>jdoerrie@chromium.org</owner> + <summary> + Records once on startup whether forms with wrong signon_realm created by + HTTP to HTTPS migration need to be removed. See https://crbug.com/881731 for + more details. + </summary> +</histogram> + <histogram name="PasswordManager.IsSyncPasswordHashSaved" enum="IsSyncPasswordHashSaved"> <owner>dvadym@chromium.org</owner> @@ -83438,11 +83449,14 @@ <histogram name="Renderer4.GestureScrollingThreadStatus" enum="ScrollingThreadStatus"> + <obsolete> + Deprecated 9/2018 and merged into Renderer4.MainThreadGestureScrollReason. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> - For every gesture, we record whether the scroll occurred on the main thread, - on the compositor thread, or on the compositor thread but blocked on the - main thread. The last case will happen when there is a blocking event + For every touch scroll, we record whether the scroll occurred on the main + thread, on the compositor thread, or on the compositor thread but blocked on + the main thread. The last case will happen when there is a blocking event listener. </summary> </histogram> @@ -83696,7 +83710,8 @@ Ideally we'd always scroll on the impl thread, but there are a variety of situations where we need to scroll on main. We should try to drive these down. For every gesture, we record whether or not the scroll occurred on the - main thread, and if it did, what the reason was. + main thread or it should scroll on the impl thread but is blocked on main + thread, and if it did, what the reason was. </summary> </histogram> @@ -83707,7 +83722,8 @@ Ideally we'd always scroll on the impl thread, but there are a variety of situations where we need to scroll on main. We should try to drive these down. For every wheel tick, we record whether or not the the scroll occurred - on the main thread, and if it did, what the reason was. + on the main thread or it should scroll on the impl thread but is blocked on + main thread, and if it did, what the reason was. </summary> </histogram> @@ -83978,6 +83994,9 @@ <histogram name="Renderer4.WheelScrollingThreadStatus" enum="ScrollingThreadStatus"> + <obsolete> + Deprecated 9/2018 and merged into Renderer4.MainThreadWheelScrollReason. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> For every wheel tick, we record whether the scroll occurred on the main @@ -86737,6 +86756,26 @@ </summary> </histogram> +<histogram name="SafeBrowsing.ContentsSize.Height" units="DIPs" + expires_after="M73"> + <owner>jialiul@chrormium.org</owner> + <owner>nparker@chromium.org</owner> + <summary> + Records the height of content area when the user opens a new browser window + or when the user finishes resizing a browser window. + </summary> +</histogram> + +<histogram name="SafeBrowsing.ContentsSize.Width" units="DIPs" + expires_after="M73"> + <owner>jialiul@chrormium.org</owner> + <owner>nparker@chromium.org</owner> + <summary> + Records the width of content area when the user opens a new browser window + or when the user finishes resizing a browser window. + </summary> +</histogram> + <histogram name="SafeBrowsing.EnabledSettingChanged" enum="BooleanEnabled"> <obsolete> Not in the code anymore (10/2015).
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc index 9db9aed2..76810a1a 100644 --- a/ui/accessibility/ax_node_data.cc +++ b/ui/accessibility/ax_node_data.cc
@@ -565,6 +565,11 @@ actions = ModifyFlag(actions, static_cast<uint32_t>(action_enum), true); } +void AXNodeData::RemoveState(ax::mojom::State state_enum) { + DCHECK_NE(state_enum, ax::mojom::State::kNone); + state = ModifyFlag(state, static_cast<uint32_t>(state_enum), false); +} + std::string AXNodeData::ToString() const { std::string result;
diff --git a/ui/accessibility/ax_node_data.h b/ui/accessibility/ax_node_data.h index 468b13f..c7d3320e 100644 --- a/ui/accessibility/ax_node_data.h +++ b/ui/accessibility/ax_node_data.h
@@ -134,6 +134,9 @@ void AddState(ax::mojom::State state_enum); void AddAction(ax::mojom::Action action_enum); + // Remove bits in the given enum's corresponding bitfield. + void RemoveState(ax::mojom::State state_enum); + // Helper functions to get some common int attributes with some specific // enum types: ax::mojom::CheckedState GetCheckedState() const {
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 9f340f7..f48f30e 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1178,7 +1178,8 @@ if (target) { (*targets)[index] = static_cast<IAccessible*>(target); (*targets)[index]->AddRef(); - index++; + if (++index > count) + break; } } *n_targets = index;
diff --git a/ui/accessibility/platform/ax_system_caret_win.cc b/ui/accessibility/platform/ax_system_caret_win.cc index bd475d5..dd91704c 100644 --- a/ui/accessibility/platform/ax_system_caret_win.cc +++ b/ui/accessibility/platform/ax_system_caret_win.cc
@@ -24,6 +24,7 @@ data_.role = ax::mojom::Role::kCaret; // |get_accState| should return 0 which means that the caret is visible. data_.state = 0; + data_.AddState(ax::mojom::State::kInvisible); // According to MSDN, "Edit" should be the name of the caret object. data_.SetName(L"Edit"); data_.offset_container_id = -1; @@ -54,13 +55,43 @@ void AXSystemCaretWin::MoveCaretTo(const gfx::Rect& bounds) { if (bounds.IsEmpty()) return; - data_.location = gfx::RectF(bounds); - if (event_target_) { + + // If the caret has non-empty bounds, assume it has been made visible. + bool newly_visible = false; + if (data_.HasState(ax::mojom::State::kInvisible)) { + newly_visible = true; + data_.RemoveState(ax::mojom::State::kInvisible); + } + + if (!event_target_) + return; + + if (newly_visible) { + ::NotifyWinEvent(EVENT_OBJECT_SHOW, event_target_, OBJID_CARET, + -caret_->GetUniqueId()); + } + + gfx::RectF new_location(bounds); + // Avoid redundant caret move events (if the location stays the same), but + // always fire when it's made visible again. + if (data_.location != new_location || newly_visible) { + data_.location = new_location; ::NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, event_target_, OBJID_CARET, -caret_->GetUniqueId()); } } +void AXSystemCaretWin::Hide() { + if (!data_.HasState(ax::mojom::State::kInvisible)) { + data_.AddState(ax::mojom::State::kInvisible); + data_.location.set_width(0); + if (event_target_) { + ::NotifyWinEvent(EVENT_OBJECT_HIDE, event_target_, OBJID_CARET, + -caret_->GetUniqueId()); + } + } +} + const AXNodeData& AXSystemCaretWin::GetData() const { return data_; }
diff --git a/ui/accessibility/platform/ax_system_caret_win.h b/ui/accessibility/platform/ax_system_caret_win.h index 03f4bf9..a4d2392 100644 --- a/ui/accessibility/platform/ax_system_caret_win.h +++ b/ui/accessibility/platform/ax_system_caret_win.h
@@ -31,6 +31,7 @@ Microsoft::WRL::ComPtr<IAccessible> GetCaret() const; void MoveCaretTo(const gfx::Rect& bounds); + void Hide(); private: // |AXPlatformNodeDelegate| members.
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc index 420df48..d37158e 100644 --- a/ui/events/blink/input_handler_proxy.cc +++ b/ui/events/blink/input_handler_proxy.cc
@@ -466,6 +466,17 @@ DCHECK( !cc::MainThreadScrollingReason::HasNonCompositedScrollReasons(reasons)); + int32_t event_disposition_result = + (device == blink::kWebGestureDeviceTouchpad ? mouse_wheel_result_ + : touch_result_); + if (event_disposition_result == DID_NOT_HANDLE) { + // We should also collect main thread scrolling reasons if a scroll event + // scrolls on impl thread but is blocked by main thread event handlers. + reasons |= (device == blink::kWebGestureDeviceTouchpad + ? cc::MainThreadScrollingReason::kWheelEventHandlerRegion + : cc::MainThreadScrollingReason::kTouchEventHandlerRegion); + } + // UMA_HISTOGRAM_ENUMERATION requires that the enum_max must be strictly // greater than the sample value. kMainThreadScrollingReasonCount doesn't // include the NotScrollingOnMain enum but the histograms do so adding @@ -511,51 +522,6 @@ } } -void InputHandlerProxy::RecordScrollingThreadStatus( - blink::WebGestureDevice device, - uint32_t reasons) { - if (device != blink::kWebGestureDeviceTouchpad && - device != blink::kWebGestureDeviceTouchscreen) { - return; - } - - ScrollingThreadStatus scrolling_thread_status = SCROLLING_ON_MAIN; - if (reasons == cc::MainThreadScrollingReason::kNotScrollingOnMain) { - int32_t event_disposition_result = - (device == blink::kWebGestureDeviceTouchpad ? mouse_wheel_result_ - : touch_result_); - switch (event_disposition_result) { - case kEventDispositionUndefined: - case DID_NOT_HANDLE_NON_BLOCKING_DUE_TO_FLING: - case DID_HANDLE_NON_BLOCKING: - case DROP_EVENT: - scrolling_thread_status = SCROLLING_ON_COMPOSITOR; - break; - case DID_NOT_HANDLE: - scrolling_thread_status = SCROLLING_ON_COMPOSITOR_BLOCKED_ON_MAIN; - break; - default: - NOTREACHED(); - scrolling_thread_status = SCROLLING_ON_COMPOSITOR; - } - } - - // UMA_HISTOGRAM_ENUMERATION requires that the enum_max must be strictly - // greater than the sample value. - const uint32_t kScrolingThreadStatusEnumMax = - ScrollingThreadStatus::LAST_SCROLLING_THREAD_STATUS_VALUE + 1; - - if (device == blink::kWebGestureDeviceTouchscreen) { - UMA_HISTOGRAM_ENUMERATION("Renderer4.GestureScrollingThreadStatus", - scrolling_thread_status, - kScrolingThreadStatusEnumMax); - } else { - UMA_HISTOGRAM_ENUMERATION("Renderer4.WheelScrollingThreadStatus", - scrolling_thread_status, - kScrolingThreadStatusEnumMax); - } -} - bool InputHandlerProxy::ShouldAnimate(bool has_precise_scroll_deltas) const { #if defined(OS_MACOSX) // Mac does not smooth scroll wheel events (crbug.com/574283). @@ -646,9 +612,6 @@ RecordMainThreadScrollingReasons(gesture_event.SourceDevice(), scroll_status.main_thread_scrolling_reasons); - RecordScrollingThreadStatus(gesture_event.SourceDevice(), - scroll_status.main_thread_scrolling_reasons); - InputHandlerProxy::EventDisposition result = DID_NOT_HANDLE; scroll_sequence_ignored_ = false; in_inertial_scrolling_ = false;
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc index 9f5bd515..c0d6d6f 100644 --- a/ui/events/blink/input_handler_proxy_unittest.cc +++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -1375,234 +1375,6 @@ testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler); } -TEST_P(InputHandlerProxyTest, MainThreadScrollingMouseWheelHistograms) { - input_handler_->RecordMainThreadScrollingReasonsForTest( - blink::kWebGestureDeviceTouchpad, - cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects | - cc::MainThreadScrollingReason::kThreadedScrollingDisabled | - cc::MainThreadScrollingReason::kPageOverlay | - cc::MainThreadScrollingReason::kHandlingScrollFromMainThread); - - EXPECT_THAT( - histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"), - testing::ElementsAre(base::Bucket(1, 1), base::Bucket(3, 1), - base::Bucket(5, 1))); - - // We only want to record "Handling scroll from main thread" reason if it's - // the only reason. If it's not the only reason, the "real" reason for - // scrolling on main is something else, and we only want to pay attention to - // that reason. So we should only include this reason in the histogram when - // its on its own. - input_handler_->RecordMainThreadScrollingReasonsForTest( - blink::kWebGestureDeviceTouchpad, - cc::MainThreadScrollingReason::kHandlingScrollFromMainThread); - - EXPECT_THAT( - histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"), - testing::ElementsAre(base::Bucket(1, 1), base::Bucket(3, 1), - base::Bucket(5, 1), base::Bucket(14, 1))); -} - -TEST_P(InputHandlerProxyTest, GestureScrollingThreadStatusHistogram) { - VERIFY_AND_RESET_MOCKS(); - - WebTouchEvent touch_start(WebInputEvent::kTouchStart, - WebInputEvent::kNoModifiers, - WebInputEvent::GetStaticTimeStampForTests()); - touch_start.touches_length = 1; - touch_start.touch_start_or_first_touch_move = true; - touch_start.touches[0] = - CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10); - - WebGestureEvent gesture_scroll_begin( - WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers, - WebInputEvent::GetStaticTimeStampForTests(), - blink::kWebGestureDeviceTouchscreen); - - WebGestureEvent gesture_scroll_end( - WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers, - WebInputEvent::GetStaticTimeStampForTests(), - blink::kWebGestureDeviceTouchscreen); - - // Touch start with passive event listener. - EXPECT_CALL( - mock_input_handler_, - EventListenerTypeForTouchStartOrMoveAt( - testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_)) - .WillOnce(testing::Return( - cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER)); - EXPECT_CALL( - mock_input_handler_, - GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove)) - .WillOnce(testing::Return(cc::EventListenerProperties::kPassive)); - EXPECT_CALL(mock_client_, - SetWhiteListedTouchAction(testing::_, testing::_, testing::_)) - .WillOnce(testing::Return()); - - expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(touch_start)); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(kImplThreadScrollState)); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_begin)); - - EXPECT_THAT(histogram_tester().GetAllSamples( - "Renderer4.GestureScrollingThreadStatus"), - testing::ElementsAre(base::Bucket(0, 1))); - - EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_end)); - - VERIFY_AND_RESET_MOCKS(); - - // Touch event with HANDLER_ON_SCROLLING_LAYER event listener. - EXPECT_CALL( - mock_input_handler_, - EventListenerTypeForTouchStartOrMoveAt( - testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_)) - .WillOnce( - testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType:: - HANDLER_ON_SCROLLING_LAYER)); - EXPECT_CALL(mock_client_, - SetWhiteListedTouchAction(testing::_, testing::_, testing::_)) - .WillOnce(testing::Return()); - - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(touch_start)); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(kImplThreadScrollState)); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_begin)); - - EXPECT_THAT(histogram_tester().GetAllSamples( - "Renderer4.GestureScrollingThreadStatus"), - testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1))); - - EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_end)); - - VERIFY_AND_RESET_MOCKS(); - - // Gesture scrolling on main thread. - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(kMainThreadScrollState)); - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_begin)); - - EXPECT_THAT(histogram_tester().GetAllSamples( - "Renderer4.GestureScrollingThreadStatus"), - testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1), - base::Bucket(2, 1))); - - EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_end)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, WheelScrollingThreadStatusHistogram) { - VERIFY_AND_RESET_MOCKS(); - - WebMouseWheelEvent wheel(WebInputEvent::kMouseWheel, - WebInputEvent::kControlKey, - WebInputEvent::GetStaticTimeStampForTests()); - - WebGestureEvent gesture_scroll_begin( - WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers, - WebInputEvent::GetStaticTimeStampForTests(), - blink::kWebGestureDeviceTouchpad); - - WebGestureEvent gesture_scroll_end( - WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers, - WebInputEvent::GetStaticTimeStampForTests(), - blink::kWebGestureDeviceTouchpad); - - // Wheel event with passive event listener. - EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_)) - .WillRepeatedly(testing::Return(false)); - EXPECT_CALL(mock_input_handler_, - GetEventListenerProperties(cc::EventListenerClass::kMouseWheel)) - .WillOnce(testing::Return(cc::EventListenerProperties::kPassive)); - expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(kImplThreadScrollState)); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_begin)); - - EXPECT_THAT( - histogram_tester().GetAllSamples("Renderer4.WheelScrollingThreadStatus"), - testing::ElementsAre(base::Bucket(0, 1))); - - EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_end)); - - VERIFY_AND_RESET_MOCKS(); - - // Wheel event with blocking event listener. If there is a wheel event handler - // at the point, we do not need to call GetEventListenerProperties since it - // indicates kBlocking. - EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_)) - .WillRepeatedly(testing::Return(true)); - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(kImplThreadScrollState)); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_begin)); - - EXPECT_THAT( - histogram_tester().GetAllSamples("Renderer4.WheelScrollingThreadStatus"), - testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1))); - - EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_end)); - - VERIFY_AND_RESET_MOCKS(); - - // Wheel scrolling on main thread. - EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_)) - .WillRepeatedly(testing::Return(true)); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(kMainThreadScrollState)); - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_begin)); - - EXPECT_THAT( - histogram_tester().GetAllSamples("Renderer4.WheelScrollingThreadStatus"), - testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1), - base::Bucket(2, 1))); - - EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_scroll_end)); - - VERIFY_AND_RESET_MOCKS(); -} - TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScroll) { base::HistogramTester histogram_tester; @@ -2103,8 +1875,423 @@ testing::Mock::VerifyAndClearExpectations(&mock_input_handler_); } +class InputHandlerProxyMainThreadScrollingReasonTest + : public InputHandlerProxyTest { + public: + enum TestEventType { + Touch, + MouseWheel, + }; + + InputHandlerProxyMainThreadScrollingReasonTest() : InputHandlerProxyTest() {} + ~InputHandlerProxyMainThreadScrollingReasonTest() { input_handler_.reset(); } + + void SetupEvents(TestEventType type) { + touch_start_ = + WebTouchEvent(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()); + touch_end_ = + WebTouchEvent(WebInputEvent::kTouchEnd, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()); + wheel_event_ = WebMouseWheelEvent( + WebInputEvent::kMouseWheel, WebInputEvent::kControlKey, + WebInputEvent::GetStaticTimeStampForTests()); + gesture_scroll_begin_ = WebGestureEvent( + WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests(), + type == TestEventType::MouseWheel + ? blink::kWebGestureDeviceTouchpad + : blink::kWebGestureDeviceTouchscreen); + gesture_scroll_end_ = WebGestureEvent( + WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests(), + type == TestEventType::MouseWheel + ? blink::kWebGestureDeviceTouchpad + : blink::kWebGestureDeviceTouchscreen); + touch_start_.touches_length = 1; + touch_start_.touch_start_or_first_touch_move = true; + touch_start_.touches[0] = + CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10); + + touch_end_.touches_length = 1; + } + + base::HistogramBase::Sample GetBucketSample(uint32_t reason) { + if (reason == cc::MainThreadScrollingReason::kNotScrollingOnMain) + return 0; + + uint32_t bucket = 1; + while ((reason = reason >> 1)) + bucket++; + return bucket; + } + + protected: + WebTouchEvent touch_start_; + WebTouchEvent touch_end_; + WebMouseWheelEvent wheel_event_; + WebGestureEvent gesture_scroll_begin_; + WebGestureEvent gesture_scroll_end_; +}; + +TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, + GestureScrollNotScrollOnMain) { + // Touch start with passive event listener. + SetupEvents(TestEventType::Touch); + + EXPECT_CALL( + mock_input_handler_, + EventListenerTypeForTouchStartOrMoveAt( + testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_)) + .WillOnce(testing::Return( + cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER)); + EXPECT_CALL( + mock_input_handler_, + GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove)) + .WillOnce(testing::Return(cc::EventListenerProperties::kPassive)); + EXPECT_CALL(mock_client_, + SetWhiteListedTouchAction(testing::_, testing::_, testing::_)) + .WillOnce(testing::Return()); + + expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(touch_start_)); + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kImplThreadScrollState)); + expected_disposition_ = InputHandlerProxy::DID_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_begin_)); + EXPECT_THAT( + histogram_tester().GetAllSamples( + "Renderer4.MainThreadGestureScrollReason"), + testing::ElementsAre(base::Bucket( + GetBucketSample(cc::MainThreadScrollingReason::kNotScrollingOnMain), + 1))); + + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + expected_disposition_ = InputHandlerProxy::DID_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_end_)); +} + +TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, + GestureScrollTouchEventHandlerRegion) { + // The touch event hits a touch event handler and should block on main thread. + // Since ScrollBegin allows the gesture to scroll on impl. We collect + // TouchEventHandler reason but not HandlingScrollFromMainThread. + SetupEvents(TestEventType::Touch); + + EXPECT_CALL( + mock_input_handler_, + EventListenerTypeForTouchStartOrMoveAt( + testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_)) + .WillOnce( + testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType:: + HANDLER_ON_SCROLLING_LAYER)); + EXPECT_CALL(mock_client_, + SetWhiteListedTouchAction(testing::_, testing::_, testing::_)) + .WillOnce(testing::Return()); + + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(touch_start_)); + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kImplThreadScrollState)); + expected_disposition_ = InputHandlerProxy::DID_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_begin_)); + EXPECT_THAT(histogram_tester().GetAllSamples( + "Renderer4.MainThreadGestureScrollReason"), + testing::ElementsAre(base::Bucket( + GetBucketSample( + cc::MainThreadScrollingReason::kTouchEventHandlerRegion), + 1))); + + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + expected_disposition_ = InputHandlerProxy::DID_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_end_)); +} + +TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, + GestureScrollTouchEventHandlerRegionAndHandlingScrollFromMainThread) { + // The touch event hits a touch event handler and should block on main thread. + // Since ScrollBegin doesn't allow the gesture to scroll on impl. We report + // TouchEventHandler reason as well as HandlingScrollFromMainThread. Since we + // do not collect HandlingScrollFromMainThread when there are other reasons + // present, TouchEventHandler is the only reason being collected in the + // histogram. + SetupEvents(TestEventType::Touch); + + EXPECT_CALL( + mock_input_handler_, + EventListenerTypeForTouchStartOrMoveAt( + testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_)) + .WillOnce( + testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType:: + HANDLER_ON_SCROLLING_LAYER)); + EXPECT_CALL(mock_client_, + SetWhiteListedTouchAction(testing::_, testing::_, testing::_)) + .WillOnce(testing::Return()); + + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(touch_start_)); + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kMainThreadScrollState)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_begin_)); + + EXPECT_THAT(histogram_tester().GetAllSamples( + "Renderer4.MainThreadGestureScrollReason"), + testing::ElementsAre(base::Bucket( + GetBucketSample( + cc::MainThreadScrollingReason::kTouchEventHandlerRegion), + 1))); + + // Handle touch end event so that input handler proxy is out of the state of + // DID_NOT_HANDLE. + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_end_)); + + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(touch_end_)); +} + +TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, + GestureScrollHandlingScrollFromMainThread) { + // Gesture scrolling on main thread. We only record + // HandlingScrollFromMainThread when it's the only available reason. + SetupEvents(TestEventType::Touch); + EXPECT_CALL( + mock_input_handler_, + EventListenerTypeForTouchStartOrMoveAt( + testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_)) + .WillOnce(testing::Return( + cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER)); + EXPECT_CALL(mock_client_, + SetWhiteListedTouchAction(testing::_, testing::_, testing::_)) + .WillOnce(testing::Return()); + EXPECT_CALL(mock_input_handler_, GetEventListenerProperties(testing::_)) + .WillRepeatedly(testing::Return(cc::EventListenerProperties::kPassive)); + + expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(touch_start_)); + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kMainThreadScrollState)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_begin_)); + + EXPECT_THAT( + histogram_tester().GetAllSamples( + "Renderer4.MainThreadGestureScrollReason"), + testing::ElementsAre(base::Bucket( + GetBucketSample( + cc::MainThreadScrollingReason::kHandlingScrollFromMainThread), + 1))); + + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_end_)); +} + +TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, WheelScrollHistogram) { + // Firstly check if input handler can correctly record main thread scrolling + // reasons. + input_handler_->RecordMainThreadScrollingReasonsForTest( + blink::kWebGestureDeviceTouchpad, + cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects | + cc::MainThreadScrollingReason::kThreadedScrollingDisabled | + cc::MainThreadScrollingReason::kPageOverlay | + cc::MainThreadScrollingReason::kHandlingScrollFromMainThread); + + EXPECT_THAT( + histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"), + testing::ElementsAre( + base::Bucket( + GetBucketSample(cc::MainThreadScrollingReason:: + kHasBackgroundAttachmentFixedObjects), + 1), + base::Bucket( + GetBucketSample( + cc::MainThreadScrollingReason::kThreadedScrollingDisabled), + 1), + base::Bucket( + GetBucketSample(cc::MainThreadScrollingReason::kPageOverlay), + 1))); + + // We only want to record "Handling scroll from main thread" reason if it's + // the only reason. If it's not the only reason, the "real" reason for + // scrolling on main is something else, and we only want to pay attention to + // that reason. So we should only include this reason in the histogram when + // its on its own. + input_handler_->RecordMainThreadScrollingReasonsForTest( + blink::kWebGestureDeviceTouchpad, + cc::MainThreadScrollingReason::kHandlingScrollFromMainThread); + + EXPECT_THAT( + histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"), + testing::ElementsAre( + base::Bucket( + GetBucketSample(cc::MainThreadScrollingReason:: + kHasBackgroundAttachmentFixedObjects), + 1), + base::Bucket( + GetBucketSample( + cc::MainThreadScrollingReason::kThreadedScrollingDisabled), + 1), + base::Bucket( + GetBucketSample(cc::MainThreadScrollingReason::kPageOverlay), 1), + base::Bucket( + GetBucketSample( + cc::MainThreadScrollingReason::kHandlingScrollFromMainThread), + 1))); +} + +TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, + WheelScrollNotScrollingOnMain) { + // Even if a scroller is composited, we still need to record its main thread + // scrolling reason if it is blocked on a main thread event handler. + SetupEvents(TestEventType::MouseWheel); + + // We can scroll on impl for an wheel event with passive event listener. + EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_)) + .WillRepeatedly(testing::Return(false)); + EXPECT_CALL(mock_input_handler_, + GetEventListenerProperties(cc::EventListenerClass::kMouseWheel)) + .WillOnce(testing::Return(cc::EventListenerProperties::kPassive)); + expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(wheel_event_)); + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kImplThreadScrollState)); + expected_disposition_ = InputHandlerProxy::DID_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_begin_)); + + EXPECT_THAT( + histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"), + testing::ElementsAre(base::Bucket( + GetBucketSample(cc::MainThreadScrollingReason::kNotScrollingOnMain), + 1))); + + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + expected_disposition_ = InputHandlerProxy::DID_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_end_)); +} + +TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, + WheelScrollWheelEventHandlerRegion) { + // Wheel event with blocking event listener. If there is a wheel event handler + // at the point, we do not need to call GetEventListenerProperties since it + // indicates kBlocking. + SetupEvents(TestEventType::MouseWheel); + EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_)) + .WillRepeatedly(testing::Return(true)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(wheel_event_)); + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kImplThreadScrollState)); + expected_disposition_ = InputHandlerProxy::DID_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_begin_)); + + EXPECT_THAT( + histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"), + testing::ElementsAre(base::Bucket( + GetBucketSample( + cc::MainThreadScrollingReason::kWheelEventHandlerRegion), + 1))); + + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + expected_disposition_ = InputHandlerProxy::DID_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_end_)); +} + +TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, + WheelScrollWheelEventHandlerRegionAndHandlingScrollFromMainThread) { + // Wheel scrolling on main thread. Because we also block scrolling with wheel + // event handler, we should record that reason as well. + SetupEvents(TestEventType::MouseWheel); + EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_)) + .WillRepeatedly(testing::Return(true)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(wheel_event_)); + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kMainThreadScrollState)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_begin_)); + + EXPECT_THAT( + histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"), + testing::ElementsAre(base::Bucket( + GetBucketSample( + cc::MainThreadScrollingReason::kWheelEventHandlerRegion), + 1))); + + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_end_)); +} + +TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, + WheelScrollHandlingScrollFromMainThread) { + // Gesture scrolling on main thread. We only record + // HandlingScrollFromMainThread when it's the only available reason. + SetupEvents(TestEventType::MouseWheel); + EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_)) + .WillRepeatedly(testing::Return(false)); + EXPECT_CALL(mock_input_handler_, + GetEventListenerProperties(cc::EventListenerClass::kMouseWheel)) + .WillOnce(testing::Return(cc::EventListenerProperties::kNone)); + expected_disposition_ = InputHandlerProxy::DROP_EVENT; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(wheel_event_)); + + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) + .WillOnce(testing::Return(kMainThreadScrollState)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_begin_)); + + EXPECT_THAT( + histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"), + testing::ElementsAre(base::Bucket( + GetBucketSample( + cc::MainThreadScrollingReason::kHandlingScrollFromMainThread), + 1))); + + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); + expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; + EXPECT_EQ(expected_disposition_, + input_handler_->HandleInputEvent(gesture_scroll_end_)); +} + INSTANTIATE_TEST_CASE_P(AnimateInput, InputHandlerProxyTest, testing::ValuesIn(test_types)); + +INSTANTIATE_TEST_CASE_P(AnimateInput, + InputHandlerProxyMainThreadScrollingReasonTest, + testing::ValuesIn(test_types)); } // namespace test } // namespace ui
diff --git a/ui/events/cocoa/events_mac.mm b/ui/events/cocoa/events_mac.mm index c60c04c7..17d539b 100644 --- a/ui/events/cocoa/events_mac.mm +++ b/ui/events/cocoa/events_mac.mm
@@ -63,6 +63,7 @@ case NSEventTypeRotate: case NSEventTypeBeginGesture: case NSEventTypeEndGesture: + case NSEventTypePressure: break; default: NOTIMPLEMENTED() << type;
diff --git a/ui/latency/frame_metrics_test_common.h b/ui/latency/frame_metrics_test_common.h index c48e814..30ed36d9 100644 --- a/ui/latency/frame_metrics_test_common.h +++ b/ui/latency/frame_metrics_test_common.h
@@ -76,21 +76,6 @@ } } -// Same as AddPatternHelper, but uses each value (+1) as its own weight. -// The "Cubed" name comes from the fact that the squared_accumulator -// for the RMS will effectively be a "cubed accumulator". -template <typename AnalyzerType> -void AddCubedPatternHelper(SharedWindowedAnalyzerClient* shared_client, - AnalyzerType* analyzer, - const std::vector<uint32_t>& values) { - for (auto i : values) { - shared_client->window_begin += base::TimeDelta::FromMicroseconds(1); - shared_client->window_end += base::TimeDelta::FromMicroseconds(1); - // weight is i+1 to avoid divide by zero. - AddSamplesHelper(analyzer, i, i + 1, 1); - } -} - // Mean and RMS can be exact for most values, however SMR loses a bit of // precision internally when accumulating the roots. Make sure the SMR // precision is at least within .5 (i.e. rounded to the nearest integer
diff --git a/ui/latency/windowed_analyzer_unittest.cc b/ui/latency/windowed_analyzer_unittest.cc index 71b4248..f60eb82 100644 --- a/ui/latency/windowed_analyzer_unittest.cc +++ b/ui/latency/windowed_analyzer_unittest.cc
@@ -6,6 +6,7 @@ #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/latency/fixed_point.h" #include "ui/latency/frame_metrics_test_common.h" namespace ui { @@ -351,6 +352,22 @@ naive_total_weight_ += weight; } + // Same as AddPatternHelper, but uses each value (+1) as its own weight. + // The "Cubed" name comes from the fact that the squared_accumulator + // for the RMS will effectively be a "cubed accumulator". + void AddCubedPatternHelper(SharedWindowedAnalyzerClient* shared_client, + const std::vector<uint32_t>& values) { + for (auto i : values) { + shared_client->window_begin += base::TimeDelta::FromMicroseconds(1); + shared_client->window_end += base::TimeDelta::FromMicroseconds(1); + uint64_t weighted_value = (i * (i + 1)); + uint64_t updated_value = static_cast<uint64_t>(i); + uint64_t weighted_root = (i + 1) * std::sqrt(updated_value << 32); + Accumulator96b weighted_square(i, (i + 1)); + AddSample(i, (i + 1), weighted_value, weighted_root, weighted_square); + } + } + struct Sample { uint32_t value; uint32_t weight; @@ -412,8 +429,8 @@ double naive_root_accumulator_prev = 0; double naive_square_accumulator_prev = 0; for (size_t i = 1; i <= kRuns; i++) { - AddCubedPatternHelper(&shared_client_naive, &analyzer_naive, pattern_bad); - AddCubedPatternHelper(&shared_client_naive, &analyzer_naive, pattern_clear); + analyzer_naive.AddCubedPatternHelper(&shared_client_naive, pattern_bad); + analyzer_naive.AddCubedPatternHelper(&shared_client_naive, pattern_clear); EXPECT_EQ(0, analyzer_naive.naive_accumulator_); EXPECT_ABS_LT(naive_root_accumulator_prev, analyzer_naive.naive_root_accumulator_); @@ -427,15 +444,6 @@ analyzer_naive.naive_root_accumulator_); EXPECT_ABS_LE(naive_square_error_floor * kRuns, analyzer_naive.naive_square_accumulator_); - - // Verify actual implementation has no error. - for (size_t i = 1; i <= kRuns; i++) { - AddCubedPatternHelper(&shared_client_impl, &analyzer_impl, pattern_bad); - AddCubedPatternHelper(&shared_client_impl, &analyzer_impl, pattern_clear); - EXPECT_EQ(0, analyzer_impl.CurrentAccumulator()); - EXPECT_EQ(0, analyzer_impl.CurrentRootAccumulator()); - EXPECT_EQ(0, analyzer_impl.CurrentSquareAccumulator()); - } } // This is a synthetic example that is just outside the dynamic range of a
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm index c8293175..7436e30 100644 --- a/ui/views/widget/native_widget_mac_unittest.mm +++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -1779,7 +1779,7 @@ // The default window with a title should look different from the // window with an empty title. - EXPECT_FALSE([empty_title_data isEqualToData:this_title_data]); + EXPECT_NSNE(empty_title_data, this_title_data); delegate.set_should_show_title(false); delegate.set_title(base::ASCIIToUTF16("This is another title")); @@ -1789,7 +1789,7 @@ // With our magic setting, the window with a title should look the // same as the window with an empty title. EXPECT_TRUE([ns_window _isTitleHidden]); - EXPECT_TRUE([empty_title_data isEqualToData:hidden_title_data]); + EXPECT_NSEQ(empty_title_data, hidden_title_data); widget->CloseNow(); } @@ -2194,9 +2194,10 @@ hosts_.push_back(std::move(holder)); } EXPECT_EQ(kNativeViewCount, native_host_parent_->child_count()); - EXPECT_TRUE(([[widget_->GetNativeView() subviews] isEqualToArray:@[ - compositor_view_, hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view() - ]])); + EXPECT_NSEQ([widget_->GetNativeView() subviews], (@[ + compositor_view_, hosts_[0]->view(), hosts_[1]->view(), + hosts_[2]->view() + ])); } void TearDown() override { @@ -2219,61 +2220,59 @@ // z-order. TEST_F(NativeWidgetMacViewsOrderTest, NativeViewAttached) { hosts_[1]->Detach(); - EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[ - compositor_view_, hosts_[0]->view(), hosts_[2]->view() - ]])); + EXPECT_NSEQ([GetContentNativeView() subviews], + (@[ compositor_view_, hosts_[0]->view(), hosts_[2]->view() ])); hosts_[1]->AttachNativeView(); - EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[ - compositor_view_, hosts_[0]->view(), hosts_[1]->view(), - hosts_[2]->view() - ]])); + EXPECT_NSEQ([GetContentNativeView() subviews], (@[ + compositor_view_, hosts_[0]->view(), hosts_[1]->view(), + hosts_[2]->view() + ])); } // Tests that NativeViews order changes according to views::View hierarchy. TEST_F(NativeWidgetMacViewsOrderTest, ReorderViews) { native_host_parent_->ReorderChildView(hosts_[2]->host(), 1); - EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[ - compositor_view_, hosts_[0]->view(), hosts_[2]->view(), - hosts_[1]->view() - ]])); + EXPECT_NSEQ([GetContentNativeView() subviews], (@[ + compositor_view_, hosts_[0]->view(), hosts_[2]->view(), + hosts_[1]->view() + ])); native_host_parent_->RemoveChildView(hosts_[2]->host()); - EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[ - compositor_view_, hosts_[0]->view(), hosts_[1]->view() - ]])); + EXPECT_NSEQ([GetContentNativeView() subviews], + (@[ compositor_view_, hosts_[0]->view(), hosts_[1]->view() ])); View* new_parent = new View(); native_host_parent_->RemoveChildView(hosts_[1]->host()); native_host_parent_->AddChildView(new_parent); new_parent->AddChildView(hosts_[1]->host()); new_parent->AddChildView(hosts_[2]->host()); - EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[ - compositor_view_, hosts_[0]->view(), hosts_[1]->view(), - hosts_[2]->view() - ]])); + EXPECT_NSEQ([GetContentNativeView() subviews], (@[ + compositor_view_, hosts_[0]->view(), hosts_[1]->view(), + hosts_[2]->view() + ])); native_host_parent_->ReorderChildView(new_parent, 0); - EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[ - compositor_view_, hosts_[1]->view(), hosts_[2]->view(), - hosts_[0]->view() - ]])); + EXPECT_NSEQ([GetContentNativeView() subviews], (@[ + compositor_view_, hosts_[1]->view(), hosts_[2]->view(), + hosts_[0]->view() + ])); } // Test that unassociated native views stay on top after reordering. TEST_F(NativeWidgetMacViewsOrderTest, UnassociatedViewsIsAbove) { base::scoped_nsobject<NSView> child_view([[NSView alloc] init]); [GetContentNativeView() addSubview:child_view]; - EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[ - compositor_view_, hosts_[0]->view(), hosts_[1]->view(), - hosts_[2]->view(), child_view - ]])); + EXPECT_NSEQ([GetContentNativeView() subviews], (@[ + compositor_view_, hosts_[0]->view(), hosts_[1]->view(), + hosts_[2]->view(), child_view + ])); native_host_parent_->ReorderChildView(hosts_[2]->host(), 1); - EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[ - compositor_view_, hosts_[0]->view(), hosts_[2]->view(), - hosts_[1]->view(), child_view - ]])); + EXPECT_NSEQ([GetContentNativeView() subviews], (@[ + compositor_view_, hosts_[0]->view(), hosts_[2]->view(), + hosts_[1]->view(), child_view + ])); } // Test -[NSWindowDelegate windowShouldClose:].
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index 314c562b..9ca4bdad 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc
@@ -1000,12 +1000,14 @@ void HWNDMessageHandler::OnCaretBoundsChanged( const ui::TextInputClient* client) { - if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) - return; - if (!ax_system_caret_) ax_system_caret_ = std::make_unique<ui::AXSystemCaretWin>(hwnd()); + if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) { + ax_system_caret_->Hide(); + return; + } + const gfx::Rect dip_caret_bounds(client->GetCaretBounds()); gfx::Rect caret_bounds = display::win::ScreenWin::DIPToScreenRect(hwnd(), dip_caret_bounds);
diff --git a/webrunner/net_http/service/url_loader_impl.cc b/webrunner/net_http/service/url_loader_impl.cc index 3cd7efd..343826ce 100644 --- a/webrunner/net_http/service/url_loader_impl.cc +++ b/webrunner/net_http/service/url_loader_impl.cc
@@ -21,9 +21,8 @@ // server responses. const size_t kReadCapacity = 1024; -// Converts |buffer| into a URLBody with the body set to a sized buffer. -oldhttp::URLBodyPtr BuildResponseBuffer( - scoped_refptr<net::GrowableIOBuffer> buffer) { +// Converts |buffer| into a URLBody with the body set to a buffer. +oldhttp::URLBodyPtr CreateURLBodyFromBuffer(net::GrowableIOBuffer* buffer) { oldhttp::URLBodyPtr body = oldhttp::URLBody::New(); // The response buffer size is exactly the offset. @@ -37,7 +36,7 @@ ZX_DLOG(WARNING, result) << "zx_vmo_write"; return nullptr; } - body->set_sized_buffer(std::move(mem_buffer)); + body->set_buffer(std::move(mem_buffer)); return body; } @@ -84,18 +83,18 @@ } std::unique_ptr<UploadDataStream> UploadDataStreamFromMemBuffer( - fuchsia::mem::Buffer sized_buffer) { + fuchsia::mem::Buffer mem_buffer) { // TODO(http://crbug.com/875534): Write a ZxMemBufferUploadStream class. std::unique_ptr<ChunkedUploadDataStream> upload_stream = std::make_unique<net::ChunkedUploadDataStream>(0); char buffer[kReadCapacity]; - size_t size = sized_buffer.size; + size_t size = mem_buffer.size; size_t offset = 0; zx_status_t result = ZX_OK; while (offset != size) { size_t length = std::min(size - offset, kReadCapacity); - result = sized_buffer.vmo.read(buffer, offset, length); + result = mem_buffer.vmo.read(buffer, offset, length); if (result != ZX_OK) { ZX_DLOG(WARNING, result) << "zx_vmo_read"; return nullptr; @@ -153,8 +152,8 @@ upload_stream = UploadDataStreamFromZxSocket(std::move(request.body->stream())); } else { - upload_stream = UploadDataStreamFromMemBuffer( - std::move(request.body->sized_buffer())); + upload_stream = + UploadDataStreamFromMemBuffer(std::move(request.body->buffer())); } if (!upload_stream) { @@ -311,7 +310,7 @@ // way to recover from a failed socket close. write_socket_ = zx::socket(); } else { - DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::SIZED_BUFFER); + DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::BUFFER); std::move(done_callback_)(BuildResponse(result)); } return false; @@ -327,9 +326,9 @@ write_socket_.write(ZX_SOCKET_SHUTDOWN_WRITE, nullptr, 0, nullptr); write_socket_ = zx::socket(); } else { - DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::SIZED_BUFFER); + DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::BUFFER); // In buffer mode, build the response and call the callback. - oldhttp::URLBodyPtr body = BuildResponseBuffer(buffer_); + oldhttp::URLBodyPtr body = CreateURLBodyFromBuffer(buffer_.get()); if (body) { oldhttp::URLResponse response = BuildResponse(result); response.body = std::move(body); @@ -363,7 +362,7 @@ return false; } } else { - DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::SIZED_BUFFER); + DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::BUFFER); // In buffer mode, expand the buffer. buffer_->SetCapacity(buffer_->capacity() + result); buffer_->set_offset(buffer_->offset() + result);