diff --git a/DEPS b/DEPS index 9b23b45f7..735f292 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # 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': 'c9a1f8e834f11acb2bf7c56cd8292cf3c761539c', + 'v8_revision': '8b00387af39d3b35326c4510f1f7e213fbd56a5d', # 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.
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 697d1b0..dabc79b 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -123,7 +123,8 @@ private static class ForceAuxiliaryBitmapRendering { private static final boolean sResult = lazyCheck(); private static boolean lazyCheck() { - return !nativeHasRequiredHardwareExtensions(); + return "goldfish".equals(Build.HARDWARE) || "ranchu".equals(Build.HARDWARE) + || !nativeHasRequiredHardwareExtensions(); } }
diff --git a/ash/test/test_keyboard_ui.cc b/ash/test/test_keyboard_ui.cc index 46558a8e..f0d03c1 100644 --- a/ash/test/test_keyboard_ui.cc +++ b/ash/test/test_keyboard_ui.cc
@@ -38,7 +38,6 @@ return root_window->GetHost()->GetInputMethod(); } -void TestKeyboardUI::SetUpdateInputType(ui::TextInputType type) {} void TestKeyboardUI::ReloadKeyboardIfNeeded() {} void TestKeyboardUI::InitInsets(const gfx::Rect& keyboard_bounds) {} void TestKeyboardUI::ResetInsets() {}
diff --git a/ash/test/test_keyboard_ui.h b/ash/test/test_keyboard_ui.h index a377c63..cd46236 100644 --- a/ash/test/test_keyboard_ui.h +++ b/ash/test/test_keyboard_ui.h
@@ -30,7 +30,6 @@ private: // Overridden from keyboard::KeyboardUI: ui::InputMethod* GetInputMethod() override; - void SetUpdateInputType(ui::TextInputType type) override; void ReloadKeyboardIfNeeded() override; void InitInsets(const gfx::Rect& keyboard_bounds) override; void ResetInsets() override;
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml index 6eebc4a..b483735 100644 --- a/build/android/lint/suppressions.xml +++ b/build/android/lint/suppressions.xml
@@ -297,6 +297,9 @@ <!-- TODO(crbug.com/635567): Fix this properly. --> <issue id="UnusedResources" severity="ignore"/> <issue id="UnusedResources"> + <!-- The two dimens below will be changing soon so please leave them in --> + <ignore regexp="design_bottom_navigation_text_size"/> + <ignore regexp="design_bottom_navigation_active_text_size"/> <ignore regexp="PRODUCT_DIR/gen/remoting/android/remoting_android_raw_resources/res/raw/credits.html"/> <ignore regexp="PRODUCT_DIR/gen/remoting/android/remoting_android_raw_resources/res/raw/credits_css.css"/> <ignore regexp="PRODUCT_DIR/gen/remoting/android/remoting_android_raw_resources/res/raw/credits_js.js"/>
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index f4f9e44..3eb20471 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -1746,9 +1746,11 @@ # builds, currently get # "third_party/binutils/Linux_x64/Release/bin/ld.gold: warning: # /tmp/lto-llvm-0b5201.o: corrupt debug info in .debug_info" + # TODO(thakis): Re-enable on fuchsia once lld can process R_X86_64_DTPOFF64 + # relocations, https://crbug.com/735101 if (!is_mac && !is_ios && !is_nacl && target_cpu != "x86" && (use_gold || use_lld) && !allow_posix_link_time_opt && - !is_official_build) { + !is_official_build && !is_fuchsia) { ldflags += [ "-Wl,--gdb-index" ] } }
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py index d91bf9b2..8150d3a 100644 --- a/build/toolchain/win/setup_toolchain.py +++ b/build/toolchain/win/setup_toolchain.py
@@ -139,10 +139,9 @@ raise Exception('%s is missing - make sure VC++ tools are installed.' % script_path) script_path = other_path - # Chromium requires the 10.0.14393.0 SDK. Previous versions don't have all - # of the required declarations, and 10.0.15063.0 is buggy. - args = [script_path, 'amd64_x86' if cpu == 'x86' else 'amd64', - '10.0.14393.0'] + # Chromium requires the 10.0.14393.0 SDK or higher - previous versions don't + # have all of the required declarations. + args = [script_path, 'amd64_x86' if cpu == 'x86' else 'amd64'] variables = _LoadEnvFromBat(args) return _ExtractImportantEnvironment(variables)
diff --git a/cc/animation/BUILD.gn b/cc/animation/BUILD.gn index 44d5b37..7ae45962 100644 --- a/cc/animation/BUILD.gn +++ b/cc/animation/BUILD.gn
@@ -21,6 +21,7 @@ "animation_id_provider.h", "animation_player.cc", "animation_player.h", + "animation_target.h", "animation_timeline.cc", "animation_timeline.h", "element_animations.cc",
diff --git a/cc/animation/animation_events.h b/cc/animation/animation_events.h index 65a7ae6..a129ed55 100644 --- a/cc/animation/animation_events.h +++ b/cc/animation/animation_events.h
@@ -19,7 +19,7 @@ namespace cc { struct CC_ANIMATION_EXPORT AnimationEvent { - enum Type { STARTED, FINISHED, ABORTED, PROPERTY_UPDATE, TAKEOVER }; + enum Type { STARTED, FINISHED, ABORTED, TAKEOVER }; AnimationEvent(Type type, ElementId element_id,
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc index d56e7585..3d6092d 100644 --- a/cc/animation/animation_host.cc +++ b/cc/animation/animation_host.cc
@@ -345,11 +345,6 @@ (*iter).second->NotifyAnimationAborted(events->events_[event_index]); break; - case AnimationEvent::PROPERTY_UPDATE: - (*iter).second->NotifyAnimationPropertyUpdate( - events->events_[event_index]); - break; - case AnimationEvent::TAKEOVER: (*iter).second->NotifyAnimationTakeover(events->events_[event_index]); break;
diff --git a/cc/animation/animation_player.cc b/cc/animation/animation_player.cc index 4213773..1c43f39 100644 --- a/cc/animation/animation_player.cc +++ b/cc/animation/animation_player.cc
@@ -13,6 +13,7 @@ #include "cc/animation/animation_timeline.h" #include "cc/animation/scroll_offset_animation_curve.h" #include "cc/animation/transform_operations.h" +#include "cc/base/math_util.h" #include "cc/trees/property_animation_state.h" namespace cc { @@ -723,82 +724,53 @@ SetNeedsPushProperties(); } -void AnimationPlayer::TickAnimations(base::TimeTicks monotonic_time) { - DCHECK(element_animations_); - - for (size_t i = 0; i < animations_.size(); ++i) { - if (animations_[i]->run_state() == Animation::STARTING || - animations_[i]->run_state() == Animation::RUNNING || - animations_[i]->run_state() == Animation::PAUSED) { - if (!animations_[i]->InEffect(monotonic_time)) - continue; - - base::TimeDelta trimmed = - animations_[i]->TrimTimeToCurrentIteration(monotonic_time); - - switch (animations_[i]->target_property()) { - case TargetProperty::TRANSFORM: { - const TransformAnimationCurve* transform_animation_curve = - animations_[i]->curve()->ToTransformAnimationCurve(); - const TransformOperations operations = - transform_animation_curve->GetValue(trimmed); - element_animations_->NotifyClientTransformOperationsAnimated( - operations, animations_[i]->affects_active_elements(), - animations_[i]->affects_pending_elements()); - break; - } - - case TargetProperty::OPACITY: { - const FloatAnimationCurve* float_animation_curve = - animations_[i]->curve()->ToFloatAnimationCurve(); - const float opacity = std::max( - std::min(float_animation_curve->GetValue(trimmed), 1.0f), 0.f); - element_animations_->NotifyClientOpacityAnimated( - opacity, animations_[i]->affects_active_elements(), - animations_[i]->affects_pending_elements()); - break; - } - - case TargetProperty::FILTER: { - const FilterAnimationCurve* filter_animation_curve = - animations_[i]->curve()->ToFilterAnimationCurve(); - const FilterOperations filter = - filter_animation_curve->GetValue(trimmed); - element_animations_->NotifyClientFilterAnimated( - filter, animations_[i]->affects_active_elements(), - animations_[i]->affects_pending_elements()); - break; - } - - case TargetProperty::BACKGROUND_COLOR: { - // Not yet implemented. - break; - } - - case TargetProperty::SCROLL_OFFSET: { - const ScrollOffsetAnimationCurve* scroll_offset_animation_curve = - animations_[i]->curve()->ToScrollOffsetAnimationCurve(); - const gfx::ScrollOffset scroll_offset = - scroll_offset_animation_curve->GetValue(trimmed); - element_animations_->NotifyClientScrollOffsetAnimated( - scroll_offset, animations_[i]->affects_active_elements(), - animations_[i]->affects_pending_elements()); - break; - } - - case TargetProperty::BOUNDS: { - const SizeAnimationCurve* size_animation_curve = - animations_[i]->curve()->ToSizeAnimationCurve(); - const gfx::SizeF size = size_animation_curve->GetValue(trimmed); - element_animations_->NotifyClientBoundsAnimated( - size, animations_[i]->affects_active_elements(), - animations_[i]->affects_pending_elements()); - break; - } - } - } +void AnimationPlayer::TickAnimation(base::TimeTicks monotonic_time, + Animation* animation, + AnimationTarget* target) { + if ((animation->run_state() != Animation::STARTING && + animation->run_state() != Animation::RUNNING && + animation->run_state() != Animation::PAUSED) || + !animation->InEffect(monotonic_time)) { + return; } + AnimationCurve* curve = animation->curve(); + base::TimeDelta trimmed = + animation->TrimTimeToCurrentIteration(monotonic_time); + + switch (animation->target_property()) { + case TargetProperty::TRANSFORM: + target->NotifyClientTransformOperationsAnimated( + curve->ToTransformAnimationCurve()->GetValue(trimmed), animation); + break; + case TargetProperty::OPACITY: + target->NotifyClientOpacityAnimated( + MathUtil::ClampToRange( + curve->ToFloatAnimationCurve()->GetValue(trimmed), 0.0f, 1.0f), + animation); + break; + case TargetProperty::FILTER: + target->NotifyClientFilterAnimated( + curve->ToFilterAnimationCurve()->GetValue(trimmed), animation); + break; + case TargetProperty::BACKGROUND_COLOR: + // Not yet implemented. + break; + case TargetProperty::SCROLL_OFFSET: + target->NotifyClientScrollOffsetAnimated( + curve->ToScrollOffsetAnimationCurve()->GetValue(trimmed), animation); + break; + case TargetProperty::BOUNDS: + target->NotifyClientBoundsAnimated( + curve->ToSizeAnimationCurve()->GetValue(trimmed), animation); + break; + } +} + +void AnimationPlayer::TickAnimations(base::TimeTicks monotonic_time) { + DCHECK(element_animations_); + for (auto& animation : animations_) + TickAnimation(monotonic_time, animation.get(), element_animations_.get()); last_tick_time_ = monotonic_time; }
diff --git a/cc/animation/animation_player.h b/cc/animation/animation_player.h index 98475a6..c2df51f 100644 --- a/cc/animation/animation_player.h +++ b/cc/animation/animation_player.h
@@ -109,7 +109,12 @@ AnimationEvents* events); void MarkAnimationsForDeletion(base::TimeTicks monotonic_time, AnimationEvents* events); + + static void TickAnimation(base::TimeTicks monotonic_time, + Animation* animation, + AnimationTarget* target); void TickAnimations(base::TimeTicks monotonic_time); + void MarkFinishedAnimations(base::TimeTicks monotonic_time); // Make animations affect active elements if and only if they affect
diff --git a/cc/animation/animation_target.h b/cc/animation/animation_target.h new file mode 100644 index 0000000..ecda3a0 --- /dev/null +++ b/cc/animation/animation_target.h
@@ -0,0 +1,45 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_ANIMATION_ANIMATION_TARGET_H_ +#define CC_ANIMATION_ANIMATION_TARGET_H_ + +#include "cc/animation/animation_export.h" + +namespace gfx { + +class ScrollOffset; +class SizeF; + +} // namespace gfx + +namespace cc { + +class Animation; +class FilterOperations; +class TransformOperations; + +// An AnimationTarget is an entity that can be affected by a ticking +// cc:Animation. Any object that expects to have an opacity update, for +// example, should derive from this class. +class CC_ANIMATION_EXPORT AnimationTarget { + public: + virtual ~AnimationTarget() {} + virtual void NotifyClientOpacityAnimated(float opacity, + Animation* animation) {} + virtual void NotifyClientFilterAnimated(const FilterOperations& filter, + Animation* animation) {} + virtual void NotifyClientBoundsAnimated(const gfx::SizeF& size, + Animation* animation) {} + virtual void NotifyClientTransformOperationsAnimated( + const TransformOperations& operations, + Animation* animation) {} + virtual void NotifyClientScrollOffsetAnimated( + const gfx::ScrollOffset& scroll_offset, + Animation* animation) {} +}; + +} // namespace cc + +#endif // CC_ANIMATION_ANIMATION_TARGET_H_
diff --git a/cc/animation/element_animations.cc b/cc/animation/element_animations.cc index 322530ba..f962545c8 100644 --- a/cc/animation/element_animations.cc +++ b/cc/animation/element_animations.cc
@@ -195,29 +195,6 @@ UpdateClientAnimationState(); } -void ElementAnimations::NotifyAnimationPropertyUpdate( - const AnimationEvent& event) { - DCHECK(!event.is_impl_only); - bool notify_active_elements = true; - bool notify_pending_elements = true; - switch (event.target_property) { - case TargetProperty::OPACITY: { - NotifyClientOpacityAnimated(event.opacity, notify_active_elements, - notify_pending_elements); - break; - } - case TargetProperty::TRANSFORM: { - TransformOperations operations; - operations.AppendMatrix(event.transform); - NotifyClientTransformOperationsAnimated( - operations, notify_active_elements, notify_pending_elements); - break; - } - default: - NOTREACHED(); - } -} - bool ElementAnimations::HasFilterAnimationThatInflatesBounds() const { for (auto& player : players_list_) { if (player.HasFilterAnimationThatInflatesBounds()) @@ -319,56 +296,42 @@ SetNeedsPushProperties(); } -void ElementAnimations::NotifyClientOpacityAnimated( - float opacity, - bool notify_active_elements, - bool notify_pending_elements) { - if (notify_active_elements && has_element_in_active_list()) +void ElementAnimations::NotifyClientOpacityAnimated(float opacity, + Animation* animation) { + if (AnimationAffectsActiveElements(animation)) OnOpacityAnimated(ElementListType::ACTIVE, opacity); - if (notify_pending_elements && has_element_in_pending_list()) + if (AnimationAffectsPendingElements(animation)) OnOpacityAnimated(ElementListType::PENDING, opacity); } -void ElementAnimations::NotifyClientTransformOperationsAnimated( - const TransformOperations& operations, - bool notify_active_elements, - bool notify_pending_elements) { - gfx::Transform transform = operations.Apply(); - if (notify_active_elements && has_element_in_active_list()) - OnTransformAnimated(ElementListType::ACTIVE, transform); - if (notify_pending_elements && has_element_in_pending_list()) - OnTransformAnimated(ElementListType::PENDING, transform); -} - void ElementAnimations::NotifyClientFilterAnimated( const FilterOperations& filters, - bool notify_active_elements, - bool notify_pending_elements) { - if (notify_active_elements && has_element_in_active_list()) + Animation* animation) { + if (AnimationAffectsActiveElements(animation)) OnFilterAnimated(ElementListType::ACTIVE, filters); - if (notify_pending_elements && has_element_in_pending_list()) + if (AnimationAffectsPendingElements(animation)) OnFilterAnimated(ElementListType::PENDING, filters); } +void ElementAnimations::NotifyClientTransformOperationsAnimated( + const TransformOperations& operations, + Animation* animation) { + gfx::Transform transform = operations.Apply(); + if (AnimationAffectsActiveElements(animation)) + OnTransformAnimated(ElementListType::ACTIVE, transform); + if (AnimationAffectsPendingElements(animation)) + OnTransformAnimated(ElementListType::PENDING, transform); +} + void ElementAnimations::NotifyClientScrollOffsetAnimated( const gfx::ScrollOffset& scroll_offset, - bool notify_active_elements, - bool notify_pending_elements) { - if (notify_active_elements && has_element_in_active_list()) + Animation* animation) { + if (AnimationAffectsActiveElements(animation)) OnScrollOffsetAnimated(ElementListType::ACTIVE, scroll_offset); - if (notify_pending_elements && has_element_in_pending_list()) + if (AnimationAffectsPendingElements(animation)) OnScrollOffsetAnimated(ElementListType::PENDING, scroll_offset); } -void ElementAnimations::NotifyClientBoundsAnimated( - const gfx::SizeF& size, - bool notify_active_elements, - bool notify_pending_elements) { - // TODO(vollick): once we have an animation observer, we can remove client - // animated notifications we do not use in element animations, such as this - // one. -} - void ElementAnimations::UpdateClientAnimationState() { if (!element_id()) return; @@ -509,4 +472,22 @@ return gfx::ScrollOffset(); } +bool ElementAnimations::AnimationAffectsActiveElements( + Animation* animation) const { + // When we force an animation update due to a notification, we do not have an + // Animation instance. In this case, we force an update of active elements. + if (!animation) + return true; + return animation->affects_active_elements() && has_element_in_active_list(); +} + +bool ElementAnimations::AnimationAffectsPendingElements( + Animation* animation) const { + // When we force an animation update due to a notification, we do not have an + // Animation instance. In this case, we force an update of pending elements. + if (!animation) + return true; + return animation->affects_pending_elements() && has_element_in_pending_list(); +} + } // namespace cc
diff --git a/cc/animation/element_animations.h b/cc/animation/element_animations.h index 95929cf3..61b7299 100644 --- a/cc/animation/element_animations.h +++ b/cc/animation/element_animations.h
@@ -12,6 +12,7 @@ #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "cc/animation/animation_export.h" +#include "cc/animation/animation_target.h" #include "cc/trees/element_id.h" #include "cc/trees/property_animation_state.h" #include "cc/trees/target_property.h" @@ -20,7 +21,6 @@ namespace gfx { class BoxF; -class SizeF; } namespace cc { @@ -39,7 +39,8 @@ // This is a CC counterpart for blink::ElementAnimations (in 1:1 relationship). // No pointer to/from respective blink::ElementAnimations object for now. class CC_ANIMATION_EXPORT ElementAnimations - : public base::RefCounted<ElementAnimations> { + : public AnimationTarget, + public base::RefCounted<ElementAnimations> { public: static scoped_refptr<ElementAnimations> Create(); @@ -148,21 +149,14 @@ void SetNeedsUpdateImplClientState(); void NotifyClientOpacityAnimated(float opacity, - bool notify_active_elements, - bool notify_pending_elements); + Animation* animation) override; + void NotifyClientFilterAnimated(const FilterOperations& filter, + Animation* animation) override; void NotifyClientTransformOperationsAnimated( const TransformOperations& operations, - bool notify_active_elements, - bool notify_pending_elements); - void NotifyClientFilterAnimated(const FilterOperations& filter, - bool notify_active_elements, - bool notify_pending_elements); + Animation* animation) override; void NotifyClientScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset, - bool notify_active_elements, - bool notify_pending_elements); - void NotifyClientBoundsAnimated(const gfx::SizeF& size, - bool notify_active_elements, - bool notify_pending_elements); + Animation* animation) override; gfx::ScrollOffset ScrollOffsetForAnimation() const; @@ -170,7 +164,7 @@ friend class base::RefCounted<ElementAnimations>; ElementAnimations(); - ~ElementAnimations(); + ~ElementAnimations() override; void OnFilterAnimated(ElementListType list_type, const FilterOperations& filters); @@ -185,6 +179,9 @@ void UpdatePlayersTickingState(UpdateTickingType update_ticking_type) const; void RemovePlayersFromTicking() const; + bool AnimationAffectsActiveElements(Animation* animation) const; + bool AnimationAffectsPendingElements(Animation* animation) const; + PlayersList players_list_; AnimationHost* animation_host_; ElementId element_id_;
diff --git a/cc/animation/element_animations_unittest.cc b/cc/animation/element_animations_unittest.cc index 8974943..6c10785 100644 --- a/cc/animation/element_animations_unittest.cc +++ b/cc/animation/element_animations_unittest.cc
@@ -687,16 +687,6 @@ return Animation::Create(std::move(curve), 0, group_id, property); } -static const AnimationEvent* GetMostRecentPropertyUpdateEvent( - const AnimationEvents* events) { - const AnimationEvent* event = 0; - for (size_t i = 0; i < events->events_.size(); ++i) - if (events->events_[i].type == AnimationEvent::PROPERTY_UPDATE) - event = &events->events_[i]; - - return event; -} - TEST_F(ElementAnimationsTest, TrivialTransition) { CreateTestLayer(true, false); AttachTimelinePlayerLayer(); @@ -715,15 +705,11 @@ player_->UpdateState(true, events.get()); EXPECT_TRUE(player_->HasTickingAnimation()); EXPECT_EQ(0.f, client_.GetOpacity(element_id_, ElementListType::ACTIVE)); - // A non-impl-only animation should not generate property updates. - const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); + player_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); player_->UpdateState(true, events.get()); EXPECT_EQ(1.f, client_.GetOpacity(element_id_, ElementListType::ACTIVE)); EXPECT_FALSE(player_->HasTickingAnimation()); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); } TEST_F(ElementAnimationsTest, FilterTransition) { @@ -753,9 +739,6 @@ EXPECT_TRUE(player_->HasTickingAnimation()); EXPECT_EQ(start_filters, client_.GetFilters(element_id_, ElementListType::ACTIVE)); - // A non-impl-only animation should not generate property updates. - const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); player_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(500)); player_->UpdateState(true, events.get()); @@ -763,16 +746,12 @@ client_.GetFilters(element_id_, ElementListType::ACTIVE).size()); EXPECT_EQ(FilterOperation::CreateBrightnessFilter(1.5f), client_.GetFilters(element_id_, ElementListType::ACTIVE).at(0)); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); player_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); player_->UpdateState(true, events.get()); EXPECT_EQ(end_filters, client_.GetFilters(element_id_, ElementListType::ACTIVE)); EXPECT_FALSE(player_->HasTickingAnimation()); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); } TEST_F(ElementAnimationsTest, ScrollOffsetTransition) { @@ -816,9 +795,6 @@ EXPECT_TRUE(player_impl_->HasTickingAnimation()); EXPECT_EQ(initial_value, client_impl_.GetScrollOffset(element_id_, ElementListType::ACTIVE)); - // Scroll offset animations should not generate property updates. - const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); player_->NotifyAnimationStarted(events->events_[0]); player_->Tick(kInitialTickTime + duration / 2); @@ -833,16 +809,12 @@ EXPECT_VECTOR2DF_EQ( gfx::Vector2dF(200.f, 250.f), client_impl_.GetScrollOffset(element_id_, ElementListType::ACTIVE)); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); player_impl_->Tick(kInitialTickTime + duration); player_impl_->UpdateState(true, events.get()); EXPECT_VECTOR2DF_EQ(target_value, client_impl_.GetScrollOffset( element_id_, ElementListType::ACTIVE)); EXPECT_FALSE(player_impl_->HasTickingAnimation()); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); player_->Tick(kInitialTickTime + duration); player_->UpdateState(true, nullptr); @@ -877,9 +849,6 @@ EXPECT_TRUE(player_impl_->HasTickingAnimation()); EXPECT_EQ(initial_value, client_impl_.GetScrollOffset(element_id_, ElementListType::ACTIVE)); - // Scroll offset animations should not generate property updates. - const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); TimeDelta duration = TimeDelta::FromMicroseconds( duration_in_seconds * base::Time::kMicrosecondsPerSecond); @@ -889,16 +858,12 @@ EXPECT_VECTOR2DF_EQ( gfx::Vector2dF(200.f, 250.f), client_impl_.GetScrollOffset(element_id_, ElementListType::ACTIVE)); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); player_impl_->Tick(kInitialTickTime + duration); player_impl_->UpdateState(true, events.get()); EXPECT_VECTOR2DF_EQ(target_value, client_impl_.GetScrollOffset( element_id_, ElementListType::ACTIVE)); EXPECT_FALSE(player_impl_->HasTickingAnimation()); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); } // This test verifies that if an animation is added after a layer is animated, @@ -1009,10 +974,6 @@ player_impl_->UpdateState(true, events.get()); DCHECK_EQ(1UL, events->events_.size()); - // Scroll offset animations should not generate property updates. - const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); - player_->NotifyAnimationStarted(events->events_[0]); player_->Tick(kInitialTickTime + duration / 2); player_->UpdateState(true, nullptr); @@ -1026,16 +987,12 @@ EXPECT_VECTOR2DF_EQ( gfx::Vector2dF(400.f, 150.f), client_impl_.GetScrollOffset(element_id_, ElementListType::PENDING)); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); player_impl_->Tick(kInitialTickTime + duration); player_impl_->UpdateState(true, events.get()); EXPECT_VECTOR2DF_EQ(target_value, client_impl_.GetScrollOffset( element_id_, ElementListType::PENDING)); EXPECT_FALSE(player_impl_->HasTickingAnimation()); - event = GetMostRecentPropertyUpdateEvent(events.get()); - EXPECT_FALSE(event); player_->Tick(kInitialTickTime + duration); player_->UpdateState(true, nullptr);
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index 27cf2a19..d96b381 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc
@@ -1114,21 +1114,6 @@ SetNeedsCommit(); } -static void RunCopyCallbackOnMainThread( - std::unique_ptr<CopyOutputRequest> request, - std::unique_ptr<CopyOutputResult> result) { - request->SendResult(std::move(result)); -} - -static void PostCopyCallbackToMainThread( - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner, - std::unique_ptr<CopyOutputRequest> request, - std::unique_ptr<CopyOutputResult> result) { - main_thread_task_runner->PostTask( - FROM_HERE, base::BindOnce(&RunCopyCallbackOnMainThread, - base::Passed(&request), base::Passed(&result))); -} - bool Layer::IsSnapped() { return scrollable(); } @@ -1218,21 +1203,17 @@ void Layer::TakeCopyRequests( std::vector<std::unique_ptr<CopyOutputRequest>>* requests) { - for (auto& it : inputs_.copy_requests) { - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner = - layer_tree_host()->GetTaskRunnerProvider()->MainThreadTaskRunner(); - std::unique_ptr<CopyOutputRequest> original_request = std::move(it); - const CopyOutputRequest& original_request_ref = *original_request; - std::unique_ptr<CopyOutputRequest> main_thread_request = - CopyOutputRequest::CreateRelayRequest( - original_request_ref, - base::Bind(&PostCopyCallbackToMainThread, main_thread_task_runner, - base::Passed(&original_request))); - if (main_thread_request->has_area()) { - main_thread_request->set_area(gfx::IntersectRects( - main_thread_request->area(), gfx::Rect(bounds()))); + for (std::unique_ptr<CopyOutputRequest>& request : inputs_.copy_requests) { + // Ensure the result callback is not invoked on the compositing thread. + if (!request->has_result_task_runner()) { + request->set_result_task_runner( + layer_tree_host()->GetTaskRunnerProvider()->MainThreadTaskRunner()); } - requests->push_back(std::move(main_thread_request)); + if (request->has_area()) { + request->set_area( + gfx::IntersectRects(request->area(), gfx::Rect(bounds()))); + } + requests->push_back(std::move(request)); } inputs_.copy_requests.clear();
diff --git a/cc/output/copy_output_request.cc b/cc/output/copy_output_request.cc index b748c5f..b08a066 100644 --- a/cc/output/copy_output_request.cc +++ b/cc/output/copy_output_request.cc
@@ -14,17 +14,6 @@ namespace cc { -// static -std::unique_ptr<CopyOutputRequest> CopyOutputRequest::CreateRelayRequest( - const CopyOutputRequest& original_request, - const CopyOutputRequestCallback& result_callback) { - std::unique_ptr<CopyOutputRequest> relay = CreateRequest(result_callback); - relay->force_bitmap_result_ = original_request.force_bitmap_result_; - relay->area_ = original_request.area_; - relay->texture_mailbox_ = original_request.texture_mailbox_; - return relay; -} - CopyOutputRequest::CopyOutputRequest() : force_bitmap_result_(false) {} CopyOutputRequest::CopyOutputRequest( @@ -42,9 +31,16 @@ } void CopyOutputRequest::SendResult(std::unique_ptr<CopyOutputResult> result) { - bool success = !result->IsEmpty(); - base::ResetAndReturn(&result_callback_).Run(std::move(result)); - TRACE_EVENT_ASYNC_END1("cc", "CopyOutputRequest", this, "success", success); + TRACE_EVENT_ASYNC_END1("cc", "CopyOutputRequest", this, "success", + !result->IsEmpty()); + if (result_task_runner_) { + result_task_runner_->PostTask( + FROM_HERE, base::BindOnce(base::ResetAndReturn(&result_callback_), + std::move(result))); + result_task_runner_ = nullptr; + } else { + base::ResetAndReturn(&result_callback_).Run(std::move(result)); + } } void CopyOutputRequest::SendEmptyResult() {
diff --git a/cc/output/copy_output_request.h b/cc/output/copy_output_request.h index 8147ab2..0194b77 100644 --- a/cc/output/copy_output_request.h +++ b/cc/output/copy_output_request.h
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/memory/ptr_util.h" #include "base/optional.h" +#include "base/task_runner.h" #include "base/unguessable_token.h" #include "cc/cc_export.h" #include "cc/resources/single_release_callback.h" @@ -43,14 +44,19 @@ const CopyOutputRequestCallback& result_callback) { return base::WrapUnique(new CopyOutputRequest(true, result_callback)); } - static std::unique_ptr<CopyOutputRequest> CreateRelayRequest( - const CopyOutputRequest& original_request, - const CopyOutputRequestCallback& result_callback); ~CopyOutputRequest(); bool IsEmpty() const { return result_callback_.is_null(); } + // Requests that the result callback be run as a task posted to the given + // |task_runner|. If this is not set, the result callback could be run from + // any context. + void set_result_task_runner(scoped_refptr<base::TaskRunner> task_runner) { + result_task_runner_ = std::move(task_runner); + } + bool has_result_task_runner() const { return !!result_task_runner_; } + // Optionally specify the source of this copy request. If set when this copy // request is submitted to a layer, a prior uncommitted copy request from the // same source will be aborted. @@ -93,6 +99,7 @@ CopyOutputRequest(bool force_bitmap_result, const CopyOutputRequestCallback& result_callback); + scoped_refptr<base::TaskRunner> result_task_runner_; base::Optional<base::UnguessableToken> source_; bool force_bitmap_result_; base::Optional<gfx::Rect> area_;
diff --git a/chrome/android/java/res/layout/chrome_home_incognito_new_tab_page.xml b/chrome/android/java/res/layout/chrome_home_incognito_new_tab_page.xml deleted file mode 100644 index 6a35d9c..0000000 --- a/chrome/android/java/res/layout/chrome_home_incognito_new_tab_page.xml +++ /dev/null
@@ -1,56 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. --> - -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:chrome="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:focusable="true" - android:focusableInTouchMode="true" - android:background="@color/ntp_bg_incognito" > - - <org.chromium.chrome.browser.widget.TintedImageButton - android:id="@+id/close_button" - android:layout_width="40dp" - android:layout_height="40dp" - android:layout_gravity="top|end" - android:src="@drawable/btn_close" - android:scaleType="center" - android:background="@android:color/transparent" - chrome:chrometint="@color/light_mode_tint" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:clipChildren="false" > - - <FrameLayout - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="0.5" - android:layout_marginTop="10dp" > - - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:contentDescription="@null" - android:layout_gravity="center" - android:src="@drawable/incognito_splash"/> - - </FrameLayout> - - <!-- This extra empty frame layout is used to ensure the FrameLayout - above is half of the parent view's height. --> - <FrameLayout - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="0.5" - android:background="@android:color/transparent" /> - - </LinearLayout> - -</FrameLayout>
diff --git a/chrome/android/java/res/layout/chrome_home_new_tab_page.xml b/chrome/android/java/res/layout/chrome_home_new_tab_page.xml deleted file mode 100644 index 2c8167c..0000000 --- a/chrome/android/java/res/layout/chrome_home_new_tab_page.xml +++ /dev/null
@@ -1,56 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. --> - -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:chrome="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:focusable="true" - android:focusableInTouchMode="true" - android:background="@android:color/white" > - - <org.chromium.chrome.browser.widget.TintedImageButton - android:id="@+id/close_button" - android:layout_width="40dp" - android:layout_height="40dp" - android:layout_gravity="top|end" - android:src="@drawable/btn_close" - android:scaleType="center" - android:background="@android:color/transparent" - chrome:chrometint="@color/dark_mode_tint" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:clipChildren="false" > - - <FrameLayout - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="0.5" > - - <org.chromium.chrome.browser.ntp.LogoView - android:id="@+id/search_provider_logo" - android:layout_width="match_parent" - android:layout_height="@dimen/ntp_logo_height" - android:layout_marginStart="16dp" - android:layout_marginEnd="16dp" - android:layout_gravity="center" /> - - </FrameLayout> - - <!-- This extra empty frame layout is used to ensure the FrameLayout - above is half of the parent view's height. --> - <FrameLayout - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="0.5" - android:background="@android:color/transparent" /> - - </LinearLayout> - -</FrameLayout>
diff --git a/chrome/android/java/res/layout/fragment_lock_screen.xml b/chrome/android/java/res/layout/fragment_lock_screen.xml deleted file mode 100644 index db87660..0000000 --- a/chrome/android/java/res/layout/fragment_lock_screen.xml +++ /dev/null
@@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/lockscreen_main" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:title="@string/lockscreen_verification_title"> - - <TextView - android:id="@+id/lockscreen_description_text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/lockscreen_verification_text"/> - - <Button - android:id="@+id/lockscreen_next_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="start" - android:paddingStart="0dp" - android:text="@string/next" - style="?android:attr/borderlessButtonStyle"/> -</LinearLayout>
diff --git a/chrome/android/java/res/layout/reader_mode_text_view.xml b/chrome/android/java/res/layout/reader_mode_text_view.xml deleted file mode 100644 index 822e1bd..0000000 --- a/chrome/android/java/res/layout/reader_mode_text_view.xml +++ /dev/null
@@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. --> - -<!-- Reader Mode bar text --> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/reader_mode_text_view" - style="@style/ContextualSearchTextViewLayout" > - <TextView - android:id="@+id/reader_mode_text" - android:text="@string/reader_view_text" - style="@style/ContextualSearchTextView" - android:layout_width="match_parent" - android:layout_gravity="bottom" - android:background="#FFF" - android:layout_marginStart="7dp" - android:layout_marginEnd="7dp" /> -</FrameLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java index b452d8a5..c74b588 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
@@ -21,8 +21,6 @@ import org.chromium.chrome.browser.ntp.snippets.SnippetsLauncher; import org.chromium.chrome.browser.offlinepages.BackgroundScheduler; import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; -import org.chromium.chrome.browser.precache.PrecacheController; -import org.chromium.chrome.browser.precache.PrecacheUMA; /** * {@link ChromeBackgroundService} is scheduled through the {@link GcmNetworkManager} when the @@ -58,11 +56,6 @@ handleFetchSnippets(context, taskTag); break; - case PrecacheController.PERIODIC_TASK_TAG: - case PrecacheController.CONTINUATION_TASK_TAG: - handlePrecache(context, taskTag); - break; - case DownloadResumptionScheduler.TASK_TAG: DownloadResumptionScheduler.getDownloadResumptionScheduler( context.getApplicationContext()).handleDownloadResumption(); @@ -107,23 +100,6 @@ SnippetsBridge.rescheduleFetching(); } - private void handlePrecache(Context context, String tag) { - if (!hasPrecacheInstance()) { - launchBrowser(context, tag); - } - precache(context, tag); - } - - @VisibleForTesting - protected boolean hasPrecacheInstance() { - return PrecacheController.hasInstance(); - } - - @VisibleForTesting - protected void precache(Context context, String tag) { - PrecacheController.get(context).precache(tag); - } - @VisibleForTesting @SuppressFBWarnings("DM_EXIT") protected void launchBrowser(Context context, String tag) { @@ -132,16 +108,6 @@ ChromeBrowserInitializer.getInstance(this).handleSynchronousStartup(); } catch (ProcessInitException e) { Log.e(TAG, "ProcessInitException while starting the browser process"); - switch (tag) { - case PrecacheController.PERIODIC_TASK_TAG: - case PrecacheController.CONTINUATION_TASK_TAG: - // Record the failure persistently, and upload to UMA when the library - // successfully loads next time. - PrecacheUMA.record(PrecacheUMA.Event.PRECACHE_TASK_LOAD_LIBRARY_FAIL); - break; - default: - break; - } // Since the library failed to initialize nothing in the application // can work, so kill the whole application not just the activity. System.exit(-1); @@ -153,11 +119,6 @@ BackgroundSyncLauncher.rescheduleTasksOnUpgrade(this); } - @VisibleForTesting - protected void reschedulePrecacheTasksOnUpgrade() { - PrecacheController.rescheduleTasksOnUpgrade(this); - } - private void rescheduleSnippetsTasksOnUpgrade() { if (SnippetsLauncher.shouldRescheduleTasksOnUpgrade()) { if (!SnippetsLauncher.hasInstance()) { @@ -175,7 +136,6 @@ @Override public void onInitializeTasks() { rescheduleBackgroundSyncTasksOnUpgrade(); - reschedulePrecacheTasksOnUpgrade(); rescheduleSnippetsTasksOnUpgrade(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java index 8ce75fd8..ec137b619 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -60,7 +60,6 @@ import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations; import org.chromium.chrome.browser.photo_picker.PhotoPickerDialog; import org.chromium.chrome.browser.physicalweb.PhysicalWeb; -import org.chromium.chrome.browser.precache.PrecacheLauncher; import org.chromium.chrome.browser.preferences.ChromePreferenceManager; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.rlz.RevenueStats; @@ -451,9 +450,6 @@ // killed. BookmarkWidgetProvider.refreshAllWidgets(context); - // Initialize whether or not precaching is enabled. - PrecacheLauncher.updatePrecachingEnabled(context); - WebApkVersionManager.updateWebApksIfNeeded(); removeSnapshotDatabase(context);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java index fb977ee..3cb91bd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
@@ -32,7 +32,8 @@ mCategoryInfo = section.getCategoryInfo(); mParentSection = section; mSuggestionsRanker = ranker; - setVisible(mCategoryInfo.getAdditionalAction() != ContentSuggestionsAdditionalAction.NONE); + setVisibilityInternal( + mCategoryInfo.getAdditionalAction() != ContentSuggestionsAdditionalAction.NONE); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java index 1809b653..a07a2292 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java
@@ -40,6 +40,10 @@ visitor.visitAllDismissedItem(); } + public void setVisible(boolean visible) { + setVisibilityInternal(visible); + } + /** * ViewHolder for an item of type {@link ItemViewType#ALL_DISMISSED}. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/Footer.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/Footer.java index dd851e9..07d1a3d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/Footer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/Footer.java
@@ -37,6 +37,10 @@ visitor.visitFooter(); } + public void setVisible(boolean visible) { + setVisibilityInternal(visible); + } + /** * The {@code ViewHolder} for the {@link Footer}. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java index 88530ed..6d44e90 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -15,9 +15,14 @@ import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ntp.ContextMenuManager; import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder.PartialBindCallback; +import org.chromium.chrome.browser.ntp.snippets.CategoryInt; +import org.chromium.chrome.browser.ntp.snippets.CategoryStatus; import org.chromium.chrome.browser.ntp.snippets.SectionHeaderViewHolder; import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder; +import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; +import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; +import org.chromium.chrome.browser.suggestions.DestructionObserver; import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView; import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate; import org.chromium.chrome.browser.suggestions.TileGrid; @@ -103,6 +108,9 @@ mRoot.addChild(mBottomSpacer); } + RemoteSuggestionsStatusObserver suggestionsObserver = new RemoteSuggestionsStatusObserver(); + mUiDelegate.addDestructionObserver(suggestionsObserver); + updateAllDismissedVisibility(); mRoot.setParent(this); } @@ -222,7 +230,8 @@ } private void updateAllDismissedVisibility() { - boolean showAllDismissed = hasAllBeenDismissed(); + boolean showAllDismissed = hasAllBeenDismissed() + && mUiDelegate.getSuggestionsSource().areRemoteSuggestionsEnabled(); mAllDismissed.setVisible(showAllDismissed); mFooter.setVisible(!showAllDismissed); } @@ -309,4 +318,24 @@ InnerNode getRootForTesting() { return mRoot; } + + private class RemoteSuggestionsStatusObserver + extends SuggestionsSource.EmptyObserver implements DestructionObserver { + public RemoteSuggestionsStatusObserver() { + mUiDelegate.getSuggestionsSource().addObserver(this); + } + + @Override + public void onCategoryStatusChanged( + @CategoryInt int category, @CategoryStatus int newStatus) { + if (!SnippetsBridge.isCategoryRemote(category)) return; + + updateAllDismissedVisibility(); + } + + @Override + public void onDestroy() { + mUiDelegate.getSuggestionsSource().removeObserver(this); + } + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/OptionalLeaf.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/OptionalLeaf.java index 19af66a..26174cc7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/OptionalLeaf.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/OptionalLeaf.java
@@ -67,7 +67,7 @@ * initially considered hidden. */ @CallSuper - public void setVisible(boolean visible) { + protected void setVisibilityInternal(boolean visible) { if (mVisible == visible) return; mVisible = visible;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java index 50e89fc..b1b39f0c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java
@@ -28,4 +28,8 @@ protected void visitOptionalItem(NodeVisitor visitor) { visitor.visitProgressItem(); } + + public void setVisible(boolean visible) { + setVisibilityInternal(visible); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java index cf3437a..4cc059122 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
@@ -43,7 +43,7 @@ public SectionList(SuggestionsUiDelegate uiDelegate, OfflinePageBridge offlinePageBridge) { mUiDelegate = uiDelegate; - mUiDelegate.getSuggestionsSource().setObserver(this); + mUiDelegate.getSuggestionsSource().addObserver(this); mOfflinePageBridge = offlinePageBridge; mUiDelegate.addDestructionObserver(new DestructionObserver() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java index 1a53583..857c604 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
@@ -15,6 +15,10 @@ import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.ntp.ContextMenuManager; +import org.chromium.chrome.browser.ntp.snippets.CategoryInt; +import org.chromium.chrome.browser.ntp.snippets.CategoryStatus; +import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; +import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; import org.chromium.chrome.browser.preferences.ChromePreferenceManager; import org.chromium.chrome.browser.signin.AccountSigninActivity; import org.chromium.chrome.browser.signin.SigninAccessPoint; @@ -39,23 +43,37 @@ */ private boolean mDismissed; + /** + * Whether the signin status means that the user has the possibility to sign in. + */ + private boolean mCanSignIn; + + /** + * Whether personalized suggestions can be shown. If it's not the case, we have no reason to + * offer the user to sign in. + */ + private boolean mCanShowPersonalizedSuggestions; + private final ImpressionTracker mImpressionTracker = new ImpressionTracker(null, this); @Nullable - private final SigninObserver mObserver; + private final SigninObserver mSigninObserver; public SignInPromo(SuggestionsUiDelegate uiDelegate) { mDismissed = ChromePreferenceManager.getInstance().getNewTabPageSigninPromoDismissed(); + SuggestionsSource suggestionsSource = uiDelegate.getSuggestionsSource(); SigninManager signinManager = SigninManager.get(ContextUtils.getApplicationContext()); if (mDismissed) { - mObserver = null; + mSigninObserver = null; } else { - mObserver = new SigninObserver(signinManager); - uiDelegate.addDestructionObserver(mObserver); + mSigninObserver = new SigninObserver(signinManager, suggestionsSource); + uiDelegate.addDestructionObserver(mSigninObserver); } - setVisible(signinManager.isSignInAllowed() && !signinManager.isSignedInOnNative()); + mCanSignIn = signinManager.isSignInAllowed() && !signinManager.isSignedInOnNative(); + mCanShowPersonalizedSuggestions = suggestionsSource.areRemoteSuggestionsEnabled(); + updateVisibility(); } @Override @@ -70,7 +88,7 @@ */ @Nullable public DestructionObserver getObserver() { - return mObserver; + return mSigninObserver; } @Override @@ -114,9 +132,8 @@ mImpressionTracker.reset(null); } - @Override - public void setVisible(boolean visible) { - super.setVisible(!mDismissed && visible); + private void updateVisibility() { + setVisibilityInternal(!mDismissed && mCanSignIn && mCanShowPersonalizedSuggestions); } @Override @@ -127,26 +144,31 @@ /** Hides the sign in promo and sets a preference to make sure it is not shown again. */ @Override public void dismiss(Callback<String> itemRemovedCallback) { + assert mSigninObserver != null; mDismissed = true; - setVisible(false); + updateVisibility(); ChromePreferenceManager.getInstance().setNewTabPageSigninPromoDismissed(true); - mObserver.unregister(); + mSigninObserver.unregister(); itemRemovedCallback.onResult(ContextUtils.getApplicationContext().getString(getHeader())); } @VisibleForTesting - class SigninObserver + class SigninObserver extends SuggestionsSource.EmptyObserver implements SignInStateObserver, SignInAllowedObserver, DestructionObserver { private final SigninManager mSigninManager; + private final SuggestionsSource mSuggestionsSource; /** Guards {@link #unregister()}, which can be called multiple times. */ private boolean mUnregistered; - private SigninObserver(SigninManager signinManager) { + private SigninObserver(SigninManager signinManager, SuggestionsSource suggestionsSource) { mSigninManager = signinManager; mSigninManager.addSignInAllowedObserver(this); mSigninManager.addSignInStateObserver(this); + + mSuggestionsSource = suggestionsSource; + mSuggestionsSource.addObserver(this); } private void unregister() { @@ -155,6 +177,8 @@ mSigninManager.removeSignInAllowedObserver(this); mSigninManager.removeSignInStateObserver(this); + + mSuggestionsSource.removeObserver(this); } @Override @@ -167,17 +191,31 @@ // Listening to onSignInAllowedChanged is important for the FRE. Sign in is not allowed // until it is completed, but the NTP is initialised before the FRE is even shown. By // implementing this we can show the promo if the user did not sign in during the FRE. - setVisible(mSigninManager.isSignInAllowed()); + mCanSignIn = mSigninManager.isSignInAllowed(); + updateVisibility(); } @Override public void onSignedIn() { - setVisible(false); + mCanSignIn = false; + updateVisibility(); } @Override public void onSignedOut() { - setVisible(true); + mCanSignIn = mSigninManager.isSignInAllowed(); + updateVisibility(); + } + + @Override + public void onCategoryStatusChanged( + @CategoryInt int category, @CategoryStatus int newStatus) { + if (!SnippetsBridge.isCategoryRemote(category)) return; + + // Checks whether the category is enabled first to avoid unnecessary calls across JNI. + mCanShowPersonalizedSuggestions = SnippetsBridge.isCategoryEnabled(category) + || mSuggestionsSource.areRemoteSuggestionsEnabled(); + updateVisibility(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java index e603b04..f359a848 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java
@@ -63,4 +63,8 @@ assert holder instanceof StatusCardViewHolder; ((StatusCardViewHolder) holder).onBindViewHolder(this); } + + public void setVisible(boolean visible) { + setVisibilityInternal(visible); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java index 9f70931f..4cad997b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java
@@ -18,7 +18,7 @@ public SectionHeader(String headerText) { this.mHeaderText = headerText; - setVisible(true); + setVisibilityInternal(true); } @Override @@ -41,4 +41,8 @@ public void visitOptionalItem(NodeVisitor visitor) { visitor.visitHeader(); } + + public void setVisible(boolean visible) { + setVisibilityInternal(visible); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java index ee4f3ef4..34130f7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -7,6 +7,7 @@ import android.graphics.Bitmap; import org.chromium.base.Callback; +import org.chromium.base.ObserverList; import org.chromium.base.annotations.CalledByNative; import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo; import org.chromium.chrome.browser.profiles.Profile; @@ -22,13 +23,17 @@ private static final String TAG = "SnippetsBridge"; private long mNativeSnippetsBridge; - private SuggestionsSource.Observer mObserver; + private final ObserverList<Observer> mObserverList = new ObserverList<>(); public static boolean isCategoryStatusAvailable(@CategoryStatus int status) { - // Note: This code is duplicated in content_suggestions_category_status.cc. + // Note: This code is duplicated in category_status.cc. return status == CategoryStatus.AVAILABLE_LOADING || status == CategoryStatus.AVAILABLE; } + public static boolean isCategoryRemote(@CategoryInt int category) { + return category > KnownCategories.REMOTE_CATEGORIES_OFFSET; + } + /** Returns whether the category is considered "enabled", and can show content suggestions. */ public static boolean isCategoryEnabled(@CategoryStatus int status) { switch (status) { @@ -62,7 +67,7 @@ assert mNativeSnippetsBridge != 0; nativeDestroy(mNativeSnippetsBridge); mNativeSnippetsBridge = 0; - mObserver = null; + mObserverList.clear(); } /** @@ -83,8 +88,9 @@ nativeSetRemoteSuggestionsEnabled(enabled); } - public static boolean areRemoteSuggestionsEnabled() { - return nativeAreRemoteSuggestionsEnabled(); + @Override + public boolean areRemoteSuggestionsEnabled() { + return nativeAreRemoteSuggestionsEnabled(mNativeSnippetsBridge); } public static boolean areRemoteSuggestionsManaged() { @@ -174,9 +180,14 @@ } @Override - public void setObserver(Observer observer) { + public void addObserver(Observer observer) { assert observer != null; - mObserver = observer; + mObserverList.addObserver(observer); + } + + @Override + public void removeObserver(Observer observer) { + mObserverList.removeObserver(observer); } @Override @@ -229,22 +240,26 @@ @CalledByNative private void onNewSuggestions(@CategoryInt int category) { - if (mObserver != null) mObserver.onNewSuggestions(category); + for (Observer observer : mObserverList) observer.onNewSuggestions(category); } @CalledByNative private void onCategoryStatusChanged(@CategoryInt int category, @CategoryStatus int newStatus) { - if (mObserver != null) mObserver.onCategoryStatusChanged(category, newStatus); + for (Observer observer : mObserverList) { + observer.onCategoryStatusChanged(category, newStatus); + } } @CalledByNative private void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) { - if (mObserver != null) mObserver.onSuggestionInvalidated(category, idWithinCategory); + for (Observer observer : mObserverList) { + observer.onSuggestionInvalidated(category, idWithinCategory); + } } @CalledByNative private void onFullRefreshRequired() { - if (mObserver != null) mObserver.onFullRefreshRequired(); + for (Observer observer : mObserverList) observer.onFullRefreshRequired(); } private native long nativeInit(Profile profile); @@ -253,7 +268,7 @@ private static native void nativeRemoteSuggestionsSchedulerOnFetchDue(); private static native void nativeRemoteSuggestionsSchedulerRescheduleFetching(); private static native void nativeSetRemoteSuggestionsEnabled(boolean enabled); - private static native boolean nativeAreRemoteSuggestionsEnabled(); + private native boolean nativeAreRemoteSuggestionsEnabled(long nativeNTPSnippetsBridge); private static native boolean nativeAreRemoteSuggestionsManaged(); private static native boolean nativeAreRemoteSuggestionsManagedByCustodian(); private static native void nativeSetContentSuggestionsNotificationsEnabled(boolean enabled);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java index b20d676..8d36eca 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
@@ -43,6 +43,11 @@ void fetchRemoteSuggestions(); /** + * @return Whether remote suggestions are enabled. + */ + boolean areRemoteSuggestionsEnabled(); + + /** * Gets the categories in the order in which they should be displayed. * @return The categories. */ @@ -120,5 +125,26 @@ /** * Sets the recipient for update events from the source. */ - void setObserver(Observer observer); + void addObserver(Observer observer); + + /** + * Removes an observer. Is no-op if the observer was not already registered. + */ + void removeObserver(Observer observer); + + /** No-op implementation of {@link SuggestionsSource.Observer}. */ + class EmptyObserver implements Observer { + @Override + public void onNewSuggestions(@CategoryInt int category) {} + + @Override + public void onCategoryStatusChanged( + @CategoryInt int category, @CategoryStatus int newStatus) {} + + @Override + public void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) {} + + @Override + public void onFullRefreshRequired() {} + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java index 2405c574..cd6af2b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
@@ -14,6 +14,7 @@ import android.os.Build; import org.chromium.base.ContextUtils; +import org.chromium.base.SysUtils; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.UrlConstants; @@ -97,7 +98,9 @@ // In the case that the user has disabled our flag and restarted, this is a minimal code // path to disable our subscription to Nearby. if (!featureIsEnabled()) { - new NearbyBackgroundSubscription(NearbySubscription.UNSUBSCRIBE).run(); + if (!SysUtils.isLowEndDevice()) { + new NearbyBackgroundSubscription(NearbySubscription.UNSUBSCRIBE).run(); + } return; } @@ -131,7 +134,8 @@ return locationUtils.isSystemLocationSettingEnabled() && locationUtils.hasAndroidLocationPermission() && TemplateUrlService.getInstance().isDefaultSearchEngineGoogle() - && !Profile.getLastUsedProfile().isOffTheRecord(); + && !Profile.getLastUsedProfile().isOffTheRecord() + && !SysUtils.isLowEndDevice(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContentSuggestionsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContentSuggestionsPreferences.java index 529a5d6..b264fd4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContentSuggestionsPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContentSuggestionsPreferences.java
@@ -23,7 +23,9 @@ import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationAction; import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationOptOut; import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; +import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.suggestions.SuggestionsDependencyFactory; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -74,7 +76,12 @@ setHasOptionsMenu(true); finishSwitchInitialisation(); - boolean isEnabled = SnippetsBridge.areRemoteSuggestionsEnabled(); + SuggestionsSource suggestionsSource = + SuggestionsDependencyFactory.getInstance().createSuggestionSource( + Profile.getLastUsedProfile()); + boolean isEnabled = suggestionsSource.areRemoteSuggestionsEnabled(); + suggestionsSource.onDestroy(); + mIsEnabled = !isEnabled; // Opposite so that we trigger side effects below. updatePreferences(isEnabled);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java index d91b9520..95504f5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
@@ -19,7 +19,6 @@ import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial; import org.chromium.chrome.browser.help.HelpAndFeedback; import org.chromium.chrome.browser.physicalweb.PhysicalWeb; -import org.chromium.chrome.browser.precache.PrecacheLauncher; import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference; import org.chromium.chrome.browser.preferences.ManagedPreferenceDelegate; import org.chromium.chrome.browser.preferences.PrefServiceBridge; @@ -130,7 +129,6 @@ (boolean) newValue); } else if (PREF_NETWORK_PREDICTIONS.equals(key)) { PrefServiceBridge.getInstance().setNetworkPredictionEnabled((boolean) newValue); - PrecacheLauncher.updatePrecachingEnabled(getActivity()); } else if (PREF_NAVIGATION_ERROR.equals(key)) { PrefServiceBridge.getInstance().setResolveNavigationErrorEnabled((boolean) newValue); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/signin/OWNERS index f5f6e7ea..6d22a37 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/OWNERS
@@ -1 +1,4 @@ +bsazonov@chromium.org gogerald@chromium.org + +# COMPONENT: Services>Signin
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java index 87cd6b2c..146072c6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
@@ -66,7 +66,7 @@ @Override public void onTileDataChanged() { - setVisible(mTileGroup.getTiles().length != 0); + setVisibilityInternal(mTileGroup.getTiles().length != 0); if (isVisible()) notifyItemChanged(0, new ViewHolder.UpdateTilesCallback(mTileGroup)); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java index 7eb8dd1..730ebbcf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java
@@ -11,6 +11,7 @@ import org.chromium.chrome.browser.AppHooks; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.datausage.DataUseTabUIManager; +import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl; import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler; import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler.OverrideUrlLoadingResult; import org.chromium.chrome.browser.externalnav.ExternalNavigationParams; @@ -52,6 +53,14 @@ /** * Constructs a new instance of {@link InterceptNavigationDelegateImpl} with the given + * {@link ExternalNavigationDelegate}. + */ + public InterceptNavigationDelegateImpl(ExternalNavigationDelegateImpl delegate, Tab tab) { + this(new ExternalNavigationHandler(delegate), tab); + } + + /** + * Constructs a new instance of {@link InterceptNavigationDelegateImpl} with the given * {@link ExternalNavigationHandler}. */ public InterceptNavigationDelegateImpl(ExternalNavigationHandler externalNavHandler, Tab tab) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java index 44be9d6..1c1d0ae 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -2794,8 +2794,7 @@ /** * See {@link #mInterceptNavigationDelegate}. */ - @VisibleForTesting - protected void setInterceptNavigationDelegate(InterceptNavigationDelegateImpl delegate) { + public void setInterceptNavigationDelegate(InterceptNavigationDelegateImpl delegate) { mInterceptNavigationDelegate = delegate; nativeSetInterceptNavigationDelegate(mNativeTabAndroid, delegate); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrExternalNavigationDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrExternalNavigationDelegate.java new file mode 100644 index 0000000..26bf71f --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrExternalNavigationDelegate.java
@@ -0,0 +1,41 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.vr_shell; + +import android.content.Intent; + +import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl; +import org.chromium.chrome.browser.tab.Tab; + +/** + * A custom external navigation delegate that show DOFF instead of sending intent to external app. + */ +public class VrExternalNavigationDelegate extends ExternalNavigationDelegateImpl { + public VrExternalNavigationDelegate(Tab tab) { + super(tab); + } + + @Override + public void startActivity(Intent intent, boolean proxy) { + VrShellDelegate.showDoffAndExitVr(false); + } + + @Override + public boolean startActivityIfNeeded(Intent intent, boolean proxy) { + return false; + } + + @Override + public void startIncognitoIntent(Intent intent, String referrerUrl, String fallbackUrl, Tab tab, + boolean needsToCloseTab, boolean proxy) { + VrShellDelegate.showDoffAndExitVr(false); + } + + @Override + public void startFileIntent( + Intent intent, String referrerUrl, Tab tab, boolean needsToCloseTab) { + VrShellDelegate.showDoffAndExitVr(false); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java index fdc2049..69032c5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -363,6 +363,11 @@ } } + public static void showDoffAndExitVr(boolean optional) { + assert sInstance != null; + sInstance.showDoffAndExitVrInternal(optional); + } + @CalledByNative private static VrShellDelegate getInstance() { Activity activity = ApplicationStatus.getLastTrackedFocusedActivity(); @@ -1145,7 +1150,7 @@ mShouldShowPageInfo = false; } - /* package */ void showDoffAndExitVr(boolean optional) { + private void showDoffAndExitVrInternal(boolean optional) { if (mShowingDaydreamDoff) return; if (showDoff(optional)) return; shutdownVr(true /* disableVrMode */, false /* canReenter */, true /* stayingInChrome */); @@ -1153,7 +1158,7 @@ /* package */ void onUnhandledPageInfo() { mShouldShowPageInfo = true; - showDoffAndExitVr(true); + showDoffAndExitVrInternal(true); } /* package */ void exitCct() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java index fe861316..3b52a8a3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -35,6 +35,7 @@ import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.tab.EmptyTabObserver; +import org.chromium.chrome.browser.tab.InterceptNavigationDelegateImpl; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tab.TabRedirectHandler; @@ -71,8 +72,6 @@ // Increasing DPR any more than this doesn't appear to increase text quality. private static final float DEFAULT_DPR = 1.4f; - // For WebVR we just create a DPR 1.0 display that matches the physical display size. - private static final float WEBVR_DPR = 1.0f; // Fairly arbitrary values that put a good amount of content on the screen without making the // text too small to read. @VisibleForTesting @@ -87,6 +86,7 @@ private final ChromeActivity mActivity; private final VrShellDelegate mDelegate; private final VirtualDisplayAndroid mContentVirtualDisplay; + private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate; private final TabRedirectHandler mTabRedirectHandler; private final TabObserver mTabObserver; private final TabModelSelectorObserver mTabModelSelectorObserver; @@ -111,6 +111,7 @@ private boolean mReprojectedRendering; + private InterceptNavigationDelegateImpl mNonVrInterceptNavigationDelegate; private TabRedirectHandler mNonVrTabRedirectHandler; private TabModelSelector mTabModelSelector; private float mLastContentWidth; @@ -163,6 +164,10 @@ mContentVirtualDisplay = VirtualDisplayAndroid.createVirtualDisplay(); mContentVirtualDisplay.setTo(primaryDisplay); + mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl( + new VrExternalNavigationDelegate(mActivity.getActivityTab()), + mActivity.getActivityTab()); + mTabRedirectHandler = new TabRedirectHandler(mActivity) { @Override public boolean shouldStayInChrome(boolean hasExternalProtocol) { @@ -354,7 +359,7 @@ setSplashScreenIcon(); // Set the UI and content sizes before we load the UI. - updateWebVrDisplaySize(forWebVr); + setContentCssSize(DEFAULT_CONTENT_WIDTH, DEFAULT_CONTENT_HEIGHT, DEFAULT_DPR); reparentAllTabs(mContentVrWindowAndroid); swapToForegroundTab(); @@ -404,6 +409,8 @@ } private void initializeTabForVR() { + mNonVrInterceptNavigationDelegate = mTab.getInterceptNavigationDelegate(); + mTab.setInterceptNavigationDelegate(mInterceptNavigationDelegate); // Make sure we are not redirecting to another app, i.e. out of VR mode. mNonVrTabRedirectHandler = mTab.getTabRedirectHandler(); mTab.setTabRedirectHandler(mTabRedirectHandler); @@ -411,6 +418,7 @@ } private void restoreTabFromVR() { + mTab.setInterceptNavigationDelegate(mNonVrInterceptNavigationDelegate); mTab.setTabRedirectHandler(mNonVrTabRedirectHandler); mNonVrTabRedirectHandler = null; } @@ -436,7 +444,7 @@ // Exits VR, telling the user to remove their headset, and returning to Chromium. @CalledByNative public void forceExitVr() { - mDelegate.showDoffAndExitVr(false); + VrShellDelegate.showDoffAndExitVr(false); } // Called because showing PageInfo isn't supported in VR. This happens when the user clicks on @@ -576,17 +584,6 @@ public void setWebVrModeEnabled(boolean enabled, boolean showToast) { mContentVrWindowAndroid.setVSyncPaused(enabled); nativeSetWebVrMode(mNativeVrShell, enabled, showToast); - updateWebVrDisplaySize(enabled); - } - - private void updateWebVrDisplaySize(boolean inWebVr) { - if (inWebVr) { - DisplayAndroid primaryDisplay = DisplayAndroid.getNonMultiDisplay(mActivity); - setContentCssSize( - primaryDisplay.getDisplayWidth(), primaryDisplay.getDisplayHeight(), WEBVR_DPR); - } else { - setContentCssSize(DEFAULT_CONTENT_WIDTH, DEFAULT_CONTENT_HEIGHT, DEFAULT_DPR); - } } @Override
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 ee14c159..c2f76ec 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
@@ -996,6 +996,12 @@ for (BottomSheetObserver o : mObservers) o.onSheetOpened(); announceForAccessibility(getResources().getString(R.string.bottom_sheet_opened)); mActivity.addViewObscuringAllTabs(this); + + setFocusable(true); + setFocusableInTouchMode(true); + setContentDescription( + getResources().getString(R.string.bottom_sheet_accessibility_description)); + if (getFocusedChild() == null) requestFocus(); } /** @@ -1011,6 +1017,10 @@ clearFocus(); mActivity.removeViewObscuringAllTabs(this); + setFocusable(false); + setFocusableInTouchMode(false); + setContentDescription(null); + showHelpBubbleIfNecessary(); }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 18c473a..1e53a36 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3106,6 +3106,9 @@ <message name="IDS_BOTTOM_SHEET_ACCESSIBILITY_EXPAND_BUTTON_HELP_BUBBLE_MESSAGE" desc="Text displayed in a help bubble above the toolbar expand button prompting users to tap the button to see their bookmarks and other content when accessibility is enabled."> Tap to see bookmarks, downloads, and history </message> + <message name="IDS_BOTTOM_SHEET_ACCESSIBILITY_DESCRIPTION" desc="Accessibility string read when the navigation panel is focused."> + Navigation panel + </message> <message name="IDS_BOTTOM_SHEET_OPENED" desc="Accessibility string read when the bottom navigation panel is opened."> Navigation panel opened </message>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 0e5344fb..b22a7fc 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -1303,6 +1303,7 @@ "java/src/org/chromium/chrome/browser/vr_shell/VrCoreInfo.java", "java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionCheckerImpl.java", "java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApiImpl.java", + "java/src/org/chromium/chrome/browser/vr_shell/VrExternalNavigationDelegate.java", "java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java", "java/src/org/chromium/chrome/browser/vr_shell/VrWindowAndroid.java", "java/src/org/chromium/chrome/browser/vr_shell/OnDispatchTouchEventCallback.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java index 542575f..78806a0e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java
@@ -21,7 +21,6 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.RetryOnFailure; import org.chromium.chrome.browser.ntp.snippets.SnippetsLauncher; -import org.chromium.chrome.browser.precache.PrecacheController; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; /** @@ -38,8 +37,6 @@ private boolean mDidLaunchBrowser = false; private boolean mDidFetchSnippets = false; private boolean mDidRescheduleFetching = false; - private boolean mHasPrecacheInstance = true; - private boolean mPrecachingStarted = false; @Override protected void launchBrowser(Context context, String tag) { @@ -57,49 +54,27 @@ } @Override - protected boolean hasPrecacheInstance() { - return mHasPrecacheInstance; - } - - @Override - protected void precache(Context context, String tag) { - if (!mHasPrecacheInstance) { - mPrecachingStarted = true; - } - } - - @Override protected void rescheduleBackgroundSyncTasksOnUpgrade() {} @Override - protected void reschedulePrecacheTasksOnUpgrade() {} - - @Override protected void rescheduleOfflinePages() {} // Posts an assertion task to the UI thread. Since this is only called after the call // to onRunTask, it will be enqueued after any possible call to launchBrowser, and we // can reliably check whether launchBrowser was called. protected void checkExpectations(final boolean expectedLaunchBrowser, - final boolean expectedPrecacheStarted, final boolean expectedFetchSnippets, - final boolean expectedRescheduleFetching) { + final boolean expectedFetchSnippets, final boolean expectedRescheduleFetching) { ThreadUtils.runOnUiThread(new Runnable() { @Override public void run() { Assert.assertEquals("StartedService", expectedLaunchBrowser, mDidLaunchBrowser); Assert.assertEquals( - "StartedPrecache", expectedPrecacheStarted, mPrecachingStarted); - Assert.assertEquals( "FetchedSnippets", expectedFetchSnippets, mDidFetchSnippets); Assert.assertEquals("RescheduledFetching", expectedRescheduleFetching, mDidRescheduleFetching); } }); } - - protected void deletePrecacheInstance() { - mHasPrecacheInstance = false; - } } @Before @@ -126,17 +101,17 @@ mSnippetsLauncher = null; } - private void startOnRunTaskAndVerify(String taskTag, boolean shouldStart, - boolean shouldPrecache, boolean shouldFetchSnippets) { + private void startOnRunTaskAndVerify( + String taskTag, boolean shouldStart, boolean shouldFetchSnippets) { mTaskService.onRunTask(new TaskParams(taskTag)); - mTaskService.checkExpectations(shouldStart, shouldPrecache, shouldFetchSnippets, false); + mTaskService.checkExpectations(shouldStart, shouldFetchSnippets, false); } @Test @SmallTest @Feature({"BackgroundSync"}) public void testBackgroundSyncNoLaunchBrowserWhenInstanceExists() { - startOnRunTaskAndVerify(BackgroundSyncLauncher.TASK_TAG, false, false, false); + startOnRunTaskAndVerify(BackgroundSyncLauncher.TASK_TAG, false, false); } @Test @@ -144,21 +119,21 @@ @Feature({"BackgroundSync"}) public void testBackgroundSyncLaunchBrowserWhenInstanceDoesNotExist() { deleteSyncLauncherInstance(); - startOnRunTaskAndVerify(BackgroundSyncLauncher.TASK_TAG, true, false, false); + startOnRunTaskAndVerify(BackgroundSyncLauncher.TASK_TAG, true, false); } @Test @SmallTest @Feature({"NTPSnippets"}) public void testNTPSnippetsFetchWifiNoLaunchBrowserWhenInstanceExists() { - startOnRunTaskAndVerify(SnippetsLauncher.TASK_TAG_WIFI, false, false, true); + startOnRunTaskAndVerify(SnippetsLauncher.TASK_TAG_WIFI, false, true); } @Test @SmallTest @Feature({"NTPSnippets"}) public void testNTPSnippetsFetchFallbackNoLaunchBrowserWhenInstanceExists() { - startOnRunTaskAndVerify(SnippetsLauncher.TASK_TAG_FALLBACK, false, false, true); + startOnRunTaskAndVerify(SnippetsLauncher.TASK_TAG_FALLBACK, false, true); } @Test @@ -166,7 +141,7 @@ @Feature({"NTPSnippets"}) public void testNTPSnippetsFetchWifiLaunchBrowserWhenInstanceDoesNotExist() { deleteSnippetsLauncherInstance(); - startOnRunTaskAndVerify(SnippetsLauncher.TASK_TAG_WIFI, true, false, true); + startOnRunTaskAndVerify(SnippetsLauncher.TASK_TAG_WIFI, true, true); } @Test @@ -174,27 +149,12 @@ @Feature({"NTPSnippets"}) public void testNTPSnippetsFetchFallbackLaunchBrowserWhenInstanceDoesNotExist() { deleteSnippetsLauncherInstance(); - startOnRunTaskAndVerify(SnippetsLauncher.TASK_TAG_FALLBACK, true, false, true); - } - - @Test - @SmallTest - @Feature({"Precache"}) - public void testPrecacheNoLaunchBrowserWhenInstanceExists() { - startOnRunTaskAndVerify(PrecacheController.PERIODIC_TASK_TAG, false, false, false); - } - - @Test - @SmallTest - @Feature({"Precache"}) - public void testPrecacheLaunchBrowserWhenInstanceDoesNotExist() { - mTaskService.deletePrecacheInstance(); - startOnRunTaskAndVerify(PrecacheController.PERIODIC_TASK_TAG, true, true, false); + startOnRunTaskAndVerify(SnippetsLauncher.TASK_TAG_FALLBACK, true, true); } private void startOnInitializeTasksAndVerify(boolean shouldStart, boolean shouldReschedule) { mTaskService.onInitializeTasks(); - mTaskService.checkExpectations(shouldStart, false, false, shouldReschedule); + mTaskService.checkExpectations(shouldStart, false, shouldReschedule); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java index 60352ac..4fd8810 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java
@@ -9,6 +9,8 @@ import com.google.vr.testframework.controller.ControllerTestApi; +import org.junit.Assert; + import java.util.concurrent.TimeUnit; /** @@ -21,6 +23,7 @@ * - PairedControllerAddress: "FOO" */ public class EmulatedVrController { + public enum ScrollDirection { UP, DOWN, LEFT, RIGHT } private final ControllerTestApi mApi; public EmulatedVrController(Context context) { @@ -87,31 +90,41 @@ } /** - * Performs an upward swipe on the touchpad, which scrolls down in VR Shell. + * Performs an swipe on the touchpad in order to scroll in the specified + * direction while in the VR browser. * Note that scrolling this way is not consistent, i.e. scrolling down then * scrolling up at the same speed won't necessarily scroll back to the exact * starting position on the page. * + * @param direction the ScrollDirection to scroll with * @param steps the number of intermediate steps to send while scrolling * @param speed how long to wait between steps in the scroll, with higher * numbers resulting in a faster scroll */ - public void scrollDown(int steps, int speed) { - performLinearTouchpadMovement(0.5f, 0.9f, 0.5f, 0.1f, steps, speed); - } - - /** - * Performs a downward swipe on the touchpad, which scrolls up in VR Shell. - * Note that scrolling this way is not consistent, i.e. scrolling down then - * scrolling up at the same speed won't necessarily scroll back to the exact - * starting position on the page. - * - * @param steps the number of intermediate steps to send while scrolling - * @param speed how long to wait between steps in the scroll, with higher - * numbers resulting in a faster scroll - */ - public void scrollUp(int steps, int speed) { - performLinearTouchpadMovement(0.5f, 0.1f, 0.5f, 0.9f, steps, speed); + public void scroll(ScrollDirection direction, int steps, int speed) { + float startX, startY, endX, endY; + startX = startY = endX = endY = 0.5f; + switch (direction) { + case UP: + startY = 0.1f; + endY = 0.9f; + break; + case DOWN: + startY = 0.9f; + endY = 0.1f; + break; + case LEFT: + startX = 0.1f; + endX = 0.9f; + break; + case RIGHT: + startX = 0.9f; + endX = 0.1f; + break; + default: + Assert.fail("Unknown scroll direction enum given"); + } + performLinearTouchpadMovement(startX, startY, endX, endY, steps, speed); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellControllerInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellControllerInputTest.java index 2ccb9e9..88a4082 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellControllerInputTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellControllerInputTest.java
@@ -37,17 +37,17 @@ @Rule public VrTestRule mVrTestRule = new VrTestRule(); - // TODO(bsheedy): Modify test to also check horizontal scrolling /** - * Verifies that swiping up/down on the Daydream controller's touchpad scrolls - * the webpage while in the VR browser. + * Verifies that swiping up/down/left/right on the Daydream controller's + * touchpad scrolls the webpage while in the VR browser. */ @Test @Restriction({RESTRICTION_TYPE_DEVICE_DAYDREAM, RESTRICTION_TYPE_VIEWER_DAYDREAM}) @MediumTest public void testControllerScrolling() throws InterruptedException { // Load page in VR and make sure the controller is pointed at the content quad - mVrTestRule.loadUrl("chrome://credits", PAGE_LOAD_TIMEOUT_S); + mVrTestRule.loadUrl( + mVrTestRule.getHtmlTestFile("test_controller_scrolling"), PAGE_LOAD_TIMEOUT_S); VrTransitionUtils.forceEnterVr(); VrTransitionUtils.waitForVrEntry(POLL_TIMEOUT_LONG_MS); EmulatedVrController controller = new EmulatedVrController(mVrTestRule.getActivity()); @@ -59,23 +59,39 @@ CriteriaHelper.pollUiThread(new Criteria() { @Override public boolean isSatisfied() { - return cvc.computeVerticalScrollRange() > cvc.getContainerView().getHeight(); + return cvc.computeVerticalScrollRange() > cvc.getContainerView().getHeight() + && cvc.computeHorizontalScrollRange() > cvc.getContainerView().getWidth(); } }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_LONG_MS); // Test that scrolling down works - int startScrollY = cvc.getNativeScrollYForTest(); + int startScrollPoint = cvc.getNativeScrollYForTest(); // Arbitrary, but valid values to scroll smoothly int scrollSteps = 20; int scrollSpeed = 60; - controller.scrollDown(scrollSteps, scrollSpeed); - int endScrollY = cvc.getNativeScrollYForTest(); - Assert.assertTrue("Controller was able to scroll down", startScrollY < endScrollY); + controller.scroll(EmulatedVrController.ScrollDirection.DOWN, scrollSteps, scrollSpeed); + // We need this second scroll down, otherwise the horizontal scrolling becomes flaky + // TODO(bsheedy): Figure out why this is the case + controller.scroll(EmulatedVrController.ScrollDirection.DOWN, scrollSteps, scrollSpeed); + int endScrollPoint = cvc.getNativeScrollYForTest(); + Assert.assertTrue("Controller was able to scroll down", startScrollPoint < endScrollPoint); // Test that scrolling up works - startScrollY = endScrollY; - controller.scrollUp(scrollSteps, scrollSpeed); - endScrollY = cvc.getNativeScrollYForTest(); - Assert.assertTrue("Controller was able to scroll up", startScrollY > endScrollY); + startScrollPoint = endScrollPoint; + controller.scroll(EmulatedVrController.ScrollDirection.UP, scrollSteps, scrollSpeed); + endScrollPoint = cvc.getNativeScrollYForTest(); + Assert.assertTrue("Controller was able to scroll up", startScrollPoint > endScrollPoint); + + // Test that scrolling right works + startScrollPoint = cvc.getNativeScrollXForTest(); + controller.scroll(EmulatedVrController.ScrollDirection.RIGHT, scrollSteps, scrollSpeed); + endScrollPoint = cvc.getNativeScrollXForTest(); + Assert.assertTrue("Controller was able to scroll right", startScrollPoint < endScrollPoint); + + // Test that scrolling left works + startScrollPoint = endScrollPoint; + controller.scroll(EmulatedVrController.ScrollDirection.LEFT, scrollSteps, scrollSpeed); + endScrollPoint = cvc.getNativeScrollXForTest(); + Assert.assertTrue("Controller was able to scroll left", startScrollPoint > endScrollPoint); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTransitionTest.java index 08149a3..a5a1d465 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTransitionTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTransitionTest.java
@@ -29,7 +29,6 @@ import org.chromium.chrome.browser.vr_shell.util.VrTransitionUtils; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.ui.display.DisplayAndroid; import java.util.concurrent.TimeoutException; @@ -138,27 +137,20 @@ mVrTestRule.getHtmlTestFile("test_navigation_webvr_page"), PAGE_LOAD_TIMEOUT_S); VrTransitionUtils.enterPresentationOrFail(mVrTestRule.getFirstTabCvc()); - // Validate our size is what we expect while presenting. - DisplayAndroid primaryDisplay = - DisplayAndroid.getNonMultiDisplay(mVrTestRule.getActivity()); - float expectedWidth = primaryDisplay.getDisplayWidth(); - float expectedHeight = primaryDisplay.getDisplayHeight(); + // Validate our size is what we expect while in VR. + float expectedWidth = VrShellImpl.DEFAULT_CONTENT_WIDTH; + float expectedHeight = VrShellImpl.DEFAULT_CONTENT_HEIGHT; + String javascript = "Math.abs(screen.width - " + expectedWidth + ") <= 1 && " + + "Math.abs(screen.height - " + expectedHeight + ") <= 1"; Assert.assertTrue(mVrTestRule.pollJavaScriptBoolean( - "screen.width == " + expectedWidth + " && screen.height == " + expectedHeight, - POLL_TIMEOUT_LONG_MS, mVrTestRule.getFirstTabWebContents())); + javascript, POLL_TIMEOUT_LONG_MS, mVrTestRule.getFirstTabWebContents())); // Exit presentation through JavaScript. mVrTestRule.runJavaScriptOrFail("vrDisplay.exitPresent();", POLL_TIMEOUT_SHORT_MS, mVrTestRule.getFirstTabWebContents()); - // Validate our size is what we expect while in the VR browser. - expectedWidth = VrShellImpl.DEFAULT_CONTENT_WIDTH; - expectedHeight = VrShellImpl.DEFAULT_CONTENT_HEIGHT; - // We aren't comparing for equality because there is some rounding that occurs. - Assert.assertTrue( - mVrTestRule.pollJavaScriptBoolean("Math.abs(screen.width - " + expectedWidth - + ") < 2 && Math.abs(screen.height - " + expectedHeight + ") < 2", - POLL_TIMEOUT_LONG_MS, mVrTestRule.getFirstTabWebContents())); + Assert.assertTrue(mVrTestRule.pollJavaScriptBoolean( + javascript, POLL_TIMEOUT_LONG_MS, mVrTestRule.getFirstTabWebContents())); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java index 99b03b47..7cb9ae3 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -11,7 +11,6 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -63,6 +62,7 @@ import org.chromium.chrome.browser.ntp.snippets.CategoryStatus; import org.chromium.chrome.browser.ntp.snippets.KnownCategories; import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; +import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.preferences.ChromePreferenceManager; import org.chromium.chrome.browser.signin.SigninManager; @@ -80,6 +80,7 @@ import org.chromium.testing.local.LocalRobolectricTestRunner; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -254,10 +255,7 @@ mSource.setInfoForCategory( TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).showIfEmpty().build()); - when(mUiDelegate.getSuggestionsSource()).thenReturn(mSource); - when(mUiDelegate.getEventReporter()).thenReturn(mock(SuggestionsEventReporter.class)); - when(mUiDelegate.getSuggestionsRanker()).thenReturn(mock(SuggestionsRanker.class)); - + resetUiDelegate(); reloadNtp(); } @@ -892,28 +890,26 @@ @Test @Feature({"Ntp"}) public void testSigninPromo() { + @CategoryInt + final int remoteCategory = KnownCategories.REMOTE_CATEGORIES_OFFSET + TEST_CATEGORY; + when(mMockSigninManager.isSignInAllowed()).thenReturn(true); when(mMockSigninManager.isSignedInOnNative()).thenReturn(false); - ArgumentCaptor<DestructionObserver> observers = - ArgumentCaptor.forClass(DestructionObserver.class); - - doNothing().when(mUiDelegate).addDestructionObserver(observers.capture()); - + mSource.setRemoteSuggestionsEnabled(true); + resetUiDelegate(); reloadNtp(); + assertTrue(isSignInPromoVisible()); - // Note: As currently implemented, these two variables should point to the same object, a + // Note: As currently implemented, these variables should point to the same object, a // SignInPromo.SigninObserver - SignInStateObserver signInStateObserver = null; - SignInAllowedObserver signInAllowedObserver = null; - for (DestructionObserver observer : observers.getAllValues()) { - if (observer instanceof SignInStateObserver) { - signInStateObserver = (SignInStateObserver) observer; - } - if (observer instanceof SignInAllowedObserver) { - signInAllowedObserver = (SignInAllowedObserver) observer; - } - } + List<DestructionObserver> observers = getDestructionObserver(mUiDelegate); + SignInStateObserver signInStateObserver = + findFirstInstanceOf(observers, SignInStateObserver.class); + SignInAllowedObserver signInAllowedObserver = + findFirstInstanceOf(observers, SignInAllowedObserver.class); + SuggestionsSource.Observer suggestionsObserver = + findFirstInstanceOf(observers, SuggestionsSource.Observer.class); signInStateObserver.onSignedIn(); assertFalse(isSignInPromoVisible()); @@ -928,6 +924,15 @@ when(mMockSigninManager.isSignInAllowed()).thenReturn(true); signInAllowedObserver.onSignInAllowedChanged(); assertTrue(isSignInPromoVisible()); + + mSource.setRemoteSuggestionsEnabled(false); + suggestionsObserver.onCategoryStatusChanged( + remoteCategory, CategoryStatus.CATEGORY_EXPLICITLY_DISABLED); + assertFalse(isSignInPromoVisible()); + + mSource.setRemoteSuggestionsEnabled(true); + suggestionsObserver.onCategoryStatusChanged(remoteCategory, CategoryStatus.AVAILABLE); + assertTrue(isSignInPromoVisible()); } @Test @@ -960,17 +965,8 @@ @Test @Feature({"Ntp"}) public void testAllDismissedVisibility() { - ArgumentCaptor<DestructionObserver> observers = - ArgumentCaptor.forClass(DestructionObserver.class); - - verify(mUiDelegate, atLeastOnce()).addDestructionObserver(observers.capture()); - - SigninObserver signinObserver = null; - for (DestructionObserver observer : observers.getAllValues()) { - if (observer instanceof SigninObserver) { - signinObserver = (SigninObserver) observer; - } - } + SigninObserver signinObserver = + findFirstInstanceOf(getDestructionObserver(mUiDelegate), SigninObserver.class); @SuppressWarnings("unchecked") Callback<String> itemDismissedCallback = mock(Callback.class); @@ -1045,8 +1041,28 @@ assertEquals(RecyclerView.NO_POSITION, mAdapter.getFirstPositionForType(ItemViewType.ALL_DISMISSED)); + // Disabling remote suggestions should remove both the promo and the AllDismissed item + mSource.setRemoteSuggestionsEnabled(false); + signinObserver.onCategoryStatusChanged( + KnownCategories.REMOTE_CATEGORIES_OFFSET + TEST_CATEGORY, + CategoryStatus.CATEGORY_EXPLICITLY_DISABLED); + // Adapter content: + // Idx | Item + // ----|-------------------- + // 0 | Above-the-fold + // 1 | Footer + // 2 | Spacer + assertEquals(ItemViewType.FOOTER, mAdapter.getItemViewType(1)); + assertEquals(RecyclerView.NO_POSITION, + mAdapter.getFirstPositionForType(ItemViewType.ALL_DISMISSED)); + assertEquals( + RecyclerView.NO_POSITION, mAdapter.getFirstPositionForType(ItemViewType.PROMO)); + // Prepare some suggestions. They should not load because the category is dismissed on // the current NTP. + mSource.setRemoteSuggestionsEnabled(true); + signinObserver.onCategoryStatusChanged( + KnownCategories.REMOTE_CATEGORIES_OFFSET + TEST_CATEGORY, CategoryStatus.AVAILABLE); mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE); mSource.setSuggestionsForCategory(TEST_CATEGORY, createDummySuggestions(1, TEST_CATEGORY)); mSource.setInfoForCategory(TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).build()); @@ -1137,6 +1153,13 @@ return new SectionDescriptor(Collections.<SnippetArticle>emptyList()); } + private void resetUiDelegate() { + reset(mUiDelegate); + when(mUiDelegate.getSuggestionsSource()).thenReturn(mSource); + when(mUiDelegate.getEventReporter()).thenReturn(mock(SuggestionsEventReporter.class)); + when(mUiDelegate.getSuggestionsRanker()).thenReturn(mock(SuggestionsRanker.class)); + } + private void reloadNtp() { mAdapter = new NewTabPageAdapter(mUiDelegate, mock(View.class), makeUiConfig(), mOfflinePageBridge, mock(ContextMenuManager.class), /* tileGroupDelegate = @@ -1151,4 +1174,25 @@ private int getCategory(TreeNode item) { return ((SuggestionsSection) item).getCategory(); } + + /** + * Note: Currently the observers need to be re-registered to be returned again if this method + * has been called, as it relies on argument captors that don't repeatedly capture individual + * calls. + * @return The currently registered destruction observers. + */ + private List<DestructionObserver> getDestructionObserver(SuggestionsUiDelegate delegate) { + ArgumentCaptor<DestructionObserver> observers = + ArgumentCaptor.forClass(DestructionObserver.class); + verify(delegate, atLeastOnce()).addDestructionObserver(observers.capture()); + return observers.getAllValues(); + } + + @SuppressWarnings("unchecked") + private static <T> T findFirstInstanceOf(Collection<?> collection, Class<T> clazz) { + for (Object item : collection) { + if (clazz.isAssignableFrom(item.getClass())) return (T) item; + } + return null; + } }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 712beec2..a1a5aa3 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -8785,7 +8785,7 @@ </message> <!--- Sync Confirmation section of the tab modal signin flow when sync is disabled by policy --> - <message name="IDS_SYNC_DISABLED_CONFIRMATION_CHROME_SYNC_TITLE" desc="Title of the chrome sync section of the sync confirmation dialog in the tab modal signin flow when sync is disabled by policy" formatter_data="android_java"> + <message name="IDS_SYNC_DISABLED_CONFIRMATION_CHROME_SYNC_TITLE" desc="Title of the chrome sync section of the sync confirmation dialog in the tab modal signin flow when sync is disabled by policy"> Sync is disabled by your administrator </message> <message name="IDS_SYNC_DISABLED_CONFIRMATION_DETAILS" desc="Body of the sync confirmation dialog in the tab modal signin flow when sync is disabled by policy">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 102e80f..bd62b58 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1403,6 +1403,8 @@ "usb/web_usb_histograms.h", "usb/web_usb_permission_provider.cc", "usb/web_usb_permission_provider.h", + "vr/vr_tab_helper.cc", + "vr/vr_tab_helper.h", "web_data_service_factory.cc", "web_data_service_factory.h", "webshare/share_target_pref_helper.cc", @@ -3550,10 +3552,6 @@ if (enable_vr) { if (is_android) { - sources += [ - "android/vr_shell/vr_tab_helper.cc", - "android/vr_shell/vr_tab_helper.h", - ] deps += [ "android/vr_shell:vr_android" ] configs += [ "//third_party/gvr-android-sdk:libgvr_config" ] }
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc index 2a27f7e..51fe451 100644 --- a/chrome/browser/android/download/download_controller.cc +++ b/chrome/browser/android/download/download_controller.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/permissions/permission_update_infobar_delegate_android.h" #include "chrome/browser/ui/android/view_android_helper.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/grit/chromium_strings.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" @@ -30,7 +31,6 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/common/referrer.h" -#include "device/vr/features/features.h" #include "jni/DownloadController_jni.h" #include "net/base/filename_util.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -38,10 +38,6 @@ #include "ui/android/window_android.h" #include "ui/base/page_transition_types.h" -#if BUILDFLAG(ENABLE_VR) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) - using base::android::ConvertUTF8ToJavaString; using base::android::JavaParamRef; using base::android::ScopedJavaLocalRef; @@ -223,11 +219,9 @@ const DownloadControllerBase::AcquireFileAccessPermissionCallback& cb) { DCHECK_CURRENTLY_ON(BrowserThread::UI); -#if BUILDFLAG(ENABLE_VR) WebContents* web_contents = web_contents_getter.Run(); - if (vr_shell::VrTabHelper::IsInVr(web_contents)) + if (vr::VrTabHelper::IsInVr(web_contents)) return; -#endif if (HasFileAccessPermission()) { BrowserThread::PostTask(
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc index f90fec1..27e4da5 100644 --- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc +++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -163,18 +163,6 @@ content_suggestions_service->SetRemoteSuggestionsEnabled(enabled); } -static jboolean AreRemoteSuggestionsEnabled( - JNIEnv* env, - const JavaParamRef<jclass>& caller) { - ntp_snippets::ContentSuggestionsService* content_suggestions_service = - ContentSuggestionsServiceFactory::GetForProfile( - ProfileManager::GetLastUsedProfile()); - if (!content_suggestions_service) - return false; - - return content_suggestions_service->AreRemoteSuggestionsEnabled(); -} - // Returns true if the remote provider is managed by an adminstrator's policy. static jboolean AreRemoteSuggestionsManaged( JNIEnv* env, @@ -288,6 +276,12 @@ content_suggestions_service_->GetSuggestionsForCategory(category)); } +jboolean NTPSnippetsBridge::AreRemoteSuggestionsEnabled( + JNIEnv* env, + const JavaParamRef<jobject>& obj) { + return content_suggestions_service_->AreRemoteSuggestionsEnabled(); +} + void NTPSnippetsBridge::FetchSuggestionImage( JNIEnv* env, const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.h b/chrome/browser/android/ntp/ntp_snippets_bridge.h index 0860da0..396ac80 100644 --- a/chrome/browser/android/ntp/ntp_snippets_bridge.h +++ b/chrome/browser/android/ntp/ntp_snippets_bridge.h
@@ -53,6 +53,10 @@ const base::android::JavaParamRef<jobject>& obj, jint j_category_id); + jboolean AreRemoteSuggestionsEnabled( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj); + void FetchSuggestionImage( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc index fc06a47..714998d 100644 --- a/chrome/browser/android/tab_web_contents_delegate_android.cc +++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -13,12 +13,6 @@ #include "chrome/browser/android/banners/app_banner_manager_android.h" #include "chrome/browser/android/feature_utilities.h" #include "chrome/browser/android/hung_renderer_infobar_delegate.h" - -#include "device/vr/features/features.h" -#if BUILDFLAG(ENABLE_VR) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) - #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/file_select_helper.h" #include "chrome/browser/infobars/infobar_service.h" @@ -33,6 +27,7 @@ #include "chrome/browser/ui/find_bar/find_notification_details.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" #include "chrome/browser/ui/tab_helpers.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" #include "components/app_modal/javascript_dialog_manager.h" @@ -126,11 +121,9 @@ void TabWebContentsDelegateAndroid::RunFileChooser( content::RenderFrameHost* render_frame_host, const FileChooserParams& params) { -#if BUILDFLAG(ENABLE_VR) - if (vr_shell::VrTabHelper::IsInVr( + if (vr::VrTabHelper::IsInVr( WebContents::FromRenderFrameHost(render_frame_host))) return; -#endif FileSelectHelper::RunFileChooser(render_frame_host, params); } @@ -138,10 +131,8 @@ TabWebContentsDelegateAndroid::RunBluetoothChooser( content::RenderFrameHost* frame, const BluetoothChooser::EventHandler& event_handler) { -#if BUILDFLAG(ENABLE_VR) - if (vr_shell::VrTabHelper::IsInVr(WebContents::FromRenderFrameHost(frame))) + if (vr::VrTabHelper::IsInVr(WebContents::FromRenderFrameHost(frame))) return nullptr; -#endif return base::MakeUnique<BluetoothChooserAndroid>(frame, event_handler); } @@ -271,11 +262,9 @@ content::JavaScriptDialogManager* TabWebContentsDelegateAndroid::GetJavaScriptDialogManager( WebContents* source) { -#if BUILDFLAG(ENABLE_VR) - if (vr_shell::VrTabHelper::IsInVr(source)) { + if (vr::VrTabHelper::IsInVr(source)) { return nullptr; } -#endif return app_modal::JavaScriptDialogManager::GetInstance(); } @@ -283,13 +272,11 @@ content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) { -#if BUILDFLAG(ENABLE_VR) - if (vr_shell::VrTabHelper::IsInVr(web_contents)) { + if (vr::VrTabHelper::IsInVr(web_contents)) { callback.Run(content::MediaStreamDevices(), content::MEDIA_DEVICE_NOT_SUPPORTED, nullptr); return; } -#endif MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest( web_contents, request, callback, nullptr); }
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc index fd602959..478c2ed 100644 --- a/chrome/browser/android/vr_shell/vr_shell.cc +++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -27,7 +27,6 @@ #include "chrome/browser/android/vr_shell/vr_input_manager.h" #include "chrome/browser/android/vr_shell/vr_shell_delegate.h" #include "chrome/browser/android/vr_shell/vr_shell_gl.h" -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" #include "chrome/browser/android/vr_shell/vr_usage_monitor.h" #include "chrome/browser/android/vr_shell/vr_web_contents_observer.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" @@ -35,6 +34,7 @@ #include "chrome/browser/vr/toolbar_helper.h" #include "chrome/browser/vr/ui_interface.h" #include "chrome/browser/vr/ui_scene_manager.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_controller.h" @@ -84,7 +84,7 @@ // VrTabHelper for details). contents->GetRenderWidgetHostView()->SetIsInVR(is_in_vr); - VrTabHelper* vr_tab_helper = VrTabHelper::FromWebContents(contents); + vr::VrTabHelper* vr_tab_helper = vr::VrTabHelper::FromWebContents(contents); DCHECK(vr_tab_helper); vr_tab_helper->SetIsInVr(is_in_vr); }
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc index 7cca0b4..ed9b708d 100644 --- a/chrome/browser/android/vr_shell/vr_shell_gl.cc +++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -636,6 +636,12 @@ } void VrShellGl::OnContentMove(const gfx::PointF& normalized_hit_point) { + // TODO(mthiesse, vollick): Content is currently way too sensitive to mouse + // moves for how noisy the controller is. It's almost impossible to click a + // link without unintentionally starting a drag event. For this reason we + // disable mouse moves, only delivering a down and up event. + if (controller_->ButtonState(gvr::kControllerButtonClick)) + return; SendGestureToContent( MakeMouseEvent(blink::WebInputEvent::kMouseMove, normalized_hit_point)); }
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 5563c919..1dc878b9 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -209,10 +209,6 @@ // Opens a tab for each GURL in |urls|. - (void)openUrls:(const std::vector<GURL>&)urls; -// Creates StartupBrowserCreator and opens |urls| with it. -- (void)openUrlsViaStartupBrowserCreator:(const std::vector<GURL>&)urls - inBrowser:(Browser*)browser; - // This class cannot open urls until startup has finished. The urls that cannot // be opened are cached in |startupUrls_|. This method must be called exactly // once after startup has completed. It opens the urls in |startupUrls_|, and @@ -1279,16 +1275,6 @@ prefs->GetBoolean(prefs::kBrowserGuestModeEnabled); } -- (void)openUrlsViaStartupBrowserCreator:(const std::vector<GURL>&)urls - inBrowser:(Browser*)browser { - base::CommandLine dummy(base::CommandLine::NO_PROGRAM); - chrome::startup::IsFirstRun first_run = - first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN - : chrome::startup::IS_NOT_FIRST_RUN; - StartupBrowserCreatorImpl launch(base::FilePath(), dummy, first_run); - launch.OpenURLsInBrowser(browser, false, urls); -} - // Various methods to open URLs that we get in a native fashion. We use // StartupBrowserCreator here because on the other platforms, URLs to open come // through the ProcessSingleton, and it calls StartupBrowserCreator. It's best @@ -1299,36 +1285,20 @@ return; } - Profile* profile = [self safeLastProfileForNewWindows]; - SessionStartupPref pref = StartupBrowserCreator::GetSessionStartupPref( - *base::CommandLine::ForCurrentProcess(), profile); - - if (pref.type == SessionStartupPref::LAST) { - if (SessionRestore::IsRestoring(profile)) { - // In case of session restore, remember |urls|, so they will be opened - // after session is resored, in the tabs next to it. - SessionRestore::AddURLsToOpen(profile, urls); - } else { - Browser* browser = chrome::GetLastActiveBrowser(); - if (!browser) { - // This behavior is needed for the case when chromium app is launched, - // but there are no open indows. - browser = new Browser(Browser::CreateParams(profile, true)); - browser->window()->Show(); - SessionRestore::AddURLsToOpen(profile, urls); - } else { - [self openUrlsViaStartupBrowserCreator:urls inBrowser:browser]; - } - } - } else { - Browser* browser = chrome::GetLastActiveBrowser(); - // If no browser window exists then create one with no tabs to be filled in. - if (!browser) { - browser = new Browser(Browser::CreateParams(profile, true)); - browser->window()->Show(); - } - [self openUrlsViaStartupBrowserCreator:urls inBrowser:browser]; + Browser* browser = chrome::GetLastActiveBrowser(); + // if no browser window exists then create one with no tabs to be filled in + if (!browser) { + browser = new Browser( + Browser::CreateParams([self safeLastProfileForNewWindows], true)); + browser->window()->Show(); } + + base::CommandLine dummy(base::CommandLine::NO_PROGRAM); + chrome::startup::IsFirstRun first_run = + first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN + : chrome::startup::IS_NOT_FIRST_RUN; + StartupBrowserCreatorImpl launch(base::FilePath(), dummy, first_run); + launch.OpenURLsInBrowser(browser, false, urls); } - (void)getUrl:(NSAppleEventDescriptor*)event
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm index 922ed687..63324c0 100644 --- a/chrome/browser/app_controller_mac_browsertest.mm +++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -23,9 +23,7 @@ #include "chrome/browser/apps/app_browsertest_util.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/history/history_service_factory.h" -#include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_manager.h" @@ -48,10 +46,8 @@ #include "components/bookmarks/test/bookmark_test_helpers.h" #include "components/prefs/pref_service.h" #include "content/public/browser/navigation_controller.h" -#include "content/public/browser/notification_service.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" -#include "content/public/test/repeated_notification_observer.h" #include "content/public/test/test_navigation_observer.h" #include "extensions/browser/app_window/app_window_registry.h" #include "extensions/common/extension.h" @@ -60,7 +56,7 @@ namespace { -GURL g_open_shortcut_url = GURL("https://localhost"); +GURL g_open_shortcut_url = GURL::EmptyGURL(); // Returns an Apple Event that instructs the application to open |url|. NSAppleEventDescriptor* AppleEventToOpenUrl(const GURL& url) { @@ -107,6 +103,9 @@ @implementation TestOpenShortcutOnStartup - (void)applicationWillFinishLaunching:(NSNotification*)notification { + if (!g_open_shortcut_url.is_valid()) + return; + SendAppleEventToOpenUrlToAppController(g_open_shortcut_url); } @@ -381,6 +380,9 @@ ASSERT_TRUE(destination != NULL); method_exchangeImplementations(original, destination); + + ASSERT_TRUE(embedded_test_server()->Start()); + g_open_shortcut_url = embedded_test_server()->GetURL("/simple.html"); } void SetUpCommandLine(base::CommandLine* command_line) override { @@ -399,203 +401,6 @@ ->GetLastCommittedURL()); } -const char kSessionURL[] = "https://example.com/session.html"; -const char kPresetURL[] = "https://example.com/preset.html"; -const char kUrlToOpen[] = "https://example.com/shortcut.html"; - -class AppControllerOpenShortcutOnStartupBrowserTest - : public AppControllerOpenShortcutBrowserTest, - public testing::WithParamInterface<SessionStartupPref::Type> { - public: - AppControllerOpenShortcutOnStartupBrowserTest() - : session_startup_pref_(GetParam()) {} - virtual ~AppControllerOpenShortcutOnStartupBrowserTest() {} - - void SetUpInProcessBrowserTestFixture() override { - // Don't open URL via AppControllerOpenShortcutBrowserTest in PRE test, - // PRE test should only prepare session-to-restore. - if (!base::StartsWith( - testing::UnitTest::GetInstance()->current_test_info()->name(), - "PRE_", base::CompareCase::SENSITIVE)) { - AppControllerOpenShortcutBrowserTest::SetUpInProcessBrowserTestFixture(); - } - } - - void SetUpOnMainThread() override { - ASSERT_TRUE(embedded_test_server()->Start()); - SessionStartupPref pref(GetParam()); - pref.urls.push_back(GURL(kPresetURL)); - SessionStartupPref::SetStartupPref(browser()->profile(), pref); - } - - protected: - void SetUpCommandLine(base::CommandLine* command_line) override { - set_open_about_blank_on_browser_launch(false); - // Skip AppControllerOpenShortcutBrowserTest::SetUpCommandLine, which adds - // startup URL. - } - - SessionStartupPref::Type GetSessionStartupPref() { - return session_startup_pref_; - } - - private: - SessionStartupPref::Type session_startup_pref_; - - DISALLOW_COPY_AND_ASSIGN(AppControllerOpenShortcutOnStartupBrowserTest); -}; - -IN_PROC_BROWSER_TEST_P(AppControllerOpenShortcutOnStartupBrowserTest, - PRE_OpenURL) { - // Prepare a session to restore in main test body. - ui_test_utils::NavigateToURL(browser(), GURL(kSessionURL)); - ASSERT_EQ(1, browser()->tab_strip_model()->count()); -} - -// This test checks that when AppleEvent on opening URL is received during -// browser starup, that URL is opened and located properly alongside restored -// session or startup URLs. -// Emulates opening local file or URL from other application when chromium -// application is not started. -IN_PROC_BROWSER_TEST_P(AppControllerOpenShortcutOnStartupBrowserTest, OpenURL) { - TabStripModel* tab_strip = browser()->tab_strip_model(); - if (GetSessionStartupPref() == SessionStartupPref::DEFAULT) { - // Open NTP startup setting - tab opened via shortcut should replace NTP. - EXPECT_EQ(1, tab_strip->count()); - } else if (GetSessionStartupPref() == SessionStartupPref::LAST) { - // Restore sesion on startup - expect tab of that session. - EXPECT_EQ(2, tab_strip->count()); - EXPECT_EQ(kSessionURL, tab_strip->GetWebContentsAt(0)->GetURL().spec()); - } else if (GetSessionStartupPref() == SessionStartupPref::URLS) { - // Open specific set of pages startup setting - expect that set of pages. - EXPECT_EQ(2, tab_strip->count()); - EXPECT_EQ(kPresetURL, tab_strip->GetWebContentsAt(0)->GetURL().spec()); - } else { - NOTREACHED() << "Unknown session startup pref, not covered by test."; - } - // Tab opened via shortcut should be the last tab and shold be active. - EXPECT_EQ( - g_open_shortcut_url.spec(), - tab_strip->GetWebContentsAt(tab_strip->count() - 1)->GetURL().spec()); - EXPECT_EQ(tab_strip->count() - 1, tab_strip->active_index()); -} - -INSTANTIATE_TEST_CASE_P(AppControllerOpenShortcutOnStartupPrefsAny, - AppControllerOpenShortcutOnStartupBrowserTest, - testing::Values(SessionStartupPref::DEFAULT, - SessionStartupPref::LAST, - SessionStartupPref::URLS)); - -class AppControllerOpenShortcutInBrowserTest - : public InProcessBrowserTest, - public testing::WithParamInterface<SessionStartupPref::Type> { - public: - AppControllerOpenShortcutInBrowserTest() - : session_startup_pref_(GetParam()) {} - - protected: - SessionStartupPref::Type GetSessionStartupPref() { - return session_startup_pref_; - } - - void SetUpOnMainThread() override { - SessionStartupPref pref(session_startup_pref_); - pref.urls.push_back(GURL(kPresetURL)); - SessionStartupPref::SetStartupPref(browser()->profile(), pref); - } - - void SetUpCommandLine(base::CommandLine* command_line) override { - set_open_about_blank_on_browser_launch(false); - } - - private: - SessionStartupPref::Type session_startup_pref_; - - DISALLOW_COPY_AND_ASSIGN(AppControllerOpenShortcutInBrowserTest); -}; - -IN_PROC_BROWSER_TEST_P(AppControllerOpenShortcutInBrowserTest, - PRE_OpenShortcutInBrowserWithWindow) { - // Prepare a session to restore in main test body. - ui_test_utils::NavigateToURL(browser(), GURL(kSessionURL)); - ASSERT_EQ(1, browser()->tab_strip_model()->count()); -} - -// This test checks that when AppleEvent on opening URL is received by already -// started browser with window, that URL opens in a tab next to existing tabs. -// This needs to be TEST_P (with SessionStartupPref::Type) parameter to -// ensure that opening URL logic will not by mistake restore sesiion or open -// startup URLs. -IN_PROC_BROWSER_TEST_P(AppControllerOpenShortcutInBrowserTest, - OpenShortcutInBrowserWithWindow) { - ui_test_utils::NavigateToURL(browser(), GURL(kSessionURL)); - ASSERT_EQ(1, browser()->tab_strip_model()->count()); - SendAppleEventToOpenUrlToAppController(GURL(kUrlToOpen)); - content::TestNavigationObserver event_navigation_observer( - browser()->tab_strip_model()->GetActiveWebContents()); - event_navigation_observer.Wait(); - - ASSERT_EQ(2, browser()->tab_strip_model()->count()); - TabStripModel* tab_strip = browser()->tab_strip_model(); - EXPECT_EQ(kUrlToOpen, tab_strip->GetWebContentsAt(1)->GetURL().spec()); - EXPECT_EQ(1, tab_strip->active_index()); -} - -IN_PROC_BROWSER_TEST_P(AppControllerOpenShortcutInBrowserTest, - PRE_OpenShortcutInBrowserWithoutWindow) { - // Prepare a session to restore in main test body. - ui_test_utils::NavigateToURL(browser(), GURL(kSessionURL)); - ASSERT_EQ(1, browser()->tab_strip_model()->count()); -} - -// This test checks that when AppleEvent on opening URL is received by -// chromium application withot windows, that URL is opened, alongside with -// restored session if corresponding setting is enabled. -IN_PROC_BROWSER_TEST_P(AppControllerOpenShortcutInBrowserTest, - OpenShortcutInBrowserWithoutWindow) { - ui_test_utils::NavigateToURL(browser(), GURL(kSessionURL)); - content::RepeatedNotificationObserver close_observer( - chrome::NOTIFICATION_BROWSER_CLOSED, 1); - browser()->window()->Close(); - close_observer.Wait(); - - content::RepeatedNotificationObserver open_observer( - chrome::NOTIFICATION_TAB_ADDED, 1); - SendAppleEventToOpenUrlToAppController(GURL(kUrlToOpen)); - - open_observer.Wait(); - - Browser* browser = BrowserList::GetInstance()->GetLastActive(); - TabStripModel* tab_strip = browser->tab_strip_model(); - - if (GetSessionStartupPref() == SessionStartupPref::DEFAULT) { - // Open NTP startup setting - tab opened via shortcut should replace NTP. - ASSERT_EQ(1, tab_strip->count()); - } else if (GetSessionStartupPref() == SessionStartupPref::LAST) { - // Restore sesion on startup - expect tab of that session. - ASSERT_EQ(2, tab_strip->count()); - EXPECT_EQ(kSessionURL, tab_strip->GetWebContentsAt(0)->GetURL().spec()); - } else if (GetSessionStartupPref() == SessionStartupPref::URLS) { - // Open specific set of pages startup setting - when Chromium application - // is already started, do NOT expect these pages to be opened. - ASSERT_EQ(1, tab_strip->count()); - } else { - NOTREACHED() << "Unknown session startup pref, not covered by test."; - } - - // Tab opened via shortcut should be the last tab and shold be active. - EXPECT_EQ( - kUrlToOpen, - tab_strip->GetWebContentsAt(tab_strip->count() - 1)->GetURL().spec()); - EXPECT_EQ(tab_strip->count() - 1, tab_strip->active_index()); -} - -INSTANTIATE_TEST_CASE_P(AppControllerOpenShortcutInBrowserPrefsAny, - AppControllerOpenShortcutInBrowserTest, - testing::Values(SessionStartupPref::DEFAULT, - SessionStartupPref::LAST, - SessionStartupPref::URLS)); - class AppControllerReplaceNTPBrowserTest : public InProcessBrowserTest { protected: AppControllerReplaceNTPBrowserTest() {}
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index 0cdfbea..38d453ed 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -9,9 +9,12 @@ #include <set> #include <string> #include <utility> +#include <vector> #include "base/callback.h" #include "base/metrics/user_metrics.h" +#include "base/task_scheduler/post_task.h" +#include "build/build_config.h" #include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/browser_process.h" @@ -87,10 +90,9 @@ #if defined(OS_ANDROID) #include "chrome/browser/android/webapps/webapp_registry.h" #include "chrome/browser/offline_pages/offline_page_model_factory.h" -#include "chrome/browser/precache/precache_manager_factory.h" #include "components/offline_pages/core/offline_page_feature.h" #include "components/offline_pages/core/offline_page_model.h" -#include "components/precache/content/precache_manager.h" +#include "sql/connection.h" #endif #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -254,6 +256,16 @@ service->RemoveBrowsingData(data_type_mask, origin_filter); } +#if defined(OS_ANDROID) +void ClearPrecacheInBackground(content::BrowserContext* browser_context) { + // Precache code was removed in M61 but the sqlite database file could be + // still here. + base::FilePath db_path(browser_context->GetPath().Append( + base::FilePath(FILE_PATH_LITERAL("PrecacheDatabase")))); + sql::Connection::Delete(db_path); +} +#endif + // Returned by ChromeBrowsingDataRemoverDelegate::GetOriginTypeMatcher(). bool DoesOriginMatchEmbedderMask(int origin_type_mask, const GURL& origin, @@ -616,18 +628,11 @@ #endif #if defined(OS_ANDROID) - precache::PrecacheManager* precache_manager = - precache::PrecacheManagerFactory::GetForBrowserContext(profile_); - // |precache_manager| could be nullptr if the profile is off the record. - if (!precache_manager) { - clear_precache_history_.Start(); - precache_manager->ClearHistory(); - // The above calls are done on the UI thread but do their work on the DB - // thread. So wait for it. - BrowserThread::PostTaskAndReply( - BrowserThread::DB, FROM_HERE, base::Bind(&base::DoNothing), - clear_precache_history_.GetCompletionCallback()); - } + clear_precache_history_.Start(); + base::PostTaskWithTraitsAndReply( + FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, + base::BindOnce(&ClearPrecacheInBackground, profile_), + clear_precache_history_.GetCompletionCallback()); // Clear the history information (last launch time and origin URL) of any // registered webapps.
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.cc index b814ae2..e696dac4 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.cc
@@ -25,7 +25,6 @@ #if defined(OS_ANDROID) #include "chrome/browser/offline_pages/offline_page_model_factory.h" -#include "chrome/browser/precache/precache_manager_factory.h" #endif #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -69,7 +68,6 @@ #if defined(OS_ANDROID) DependsOn(offline_pages::OfflinePageModelFactory::GetInstance()); - DependsOn(precache::PrecacheManagerFactory::GetInstance()); #endif #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 824183f..91cace2 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3082,8 +3082,9 @@ void ChromeContentBrowserClient::RegisterOutOfProcessServices( OutOfProcessServiceMap* services) { #if BUILDFLAG(ENABLE_PRINTING) - services->emplace(printing::mojom::kServiceName, - base::ASCIIToUTF16("PDF Compositor Service")); + (*services)[printing::mojom::kServiceName] = { + base::ASCIIToUTF16("PDF Compositor Service"), + content::SANDBOX_TYPE_UTILITY}; #endif }
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc index c79f5a6d..c32c0c7 100644 --- a/chrome/browser/chrome_service_worker_browsertest.cc +++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -274,7 +274,6 @@ " issuedRequests.forEach(function(data) {" " str += data + '\\n';" " });" - " window.domAutomationController.setAutomationId(0);" " window.domAutomationController.send(str);" "}" "navigator.serviceWorker.addEventListener("
diff --git a/chrome/browser/chromeos/login/users/default_user_image/default_user_images.cc b/chrome/browser/chromeos/login/users/default_user_image/default_user_images.cc index 41db15e..84b9b7c 100644 --- a/chrome/browser/chromeos/login/users/default_user_image/default_user_images.cc +++ b/chrome/browser/chromeos/login/users/default_user_image/default_user_images.cc
@@ -6,11 +6,13 @@ #include "base/logging.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/sys_info.h" +#include "base/values.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/chromeos/resources/grit/ui_chromeos_resources.h" @@ -261,5 +263,24 @@ return index + 6; } +std::unique_ptr<base::ListValue> GetAsDictionary() { + auto image_urls = base::MakeUnique<base::ListValue>(); + for (int i = default_user_image::kFirstDefaultImageIndex; + i < default_user_image::kDefaultImagesCount; ++i) { + auto image_data = base::MakeUnique<base::DictionaryValue>(); + image_data->SetString("url", default_user_image::GetDefaultImageUrl(i)); + image_data->SetString("author", + l10n_util::GetStringUTF16( + default_user_image::kDefaultImageAuthorIDs[i])); + image_data->SetString("website", + l10n_util::GetStringUTF16( + default_user_image::kDefaultImageWebsiteIDs[i])); + image_data->SetString("title", + default_user_image::GetDefaultImageDescription(i)); + image_urls->Append(std::move(image_data)); + } + return image_urls; +} + } // namespace default_user_image } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/default_user_image/default_user_images.h b/chrome/browser/chromeos/login/users/default_user_image/default_user_images.h index 517d7224..d0cf3f5 100644 --- a/chrome/browser/chromeos/login/users/default_user_image/default_user_images.h +++ b/chrome/browser/chromeos/login/users/default_user_image/default_user_images.h
@@ -7,11 +7,16 @@ #include <stddef.h> +#include <memory> #include <string> #include "base/strings/string16.h" #include "chromeos/chromeos_export.h" +namespace base { +class ListValue; +} + namespace gfx { class ImageSkia; } @@ -74,6 +79,10 @@ // Returns the histogram value corresponding to the given default image index. CHROMEOS_EXPORT int GetDefaultImageHistogramValue(int index); +// Returns a list of dictionary values with url, author, website, and title +// properties set for each default user image. +CHROMEOS_EXPORT std::unique_ptr<base::ListValue> GetAsDictionary(); + } // namespace default_user_image } // namespace chromeos
diff --git a/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc b/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc index 8d04694..e2b460ab 100644 --- a/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc +++ b/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc
@@ -47,8 +47,7 @@ AppInfoLaunchSource::NUM_LAUNCH_SOURCES); } - ShowAppInfoInNativeDialog(web_contents, GetAppInfoNativeDialogSize(), - profile, extension, on_complete); + ShowAppInfoInNativeDialog(web_contents, profile, extension, on_complete); return; // All done. }
diff --git a/chrome/browser/importer/external_process_importer_client.cc b/chrome/browser/importer/external_process_importer_client.cc index a0ff28f0..0bca7e1 100644 --- a/chrome/browser/importer/external_process_importer_client.cc +++ b/chrome/browser/importer/external_process_importer_client.cc
@@ -294,7 +294,7 @@ this, BrowserThread::GetTaskRunnerForThread(thread_id).get()); utility_process_host->SetName( l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_PROFILE_IMPORTER_NAME)); - utility_process_host->DisableSandbox(); + utility_process_host->SetSandboxType(content::SANDBOX_TYPE_NO_SANDBOX); #if defined(OS_MACOSX) base::EnvironmentMap env;
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc index 1897702a..40717139 100644 --- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc +++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -52,7 +52,6 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/download_test_observer.h" -#include "content/public/test/repeated_notification_observer.h" #include "content/public/test/test_navigation_observer.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/url_request/url_request_mock_http_job.h" @@ -83,6 +82,41 @@ GetNextDialog()->CancelAppModalDialog(); } +class RepeatedNotificationObserver : public content::NotificationObserver { + public: + explicit RepeatedNotificationObserver(int type, int count) + : num_outstanding_(count), running_(false) { + registrar_.Add(this, type, content::NotificationService::AllSources()); + } + + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override { + ASSERT_GT(num_outstanding_, 0); + if (!--num_outstanding_ && running_) { + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, + run_loop_.QuitClosure()); + } + } + + void Wait() { + if (num_outstanding_ <= 0) + return; + + running_ = true; + run_loop_.Run(); + running_ = false; + } + + private: + int num_outstanding_; + content::NotificationRegistrar registrar_; + bool running_; + base::RunLoop run_loop_; + + DISALLOW_COPY_AND_ASSIGN(RepeatedNotificationObserver); +}; + class TabRestoreServiceChangesObserver : public sessions::TabRestoreServiceObserver { public: @@ -271,7 +305,7 @@ browser(), embedded_test_server()->GetURL("/beforeunload.html"))); PrepareForDialog(browser()); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(CancelClose()); @@ -279,7 +313,7 @@ EXPECT_FALSE(browser_shutdown::IsTryingToQuit()); EXPECT_EQ(1, browser()->tab_strip_model()->count()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -295,7 +329,7 @@ browser(), embedded_test_server()->GetURL("/beforeunload.html"))); PrepareForDialog(browser()); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1); chrome::CloseAllBrowsersAndQuit(); chrome::CloseAllBrowsersAndQuit(); @@ -304,7 +338,7 @@ EXPECT_FALSE(browser_shutdown::IsTryingToQuit()); EXPECT_EQ(1, browser()->tab_strip_model()->count()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); chrome::CloseAllBrowsersAndQuit(); chrome::CloseAllBrowsersAndQuit(); @@ -324,7 +358,7 @@ ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIAboutURL))); PrepareForDialog(browser()); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(CancelClose()); @@ -341,7 +375,7 @@ ASSERT_NO_FATAL_FAILURE(AcceptClose()); navigation_observer.Wait(); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); chrome::CloseAllBrowsersAndQuit(); close_observer.Wait(); @@ -381,7 +415,7 @@ // Cancel shutdown on the first beforeunload event. { - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(CancelClose()); @@ -393,7 +427,7 @@ // Cancel shutdown on the second beforeunload event. { - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -405,7 +439,7 @@ EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count()); // Allow shutdown for both beforeunload events. - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -433,7 +467,7 @@ // the dialog is guaranteed to show. PrepareForDialog(browsers_[0]->tab_strip_model()->GetWebContentsAt(1)); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(CancelClose()); @@ -442,7 +476,7 @@ // All tabs should still be open. EXPECT_EQ(3, browsers_[0]->tab_strip_model()->count()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -469,7 +503,7 @@ // the dialog is guaranteed to show. PrepareForDialog(browsers_[1]); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(CancelClose()); @@ -480,7 +514,7 @@ EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count()); EXPECT_EQ(1, browsers_[2]->tab_strip_model()->count()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 3); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -515,7 +549,7 @@ PrepareForDialog( browsers_[0]->tab_strip_model()->GetWebContentsAt(kResposiveTabIndex)); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(CancelClose()); @@ -524,7 +558,7 @@ // All tabs should still be open. EXPECT_EQ(kTabCount, browsers_[0]->tab_strip_model()->count()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); // Quit, this time accepting close confirmation dialog. @@ -563,7 +597,7 @@ // the dialog is guaranteed to show. PrepareForDialog(browsers_[kResposiveBrowserIndex]); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, kResposiveBrowserIndex + 1); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(CancelClose()); @@ -575,7 +609,7 @@ EXPECT_EQ(1, browsers_[i]->tab_strip_model()->count()); // Quit, this time accepting close confirmation dialog. - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, kBrowserCount); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -592,7 +626,7 @@ browsers_[0], embedded_test_server()->GetURL("/beforeunload.html"))); PrepareForDialog(browsers_[0]); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); chrome::CloseAllBrowsersAndQuit(); browsers_.push_back(CreateBrowser(browser()->profile())); @@ -611,7 +645,7 @@ browsers_[0], embedded_test_server()->GetURL("/beforeunload.html"))); PrepareForDialog(browsers_[0]); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2); chrome::CloseAllBrowsersAndQuit(); browsers_.push_back(CreateBrowser(browser()->profile())); @@ -626,7 +660,7 @@ EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count()); // Allow shutdown for both beforeunload dialogs. - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -648,7 +682,7 @@ PrepareForDialog(browsers_[0]); PrepareForDialog(browsers_[1]); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -674,7 +708,7 @@ PrepareForDialog(browsers_[0]); PrepareForDialog(browsers_[1]); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -693,7 +727,7 @@ EXPECT_EQ(2, browsers_[0]->tab_strip_model()->count()); EXPECT_EQ(2, browsers_[1]->tab_strip_model()->count()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); chrome::CloseAllBrowsersAndQuit(); ASSERT_NO_FATAL_FAILURE(AcceptClose()); @@ -818,7 +852,7 @@ browsers_[0], embedded_test_server()->GetURL("/beforeunload.html"))); PrepareForDialog(browsers_[0]); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1); chrome::CloseAllBrowsersAndQuit(); @@ -834,7 +868,7 @@ EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count()); EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); chrome::CloseAllBrowsersAndQuit(); browsers_[1]->tab_strip_model()->CloseAllTabs(); @@ -853,7 +887,7 @@ browsers_[0], embedded_test_server()->GetURL("/beforeunload.html"))); PrepareForDialog(browsers_[0]); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2); chrome::CloseAllBrowsersAndQuit(); @@ -869,7 +903,7 @@ EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count()); EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); chrome::CloseAllBrowsersAndQuit(); ASSERT_FALSE(browsers_[1]->ShouldCloseWindow()); @@ -892,7 +926,7 @@ PrepareForDialog(browsers_[0]); PrepareForDialog(browsers_[1]); - content::RepeatedNotificationObserver cancel_observer( + RepeatedNotificationObserver cancel_observer( chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1); chrome::CloseAllBrowsersAndQuit(); @@ -903,7 +937,7 @@ EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count()); EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); chrome::CloseAllBrowsersAndQuit(); ASSERT_FALSE(browsers_[0]->ShouldCloseWindow()); @@ -953,7 +987,7 @@ SetDownloadPathForProfile(browser()->profile()); ASSERT_NO_FATAL_FAILURE(CreateStalledDownload(browser())); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); TestBrowserCloseManager::AttemptClose( @@ -1002,7 +1036,7 @@ browser()->profile())->NonMaliciousInProgressCount()); // Close the browser with no user action. - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); TestBrowserCloseManager::AttemptClose( TestBrowserCloseManager::NO_USER_CHOICE); @@ -1026,7 +1060,7 @@ EXPECT_EQ(GURL(chrome::kChromeUIDownloadsURL), browser()->tab_strip_model()->GetActiveWebContents()->GetURL()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); TestBrowserCloseManager::AttemptClose( @@ -1048,7 +1082,7 @@ SetDownloadPathForProfile(otr_profile); Browser* otr_browser = CreateBrowser(otr_profile); { - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); browser()->window()->Close(); close_observer.Wait(); @@ -1063,7 +1097,7 @@ EXPECT_EQ(GURL(chrome::kChromeUIDownloadsURL), otr_browser->tab_strip_model()->GetActiveWebContents()->GetURL()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); TestBrowserCloseManager::AttemptClose( @@ -1097,7 +1131,7 @@ ASSERT_EQ(0, num_downloads_blocking); { - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); otr_browser->window()->Close(); close_observer.Wait(); @@ -1109,7 +1143,7 @@ ASSERT_EQ(1, num_downloads_blocking); { - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); TestBrowserCloseManager::AttemptClose( TestBrowserCloseManager::USER_CHOICE_USER_ALLOWS_CLOSE); @@ -1147,7 +1181,7 @@ SetDownloadPathForProfile(other_profile); ASSERT_NO_FATAL_FAILURE(CreateStalledDownload(browser())); { - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); browser()->window()->Close(); close_observer.Wait(); @@ -1168,7 +1202,7 @@ other_profile_browser->tab_strip_model()->GetActiveWebContents() ->GetURL()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 2); TestBrowserCloseManager::AttemptClose( TestBrowserCloseManager::USER_CHOICE_USER_ALLOWS_CLOSE); @@ -1200,7 +1234,7 @@ cancel_observer.Wait(); EXPECT_FALSE(browser_shutdown::IsTryingToQuit()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); TestBrowserCloseManager::AttemptClose( TestBrowserCloseManager::USER_CHOICE_USER_ALLOWS_CLOSE); @@ -1246,7 +1280,7 @@ std::unique_ptr<ScopedKeepAlive> tmp_keep_alive; Profile* profile = browser()->profile(); { - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); tmp_keep_alive.reset(new ScopedKeepAlive(KeepAliveOrigin::PANEL_VIEW, KeepAliveRestartOption::DISABLED)); @@ -1263,7 +1297,7 @@ new_browser_observer.WaitForSingleNewBrowser(); tmp_keep_alive.reset(); EXPECT_FALSE(IsBackgroundModeSuspended()); - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); // Background mode should not be suspended when quitting. @@ -1278,7 +1312,7 @@ // background mode. IN_PROC_BROWSER_TEST_P(BrowserCloseManagerWithBackgroundModeBrowserTest, DISABLED_CloseSingleBrowserWithBackgroundMode) { - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); EXPECT_FALSE(IsBackgroundModeSuspended()); browser()->window()->Close(); @@ -1292,7 +1326,7 @@ // background mode but does not cause Chrome to quit. IN_PROC_BROWSER_TEST_P(BrowserCloseManagerWithBackgroundModeBrowserTest, DISABLED_CloseAllBrowsersWithNoOpenBrowsersWithBackgroundMode) { - content::RepeatedNotificationObserver close_observer( + RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); EXPECT_FALSE(IsBackgroundModeSuspended()); ScopedKeepAlive tmp_keep_alive(KeepAliveOrigin::PANEL_VIEW,
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc index 23e8ba8..8e1a788d 100644 --- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc +++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -982,7 +982,8 @@ return content::PREVIEWS_OFF; // If the allowed previews are limited, ensure we honor those limits. - if (previews_state != content::PREVIEWS_OFF && + if (previews_to_allow != content::PREVIEWS_UNSPECIFIED && + previews_state != content::PREVIEWS_OFF && previews_state != content::PREVIEWS_NO_TRANSFORM) { previews_state = previews_state & previews_to_allow; // If no valid previews are left, set the state explictly to PREVIEWS_OFF.
diff --git a/chrome/browser/media/android/router/media_router_dialog_controller_android.cc b/chrome/browser/media/android/router/media_router_dialog_controller_android.cc index 08983f6..59db7ee 100644 --- a/chrome/browser/media/android/router/media_router_dialog_controller_android.cc +++ b/chrome/browser/media/android/router/media_router_dialog_controller_android.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/media/router/media_router.h" #include "chrome/browser/media/router/media_router_factory.h" #include "chrome/browser/media/router/presentation_request.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/common/media_router/media_source.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" @@ -21,10 +22,6 @@ #include "device/vr/features/features.h" #include "jni/ChromeMediaRouterDialogController_jni.h" -#if BUILDFLAG(ENABLE_VR) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) - DEFINE_WEB_CONTENTS_USER_DATA_KEY( media_router::MediaRouterDialogControllerAndroid); @@ -148,13 +145,11 @@ } void MediaRouterDialogControllerAndroid::CreateMediaRouterDialog() { -#if BUILDFLAG(ENABLE_VR) // TODO(crbug.com/736568): Re-enable dialog in VR. - if (vr_shell::VrTabHelper::IsInVr(initiator())) { + if (vr::VrTabHelper::IsInVr(initiator())) { CancelPresentationRequest(); return; } -#endif // BUILDFLAG(ENABLE_VR) JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc index 4d7bb356..16243b2f 100644 --- a/chrome/browser/media/encrypted_media_browsertest.cc +++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -308,6 +308,11 @@ scoped_feature_list_.InitWithFeatures( {media::kExternalClearKeyForTesting}, {}); } + } else { + if (cdm_host_type == CdmHostType::kMojo) { + scoped_feature_list_.InitWithFeatures( + {media::kMojoCdm, media::kSupportExperimentalCdmInterface}, {}); + } } #endif // BUILDFLAG(ENABLE_PEPPER_CDMS) }
diff --git a/chrome/browser/media/media_engagement_contents_observer.cc b/chrome/browser/media/media_engagement_contents_observer.cc index 99ca935..20ab226 100644 --- a/chrome/browser/media/media_engagement_contents_observer.cc +++ b/chrome/browser/media/media_engagement_contents_observer.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/media/media_engagement_contents_observer.h" +#include "build/build_config.h" #include "chrome/browser/media/media_engagement_service.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h" @@ -62,6 +63,7 @@ if (committed_origin_.unique()) return; + service_->RecordVisit(committed_origin_.GetURL()); } @@ -146,8 +148,12 @@ // Do not record significant playback if the tab did not make // a sound in the last two seconds. +#if defined(OS_ANDROID) +// Skipping WasRecentlyAudible check on Android (not available). +#else if (!web_contents()->WasRecentlyAudible()) return; +#endif significant_playback_recorded_ = true;
diff --git a/chrome/browser/media/media_engagement_contents_observer_unittest.cc b/chrome/browser/media/media_engagement_contents_observer_unittest.cc index 3e3bebf..a66b955 100644 --- a/chrome/browser/media/media_engagement_contents_observer_unittest.cc +++ b/chrome/browser/media/media_engagement_contents_observer_unittest.cc
@@ -6,6 +6,7 @@ #include "base/test/scoped_feature_list.h" #include "base/timer/mock_timer.h" +#include "build/build_config.h" #include "chrome/browser/media/media_engagement_score.h" #include "chrome/browser/media/media_engagement_service.h" #include "chrome/browser/media/media_engagement_service_factory.h" @@ -127,8 +128,12 @@ } void SimulateAudible() { +#if defined(OS_ANDROID) +// WasRecentlyAudible is not available on Android. +#else content::WebContentsTester::For(web_contents()) ->SetWasRecentlyAudible(true); +#endif } void SimulateInaudible() {
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc index c142faad..f2be4a8 100644 --- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc +++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -21,9 +21,6 @@ #include "chrome/browser/chrome_browser_main.h" #include "chrome/browser/mac/bluetooth_utility.h" #include "chrome/browser/shell_integration.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_list.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "components/flags_ui/pref_service_flags_storage.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_switches.h" @@ -549,17 +546,7 @@ is_screen_observer_ = true; #if !defined(OS_ANDROID) - const BrowserList* browser_list = BrowserList::GetInstance(); - - auto first_browser = browser_list->begin(); - if (first_browser != browser_list->end()) { - TabStripModel* tab_strip = (*first_browser)->tab_strip_model(); - DCHECK(tab_strip); - // In case this code becomes reachable with empty tab strip, - // startup_metric_utils::SetNonBrowserUIDisplayed() should be used. - DCHECK(!tab_strip->empty()); - metrics::BeginFirstWebContentsProfiling(); - } + metrics::BeginFirstWebContentsProfiling(); metrics::TabUsageRecorder::InitializeIfNeeded(); #endif // !defined(OS_ANDROID) }
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc index fae150e..d3643a0 100644 --- a/chrome/browser/net/chrome_network_delegate.cc +++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -64,7 +64,6 @@ #if defined(OS_ANDROID) #include "chrome/browser/io_thread.h" -#include "chrome/browser/precache/precache_util.h" #endif #if defined(OS_CHROMEOS) @@ -377,12 +376,6 @@ // of redirected requests. RecordNetworkErrorHistograms(request, net_error); - if (net_error == net::OK) { -#if defined(OS_ANDROID) - precache::UpdatePrecacheMetricsAndState(request, profile_); -#endif // defined(OS_ANDROID) - } - extensions_delegate_->OnCompleted(request, started, net_error); if (domain_reliability_monitor_) domain_reliability_monitor_->OnCompleted(request, started);
diff --git a/chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc b/chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc index 4e49c10..7c26946 100644 --- a/chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc +++ b/chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc
@@ -8,6 +8,7 @@ #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/history/core/browser/top_sites.h" #include "components/ntp_tiles/most_visited_sites.h" #include "components/ntp_tiles/ntp_tile.h" #include "testing/gmock/include/gmock/gmock.h" @@ -127,4 +128,26 @@ TileSource::TOP_SITES)))); } +// Tests usage of MostVisitedSites mimicking Chrome Home, where an observer is +// installed early and once and navigations follow afterwards. +IN_PROC_BROWSER_TEST_F(NTPTilesTest, NavigateAfterSettingObserver) { + ASSERT_TRUE(embedded_test_server()->Start()); + const GURL page_url = embedded_test_server()->GetURL("/simple.html"); + + // Register the observer before doing the navigation. + MostVisitedSitesWaiter waiter; + most_visited_sites_->SetMostVisitedURLsObserver(&waiter, /*num_sites=*/8); + + ui_test_utils::NavigateToURLWithDisposition( + browser(), page_url, WindowOpenDisposition::CURRENT_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + + // TODO(crbug.com/741431): When Refresh calls SyncWithHistory() for signed + // out users, replace the call below with most_visited_sites_->Refresh(). + most_visited_sites_->top_sites()->SyncWithHistory(); + NTPTilesVector tiles = waiter.WaitForTiles(); + EXPECT_THAT(tiles, Contains(MatchesTile("OK", page_url.spec().c_str(), + TileSource::TOP_SITES))); +} + } // namespace ntp_tiles
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index c3446297..f93d6e5 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -26,6 +26,7 @@ #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/ui/autofill/password_generation_popup_controller_impl.h" #include "chrome/browser/ui/passwords/passwords_client_ui_delegate.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/common/channel_info.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" @@ -88,11 +89,6 @@ #include "extensions/common/constants.h" #endif -#include "device/vr/features/features.h" -#if BUILDFLAG(ENABLE_VR) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) - using password_manager::ContentPasswordManagerDriverFactory; using password_manager::PasswordManagerInternalsService; using password_manager::PasswordManagerMetricsRecorder; @@ -216,12 +212,10 @@ entry->GetURL().host_piece() != chrome::kChromeUIChromeSigninHost; } -#if BUILDFLAG(ENABLE_VR) // The password manager is disabled while VR (virtual reality) is being used, // as the use of conventional UI elements might harm the user experience in // VR. - is_enabled = is_enabled && !vr_shell::VrTabHelper::IsInVr(web_contents()); -#endif // BUILDFLAG(ENABLE_VR) + is_enabled = is_enabled && !vr::VrTabHelper::IsInVr(web_contents()); if (log_manager_->IsLoggingActive()) { password_manager::BrowserSavePasswordProgressLogger logger(
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc index f2850063..bc068fc 100644 --- a/chrome/browser/permissions/permission_manager.cc +++ b/chrome/browser/permissions/permission_manager.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/storage/durable_storage_permission_context.h" #include "chrome/browser/tab_contents/tab_util.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/common/features.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "content/public/browser/browser_thread.h" @@ -34,10 +35,6 @@ #include "device/vr/features/features.h" #include "ppapi/features/features.h" -#if BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) - #if BUILDFLAG(ENABLE_PLUGINS) #include "chrome/browser/plugins/flash_permission_context.h" #endif @@ -329,13 +326,11 @@ content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); -#if BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) - if (vr_shell::VrTabHelper::IsInVr(web_contents)) { + if (vr::VrTabHelper::IsInVr(web_contents)) { callback.Run( std::vector<ContentSetting>(permissions.size(), CONTENT_SETTING_BLOCK)); return kNoPendingOperation; } -#endif // BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
diff --git a/chrome/browser/permissions/permission_manager_unittest.cc b/chrome/browser/permissions/permission_manager_unittest.cc index b5911d6b..212d1af 100644 --- a/chrome/browser/permissions/permission_manager_unittest.cc +++ b/chrome/browser/permissions/permission_manager_unittest.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/permissions/permission_request_manager.h" #include "chrome/browser/permissions/permission_result.h" #include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -19,18 +20,12 @@ #include "device/vr/features/features.h" #include "testing/gtest/include/gtest/gtest.h" -#if BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) - using blink::mojom::PermissionStatus; using content::PermissionType; namespace { -#if BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) int kNoPendingOperation = -1; -#endif // BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) class PermissionManagerTestingProfile final : public TestingProfile { public: @@ -406,10 +401,9 @@ GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id); } -#if BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) TEST_F(PermissionManagerTest, SuppressPermissionRequests) { content::WebContents* contents = web_contents(); - vr_shell::VrTabHelper::CreateForWebContents(contents); + vr::VrTabHelper::CreateForWebContents(contents); NavigateAndCommit(url()); SetPermission(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW); @@ -420,8 +414,7 @@ EXPECT_TRUE(callback_called()); EXPECT_EQ(PermissionStatus::GRANTED, callback_result()); - vr_shell::VrTabHelper* vr_tab_helper = - vr_shell::VrTabHelper::FromWebContents(contents); + vr::VrTabHelper* vr_tab_helper = vr::VrTabHelper::FromWebContents(contents); vr_tab_helper->SetIsInVr(true); EXPECT_EQ( kNoPendingOperation, @@ -440,7 +433,6 @@ EXPECT_TRUE(callback_called()); EXPECT_EQ(PermissionStatus::GRANTED, callback_result()); } -#endif // BUILDFLAG(ENABLE_VR) && defined(OS_ANDROID) TEST_F(PermissionManagerTest, PermissionIgnoredCleanup) { content::WebContents* contents = web_contents();
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc index ee16133..d3e9c258 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -137,6 +137,17 @@ callback.Run(client->dm_token(), client->client_id()); } +void UserPolicySigninService::GoogleSigninSucceeded( + const std::string& account_id, + const std::string& username) { + if (!oauth2_token_service_->RefreshTokenIsAvailable(account_id)) + return; + + // ProfileOAuth2TokenService now has a refresh token for the primary account + // so initialize the UserCloudPolicyManager. + TryInitializeForSignedInUser(); +} + void UserPolicySigninService::OnRefreshTokenAvailable( const std::string& account_id) { // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is @@ -145,6 +156,20 @@ FROM_HERE_WITH_EXPLICIT_FUNCTION( "422460 UserPolicySigninService::OnRefreshTokenAvailable")); + // Ignore OAuth tokens for any account but the primary one. + if (account_id != signin_manager()->GetAuthenticatedAccountId()) + return; + + // ProfileOAuth2TokenService now has a refresh token for the primary account + // so initialize the UserCloudPolicyManager. + TryInitializeForSignedInUser(); +} + +void UserPolicySigninService::TryInitializeForSignedInUser() { + DCHECK(signin_manager()->IsAuthenticated()); + DCHECK(oauth2_token_service_->RefreshTokenIsAvailable( + signin_manager()->GetAuthenticatedAccountId())); + // If using a TestingProfile with no UserCloudPolicyManager, skip // initialization. if (!policy_manager()) { @@ -152,12 +177,6 @@ return; } - // Ignore OAuth tokens for any account but the primary one. - if (account_id != signin_manager()->GetAuthenticatedAccountId()) - return; - - // ProfileOAuth2TokenService now has a refresh token so initialize the - // UserCloudPolicyManager. InitializeForSignedInUser( signin_manager()->GetAuthenticatedAccountInfo().email, profile_->GetRequestContext());
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.h b/chrome/browser/policy/cloud/user_policy_signin_service.h index 7cd00098..819d29a0 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service.h +++ b/chrome/browser/policy/cloud/user_policy_signin_service.h
@@ -60,6 +60,11 @@ const std::string& account_id, const PolicyRegistrationCallback& callback); + // SigninManagerBase::Observer implementation: + // UserPolicySigninService is already an observer of SigninManagerBase. + void GoogleSigninSucceeded(const std::string& account_id, + const std::string& username) override; + // OAuth2TokenService::Observer implementation: void OnRefreshTokenAvailable(const std::string& account_id) override; @@ -92,6 +97,11 @@ // cloud policy. void ProhibitSignoutIfNeeded(); + // Helper method that attempts calls |InitializeForSignedInUser| only if + // |policy_manager| is not-nul. Expects that there is a refresh token for + // the primary account. + void TryInitializeForSignedInUser(); + // Invoked when a policy registration request is complete. void CallPolicyRegistrationCallback(std::unique_ptr<CloudPolicyClient> client, PolicyRegistrationCallback callback);
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc index d4fa2fa..aea94a0 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -400,9 +400,39 @@ ASSERT_FALSE(manager_->core()->service()); } - // TODO(joaodasilva): these tests rely on issuing the OAuth2 login refresh - // token after signin. Revisit this after figuring how to handle that on - // Android. +#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) +TEST_F(UserPolicySigninServiceTest, InitRefreshTokenAvailableBeforeSignin) { + // Make sure user is not signed in. + ASSERT_FALSE( + SigninManagerFactory::GetForProfile(profile_.get())->IsAuthenticated()); + + // No oauth access token yet, so client registration should be deferred. + ASSERT_FALSE(IsRequestActive()); + + // Make oauth token available. + std::string account_id = AccountTrackerService::PickAccountIdForAccount( + profile_.get()->GetPrefs(), kTestGaiaId, kTestUser); + GetTokenService()->UpdateCredentials(account_id, "oauth_login_refresh_token"); + + // Not ssigned in yet, so client registration should be deferred. + ASSERT_FALSE(IsRequestActive()); + + // Sign in to Chrome. + signin_manager_->SignIn(kTestGaiaId, kTestUser, ""); + + // Complete initialization of the store. + mock_store_->NotifyStoreLoaded(); + + // Client registration should be in progress since we now have an oauth token + // for the authenticated account id. + EXPECT_EQ(mock_store_->signin_username(), kTestUser); + ASSERT_TRUE(IsRequestActive()); +} +#endif // !defined(OS_ANDROID) && !defined(OS_CHROMEOS) + +// TODO(joaodasilva): these tests rely on issuing the OAuth2 login refresh +// token after signin. Revisit this after figuring how to handle that on +// Android. #if !defined(OS_ANDROID) TEST_F(UserPolicySigninServiceSignedInTest, InitWhileSignedIn) {
diff --git a/chrome/browser/printing/background_printing_manager.cc b/chrome/browser/printing/background_printing_manager.cc index 330ecb9..fd10907 100644 --- a/chrome/browser/printing/background_printing_manager.cc +++ b/chrome/browser/printing/background_printing_manager.cc
@@ -113,6 +113,11 @@ } } +void BackgroundPrintingManager::OnPrintRequestCancelled( + WebContents* preview_contents) { + DeletePreviewContents(preview_contents); +} + void BackgroundPrintingManager::DeletePreviewContents( WebContents* preview_contents) { auto i = printing_contents_map_.find(preview_contents);
diff --git a/chrome/browser/printing/background_printing_manager.h b/chrome/browser/printing/background_printing_manager.h index ff0bd1e..ea211ad 100644 --- a/chrome/browser/printing/background_printing_manager.h +++ b/chrome/browser/printing/background_printing_manager.h
@@ -48,6 +48,8 @@ void DeletePreviewContentsForBrowserContext( content::BrowserContext* browser_context); + void OnPrintRequestCancelled(content::WebContents* preview_dialog); + private: // content::NotificationObserver overrides: void Observe(int type,
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc index e1deb6d3..3f9ca09b 100644 --- a/chrome/browser/push_messaging/push_messaging_browsertest.cc +++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -56,6 +56,7 @@ #include "content/public/browser/notification_service.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "content/public/common/push_subscription_options.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/browsing_data_remover_test_util.h" @@ -108,8 +109,8 @@ const std::string& registration_id, const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth, - content::PushRegistrationStatus status) { - EXPECT_EQ(content::PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE, + content::mojom::PushRegistrationStatus status) { + EXPECT_EQ(content::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE, status); done_callback.Run(); } @@ -1070,7 +1071,7 @@ 0 /* SERVICE_WORKER_OK */, 1); histogram_tester_.ExpectUniqueSample( "PushMessaging.DeliveryStatus", - content::PUSH_DELIVERY_STATUS_SUCCESS, 1); + static_cast<int>(content::mojom::PushDeliveryStatus::SUCCESS), 1); } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventOnShutdown) { @@ -1172,13 +1173,16 @@ "PushMessaging.DeliveryStatus.ServiceWorkerEvent", 0); histogram_tester_.ExpectUniqueSample( "PushMessaging.DeliveryStatus", - content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER, 1); + static_cast<int>(content::mojom::PushDeliveryStatus::NO_SERVICE_WORKER), + 1); // Missing Service Workers should trigger an automatic unsubscription attempt. EXPECT_EQ(app_id, gcm_driver_->last_deletetoken_app_id()); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_DELIVERY_NO_SERVICE_WORKER, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::DELIVERY_NO_SERVICE_WORKER), + 1); // |app_identifier| should no longer be stored in prefs. PushMessagingAppIdentifier stored_app_identifier = @@ -1202,7 +1206,9 @@ EXPECT_EQ("unsubscribe result: true", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 1); gcm::IncomingMessage message; message.sender_id = GetTestApplicationServerKey(); @@ -1221,13 +1227,15 @@ "PushMessaging.DeliveryStatus.ServiceWorkerEvent", 0); histogram_tester_.ExpectUniqueSample( "PushMessaging.DeliveryStatus", - content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID, 1); + static_cast<int>(content::mojom::PushDeliveryStatus::UNKNOWN_APP_ID), 1); // Missing subscriptions should trigger an automatic unsubscription attempt. EXPECT_EQ(app_identifier.app_id(), gcm_driver_->last_deletetoken_app_id()); histogram_tester_.ExpectBucketCount( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_DELIVERY_UNKNOWN_APP_ID, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::DELIVERY_UNKNOWN_APP_ID), + 1); } // Tests receiving messages for an origin that does not have permission, but @@ -1270,7 +1278,8 @@ "PushMessaging.DeliveryStatus.ServiceWorkerEvent", 0); histogram_tester_.ExpectUniqueSample( "PushMessaging.DeliveryStatus", - content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED, 1); + static_cast<int>(content::mojom::PushDeliveryStatus::PERMISSION_DENIED), + 1); // Missing permission should trigger an automatic unsubscription attempt. EXPECT_EQ(app_identifier.app_id(), gcm_driver_->last_deletetoken_app_id()); @@ -1283,7 +1292,9 @@ EXPECT_TRUE(app_identifier_afterwards.is_null()); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_DELIVERY_PERMISSION_DENIED, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::DELIVERY_PERMISSION_DENIED), + 1); } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, @@ -1613,14 +1624,18 @@ EXPECT_EQ("unsubscribe result: true", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 1); // Resolves false if there was no longer a subscription. ASSERT_TRUE(RunScript("unsubscribeStoredPushSubscription()", &script_result)); EXPECT_EQ("unsubscribe result: false", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 2); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 2); // TODO(johnme): Test that doesn't reject if there was a network error (should // deactivate subscription locally anyway). @@ -1641,7 +1656,9 @@ EXPECT_EQ("unsubscribe result: true", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 3); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 3); // Unsubscribing (with an existing reference to a PushSubscription), after // unregistering the Service Worker, should fail. @@ -1663,7 +1680,9 @@ // Unregistering should have triggered an automatic unsubscribe. histogram_tester_.ExpectBucketCount( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_SERVICE_WORKER_UNREGISTERED, 1); + static_cast<int>(content::mojom::PushUnregistrationReason:: + SERVICE_WORKER_UNREGISTERED), + 1); histogram_tester_.ExpectTotalCount("PushMessaging.UnregistrationReason", 4); // Now manual unsubscribe should return false. @@ -1687,14 +1706,18 @@ EXPECT_EQ("unsubscribe result: true", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 1); // Resolves false if there was no longer a subscription. ASSERT_TRUE(RunScript("unsubscribeStoredPushSubscription()", &script_result)); EXPECT_EQ("unsubscribe result: false", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 2); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 2); // Doesn't reject if there was a network error (deactivates subscription // locally anyway). @@ -1706,7 +1729,9 @@ EXPECT_EQ("unsubscribe result: true", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 3); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 3); ASSERT_TRUE(RunScript("hasSubscription()", &script_result)); EXPECT_EQ("false - not subscribed", script_result); @@ -1722,7 +1747,9 @@ EXPECT_EQ("unsubscribe result: true", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 4); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 4); // Unsubscribing (with an existing reference to a PushSubscription), after // replacing the Service Worker, actually still works, as the Service Worker @@ -1740,7 +1767,9 @@ EXPECT_EQ("unsubscribe result: true", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 5); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 5); // Unsubscribing (with an existing reference to a PushSubscription), after // unregistering the Service Worker, should fail. @@ -1764,7 +1793,9 @@ // Unregistering should have triggered an automatic unsubscribe. histogram_tester_.ExpectBucketCount( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_SERVICE_WORKER_UNREGISTERED, 1); + static_cast<int>(content::mojom::PushUnregistrationReason:: + SERVICE_WORKER_UNREGISTERED), + 1); histogram_tester_.ExpectTotalCount("PushMessaging.UnregistrationReason", 6); // Now manual unsubscribe should return false. @@ -1788,7 +1819,9 @@ EXPECT_EQ("unsubscribe result: true", script_result); histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::JAVASCRIPT_API), + 1); // Since the service is offline, the network request to GCM is still being // retried, so the app handler shouldn't have been unregistered yet. @@ -1820,7 +1853,9 @@ // This should have unregistered the push subscription. histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_SERVICE_WORKER_UNREGISTERED, 1); + static_cast<int>(content::mojom::PushUnregistrationReason:: + SERVICE_WORKER_UNREGISTERED), + 1); // We should not be able to look up the app id. GURL origin = https_server()->GetURL("/").GetOrigin(); @@ -1852,7 +1887,9 @@ // This should have unregistered the push subscription. histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_SERVICE_WORKER_DATABASE_WIPED, 1); + static_cast<int>(content::mojom::PushUnregistrationReason:: + SERVICE_WORKER_DATABASE_WIPED), + 1); // There should not be any subscriptions left. EXPECT_EQ(PushMessagingAppIdentifier::GetCount(GetBrowser()->profile()), 0u); @@ -1891,7 +1928,9 @@ // This should have unsubscribed the push subscription. histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_GET_SUBSCRIPTION_STORAGE_CORRUPT, 1); + static_cast<int>(content::mojom::PushUnregistrationReason:: + GET_SUBSCRIPTION_STORAGE_CORRUPT), + 1); // We should no longer be able to look up the app id. PushMessagingAppIdentifier app_identifier3 = PushMessagingAppIdentifier::FindByServiceWorker( @@ -1935,7 +1974,9 @@ // This should have unsubscribed the original push subscription. histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_SUBSCRIBE_STORAGE_CORRUPT, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::SUBSCRIBE_STORAGE_CORRUPT), + 1); // Looking up the app id should return a different id. PushMessagingAppIdentifier app_identifier3 = PushMessagingAppIdentifier::FindByServiceWorker( @@ -1975,7 +2016,9 @@ histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::PERMISSION_REVOKED), + 1); } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, @@ -2011,7 +2054,9 @@ histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::PERMISSION_REVOKED), + 1); } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, @@ -2047,7 +2092,9 @@ histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::PERMISSION_REVOKED), + 1); } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, @@ -2080,7 +2127,9 @@ histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::PERMISSION_REVOKED), + 1); } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, @@ -2116,7 +2165,9 @@ histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::PERMISSION_REVOKED), + 1); } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, @@ -2152,7 +2203,9 @@ histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::PERMISSION_REVOKED), + 1); } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, @@ -2273,7 +2326,9 @@ histogram_tester_.ExpectUniqueSample( "PushMessaging.UnregistrationReason", - content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED, 1); + static_cast<int>( + content::mojom::PushUnregistrationReason::PERMISSION_REVOKED), + 1); base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/push_messaging/push_messaging_notification_manager.cc b/chrome/browser/push_messaging/push_messaging_notification_manager.cc index b2df4e98..08e8ef7 100644 --- a/chrome/browser/push_messaging/push_messaging_notification_manager.cc +++ b/chrome/browser/push_messaging/push_messaging_notification_manager.cc
@@ -29,6 +29,7 @@ #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/common/notification_resources.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "content/public/common/url_constants.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom.h" @@ -54,9 +55,10 @@ using content::WebContents; namespace { -void RecordUserVisibleStatus(content::PushUserVisibleStatus status) { - UMA_HISTOGRAM_ENUMERATION("PushMessaging.UserVisibleStatus", status, - content::PUSH_USER_VISIBLE_STATUS_LAST + 1); +void RecordUserVisibleStatus(content::mojom::PushUserVisibleStatus status) { + UMA_HISTOGRAM_ENUMERATION( + "PushMessaging.UserVisibleStatus", status, + static_cast<int>(content::mojom::PushUserVisibleStatus::LAST) + 1); } content::StoragePartition* GetStoragePartition(Profile* profile, @@ -201,13 +203,13 @@ if (notification_needed && notification_shown) { RecordUserVisibleStatus( - content::PUSH_USER_VISIBLE_STATUS_REQUIRED_AND_SHOWN); + content::mojom::PushUserVisibleStatus::REQUIRED_AND_SHOWN); } else if (!notification_needed && !notification_shown) { RecordUserVisibleStatus( - content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN); + content::mojom::PushUserVisibleStatus::NOT_REQUIRED_AND_NOT_SHOWN); } else { RecordUserVisibleStatus( - content::PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_BUT_SHOWN); + content::mojom::PushUserVisibleStatus::NOT_REQUIRED_BUT_SHOWN); } message_handled_closure.Run(); @@ -255,14 +257,14 @@ // If the origin was allowed to issue a silent push, just return. if (silent_push_allowed) { - RecordUserVisibleStatus( - content::PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_USED_GRACE); + RecordUserVisibleStatus(content::mojom::PushUserVisibleStatus:: + REQUIRED_BUT_NOT_SHOWN_USED_GRACE); message_handled_closure.Run(); return; } - RecordUserVisibleStatus( - content::PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED); + RecordUserVisibleStatus(content::mojom::PushUserVisibleStatus:: + REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED); rappor::SampleDomainAndRegistryFromGURL( g_browser_process->rappor_service(), "PushMessaging.GenericNotificationShown.Origin", origin);
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc index b1fc84d..b2262302 100644 --- a/chrome/browser/push_messaging/push_messaging_service_impl.cc +++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -54,7 +54,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/child_process_host.h" #include "content/public/common/content_switches.h" -#include "content/public/common/push_messaging_status.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "content/public/common/push_subscription_options.h" #include "ui/base/l10n/l10n_util.h" @@ -82,14 +82,16 @@ "pushManager.subscribe({userVisibleOnly: true}) instead. See " "https://goo.gl/yqv4Q4 for more details."; -void RecordDeliveryStatus(content::PushDeliveryStatus status) { - UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus", status, - content::PUSH_DELIVERY_STATUS_LAST + 1); +void RecordDeliveryStatus(content::mojom::PushDeliveryStatus status) { + UMA_HISTOGRAM_ENUMERATION( + "PushMessaging.DeliveryStatus", status, + static_cast<int>(content::mojom::PushDeliveryStatus::LAST) + 1); } -void RecordUnsubscribeReason(content::PushUnregistrationReason reason) { - UMA_HISTOGRAM_ENUMERATION("PushMessaging.UnregistrationReason", reason, - content::PUSH_UNREGISTRATION_REASON_LAST + 1); +void RecordUnsubscribeReason(content::mojom::PushUnregistrationReason reason) { + UMA_HISTOGRAM_ENUMERATION( + "PushMessaging.UnregistrationReason", reason, + static_cast<int>(content::mojom::PushUnregistrationReason::LAST) + 1); } void RecordUnsubscribeGCMResult(gcm::GCMClient::Result result) { @@ -118,8 +120,9 @@ return blink::kWebPushPermissionStatusDenied; } -void UnregisterCallbackToClosure(const base::Closure& closure, - content::PushUnregistrationStatus status) { +void UnregisterCallbackToClosure( + const base::Closure& closure, + content::mojom::PushUnregistrationStatus status) { DCHECK(!closure.is_null()); closure.Run(); } @@ -227,7 +230,7 @@ // Delete all cached subscriptions, since they are now invalid. for (const auto& identifier : PushMessagingAppIdentifier::GetAll(profile_)) { RecordUnsubscribeReason( - content::PUSH_UNREGISTRATION_REASON_GCM_STORE_RESET); + content::mojom::PushUnregistrationReason::GCM_STORE_RESET); // Clear all the subscriptions in parallel, to reduce risk that shutdown // occurs before we finish clearing them. ClearPushSubscriptionId(profile_, identifier.origin(), @@ -274,15 +277,16 @@ DeliverMessageCallback(app_id, GURL::EmptyGURL(), -1 /* kInvalidServiceWorkerRegistrationId */, message, message_handled_closure, - content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID); + content::mojom::PushDeliveryStatus::UNKNOWN_APP_ID); return; } // Drop message and unregister if |origin| has lost push permission. if (!IsPermissionSet(app_identifier.origin())) { - DeliverMessageCallback(app_id, app_identifier.origin(), - app_identifier.service_worker_registration_id(), - message, message_handled_closure, - content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED); + DeliverMessageCallback( + app_id, app_identifier.origin(), + app_identifier.service_worker_registration_id(), message, + message_handled_closure, + content::mojom::PushDeliveryStatus::PERMISSION_DENIED); return; } @@ -320,7 +324,7 @@ int64_t service_worker_registration_id, const gcm::IncomingMessage& message, const base::Closure& message_handled_closure, - content::PushDeliveryStatus status) { + content::mojom::PushDeliveryStatus status) { DCHECK_GE(in_flight_message_deliveries_.count(app_id), 1u); RecordDeliveryStatus(status); @@ -333,8 +337,8 @@ base::ScopedClosureRunner completion_closure_runner(completion_closure); // A reason to automatically unsubscribe. UNKNOWN means do not unsubscribe. - content::PushUnregistrationReason unsubscribe_reason = - content::PUSH_UNREGISTRATION_REASON_UNKNOWN; + content::mojom::PushUnregistrationReason unsubscribe_reason = + content::mojom::PushUnregistrationReason::UNKNOWN; // TODO(mvanouwerkerk): Show a warning in the developer console of the // Service Worker corresponding to app_id (and/or on an internals page). @@ -344,9 +348,9 @@ // the Service Worker JavaScript, even if the website's event handler failed // (to prevent sites deliberately failing in order to avoid having to show // notifications). - case content::PUSH_DELIVERY_STATUS_SUCCESS: - case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: - case content::PUSH_DELIVERY_STATUS_TIMEOUT: + case content::mojom::PushDeliveryStatus::SUCCESS: + case content::mojom::PushDeliveryStatus::EVENT_WAITUNTIL_REJECTED: + case content::mojom::PushDeliveryStatus::TIMEOUT: // Only enforce the user visible requirements if this is currently running // as the delivery callback for the last in-flight message, and silent // push has not been enabled through a command line flag. @@ -358,24 +362,24 @@ completion_closure_runner.Release()); } break; - case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: + case content::mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR: // Do nothing, and hope the error is transient. break; - case content::PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID: + case content::mojom::PushDeliveryStatus::UNKNOWN_APP_ID: unsubscribe_reason = - content::PUSH_UNREGISTRATION_REASON_DELIVERY_UNKNOWN_APP_ID; + content::mojom::PushUnregistrationReason::DELIVERY_UNKNOWN_APP_ID; break; - case content::PUSH_DELIVERY_STATUS_PERMISSION_DENIED: + case content::mojom::PushDeliveryStatus::PERMISSION_DENIED: unsubscribe_reason = - content::PUSH_UNREGISTRATION_REASON_DELIVERY_PERMISSION_DENIED; + content::mojom::PushUnregistrationReason::DELIVERY_PERMISSION_DENIED; break; - case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: + case content::mojom::PushDeliveryStatus::NO_SERVICE_WORKER: unsubscribe_reason = - content::PUSH_UNREGISTRATION_REASON_DELIVERY_NO_SERVICE_WORKER; + content::mojom::PushUnregistrationReason::DELIVERY_NO_SERVICE_WORKER; break; } - if (unsubscribe_reason != content::PUSH_UNREGISTRATION_REASON_UNKNOWN) { + if (unsubscribe_reason != content::mojom::PushUnregistrationReason::UNKNOWN) { PushMessagingAppIdentifier app_identifier = PushMessagingAppIdentifier::FindByAppId(profile_, app_id); UnsubscribeInternal( @@ -459,8 +463,8 @@ if (push_subscription_count_ + pending_push_subscription_count_ >= kMaxRegistrations) { - SubscribeEndWithError(callback, - content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED); + SubscribeEndWithError( + callback, content::mojom::PushRegistrationStatus::LIMIT_REACHED); return; } @@ -475,8 +479,8 @@ web_contents->GetMainFrame()->AddMessageToConsole( content::CONSOLE_MESSAGE_LEVEL_ERROR, kSilentPushUnsupportedMessage); - SubscribeEndWithError(callback, - content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); + SubscribeEndWithError( + callback, content::mojom::PushRegistrationStatus::PERMISSION_DENIED); return; } @@ -500,8 +504,9 @@ if (push_subscription_count_ + pending_push_subscription_count_ >= kMaxRegistrations) { - SubscribeEndWithError(register_callback, - content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED); + SubscribeEndWithError( + register_callback, + content::mojom::PushRegistrationStatus::LIMIT_REACHED); return; } @@ -509,8 +514,9 @@ GetPermissionStatus(requesting_origin, options.user_visible_only); if (permission_status != blink::kWebPushPermissionStatusGranted) { - SubscribeEndWithError(register_callback, - content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); + SubscribeEndWithError( + register_callback, + content::mojom::PushRegistrationStatus::PERMISSION_DENIED); return; } @@ -544,8 +550,9 @@ const RegisterCallback& register_callback, ContentSetting content_setting) { if (content_setting != CONTENT_SETTING_ALLOW) { - SubscribeEndWithError(register_callback, - content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); + SubscribeEndWithError( + register_callback, + content::mojom::PushRegistrationStatus::PERMISSION_DENIED); return; } @@ -565,13 +572,13 @@ const std::string& subscription_id, const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth, - content::PushRegistrationStatus status) { + content::mojom::PushRegistrationStatus status) { callback.Run(subscription_id, p256dh, auth, status); } void PushMessagingServiceImpl::SubscribeEndWithError( const RegisterCallback& callback, - content::PushRegistrationStatus status) { + content::mojom::PushRegistrationStatus status) { SubscribeEnd(callback, std::string() /* subscription_id */, std::vector<uint8_t>() /* p256dh */, std::vector<uint8_t>() /* auth */, status); @@ -585,8 +592,8 @@ InstanceID::Result result) { DecreasePushSubscriptionCount(1, true /* was_pending */); - content::PushRegistrationStatus status = - content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR; + content::mojom::PushRegistrationStatus status = + content::mojom::PushRegistrationStatus::SERVICE_ERROR; switch (result) { case InstanceID::SUCCESS: @@ -606,10 +613,10 @@ case InstanceID::UNKNOWN_ERROR: DLOG(ERROR) << "Push messaging subscription failed; InstanceID::Result = " << result; - status = content::PUSH_REGISTRATION_STATUS_SERVICE_ERROR; + status = content::mojom::PushRegistrationStatus::SERVICE_ERROR; break; case InstanceID::NETWORK_ERROR: - status = content::PUSH_REGISTRATION_STATUS_NETWORK_ERROR; + status = content::mojom::PushRegistrationStatus::NETWORK_ERROR; break; } @@ -624,7 +631,8 @@ const std::string& auth_secret) { if (p256dh.empty()) { SubscribeEndWithError( - callback, content::PUSH_REGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE); + callback, + content::mojom::PushRegistrationStatus::PUBLIC_KEY_UNAVAILABLE); return; } @@ -632,10 +640,11 @@ IncreasePushSubscriptionCount(1, false /* is_pending */); - SubscribeEnd(callback, subscription_id, - std::vector<uint8_t>(p256dh.begin(), p256dh.end()), - std::vector<uint8_t>(auth_secret.begin(), auth_secret.end()), - content::PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE); + SubscribeEnd( + callback, subscription_id, + std::vector<uint8_t>(p256dh.begin(), p256dh.end()), + std::vector<uint8_t>(auth_secret.begin(), auth_secret.end()), + content::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE); } // GetSubscriptionInfo methods ------------------------------------------------- @@ -701,7 +710,7 @@ // Unsubscribe methods --------------------------------------------------------- void PushMessagingServiceImpl::Unsubscribe( - content::PushUnregistrationReason reason, + content::mojom::PushUnregistrationReason reason, const GURL& requesting_origin, int64_t service_worker_registration_id, const std::string& sender_id, @@ -717,7 +726,7 @@ } void PushMessagingServiceImpl::UnsubscribeInternal( - content::PushUnregistrationReason reason, + content::mojom::PushUnregistrationReason reason, const GURL& origin, int64_t service_worker_registration_id, const std::string& app_id, @@ -745,7 +754,7 @@ } void PushMessagingServiceImpl::DidClearPushSubscriptionId( - content::PushUnregistrationReason reason, + content::mojom::PushUnregistrationReason reason, const std::string& app_id, const std::string& sender_id, const UnregisterCallback& callback) { @@ -753,7 +762,7 @@ // Without an |app_id|, we can neither delete the subscription from the // PushMessagingAppIdentifier map, nor unsubscribe with the GCM Driver. callback.Run( - content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); + content::mojom::PushUnregistrationStatus::SUCCESS_WAS_NOT_REGISTERED); return; } @@ -776,8 +785,9 @@ // eventually reach GCM servers even if this particular attempt fails. callback.Run( was_subscribed - ? content::PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED - : content::PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED); + ? content::mojom::PushUnregistrationStatus::SUCCESS_UNREGISTERED + : content::mojom::PushUnregistrationStatus:: + SUCCESS_WAS_NOT_REGISTERED); if (PushMessagingAppIdentifier::UseInstanceID(app_id)) { GetInstanceIDDriver()->GetInstanceID(app_id)->DeleteID( @@ -859,8 +869,8 @@ // Android from GCM, as that requires a sender_id. (Ideally we'd fetch it // from the SWDB in some "before_unregistered" SWObserver event.) UnsubscribeInternal( - content::PUSH_UNREGISTRATION_REASON_SERVICE_WORKER_UNREGISTERED, origin, - service_worker_registration_id, app_identifier.app_id(), + content::mojom::PushUnregistrationReason::SERVICE_WORKER_UNREGISTERED, + origin, service_worker_registration_id, app_identifier.app_id(), std::string() /* sender_id */, base::Bind(&UnregisterCallbackToClosure, service_worker_unregistered_callback_for_testing_.is_null() @@ -890,7 +900,7 @@ // Android from GCM, as that requires a sender_id. We can't fetch those from // the Service Worker database anymore as it's been deleted. UnsubscribeInternal( - content::PUSH_UNREGISTRATION_REASON_SERVICE_WORKER_DATABASE_WIPED, + content::mojom::PushUnregistrationReason::SERVICE_WORKER_DATABASE_WIPED, app_identifier.origin(), app_identifier.service_worker_registration_id(), app_identifier.app_id(), std::string() /* sender_id */, @@ -954,7 +964,7 @@ base::Bind(&UnregisterCallbackToClosure, barrier_closure))); } else { UnsubscribeInternal( - content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED, + content::mojom::PushUnregistrationReason::PERMISSION_REVOKED, app_identifier.origin(), app_identifier.service_worker_registration_id(), app_identifier.app_id(), std::string() /* sender_id */, @@ -976,10 +986,10 @@ // Android, Unsubscribe will just delete the app identifier to block future // messages. // TODO(johnme): Auto-unregister before SW DB is cleared (crbug.com/402458). - UnsubscribeInternal(content::PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED, - app_identifier.origin(), - app_identifier.service_worker_registration_id(), - app_identifier.app_id(), sender_id, callback); + UnsubscribeInternal( + content::mojom::PushUnregistrationReason::PERMISSION_REVOKED, + app_identifier.origin(), app_identifier.service_worker_registration_id(), + app_identifier.app_id(), sender_id, callback); } void PushMessagingServiceImpl::SetContentSettingChangedCallbackForTesting(
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.h b/chrome/browser/push_messaging/push_messaging_service_impl.h index 27c59cfa..a033285 100644 --- a/chrome/browser/push_messaging/push_messaging_service_impl.h +++ b/chrome/browser/push_messaging/push_messaging_service_impl.h
@@ -31,7 +31,6 @@ #include "content/public/browser/notification_registrar.h" #include "content/public/browser/push_messaging_service.h" #include "content/public/common/push_event_payload.h" -#include "content/public/common/push_messaging_status.h" #include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h" @@ -42,6 +41,13 @@ class ScopedKeepAlive; struct PushSubscriptionOptions; +namespace content { +namespace mojom { +enum class PushDeliveryStatus; +enum class PushRegistrationStatus; +} // namespace mojom +} // namespace content + namespace gcm { class GCMDriver; } @@ -93,7 +99,7 @@ const std::string& sender_id, const std::string& subscription_id, const SubscriptionInfoCallback& callback) override; - void Unsubscribe(content::PushUnregistrationReason reason, + void Unsubscribe(content::mojom::PushUnregistrationReason reason, const GURL& requesting_origin, int64_t service_worker_registration_id, const std::string& sender_id, @@ -151,7 +157,7 @@ int64_t service_worker_registration_id, const gcm::IncomingMessage& message, const base::Closure& message_handled_closure, - content::PushDeliveryStatus status); + content::mojom::PushDeliveryStatus status); void DidHandleMessage(const std::string& app_id, const base::Closure& completion_closure); @@ -167,10 +173,10 @@ const std::string& subscription_id, const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth, - content::PushRegistrationStatus status); + content::mojom::PushRegistrationStatus status); void SubscribeEndWithError(const RegisterCallback& callback, - content::PushRegistrationStatus status); + content::mojom::PushRegistrationStatus status); void DidSubscribe(const PushMessagingAppIdentifier& app_identifier, const std::string& sender_id, @@ -202,17 +208,18 @@ // whenever they can be obtained. It's valid for |origin| to be empty and // |service_worker_registration_id| to be kInvalidServiceWorkerRegistrationId, // or for app_id to be empty, but not both at once. - void UnsubscribeInternal(content::PushUnregistrationReason reason, + void UnsubscribeInternal(content::mojom::PushUnregistrationReason reason, const GURL& origin, int64_t service_worker_registration_id, const std::string& app_id, const std::string& sender_id, const UnregisterCallback& callback); - void DidClearPushSubscriptionId(content::PushUnregistrationReason reason, - const std::string& app_id, - const std::string& sender_id, - const UnregisterCallback& callback); + void DidClearPushSubscriptionId( + content::mojom::PushUnregistrationReason reason, + const std::string& app_id, + const std::string& sender_id, + const UnregisterCallback& callback); void DidUnregister(bool was_subscribed, gcm::GCMClient::Result result); void DidDeleteID(const std::string& app_id,
diff --git a/chrome/browser/push_messaging/push_messaging_service_unittest.cc b/chrome/browser/push_messaging/push_messaging_service_unittest.cc index ecb1026..b3abca7 100644 --- a/chrome/browser/push_messaging/push_messaging_service_unittest.cc +++ b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
@@ -27,6 +27,7 @@ #include "components/gcm_driver/fake_gcm_client_factory.h" #include "components/gcm_driver/gcm_profile_service.h" #include "content/public/common/push_event_payload.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "content/public/common/push_subscription_options.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -110,8 +111,8 @@ const std::string& registration_id, const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth, - content::PushRegistrationStatus status) { - EXPECT_EQ(content::PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE, + content::mojom::PushRegistrationStatus status) { + EXPECT_EQ(content::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE, status); *subscription_id_out = registration_id;
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc index 822e3353..a8400aaf 100644 --- a/chrome/browser/safe_browsing/download_protection_service.cc +++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -362,6 +362,9 @@ tab_referrer_url_(item->GetTabReferrerUrl()), archived_executable_(false), archive_is_valid_(ArchiveValid::UNSET), +#if defined(OS_MACOSX) + disk_image_signature_(nullptr), +#endif callback_(callback), service_(service), binary_feature_extractor_(binary_feature_extractor), @@ -826,6 +829,11 @@ if (!service_) return; + if (results.signature_blob.size() > 0) { + disk_image_signature_ = + base::MakeUnique<std::vector<uint8_t>>(results.signature_blob); + } + // Even if !results.success, some of the DMG may have been parsed. archive_is_valid_ = (results.success ? ArchiveValid::VALID : ArchiveValid::INVALID); @@ -1071,6 +1079,18 @@ request.mutable_referrer_chain()); } +#if defined(OS_MACOSX) + UMA_HISTOGRAM_BOOLEAN( + "SBClientDownload." + "DownloadFileHasDmgSignature", + disk_image_signature_ != nullptr); + + if (disk_image_signature_) { + request.set_udif_code_signature(disk_image_signature_->data(), + disk_image_signature_->size()); + } +#endif + if (archive_is_valid_ != ArchiveValid::UNSET) request.set_archive_valid(archive_is_valid_ == ArchiveValid::VALID); request.mutable_signature()->CopyFrom(signature_info_); @@ -1266,6 +1286,10 @@ bool archived_executable_; ArchiveValid archive_is_valid_; +#if defined(OS_MACOSX) + std::unique_ptr<std::vector<uint8_t>> disk_image_signature_; +#endif + ClientDownloadRequest_SignatureInfo signature_info_; std::unique_ptr<ClientDownloadRequest_ImageHeaders> image_headers_; google::protobuf::RepeatedPtrField<ClientDownloadRequest_ArchivedBinary>
diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc index 0976d6e..3cfa40e 100644 --- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
@@ -1448,6 +1448,88 @@ CheckClientDownloadReportCorruptArchive(DMG); } +// Tests that signatures get recorded and uploaded for signed DMGs. +TEST_F(DownloadProtectionServiceTest, + CheckClientDownloadReportDmgWithSignature) { + net::FakeURLFetcherFactory factory(NULL); + PrepareResponse(&factory, ClientDownloadResponse::SAFE, net::HTTP_OK, + net::URLRequestStatus::SUCCESS); + + base::FilePath signed_dmg; + EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &signed_dmg)); + signed_dmg = signed_dmg.AppendASCII("safe_browsing") + .AppendASCII("mach_o") + .AppendASCII("signed-archive.dmg"); + + NiceMockDownloadItem item; + PrepareBasicDownloadItemWithFullPaths( + &item, {"http://www.evil.com/a.dmg"}, // url_chain + "http://www.google.com/", // referrer + signed_dmg, // tmp_path + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("a.dmg"))); // final_path + + RunLoop run_loop; + download_service_->CheckClientDownload( + &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, + base::Unretained(this), run_loop.QuitClosure())); + run_loop.Run(); + + ASSERT_TRUE(HasClientDownloadRequest()); + EXPECT_TRUE(GetClientDownloadRequest()->has_udif_code_signature()); + EXPECT_EQ(2215u, GetClientDownloadRequest()->udif_code_signature().length()); + + base::FilePath signed_dmg_signature; + EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &signed_dmg_signature)); + signed_dmg_signature = signed_dmg_signature.AppendASCII("safe_browsing") + .AppendASCII("mach_o") + .AppendASCII("signed-archive-signature.data"); + + std::string signature; + base::ReadFileToString(signed_dmg_signature, &signature); + EXPECT_EQ(2215u, signature.length()); + EXPECT_EQ(signature, GetClientDownloadRequest()->udif_code_signature()); + + ClearClientDownloadRequest(); + + Mock::VerifyAndClearExpectations(sb_service_.get()); + Mock::VerifyAndClearExpectations(binary_feature_extractor_.get()); +} + +// Tests that no signature gets recorded and uploaded for unsigned DMGs. +TEST_F(DownloadProtectionServiceTest, + CheckClientDownloadReportDmgWithoutSignature) { + net::FakeURLFetcherFactory factory(NULL); + PrepareResponse(&factory, ClientDownloadResponse::SAFE, net::HTTP_OK, + net::URLRequestStatus::SUCCESS); + + base::FilePath unsigned_dmg; + EXPECT_TRUE(PathService::Get(chrome::DIR_GEN_TEST_DATA, &unsigned_dmg)); + unsigned_dmg = unsigned_dmg.AppendASCII("chrome") + .AppendASCII("safe_browsing_dmg") + .AppendASCII("mach_o_in_dmg.dmg"); + + NiceMockDownloadItem item; + PrepareBasicDownloadItemWithFullPaths( + &item, {"http://www.evil.com/a.dmg"}, // url_chain + "http://www.google.com/", // referrer + unsigned_dmg, // tmp_path + temp_dir_.GetPath().Append(FILE_PATH_LITERAL("a.dmg"))); // final_path + + RunLoop run_loop; + download_service_->CheckClientDownload( + &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, + base::Unretained(this), run_loop.QuitClosure())); + run_loop.Run(); + + ASSERT_TRUE(HasClientDownloadRequest()); + EXPECT_FALSE(GetClientDownloadRequest()->has_udif_code_signature()); + + ClearClientDownloadRequest(); + + Mock::VerifyAndClearExpectations(sb_service_.get()); + Mock::VerifyAndClearExpectations(binary_feature_extractor_.get()); +} + // Test that downloaded files with no disk image extension that have a 'koly' // trailer are treated as disk images and processed accordingly. TEST_F(DownloadProtectionServiceTest,
diff --git a/chrome/browser/safe_browsing/sandboxed_dmg_analyzer_mac_unittest.cc b/chrome/browser/safe_browsing/sandboxed_dmg_analyzer_mac_unittest.cc index bbf91ba..8e8dc81e 100644 --- a/chrome/browser/safe_browsing/sandboxed_dmg_analyzer_mac_unittest.cc +++ b/chrome/browser/safe_browsing/sandboxed_dmg_analyzer_mac_unittest.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/macros.h" #include "base/path_service.h" #include "base/run_loop.h" @@ -141,5 +142,44 @@ EXPECT_TRUE(got_dylib); } +TEST_F(SandboxedDMGAnalyzerTest, AnalyzeDmgNoSignature) { + base::FilePath unsigned_dmg; + ASSERT_NO_FATAL_FAILURE(unsigned_dmg = GetFilePath("mach_o_in_dmg.dmg")); + + ArchiveAnalyzerResults results; + AnalyzeFile(unsigned_dmg, &results); + + EXPECT_TRUE(results.success); + EXPECT_EQ(0u, results.signature_blob.size()); + EXPECT_EQ(nullptr, results.signature_blob.data()); +} + +TEST_F(SandboxedDMGAnalyzerTest, AnalyzeDmgWithSignature) { + base::FilePath signed_dmg; + EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &signed_dmg)); + signed_dmg = signed_dmg.AppendASCII("safe_browsing") + .AppendASCII("mach_o") + .AppendASCII("signed-archive.dmg"); + + ArchiveAnalyzerResults results; + AnalyzeFile(signed_dmg, &results); + + EXPECT_TRUE(results.success); + EXPECT_EQ(2215u, results.signature_blob.size()); + + base::FilePath signed_dmg_signature; + EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &signed_dmg_signature)); + signed_dmg_signature = signed_dmg_signature.AppendASCII("safe_browsing") + .AppendASCII("mach_o") + .AppendASCII("signed-archive-signature.data"); + + std::string from_file; + base::ReadFileToString(signed_dmg_signature, &from_file); + EXPECT_EQ(2215u, from_file.length()); + std::string signature(results.signature_blob.begin(), + results.signature_blob.end()); + EXPECT_EQ(from_file, signature); +} + } // namespace } // namespace safe_browsing
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index 05a2a101..b8bf25a4 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc
@@ -277,10 +277,6 @@ Profile* profile() { return profile_; } - void AddURLsToOpen(const std::vector<GURL>& urls) { - urls_to_open_.insert(urls_to_open_.end(), urls.begin(), urls.end()); - } - private: // Invoked when done with creating all the tabs/browsers. // @@ -853,24 +849,6 @@ } // static -void SessionRestore::AddURLsToOpen(const Profile* profile, - const std::vector<GURL>& urls) { - // TODO(eugenebng@yandex-team.ru): crbug/735958 fix callers to not - // call this without session restorers, or reword the NOTREACHED - // assertion to explain why it is OK ignore URLs to open when there - // are no active session restorers. - if (!active_session_restorers) - return; - for (auto* session_restorer : *active_session_restorers) { - if (session_restorer->profile() == profile) { - session_restorer->AddURLsToOpen(urls); - return; - } - } - NOTREACHED() << "Failed to add urls to open for session restore"; -} - -// static void SessionRestore::AddObserver(SessionRestoreObserver* observer) { observers().AddObserver(observer); }
diff --git a/chrome/browser/sessions/session_restore.h b/chrome/browser/sessions/session_restore.h index 10dabff1..b468b25 100644 --- a/chrome/browser/sessions/session_restore.h +++ b/chrome/browser/sessions/session_restore.h
@@ -103,11 +103,6 @@ static CallbackSubscription RegisterOnSessionRestoredCallback( const base::Callback<void(int)>& callback); - // Add |urls| to URLs-to-open list, so that they will be opened after session - // URLs when session is restored. - static void AddURLsToOpen(const Profile* profile, - const std::vector<GURL>& urls); - // Add/remove an observer to/from this session restore. static void AddObserver(SessionRestoreObserver* observer); static void RemoveObserver(SessionRestoreObserver* observer);
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index 71d95be4..00f938d 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -4,7 +4,6 @@ #include <stddef.h> -#include <algorithm> #include <set> #include <vector> @@ -209,9 +208,6 @@ GURL url3_; const BrowserList* active_browser_list_; - - private: - DISALLOW_COPY_AND_ASSIGN(SessionRestoreTest); }; // Activates the smart restore behaviour and tracks the loading of tabs. @@ -1623,48 +1619,3 @@ } } } - -namespace { - -const char kStartupURL[] = "http://example.com/"; -const char kSessionURL[] = "http://localhost/"; - -} // namespace - -class SessionRestoreWithStartupURLTest : public SessionRestoreTest { - public: - SessionRestoreWithStartupURLTest() {} - - protected: - void SetUpCommandLine(base::CommandLine* command_line) override { - // Add startup URL to command line, but only in main test body in order - // to prevent that URL from beng opened twice. - if (!base::StartsWith( - testing::UnitTest::GetInstance()->current_test_info()->name(), - "PRE_", base::CompareCase::SENSITIVE)) { - command_line->AppendArg(kStartupURL); - } - SessionRestoreTest::SetUpCommandLine(command_line); - } - - private: - DISALLOW_COPY_AND_ASSIGN(SessionRestoreWithStartupURLTest); -}; - -IN_PROC_BROWSER_TEST_F(SessionRestoreWithStartupURLTest, - PRE_StartupURLsWithSessionRestore) { - // Prepare a session to restore in main test body. - ui_test_utils::NavigateToURL(browser(), GURL(kSessionURL)); -} - -IN_PROC_BROWSER_TEST_F(SessionRestoreWithStartupURLTest, - StartupURLsWithSessionRestore) { - // Check that browser is started with restored session and - // tab with startup URL next to it. - TabStripModel* tab_strip = browser()->tab_strip_model(); - ASSERT_EQ(2, tab_strip->count()); - EXPECT_EQ(kSessionURL, - tab_strip->GetWebContentsAt(0)->GetURL().possibly_invalid_spec()); - EXPECT_EQ(kStartupURL, - tab_strip->GetWebContentsAt(1)->GetURL().possibly_invalid_spec()); -}
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc index 3c327e0e..e527d8bb2 100644 --- a/chrome/browser/signin/dice_browsertest.cc +++ b/chrome/browser/signin/dice_browsertest.cc
@@ -57,6 +57,7 @@ const char kMainEmail[] = "main_email@example.com"; const char kMainGaiaID[] = "main_gaia_id"; const char kOAuth2TokenExchangeURL[] = "/oauth2/v4/token"; +const char kOAuth2TokenRevokeURL[] = "/o/oauth2/revoke"; const char kSecondaryEmail[] = "secondary_email@example.com"; const char kSecondaryGaiaID[] = "secondary_gaia_id"; const char kSigninURL[] = "/signin"; @@ -152,7 +153,7 @@ std::string content = "{" " \"access_token\":\"access_token\"," - " \"refresh_token\":\"refresh_token\"," + " \"refresh_token\":\"new_refresh_token\"," " \"expires_in\":9999" "}"; @@ -162,6 +163,20 @@ return std::move(http_response); } +// Handler for OAuth2 token revocation. +std::unique_ptr<HttpResponse> HandleOAuth2TokenRevokeURL( + int* out_token_revoked_count, + const HttpRequest& request) { + if (!net::test_server::ShouldHandle(request, kOAuth2TokenRevokeURL)) + return nullptr; + + ++(*out_token_revoked_count); + + std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); + http_response->AddCustomHeader("Cache-Control", "no-store"); + return std::move(http_response); +} + } // namespace FakeGaia class DiceBrowserTest : public InProcessBrowserTest, @@ -172,13 +187,17 @@ DiceBrowserTest() : https_server_(net::EmbeddedTestServer::TYPE_HTTPS), token_requested_(false), - refresh_token_available_(false) { + refresh_token_available_(false), + token_revoked_notification_count_(0), + token_revoked_count_(0) { https_server_.RegisterDefaultHandler( base::Bind(&FakeGaia::HandleSigninURL)); https_server_.RegisterDefaultHandler( base::Bind(&FakeGaia::HandleSignoutURL)); https_server_.RegisterDefaultHandler( base::Bind(&FakeGaia::HandleOAuth2TokenExchangeURL, &token_requested_)); + https_server_.RegisterDefaultHandler(base::Bind( + &FakeGaia::HandleOAuth2TokenRevokeURL, &token_revoked_count_)); } // Navigates to the given path on the test server. @@ -219,7 +238,7 @@ // Signin main account. SigninManager* signin_manager = GetSigninManager(); signin_manager->StartSignInWithRefreshToken( - "refresh_token", kMainGaiaID, kMainEmail, "password", + "existing_refresh_token", kMainGaiaID, kMainEmail, "password", SigninManager::OAuthTokenFetchedCallback()); ASSERT_TRUE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID())); ASSERT_EQ(GetMainAccountID(), signin_manager->GetAuthenticatedAccountId()); @@ -255,6 +274,7 @@ const GURL& base_url = https_server_.base_url(); command_line->AppendSwitchASCII(switches::kGaiaUrl, base_url.spec()); command_line->AppendSwitchASCII(switches::kGoogleApisUrl, base_url.spec()); + command_line->AppendSwitchASCII(switches::kLsoUrl, base_url.spec()); switches::EnableAccountConsistencyDiceForTesting(command_line); } @@ -274,9 +294,15 @@ refresh_token_available_ = true; } + void OnRefreshTokenRevoked(const std::string& account_id) override { + ++token_revoked_notification_count_; + } + net::EmbeddedTestServer https_server_; bool token_requested_; bool refresh_token_available_; + int token_revoked_notification_count_; + int token_revoked_count_; }; // Checks that signin on Gaia triggers the fetch for a refresh token. @@ -329,6 +355,9 @@ EXPECT_TRUE(refresh_token_available_); EXPECT_EQ(GetMainAccountID(), GetSigninManager()->GetAuthenticatedAccountId()); + // Old token must be revoked silently. + EXPECT_EQ(0, token_revoked_notification_count_); + EXPECT_EQ(1, token_revoked_count_); } // Checks that the Dice signout flow works and deletes all tokens. @@ -344,6 +373,8 @@ EXPECT_FALSE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID())); EXPECT_FALSE( GetTokenService()->RefreshTokenIsAvailable(GetSecondaryAccountID())); + EXPECT_EQ(2, token_revoked_notification_count_); + EXPECT_EQ(2, token_revoked_count_); } // Checks that signing out from a secondary account does not delete the main @@ -362,6 +393,8 @@ EXPECT_TRUE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID())); EXPECT_FALSE( GetTokenService()->RefreshTokenIsAvailable(GetSecondaryAccountID())); + EXPECT_EQ(1, token_revoked_notification_count_); + EXPECT_EQ(1, token_revoked_count_); } // Checks that the Dice signout flow works and deletes all tokens. @@ -377,4 +410,6 @@ EXPECT_FALSE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID())); EXPECT_FALSE( GetTokenService()->RefreshTokenIsAvailable(GetSecondaryAccountID())); + EXPECT_EQ(2, token_revoked_notification_count_); + EXPECT_EQ(2, token_revoked_count_); }
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc index 99209a5c..d837c66 100644 --- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc +++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
@@ -476,7 +476,7 @@ if (refresh_token_present) { VLOG(1) << "MutablePO2TS::UpdateCredentials; Refresh Token was present. " << "account_id=" << account_id; - + RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token()); refresh_tokens_[account_id]->set_refresh_token(refresh_token); } else { VLOG(1) << "MutablePO2TS::UpdateCredentials; Refresh Token was absent. "
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h index 216ddf47..bc597ee 100644 --- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h +++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h
@@ -108,6 +108,8 @@ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest, PersistenceLoadCredentials); FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest, + RevokeOnUpdate); + FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest, GetAccounts); FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest, RetryBackoff);
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc index a70eedf0..1f853096 100644 --- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc +++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -414,7 +414,40 @@ } #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) -TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, PersistanceNotifications) { +// Tests that calling UpdateCredentials revokes the old token, without sending +// the notification. +TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, RevokeOnUpdate) { + // Add a token. + ASSERT_TRUE(oauth2_service_delegate_->server_revokes_.empty()); + oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token"); + EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty()); + ExpectOneTokenAvailableNotification(); + + // Update the token. + oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2"); + EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size()); + ExpectOneTokenAvailableNotification(); + + // Flush the server revokes. + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty()); + + // Set the same token again. + oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2"); + EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty()); + ExpectNoNotifications(); + + // Clear the token. + oauth2_service_delegate_->RevokeAllCredentials(); + EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size()); + ExpectOneTokenRevokedNotification(); + + // Flush the server revokes. + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty()); +} + +TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, PersistenceNotifications) { oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token"); ExpectOneTokenAvailableNotification();
diff --git a/chrome/browser/site_per_process_interactive_browsertest.cc b/chrome/browser/site_per_process_interactive_browsertest.cc index fb73671..1d9a4052 100644 --- a/chrome/browser/site_per_process_interactive_browsertest.cc +++ b/chrome/browser/site_per_process_interactive_browsertest.cc
@@ -205,7 +205,6 @@ std::string result; std::string script = "function onInput(e) {" - " domAutomationController.setAutomationId(0);" " domAutomationController.send(getInputFieldText());" "}" "inputField = document.getElementById('text-field');" @@ -277,7 +276,6 @@ // have an <input>, then two <iframe> elements, then another <input>. std::string script = "function onFocus(e) {" - " domAutomationController.setAutomationId(0);" " domAutomationController.send(window.name + '-focused-' + e.target.id);" "}" "var input1 = document.createElement('input');" @@ -366,7 +364,6 @@ // iframe: 55,18;55,67 std::string script = "function onFocus(e) {" - " domAutomationController.setAutomationId(0);" " console.log(window.name + '-focused-' + e.target.id);" " domAutomationController.send(window.name + '-focused-' + e.target.id);" "}" @@ -588,7 +585,6 @@ const std::string& id) { std::string script = base::StringPrintf( "document.addEventListener('webkitfullscreenchange', function() {" - " domAutomationController.setAutomationId(0);" " domAutomationController.send('fullscreenchange %s');});", id.c_str()); EXPECT_TRUE(ExecuteScript(frame, script));
diff --git a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc index 788cb765..d851a8bf 100644 --- a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc +++ b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.cc
@@ -271,7 +271,7 @@ void ChromeSpeechRecognitionManagerDelegate::CheckRecognitionIsAllowed( int session_id, - base::Callback<void(bool ask_user, bool is_allowed)> callback) { + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); const content::SpeechRecognitionSessionContext& context = @@ -292,11 +292,10 @@ // Check that the render view type is appropriate, and whether or not we // need to request permission from the user. - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&CheckRenderViewType, - callback, - render_process_id, - render_view_id)); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::BindOnce(&CheckRenderViewType, std::move(callback), + render_process_id, render_view_id)); } content::SpeechRecognitionEventListener* @@ -317,7 +316,7 @@ // static. void ChromeSpeechRecognitionManagerDelegate::CheckRenderViewType( - base::Callback<void(bool ask_user, bool is_allowed)> callback, + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback, int render_process_id, int render_view_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -331,8 +330,9 @@ // This happens for extensions. Manifest should be checked for permission. allowed = true; check_permission = false; - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(callback, check_permission, allowed)); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::BindOnce(std::move(callback), check_permission, allowed)); return; } @@ -357,8 +357,9 @@ check_permission = true; #endif - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(callback, check_permission, allowed)); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::BindOnce(std::move(callback), check_permission, allowed)); } } // namespace speech
diff --git a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.h b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.h index cf81400..a2aab11 100644 --- a/chrome/browser/speech/chrome_speech_recognition_manager_delegate.h +++ b/chrome/browser/speech/chrome_speech_recognition_manager_delegate.h
@@ -45,7 +45,8 @@ // SpeechRecognitionManagerDelegate methods. void CheckRecognitionIsAllowed( int session_id, - base::Callback<void(bool ask_user, bool is_allowed)> callback) override; + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback) + override; content::SpeechRecognitionEventListener* GetEventListener() override; bool FilterProfanities(int render_process_id) override; @@ -58,7 +59,7 @@ // Checks for VIEW_TYPE_TAB_CONTENTS host in the UI thread and notifies back // the result in the IO thread through |callback|. static void CheckRenderViewType( - base::Callback<void(bool ask_user, bool is_allowed)> callback, + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback, int render_process_id, int render_view_id);
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc index 8a3af9f1..d2698e0 100644 --- a/chrome/browser/ssl/ssl_browser_tests.cc +++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -4352,6 +4352,35 @@ CheckAuthenticatedState(tab, AuthState::NONE); } +// Checks that a restore followed immediately by a history navigation doesn't +// lose SSL state. +// Disabled since this is a test for bug 738177. +IN_PROC_BROWSER_TEST_F(SSLUITest, DISABLED_RestoreThenNavigateHasSSLState) { + // This race condition only happens with PlzNavigate. + if (!content::IsBrowserSideNavigationEnabled()) + return; + ASSERT_TRUE(https_server_.Start()); + GURL url1(https_server_.GetURL("/ssl/google.html")); + GURL url2(https_server_.GetURL("/ssl/page_with_refs.html")); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url1, WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + ui_test_utils::NavigateToURL(browser(), url2); + chrome::CloseTab(browser()); + + content::WindowedNotificationObserver tab_added_observer( + chrome::NOTIFICATION_TAB_PARENTED, + content::NotificationService::AllSources()); + chrome::RestoreTab(browser()); + tab_added_observer.Wait(); + + WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); + content::TestNavigationManager observer(tab, url1); + chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB); + observer.WaitForNavigationFinished(); + CheckAuthenticatedState(tab, AuthState::NONE); +} + // Simulate the URL changing when the user presses enter in the omnibox. This // could happen when the user's login is expired and the server redirects them // to a login page. This will be considered a SAME_PAGE navigation but we do
diff --git a/chrome/browser/ui/android/login_handler_android.cc b/chrome/browser/ui/android/login_handler_android.cc index 65e04b5b..895e430 100644 --- a/chrome/browser/ui/android/login_handler_android.cc +++ b/chrome/browser/ui/android/login_handler_android.cc
@@ -9,14 +9,9 @@ #include "base/logging.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" - -#include "device/vr/features/features.h" -#if BUILDFLAG(ENABLE_VR) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) - #include "chrome/browser/ui/android/chrome_http_auth_handler.h" #include "chrome/browser/ui/android/view_android_helper.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" #include "net/base/auth.h" @@ -56,12 +51,10 @@ ViewAndroidHelper* view_helper = ViewAndroidHelper::FromWebContents( web_contents); -#if BUILDFLAG(ENABLE_VR) - if (vr_shell::VrTabHelper::IsInVr(web_contents)) { + if (vr::VrTabHelper::IsInVr(web_contents)) { CancelAuth(); return; } -#endif // Notify WindowAndroid that HTTP authentication is required. if (view_helper->GetViewAndroid() &&
diff --git a/chrome/browser/ui/android/ssl_client_certificate_request.cc b/chrome/browser/ui/android/ssl_client_certificate_request.cc index 3d9a25e..0886180 100644 --- a/chrome/browser/ui/android/ssl_client_certificate_request.cc +++ b/chrome/browser/ui/android/ssl_client_certificate_request.cc
@@ -16,9 +16,9 @@ #include "base/memory/ref_counted.h" #include "chrome/browser/ssl/ssl_client_certificate_selector.h" #include "chrome/browser/ui/android/view_android_helper.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/client_certificate_delegate.h" -#include "device/vr/features/features.h" #include "jni/SSLClientCertificateRequest_jni.h" #include "net/base/host_port_pair.h" #include "net/cert/cert_database.h" @@ -30,10 +30,6 @@ #include "ui/android/view_android.h" #include "ui/android/window_android.h" -#if BUILDFLAG(ENABLE_VR) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) - using base::android::JavaParamRef; using base::android::ScopedJavaLocalRef; @@ -193,12 +189,11 @@ net::SSLCertRequestInfo* cert_request_info, net::ClientCertIdentityList unused_client_certs, std::unique_ptr<content::ClientCertificateDelegate> delegate) { -#if BUILDFLAG(ENABLE_VR) - if (vr_shell::VrTabHelper::IsInVr(contents)) { + if (vr::VrTabHelper::IsInVr(contents)) { delegate->ContinueWithCertificate(nullptr, nullptr); return; } -#endif // BUILDFLAG(ENABLE_VR) + ui::WindowAndroid* window = ViewAndroidHelper::FromWebContents(contents) ->GetViewAndroid()->GetWindowAndroid(); DCHECK(window);
diff --git a/chrome/browser/ui/android/usb_chooser_dialog_android.cc b/chrome/browser/ui/android/usb_chooser_dialog_android.cc index ebe196f..3bf01d85 100644 --- a/chrome/browser/ui/android/usb_chooser_dialog_android.cc +++ b/chrome/browser/ui/android/usb_chooser_dialog_android.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" #include "chrome/browser/usb/web_usb_histograms.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/common/url_constants.h" #include "components/security_state/core/security_state.h" #include "components/url_formatter/elide_url.h" @@ -34,10 +35,6 @@ #include "ui/android/window_android.h" #include "url/gurl.h" -#if BUILDFLAG(ENABLE_VR) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) - using device::UsbDevice; namespace { @@ -65,14 +62,13 @@ weak_factory_(this) { content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host_); -#if BUILDFLAG(ENABLE_VR) - if (vr_shell::VrTabHelper::IsInVr(web_contents)) { + if (vr::VrTabHelper::IsInVr(web_contents)) { DCHECK(!callback_.is_null()); callback_.Run(nullptr); callback_.Reset(); // Reset |callback_| so that it is only run once. return; } -#endif + device::UsbService* usb_service = device::DeviceClient::Get()->GetUsbService(); if (!usb_service)
diff --git a/chrome/browser/ui/apps/app_info_dialog.h b/chrome/browser/ui/apps/app_info_dialog.h index 4805d6a7..698e8982 100644 --- a/chrome/browser/ui/apps/app_info_dialog.h +++ b/chrome/browser/ui/apps/app_info_dialog.h
@@ -21,7 +21,6 @@ namespace gfx { class Rect; -class Size; } // Used for UMA to track where the App Info dialog is launched from. @@ -36,9 +35,6 @@ // Returns true if the app info dialog is available on the current platform. bool CanShowAppInfoDialog(); -// Returns the size of the native window container for the app info dialog. -gfx::Size GetAppInfoNativeDialogSize(); - #if BUILDFLAG(ENABLE_APP_LIST) // Shows the chrome app information as a frameless window for the given |app| // and |profile| at the given |app_list_bounds|. Appears 'inside' the app list. @@ -49,9 +45,8 @@ const base::Closure& close_callback); #endif -// Shows the chrome app information in a native dialog box of the given |size|. +// Shows the chrome app information in a native dialog box. void ShowAppInfoInNativeDialog(content::WebContents* web_contents, - const gfx::Size& size, Profile* profile, const extensions::Extension* app, const base::Closure& close_callback);
diff --git a/chrome/browser/ui/ash/chrome_keyboard_ui.cc b/chrome/browser/ui/ash/chrome_keyboard_ui.cc index 4354548b..9eaa8ce 100644 --- a/chrome/browser/ui/ash/chrome_keyboard_ui.cc +++ b/chrome/browser/ui/ash/chrome_keyboard_ui.cc
@@ -34,45 +34,8 @@ namespace virtual_keyboard_private = extensions::api::virtual_keyboard_private; -typedef virtual_keyboard_private::OnTextInputBoxFocused::Context Context; - namespace { -const char* kVirtualKeyboardExtensionID = "mppnpdlheglhdfmldimlhpnegondlapf"; - -virtual_keyboard_private::OnTextInputBoxFocusedType -TextInputTypeToGeneratedInputTypeEnum(ui::TextInputType type) { - switch (type) { - case ui::TEXT_INPUT_TYPE_NONE: - return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_NONE; - case ui::TEXT_INPUT_TYPE_PASSWORD: - return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_PASSWORD; - case ui::TEXT_INPUT_TYPE_EMAIL: - return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_EMAIL; - case ui::TEXT_INPUT_TYPE_NUMBER: - return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_NUMBER; - case ui::TEXT_INPUT_TYPE_TELEPHONE: - return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_TEL; - case ui::TEXT_INPUT_TYPE_URL: - return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_URL; - case ui::TEXT_INPUT_TYPE_DATE: - return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_DATE; - case ui::TEXT_INPUT_TYPE_TEXT: - case ui::TEXT_INPUT_TYPE_SEARCH: - case ui::TEXT_INPUT_TYPE_DATE_TIME: - case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL: - case ui::TEXT_INPUT_TYPE_MONTH: - case ui::TEXT_INPUT_TYPE_TIME: - case ui::TEXT_INPUT_TYPE_WEEK: - case ui::TEXT_INPUT_TYPE_TEXT_AREA: - case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE: - case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD: - return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_TEXT; - } - NOTREACHED(); - return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_NONE; -} - class AshKeyboardControllerObserver : public keyboard::KeyboardControllerObserver { public: @@ -209,30 +172,3 @@ ->GetContainer(ash::kShellWindowId_ImeWindowParentContainer) ->Contains(window); } - -void ChromeKeyboardUI::SetUpdateInputType(ui::TextInputType type) { - // TODO(bshe): Need to check the affected window's profile once multi-profile - // is supported. - extensions::EventRouter* router = - extensions::EventRouter::Get(browser_context()); - - if (!router->HasEventListener( - virtual_keyboard_private::OnTextInputBoxFocused::kEventName)) { - return; - } - - std::unique_ptr<base::ListValue> event_args(new base::ListValue()); - std::unique_ptr<base::DictionaryValue> input_context( - new base::DictionaryValue()); - input_context->SetString("type", - virtual_keyboard_private::ToString( - TextInputTypeToGeneratedInputTypeEnum(type))); - event_args->Append(std::move(input_context)); - - auto event = base::MakeUnique<extensions::Event>( - extensions::events::VIRTUAL_KEYBOARD_PRIVATE_ON_TEXT_INPUT_BOX_FOCUSED, - virtual_keyboard_private::OnTextInputBoxFocused::kEventName, - std::move(event_args), browser_context()); - router->DispatchEventToExtension(kVirtualKeyboardExtensionID, - std::move(event)); -}
diff --git a/chrome/browser/ui/ash/chrome_keyboard_ui.h b/chrome/browser/ui/ash/chrome_keyboard_ui.h index b796029..680613d 100644 --- a/chrome/browser/ui/ash/chrome_keyboard_ui.h +++ b/chrome/browser/ui/ash/chrome_keyboard_ui.h
@@ -45,15 +45,6 @@ void SetController(keyboard::KeyboardController* controller) override; void ShowKeyboardContainer(aura::Window* container) override; - // The overridden implementation dispatches - // chrome.virtualKeyboardPrivate.onTextInputBoxFocused event to extension to - // provide the input type information. Naturally, when the virtual keyboard - // extension is used as an IME then chrome.input.ime.onFocus provides the - // information, but not when the virtual keyboard is used in conjunction with - // another IME. virtualKeyboardPrivate.onTextInputBoxFocused is the remedy in - // that case. - void SetUpdateInputType(ui::TextInputType type) override; - // content::WebContentsObserver overrides void RenderViewCreated(content::RenderViewHost* render_view_host) override;
diff --git a/chrome/browser/ui/cocoa/new_tab_button.mm b/chrome/browser/ui/cocoa/new_tab_button.mm index 50a829b..bd8f593 100644 --- a/chrome/browser/ui/cocoa/new_tab_button.mm +++ b/chrome/browser/ui/cocoa/new_tab_button.mm
@@ -428,6 +428,9 @@ [strokeColor set]; [bezierPath stroke]; + BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); + CGFloat buttonWidth = newTabButtonImageSize.width; + // Bottom edge. const CGFloat kBottomEdgeX = 9; const CGFloat kBottomEdgeY = 1.2825; @@ -435,6 +438,10 @@ NSPoint bottomEdgeStart = NSMakePoint(kBottomEdgeX, kBottomEdgeY); NSPoint bottomEdgeEnd = NSMakePoint(kBottomEdgeX + kBottomEdgeWidth, kBottomEdgeY); + if (isRTL) { + bottomEdgeStart.x = buttonWidth - bottomEdgeStart.x; + bottomEdgeEnd.x = buttonWidth - bottomEdgeEnd.x; + } NSBezierPath* bottomEdgePath = [NSBezierPath bezierPath]; [bottomEdgePath moveToPoint:bottomEdgeStart]; [bottomEdgePath lineToPoint:bottomEdgeEnd]; @@ -477,6 +484,10 @@ // Shadow beneath the bottom or top edge. if (!NSEqualPoints(shadowStart, NSZeroPoint)) { + if (isRTL) { + shadowStart.x = buttonWidth - shadowStart.x; + shadowEnd.x = buttonWidth - shadowEnd.x; + } NSBezierPath* shadowPath = [NSBezierPath bezierPath]; [shadowPath moveToPoint:shadowStart]; [shadowPath lineToPoint:shadowEnd];
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index e98dac63..2f5b3f8 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -57,6 +57,7 @@ #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" #include "chrome/browser/ui/tab_dialogs.h" +#include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/features.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" @@ -81,12 +82,6 @@ #include "chrome/browser/android/offline_pages/recent_tab_helper.h" #include "chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.h" #include "chrome/browser/android/voice_search_tab_helper.h" - -#include "device/vr/features/features.h" // nogncheck -#if BUILDFLAG(ENABLE_VR) -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" -#endif // BUILDFLAG(ENABLE_VR) - #include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h" #include "chrome/browser/ui/android/context_menu_helper.h" #include "chrome/browser/ui/android/view_android_helper.h" @@ -228,6 +223,7 @@ // TODO(vabr): Remove TabSpecificContentSettings from here once their function // is taken over by ChromeContentSettingsClient. http://crbug.com/387075 TabSpecificContentSettings::CreateForWebContents(web_contents); + vr::VrTabHelper::CreateForWebContents(web_contents); // NO! Do not just add your tab helper here. This is a large alphabetized // block; please insert your tab helper above in alphabetical order. @@ -246,11 +242,6 @@ SingleTabModeTabHelper::CreateForWebContents(web_contents); ViewAndroidHelper::CreateForWebContents(web_contents); VoiceSearchTabHelper::CreateForWebContents(web_contents); - -#if BUILDFLAG(ENABLE_VR) - vr_shell::VrTabHelper::CreateForWebContents(web_contents); -#endif - #else BookmarkTabHelper::CreateForWebContents(web_contents); extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
diff --git a/chrome/browser/ui/views/accessibility/invert_bubble_view.cc b/chrome/browser/ui/views/accessibility/invert_bubble_view.cc index d6eea48..5e58c77 100644 --- a/chrome/browser/ui/views/accessibility/invert_bubble_view.cc +++ b/chrome/browser/ui/views/accessibility/invert_bubble_view.cc
@@ -176,9 +176,13 @@ if (color_utils::IsInvertedColorScheme() && anchor && anchor->GetWidget() && !pref_service->GetBoolean(prefs::kInvertNotificationShown)) { pref_service->SetBoolean(prefs::kInvertNotificationShown, true); - InvertBubbleView* delegate = new InvertBubbleView(browser, anchor); - views::BubbleDialogDelegateView::CreateBubble(delegate)->Show(); + ShowInvertBubbleView(browser, anchor); } } +void ShowInvertBubbleView(Browser* browser, views::View* anchor) { + InvertBubbleView* delegate = new InvertBubbleView(browser, anchor); + views::BubbleDialogDelegateView::CreateBubble(delegate)->Show(); +} + } // namespace chrome
diff --git a/chrome/browser/ui/views/accessibility/invert_bubble_view.h b/chrome/browser/ui/views/accessibility/invert_bubble_view.h index c2d4dc8..b1736c65 100644 --- a/chrome/browser/ui/views/accessibility/invert_bubble_view.h +++ b/chrome/browser/ui/views/accessibility/invert_bubble_view.h
@@ -6,6 +6,11 @@ #define CHROME_BROWSER_UI_VIEWS_ACCESSIBILITY_INVERT_BUBBLE_VIEW_H_ class BrowserView; +class Browser; + +namespace views { +class View; +} namespace chrome { @@ -15,6 +20,9 @@ // this condition for a particular profile. void MaybeShowInvertBubbleView(BrowserView* browser_view); +// Shows the above bubble unconditionally. +void ShowInvertBubbleView(Browser* browser, views::View* anchor); + } // namespace chrome #endif // CHROME_BROWSER_UI_VIEWS_ACCESSIBILITY_INVERT_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/accessibility/invert_bubble_view_browsertest.cc b/chrome/browser/ui/views/accessibility/invert_bubble_view_browsertest.cc new file mode 100644 index 0000000..c31a254 --- /dev/null +++ b/chrome/browser/ui/views/accessibility/invert_bubble_view_browsertest.cc
@@ -0,0 +1,32 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/accessibility/invert_bubble_view.h" + +#include <string> + +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/test/test_browser_dialog.h" +#include "ui/views/view.h" + +class InvertBubbleViewBrowserTest : public DialogBrowserTest { + public: + InvertBubbleViewBrowserTest() {} + + // DialogBrowserTest: + void ShowDialog(const std::string& name) override { + chrome::ShowInvertBubbleView(browser(), &anchor_); + } + + private: + views::View anchor_; + + DISALLOW_COPY_AND_ASSIGN(InvertBubbleViewBrowserTest); +}; + +// Invokes a bubble that asks the user if they want to install a high contrast +// Chrome theme. See test_browser_dialog.h. +IN_PROC_BROWSER_TEST_F(InvertBubbleViewBrowserTest, InvokeDialog_default) { + RunDialog(); +}
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc index f2dbaef..3bb451d 100644 --- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc +++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc
@@ -70,10 +70,6 @@ #endif } -gfx::Size GetAppInfoNativeDialogSize() { - return gfx::Size(380, 490); -} - #if BUILDFLAG(ENABLE_APP_LIST) void ShowAppInfoInAppList(gfx::NativeWindow parent, const gfx::Rect& app_list_bounds, @@ -91,14 +87,14 @@ #endif void ShowAppInfoInNativeDialog(content::WebContents* web_contents, - const gfx::Size& size, Profile* profile, const extensions::Extension* app, const base::Closure& close_callback) { gfx::NativeWindow window = web_contents->GetTopLevelNativeWindow(); views::View* app_info_view = new AppInfoDialog(window, profile, app); + constexpr gfx::Size kDialogSize = gfx::Size(380, 490); views::DialogDelegate* dialog = - CreateDialogContainerForView(app_info_view, size, close_callback); + CreateDialogContainerForView(app_info_view, kDialogSize, close_callback); views::Widget* dialog_widget; if (dialog->GetModalType() == ui::MODAL_TYPE_CHILD) { dialog_widget =
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_browsertest.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_browsertest.cc new file mode 100644 index 0000000..1bc7da8 --- /dev/null +++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_browsertest.cc
@@ -0,0 +1,59 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/apps/app_info_dialog.h" + +#include <string> + +#include "build/build_config.h" +#include "chrome/browser/extensions/test_extension_environment.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/test/test_browser_dialog.h" +#include "chrome/test/base/testing_profile.h" + +#if defined(OS_MACOSX) +#include "base/command_line.h" +#include "chrome/common/chrome_switches.h" +#endif + +class AppInfoDialogBrowserTest : public DialogBrowserTest { + public: + AppInfoDialogBrowserTest() {} + + // DialogBrowserTest: + void ShowDialog(const std::string& name) override { + extension_environment_ = + base::MakeUnique<extensions::TestExtensionEnvironment>(nullptr); + constexpr char kTestExtensionId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + extension_ = + extension_environment_->MakePackagedApp(kTestExtensionId, true); + auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); + ShowAppInfoInNativeDialog( + web_contents, extension_environment_->profile(), extension_.get(), + base::Bind(&AppInfoDialogBrowserTest::OnDialogClosed, + base::Unretained(this))); + } + + void OnDialogClosed() { extension_environment_.reset(); } + +#if defined(OS_MACOSX) + // content::BrowserTestBase: + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch(switches::kEnableAppInfoDialogMac); + } +#endif + + private: + std::unique_ptr<extensions::TestExtensionEnvironment> extension_environment_; + scoped_refptr<extensions::Extension> extension_; + + DISALLOW_COPY_AND_ASSIGN(AppInfoDialogBrowserTest); +}; + +// Invokes a dialog that shows details of an installed extension. See +// test_browser_dialog.h. +IN_PROC_BROWSER_TEST_F(AppInfoDialogBrowserTest, InvokeDialog_default) { + RunDialog(); +}
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc index fb73c92f..a5f072b 100644 --- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc +++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -1210,10 +1210,9 @@ // the test before the event has had a chance to be reported back to the // browser. std::string expected_response = base::StringPrintf("\"i%d\"", i); - right_frame()->ExecuteJavaScriptWithUserGestureForTests(base::UTF8ToUTF16( - base::StringPrintf("domAutomationController.setAutomationId(0);\n" - "domAutomationController.send(%s);\n", - expected_response.c_str()))); + right_frame()->ExecuteJavaScriptWithUserGestureForTests( + base::UTF8ToUTF16(base::StringPrintf( + "domAutomationController.send(%s);", expected_response.c_str()))); // Wait until our response comes back (it might be mixed with responses // carrying events that are sent by event_monitoring.js).
diff --git a/chrome/browser/ui/views/hung_renderer_view_browsertest.cc b/chrome/browser/ui/views/hung_renderer_view_browsertest.cc index e6d85b8..2a9dc909 100644 --- a/chrome/browser/ui/views/hung_renderer_view_browsertest.cc +++ b/chrome/browser/ui/views/hung_renderer_view_browsertest.cc
@@ -6,14 +6,12 @@ #include <string> -#include "base/command_line.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tab_dialogs.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/test/test_browser_dialog.h" #include "content/public/browser/web_contents_unresponsive_state.h" -#include "ui/base/ui_base_switches.h" class HungRendererDialogViewBrowserTest : public DialogBrowserTest { public:
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc index ea5764be..8bd5b218 100644 --- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc +++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -313,16 +313,8 @@ } void BrowserTabStripController::UpdateLoadingAnimations() { - // Don't use the model count here as it's possible for this to be invoked - // before we've applied an update from the model (Browser::TabInsertedAt may - // be processed before us and invokes this). - for (int i = 0, tab_count = tabstrip_->tab_count(); i < tab_count; ++i) { - if (model_->ContainsIndex(i)) { - Tab* tab = tabstrip_->tab_at(i); - WebContents* contents = model_->GetWebContentsAt(i); - tab->UpdateLoadingAnimation(TabContentsNetworkState(contents)); - } - } + for (int i = 0, tab_count = tabstrip_->tab_count(); i < tab_count; ++i) + tabstrip_->tab_at(i)->StepLoadingAnimation(); } int BrowserTabStripController::HasAvailableDragActions() const {
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc index babe43fc..55766eac 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/metrics/user_metrics.h" #include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" #include "build/build_config.h" #include "cc/paint/paint_flags.h" #include "cc/paint/paint_recorder.h" @@ -97,6 +98,11 @@ const char kTabCloseButtonName[] = "TabCloseButton"; +bool ShouldShowThrobber(TabRendererData::NetworkState state) { + return state != TabRendererData::NETWORK_STATE_NONE && + state != TabRendererData::NETWORK_STATE_ERROR; +} + //////////////////////////////////////////////////////////////////////////////// // Drawing and utility functions @@ -361,11 +367,10 @@ // Resets the times tracking when the throbber changes state. void ResetStartTimes(); - private: // views::View: - bool CanProcessEventsWithinSubtree() const override; void OnPaint(gfx::Canvas* canvas) override; + private: Tab* owner_; // Weak. Owns |this|. // The point in time when the tab icon was first painted in the waiting state. @@ -380,7 +385,9 @@ DISALLOW_COPY_AND_ASSIGN(ThrobberView); }; -Tab::ThrobberView::ThrobberView(Tab* owner) : owner_(owner) {} +Tab::ThrobberView::ThrobberView(Tab* owner) : owner_(owner) { + set_can_process_events_within_subtree(false); +} void Tab::ThrobberView::ResetStartTimes() { waiting_start_time_ = base::TimeTicks(); @@ -388,15 +395,9 @@ waiting_state_ = gfx::ThrobberWaitingState(); } -bool Tab::ThrobberView::CanProcessEventsWithinSubtree() const { - return false; -} - void Tab::ThrobberView::OnPaint(gfx::Canvas* canvas) { const TabRendererData::NetworkState state = owner_->data().network_state; - if (state == TabRendererData::NETWORK_STATE_NONE || - state == TabRendererData::NETWORK_STATE_ERROR) - return; + CHECK(ShouldShowThrobber(state)); const ui::ThemeProvider* tp = GetThemeProvider(); const gfx::Rect bounds = GetLocalBounds(); @@ -534,8 +535,8 @@ return; TabRendererData old(data_); - UpdateLoadingAnimation(data.network_state); data_ = data; + UpdateThrobber(old); base::string16 title = data_.title; if (title.empty()) { @@ -569,17 +570,11 @@ SchedulePaint(); } -void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { - if (state == data_.network_state && - (state == TabRendererData::NETWORK_STATE_NONE || - state == TabRendererData::NETWORK_STATE_ERROR)) { - // If the network state is none or is a network error and hasn't changed, - // do nothing. Otherwise we need to advance the animation frame. +void Tab::StepLoadingAnimation() { + if (!throbber_->visible()) return; - } - data_.network_state = state; - AdvanceLoadingAnimation(); + RefreshThrobber(); } void Tab::StartPulse() { @@ -1273,10 +1268,8 @@ return; // Throbber will do its own painting. - if (data().network_state != TabRendererData::NETWORK_STATE_NONE && - data().network_state != TabRendererData::NETWORK_STATE_ERROR) { + if (throbber_->visible()) return; - } // Ensure that |favicon_| is created. if (favicon_.isNull()) { ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); @@ -1306,16 +1299,47 @@ } } -void Tab::AdvanceLoadingAnimation() { - const TabRendererData::NetworkState state = data().network_state; - if (state == TabRendererData::NETWORK_STATE_NONE || - state == TabRendererData::NETWORK_STATE_ERROR) { +void Tab::UpdateThrobber(const TabRendererData& old) { + const bool should_show = ShouldShowThrobber(data_.network_state); + const bool is_showing = throbber_->visible(); + + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDelayReloadStopButtonChange)) { + // Minimize flip-flops between showing the throbber and the favicon. Delay + // the switch from favicon to throbber if the switch would occur just after + // the a throbbing session finishes. The heuristic for "throbbing session + // finishing" is that the old and new URLs match and that the throbber has + // been shown recently. See crbug.com/734104 + constexpr auto kSuppressChangeDuration = base::TimeDelta::FromSeconds(3); + if (!is_showing && should_show && old.url == data_.url && + (base::TimeTicks::Now() - last_throbber_show_time_) < + kSuppressChangeDuration) { + if (!delayed_throbber_show_timer_.IsRunning()) { + delayed_throbber_show_timer_.Start(FROM_HERE, kSuppressChangeDuration, + this, &Tab::RefreshThrobber); + } + return; + } + + delayed_throbber_show_timer_.Stop(); + } + + if (!is_showing && !should_show) + return; + + RefreshThrobber(); +} + +void Tab::RefreshThrobber() { + if (!ShouldShowThrobber(data().network_state)) { throbber_->ResetStartTimes(); throbber_->SetVisible(false); ScheduleIconPaint(); return; } + last_throbber_show_time_ = base::TimeTicks::Now(); + // Since the throbber can animate for a long time, paint to a separate layer // when possible to reduce repaint overhead. const bool paint_to_layer = controller_->CanPaintThrobberToLayer();
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h index 573ea77..e150f104 100644 --- a/chrome/browser/ui/views/tabs/tab.h +++ b/chrome/browser/ui/views/tabs/tab.h
@@ -12,6 +12,8 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/time/time.h" +#include "base/timer/timer.h" #include "cc/paint/paint_record.h" #include "chrome/browser/ui/views/tabs/tab_renderer_data.h" #include "ui/base/layout.h" @@ -94,8 +96,8 @@ void SetData(const TabRendererData& data); const TabRendererData& data() const { return data_; } - // Sets the network state. - void UpdateLoadingAnimation(TabRendererData::NetworkState state); + // Redraws the loading animation if one is visible. Otherwise, no-op. + void StepLoadingAnimation(); // Starts/Stops a pulse animation. void StartPulse(); @@ -259,8 +261,11 @@ // Paints the favicon, mirrored for RTL if needed. void PaintIcon(gfx::Canvas* canvas); - // Invoked if data_.network_state changes, or the network_state is not none. - void AdvanceLoadingAnimation(); + // Updates the throbber. + void UpdateThrobber(const TabRendererData& old); + + // Sets the throbber visibility according to the state in |data_|. + void RefreshThrobber(); // Returns the number of favicon-size elements that can fit in the tab's // current size. @@ -363,6 +368,15 @@ // and thus may be null. gfx::ImageSkia favicon_; + // This timer allows us to delay updating the visibility of the loading + // indicator so that state changes of a very brief duration aren't visually + // apparent to the user. + base::OneShotTimer delayed_throbber_show_timer_; + + // The last time the throbber was visible to the user. See notes in + // UpdateThrobber(). + base::TimeTicks last_throbber_show_time_; + class BackgroundCache { public: BackgroundCache();
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc index c751379..05b823f 100644 --- a/chrome/browser/ui/views/tabs/tab_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -6,12 +6,14 @@ #include <stddef.h> +#include "base/command_line.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/layout_constants.h" #include "chrome/browser/ui/tabs/tab_utils.h" #include "chrome/browser/ui/views/tabs/alert_indicator_button.h" #include "chrome/browser/ui/views/tabs/tab_controller.h" +#include "chrome/common/chrome_switches.h" #include "chrome/grit/theme_resources.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/models/list_selection_model.h" @@ -233,6 +235,17 @@ } } + void FastForwardThrobberStateTimer(Tab* tab) { + ASSERT_TRUE(tab->delayed_throbber_show_timer_.IsRunning()); + auto closure = tab->delayed_throbber_show_timer_.user_task(); + tab->delayed_throbber_show_timer_.Stop(); + closure.Run(); + } + + void WindBackLastThrobberShowTime(Tab* tab) { + tab->last_throbber_show_time_ = base::TimeTicks(); + } + protected: void InitWidget(Widget* widget) { Widget::InitParams params(CreateParams(Widget::InitParams::TYPE_WINDOW)); @@ -442,47 +455,153 @@ tab.SetBoundsRect(gfx::Rect(Tab::GetStandardSize())); views::View* throbber = GetThrobberView(tab); + TabRendererData data; + data.url = GURL("http://example.com"); EXPECT_FALSE(throbber->visible()); EXPECT_EQ(TabRendererData::NETWORK_STATE_NONE, tab.data().network_state); EXPECT_EQ(throbber->bounds(), GetFaviconBounds(tab)); - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_NONE); - EXPECT_FALSE(throbber->visible()); - // Simulate a "normal" tab load: should paint to a layer. - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + data.network_state = TabRendererData::NETWORK_STATE_WAITING; + tab.SetData(data); EXPECT_TRUE(tab_controller.CanPaintThrobberToLayer()); EXPECT_TRUE(throbber->visible()); EXPECT_TRUE(throbber->layer()); - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_LOADING); + data.network_state = TabRendererData::NETWORK_STATE_LOADING; + tab.SetData(data); EXPECT_TRUE(throbber->visible()); EXPECT_TRUE(throbber->layer()); - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_NONE); + data.network_state = TabRendererData::NETWORK_STATE_NONE; + tab.SetData(data); + EXPECT_FALSE(throbber->visible()); + + // After loading is done, simulate another resource starting to load. + data.network_state = TabRendererData::NETWORK_STATE_WAITING; + tab.SetData(data); + EXPECT_TRUE(throbber->visible()); + + // Reset. + data.network_state = TabRendererData::NETWORK_STATE_NONE; + tab.SetData(data); EXPECT_FALSE(throbber->visible()); // Simulate a drag started and stopped during a load: layer painting stops // temporarily. - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + data.network_state = TabRendererData::NETWORK_STATE_WAITING; + tab.SetData(data); EXPECT_TRUE(throbber->visible()); EXPECT_TRUE(throbber->layer()); tab_controller.set_paint_throbber_to_layer(false); - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + tab.StepLoadingAnimation(); EXPECT_TRUE(throbber->visible()); EXPECT_FALSE(throbber->layer()); tab_controller.set_paint_throbber_to_layer(true); - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + tab.StepLoadingAnimation(); EXPECT_TRUE(throbber->visible()); EXPECT_TRUE(throbber->layer()); - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_NONE); + data.network_state = TabRendererData::NETWORK_STATE_NONE; + tab.SetData(data); EXPECT_FALSE(throbber->visible()); // Simulate a tab load starting and stopping during tab dragging (or with // stacked tabs): no layer painting. tab_controller.set_paint_throbber_to_layer(false); - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + data.network_state = TabRendererData::NETWORK_STATE_WAITING; + tab.SetData(data); EXPECT_TRUE(throbber->visible()); EXPECT_FALSE(throbber->layer()); - tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_NONE); + data.network_state = TabRendererData::NETWORK_STATE_NONE; + tab.SetData(data); + EXPECT_FALSE(throbber->visible()); +} + +// As above, but tests what happens when we're heuristically delaying the switch +// between favicon and throbber. +TEST_F(TabTest, LayeredThrobber2) { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kDelayReloadStopButtonChange); + + Widget widget; + InitWidget(&widget); + + FakeTabController tab_controller; + Tab tab(&tab_controller, nullptr); + widget.GetContentsView()->AddChildView(&tab); + tab.SetBoundsRect(gfx::Rect(Tab::GetStandardSize())); + + views::View* throbber = GetThrobberView(tab); + TabRendererData data; + data.url = GURL("http://example.com"); + EXPECT_FALSE(throbber->visible()); + EXPECT_EQ(TabRendererData::NETWORK_STATE_NONE, tab.data().network_state); + EXPECT_EQ(throbber->bounds(), GetFaviconBounds(tab)); + + // Simulate a "normal" tab load: should paint to a layer. + data.network_state = TabRendererData::NETWORK_STATE_WAITING; + tab.SetData(data); + EXPECT_TRUE(tab_controller.CanPaintThrobberToLayer()); + EXPECT_TRUE(throbber->visible()); + EXPECT_TRUE(throbber->layer()); + data.network_state = TabRendererData::NETWORK_STATE_LOADING; + tab.SetData(data); + EXPECT_TRUE(throbber->visible()); + EXPECT_TRUE(throbber->layer()); + data.network_state = TabRendererData::NETWORK_STATE_NONE; + tab.SetData(data); + EXPECT_FALSE(throbber->visible()); + + // After loading is done, simulate another resource starting to load. The + // throbber shouldn't immediately become visible again. + data.network_state = TabRendererData::NETWORK_STATE_WAITING; + tab.SetData(data); + EXPECT_FALSE(throbber->visible()); + ASSERT_NO_FATAL_FAILURE(FastForwardThrobberStateTimer(&tab)); + EXPECT_TRUE(throbber->visible()); + + // On the other hand, if a resource starts to load after the throbber has been + // absent for a while, jump straight to showing it. + data.network_state = TabRendererData::NETWORK_STATE_NONE; + tab.SetData(data); + EXPECT_FALSE(throbber->visible()); + WindBackLastThrobberShowTime(&tab); + data.network_state = TabRendererData::NETWORK_STATE_WAITING; + tab.SetData(data); + EXPECT_TRUE(throbber->visible()); + + // Reset. + data.network_state = TabRendererData::NETWORK_STATE_NONE; + tab.SetData(data); + EXPECT_FALSE(throbber->visible()); + + // Simulate a drag started and stopped during a load: layer painting stops + // temporarily. + data.network_state = TabRendererData::NETWORK_STATE_WAITING; + tab.SetData(data); + ASSERT_NO_FATAL_FAILURE(FastForwardThrobberStateTimer(&tab)); + EXPECT_TRUE(throbber->visible()); + EXPECT_TRUE(throbber->layer()); + tab_controller.set_paint_throbber_to_layer(false); + tab.StepLoadingAnimation(); + EXPECT_TRUE(throbber->visible()); + EXPECT_FALSE(throbber->layer()); + tab_controller.set_paint_throbber_to_layer(true); + tab.StepLoadingAnimation(); + EXPECT_TRUE(throbber->visible()); + EXPECT_TRUE(throbber->layer()); + data.network_state = TabRendererData::NETWORK_STATE_NONE; + tab.SetData(data); + EXPECT_FALSE(throbber->visible()); + + // Simulate a tab load starting and stopping during tab dragging (or with + // stacked tabs): no layer painting. + tab_controller.set_paint_throbber_to_layer(false); + data.network_state = TabRendererData::NETWORK_STATE_WAITING; + tab.SetData(data); + ASSERT_NO_FATAL_FAILURE(FastForwardThrobberStateTimer(&tab)); + EXPECT_TRUE(throbber->visible()); + EXPECT_FALSE(throbber->layer()); + data.network_state = TabRendererData::NETWORK_STATE_NONE; + tab.SetData(data); EXPECT_FALSE(throbber->visible()); }
diff --git a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc index 4d410499..8063753 100644 --- a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
@@ -407,23 +407,9 @@ // TODO(antrim) : this is an explicit code duplications with UserImageScreen. // It should be removed by issue 251179. void SupervisedUserCreationScreenHandler::HandleGetImages() { - base::ListValue image_urls; - for (int i = default_user_image::kFirstDefaultImageIndex; - i < default_user_image::kDefaultImagesCount; ++i) { - std::unique_ptr<base::DictionaryValue> image_data( - new base::DictionaryValue); - image_data->SetString("url", default_user_image::GetDefaultImageUrl(i)); - image_data->SetString("author", - l10n_util::GetStringUTF16( - default_user_image::kDefaultImageAuthorIDs[i])); - image_data->SetString("website", - l10n_util::GetStringUTF16( - default_user_image::kDefaultImageWebsiteIDs[i])); - image_data->SetString("title", - default_user_image::GetDefaultImageDescription(i)); - image_urls.Append(std::move(image_data)); - } - CallJS("setDefaultImages", image_urls); + std::unique_ptr<base::ListValue> image_urls = + default_user_image::GetAsDictionary(); + CallJS("setDefaultImages", *image_urls); } void SupervisedUserCreationScreenHandler::HandlePhotoTaken
diff --git a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc index d313a59..76761ea80 100644 --- a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
@@ -127,23 +127,9 @@ // TODO(antrim) : It looks more like parameters for "Init" rather than callback. void UserImageScreenHandler::HandleGetImages() { - base::ListValue image_urls; - for (int i = default_user_image::kFirstDefaultImageIndex; - i < default_user_image::kDefaultImagesCount; ++i) { - std::unique_ptr<base::DictionaryValue> image_data( - new base::DictionaryValue); - image_data->SetString("url", default_user_image::GetDefaultImageUrl(i)); - image_data->SetString("author", - l10n_util::GetStringUTF16( - default_user_image::kDefaultImageAuthorIDs[i])); - image_data->SetString("website", - l10n_util::GetStringUTF16( - default_user_image::kDefaultImageWebsiteIDs[i])); - image_data->SetString("title", - default_user_image::GetDefaultImageDescription(i)); - image_urls.Append(std::move(image_data)); - } - CallJS("setDefaultImages", image_urls); + std::unique_ptr<base::ListValue> image_urls = + default_user_image::GetAsDictionary(); + CallJS("setDefaultImages", *image_urls); } void UserImageScreenHandler::HandleScreenReady() {
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc index 8a5b7f958..ad2603e6 100644 --- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc +++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -630,9 +630,9 @@ AppInfoLaunchSource::FROM_APPS_PAGE, AppInfoLaunchSource::NUM_LAUNCH_SOURCES); - ShowAppInfoInNativeDialog( - web_ui()->GetWebContents(), GetAppInfoNativeDialogSize(), - Profile::FromWebUI(web_ui()), extension, base::Closure()); + ShowAppInfoInNativeDialog(web_ui()->GetWebContents(), + Profile::FromWebUI(web_ui()), extension, + base::Closure()); } void AppLauncherHandler::HandleReorderApps(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc index 7e7d444a..50ef4300 100644 --- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc +++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -336,20 +336,26 @@ policy::BrowserPolicyConnectorChromeOS* connector = g_browser_process->platform_part()->browser_policy_connector_chromeos(); - std::string enterprise_domain = connector->GetEnterpriseDomain(); - // TODO(jamescook): What about Active Directory managed devices? - if (!enterprise_domain.empty()) { - // Device is enterprise enrolled. + if (connector->IsEnterpriseManaged()) { localized_strings.SetString("enterpriseInfoVisible", "true"); - base::string16 enterprise_info = - l10n_util::GetStringFUTF16(IDS_ASH_ENTERPRISE_DEVICE_MANAGED_BY, - base::UTF8ToUTF16(enterprise_domain)); - localized_strings.SetString("enterpriseInfoMessage", enterprise_info); localized_strings.SetString("enterpriseLearnMore", - l10n_util::GetStringUTF16(IDS_LEARN_MORE)); + l10n_util::GetStringUTF16(IDS_LEARN_MORE)); localized_strings.SetString("enterpriseInfoHintLink", chrome::kLearnMoreEnterpriseURL); + base::string16 enterprise_info; + if (connector->IsCloudManaged()) { + const std::string enterprise_domain = connector->GetEnterpriseDomain(); + enterprise_info = + l10n_util::GetStringFUTF16(IDS_ASH_ENTERPRISE_DEVICE_MANAGED_BY, + base::UTF8ToUTF16(enterprise_domain)); + } else if (connector->IsActiveDirectoryManaged()) { + enterprise_info = + l10n_util::GetStringUTF16(IDS_ASH_ENTERPRISE_DEVICE_MANAGED); + } else { + NOTREACHED() << "Unknown management type"; + } + localized_strings.SetString("enterpriseInfoMessage", enterprise_info); } else { localized_strings.SetString("enterpriseInfoVisible", "false"); localized_strings.SetString("enterpriseInfoMessage", "");
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc index 27f6272d..c52327c8 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -1594,6 +1594,10 @@ preview_callbacks_.pop(); } +void PrintPreviewHandler::OnPrintRequestCancelled() { + HandleCancelPendingPrintRequest(nullptr); +} + #if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG) void PrintPreviewHandler::ShowSystemDialog() { HandleShowSystemDialog(NULL);
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h index 6561892..c638f650 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -86,6 +86,9 @@ // Called when print preview is ready. void OnPrintPreviewReady(int preview_uid, int request_id); + // Called when a print request is cancelled due to its initiator closing. + void OnPrintRequestCancelled(); + // Send the print preset options from the document. void SendPrintPresetOptions(bool disable_scaling, int copies, int duplex);
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc index 5233b57b..411c574 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -533,13 +533,20 @@ } void PrintPreviewUI::OnInitiatorClosed() { + // Should only get here if the initiator was still tracked by the Print + // Preview Dialog Controller, so the print job has not yet been sent. WebContents* preview_dialog = web_ui()->GetWebContents(); printing::BackgroundPrintingManager* background_printing_manager = g_browser_process->background_printing_manager(); - if (background_printing_manager->HasPrintPreviewDialog(preview_dialog)) - web_ui()->CallJavascriptFunctionUnsafe("cancelPendingPrintRequest"); - else + if (background_printing_manager->HasPrintPreviewDialog(preview_dialog)) { + // Dialog is hidden but is still generating the preview. Cancel the print + // request as it can't be completed. + background_printing_manager->OnPrintRequestCancelled(preview_dialog); + handler_->OnPrintRequestCancelled(); + } else { + // Initiator was closed while print preview dialog was still open. OnClosePrintPreviewDialog(); + } } void PrintPreviewUI::OnPrintPreviewCancelled() {
diff --git a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc index 378b08c..c21e51d 100644 --- a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc
@@ -127,23 +127,9 @@ } void ChangePictureHandler::SendDefaultImages() { - base::ListValue image_urls; - for (int i = default_user_image::kFirstDefaultImageIndex; - i < default_user_image::kDefaultImagesCount; ++i) { - std::unique_ptr<base::DictionaryValue> image_data( - new base::DictionaryValue); - image_data->SetString("url", default_user_image::GetDefaultImageUrl(i)); - image_data->SetString("author", - l10n_util::GetStringUTF16( - default_user_image::kDefaultImageAuthorIDs[i])); - image_data->SetString("website", - l10n_util::GetStringUTF16( - default_user_image::kDefaultImageWebsiteIDs[i])); - image_data->SetString("title", - default_user_image::GetDefaultImageDescription(i)); - image_urls.Append(std::move(image_data)); - } - FireWebUIListener("default-images-changed", image_urls); + std::unique_ptr<base::ListValue> image_urls = + default_user_image::GetAsDictionary(); + FireWebUIListener("default-images-changed", *image_urls); } void ChangePictureHandler::HandleChooseFile(const base::ListValue* args) {
diff --git a/chrome/browser/android/vr_shell/vr_tab_helper.cc b/chrome/browser/vr/vr_tab_helper.cc similarity index 80% rename from chrome/browser/android/vr_shell/vr_tab_helper.cc rename to chrome/browser/vr/vr_tab_helper.cc index 20372ea..b8f14db 100644 --- a/chrome/browser/android/vr_shell/vr_tab_helper.cc +++ b/chrome/browser/vr/vr_tab_helper.cc
@@ -2,19 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/android/vr_shell/vr_tab_helper.h" +#include "chrome/browser/vr/vr_tab_helper.h" -#include "chrome/browser/android/vr_shell/vr_shell_delegate.h" #include "content/public/browser/render_view_host.h" #include "content/public/common/web_preferences.h" -#include "device/vr/android/gvr/gvr_delegate_provider.h" using content::WebContents; using content::WebPreferences; -DEFINE_WEB_CONTENTS_USER_DATA_KEY(vr_shell::VrTabHelper); +DEFINE_WEB_CONTENTS_USER_DATA_KEY(vr::VrTabHelper); -namespace vr_shell { +namespace vr { VrTabHelper::VrTabHelper(content::WebContents* contents) : web_contents_(contents) {} @@ -44,4 +42,4 @@ return vr_tab_helper->is_in_vr(); } -} // namespace vr_shell +} // namespace vr
diff --git a/chrome/browser/android/vr_shell/vr_tab_helper.h b/chrome/browser/vr/vr_tab_helper.h similarity index 79% rename from chrome/browser/android/vr_shell/vr_tab_helper.h rename to chrome/browser/vr/vr_tab_helper.h index 315ce623..b24f3a0 100644 --- a/chrome/browser/android/vr_shell/vr_tab_helper.h +++ b/chrome/browser/vr/vr_tab_helper.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_VR_TAB_HELPER_H_ -#define CHROME_BROWSER_ANDROID_VR_SHELL_VR_TAB_HELPER_H_ +#ifndef CHROME_BROWSER_VR_VR_TAB_HELPER_H_ +#define CHROME_BROWSER_VR_VR_TAB_HELPER_H_ #include "base/macros.h" #include "content/public/browser/web_contents_user_data.h" -namespace vr_shell { +namespace vr { class VrTabHelper : public content::WebContentsUserData<VrTabHelper> { public: @@ -33,6 +33,6 @@ DISALLOW_COPY_AND_ASSIGN(VrTabHelper); }; -} // namespace vr_shell +} // namespace vr -#endif // CHROME_BROWSER_ANDROID_VR_SHELL_VR_TAB_HELPER_H_ +#endif // CHROME_BROWSER_VR_VR_TAB_HELPER_H_
diff --git a/chrome/browser/web_applications/web_app_mac_unittest.mm b/chrome/browser/web_applications/web_app_mac_unittest.mm index 148470b..706b2ae 100644 --- a/chrome/browser/web_applications/web_app_mac_unittest.mm +++ b/chrome/browser/web_applications/web_app_mac_unittest.mm
@@ -324,7 +324,8 @@ EXPECT_EQ(product_logo.Height(), [image size].height); } -TEST_F(WebAppShortcutCreatorTest, RevealAppShimInFinder) { +// Disabled, sometimes crashes on "Mac10.10 tests". https://crbug.com/741642 +TEST_F(WebAppShortcutCreatorTest, DISABLED_RevealAppShimInFinder) { WebAppShortcutCreatorMock shortcut_creator(app_data_dir_, info_.get()); EXPECT_CALL(shortcut_creator, GetApplicationsDirname()) .WillRepeatedly(Return(destination_dir_));
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index cd8f5638..a11cec4 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -134,7 +134,7 @@ #if defined(OS_ANDROID) // Experiment to extract structured metadata for app indexing. const base::Feature kCopylessPaste{"CopylessPaste", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; #endif #if defined(OS_WIN)
diff --git a/chrome/common/safe_browsing/archive_analyzer_results.h b/chrome/common/safe_browsing/archive_analyzer_results.h index 0728d93..a9635aa 100644 --- a/chrome/common/safe_browsing/archive_analyzer_results.h +++ b/chrome/common/safe_browsing/archive_analyzer_results.h
@@ -11,6 +11,7 @@ #include <vector> #include "base/files/file_path.h" +#include "build/build_config.h" #include "components/safe_browsing/csd.pb.h" namespace safe_browsing { @@ -22,6 +23,9 @@ google::protobuf::RepeatedPtrField<ClientDownloadRequest_ArchivedBinary> archived_binary; std::vector<base::FilePath> archived_archive_filenames; +#if defined(OS_MACOSX) + std::vector<uint8_t> signature_blob; +#endif // OS_MACOSX ArchiveAnalyzerResults(); ArchiveAnalyzerResults(const ArchiveAnalyzerResults& other); ~ArchiveAnalyzerResults();
diff --git a/chrome/common/safe_browsing/safe_archive_analyzer_param_traits.h b/chrome/common/safe_browsing/safe_archive_analyzer_param_traits.h index cab667f2..95f428c5f 100644 --- a/chrome/common/safe_browsing/safe_archive_analyzer_param_traits.h +++ b/chrome/common/safe_browsing/safe_archive_analyzer_param_traits.h
@@ -8,6 +8,7 @@ #error FULL_SAFE_BROWSING should be defined. #endif +#include "build/build_config.h" #include "chrome/common/safe_browsing/archive_analyzer_results.h" #include "chrome/common/safe_browsing/ipc_protobuf_message_macros.h" #include "chrome/common/safe_browsing/protobuf_message_param_traits.h" @@ -91,4 +92,7 @@ IPC_STRUCT_TRAITS_MEMBER(has_archive) IPC_STRUCT_TRAITS_MEMBER(archived_binary) IPC_STRUCT_TRAITS_MEMBER(archived_archive_filenames) +#if defined(OS_MACOSX) + IPC_STRUCT_TRAITS_MEMBER(signature_blob) +#endif // OS_MACOSX IPC_STRUCT_TRAITS_END()
diff --git a/chrome/installer/zucchini/BUILD.gn b/chrome/installer/zucchini/BUILD.gn index 323b011..6f97b1b1b 100644 --- a/chrome/installer/zucchini/BUILD.gn +++ b/chrome/installer/zucchini/BUILD.gn
@@ -13,6 +13,8 @@ "disassembler.cc", "disassembler.h", "image_utils.h", + "io_utils.cc", + "io_utils.h", "suffix_array.h", "typed_value.h", ] @@ -45,6 +47,7 @@ sources = [ "buffer_view_unittest.cc", "crc32_unittest.cc", + "io_utils_unittest.cc", "suffix_array_unittest.cc", "typed_value_unittest.cc", ]
diff --git a/chrome/installer/zucchini/io_utils.cc b/chrome/installer/zucchini/io_utils.cc new file mode 100644 index 0000000..e889632 --- /dev/null +++ b/chrome/installer/zucchini/io_utils.cc
@@ -0,0 +1,52 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/zucchini/io_utils.h" + +#include <iostream> + +namespace zucchini { + +/******** LimitedOutputStream::StreamBuf ********/ + +LimitedOutputStream::StreamBuf::StreamBuf(std::ostream& os, int limit) + : os_(os), limit_(limit) {} + +LimitedOutputStream::StreamBuf::~StreamBuf() { + // Display warning in case we forget to flush data with std::endl. + if (!str().empty()) { + std::cerr << "Warning: LimitedOutputStream has " << str().length() + << " bytes of unflushed output." << std::endl; + } +} + +int LimitedOutputStream::StreamBuf::sync() { + if (full()) { + str(""); + return 0; + } + os_ << str(); + str(""); + if (++counter_ >= limit_) + os_ << "(Additional output suppressed)\n"; + os_.flush(); + return 0; +} + +/******** LimitedOutputStream ********/ + +LimitedOutputStream::LimitedOutputStream(std::ostream& os, int limit) + : std::ostream(&buf_), buf_(os, limit) {} + +/******** PrefixSep ********/ + +std::ostream& operator<<(std::ostream& ostr, PrefixSep& obj) { + if (obj.first_) + obj.first_ = false; + else + ostr << obj.sep_str_; + return ostr; +} + +} // namespace zucchini
diff --git a/chrome/installer/zucchini/io_utils.h b/chrome/installer/zucchini/io_utils.h new file mode 100644 index 0000000..76e0075 --- /dev/null +++ b/chrome/installer/zucchini/io_utils.h
@@ -0,0 +1,144 @@ +// 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_INSTALLER_ZUCCHINI_IO_UTILS_H_ +#define CHROME_INSTALLER_ZUCCHINI_IO_UTILS_H_ + +#include <cctype> +#include <istream> +#include <ostream> +#include <sstream> +#include <string> + +#include "base/macros.h" + +namespace zucchini { + +// An std::ostream wrapper that that limits number of std::endl lines to output, +// useful for preventing excessive debug message output. Usage requires some +// work by the caller. Sample: +// static LimitedOutputStream los(std::cerr, 10); +// if (!los.full()) { +// ... // Prepare message. Block may be skipped so don't do other work! +// los << message; +// los << std::endl; // Important! +// } +class LimitedOutputStream : public std::ostream { + private: + class StreamBuf : public std::stringbuf { + public: + StreamBuf(std::ostream& os, int limit); + ~StreamBuf(); + + int sync() override; + bool full() const { return counter_ >= limit_; } + + private: + std::ostream& os_; + const int limit_; + int counter_ = 0; + }; + + public: + LimitedOutputStream(std::ostream& os, int limit); + bool full() const { return buf_.full(); } + + private: + StreamBuf buf_; + + DISALLOW_COPY_AND_ASSIGN(LimitedOutputStream); +}; + +// A class to render hexadecimal numbers for std::ostream with 0-padding. This +// is more concise and flexible than stateful STL manipulator alternatives; so: +// std::ios old_fmt(nullptr); +// old_fmt.copyfmt(std::cout); +// std::cout << std::uppercase << std::hex; +// std::cout << std::setfill('0') << std::setw(8) << int_data << std::endl; +// std::cout.copyfmt(old_fmt); +// can be expressed as: +// std::cout << AxHex<8>(int_data) << std::endl; +template <int N, typename T = uint32_t> +struct AsHex { + explicit AsHex(T value_in) : value(value_in) {} + T value; +}; + +template <int N, typename T> +std::ostream& operator<<(std::ostream& os, const AsHex<N, T>& as_hex) { + char buf[N + 1]; + buf[N] = '\0'; + T value = as_hex.value; + for (int i = N - 1; i >= 0; --i, value >>= 4) + buf[i] = "0123456789ABCDEF"[static_cast<int>(value & 0x0F)]; + if (value) + os << "..."; // To indicate data truncation, or negative values. + os << buf; + return os; +} + +// An output manipulator to simplify printing list separators. Sample usage: +// PrefixSep sep(","); +// for (int i : {3, 1, 4, 1, 5, 9}) +// std::cout << sep << i; +// std::cout << std::endl; // Outputs "3,1,4,1,5,9\n". +class PrefixSep { + public: + explicit PrefixSep(const std::string& sep_str) : sep_str_(sep_str) {} + + friend std::ostream& operator<<(std::ostream& ostr, PrefixSep& obj); + + private: + std::string sep_str_; + bool first_ = true; + + DISALLOW_COPY_AND_ASSIGN(PrefixSep); +}; + +// An input manipulator that dictates the expected next character in +// |std::istream|, and invalidates the stream if expectation is not met. +class EatChar { + public: + explicit EatChar(char ch) : ch_(ch) {} + + friend inline std::istream& operator>>(std::istream& istr, + const EatChar& obj) { + if (!istr.fail() && istr.get() != obj.ch_) + istr.setstate(std::ios_base::failbit); + return istr; + } + + private: + char ch_; + + DISALLOW_COPY_AND_ASSIGN(EatChar); +}; + +// An input manipulator that reads an unsigned integer from |std::istream|, +// and invalidates the stream on failure. Intolerant of leading white spaces, +template <typename T> +class StrictUInt { + public: + explicit StrictUInt(T& var) : var_(var) {} + StrictUInt(const StrictUInt&) = default; + + friend std::istream& operator>>(std::istream& istr, StrictUInt<T> obj) { + if (!istr.fail() && !::isdigit(istr.peek())) { + istr.setstate(std::ios_base::failbit); + return istr; + } + return istr >> obj.var_; + } + + private: + T& var_; +}; + +// Stub out uint8_t: istream treats it as char, and value won't be read as int! +template <> +struct StrictUInt<uint8_t> {}; + +} // namespace zucchini + +#endif // CHROME_INSTALLER_ZUCCHINI_IO_UTILS_H_
diff --git a/chrome/installer/zucchini/io_utils_unittest.cc b/chrome/installer/zucchini/io_utils_unittest.cc new file mode 100644 index 0000000..95acbba5 --- /dev/null +++ b/chrome/installer/zucchini/io_utils_unittest.cc
@@ -0,0 +1,159 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/zucchini/io_utils.h" + +#include <sstream> +#include <string> + +#include "base/logging.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace zucchini { + +TEST(IOUtilsTest, LimitedOutputStream) { + std::ostringstream oss; + LimitedOutputStream los(oss, 3); + EXPECT_FALSE(los.full()); + EXPECT_EQ("", oss.str()); + // Line 1. + los << "a" << 1 << "b" << 2 << "c" << 3 << std::endl; + EXPECT_FALSE(los.full()); + EXPECT_EQ("a1b2c3\n", oss.str()); + // Line 2. + oss.str(""); + los << "\r\r\n\n" << std::endl; // Manual new lines don't count. + EXPECT_FALSE(los.full()); + EXPECT_EQ("\r\r\n\n\n", oss.str()); + // Line 3. + oss.str(""); + los << "blah" << 137; + EXPECT_FALSE(los.full()); + los << std::endl; + EXPECT_TRUE(los.full()); + EXPECT_EQ("blah137\n(Additional output suppressed)\n", oss.str()); + // Not testing adding more lines: the behavior is undefined since we rely on + // caller suppressing output if |los.full()| is true. +} + +TEST(IOUtilsTest, AsHex) { + std::ostringstream oss; + // Helper for single-line tests. Eats dummy std::ostream& from operator<<(). + auto extract = [&oss](std::ostream&) -> std::string { + std::string ret = oss.str(); + oss.str(""); + return ret; + }; + + EXPECT_EQ("00000000", extract(oss << AsHex<8>(0))); + EXPECT_EQ("12345678", extract(oss << AsHex<8>(0x12345678U))); + EXPECT_EQ("9ABCDEF0", extract(oss << AsHex<8>(0x9ABCDEF0U))); + EXPECT_EQ("(00000064)", extract(oss << "(" << AsHex<8>(100) << ")")); + EXPECT_EQ("00FFFF", extract(oss << AsHex<6>(0xFFFFU))); + EXPECT_EQ("FFFF", extract(oss << AsHex<4>(0xFFFFU))); + EXPECT_EQ("...FF", extract(oss << AsHex<2>(0xFFFFU))); + EXPECT_EQ("...00", extract(oss << AsHex<2>(0x100U))); + EXPECT_EQ("FF\n", extract(oss << AsHex<2>(0xFFU) << std::endl)); + EXPECT_EQ("132457689BACDEF0", + extract(oss << AsHex<16, uint64_t>(0x132457689BACDEF0LLU))); + EXPECT_EQ("000000000001", extract(oss << AsHex<12, uint8_t>(1))); + EXPECT_EQ("00000089", extract(oss << AsHex<8, int32_t>(137))); + EXPECT_EQ("...FFFFFFFF", extract(oss << AsHex<8, int32_t>(-1))); + EXPECT_EQ("7FFF", extract(oss << AsHex<4, int16_t>(0x7FFFU))); + EXPECT_EQ("...8000", extract(oss << AsHex<4, int16_t>(0x8000U))); + EXPECT_EQ("8000", extract(oss << AsHex<4, uint16_t>(0x8000U))); +} + +TEST(IOUtilsTest, PrefixSep) { + std::ostringstream oss; + PrefixSep sep(","); + oss << sep << 3; + EXPECT_EQ("3", oss.str()); + oss << sep << 1; + EXPECT_EQ("3,1", oss.str()); + oss << sep << 4 << sep << 1 << sep << "59"; + EXPECT_EQ("3,1,4,1,59", oss.str()); +} + +TEST(IOUtilsTest, PrefixSepAlt) { + std::ostringstream oss; + PrefixSep sep(" "); + oss << sep << 3; + EXPECT_EQ("3", oss.str()); + oss << sep << 1; + EXPECT_EQ("3 1", oss.str()); + oss << sep << 4 << sep << 1 << sep << "59"; + EXPECT_EQ("3 1 4 1 59", oss.str()); +} + +TEST(IOUtilsTest, EatChar) { + std::istringstream main_iss; + // Helper for single-line tests. + auto iss = [&main_iss](const std::string s) -> std::istringstream& { + main_iss.clear(); + main_iss.str(s); + return main_iss; + }; + + EXPECT_TRUE(iss("a,1") >> EatChar('a') >> EatChar(',') >> EatChar('1')); + EXPECT_FALSE(iss("a,a") >> EatChar('a') >> EatChar(',') >> EatChar('1')); + EXPECT_FALSE(iss("a") >> EatChar('a') >> EatChar(',') >> EatChar('1')); + EXPECT_FALSE(iss("x") >> EatChar('X')); + EXPECT_TRUE(iss("_\n") >> EatChar('_') >> EatChar('\n')); +} + +TEST(IOUtilsTest, StrictUInt) { + std::istringstream main_iss; + // Helper for single-line tests. + auto iss = [&main_iss](const std::string& s) -> std::istringstream& { + main_iss.clear(); + main_iss.str(s); + return main_iss; + }; + + uint32_t u32 = 0; + EXPECT_TRUE(iss("1234") >> StrictUInt<uint32_t>(u32)); + EXPECT_EQ(uint32_t(1234), u32); + EXPECT_TRUE(iss("001234") >> StrictUInt<uint32_t>(u32)); + EXPECT_EQ(uint32_t(1234), u32); + EXPECT_FALSE(iss("blahblah") >> StrictUInt<uint32_t>(u32)); + EXPECT_EQ(uint32_t(1234), u32); // No overwrite on failure. + EXPECT_TRUE(iss("137suffix") >> StrictUInt<uint32_t>(u32)); + EXPECT_EQ(uint32_t(137), u32); + EXPECT_FALSE(iss(" 1234") >> StrictUInt<uint32_t>(u32)); + EXPECT_FALSE(iss("-1234") >> StrictUInt<uint32_t>(u32)); + + uint16_t u16 = 0; + EXPECT_TRUE(iss("65535") >> StrictUInt<uint16_t>(u16)); + EXPECT_EQ(uint16_t(65535), u16); + EXPECT_FALSE(iss("65536") >> StrictUInt<uint16_t>(u16)); // Overflow. + + uint64_t u64 = 0; + EXPECT_TRUE(iss("1000000000001") >> StrictUInt<uint64_t>(u64)); + EXPECT_EQ(uint64_t(1000000000001LL), u64); + + // uint8_t is stubbed out, so no tests for it. +} + +TEST(IOUtilsTest, ParseSimpleEquations) { + std::istringstream iss("123+456=579,4-3=1"); + uint32_t a = 0; + uint32_t b = 0; + uint32_t c = 0; + EXPECT_TRUE(iss >> StrictUInt<uint32_t>(a) >> EatChar('+') >> + StrictUInt<uint32_t>(b) >> EatChar('=') >> + StrictUInt<uint32_t>(c)); + EXPECT_EQ(uint32_t(123), a); + EXPECT_EQ(uint32_t(456), b); + EXPECT_EQ(uint32_t(579), c); + EXPECT_TRUE(iss >> EatChar(',')); + EXPECT_TRUE(iss >> StrictUInt<uint32_t>(a) >> EatChar('-') >> + StrictUInt<uint32_t>(b) >> EatChar('=') >> + StrictUInt<uint32_t>(c)); + EXPECT_EQ(uint32_t(4), a); + EXPECT_EQ(uint32_t(3), b); + EXPECT_EQ(uint32_t(1), c); +} + +} // namespace zucchini
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 4c185565..dd3049c3 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1534,6 +1534,7 @@ "../browser/ui/toolbar/mock_component_toolbar_actions_factory.cc", "../browser/ui/toolbar/mock_component_toolbar_actions_factory.h", "../browser/ui/update_chrome_dialog_browsertest.cc", + "../browser/ui/views/apps/app_info_dialog/app_info_dialog_views_browsertest.cc", "../browser/ui/views/chrome_cleaner_dialog_browsertest_win.cc", "../browser/ui/views/extensions/chooser_dialog_view_browsertest.cc", "../browser/ui/views/hung_renderer_view_browsertest.cc", @@ -2510,6 +2511,7 @@ if (is_win) { sources += [ "../browser/extensions/api/networking_private/networking_private_credentials_getter_browsertest.cc", + "../browser/ui/views/accessibility/invert_bubble_view_browsertest.cc", "../browser/ui/views/settings_reset_prompt_dialog_browsertest.cc", ] }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java index 698f061..2ef79e0 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java
@@ -9,6 +9,7 @@ import android.graphics.Bitmap; import org.chromium.base.Callback; +import org.chromium.base.ObserverList; import org.chromium.base.ThreadUtils; import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo; import org.chromium.chrome.browser.ntp.snippets.CategoryInt; @@ -28,7 +29,7 @@ * A fake Suggestions source for use in unit and instrumentation tests. */ public class FakeSuggestionsSource implements SuggestionsSource { - private SuggestionsSource.Observer mObserver; + private ObserverList<Observer> mObserverList = new ObserverList<>(); private final List<Integer> mCategories = new ArrayList<>(); private final Map<Integer, List<SnippetArticle>> mSuggestions = new HashMap<>(); private final Map<Integer, Integer> mCategoryStatus = new LinkedHashMap<>(); @@ -45,6 +46,9 @@ new HashMap<>(); private final Map<Integer, Integer> mDismissedCategoryStatus = new LinkedHashMap<>(); private final Map<Integer, SuggestionsCategoryInfo> mDismissedCategoryInfo = new HashMap<>(); + + private boolean mRemoteSuggestionsEnabled = true; + /** * Sets the status to be returned for a given category. */ @@ -55,7 +59,7 @@ } else if (!mCategories.contains(category)) { mCategories.add(category); } - if (mObserver != null) mObserver.onCategoryStatusChanged(category, status); + for (Observer observer : mObserverList) observer.onCategoryStatusChanged(category, status); } /** @@ -65,7 +69,7 @@ @CategoryInt int category, List<SnippetArticle> suggestions) { // Copy the suggestions list so that it can't be modified anymore. mSuggestions.put(category, new ArrayList<>(suggestions)); - if (mObserver != null) mObserver.onNewSuggestions(category); + for (Observer observer : mObserverList) observer.onNewSuggestions(category); } /** @@ -136,14 +140,16 @@ break; } } - mObserver.onSuggestionInvalidated(category, idWithinCategory); + for (Observer observer : mObserverList) { + observer.onSuggestionInvalidated(category, idWithinCategory); + } } /** * Notifies the observer that a full refresh is required. */ public void fireFullRefreshRequired() { - mObserver.onFullRefreshRequired(); + for (Observer observer : mObserverList) observer.onFullRefreshRequired(); } /** @@ -160,6 +166,15 @@ public void fetchRemoteSuggestions() {} @Override + public boolean areRemoteSuggestionsEnabled() { + return mRemoteSuggestionsEnabled; + } + + public void setRemoteSuggestionsEnabled(boolean enabled) { + mRemoteSuggestionsEnabled = enabled; + } + + @Override public void dismissSuggestion(SnippetArticle suggestion) { for (List<SnippetArticle> suggestions : mSuggestions.values()) { suggestions.remove(suggestion); @@ -229,8 +244,13 @@ } @Override - public void setObserver(Observer observer) { - mObserver = observer; + public void addObserver(Observer observer) { + mObserverList.addObserver(observer); + } + + @Override + public void removeObserver(Observer observer) { + mObserverList.removeObserver(observer); } @Override
diff --git a/chrome/test/base/tracing_browsertest.cc b/chrome/test/base/tracing_browsertest.cc index 5347d14..d343a851 100644 --- a/chrome/test/base/tracing_browsertest.cc +++ b/chrome/test/base/tracing_browsertest.cc
@@ -101,13 +101,8 @@ } }; -// crbug.com/708487. -#if defined(OS_MACOSX) && defined(ADDRESS_SANITIZER) -#define MAYBE_TestMemoryInfra DISABLED_TestMemoryInfra -#else -#define MAYBE_TestMemoryInfra TestMemoryInfra -#endif // defined(OS_MACOSX) && defined(ADDRESS_SANITIZER) -IN_PROC_BROWSER_TEST_F(TracingBrowserTest, MAYBE_TestMemoryInfra) { +// crbug.com/708487 +IN_PROC_BROWSER_TEST_F(TracingBrowserTest, DISABLED_TestMemoryInfra) { PerformDumpMemoryTestActions( base::trace_event::TraceConfig( base::trace_event::TraceConfigMemoryTestUtil:: @@ -115,13 +110,8 @@ base::trace_event::MemoryDumpLevelOfDetail::DETAILED); } -// crbug.com/708487. -#if defined(OS_MACOSX) && defined(ADDRESS_SANITIZER) -#define MAYBE_TestBackgroundMemoryInfra DISABLED_TestBackgroundMemoryInfra -#else -#define MAYBE_TestBackgroundMemoryInfra TestBackgroundMemoryInfra -#endif // defined(OS_MACOSX) && defined(ADDRESS_SANITIZER) -IN_PROC_BROWSER_TEST_F(TracingBrowserTest, MAYBE_TestBackgroundMemoryInfra) { +// crbug.com/708487 +IN_PROC_BROWSER_TEST_F(TracingBrowserTest, DISABLED_TestBackgroundMemoryInfra) { PerformDumpMemoryTestActions( base::trace_event::TraceConfig( base::trace_event::TraceConfigMemoryTestUtil::
diff --git a/chrome/test/data/android/webvr_instrumentation/html/test_controller_scrolling.html b/chrome/test/data/android/webvr_instrumentation/html/test_controller_scrolling.html new file mode 100644 index 0000000..7a15f8cd --- /dev/null +++ b/chrome/test/data/android/webvr_instrumentation/html/test_controller_scrolling.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<!-- +Used to test that vertical and horizontal scrolling work with the Daydream +controller. +--> +<html> + <head> + <style> + body { + width: 10000px; + height: 10000px; + } + </style> + </head> + <body> + This is a test page. + </body> +</html>
diff --git a/chrome/test/data/safe_browsing/mach_o/Makefile b/chrome/test/data/safe_browsing/mach_o/Makefile index 199685b..d0a7498 100644 --- a/chrome/test/data/safe_browsing/mach_o/Makefile +++ b/chrome/test/data/safe_browsing/mach_o/Makefile
@@ -6,6 +6,12 @@ # This must match the commonName in codesign.cfg. KEYCHAIN_IDENTITY=untrusted@goat.local +# Funcitons to add and remove codesigning identity to user's keychain. These +# are necessary since the codesign utility no longer supports the -k option, +# which reads the identity from a file. +pre-build = security import codesign.key && security import codesign.crt +post-build = security delete-identity -c untrusted@goat.local + executable32: src.c clang -m32 -o $@ $^ @@ -34,58 +40,57 @@ openssl x509 -req -signkey codesign.key -sha256 \ -extfile codesign.cfg -extensions req_attrs -in $< -out $@ -codesign.keychain: codesign.key codesign.crt - security create-keychain -p $(KEYCHAIN_PASSWORD) $(PWD)/$@ - security unlock-keychain -p $(KEYCHAIN_PASSWORD) $(PWD)/$@ - certtool i ./codesign.crt k=$(PWD)/$@ r=./codesign.key - -signedexecutable32: executable32 codesign.keychain +signedexecutable32: executable32 codesign.crt + $(call pre-build) cp $< $@ - security unlock-keychain -p $(KEYCHAIN_PASSWORD) \ - $(PWD)/codesign.keychain - codesign -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain $@ + codesign -s $(KEYCHAIN_IDENTITY) $@ + $(call post-build) -libsigned64.dylib: lib64.dylib codesign.keychain +libsigned64.dylib: lib64.dylib codesign.crt + $(call pre-build) cp $< $@ - security unlock-keychain -p $(KEYCHAIN_PASSWORD) \ - $(PWD)/codesign.keychain - codesign -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain $@ + codesign -s $(KEYCHAIN_IDENTITY) $@ + $(call post-build) -signedexecutablefat: executablefat codesign.keychain +signedexecutablefat: executablefat codesign.crt + $(call pre-build) cp $< $@ - security unlock-keychain -p $(KEYCHAIN_PASSWORD) \ - $(PWD)/codesign.keychain - codesign -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain \ - $@ --all-architectures + codesign -s $(KEYCHAIN_IDENTITY) $@ --all-architectures + $(call post-build) + +signed-archive.dmg: test-bundle.app codesign.crt + $(call pre-build) + hdiutil create -srcfolder test-bundle.app -format UDZO -layout \ + SPUD -volname "Signed Archive" -ov $@ + codesign -s $(KEYCHAIN_IDENTITY) $@ + $(call post-build) .PHONY: test-bundle.app test-bundle.app: signedexecutablefat libsigned64.dylib executable32 + $(call pre-build) ditto base-bundle.app $@ ditto $< $@/Contents/MacOS/test-bundle ditto $(word 2,$^) $@/Contents/Frameworks/$(word 2,$^) ditto $(word 3,$^) $@/Contents/Resources/$(word 3,$^) - security unlock-keychain -p $(KEYCHAIN_PASSWORD) \ - $(PWD)/codesign.keychain - codesign -f -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain \ - $@ --all-architectures --resource-rules ResourceRules + codesign -f -s $(KEYCHAIN_IDENTITY) $@ --all-architectures \ + --resource-rules ResourceRules + $(call post-build) .PHONY: modified-bundle.app modified-bundle.app: test-bundle.app lib32.dylib executable64 + $(call pre-build) ditto $< $@ echo "<xml/>" > $@/Contents/Resources/Base.lproj/InfoPlist.strings - security unlock-keychain -p $(KEYCHAIN_PASSWORD) \ - $(PWD)/codesign.keychain - codesign -f -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain \ - $@ --all-architectures --resource-rules ResourceRules + codesign -f -s $(KEYCHAIN_IDENTITY) $@ --all-architectures \ + --resource-rules ResourceRules echo "BAD" > $@/Contents/Resources/Base.lproj/InfoPlist.strings touch $@/Contents/Resources/codesign.cfg ditto $(word 2,$^) $@/Contents/Frameworks/libsigned64.dylib ditto $(word 3,$^) $@/Contents/Resources/executable32 echo "foo" >> $@/Contents/Resources/Base.lproj/MainMenu.nib - security unlock-keychain -p $(KEYCHAIN_PASSWORD) \ - $(PWD)/codesign.keychain - codesign -f -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain \ + codesign -f -s $(KEYCHAIN_IDENTITY) \ $@/Contents/Resources/Base.lproj/MainMenu.nib + $(call post-build) .PHONY: modified-bundle-and-exec.app modified-bundle-and-exec.app: test-bundle.app lib32.dylib executable64 @@ -110,10 +115,10 @@ .PHONY: modified-localization.app modified-localization.app: test-bundle.app + $(call pre-build) ditto $< $@ echo "<xml/>" > $@/Contents/Resources/Base.lproj/InfoPlist.strings - security unlock-keychain -p $(KEYCHAIN_PASSWORD) \ - $(PWD)/codesign.keychain - codesign -f -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain \ - $@ --all-architectures --resource-rules ResourceRules + codesign -f -s $(KEYCHAIN_IDENTITY) $@ --all-architectures \ + --resource-rules ResourceRules echo "CORRUPT" > $@/Contents/Resources/Base.lproj/InfoPlist.strings + $(call post-build)
diff --git a/chrome/test/data/safe_browsing/mach_o/README b/chrome/test/data/safe_browsing/mach_o/README index 60b51d1..848fb2b 100644 --- a/chrome/test/data/safe_browsing/mach_o/README +++ b/chrome/test/data/safe_browsing/mach_o/README
@@ -12,3 +12,8 @@ The `executableppc' file has no Makefile target, as modern Macs cannot build for PPC. This file was created in a 10.6 VM with Xcode 3.2.6. + +Creating the signed binaries requires importing a temporary codesigning +identity into the current user's keychain. This is because the `codesign -k` +flag, which specifies a specific keychain file to use, is no longer respected. +The temporary identity will be removed after the test binary is signed. \ No newline at end of file
diff --git a/chrome/test/data/safe_browsing/mach_o/codesign.keychain b/chrome/test/data/safe_browsing/mach_o/codesign.keychain deleted file mode 100644 index 0e4bf37..0000000 --- a/chrome/test/data/safe_browsing/mach_o/codesign.keychain +++ /dev/null Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/signed-archive-signature.data b/chrome/test/data/safe_browsing/mach_o/signed-archive-signature.data new file mode 100644 index 0000000..f99be07 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/signed-archive-signature.data Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/signed-archive.dmg b/chrome/test/data/safe_browsing/mach_o/signed-archive.dmg new file mode 100644 index 0000000..93480e6 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/signed-archive.dmg Binary files differ
diff --git a/chrome/utility/safe_browsing/mac/dmg_analyzer.cc b/chrome/utility/safe_browsing/mac/dmg_analyzer.cc index 09ebf17..6ba4e583 100644 --- a/chrome/utility/safe_browsing/mac/dmg_analyzer.cc +++ b/chrome/utility/safe_browsing/mac/dmg_analyzer.cc
@@ -126,6 +126,8 @@ if (!iterator.Open()) return; + results->signature_blob = iterator.GetCodeSignature(); + while (iterator.Next()) { std::unique_ptr<ReadStream> stream = iterator.GetReadStream(); if (!stream || !feature_extractor.IsMachO(stream.get()))
diff --git a/chrome/utility/safe_browsing/mac/dmg_iterator.cc b/chrome/utility/safe_browsing/mac/dmg_iterator.cc index 75f0512..8d883aa 100644 --- a/chrome/utility/safe_browsing/mac/dmg_iterator.cc +++ b/chrome/utility/safe_browsing/mac/dmg_iterator.cc
@@ -35,6 +35,10 @@ return partitions_.size() > 0; } +const std::vector<uint8_t>& DMGIterator::GetCodeSignature() { + return udif_.GetCodeSignature(); +} + bool DMGIterator::Next() { // Iterate through all the HFS partitions in the DMG file. for (; current_partition_ < partitions_.size(); ++current_partition_) {
diff --git a/chrome/utility/safe_browsing/mac/dmg_iterator.h b/chrome/utility/safe_browsing/mac/dmg_iterator.h index 74f17b0..2f3c022 100644 --- a/chrome/utility/safe_browsing/mac/dmg_iterator.h +++ b/chrome/utility/safe_browsing/mac/dmg_iterator.h
@@ -37,6 +37,10 @@ // invalid element before the first item. bool Open(); + // Returns the raw code signature file metadata. This will be empty for DMGs + // that are not signed. + const std::vector<uint8_t>& GetCodeSignature(); + // Advances the iterator to the next file item. Returns true on success // and false on end-of-iterator. bool Next();
diff --git a/chrome/utility/safe_browsing/mac/udif.cc b/chrome/utility/safe_browsing/mac/udif.cc index 0c4be3f..dea3cf9 100644 --- a/chrome/utility/safe_browsing/mac/udif.cc +++ b/chrome/utility/safe_browsing/mac/udif.cc
@@ -348,8 +348,7 @@ : stream_(stream), partition_names_(), blocks_(), - block_size_(kSectorSize) { -} + block_size_(kSectorSize) {} UDIFParser::~UDIFParser() {} @@ -360,6 +359,10 @@ return true; } +const std::vector<uint8_t>& UDIFParser::GetCodeSignature() { + return signature_blob_; +} + size_t UDIFParser::GetNumberOfPartitions() { return blocks_.size(); } @@ -557,6 +560,37 @@ partition_names_.push_back(partition_name); } + // The offsets in the trailer could be garbage in DMGs that aren't signed. + // Need a sanity check that the DMG has legit values for these fields. + if (trailer.code_signature_length != 0 && trailer_start > 0) { + auto code_signature_end = + base::CheckedNumeric<size_t>(trailer.code_signature_offset) + + trailer.code_signature_length; + if (code_signature_end.IsValid() && + code_signature_end.ValueOrDie() <= + base::checked_cast<size_t>(trailer_start)) { + signature_blob_.resize(trailer.code_signature_length); + + off_t code_signature_start = + stream_->Seek(trailer.code_signature_offset, SEEK_SET); + if (code_signature_start == -1) + return false; + + size_t bytes_read = 0; + + if (!stream_->Read(signature_blob_.data(), trailer.code_signature_length, + &bytes_read)) { + DLOG(ERROR) << "Failed to read raw signature bytes"; + return false; + } + + if (bytes_read != trailer.code_signature_length) { + DLOG(ERROR) << "Read unexpected number of raw signature bytes"; + return false; + } + } + } + return true; }
diff --git a/chrome/utility/safe_browsing/mac/udif.h b/chrome/utility/safe_browsing/mac/udif.h index fbb17c9..13aee9db 100644 --- a/chrome/utility/safe_browsing/mac/udif.h +++ b/chrome/utility/safe_browsing/mac/udif.h
@@ -51,6 +51,9 @@ // If this returns false, it is not legal to call any other methods. bool Parse(); + // Returns the blob of DMG signature data. + const std::vector<uint8_t>& GetCodeSignature(); + // Returns the number of partitions in this UDIF image. size_t GetNumberOfPartitions(); @@ -79,6 +82,7 @@ // All blocks in the UDIF image. std::vector<std::unique_ptr<const UDIFBlock>> blocks_; uint16_t block_size_; // The image's block size, in bytes. + std::vector<uint8_t> signature_blob_; // DMG signature. DISALLOW_COPY_AND_ASSIGN(UDIFParser); };
diff --git a/chromeos/attestation/attestation_flow_unittest.cc b/chromeos/attestation/attestation_flow_unittest.cc index e9cab9df..23ab18e6 100644 --- a/chromeos/attestation/attestation_flow_unittest.cc +++ b/chromeos/attestation/attestation_flow_unittest.cc
@@ -6,18 +6,16 @@ #include <utility> #include "base/bind.h" -#include "base/location.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/test/scoped_task_environment.h" -#include "base/threading/thread_task_runner_handle.h" #include "base/time/tick_clock.h" #include "base/timer/timer.h" #include "chromeos/attestation/mock_attestation_flow.h" #include "chromeos/cryptohome/cryptohome_parameters.h" #include "chromeos/cryptohome/mock_async_method_caller.h" -#include "chromeos/dbus/mock_cryptohome_client.h" +#include "chromeos/dbus/fake_cryptohome_client.h" #include "components/signin/core/account_id/account_id.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -37,38 +35,10 @@ namespace { -void DBusCallbackFalse(const BoolDBusMethodCallback& callback) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false)); -} - -void DBusCallbackTrue(const BoolDBusMethodCallback& callback) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); -} - -void DBusCallbackFail(const BoolDBusMethodCallback& callback) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_FAILURE, false)); -} - void AsyncCallbackFalse(cryptohome::AsyncMethodCaller::Callback callback) { callback.Run(false, cryptohome::MOUNT_ERROR_NONE); } -class FakeDBusData { - public: - explicit FakeDBusData(const std::string& data) : data_(data) {} - - void operator() (const CryptohomeClient::DataMethodCallback& callback) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true, data_)); - } - - private: - std::string data_; -}; - } // namespace class AttestationFlowTest : public testing::Test { @@ -105,14 +75,9 @@ Sequence flow_order; // Use DBusCallbackFalse so the full enrollment flow is triggered. - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .InSequence(flow_order) - .WillRepeatedly(Invoke(DBusCallbackFalse)); - - EXPECT_CALL(client, TpmAttestationIsPrepared(_)) - .InSequence(flow_order) - .WillOnce(Invoke(DBusCallbackTrue)); + chromeos::FakeCryptohomeClient client; + client.set_tpm_attestation_is_enrolled(false); + client.set_tpm_attestation_is_prepared(true); // Use StrictMock when we want to verify invocation frequency. StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; @@ -185,17 +150,21 @@ // Verify the order of calls in a sequence. Sequence flow_order; - // Use DBusCallbackFalse so the full enrollment flow is triggered. - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .InSequence(flow_order) - .WillRepeatedly(Invoke(DBusCallbackFalse)); + // Custom FakeCryptohomeClient to emulate a situation where it takes a bit + // for attestation to be prepared. + class FakeCryptohomeClient : public chromeos::FakeCryptohomeClient { + public: + void TpmAttestationIsPrepared( + const BoolDBusMethodCallback& callback) override { + chromeos::FakeCryptohomeClient::TpmAttestationIsPrepared(callback); + // Second call (and later), returns true. + set_tpm_attestation_is_prepared(true); + } + }; - // It will take a bit for attestation to be prepared. - EXPECT_CALL(client, TpmAttestationIsPrepared(_)) - .InSequence(flow_order) - .WillOnce(Invoke(DBusCallbackFalse)) - .WillOnce(Invoke(DBusCallbackTrue)); + FakeCryptohomeClient client; + client.set_tpm_attestation_is_enrolled(false); + client.set_tpm_attestation_is_prepared(false); // Use StrictMock when we want to verify invocation frequency. StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; @@ -265,12 +234,9 @@ StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; async_caller.SetUp(false, cryptohome::MOUNT_ERROR_NONE); - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackFalse)); - - EXPECT_CALL(client, TpmAttestationIsPrepared(_)) - .WillRepeatedly(Invoke(DBusCallbackFalse)); + chromeos::FakeCryptohomeClient client; + client.set_tpm_attestation_is_enrolled(false); + client.set_tpm_attestation_is_prepared(false); // We're not expecting any server calls in this case; StrictMock will verify. std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); @@ -299,12 +265,9 @@ EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_, _)) .Times(1); - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackFalse)); - - EXPECT_CALL(client, TpmAttestationIsPrepared(_)) - .WillOnce(Invoke(DBusCallbackTrue)); + chromeos::FakeCryptohomeClient client; + client.set_tpm_attestation_is_enrolled(false); + client.set_tpm_attestation_is_prepared(true); // We're not expecting any server calls in this case; StrictMock will verify. std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); @@ -330,12 +293,9 @@ EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_, _)) .Times(1); - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackFalse)); - - EXPECT_CALL(client, TpmAttestationIsPrepared(_)) - .WillOnce(Invoke(DBusCallbackTrue)); + chromeos::FakeCryptohomeClient client; + client.set_tpm_attestation_is_enrolled(false); + client.set_tpm_attestation_is_prepared(true); std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); proxy->DeferToFake(false); @@ -370,12 +330,9 @@ AsyncTpmAttestationEnroll(_, fake_enroll_response, _)) .WillOnce(WithArgs<2>(Invoke(AsyncCallbackFalse))); - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackFalse)); - - EXPECT_CALL(client, TpmAttestationIsPrepared(_)) - .WillOnce(Invoke(DBusCallbackTrue)); + chromeos::FakeCryptohomeClient client; + client.set_tpm_attestation_is_enrolled(false); + client.set_tpm_attestation_is_prepared(true); std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); proxy->DeferToFake(true); @@ -413,9 +370,7 @@ kEnterpriseMachineKey, _)) .Times(1); - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackTrue)); + chromeos::FakeCryptohomeClient client; std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); proxy->DeferToFake(true); @@ -447,9 +402,7 @@ cryptohome::Identification(), "", _)) .Times(1); - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackTrue)); + chromeos::FakeCryptohomeClient client; // We're not expecting any server calls in this case; StrictMock will verify. std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); @@ -476,9 +429,7 @@ cryptohome::Identification(), "", _)) .Times(1); - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackTrue)); + chromeos::FakeCryptohomeClient client; std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); proxy->DeferToFake(false); @@ -504,9 +455,8 @@ // We're not expecting any async calls in this case; StrictMock will verify. StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackFail)); + chromeos::FakeCryptohomeClient client; + client.SetServiceIsAvailable(false); // We're not expecting any server calls in this case; StrictMock will verify. std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); @@ -541,13 +491,7 @@ kEnterpriseUserKey, _)) .Times(1); - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackTrue)); - EXPECT_CALL(client, - TpmAttestationDoesKeyExist(KEY_USER, cryptohome::Identification(), - kEnterpriseUserKey, _)) - .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackFalse))); + chromeos::FakeCryptohomeClient client; std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); proxy->DeferToFake(true); @@ -575,17 +519,9 @@ // We're not expecting any async calls in this case; StrictMock will verify. StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackTrue)); - EXPECT_CALL(client, - TpmAttestationDoesKeyExist(KEY_USER, cryptohome::Identification(), - kEnterpriseUserKey, _)) - .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackTrue))); - EXPECT_CALL(client, TpmAttestationGetCertificate(KEY_USER, - cryptohome::Identification(), - kEnterpriseUserKey, _)) - .WillRepeatedly(WithArgs<3>(Invoke(FakeDBusData("fake_cert")))); + chromeos::FakeCryptohomeClient client; + client.SetTpmAttestationUserCertificate(cryptohome::Identification(), + kEnterpriseUserKey, "fake_cert"); // We're not expecting any server calls in this case; StrictMock will verify. std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); @@ -611,12 +547,9 @@ proxy->DeferToFake(true); EXPECT_CALL(*proxy, GetType()).WillRepeatedly(Return(ALTERNATE_PCA)); - chromeos::MockCryptohomeClient client; - EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) - .WillRepeatedly(Invoke(DBusCallbackFalse)); - - EXPECT_CALL(client, TpmAttestationIsPrepared(_)) - .WillRepeatedly(Invoke(DBusCallbackTrue)); + chromeos::FakeCryptohomeClient client; + client.set_tpm_attestation_is_enrolled(false); + client.set_tpm_attestation_is_prepared(true); NiceMock<cryptohome::MockAsyncMethodCaller> async_caller; async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
diff --git a/chromeos/components/tether/ble_advertiser.cc b/chromeos/components/tether/ble_advertiser.cc index f48087e..beb1555 100644 --- a/chromeos/components/tether/ble_advertiser.cc +++ b/chromeos/components/tether/ble_advertiser.cc
@@ -25,12 +25,21 @@ BleAdvertiser::IndividualAdvertisement::IndividualAdvertisement( const std::string& device_id, scoped_refptr<device::BluetoothAdapter> adapter, - std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data) + std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data, + const base::Closure& on_unregister_advertisement_success_callback, + const base::Callback<void(device::BluetoothAdvertisement::ErrorCode)>& + on_unregister_advertisement_error_callback, + std::unordered_set<std::string>* active_advertisement_device_ids_set) : device_id_(device_id), adapter_(adapter), advertisement_data_(std::move(advertisement_data)), is_initializing_advertising_(false), advertisement_(nullptr), + on_unregister_advertisement_success_callback_( + on_unregister_advertisement_success_callback), + on_unregister_advertisement_error_callback_( + on_unregister_advertisement_error_callback), + active_advertisement_device_ids_set_(active_advertisement_device_ids_set), weak_ptr_factory_(this) { adapter_->AddObserver(this); AdvertiseIfPossible(); @@ -38,15 +47,20 @@ BleAdvertiser::IndividualAdvertisement::~IndividualAdvertisement() { if (advertisement_) { - advertisement_->Unregister( - base::Bind(&base::DoNothing), - base::Bind(&IndividualAdvertisement::OnAdvertisementUnregisterFailure, - weak_ptr_factory_.GetWeakPtr())); + advertisement_->Unregister(on_unregister_advertisement_success_callback_, + on_unregister_advertisement_error_callback_); } adapter_->RemoveObserver(this); } +void BleAdvertiser::IndividualAdvertisement:: + OnPreviousAdvertisementUnregistered() { + DCHECK(active_advertisement_device_ids_set_->find(device_id_) == + active_advertisement_device_ids_set_->end()); + AdvertiseIfPossible(); +} + void BleAdvertiser::IndividualAdvertisement::AdapterPoweredChanged( device::BluetoothAdapter* adapter, bool powered) { @@ -60,13 +74,21 @@ // If the advertisement was released, delete it and try again. Note that this // situation is not expected to occur under normal circumstances. + advertisement_->RemoveObserver(this); advertisement_ = nullptr; + active_advertisement_device_ids_set_->erase(device_id_); + AdvertiseIfPossible(); } void BleAdvertiser::IndividualAdvertisement::AdvertiseIfPossible() { if (!adapter_->IsPowered() || is_initializing_advertising_ || - advertisement_) { + advertisement_ || + active_advertisement_device_ids_set_->find(device_id_) != + active_advertisement_device_ids_set_->end()) { + // It is not possible to advertise if the adapter is not powered. Likewise, + // we should not try to advertise if there is an advertisement already in + // progress. return; } @@ -90,7 +112,11 @@ void BleAdvertiser::IndividualAdvertisement::OnAdvertisementRegisteredCallback( scoped_refptr<device::BluetoothAdvertisement> advertisement) { is_initializing_advertising_ = false; + advertisement_ = advertisement; + advertisement_->AddObserver(this); + active_advertisement_device_ids_set_->insert(device_id_); + PA_LOG(INFO) << "Advertisement registered. " << "Device ID: \"" << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id_) @@ -107,15 +133,6 @@ << ", Error code: " << error_code; } -void BleAdvertiser::IndividualAdvertisement::OnAdvertisementUnregisterFailure( - device::BluetoothAdvertisement::ErrorCode error_code) { - PA_LOG(ERROR) << "Error unregistering advertisement. " - << "Device ID: \"" - << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id_) - << "\", Service data: " << advertisement_data_->DataInHex() - << " Error code: " << error_code; -} - std::unique_ptr<device::BluetoothAdvertisement::UUIDList> BleAdvertiser::IndividualAdvertisement::CreateServiceUuids() const { std::unique_ptr<device::BluetoothAdvertisement::UUIDList> list = @@ -162,11 +179,13 @@ : adapter_(adapter), eid_generator_(std::move(eid_generator)), remote_beacon_seed_fetcher_(remote_beacon_seed_fetcher), - local_device_data_provider_(local_device_data_provider) {} + local_device_data_provider_(local_device_data_provider), + weak_ptr_factory_(this) {} bool BleAdvertiser::StartAdvertisingToDevice( const cryptauth::RemoteDevice& remote_device) { - if (device_id_to_advertisement_map_.size() >= kMaxConcurrentAdvertisements) { + if (device_id_to_individual_advertisement_map_.size() >= + kMaxConcurrentAdvertisements) { PA_LOG(ERROR) << "Attempted to register a device when the maximum number " << "of devices have already been registered."; return false; @@ -208,15 +227,52 @@ return false; } - device_id_to_advertisement_map_[remote_device.GetDeviceId()] = + std::string device_id = remote_device.GetDeviceId(); + device_id_to_individual_advertisement_map_[device_id] = base::MakeUnique<IndividualAdvertisement>( - remote_device.GetDeviceId(), adapter_, std::move(advertisement)); + remote_device.GetDeviceId(), adapter_, std::move(advertisement), + base::Bind(&BleAdvertiser::OnUnregisterAdvertisementSuccess, + weak_ptr_factory_.GetWeakPtr(), device_id), + base::Bind(&BleAdvertiser::OnUnregisterAdvertisementError, + weak_ptr_factory_.GetWeakPtr(), device_id), + &active_advertisement_device_ids_set_); return true; } bool BleAdvertiser::StopAdvertisingToDevice( const cryptauth::RemoteDevice& remote_device) { - return device_id_to_advertisement_map_.erase(remote_device.GetDeviceId()) > 0; + return device_id_to_individual_advertisement_map_.erase( + remote_device.GetDeviceId()) > 0; +} + +void BleAdvertiser::OnUnregisterAdvertisementSuccess( + const std::string& associated_device_id) { + RemoveAdvertisingDeviceIdAndRetry(associated_device_id); +} + +void BleAdvertiser::OnUnregisterAdvertisementError( + const std::string& associated_device_id, + device::BluetoothAdvertisement::ErrorCode error_code) { + PA_LOG(ERROR) << "Error unregistering advertisement. " + << "Device ID: \"" + << cryptauth::RemoteDevice::TruncateDeviceIdForLogs( + associated_device_id) + << "\", Error code: " << error_code; + + // Even though there was an error unregistering the advertisement, remove it + // from the set anyway so that it is possible to try registering the + // advertisement again. Note that this situation is not expected to occur + // since unregistering an active advertisement should always succeed. + RemoveAdvertisingDeviceIdAndRetry(associated_device_id); +} + +void BleAdvertiser::RemoveAdvertisingDeviceIdAndRetry( + const std::string& device_id) { + active_advertisement_device_ids_set_.erase(device_id); + + auto it = device_id_to_individual_advertisement_map_.find(device_id); + if (it != device_id_to_individual_advertisement_map_.end()) + it->second->OnPreviousAdvertisementUnregistered(); } } // namespace tether
diff --git a/chromeos/components/tether/ble_advertiser.h b/chromeos/components/tether/ble_advertiser.h index 590b86e..a1211b2 100644 --- a/chromeos/components/tether/ble_advertiser.h +++ b/chromeos/components/tether/ble_advertiser.h
@@ -6,7 +6,9 @@ #define CHROMEOS_COMPONENTS_TETHER_BLE_ADVERTISER_H_ #include <map> +#include <unordered_set> +#include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "components/cryptauth/foreground_eid_generator.h" @@ -44,6 +46,17 @@ private: friend class BleAdvertiserTest; + // One IndividualAdvertisement is created for each device to which + // BleAdvertiser should be advertising. When an IndividualAdvertisement is + // created, it starts trying to advertise to its associated device ID; + // likewise, when it is destroyed, it stops advertising if necessary. + // + // However, because unregistering an advertisement is an asynchronous + // operation, it is possible that if an IndividualAdvertisement for one device + // is created just after another IndividualAdvertisement for the same device + // was destroyed, the previous advertisement was not fully unregistered. + // If that is the case, the newly-created IndividualAdvertisement must wait + // until OnPreviousAdvertisementUnregistered() is called. class IndividualAdvertisement : public device::BluetoothAdapter::Observer, public device::BluetoothAdvertisement::Observer { @@ -51,9 +64,17 @@ IndividualAdvertisement( const std::string& device_id, scoped_refptr<device::BluetoothAdapter> adapter, - std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data); + std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data, + const base::Closure& on_unregister_advertisement_success_callback, + const base::Callback<void(device::BluetoothAdvertisement::ErrorCode)>& + on_unregister_advertisement_error_callback, + std::unordered_set<std::string>* active_advertisement_device_ids_set); ~IndividualAdvertisement() override; + // Callback for when a previously-registered advertisement corresponding to + // |device_id_| has been unregistered. + void OnPreviousAdvertisementUnregistered(); + // device::BluetoothAdapter::Observer void AdapterPoweredChanged(device::BluetoothAdapter* adapter, bool powered) override; @@ -85,6 +106,11 @@ bool is_initializing_advertising_; scoped_refptr<device::BluetoothAdvertisement> advertisement_; + base::Closure on_unregister_advertisement_success_callback_; + base::Callback<void(device::BluetoothAdvertisement::ErrorCode)> + on_unregister_advertisement_error_callback_; + std::unordered_set<std::string>* active_advertisement_device_ids_set_; + base::WeakPtrFactory<IndividualAdvertisement> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(IndividualAdvertisement); @@ -96,6 +122,13 @@ const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher, const cryptauth::LocalDeviceDataProvider* local_device_data_provider); + void OnUnregisterAdvertisementSuccess( + const std::string& associated_device_id); + void OnUnregisterAdvertisementError( + const std::string& associated_device_id, + device::BluetoothAdvertisement::ErrorCode error_code); + void RemoveAdvertisingDeviceIdAndRetry(const std::string& device_id); + scoped_refptr<device::BluetoothAdapter> adapter_; std::unique_ptr<cryptauth::ForegroundEidGenerator> eid_generator_; @@ -104,7 +137,10 @@ const cryptauth::LocalDeviceDataProvider* local_device_data_provider_; std::map<std::string, std::unique_ptr<IndividualAdvertisement>> - device_id_to_advertisement_map_; + device_id_to_individual_advertisement_map_; + std::unordered_set<std::string> active_advertisement_device_ids_set_; + + base::WeakPtrFactory<BleAdvertiser> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(BleAdvertiser); };
diff --git a/chromeos/components/tether/ble_advertiser_unittest.cc b/chromeos/components/tether/ble_advertiser_unittest.cc index d9676ce8..2b2ff64c 100644 --- a/chromeos/components/tether/ble_advertiser_unittest.cc +++ b/chromeos/components/tether/ble_advertiser_unittest.cc
@@ -4,6 +4,8 @@ #include "chromeos/components/tether/ble_advertiser.h" +#include "base/bind.h" +#include "base/callback_forward.h" #include "base/logging.h" #include "chromeos/components/tether/ble_constants.h" #include "components/cryptauth/mock_foreground_eid_generator.h" @@ -11,8 +13,8 @@ #include "components/cryptauth/mock_remote_beacon_seed_fetcher.h" #include "components/cryptauth/proto/cryptauth_api.pb.h" #include "components/cryptauth/remote_device_test_util.h" +#include "device/bluetooth/bluetooth_advertisement.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h" -#include "device/bluetooth/test/mock_bluetooth_advertisement.h" #include "testing/gtest/include/gtest/gtest.h" using testing::Invoke; @@ -80,6 +82,33 @@ ~MockBluetoothAdapterWithAdvertisements() override {} }; +class FakeBluetoothAdvertisement : public device::BluetoothAdvertisement { + public: + // |unregister_callback| should be called with the success callback passed to + // Unregister() whenever an Unregister() call occurs. + FakeBluetoothAdvertisement( + const base::Callback< + void(const device::BluetoothAdvertisement::SuccessCallback&)>& + unregister_callback) + : unregister_callback_(unregister_callback) {} + + // BluetoothAdvertisement: + void Unregister( + const device::BluetoothAdvertisement::SuccessCallback& success_callback, + const device::BluetoothAdvertisement::ErrorCallback& error_callback) + override { + unregister_callback_.Run(success_callback); + } + + private: + ~FakeBluetoothAdvertisement() override {} + + base::Callback<void(const device::BluetoothAdvertisement::SuccessCallback&)> + unregister_callback_; + + DISALLOW_COPY_AND_ASSIGN(FakeBluetoothAdvertisement); +}; + std::vector<cryptauth::DataWithTimestamp> GenerateFakeAdvertisements() { cryptauth::DataWithTimestamp advertisement1("advertisement1", 1000L, 2000L); cryptauth::DataWithTimestamp advertisement2("advertisement2", 2000L, 3000L); @@ -163,7 +192,7 @@ ble_advertiser_.reset(); // All observers should have been removed. - EXPECT_FALSE(individual_advertisements_.size()); + EXPECT_TRUE(individual_advertisements_.empty()); } void OnAdapterAddObserver(device::BluetoothAdapter::Observer* observer) { @@ -186,11 +215,11 @@ scoped_refptr<RegisterAdvertisementArgs> args, const BleAdvertiser::IndividualAdvertisement* advertisement) { // First, verify that the service UUID list is correct. - EXPECT_EQ(static_cast<size_t>(1), args->service_uuids.size()); + EXPECT_EQ(1u, args->service_uuids.size()); EXPECT_EQ(std::string(kAdvertisingServiceUuid), args->service_uuids[0]); // Then, verify that the service data is correct. - EXPECT_EQ(static_cast<size_t>(1), args->service_data.size()); + EXPECT_EQ(1u, args->service_data.size()); std::vector<uint8_t> service_data_from_args = args->service_data[std::string(kAdvertisingServiceUuid)]; EXPECT_EQ(service_data_from_args.size(), @@ -218,8 +247,9 @@ } void InvokeCallback(scoped_refptr<RegisterAdvertisementArgs> args) { - args->callback.Run( - make_scoped_refptr(new device::MockBluetoothAdvertisement)); + args->callback.Run(make_scoped_refptr(new FakeBluetoothAdvertisement( + base::Bind(&BleAdvertiserTest::OnAdvertisementUnregistered, + base::Unretained(this))))); } void ReleaseAdvertisement( @@ -228,6 +258,18 @@ individual_advertisement->advertisement_.get()); } + void OnAdvertisementUnregistered( + const device::BluetoothAdvertisement::SuccessCallback& success_callback) { + unregister_callbacks_.push_back(success_callback); + } + + void InvokeLastUnregisterCallbackAndRemove() { + DCHECK(!unregister_callbacks_.empty()); + unregister_callbacks_[unregister_callbacks_.size() - 1].Run(); + unregister_callbacks_.erase(unregister_callbacks_.begin() + + unregister_callbacks_.size() - 1); + } + std::unique_ptr<BleAdvertiser> ble_advertiser_; scoped_refptr<StrictMock<MockBluetoothAdapterWithAdvertisements>> @@ -241,6 +283,8 @@ register_advertisement_args_; std::vector<BleAdvertiser::IndividualAdvertisement*> individual_advertisements_; + std::vector<device::BluetoothAdvertisement::SuccessCallback> + unregister_callbacks_; const std::vector<cryptauth::RemoteDevice> fake_devices_; const std::vector<cryptauth::DataWithTimestamp> fake_advertisements_; @@ -299,10 +343,10 @@ base::MakeUnique<cryptauth::DataWithTimestamp>(fake_advertisements_[0])); EXPECT_TRUE(ble_advertiser_->StartAdvertisingToDevice(fake_devices_[0])); - EXPECT_EQ(static_cast<size_t>(1), individual_advertisements_.size()); + EXPECT_EQ(1u, individual_advertisements_.size()); // RegisterAdvertisement() should not have been called. - EXPECT_FALSE(register_advertisement_args_.size()); + EXPECT_TRUE(register_advertisement_args_.empty()); } TEST_F(BleAdvertiserTest, RegisteringAdvertisementFails) { @@ -315,8 +359,8 @@ base::MakeUnique<cryptauth::DataWithTimestamp>(fake_advertisements_[0])); EXPECT_TRUE(ble_advertiser_->StartAdvertisingToDevice(fake_devices_[0])); - EXPECT_EQ(static_cast<size_t>(1), individual_advertisements_.size()); - EXPECT_EQ(static_cast<size_t>(1), register_advertisement_args_.size()); + EXPECT_EQ(1u, individual_advertisements_.size()); + EXPECT_EQ(1u, register_advertisement_args_.size()); VerifyServiceDataMatches(register_advertisement_args_[0], individual_advertisements_[0]); @@ -334,8 +378,8 @@ base::MakeUnique<cryptauth::DataWithTimestamp>(fake_advertisements_[0])); EXPECT_TRUE(ble_advertiser_->StartAdvertisingToDevice(fake_devices_[0])); - EXPECT_EQ(static_cast<size_t>(1), individual_advertisements_.size()); - EXPECT_EQ(static_cast<size_t>(1), register_advertisement_args_.size()); + EXPECT_EQ(1u, individual_advertisements_.size()); + EXPECT_EQ(1u, register_advertisement_args_.size()); VerifyServiceDataMatches(register_advertisement_args_[0], individual_advertisements_[0]); @@ -344,7 +388,8 @@ // Now, unregister. EXPECT_TRUE(ble_advertiser_->StopAdvertisingToDevice(fake_devices_[0])); - EXPECT_FALSE(individual_advertisements_.size()); + InvokeLastUnregisterCallbackAndRemove(); + EXPECT_TRUE(individual_advertisements_.empty()); } TEST_F(BleAdvertiserTest, AdvertisementRegisteredSuccessfully_TwoDevices) { @@ -358,8 +403,8 @@ base::MakeUnique<cryptauth::DataWithTimestamp>(fake_advertisements_[0])); EXPECT_TRUE(ble_advertiser_->StartAdvertisingToDevice(fake_devices_[0])); - EXPECT_EQ(static_cast<size_t>(1), individual_advertisements_.size()); - EXPECT_EQ(static_cast<size_t>(1), register_advertisement_args_.size()); + EXPECT_EQ(1u, individual_advertisements_.size()); + EXPECT_EQ(1u, register_advertisement_args_.size()); VerifyServiceDataMatches(register_advertisement_args_[0], individual_advertisements_[0]); @@ -371,8 +416,8 @@ base::MakeUnique<cryptauth::DataWithTimestamp>(fake_advertisements_[1])); EXPECT_TRUE(ble_advertiser_->StartAdvertisingToDevice(fake_devices_[1])); - EXPECT_EQ(static_cast<size_t>(2), individual_advertisements_.size()); - EXPECT_EQ(static_cast<size_t>(2), register_advertisement_args_.size()); + EXPECT_EQ(2u, individual_advertisements_.size()); + EXPECT_EQ(2u, register_advertisement_args_.size()); VerifyServiceDataMatches(register_advertisement_args_[1], individual_advertisements_[1]); @@ -382,9 +427,11 @@ // Now, unregister. EXPECT_TRUE(ble_advertiser_->StopAdvertisingToDevice(fake_devices_[0])); EXPECT_EQ(1u, individual_advertisements_.size()); + InvokeLastUnregisterCallbackAndRemove(); EXPECT_TRUE(ble_advertiser_->StopAdvertisingToDevice(fake_devices_[1])); - EXPECT_EQ(0u, individual_advertisements_.size()); + EXPECT_TRUE(individual_advertisements_.empty()); + InvokeLastUnregisterCallbackAndRemove(); } TEST_F(BleAdvertiserTest, TooManyDevicesRegistered) { @@ -424,17 +471,17 @@ base::MakeUnique<cryptauth::DataWithTimestamp>(fake_advertisements_[0])); EXPECT_TRUE(ble_advertiser_->StartAdvertisingToDevice(fake_devices_[0])); - EXPECT_EQ(static_cast<size_t>(1), individual_advertisements_.size()); + EXPECT_EQ(1u, individual_advertisements_.size()); // RegisterAdvertisement() should not have been called. - EXPECT_FALSE(register_advertisement_args_.size()); + EXPECT_TRUE(register_advertisement_args_.empty()); // Now, simulate power being changed. Since the power is now on, // RegisterAdvertisement() should have been called. individual_advertisements_[0]->AdapterPoweredChanged(mock_adapter_.get(), true); - EXPECT_EQ(static_cast<size_t>(1), individual_advertisements_.size()); - EXPECT_EQ(static_cast<size_t>(1), register_advertisement_args_.size()); + EXPECT_EQ(1u, individual_advertisements_.size()); + EXPECT_EQ(1u, register_advertisement_args_.size()); VerifyServiceDataMatches(register_advertisement_args_[0], individual_advertisements_[0]); } @@ -449,8 +496,8 @@ base::MakeUnique<cryptauth::DataWithTimestamp>(fake_advertisements_[0])); EXPECT_TRUE(ble_advertiser_->StartAdvertisingToDevice(fake_devices_[0])); - EXPECT_EQ(static_cast<size_t>(1), individual_advertisements_.size()); - EXPECT_EQ(static_cast<size_t>(1), register_advertisement_args_.size()); + EXPECT_EQ(1u, individual_advertisements_.size()); + EXPECT_EQ(1u, register_advertisement_args_.size()); VerifyServiceDataMatches(register_advertisement_args_[0], individual_advertisements_[0]); @@ -460,7 +507,7 @@ // Now, simulate the advertisement being released. A new advertisement should // have been created. ReleaseAdvertisement(individual_advertisements_[0]); - EXPECT_EQ(static_cast<size_t>(2), register_advertisement_args_.size()); + EXPECT_EQ(2u, register_advertisement_args_.size()); VerifyServiceDataMatches(register_advertisement_args_[1], individual_advertisements_[0]); @@ -469,7 +516,60 @@ // Now, unregister. EXPECT_TRUE(ble_advertiser_->StopAdvertisingToDevice(fake_devices_[0])); - EXPECT_FALSE(individual_advertisements_.size()); + InvokeLastUnregisterCallbackAndRemove(); + EXPECT_TRUE(individual_advertisements_.empty()); +} + +// Regression test for crbug.com/739883. This issue arises when the following +// occurs: +// (1) BleAdvertiser starts advertising to device A. +// (2) BleAdvertiser stops advertising to device A. The advertisement starts +// its asynchyronous unregistration flow. +// (3) BleAdvertiser starts advertising to device A again, but the previous +// advertisement has not yet been fully unregistered. +// Before the fix for crbug.com/739883, this would cause an error of type +// ERROR_ADVERTISEMENT_ALREADY_EXISTS. However, the fix for this issue ensures +// that the new advertisement in step (3) above does not start until the +// previous one has been finished. +TEST_F(BleAdvertiserTest, SameAdvertisementAdded_FirstHasNotBeenUnregistered) { + EXPECT_CALL(*mock_adapter_, AddObserver(_)).Times(2); + EXPECT_CALL(*mock_adapter_, RemoveObserver(_)).Times(2); + EXPECT_CALL(*mock_adapter_, IsPowered()).Times(3); + EXPECT_CALL(*mock_adapter_, RegisterAdvertisementWithArgsStruct(_)).Times(2); + + mock_eid_generator_->set_advertisement( + base::MakeUnique<cryptauth::DataWithTimestamp>(fake_advertisements_[0])); + + EXPECT_TRUE(ble_advertiser_->StartAdvertisingToDevice(fake_devices_[0])); + EXPECT_EQ(1u, individual_advertisements_.size()); + EXPECT_EQ(1u, register_advertisement_args_.size()); + VerifyServiceDataMatches(register_advertisement_args_[0], + individual_advertisements_[0]); + + InvokeCallback(register_advertisement_args_[0]); + VerifyAdvertisementHasStarted(individual_advertisements_[0]); + + // Unregister, but do not invoke the last unregister callback. + EXPECT_TRUE(ble_advertiser_->StopAdvertisingToDevice(fake_devices_[0])); + EXPECT_TRUE(individual_advertisements_.empty()); + + // Start advertising again, to the same device. A new IndividualAdvertisement + // should have been created, but a call to RegisterAdvertisement() should NOT + // have occurred, since the previous advertisement has not yet been + // unregistered. + EXPECT_TRUE(ble_advertiser_->StartAdvertisingToDevice(fake_devices_[0])); + EXPECT_EQ(1u, individual_advertisements_.size()); + // Should still be only one set of RegisterAdvertisement() args. + EXPECT_EQ(1u, register_advertisement_args_.size()); + + // Now, complete the previous unregistration. + InvokeLastUnregisterCallbackAndRemove(); + + // RegisterAdvertisement() should be called for the new advertisement. + EXPECT_EQ(2u, register_advertisement_args_.size()); + + VerifyServiceDataMatches(register_advertisement_args_[1], + individual_advertisements_[0]); } } // namespace tether
diff --git a/chromeos/dbus/fake_cryptohome_client.cc b/chromeos/dbus/fake_cryptohome_client.cc index 974676f..ba222d1 100644 --- a/chromeos/dbus/fake_cryptohome_client.cc +++ b/chromeos/dbus/fake_cryptohome_client.cc
@@ -7,7 +7,7 @@ #include <stddef.h> #include <stdint.h> -#include <utility> +#include <tuple> #include "base/bind.h" #include "base/command_line.h" @@ -15,6 +15,7 @@ #include "base/location.h" #include "base/path_service.h" #include "base/single_thread_task_runner.h" +#include "base/stl_util.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" #include "chromeos/attestation/attestation.pb.h" @@ -379,13 +380,17 @@ void FakeCryptohomeClient::TpmAttestationIsPrepared( const BoolDBusMethodCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); + FROM_HERE, base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS, + tpm_attestation_is_prepared_)); } void FakeCryptohomeClient::TpmAttestationIsEnrolled( const BoolDBusMethodCallback& callback) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); + auto task = service_is_available_ + ? base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS, + tpm_attestation_is_enrolled_) + : base::BindOnce(callback, DBUS_METHOD_CALL_FAILURE, false); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task)); } void FakeCryptohomeClient::AsyncTpmAttestationCreateEnrollRequest( @@ -424,8 +429,14 @@ const cryptohome::Identification& cryptohome_id, const std::string& key_name, const BoolDBusMethodCallback& callback) { + bool result = false; + if (key_type == attestation::KEY_USER) { + result = base::ContainsKey(user_certificate_map_, + std::make_pair(cryptohome_id, key_name)); + } + base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false)); + FROM_HERE, base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS, result)); } void FakeCryptohomeClient::TpmAttestationGetCertificate( @@ -433,9 +444,19 @@ const cryptohome::Identification& cryptohome_id, const std::string& key_name, const DataMethodCallback& callback) { + bool result = false; + std::string certificate; + if (key_type == attestation::KEY_USER) { + const auto it = user_certificate_map_.find({cryptohome_id, key_name}); + if (it != user_certificate_map_.end()) { + result = true; + certificate = it->second; + } + } + base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, - base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false, std::string())); + base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS, result, certificate)); } void FakeCryptohomeClient::TpmAttestationGetPublicKey( @@ -515,7 +536,7 @@ const cryptohome::GetKeyDataRequest& request, const ProtobufMethodCallback& callback) { cryptohome::BaseReply reply; - auto it = key_data_map_.find(cryptohome_id); + const auto it = key_data_map_.find(cryptohome_id); if (it == key_data_map_.end()) { reply.set_error(cryptohome::CRYPTOHOME_ERROR_ACCOUNT_NOT_FOUND); } else { @@ -646,6 +667,15 @@ } } +void FakeCryptohomeClient::SetTpmAttestationUserCertificate( + const cryptohome::Identification& cryptohome_id, + const std::string& key_name, + const std::string& certificate) { + user_certificate_map_.emplace(std::piecewise_construct, + std::forward_as_tuple(cryptohome_id, key_name), + std::forward_as_tuple(certificate)); +} + // static std::vector<uint8_t> FakeCryptohomeClient::GetStubSystemSalt() { const char kStubSystemSalt[] = "stub_system_salt";
diff --git a/chromeos/dbus/fake_cryptohome_client.h b/chromeos/dbus/fake_cryptohome_client.h index 32671a2d..673fe579 100644 --- a/chromeos/dbus/fake_cryptohome_client.h +++ b/chromeos/dbus/fake_cryptohome_client.h
@@ -9,6 +9,7 @@ #include <map> #include <string> +#include <utility> #include <vector> #include "base/macros.h" @@ -236,6 +237,19 @@ needs_dircrypto_migration_ = needs_migration; } + void set_tpm_attestation_is_enrolled(bool enrolled) { + tpm_attestation_is_enrolled_ = enrolled; + } + + void set_tpm_attestation_is_prepared(bool prepared) { + tpm_attestation_is_prepared_ = prepared; + } + + void SetTpmAttestationUserCertificate( + const cryptohome::Identification& cryptohome_id, + const std::string& key_name, + const std::string& certificate); + private: void ReturnProtobufMethodCallback( const cryptohome::BaseReply& reply, @@ -276,11 +290,17 @@ std::map<cryptohome::Identification, cryptohome::KeyData> key_data_map_; + // User attestation certificate mapped by cryptohome_id and key_name. + std::map<std::pair<cryptohome::Identification, std::string>, std::string> + user_certificate_map_; + DircryptoMigrationProgessHandler dircrypto_migration_progress_handler_; base::RepeatingTimer dircrypto_migration_progress_timer_; uint64_t dircrypto_migration_progress_; bool needs_dircrypto_migration_ = false; + bool tpm_attestation_is_enrolled_ = true; + bool tpm_attestation_is_prepared_ = true; base::WeakPtrFactory<FakeCryptohomeClient> weak_ptr_factory_;
diff --git a/components/cronet/ios/BUILD.gn b/components/cronet/ios/BUILD.gn index 3244295..3227d03 100644 --- a/components/cronet/ios/BUILD.gn +++ b/components/cronet/ios/BUILD.gn
@@ -59,6 +59,7 @@ "//components/prefs:prefs", "//ios/net:net", "//ios/web:user_agent", + "//ios/web/public/global_state", "//net", "//url", ]
diff --git a/components/cronet/ios/DEPS b/components/cronet/ios/DEPS index 60c6da07..ea7d66e 100644 --- a/components/cronet/ios/DEPS +++ b/components/cronet/ios/DEPS
@@ -1,4 +1,4 @@ include_rules = [ "+ios/net", - "+ios/web", + "+ios/web/public", ]
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm index dd3c96f..1688e6d 100644 --- a/components/cronet/ios/cronet_environment.mm +++ b/components/cronet/ios/cronet_environment.mm
@@ -22,12 +22,12 @@ #include "base/path_service.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/waitable_event.h" -#include "base/task_scheduler/task_scheduler.h" #include "components/cronet/histogram_manager.h" #include "components/cronet/ios/version.h" #include "components/prefs/json_pref_store.h" #include "components/prefs/pref_filter.h" #include "ios/net/cookies/cookie_store_ios.h" +#include "ios/web/public/global_state/ios_global_state.h" #include "ios/web/public/user_agent.h" #include "net/base/network_change_notifier.h" #include "net/cert/cert_verifier.h" @@ -118,7 +118,8 @@ if (!g_at_exit_) g_at_exit_ = new base::AtExitManager; - base::TaskScheduler::CreateAndStartWithDefaultParams("CronetIos"); + ios_global_state::Create(); + ios_global_state::StartTaskScheduler(/*init_params=*/nullptr); url::Initialize(); base::CommandLine::Init(0, nullptr);
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc index 865e8d84..050068e 100644 --- a/components/network_session_configurator/browser/network_session_configurator.cc +++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -233,9 +233,8 @@ return 0; } -net::QuicVersionVector GetQuicVersions( - const VariationParameters& quic_trial_params) { - return network_session_configurator::ParseQuicVersions( +net::QuicVersion GetQuicVersion(const VariationParameters& quic_trial_params) { + return network_session_configurator::ParseQuicVersion( GetVariationParam(quic_trial_params, "quic_version")); } @@ -307,35 +306,28 @@ params->quic_user_agent_id = quic_user_agent_id; - net::QuicVersionVector supported_versions = - GetQuicVersions(quic_trial_params); - if (!supported_versions.empty()) + net::QuicVersion version = GetQuicVersion(quic_trial_params); + if (version != net::QUIC_VERSION_UNSUPPORTED) { + net::QuicVersionVector supported_versions; + supported_versions.push_back(version); params->quic_supported_versions = supported_versions; + } } } // anonymous namespace namespace network_session_configurator { -net::QuicVersionVector ParseQuicVersions(const std::string& quic_versions) { - net::QuicVersionVector supported_versions; - net::QuicVersionVector all_supported_versions = net::AllSupportedVersions(); - - for (const base::StringPiece& version : base::SplitStringPiece( - quic_versions, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { - auto it = all_supported_versions.begin(); - while (it != all_supported_versions.end()) { - if (net::QuicVersionToString(*it) == version) { - supported_versions.push_back(*it); - // Remove the supported version to deduplicate versions extracted from - // |quic_versions|. - all_supported_versions.erase(it); - continue; - } - it++; +net::QuicVersion ParseQuicVersion(const std::string& quic_version) { + net::QuicVersionVector supported_versions = net::AllSupportedVersions(); + for (size_t i = 0; i < supported_versions.size(); ++i) { + net::QuicVersion version = supported_versions[i]; + if (net::QuicVersionToString(version) == quic_version) { + return version; } } - return supported_versions; + + return net::QUIC_VERSION_UNSUPPORTED; } void ParseCommandLineAndFieldTrials(const base::CommandLine& command_line, @@ -386,11 +378,13 @@ } if (command_line.HasSwitch(switches::kQuicVersion)) { - net::QuicVersionVector supported_versions = - network_session_configurator::ParseQuicVersions( - command_line.GetSwitchValueASCII(switches::kQuicVersion)); - if (!supported_versions.empty()) + net::QuicVersion version = network_session_configurator::ParseQuicVersion( + command_line.GetSwitchValueASCII(switches::kQuicVersion)); + if (version != net::QUIC_VERSION_UNSUPPORTED) { + net::QuicVersionVector supported_versions; + supported_versions.push_back(version); params->quic_supported_versions = supported_versions; + } } if (command_line.HasSwitch(switches::kOriginToForceQuicOn)) {
diff --git a/components/network_session_configurator/browser/network_session_configurator.h b/components/network_session_configurator/browser/network_session_configurator.h index 69e064bf3..7c7f25d 100644 --- a/components/network_session_configurator/browser/network_session_configurator.h +++ b/components/network_session_configurator/browser/network_session_configurator.h
@@ -18,8 +18,9 @@ // Helper functions to configure HttpNetworkSession::Params based on field // trials and command line. -// Parse serialized QUIC versions string. -net::QuicVersionVector ParseQuicVersions(const std::string& quic_versions); +// Parse serialized QUIC version string. +// Return QUIC_VERSION_UNSUPPORTED on failure. +net::QuicVersion ParseQuicVersion(const std::string& quic_version); // Configure |params| based on field trials and command line, // and forcing (policy or other command line) arguments.
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc index b04421d..94e81d0 100644 --- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc +++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -306,42 +306,6 @@ } TEST_F(NetworkSessionConfiguratorTest, - MultipleQuicVersionFromFieldTrialParams) { - std::map<std::string, std::string> field_trial_params; - std::string quic_versions = - net::QuicVersionToString(net::AllSupportedVersions().front()) + "," + - net::QuicVersionToString(net::AllSupportedVersions().back()); - - field_trial_params["quic_version"] = quic_versions; - variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params); - base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled"); - - ParseFieldTrials(); - - net::QuicVersionVector supported_versions; - supported_versions.push_back(net::AllSupportedVersions().front()); - supported_versions.push_back(net::AllSupportedVersions().back()); - EXPECT_EQ(supported_versions, params_.quic_supported_versions); -} - -TEST_F(NetworkSessionConfiguratorTest, SameQuicVersionsFromFieldTrialParams) { - std::map<std::string, std::string> field_trial_params; - std::string quic_versions = - net::QuicVersionToString(net::AllSupportedVersions().front()) + "," + - net::QuicVersionToString(net::AllSupportedVersions().front()); - - field_trial_params["quic_version"] = quic_versions; - variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params); - base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled"); - - ParseFieldTrials(); - - net::QuicVersionVector supported_versions; - supported_versions.push_back(net::AllSupportedVersions().front()); - EXPECT_EQ(supported_versions, params_.quic_supported_versions); -} - -TEST_F(NetworkSessionConfiguratorTest, QuicConnectionOptionsFromFieldTrialParams) { std::map<std::string, std::string> field_trial_params; field_trial_params["connection_options"] = "TIME,TBBR,REJ";
diff --git a/components/payments/core/autofill_payment_instrument.cc b/components/payments/core/autofill_payment_instrument.cc index 2b096c3..86d98f0277 100644 --- a/components/payments/core/autofill_payment_instrument.cc +++ b/components/payments/core/autofill_payment_instrument.cc
@@ -80,7 +80,7 @@ weak_ptr_factory_.GetWeakPtr()); } -bool AutofillPaymentInstrument::IsCompleteForPayment() { +bool AutofillPaymentInstrument::IsCompleteForPayment() const { // COMPLETE or EXPIRED cards are considered valid for payment. The user will // be prompted to enter the new expiration at the CVC step. return autofill::GetCompletionStatusForCard(credit_card_, app_locale_, @@ -88,17 +88,17 @@ autofill::CREDIT_CARD_EXPIRED; } -bool AutofillPaymentInstrument::IsExactlyMatchingMerchantRequest() { +bool AutofillPaymentInstrument::IsExactlyMatchingMerchantRequest() const { return matches_merchant_card_type_exactly_; } -base::string16 AutofillPaymentInstrument::GetMissingInfoLabel() { +base::string16 AutofillPaymentInstrument::GetMissingInfoLabel() const { return autofill::GetCompletionMessageForCard( autofill::GetCompletionStatusForCard(credit_card_, app_locale_, billing_profiles_)); } -bool AutofillPaymentInstrument::IsValidForCanMakePayment() { +bool AutofillPaymentInstrument::IsValidForCanMakePayment() const { autofill::CreditCardCompletionStatus status = autofill::GetCompletionStatusForCard(credit_card_, app_locale_, billing_profiles_);
diff --git a/components/payments/core/autofill_payment_instrument.h b/components/payments/core/autofill_payment_instrument.h index 7ec5071..3600918 100644 --- a/components/payments/core/autofill_payment_instrument.h +++ b/components/payments/core/autofill_payment_instrument.h
@@ -41,10 +41,10 @@ // PaymentInstrument: void InvokePaymentApp(PaymentInstrument::Delegate* delegate) override; - bool IsCompleteForPayment() override; - bool IsExactlyMatchingMerchantRequest() override; - base::string16 GetMissingInfoLabel() override; - bool IsValidForCanMakePayment() override; + bool IsCompleteForPayment() const override; + bool IsExactlyMatchingMerchantRequest() const override; + base::string16 GetMissingInfoLabel() const override; + bool IsValidForCanMakePayment() const override; void RecordUse() override; base::string16 GetLabel() const override; base::string16 GetSublabel() const override;
diff --git a/components/payments/core/payment_instrument.h b/components/payments/core/payment_instrument.h index ecdc99e..24b1d14 100644 --- a/components/payments/core/payment_instrument.h +++ b/components/payments/core/payment_instrument.h
@@ -40,17 +40,17 @@ virtual void InvokePaymentApp(Delegate* delegate) = 0; // Returns whether the instrument is complete to be used as a payment method // without further editing. - virtual bool IsCompleteForPayment() = 0; + virtual bool IsCompleteForPayment() const = 0; // Returns whether the instrument is exactly matching all filters provided by // the merchant. For example, this can return "false" for unknown card types, // if the merchant requested only debit cards. - virtual bool IsExactlyMatchingMerchantRequest() = 0; + virtual bool IsExactlyMatchingMerchantRequest() const = 0; // Returns a message to indicate to the user what's missing for the instrument // to be complete for payment. - virtual base::string16 GetMissingInfoLabel() = 0; + virtual base::string16 GetMissingInfoLabel() const = 0; // Returns whether the instrument is valid for the purposes of responding to // canMakePayment. - virtual bool IsValidForCanMakePayment() = 0; + virtual bool IsValidForCanMakePayment() const = 0; // Records the use of this payment instrument. virtual void RecordUse() = 0; // Return the sub/label of payment instrument, to be displayed to the user.
diff --git a/components/safe_browsing/csd.proto b/components/safe_browsing/csd.proto index b561039..088d7b5 100644 --- a/components/safe_browsing/csd.proto +++ b/components/safe_browsing/csd.proto
@@ -521,6 +521,11 @@ // Deprecated. optional bool DEPRECATED_download_attribution_finch_enabled = 39 [deprecated = true]; + + // The Mac disk image code signature. + // The underlying structure of code signature is defined at + // https://opensource.apple.com/source/xnu/xnu-2782.1.97/bsd/sys/codesign.h + optional bytes udif_code_signature = 40; } // Please update SafeBrowsingNavigationObserverManager::SanitizeReferrerChain()
diff --git a/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc b/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc index 6732389..12fb5087 100644 --- a/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc +++ b/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
@@ -88,7 +88,7 @@ void RequestCompleteGpuInfo( const RequestCompleteGpuInfoCallback& callback) override {} - void LoadedShader(const std::string& data) override {} + void LoadedShader(const std::string& key, const std::string& data) override {} void DestroyingVideoSurface( int32_t surface_id,
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc index 932d213..06c4ed1 100644 --- a/content/browser/accessibility/browser_accessibility_com_win.cc +++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -1068,21 +1068,7 @@ if (!owner()) return E_FAIL; - if (!accessible) - return E_INVALIDARG; - - AXPlatformNodeBase* cell = - GetTableCell(static_cast<int>(row), static_cast<int>(column)); - if (cell) { - auto* node_win = static_cast<AXPlatformNodeWin*>(cell); - node_win->AddRef(); - - *accessible = static_cast<IAccessible*>(node_win); - return S_OK; - } - - *accessible = nullptr; - return E_INVALIDARG; + return AXPlatformNodeWin::get_accessibleAt(row, column, accessible); } STDMETHODIMP BrowserAccessibilityComWin::get_caption(IUnknown** accessible) { @@ -1091,12 +1077,7 @@ if (!owner()) return E_FAIL; - if (!accessible) - return E_INVALIDARG; - - // TODO(dmazzoni): implement - *accessible = nullptr; - return S_FALSE; + return AXPlatformNodeWin::get_caption(accessible); } STDMETHODIMP BrowserAccessibilityComWin::get_childIndex(long row, @@ -1107,17 +1088,7 @@ if (!owner()) return E_FAIL; - if (!cell_index) - return E_INVALIDARG; - - auto* cell = GetTableCell(static_cast<int>(row), static_cast<int>(column)); - if (cell) { - *cell_index = static_cast<LONG>(cell->GetTableCellIndex()); - return S_OK; - } - - *cell_index = 0; - return E_INVALIDARG; + return AXPlatformNodeWin::get_childIndex(row, column, cell_index); } STDMETHODIMP BrowserAccessibilityComWin::get_columnDescription( @@ -1128,38 +1099,7 @@ if (!owner()) return E_FAIL; - if (!description) - return E_INVALIDARG; - - int columns = GetTableColumnCount(); - if (column < 0 || column >= columns) - return E_INVALIDARG; - - int rows = GetTableRowCount(); - if (rows <= 0) { - *description = nullptr; - return S_FALSE; - } - - for (int i = 0; i < rows; ++i) { - auto* cell = GetTableCell(i, column); - if (cell && cell->GetData().role == ui::AX_ROLE_COLUMN_HEADER) { - base::string16 cell_name = cell->GetString16Attribute(ui::AX_ATTR_NAME); - if (cell_name.size() > 0) { - *description = SysAllocString(cell_name.c_str()); - return S_OK; - } - - cell_name = cell->GetString16Attribute(ui::AX_ATTR_DESCRIPTION); - if (cell_name.size() > 0) { - *description = SysAllocString(cell_name.c_str()); - return S_OK; - } - } - } - - *description = nullptr; - return S_FALSE; + return AXPlatformNodeWin::get_columnDescription(column, description); } STDMETHODIMP BrowserAccessibilityComWin::get_columnExtentAt( @@ -1171,15 +1111,7 @@ if (!owner()) return E_FAIL; - if (!n_columns_spanned) - return E_INVALIDARG; - - auto* cell = GetTableCell(static_cast<int>(row), static_cast<int>(column)); - if (!cell) - return E_INVALIDARG; - - *n_columns_spanned = cell->GetTableColumnSpan(); - return S_OK; + return AXPlatformNodeWin::get_columnExtentAt(row, column, n_columns_spanned); } STDMETHODIMP BrowserAccessibilityComWin::get_columnHeader( @@ -1187,8 +1119,12 @@ long* starting_row_index) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_COLUMN_HEADER); AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); - // TODO(dmazzoni): implement - return E_NOTIMPL; + + if (!owner()) + return E_FAIL; + + return AXPlatformNodeWin::get_columnHeader(accessible_table, + starting_row_index); } STDMETHODIMP BrowserAccessibilityComWin::get_columnIndex(long cell_index, @@ -1198,14 +1134,7 @@ if (!owner()) return E_FAIL; - if (!column_index) - return E_INVALIDARG; - - auto* cell = GetTableCell(cell_index); - if (!cell) - return E_INVALIDARG; - *column_index = cell->GetTableColumn(); - return S_OK; + return AXPlatformNodeWin::get_columnIndex(cell_index, column_index); } STDMETHODIMP BrowserAccessibilityComWin::get_nColumns(long* column_count) { @@ -1214,11 +1143,7 @@ if (!owner()) return E_FAIL; - if (!column_count) - return E_INVALIDARG; - - *column_count = GetTableColumnCount(); - return S_OK; + return AXPlatformNodeWin::get_nColumns(column_count); } STDMETHODIMP BrowserAccessibilityComWin::get_nRows(long* row_count) { @@ -1227,11 +1152,7 @@ if (!owner()) return E_FAIL; - if (!row_count) - return E_INVALIDARG; - - *row_count = GetTableRowCount(); - return S_OK; + return AXPlatformNodeWin::get_nRows(row_count); } STDMETHODIMP BrowserAccessibilityComWin::get_nSelectedChildren( @@ -1241,12 +1162,7 @@ if (!owner()) return E_FAIL; - if (!cell_count) - return E_INVALIDARG; - - // TODO(dmazzoni): add support for selected cells/rows/columns in tables. - *cell_count = 0; - return S_FALSE; + return AXPlatformNodeWin::get_nSelectedChildren(cell_count); } STDMETHODIMP BrowserAccessibilityComWin::get_nSelectedColumns( @@ -1256,11 +1172,7 @@ if (!owner()) return E_FAIL; - if (!column_count) - return E_INVALIDARG; - - *column_count = 0; - return S_FALSE; + return AXPlatformNodeWin::get_nSelectedColumns(column_count); } STDMETHODIMP BrowserAccessibilityComWin::get_nSelectedRows(long* row_count) { @@ -1269,11 +1181,7 @@ if (!owner()) return E_FAIL; - if (!row_count) - return E_INVALIDARG; - - *row_count = 0; - return S_FALSE; + return AXPlatformNodeWin::get_nSelectedRows(row_count); } STDMETHODIMP BrowserAccessibilityComWin::get_rowDescription(long row, @@ -1283,36 +1191,7 @@ if (!owner()) return E_FAIL; - if (!description) - return E_INVALIDARG; - - if (row < 0 || row >= GetTableRowCount()) - return E_INVALIDARG; - - int columns = GetTableColumnCount(); - if (columns <= 0) { - *description = nullptr; - return S_FALSE; - } - - for (int i = 0; i < columns; ++i) { - auto* cell = GetTableCell(row, i); - if (cell && cell->GetData().role == ui::AX_ROLE_ROW_HEADER) { - base::string16 cell_name = cell->GetString16Attribute(ui::AX_ATTR_NAME); - if (cell_name.size() > 0) { - *description = SysAllocString(cell_name.c_str()); - return S_OK; - } - cell_name = cell->GetString16Attribute(ui::AX_ATTR_DESCRIPTION); - if (cell_name.size() > 0) { - *description = SysAllocString(cell_name.c_str()); - return S_OK; - } - } - } - - *description = nullptr; - return S_FALSE; + return AXPlatformNodeWin::get_rowDescription(row, description); } STDMETHODIMP BrowserAccessibilityComWin::get_rowExtentAt(long row, @@ -1323,15 +1202,7 @@ if (!owner()) return E_FAIL; - if (!n_rows_spanned) - return E_INVALIDARG; - - auto* cell = GetTableCell(row, column); - if (!cell) - return E_INVALIDARG; - - *n_rows_spanned = GetTableRowSpan(); - return S_OK; + return AXPlatformNodeWin::get_rowExtentAt(row, column, n_rows_spanned); } STDMETHODIMP BrowserAccessibilityComWin::get_rowHeader( @@ -1339,8 +1210,11 @@ long* starting_column_index) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ROW_HEADER); AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); - // TODO(dmazzoni): implement - return E_NOTIMPL; + if (!owner()) + return E_FAIL; + + return AXPlatformNodeWin::get_rowHeader(accessible_table, + starting_column_index); } STDMETHODIMP BrowserAccessibilityComWin::get_rowIndex(long cell_index, @@ -1350,15 +1224,7 @@ if (!owner()) return E_FAIL; - if (!row_index) - return E_INVALIDARG; - - auto* cell = GetTableCell(cell_index); - if (!cell) - return E_INVALIDARG; - - *row_index = cell->GetTableRow(); - return S_OK; + return AXPlatformNodeWin::get_rowIndex(cell_index, row_index); } STDMETHODIMP BrowserAccessibilityComWin::get_selectedChildren( @@ -1370,12 +1236,8 @@ if (!owner()) return E_FAIL; - if (!children || !n_children) - return E_INVALIDARG; - - // TODO(dmazzoni): Implement this. - *n_children = 0; - return S_FALSE; + return AXPlatformNodeWin::get_selectedChildren(max_children, children, + n_children); } STDMETHODIMP BrowserAccessibilityComWin::get_selectedColumns(long max_columns, @@ -1386,12 +1248,8 @@ if (!owner()) return E_FAIL; - if (!columns || !n_columns) - return E_INVALIDARG; - - // TODO(dmazzoni): Implement this. - *n_columns = 0; - return S_FALSE; + return AXPlatformNodeWin::get_selectedColumns(max_columns, columns, + n_columns); } STDMETHODIMP BrowserAccessibilityComWin::get_selectedRows(long max_rows, @@ -1402,12 +1260,7 @@ if (!owner()) return E_FAIL; - if (!rows || !n_rows) - return E_INVALIDARG; - - // TODO(dmazzoni): Implement this. - *n_rows = 0; - return S_FALSE; + return AXPlatformNodeWin::get_selectedRows(max_rows, rows, n_rows); } STDMETHODIMP BrowserAccessibilityComWin::get_summary(IUnknown** accessible) { @@ -1416,12 +1269,7 @@ if (!owner()) return E_FAIL; - if (!accessible) - return E_INVALIDARG; - - // TODO(dmazzoni): implement - *accessible = nullptr; - return S_FALSE; + return AXPlatformNodeWin::get_summary(accessible); } STDMETHODIMP BrowserAccessibilityComWin::get_isColumnSelected( @@ -1432,12 +1280,7 @@ if (!owner()) return E_FAIL; - if (!is_selected) - return E_INVALIDARG; - - // TODO(dmazzoni): Implement this. - *is_selected = false; - return S_OK; + return AXPlatformNodeWin::get_isColumnSelected(column, is_selected); } STDMETHODIMP BrowserAccessibilityComWin::get_isRowSelected( @@ -1448,12 +1291,7 @@ if (!owner()) return E_FAIL; - if (!is_selected) - return E_INVALIDARG; - - // TODO(dmazzoni): Implement this. - *is_selected = false; - return S_OK; + return AXPlatformNodeWin::get_isRowSelected(row, is_selected); } STDMETHODIMP BrowserAccessibilityComWin::get_isSelected(long row, @@ -1464,12 +1302,7 @@ if (!owner()) return E_FAIL; - if (!is_selected) - return E_INVALIDARG; - - // TODO(dmazzoni): Implement this. - *is_selected = false; - return S_OK; + return AXPlatformNodeWin::get_isSelected(row, column, is_selected); } STDMETHODIMP BrowserAccessibilityComWin::get_rowColumnExtentsAtIndex( @@ -1484,49 +1317,52 @@ if (!owner()) return E_FAIL; - if (!row || !column || !row_extents || !column_extents || !is_selected) - return E_INVALIDARG; - - auto* cell = GetTableCell(index); - if (!cell) - return E_INVALIDARG; - - *row = cell->GetTableRow(); - *column = cell->GetTableColumn(); - *row_extents = GetTableRowSpan(); - *column_extents = GetTableColumnSpan(); - *is_selected = false; // Not supported. - - return S_OK; + return AXPlatformNodeWin::get_rowColumnExtentsAtIndex( + index, row, column, row_extents, column_extents, is_selected); } STDMETHODIMP BrowserAccessibilityComWin::selectRow(long row) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SELECT_ROW); AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); - return E_NOTIMPL; + if (!owner()) + return E_FAIL; + + return AXPlatformNodeWin::selectRow(row); } STDMETHODIMP BrowserAccessibilityComWin::selectColumn(long column) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SELECT_COLUMN); AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); - return E_NOTIMPL; + if (!owner()) + return E_FAIL; + + return AXPlatformNodeWin::selectColumn(column); } STDMETHODIMP BrowserAccessibilityComWin::unselectRow(long row) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_UNSELECT_ROW); AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); - return E_NOTIMPL; + if (!owner()) + return E_FAIL; + + return AXPlatformNodeWin::unselectRow(row); } STDMETHODIMP BrowserAccessibilityComWin::unselectColumn(long column) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_UNSELECT_COLUMN); AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); - return E_NOTIMPL; + if (!owner()) + return E_FAIL; + + return AXPlatformNodeWin::unselectColumn(column); } STDMETHODIMP BrowserAccessibilityComWin::get_modelChange(IA2TableModelChange* model_change) { - return E_NOTIMPL; + if (!owner()) + return E_FAIL; + + return AXPlatformNodeWin::get_modelChange(model_change); } // @@ -1541,26 +1377,16 @@ if (!owner()) return E_FAIL; - if (!cell) - return E_INVALIDARG; - - AXPlatformNodeBase* table_cell = - GetTableCell(static_cast<int>(row), static_cast<int>(column)); - if (table_cell) { - auto* node_win = static_cast<AXPlatformNodeWin*>(table_cell); - node_win->AddRef(); - *cell = static_cast<IAccessible*>(node_win); - return S_OK; - } - - *cell = nullptr; - return E_INVALIDARG; + return AXPlatformNodeWin::get_cellAt(row, column, cell); } STDMETHODIMP BrowserAccessibilityComWin::get_nSelectedCells(long* cell_count) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_N_SELECTED_CELLS); AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); - return get_nSelectedChildren(cell_count); + if (!owner()) + return E_FAIL; + + return AXPlatformNodeWin::get_nSelectedCells(cell_count); } STDMETHODIMP BrowserAccessibilityComWin::get_selectedCells( @@ -1571,12 +1397,7 @@ if (!owner()) return E_FAIL; - if (!cells || !n_selected_cells) - return E_INVALIDARG; - - // TODO(dmazzoni): Implement this. - *n_selected_cells = 0; - return S_OK; + return AXPlatformNodeWin::get_selectedCells(cells, n_selected_cells); } STDMETHODIMP BrowserAccessibilityComWin::get_selectedColumns(long** columns, @@ -1586,12 +1407,7 @@ if (!owner()) return E_FAIL; - if (!columns || !n_columns) - return E_INVALIDARG; - - // TODO(dmazzoni): Implement this. - *n_columns = 0; - return S_OK; + return AXPlatformNodeWin::get_selectedColumns(columns, n_columns); } STDMETHODIMP BrowserAccessibilityComWin::get_selectedRows(long** rows, @@ -1601,12 +1417,7 @@ if (!owner()) return E_FAIL; - if (!rows || !n_rows) - return E_INVALIDARG; - - // TODO(dmazzoni): Implement this. - *n_rows = 0; - return S_OK; + return AXPlatformNodeWin::get_selectedRows(rows, n_rows); } // @@ -1620,11 +1431,7 @@ if (!owner()) return E_FAIL; - if (!n_columns_spanned) - return E_INVALIDARG; - - *n_columns_spanned = GetTableColumnSpan(); - return S_OK; + return AXPlatformNodeWin::get_columnExtent(n_columns_spanned); } STDMETHODIMP BrowserAccessibilityComWin::get_columnHeaderCells( @@ -1635,43 +1442,8 @@ if (!owner()) return E_FAIL; - if (!cell_accessibles || !n_column_header_cells) - return E_INVALIDARG; - - *n_column_header_cells = 0; - auto* table = GetTable(); - if (!table) { - NOTREACHED(); - return S_FALSE; - } - - int column = GetTableColumn(); - int columns = GetTableColumnCount(); - int rows = GetTableRowCount(); - if (columns <= 0 || rows <= 0 || column < 0 || column >= columns) - return S_FALSE; - - for (int i = 0; i < rows; ++i) { - auto* cell = GetTableCell(i, column); - if (cell && cell->GetData().role == ui::AX_ROLE_COLUMN_HEADER) - (*n_column_header_cells)++; - } - - *cell_accessibles = static_cast<IUnknown**>( - CoTaskMemAlloc((*n_column_header_cells) * sizeof(cell_accessibles[0]))); - int index = 0; - for (int i = 0; i < rows; ++i) { - AXPlatformNodeBase* cell = GetTableCell(i, column); - if (cell && cell->GetData().role == ui::AX_ROLE_COLUMN_HEADER) { - auto* node_win = static_cast<AXPlatformNodeWin*>(cell); - node_win->AddRef(); - - (*cell_accessibles)[index] = static_cast<IAccessible*>(node_win); - ++index; - } - } - - return S_OK; + return AXPlatformNodeWin::get_columnHeaderCells(cell_accessibles, + n_column_header_cells); } STDMETHODIMP BrowserAccessibilityComWin::get_columnIndex(long* column_index) { @@ -1680,11 +1452,7 @@ if (!owner()) return E_FAIL; - if (!column_index) - return E_INVALIDARG; - - *column_index = GetTableColumn(); - return S_OK; + return AXPlatformNodeWin::get_columnIndex(column_index); } STDMETHODIMP BrowserAccessibilityComWin::get_rowExtent(long* n_rows_spanned) { @@ -1693,11 +1461,7 @@ if (!owner()) return E_FAIL; - if (!n_rows_spanned) - return E_INVALIDARG; - - *n_rows_spanned = GetTableRowSpan(); - return S_OK; + return AXPlatformNodeWin::get_rowExtent(n_rows_spanned); } STDMETHODIMP BrowserAccessibilityComWin::get_rowHeaderCells( @@ -1708,43 +1472,8 @@ if (!owner()) return E_FAIL; - if (!cell_accessibles || !n_row_header_cells) - return E_INVALIDARG; - - *n_row_header_cells = 0; - auto* table = GetTable(); - if (!table) { - NOTREACHED(); - return S_FALSE; - } - - int row = GetTableRow(); - int columns = GetTableColumnCount(); - int rows = GetTableRowCount(); - if (columns <= 0 || rows <= 0 || row < 0 || row >= rows) - return S_FALSE; - - for (int i = 0; i < columns; ++i) { - auto* cell = GetTableCell(row, i); - if (cell && cell->GetData().role == ui::AX_ROLE_ROW_HEADER) - (*n_row_header_cells)++; - } - - *cell_accessibles = static_cast<IUnknown**>( - CoTaskMemAlloc((*n_row_header_cells) * sizeof(cell_accessibles[0]))); - int index = 0; - for (int i = 0; i < columns; ++i) { - AXPlatformNodeBase* cell = GetTableCell(row, i); - if (cell && cell->GetData().role == ui::AX_ROLE_ROW_HEADER) { - auto* node_win = static_cast<AXPlatformNodeWin*>(cell); - node_win->AddRef(); - - (*cell_accessibles)[index] = static_cast<IAccessible*>(node_win); - ++index; - } - } - - return S_OK; + return AXPlatformNodeWin::get_rowHeaderCells(cell_accessibles, + n_row_header_cells); } STDMETHODIMP BrowserAccessibilityComWin::get_rowIndex(long* row_index) { @@ -1753,11 +1482,7 @@ if (!owner()) return E_FAIL; - if (!row_index) - return E_INVALIDARG; - - *row_index = GetTableRow(); - return S_OK; + return AXPlatformNodeWin::get_rowIndex(row_index); } STDMETHODIMP BrowserAccessibilityComWin::get_isSelected(boolean* is_selected) { @@ -1766,11 +1491,7 @@ if (!owner()) return E_FAIL; - if (!is_selected) - return E_INVALIDARG; - - *is_selected = false; - return S_OK; + return AXPlatformNodeWin::get_isSelected(is_selected); } STDMETHODIMP BrowserAccessibilityComWin::get_rowColumnExtents( @@ -1784,18 +1505,8 @@ if (!owner()) return E_FAIL; - if (!row_index || !column_index || !row_extents || !column_extents || - !is_selected) { - return E_INVALIDARG; - } - - *row_index = GetTableRow(); - *column_index = GetTableColumn(); - *row_extents = GetTableRowSpan(); - *column_extents = GetTableColumnSpan(); - *is_selected = false; // Not supported. - - return S_OK; + return AXPlatformNodeWin::get_rowColumnExtents( + row_index, column_index, row_extents, column_extents, is_selected); } STDMETHODIMP BrowserAccessibilityComWin::get_table(IUnknown** table) { @@ -1804,22 +1515,7 @@ if (!owner()) return E_FAIL; - if (!table) - return E_INVALIDARG; - - auto* find_table = GetTable(); - if (!find_table) { - *table = nullptr; - return S_FALSE; - } - - // The IAccessibleTable interface is still on the BrowserAccessibilityComWin - // class. - auto* node_win = static_cast<BrowserAccessibilityComWin*>(find_table); - node_win->AddRef(); - - *table = static_cast<IAccessibleTable*>(node_win); - return S_OK; + return AXPlatformNodeWin::get_table(table); } //
diff --git a/content/browser/accessibility/browser_accessibility_com_win.h b/content/browser/accessibility/browser_accessibility_com_win.h index 082580b..28397d3 100644 --- a/content/browser/accessibility/browser_accessibility_com_win.h +++ b/content/browser/accessibility/browser_accessibility_com_win.h
@@ -54,9 +54,6 @@ public IAccessibleHyperlink, public IAccessibleHypertext, public IAccessibleImage, - public IAccessibleTable, - public IAccessibleTable2, - public IAccessibleTableCell, public IAccessibleValue, public ISimpleDOMDocument, public ISimpleDOMNode,
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc index 4a26d01..32bfb9f 100644 --- a/content/browser/background_fetch/background_fetch_context.cc +++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -76,8 +76,7 @@ const BackgroundFetchRegistrationId& registration_id, const BackgroundFetchOptions& options, blink::mojom::BackgroundFetchService::FetchCallback callback, - blink::mojom::BackgroundFetchError error, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests) { + blink::mojom::BackgroundFetchError error) { DCHECK_CURRENTLY_ON(BrowserThread::IO); RecordRegistrationCreatedError(error); @@ -87,7 +86,7 @@ } // Create the BackgroundFetchJobController, which will do the actual fetching. - CreateController(registration_id, options, std::move(initial_requests)); + CreateController(registration_id, options); // Create the BackgroundFetchRegistration the renderer process will receive, // which enables it to resolve the promise telling the developer it worked. @@ -142,8 +141,7 @@ void BackgroundFetchContext::CreateController( const BackgroundFetchRegistrationId& registration_id, - const BackgroundFetchOptions& options, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests) { + const BackgroundFetchOptions& options) { DCHECK_CURRENTLY_ON(BrowserThread::IO); net::NetworkTrafficAnnotationTag traffic_annotation = @@ -183,9 +181,9 @@ // TODO(peter): We should actually be able to use Background Fetch in layout // tests. That requires a download manager and a request context. if (request_context_getter_) { - // Start fetching the |initial_requests| immediately. At some point in the + // Start fetching the first few requests immediately. At some point in the // future we may want a more elaborate scheduling mechanism here. - controller->Start(std::move(initial_requests)); + controller->Start(); } active_fetches_.insert(
diff --git a/content/browser/background_fetch/background_fetch_context.h b/content/browser/background_fetch/background_fetch_context.h index 944b5bc..d96e76b 100644 --- a/content/browser/background_fetch/background_fetch_context.h +++ b/content/browser/background_fetch/background_fetch_context.h
@@ -31,7 +31,6 @@ class BackgroundFetchJobController; struct BackgroundFetchOptions; class BackgroundFetchRegistrationId; -class BackgroundFetchRequestInfo; class BlobHandle; class BrowserContext; class ServiceWorkerContextWrapper; @@ -84,18 +83,15 @@ // Creates a new Job Controller for the given |registration_id| and |options|, // which will start fetching the files that are part of the registration. - void CreateController( - const BackgroundFetchRegistrationId& registration_id, - const BackgroundFetchOptions& options, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests); + void CreateController(const BackgroundFetchRegistrationId& registration_id, + const BackgroundFetchOptions& options); // Called when a new registration has been created by the data manager. void DidCreateRegistration( const BackgroundFetchRegistrationId& registration_id, const BackgroundFetchOptions& options, blink::mojom::BackgroundFetchService::FetchCallback callback, - blink::mojom::BackgroundFetchError error, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests); + blink::mojom::BackgroundFetchError error); // Called when the given |controller| has finished processing its job. void DidCompleteJob(BackgroundFetchJobController* controller);
diff --git a/content/browser/background_fetch/background_fetch_data_manager.cc b/content/browser/background_fetch/background_fetch_data_manager.cc index 52c5ae50..408dc1db 100644 --- a/content/browser/background_fetch/background_fetch_data_manager.cc +++ b/content/browser/background_fetch/background_fetch_data_manager.cc
@@ -54,7 +54,7 @@ bool HasPendingRequests() const { return !pending_requests_.empty(); } // Consumes a request from the queue that is to be fetched. - scoped_refptr<BackgroundFetchRequestInfo> GetPendingRequest() { + scoped_refptr<BackgroundFetchRequestInfo> PopNextPendingRequest() { DCHECK(!pending_requests_.empty()); auto request = pending_requests_.front(); @@ -83,7 +83,7 @@ // Marks the |request| as having completed. Verifies that the |request| is // currently active and moves it to the |completed_requests_| vector. - void MarkRequestAsComplete(BackgroundFetchRequestInfo* request) { + bool MarkRequestAsComplete(BackgroundFetchRequestInfo* request) { const auto iter = std::find_if( active_requests_.begin(), active_requests_.end(), [&request](scoped_refptr<BackgroundFetchRequestInfo> active_request) { @@ -95,6 +95,10 @@ completed_requests_.push_back(*iter); active_requests_.erase(iter); + + bool has_pending_or_active_requests = + !pending_requests_.empty() || !active_requests_.empty(); + return has_pending_or_active_requests; } // Returns the vector with all completed requests part of this registration. @@ -146,31 +150,33 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (registrations_.find(registration_id) != registrations_.end()) { - std::move(callback).Run( - blink::mojom::BackgroundFetchError::DUPLICATED_TAG, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>>()); + std::move(callback).Run(blink::mojom::BackgroundFetchError::DUPLICATED_TAG); return; } - std::unique_ptr<RegistrationData> registration_data = - base::MakeUnique<RegistrationData>(requests, options); - - // Create a vector with the initial requests to feed the Job Controller with. - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests; - for (size_t i = 0; i < kMaximumBackgroundFetchParallelRequests; ++i) { - if (!registration_data->HasPendingRequests()) - break; - - initial_requests.push_back(registration_data->GetPendingRequest()); - } - - // Store the created |registration_data| so that we can easily access it. - registrations_.insert( - std::make_pair(registration_id, std::move(registration_data))); + // Create the |RegistrationData|, and store it for easy access. + registrations_.insert(std::make_pair( + registration_id, base::MakeUnique<RegistrationData>(requests, options))); // Inform the |callback| of the newly created registration. - std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE, - std::move(initial_requests)); + std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE); +} + +void BackgroundFetchDataManager::PopNextRequest( + const BackgroundFetchRegistrationId& registration_id, + NextRequestCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + auto iter = registrations_.find(registration_id); + DCHECK(iter != registrations_.end()); + + RegistrationData* registration_data = iter->second.get(); + + scoped_refptr<BackgroundFetchRequestInfo> next_request; + if (registration_data->HasPendingRequests()) + next_request = registration_data->PopNextPendingRequest(); + + std::move(callback).Run(std::move(next_request)); } void BackgroundFetchDataManager::MarkRequestAsStarted( @@ -186,23 +192,20 @@ registration_data->MarkRequestAsStarted(request, download_guid); } -void BackgroundFetchDataManager::MarkRequestAsCompleteAndGetNextRequest( +void BackgroundFetchDataManager::MarkRequestAsComplete( const BackgroundFetchRegistrationId& registration_id, BackgroundFetchRequestInfo* request, - NextRequestCallback callback) { + MarkedCompleteCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto iter = registrations_.find(registration_id); DCHECK(iter != registrations_.end()); RegistrationData* registration_data = iter->second.get(); - registration_data->MarkRequestAsComplete(request); + bool has_pending_or_active_requests = + registration_data->MarkRequestAsComplete(request); - scoped_refptr<BackgroundFetchRequestInfo> next_request; - if (registration_data->HasPendingRequests()) - next_request = registration_data->GetPendingRequest(); - - std::move(callback).Run(std::move(next_request)); + std::move(callback).Run(has_pending_or_active_requests); } void BackgroundFetchDataManager::GetSettledFetchesForRegistration(
diff --git a/content/browser/background_fetch/background_fetch_data_manager.h b/content/browser/background_fetch/background_fetch_data_manager.h index ab17f48..424d5be 100644 --- a/content/browser/background_fetch/background_fetch_data_manager.h +++ b/content/browser/background_fetch/background_fetch_data_manager.h
@@ -33,13 +33,14 @@ // which will keep the metadata up to date. class CONTENT_EXPORT BackgroundFetchDataManager { public: - using CreateRegistrationCallback = base::OnceCallback<void( - blink::mojom::BackgroundFetchError, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>>)>; + using CreateRegistrationCallback = + base::OnceCallback<void(blink::mojom::BackgroundFetchError)>; using DeleteRegistrationCallback = base::OnceCallback<void(blink::mojom::BackgroundFetchError)>; using NextRequestCallback = base::OnceCallback<void(scoped_refptr<BackgroundFetchRequestInfo>)>; + using MarkedCompleteCallback = + base::OnceCallback<void(bool /* has_pending_or_active_requests */)>; using SettledFetchesCallback = base::OnceCallback<void(blink::mojom::BackgroundFetchError, bool /* background_fetch_succeeded */, @@ -58,6 +59,11 @@ const BackgroundFetchOptions& options, CreateRegistrationCallback callback); + // Removes the next request, if any, from the pending requests queue, and + // invokes the |callback| with that request, else a null request. + void PopNextRequest(const BackgroundFetchRegistrationId& registration_id, + NextRequestCallback callback); + // Marks that the |request|, part of the Background Fetch identified by // |registration_id|, has been started as |download_guid|. void MarkRequestAsStarted( @@ -66,12 +72,11 @@ const std::string& download_guid); // Marks that the |request|, part of the Background Fetch identified by - // |registration_id|, has completed. Will invoke the |callback| with the - // next request, if any, when the operation has completed. - void MarkRequestAsCompleteAndGetNextRequest( + // |registration_id|, has completed. + void MarkRequestAsComplete( const BackgroundFetchRegistrationId& registration_id, BackgroundFetchRequestInfo* request, - NextRequestCallback callback); + MarkedCompleteCallback callback); // Reads all settled fetches for the given |registration_id|. Both the Request // and Response objects will be initialised based on the stored data. Will
diff --git a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc index 9e4eb46..9a9e71a 100644 --- a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc +++ b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
@@ -35,9 +35,7 @@ const BackgroundFetchRegistrationId& registration_id, const std::vector<ServiceWorkerFetchRequest>& requests, const BackgroundFetchOptions& options, - blink::mojom::BackgroundFetchError* out_error, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>>* - out_initial_requests) { + blink::mojom::BackgroundFetchError* out_error) { DCHECK(out_error); base::RunLoop run_loop; @@ -45,7 +43,7 @@ registration_id, requests, options, base::BindOnce(&BackgroundFetchDataManagerTest::DidCreateRegistration, base::Unretained(this), run_loop.QuitClosure(), - out_error, out_initial_requests)); + out_error)); run_loop.Run(); } @@ -64,15 +62,10 @@ } private: - void DidCreateRegistration( - base::Closure quit_closure, - blink::mojom::BackgroundFetchError* out_error, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>>* - out_initial_requests, - blink::mojom::BackgroundFetchError error, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests) { + void DidCreateRegistration(base::Closure quit_closure, + blink::mojom::BackgroundFetchError* out_error, + blink::mojom::BackgroundFetchError error) { *out_error = error; - *out_initial_requests = std::move(initial_requests); quit_closure.Run(); } @@ -100,20 +93,19 @@ BackgroundFetchOptions options; blink::mojom::BackgroundFetchError error; - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests; // Deleting the not-yet-created registration should fail. ASSERT_NO_FATAL_FAILURE(DeleteRegistration(registration_id, &error)); EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_TAG); // Creating the initial registration should succeed. - ASSERT_NO_FATAL_FAILURE(CreateRegistration(registration_id, requests, options, - &error, &initial_requests)); + ASSERT_NO_FATAL_FAILURE( + CreateRegistration(registration_id, requests, options, &error)); EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); // Attempting to create it again should yield an error. - ASSERT_NO_FATAL_FAILURE(CreateRegistration(registration_id, requests, options, - &error, &initial_requests)); + ASSERT_NO_FATAL_FAILURE( + CreateRegistration(registration_id, requests, options, &error)); EXPECT_EQ(error, blink::mojom::BackgroundFetchError::DUPLICATED_TAG); // Deleting the registration should succeed. @@ -121,8 +113,8 @@ EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); // And then recreating the registration again should work fine. - ASSERT_NO_FATAL_FAILURE(CreateRegistration(registration_id, requests, options, - &error, &initial_requests)); + ASSERT_NO_FATAL_FAILURE( + CreateRegistration(registration_id, requests, options, &error)); EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); }
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc index 1032fa2..c8a75672 100644 --- a/content/browser/background_fetch/background_fetch_job_controller.cc +++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -260,22 +260,33 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); }; -void BackgroundFetchJobController::Start( - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests) { +void BackgroundFetchJobController::Start() { DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_LE(initial_requests.size(), kMaximumBackgroundFetchParallelRequests); DCHECK_EQ(state_, State::INITIALIZED); state_ = State::FETCHING; - for (const auto& request : initial_requests) - StartRequest(request); + // TODO(crbug.com/741609): Enforce kMaximumBackgroundFetchParallelRequests + // globally and/or per origin rather than per fetch. + for (size_t i = 0; i < kMaximumBackgroundFetchParallelRequests; i++) { + data_manager_->PopNextRequest( + registration_id_, + base::BindOnce(&BackgroundFetchJobController::StartRequest, + weak_ptr_factory_.GetWeakPtr())); + } } void BackgroundFetchJobController::StartRequest( scoped_refptr<BackgroundFetchRequestInfo> request) { DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_EQ(state_, State::FETCHING); + if (!request) { + // This can happen when |Start| tries to start multiple initial requests, + // but the fetch does not contain that many pending requests; or when + // |DidMarkRequestCompleted| tries to start the next request but there are + // none left. + return; + } BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(&Core::StartRequest, ui_core_ptr_, std::move(request), traffic_annotation_)); @@ -295,33 +306,29 @@ // The DataManager must acknowledge that it stored the data and that there are // no more pending requests to avoid marking this job as completed too early. - pending_completed_file_acknowledgements_++; - - data_manager_->MarkRequestAsCompleteAndGetNextRequest( + data_manager_->MarkRequestAsComplete( registration_id_, request.get(), - base::BindOnce(&BackgroundFetchJobController::DidGetNextRequest, + base::BindOnce(&BackgroundFetchJobController::DidMarkRequestCompleted, weak_ptr_factory_.GetWeakPtr())); } -void BackgroundFetchJobController::DidGetNextRequest( - scoped_refptr<BackgroundFetchRequestInfo> request) { +void BackgroundFetchJobController::DidMarkRequestCompleted( + bool has_pending_or_active_requests) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_LE(pending_completed_file_acknowledgements_, 1); - pending_completed_file_acknowledgements_--; + DCHECK_EQ(state_, State::FETCHING); - // If a |request| has been given, start downloading the file and bail. - if (request) { - StartRequest(std::move(request)); + // If not all requests have completed, start a pending request if there are + // any left, and bail. + if (has_pending_or_active_requests) { + data_manager_->PopNextRequest( + registration_id_, + base::BindOnce(&BackgroundFetchJobController::StartRequest, + weak_ptr_factory_.GetWeakPtr())); return; } - // If there are outstanding completed file acknowlegements, bail as well. - if (pending_completed_file_acknowledgements_ > 0) - return; - - state_ = State::COMPLETED; - // Otherwise the job this controller is responsible for has completed. + state_ = State::COMPLETED; std::move(completed_callback_).Run(this); } @@ -334,11 +341,19 @@ void BackgroundFetchJobController::Abort() { DCHECK_CURRENTLY_ON(BrowserThread::IO); + switch (state_) { + case State::INITIALIZED: + case State::FETCHING: + break; + case State::ABORTED: + case State::COMPLETED: + return; // Ignore attempt to abort after completion/abort. + } + // TODO(harkness): Abort all in-progress downloads. state_ = State::ABORTED; - - // Inform the owner of the controller about the job having completed. + // Inform the owner of the controller about the job having aborted. std::move(completed_callback_).Run(this); }
diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h index 3698664..a944352b0 100644 --- a/content/browser/background_fetch/background_fetch_job_controller.h +++ b/content/browser/background_fetch/background_fetch_job_controller.h
@@ -48,10 +48,9 @@ const net::NetworkTrafficAnnotationTag& traffic_annotation); ~BackgroundFetchJobController(); - // Starts fetching the |initial_fetches|. The controller will continue to + // Starts fetching the first few requests. The controller will continue to // fetch new content until all requests have been handled. - void Start( - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests); + void Start(); // Updates the representation of this Background Fetch in the user interface // to match the given |title|. @@ -85,9 +84,8 @@ // Called when the given |request| has been completed. void DidCompleteRequest(scoped_refptr<BackgroundFetchRequestInfo> request); - // Called when a completed download has been marked as such in the DataManager - // and the next request, if any, has been read from storage. - void DidGetNextRequest(scoped_refptr<BackgroundFetchRequestInfo> request); + // Called when a completed download has been marked as such in DataManager. + void DidMarkRequestCompleted(bool has_pending_or_active_requests); // The registration id on behalf of which this controller is fetching data. BackgroundFetchRegistrationId registration_id_; @@ -106,9 +104,6 @@ // will be kept alive until after the JobController is destroyed. BackgroundFetchDataManager* data_manager_; - // Number of outstanding acknowledgements we still expect to receive. - int pending_completed_file_acknowledgements_ = 0; - // Callback for when all fetches have been completed. CompletedCallback completed_callback_;
diff --git a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc index 201299e..b2e3e3e 100644 --- a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc +++ b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
@@ -41,11 +41,8 @@ // included |request_data|. Should be wrapped in ASSERT_NO_FATAL_FAILURE(). void CreateRegistrationForRequests( BackgroundFetchRegistrationId* registration_id, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>>* - out_initial_requests, std::map<std::string /* url */, std::string /* method */> request_data) { DCHECK(registration_id); - DCHECK(out_initial_requests); ASSERT_TRUE(CreateRegistrationId(kExampleTag, registration_id)); @@ -64,14 +61,10 @@ data_manager_.CreateRegistration( *registration_id, requests, BackgroundFetchOptions(), base::BindOnce(&BackgroundFetchJobControllerTest::DidCreateRegistration, - base::Unretained(this), &error, out_initial_requests, - run_loop.QuitClosure())); + base::Unretained(this), &error, run_loop.QuitClosure())); run_loop.Run(); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); - ASSERT_GE(out_initial_requests->size(), 1u); - ASSERT_LE(out_initial_requests->size(), - kMaximumBackgroundFetchParallelRequests); // Provide fake responses for the given |request_data| pairs. for (const auto& pair : request_data) { @@ -107,18 +100,12 @@ base::OnceClosure job_completed_closure_; private: - void DidCreateRegistration( - blink::mojom::BackgroundFetchError* out_error, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>>* - out_initial_requests, - const base::Closure& quit_closure, - blink::mojom::BackgroundFetchError error, - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests) { + void DidCreateRegistration(blink::mojom::BackgroundFetchError* out_error, + const base::Closure& quit_closure, + blink::mojom::BackgroundFetchError error) { DCHECK(out_error); - DCHECK(out_initial_requests); *out_error = error; - *out_initial_requests = std::move(initial_requests); quit_closure.Run(); } @@ -140,11 +127,9 @@ TEST_F(BackgroundFetchJobControllerTest, SingleRequestJob) { BackgroundFetchRegistrationId registration_id; - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests; ASSERT_NO_FATAL_FAILURE(CreateRegistrationForRequests( - ®istration_id, &initial_requests, - {{"https://example.com/funny_cat.png", "GET"}})); + ®istration_id, {{"https://example.com/funny_cat.png", "GET"}})); std::unique_ptr<BackgroundFetchJobController> controller = CreateJobController(registration_id); @@ -152,7 +137,7 @@ EXPECT_EQ(controller->state(), BackgroundFetchJobController::State::INITIALIZED); - controller->Start(initial_requests /* deliberate copy */); + controller->Start(); EXPECT_EQ(controller->state(), BackgroundFetchJobController::State::FETCHING); // Mark the single download item as finished, completing the job. @@ -170,19 +155,17 @@ TEST_F(BackgroundFetchJobControllerTest, MultipleRequestJob) { BackgroundFetchRegistrationId registration_id; - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests; // This test should always issue more requests than the number of allowed // parallel requests. That way we ensure testing the iteration behaviour. ASSERT_GT(5u, kMaximumBackgroundFetchParallelRequests); ASSERT_NO_FATAL_FAILURE(CreateRegistrationForRequests( - ®istration_id, &initial_requests, - {{"https://example.com/funny_cat.png", "GET"}, - {"https://example.com/scary_cat.png", "GET"}, - {"https://example.com/crazy_cat.png", "GET"}, - {"https://example.com/silly_cat.png", "GET"}, - {"https://example.com/happy_cat.png", "GET"}})); + ®istration_id, {{"https://example.com/funny_cat.png", "GET"}, + {"https://example.com/scary_cat.png", "GET"}, + {"https://example.com/crazy_cat.png", "GET"}, + {"https://example.com/silly_cat.png", "GET"}, + {"https://example.com/happy_cat.png", "GET"}})); std::unique_ptr<BackgroundFetchJobController> controller = CreateJobController(registration_id); @@ -196,7 +179,7 @@ base::RunLoop run_loop; job_completed_closure_ = run_loop.QuitClosure(); - controller->Start(initial_requests /* deliberate copy */); + controller->Start(); EXPECT_EQ(controller->state(), BackgroundFetchJobController::State::FETCHING); @@ -210,11 +193,9 @@ TEST_F(BackgroundFetchJobControllerTest, AbortJob) { BackgroundFetchRegistrationId registration_id; - std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests; ASSERT_NO_FATAL_FAILURE(CreateRegistrationForRequests( - ®istration_id, &initial_requests, - {{"https://example.com/sad_cat.png", "GET"}})); + ®istration_id, {{"https://example.com/sad_cat.png", "GET"}})); std::unique_ptr<BackgroundFetchJobController> controller = CreateJobController(registration_id); @@ -222,12 +203,12 @@ EXPECT_EQ(controller->state(), BackgroundFetchJobController::State::INITIALIZED); - // Start the set of |initial_requests|, and abort them immediately after. + // Start the first few requests, and abort them immediately after. { base::RunLoop run_loop; job_completed_closure_ = run_loop.QuitClosure(); - controller->Start(initial_requests /* deliberate copy */); + controller->Start(); EXPECT_EQ(controller->state(), BackgroundFetchJobController::State::FETCHING);
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc index 47cfea1..15f619a 100644 --- a/content/browser/browser_child_process_host_impl.cc +++ b/content/browser/browser_child_process_host_impl.cc
@@ -499,9 +499,13 @@ break; default: - UMA_HISTOGRAM_ENUMERATION( - "UMA.SubprocessMetricsProvider.UntrackedProcesses", - data_.process_type, PROCESS_TYPE_CONTENT_END); + // Report new processes. "Custom" ones are renumbered to 1000+ so that + // they won't conflict with any standard ones in the future. + int process_type = data_.process_type; + if (process_type >= PROCESS_TYPE_CONTENT_END) + process_type += 1000 - PROCESS_TYPE_CONTENT_END; + UMA_HISTOGRAM_SPARSE_SLOWLY( + "UMA.SubprocessMetricsProvider.UntrackedProcesses", process_type); return; }
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc index 4330c11..0b7c64f03 100644 --- a/content/browser/browser_context.cc +++ b/content/browser/browser_context.cc
@@ -345,7 +345,7 @@ const GURL& origin, int64_t service_worker_registration_id, const PushEventPayload& payload, - const base::Callback<void(PushDeliveryStatus)>& callback) { + const base::Callback<void(mojom::PushDeliveryStatus)>& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); PushMessagingRouter::DeliverMessage(browser_context, origin, service_worker_registration_id, payload,
diff --git a/content/browser/cocoa/system_hotkey_helper_mac.mm b/content/browser/cocoa/system_hotkey_helper_mac.mm index cbac199..635a29d 100644 --- a/content/browser/cocoa/system_hotkey_helper_mac.mm +++ b/content/browser/cocoa/system_hotkey_helper_mac.mm
@@ -34,7 +34,9 @@ void SystemHotkeyHelperMac::DeferredLoadSystemHotkeys() { base::PostDelayedTaskWithTraits( - FROM_HERE, {base::MayBlock()}, + FROM_HERE, + {base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()}, base::Bind(&SystemHotkeyHelperMac::LoadSystemHotkeys, base::Unretained(this)), base::TimeDelta::FromSeconds(kLoadHotkeysDelaySeconds));
diff --git a/content/browser/devtools/protocol/service_worker_handler.cc b/content/browser/devtools/protocol/service_worker_handler.cc index 1d2f1a6..9ad73e7 100644 --- a/content/browser/devtools/protocol/service_worker_handler.cc +++ b/content/browser/devtools/protocol/service_worker_handler.cc
@@ -28,7 +28,7 @@ #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/common/push_event_payload.h" -#include "content/public/common/push_messaging_status.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "url/gurl.h" namespace content { @@ -47,8 +47,7 @@ ServiceWorkerStatusCode status) { } -void PushDeliveryNoOp(PushDeliveryStatus status) { -} +void PushDeliveryNoOp(mojom::PushDeliveryStatus status) {} const std::string GetVersionRunningStatusString( EmbeddedWorkerStatus running_status) {
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 6005e0d..cfe6fab 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -1217,8 +1217,11 @@ std::string prefix = GetShaderPrefixKey(data); bool prefix_ok = !key.compare(0, prefix.length(), prefix); UMA_HISTOGRAM_BOOLEAN("GPU.ShaderLoadPrefixOK", prefix_ok); - if (prefix_ok) - gpu_service_ptr_->LoadedShader(data); + if (prefix_ok) { + // Remove the prefix from the key before load. + std::string key_no_prefix = key.substr(prefix.length() + 1); + gpu_service_ptr_->LoadedShader(key_no_prefix, data); + } } ui::mojom::GpuService* GpuProcessHost::gpu_service() {
diff --git a/content/browser/push_messaging/push_messaging_manager.cc b/content/browser/push_messaging/push_messaging_manager.cc index 3b0ee0f..2cf4537 100644 --- a/content/browser/push_messaging/push_messaging_manager.cc +++ b/content/browser/push_messaging/push_messaging_manager.cc
@@ -19,6 +19,7 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_storage.h" +#include "content/common/push_messaging.mojom.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/permission_manager.h" #include "content/public/browser/permission_type.h" @@ -28,7 +29,7 @@ #include "content/public/common/child_process_host.h" #include "content/public/common/console_message_level.h" #include "content/public/common/content_switches.h" -#include "content/public/common/push_messaging_status.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h" namespace content { @@ -51,26 +52,62 @@ // These UMA methods are called from the IO and/or UI threads. Racey but ok, see // https://groups.google.com/a/chromium.org/d/msg/chromium-dev/FNzZRJtN2aw/Aw0CWAXJJ1kJ -void RecordRegistrationStatus(PushRegistrationStatus status) { +void RecordRegistrationStatus(mojom::PushRegistrationStatus status) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) || BrowserThread::CurrentlyOn(BrowserThread::UI)); - UMA_HISTOGRAM_ENUMERATION("PushMessaging.RegistrationStatus", status, - PUSH_REGISTRATION_STATUS_LAST + 1); + UMA_HISTOGRAM_ENUMERATION( + "PushMessaging.RegistrationStatus", status, + static_cast<int>(mojom::PushRegistrationStatus::LAST) + 1); } -void RecordUnregistrationStatus(PushUnregistrationStatus status) { +void RecordUnregistrationStatus(mojom::PushUnregistrationStatus status) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - UMA_HISTOGRAM_ENUMERATION("PushMessaging.UnregistrationStatus", status, - PUSH_UNREGISTRATION_STATUS_LAST + 1); + UMA_HISTOGRAM_ENUMERATION( + "PushMessaging.UnregistrationStatus", status, + static_cast<int>(mojom::PushUnregistrationStatus::LAST) + 1); } -void RecordGetRegistrationStatus(PushGetRegistrationStatus status) { +void RecordGetRegistrationStatus(mojom::PushGetRegistrationStatus status) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) || BrowserThread::CurrentlyOn(BrowserThread::UI)); - UMA_HISTOGRAM_ENUMERATION("PushMessaging.GetRegistrationStatus", status, - PUSH_GETREGISTRATION_STATUS_LAST + 1); + UMA_HISTOGRAM_ENUMERATION( + "PushMessaging.GetRegistrationStatus", status, + static_cast<int>(mojom::PushGetRegistrationStatus::LAST) + 1); +} + +const char* PushUnregistrationStatusToString( + mojom::PushUnregistrationStatus status) { + switch (status) { + case mojom::PushUnregistrationStatus::SUCCESS_UNREGISTERED: + return "Unregistration successful - from push service"; + + case mojom::PushUnregistrationStatus::SUCCESS_WAS_NOT_REGISTERED: + return "Unregistration successful - was not registered"; + + case mojom::PushUnregistrationStatus::PENDING_NETWORK_ERROR: + return "Unregistration pending - a network error occurred, but it will " + "be retried until it succeeds"; + + case mojom::PushUnregistrationStatus::NO_SERVICE_WORKER: + return "Unregistration failed - no Service Worker"; + + case mojom::PushUnregistrationStatus::SERVICE_NOT_AVAILABLE: + return "Unregistration failed - push service not available"; + + case mojom::PushUnregistrationStatus::PENDING_SERVICE_ERROR: + return "Unregistration pending - a push service error occurred, but it " + "will be retried until it succeeds"; + + case mojom::PushUnregistrationStatus::STORAGE_ERROR: + return "Unregistration failed - storage error"; + + case mojom::PushUnregistrationStatus::NETWORK_ERROR: + return "Unregistration failed - could not connect to push server"; + } + NOTREACHED(); + return ""; } void UnregisterCallbackToClosure(const base::Closure& closure, - PushUnregistrationStatus status) { + mojom::PushUnregistrationStatus status) { DCHECK(!closure.is_null()); closure.Run(); } @@ -158,8 +195,8 @@ // Callback called on UI thread. void GetSubscriptionDidUnsubscribe( GetSubscriptionCallback callback, - PushGetRegistrationStatus get_status, - PushUnregistrationStatus unsubscribe_status); + mojom::PushGetRegistrationStatus get_status, + mojom::PushUnregistrationStatus unsubscribe_status); // Public GetPermission methods on UI thread --------------------------------- @@ -203,13 +240,14 @@ const std::string& push_registration_id, const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth, - PushRegistrationStatus status); + mojom::PushRegistrationStatus status); // Private Unregister methods on UI thread ----------------------------------- - void DidUnregisterFromService(UnsubscribeCallback callback, - int64_t service_worker_registration_id, - PushUnregistrationStatus unregistration_status); + void DidUnregisterFromService( + UnsubscribeCallback callback, + int64_t service_worker_registration_id, + mojom::PushUnregistrationStatus unregistration_status); // Outer part of the PushMessagingManager which lives on the IO thread. base::WeakPtr<PushMessagingManager> io_parent_; @@ -304,7 +342,7 @@ if (!service_worker_registration || !service_worker_registration->active_version()) { SendSubscriptionError(std::move(data), - PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER); + mojom::PushRegistrationStatus::NO_SERVICE_WORKER); return; } data.requesting_origin = service_worker_registration->pattern().GetOrigin(); @@ -332,12 +370,12 @@ FixSenderInfo(data.options.sender_info, stored_sender_id); if (fixed_sender_id.empty()) { SendSubscriptionError(std::move(data), - PUSH_REGISTRATION_STATUS_NO_SENDER_ID); + mojom::PushRegistrationStatus::NO_SENDER_ID); return; } if (fixed_sender_id != stored_sender_id) { SendSubscriptionError(std::move(data), - PUSH_REGISTRATION_STATUS_SENDER_ID_MISMATCH); + mojom::PushRegistrationStatus::SENDER_ID_MISMATCH); return; } @@ -387,7 +425,7 @@ BrowserThread::IO, FROM_HERE, base::Bind(&PushMessagingManager::SendSubscriptionSuccess, io_parent_, base::Passed(&data), - PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE, + mojom::PushRegistrationStatus::SUCCESS_FROM_CACHE, push_subscription_id, p256dh, auth)); } else { PushMessagingService* push_service = service(); @@ -399,7 +437,7 @@ BrowserThread::IO, FROM_HERE, base::Bind(&PushMessagingManager::SendSubscriptionError, io_parent_, base::Passed(&data), - PUSH_REGISTRATION_STATUS_RENDERER_SHUTDOWN)); + mojom::PushRegistrationStatus::RENDERER_SHUTDOWN)); return; } @@ -410,7 +448,7 @@ // Consider this subscription attempt to have failed. The re-subscribe will // be logged to UMA as a separate subscription attempt. - RecordRegistrationStatus(PUSH_REGISTRATION_STATUS_STORAGE_CORRUPT); + RecordRegistrationStatus(mojom::PushRegistrationStatus::STORAGE_CORRUPT); int64_t registration_id = data.service_worker_registration_id; GURL requesting_origin = data.requesting_origin; @@ -420,8 +458,8 @@ std::vector<std::string>() /* push_registration_id_and_sender_id */, SERVICE_WORKER_ERROR_NOT_FOUND); push_service->Unsubscribe( - PUSH_UNREGISTRATION_REASON_SUBSCRIBE_STORAGE_CORRUPT, requesting_origin, - registration_id, sender_id, + mojom::PushUnregistrationReason::SUBSCRIBE_STORAGE_CORRUPT, + requesting_origin, registration_id, sender_id, base::Bind(&UnregisterCallbackToClosure, base::Bind(IgnoreResult(&BrowserThread::PostTask), BrowserThread::IO, FROM_HERE, try_again_on_io))); @@ -435,7 +473,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); if (service_worker_status != SERVICE_WORKER_OK) { SendSubscriptionError(std::move(data), - PUSH_REGISTRATION_STATUS_NO_SENDER_ID); + mojom::PushRegistrationStatus::NO_SENDER_ID); return; } DCHECK_EQ(1u, stored_sender_id.size()); @@ -445,7 +483,7 @@ FixSenderInfo(data.options.sender_info, stored_sender_id[0]); if (fixed_sender_id.empty()) { SendSubscriptionError(std::move(data), - PUSH_REGISTRATION_STATUS_NO_SENDER_ID); + mojom::PushRegistrationStatus::NO_SENDER_ID); return; } data.options.sender_info = fixed_sender_id; @@ -468,7 +506,7 @@ BrowserThread::IO, FROM_HERE, base::Bind(&PushMessagingManager::SendSubscriptionError, io_parent_, base::Passed(&data), - PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE)); + mojom::PushRegistrationStatus::SERVICE_NOT_AVAILABLE)); } else { // Prevent websites from detecting incognito mode, by emulating what would // have happened if we had a PushMessagingService available. @@ -476,9 +514,10 @@ // Throw a permission denied error under the same circumstances. BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&PushMessagingManager::SendSubscriptionError, io_parent_, - base::Passed(&data), - PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED)); + base::Bind( + &PushMessagingManager::SendSubscriptionError, io_parent_, + base::Passed(&data), + mojom::PushRegistrationStatus::INCOGNITO_PERMISSION_DENIED)); } else { RenderFrameHost* render_frame_host = RenderFrameHost::FromID(render_process_id_, data.render_frame_id); @@ -495,10 +534,10 @@ if (!browser_context->GetPermissionManager()) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind( - &PushMessagingManager::SendSubscriptionError, io_parent_, - base::Passed(&data), - PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED)); + base::Bind(&PushMessagingManager::SendSubscriptionError, + io_parent_, base::Passed(&data), + mojom::PushRegistrationStatus:: + INCOGNITO_PERMISSION_DENIED)); return; } @@ -547,7 +586,7 @@ BrowserThread::IO, FROM_HERE, base::Bind(&PushMessagingManager::SendSubscriptionError, io_parent_, base::Passed(&data), - PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED)); + mojom::PushRegistrationStatus::INCOGNITO_PERMISSION_DENIED)); } void PushMessagingManager::Core::DidRegister( @@ -555,9 +594,9 @@ const std::string& push_registration_id, const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth, - PushRegistrationStatus status) { + mojom::PushRegistrationStatus status) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (status == PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE) { + if (status == mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&PushMessagingManager::PersistRegistrationOnIO, io_parent_, @@ -596,19 +635,20 @@ ServiceWorkerStatusCode service_worker_status) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (service_worker_status == SERVICE_WORKER_OK) { - SendSubscriptionSuccess(std::move(data), - PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE, - push_registration_id, p256dh, auth); + SendSubscriptionSuccess( + std::move(data), + mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE, + push_registration_id, p256dh, auth); } else { // TODO(johnme): Unregister, so PushMessagingServiceImpl can decrease count. SendSubscriptionError(std::move(data), - PUSH_REGISTRATION_STATUS_STORAGE_ERROR); + mojom::PushRegistrationStatus::STORAGE_ERROR); } } void PushMessagingManager::SendSubscriptionError( RegisterData data, - PushRegistrationStatus status) { + mojom::PushRegistrationStatus status) { DCHECK_CURRENTLY_ON(BrowserThread::IO); std::move(data.callback) .Run(status, base::nullopt /* endpoint */, base::nullopt /* options */, @@ -618,7 +658,7 @@ void PushMessagingManager::SendSubscriptionSuccess( RegisterData data, - PushRegistrationStatus status, + mojom::PushRegistrationStatus status, const std::string& push_subscription_id, const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth) { @@ -628,7 +668,7 @@ // that we have an existing registration. Hence it's ok to throw an error. DCHECK(!ui_core_->is_incognito()); SendSubscriptionError(std::move(data), - PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE); + mojom::PushRegistrationStatus::SERVICE_NOT_AVAILABLE); return; } @@ -652,7 +692,7 @@ service_worker_registration_id); if (!service_worker_registration) { DidUnregister(std::move(callback), - PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER); + mojom::PushUnregistrationStatus::NO_SERVICE_WORKER); return; } @@ -699,12 +739,12 @@ BrowserThread::IO, FROM_HERE, base::Bind(&PushMessagingManager::DidUnregister, io_parent_, base::Passed(&callback), - PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE)); + mojom::PushUnregistrationStatus::SERVICE_NOT_AVAILABLE)); return; } push_service->Unsubscribe( - PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API, requesting_origin, + mojom::PushUnregistrationReason::JAVASCRIPT_API, requesting_origin, service_worker_registration_id, sender_id, base::Bind(&Core::DidUnregisterFromService, weak_factory_ui_to_ui_.GetWeakPtr(), base::Passed(&callback), @@ -714,7 +754,7 @@ void PushMessagingManager::Core::DidUnregisterFromService( UnsubscribeCallback callback, int64_t service_worker_registration_id, - PushUnregistrationStatus unregistration_status) { + mojom::PushUnregistrationStatus unregistration_status) { DCHECK_CURRENTLY_ON(BrowserThread::UI); BrowserThread::PostTask( @@ -725,30 +765,30 @@ void PushMessagingManager::DidUnregister( UnsubscribeCallback callback, - PushUnregistrationStatus unregistration_status) { + mojom::PushUnregistrationStatus unregistration_status) { // Only called from IO thread, but would be safe to call from UI thread. DCHECK_CURRENTLY_ON(BrowserThread::IO); switch (unregistration_status) { - case PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED: - case PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR: - case PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR: + case mojom::PushUnregistrationStatus::SUCCESS_UNREGISTERED: + case mojom::PushUnregistrationStatus::PENDING_NETWORK_ERROR: + case mojom::PushUnregistrationStatus::PENDING_SERVICE_ERROR: std::move(callback).Run(blink::WebPushError::kErrorTypeNone, true /* did_unsubscribe */, base::nullopt /* error_message */); break; - case PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED: + case mojom::PushUnregistrationStatus::SUCCESS_WAS_NOT_REGISTERED: std::move(callback).Run(blink::WebPushError::kErrorTypeNone, false /* did_unsubscribe */, base::nullopt /* error_message */); break; - case PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER: - case PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE: - case PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR: + case mojom::PushUnregistrationStatus::NO_SERVICE_WORKER: + case mojom::PushUnregistrationStatus::SERVICE_NOT_AVAILABLE: + case mojom::PushUnregistrationStatus::STORAGE_ERROR: std::move(callback).Run(blink::WebPushError::kErrorTypeAbort, false, std::string(PushUnregistrationStatusToString( unregistration_status)) /* error_message */); break; - case PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR: + case mojom::PushUnregistrationStatus::NETWORK_ERROR: NOTREACHED(); break; } @@ -778,8 +818,8 @@ const std::vector<std::string>& push_subscription_id_and_sender_info, ServiceWorkerStatusCode service_worker_status) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - PushGetRegistrationStatus get_status = - PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR; + mojom::PushGetRegistrationStatus get_status = + mojom::PushGetRegistrationStatus::STORAGE_ERROR; switch (service_worker_status) { case SERVICE_WORKER_OK: { DCHECK_EQ(2u, push_subscription_id_and_sender_info.size()); @@ -791,8 +831,9 @@ // Return not found in incognito mode, so websites can't detect it. get_status = ui_core_->is_incognito() - ? PUSH_GETREGISTRATION_STATUS_INCOGNITO_REGISTRATION_NOT_FOUND - : PUSH_GETREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE; + ? mojom::PushGetRegistrationStatus:: + INCOGNITO_REGISTRATION_NOT_FOUND + : mojom::PushGetRegistrationStatus::SERVICE_NOT_AVAILABLE; break; } @@ -800,7 +841,7 @@ service_worker_context_->GetLiveRegistration( service_worker_registration_id); if (!registration) { - get_status = PUSH_GETREGISTRATION_STATUS_NO_LIVE_SERVICE_WORKER; + get_status = mojom::PushGetRegistrationStatus::NO_LIVE_SERVICE_WORKER; break; } @@ -824,11 +865,11 @@ return; } case SERVICE_WORKER_ERROR_NOT_FOUND: { - get_status = PUSH_GETREGISTRATION_STATUS_REGISTRATION_NOT_FOUND; + get_status = mojom::PushGetRegistrationStatus::REGISTRATION_NOT_FOUND; break; } case SERVICE_WORKER_ERROR_FAILED: { - get_status = PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR; + get_status = mojom::PushGetRegistrationStatus::STORAGE_ERROR; break; } case SERVICE_WORKER_ERROR_ABORT: @@ -850,7 +891,7 @@ case SERVICE_WORKER_ERROR_MAX_VALUE: { NOTREACHED() << "Got unexpected error code: " << service_worker_status << " " << ServiceWorkerStatusToString(service_worker_status); - get_status = PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR; + get_status = mojom::PushGetRegistrationStatus::STORAGE_ERROR; break; } } @@ -879,7 +920,8 @@ options.user_visible_only = true; options.sender_info = sender_info; - PushGetRegistrationStatus status = PUSH_GETREGISTRATION_STATUS_SUCCESS; + mojom::PushGetRegistrationStatus status = + mojom::PushGetRegistrationStatus::SUCCESS; BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::BindOnce(std::move(callback), status, @@ -895,7 +937,7 @@ BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::BindOnce(std::move(callback), - PUSH_GETREGISTRATION_STATUS_RENDERER_SHUTDOWN, + mojom::PushGetRegistrationStatus::RENDERER_SHUTDOWN, base::nullopt /* endpoint */, base::nullopt /* options */, base::nullopt /* p256dh */, base::nullopt /* auth */)); @@ -906,12 +948,12 @@ // database, it did not have matching counterparts in the // PushMessagingAppIdentifier map and/or GCM Store. Unsubscribe to fix this // inconsistency. - PushGetRegistrationStatus status = - PUSH_GETREGISTRATION_STATUS_STORAGE_CORRUPT; + mojom::PushGetRegistrationStatus status = + mojom::PushGetRegistrationStatus::STORAGE_CORRUPT; push_service->Unsubscribe( - PUSH_UNREGISTRATION_REASON_GET_SUBSCRIPTION_STORAGE_CORRUPT, origin, - service_worker_registration_id, sender_info, + mojom::PushUnregistrationReason::GET_SUBSCRIPTION_STORAGE_CORRUPT, + origin, service_worker_registration_id, sender_info, base::Bind(&Core::GetSubscriptionDidUnsubscribe, weak_factory_ui_to_ui_.GetWeakPtr(), base::Passed(&callback), status)); @@ -922,8 +964,8 @@ void PushMessagingManager::Core::GetSubscriptionDidUnsubscribe( GetSubscriptionCallback callback, - PushGetRegistrationStatus get_status, - PushUnregistrationStatus unsubscribe_status) { + mojom::PushGetRegistrationStatus get_status, + mojom::PushUnregistrationStatus unsubscribe_status) { DCHECK_CURRENTLY_ON(BrowserThread::UI); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE,
diff --git a/content/browser/push_messaging/push_messaging_manager.h b/content/browser/push_messaging/push_messaging_manager.h index 495f9bce..01d0899 100644 --- a/content/browser/push_messaging/push_messaging_manager.h +++ b/content/browser/push_messaging/push_messaging_manager.h
@@ -16,7 +16,6 @@ #include "content/common/push_messaging.mojom.h" #include "content/common/service_worker/service_worker_status_code.h" #include "content/public/browser/browser_thread.h" -#include "content/public/common/push_messaging_status.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "url/gurl.h" @@ -26,6 +25,11 @@ namespace content { +namespace mojom { +enum class PushRegistrationStatus; +enum class PushUnregistrationStatus; +} // namespace mojom + class PushMessagingService; class ServiceWorkerContextWrapper; struct PushSubscriptionOptions; @@ -89,10 +93,11 @@ ServiceWorkerStatusCode service_worker_status); // Called both from IO thread, and via PostTask from UI thread. - void SendSubscriptionError(RegisterData data, PushRegistrationStatus status); + void SendSubscriptionError(RegisterData data, + mojom::PushRegistrationStatus status); // Called both from IO thread, and via PostTask from UI thread. void SendSubscriptionSuccess(RegisterData data, - PushRegistrationStatus status, + mojom::PushRegistrationStatus status, const std::string& push_subscription_id, const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth); @@ -106,7 +111,7 @@ // Called both from IO thread, and via PostTask from UI thread. void DidUnregister(UnsubscribeCallback callback, - PushUnregistrationStatus unregistration_status); + mojom::PushUnregistrationStatus unregistration_status); void DidGetSubscription( GetSubscriptionCallback callback,
diff --git a/content/browser/push_messaging/push_messaging_router.cc b/content/browser/push_messaging/push_messaging_router.cc index 995b15d9..7f87b28 100644 --- a/content/browser/push_messaging/push_messaging_router.cc +++ b/content/browser/push_messaging/push_messaging_router.cc
@@ -17,6 +17,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/push_event_payload.h" +#include "content/public/common/push_messaging_status.mojom.h" namespace content { @@ -28,7 +29,7 @@ void RunDeliverCallback( const PushMessagingRouter::DeliverMessageCallback& deliver_message_callback, - PushDeliveryStatus delivery_status) { + mojom::PushDeliveryStatus delivery_status) { DCHECK_CURRENTLY_ON(BrowserThread::IO); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, @@ -85,12 +86,12 @@ SERVICE_WORKER_ERROR_MAX_VALUE); if (service_worker_status == SERVICE_WORKER_ERROR_NOT_FOUND) { RunDeliverCallback(deliver_message_callback, - PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER); + mojom::PushDeliveryStatus::NO_SERVICE_WORKER); return; } if (service_worker_status != SERVICE_WORKER_OK) { RunDeliverCallback(deliver_message_callback, - PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR); + mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR); return; } @@ -137,17 +138,17 @@ UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus.ServiceWorkerEvent", service_worker_status, SERVICE_WORKER_ERROR_MAX_VALUE); - PushDeliveryStatus delivery_status = - PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR; + mojom::PushDeliveryStatus delivery_status = + mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR; switch (service_worker_status) { case SERVICE_WORKER_OK: - delivery_status = PUSH_DELIVERY_STATUS_SUCCESS; + delivery_status = mojom::PushDeliveryStatus::SUCCESS; break; case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED: - delivery_status = PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED; + delivery_status = mojom::PushDeliveryStatus::EVENT_WAITUNTIL_REJECTED; break; case SERVICE_WORKER_ERROR_TIMEOUT: - delivery_status = PUSH_DELIVERY_STATUS_TIMEOUT; + delivery_status = mojom::PushDeliveryStatus::TIMEOUT; break; case SERVICE_WORKER_ERROR_FAILED: case SERVICE_WORKER_ERROR_ABORT: @@ -159,7 +160,7 @@ case SERVICE_WORKER_ERROR_DISK_CACHE: case SERVICE_WORKER_ERROR_REDUNDANT: case SERVICE_WORKER_ERROR_DISALLOWED: - delivery_status = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR; + delivery_status = mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR; break; case SERVICE_WORKER_ERROR_EXISTS: case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED: @@ -170,7 +171,7 @@ case SERVICE_WORKER_ERROR_MAX_VALUE: NOTREACHED() << "Got unexpected error code: " << service_worker_status << " " << ServiceWorkerStatusToString(service_worker_status); - delivery_status = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR; + delivery_status = mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR; break; } RunDeliverCallback(deliver_message_callback, delivery_status);
diff --git a/content/browser/push_messaging/push_messaging_router.h b/content/browser/push_messaging/push_messaging_router.h index d57366f..9fae535 100644 --- a/content/browser/push_messaging/push_messaging_router.h +++ b/content/browser/push_messaging/push_messaging_router.h
@@ -12,12 +12,15 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "content/common/service_worker/service_worker_status_code.h" -#include "content/public/common/push_messaging_status.h" #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerEventResult.h" #include "url/gurl.h" namespace content { +namespace mojom { +enum class PushDeliveryStatus; +} + class BrowserContext; struct PushEventPayload; class ServiceWorkerContextWrapper; @@ -26,7 +29,8 @@ class PushMessagingRouter { public: - typedef base::Callback<void(PushDeliveryStatus)> DeliverMessageCallback; + using DeliverMessageCallback = + base::Callback<void(mojom::PushDeliveryStatus)>; // Delivers a push message with |data| to the Service Worker identified by // |origin| and |service_worker_registration_id|. Must be called on the UI
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc index 91b296e..87b3229 100644 --- a/content/browser/service_manager/service_manager_context.cc +++ b/content/browser/service_manager/service_manager_context.cc
@@ -77,15 +77,15 @@ void StartServiceInUtilityProcess( const std::string& service_name, const base::string16& process_name, - bool use_sandbox, + SandboxType sandbox_type, service_manager::mojom::ServiceRequest request) { DCHECK_CURRENTLY_ON(BrowserThread::IO); UtilityProcessHost* process_host = UtilityProcessHost::Create(nullptr, nullptr); process_host->SetName(process_name); - if (!use_sandbox) - process_host->DisableSandbox(); + process_host->SetSandboxType(sandbox_type); process_host->Start(); + service_manager::mojom::ServiceFactoryPtr service_factory; BindInterface(process_host, mojo::MakeRequest(&service_factory)); service_factory->CreateService(std::move(request), service_name); @@ -337,49 +337,37 @@ // GetConnectorForIOThread(). g_io_thread_connector.Get() = browser_connection->GetConnector()->Clone(); - ContentBrowserClient::OutOfProcessServiceMap sandboxed_services; - GetContentClient() - ->browser() - ->RegisterOutOfProcessServices(&sandboxed_services); - sandboxed_services.insert( - std::make_pair(data_decoder::mojom::kServiceName, - base::ASCIIToUTF16("Data Decoder Service"))); - for (const auto& service : sandboxed_services) { - packaged_services_connection_->AddServiceRequestHandler( - service.first, base::Bind(&StartServiceInUtilityProcess, service.first, - service.second, true /* use_sandbox */)); - } + ContentBrowserClient::OutOfProcessServiceMap out_of_process_services; + GetContentClient()->browser()->RegisterOutOfProcessServices( + &out_of_process_services); - ContentBrowserClient::OutOfProcessServiceMap unsandboxed_services; - GetContentClient() - ->browser() - ->RegisterUnsandboxedOutOfProcessServices(&unsandboxed_services); + out_of_process_services[data_decoder::mojom::kServiceName] = { + base::ASCIIToUTF16("Data Decoder Service"), SANDBOX_TYPE_UTILITY}; bool network_service_enabled = base::FeatureList::IsEnabled(features::kNetworkService); if (network_service_enabled) { - unsandboxed_services.insert( - std::make_pair(content::mojom::kNetworkServiceName, - base::ASCIIToUTF16("Network Service"))); + out_of_process_services[content::mojom::kNetworkServiceName] = { + base::ASCIIToUTF16("Network Service"), SANDBOX_TYPE_NETWORK}; } + if (base::FeatureList::IsEnabled(video_capture::kMojoVideoCapture)) { - unsandboxed_services.insert( - std::make_pair(video_capture::mojom::kServiceName, - base::ASCIIToUTF16("Video Capture Service"))); + out_of_process_services[video_capture::mojom::kServiceName] = { + base::ASCIIToUTF16("Video Capture Service"), SANDBOX_TYPE_NO_SANDBOX}; } #if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS) // TODO(xhwang): This is only used for test/experiment for now so it's okay // to run it in an unsandboxed utility process. Fix CDM loading so that we can // run it in the sandboxed utility process. See http://crbug.com/510604 - unsandboxed_services.insert(std::make_pair( - media::mojom::kMediaServiceName, base::ASCIIToUTF16("Media Service"))); + out_of_process_services[media::mojom::kMediaServiceName] = { + base::ASCIIToUTF16("Media Service"), SANDBOX_TYPE_NO_SANDBOX}; #endif - for (const auto& service : unsandboxed_services) { + for (const auto& service : out_of_process_services) { packaged_services_connection_->AddServiceRequestHandler( service.first, base::Bind(&StartServiceInUtilityProcess, service.first, - service.second, false /* use_sandbox */)); + service.second.first, service.second.second)); } #if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc index 6fb729c..740885a 100644 --- a/content/browser/speech/speech_recognition_manager_impl.cc +++ b/content/browser/speech/speech_recognition_manager_impl.cc
@@ -156,9 +156,9 @@ if (delegate_) { delegate_->CheckRecognitionIsAllowed( session_id, - base::Bind(&SpeechRecognitionManagerImpl::RecognitionAllowedCallback, - weak_factory_.GetWeakPtr(), - session_id)); + base::BindOnce( + &SpeechRecognitionManagerImpl::RecognitionAllowedCallback, + weak_factory_.GetWeakPtr(), session_id)); } } @@ -274,7 +274,7 @@ SessionsTable::iterator iter = sessions_.find(session_id); if (iter->second->ui) { // Notify the UI that the devices are being used. - iter->second->ui->OnStarted(base::Closure(), + iter->second->ui->OnStarted(base::OnceClosure(), MediaStreamUIProxy::WindowIdCallback()); }
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc index f6c4e30..7a9069e 100644 --- a/content/browser/utility_process_host_impl.cc +++ b/content/browser/utility_process_host_impl.cc
@@ -168,8 +168,11 @@ exposed_dir_ = dir; } -void UtilityProcessHostImpl::DisableSandbox() { - no_sandbox_ = true; +void UtilityProcessHostImpl::SetSandboxType(SandboxType sandbox_type) { + DCHECK(sandbox_type != SANDBOX_TYPE_INVALID); + + // TODO(tsepez): Store sandbox type itself. + no_sandbox_ = IsUnsandboxedSandboxType(sandbox_type); } #if defined(OS_WIN)
diff --git a/content/browser/utility_process_host_impl.h b/content/browser/utility_process_host_impl.h index 517fb3c..0bf3880 100644 --- a/content/browser/utility_process_host_impl.h +++ b/content/browser/utility_process_host_impl.h
@@ -44,7 +44,7 @@ base::WeakPtr<UtilityProcessHost> AsWeakPtr() override; bool Send(IPC::Message* message) override; void SetExposedDir(const base::FilePath& dir) override; - void DisableSandbox() override; + void SetSandboxType(SandboxType sandbox_type) override; #if defined(OS_WIN) void ElevatePrivileges() override; #endif
diff --git a/content/child/push_messaging/push_provider.cc b/content/child/push_messaging/push_provider.cc index 54761ccb..f571543c 100644 --- a/content/child/push_messaging/push_provider.cc +++ b/content/child/push_messaging/push_provider.cc
@@ -14,6 +14,7 @@ #include "content/child/child_thread_impl.h" #include "content/child/service_worker/web_service_worker_registration_impl.h" #include "content/public/common/child_process_host.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "content/public/common/push_subscription_options.h" #include "content/public/common/service_names.mojom.h" #include "services/service_manager/public/cpp/connector.h" @@ -24,8 +25,65 @@ namespace content { namespace { -int CurrentWorkerId() { - return WorkerThread::GetCurrentId(); +const char* PushRegistrationStatusToString( + mojom::PushRegistrationStatus status) { + switch (status) { + case mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE: + return "Registration successful - from push service"; + + case mojom::PushRegistrationStatus::NO_SERVICE_WORKER: + return "Registration failed - no Service Worker"; + + case mojom::PushRegistrationStatus::SERVICE_NOT_AVAILABLE: + return "Registration failed - push service not available"; + + case mojom::PushRegistrationStatus::LIMIT_REACHED: + return "Registration failed - registration limit has been reached"; + + case mojom::PushRegistrationStatus::PERMISSION_DENIED: + return "Registration failed - permission denied"; + + case mojom::PushRegistrationStatus::SERVICE_ERROR: + return "Registration failed - push service error"; + + case mojom::PushRegistrationStatus::NO_SENDER_ID: + return "Registration failed - missing applicationServerKey, and " + "gcm_sender_id not found in manifest"; + + case mojom::PushRegistrationStatus::STORAGE_ERROR: + return "Registration failed - storage error"; + + case mojom::PushRegistrationStatus::SUCCESS_FROM_CACHE: + return "Registration successful - from cache"; + + case mojom::PushRegistrationStatus::NETWORK_ERROR: + return "Registration failed - could not connect to push server"; + + case mojom::PushRegistrationStatus::INCOGNITO_PERMISSION_DENIED: + // We split this out for UMA, but it must be indistinguishable to JS. + return PushRegistrationStatusToString( + mojom::PushRegistrationStatus::PERMISSION_DENIED); + + case mojom::PushRegistrationStatus::PUBLIC_KEY_UNAVAILABLE: + return "Registration failed - could not retrieve the public key"; + + case mojom::PushRegistrationStatus::MANIFEST_EMPTY_OR_MISSING: + return "Registration failed - missing applicationServerKey, and manifest " + "empty or missing"; + + case mojom::PushRegistrationStatus::SENDER_ID_MISMATCH: + return "Registration failed - A subscription with a different " + "applicationServerKey (or gcm_sender_id) already exists; to " + "change the applicationServerKey, unsubscribe then resubscribe."; + + case mojom::PushRegistrationStatus::STORAGE_CORRUPT: + return "Registration failed - storage corrupt"; + + case mojom::PushRegistrationStatus::RENDERER_SHUTDOWN: + return "Registration failed - renderer shutdown"; + } + NOTREACHED(); + return ""; } // Returns the id of the given |service_worker_registration|, which @@ -40,30 +98,30 @@ } // namespace blink::WebPushError PushRegistrationStatusToWebPushError( - PushRegistrationStatus status) { + mojom::PushRegistrationStatus status) { blink::WebPushError::ErrorType error_type = blink::WebPushError::kErrorTypeAbort; switch (status) { - case PUSH_REGISTRATION_STATUS_PERMISSION_DENIED: + case mojom::PushRegistrationStatus::PERMISSION_DENIED: error_type = blink::WebPushError::kErrorTypeNotAllowed; break; - case PUSH_REGISTRATION_STATUS_SENDER_ID_MISMATCH: + case mojom::PushRegistrationStatus::SENDER_ID_MISMATCH: error_type = blink::WebPushError::kErrorTypeInvalidState; break; - case PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE: - case PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER: - case PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE: - case PUSH_REGISTRATION_STATUS_LIMIT_REACHED: - case PUSH_REGISTRATION_STATUS_SERVICE_ERROR: - case PUSH_REGISTRATION_STATUS_NO_SENDER_ID: - case PUSH_REGISTRATION_STATUS_STORAGE_ERROR: - case PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE: - case PUSH_REGISTRATION_STATUS_NETWORK_ERROR: - case PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED: - case PUSH_REGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE: - case PUSH_REGISTRATION_STATUS_MANIFEST_EMPTY_OR_MISSING: - case PUSH_REGISTRATION_STATUS_STORAGE_CORRUPT: - case PUSH_REGISTRATION_STATUS_RENDERER_SHUTDOWN: + case mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE: + case mojom::PushRegistrationStatus::NO_SERVICE_WORKER: + case mojom::PushRegistrationStatus::SERVICE_NOT_AVAILABLE: + case mojom::PushRegistrationStatus::LIMIT_REACHED: + case mojom::PushRegistrationStatus::SERVICE_ERROR: + case mojom::PushRegistrationStatus::NO_SENDER_ID: + case mojom::PushRegistrationStatus::STORAGE_ERROR: + case mojom::PushRegistrationStatus::SUCCESS_FROM_CACHE: + case mojom::PushRegistrationStatus::NETWORK_ERROR: + case mojom::PushRegistrationStatus::INCOGNITO_PERMISSION_DENIED: + case mojom::PushRegistrationStatus::PUBLIC_KEY_UNAVAILABLE: + case mojom::PushRegistrationStatus::MANIFEST_EMPTY_OR_MISSING: + case mojom::PushRegistrationStatus::STORAGE_CORRUPT: + case mojom::PushRegistrationStatus::RENDERER_SHUTDOWN: error_type = blink::WebPushError::kErrorTypeAbort; break; } @@ -101,7 +159,7 @@ return g_push_provider_tls.Pointer()->Get(); PushProvider* provider = new PushProvider(main_thread_task_runner); - if (CurrentWorkerId()) + if (WorkerThread::GetCurrentId()) WorkerThread::AddObserver(provider); return provider; } @@ -146,15 +204,15 @@ void PushProvider::DidSubscribe( std::unique_ptr<blink::WebPushSubscriptionCallbacks> callbacks, - content::PushRegistrationStatus status, + mojom::PushRegistrationStatus status, const base::Optional<GURL>& endpoint, - const base::Optional<content::PushSubscriptionOptions>& options, + const base::Optional<PushSubscriptionOptions>& options, const base::Optional<std::vector<uint8_t>>& p256dh, const base::Optional<std::vector<uint8_t>>& auth) { DCHECK(callbacks); - if (status == PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE || - status == PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE) { + if (status == mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE || + status == mojom::PushRegistrationStatus::SUCCESS_FROM_CACHE) { DCHECK(endpoint); DCHECK(options); DCHECK(p256dh); @@ -221,14 +279,14 @@ void PushProvider::DidGetSubscription( std::unique_ptr<blink::WebPushSubscriptionCallbacks> callbacks, - content::PushGetRegistrationStatus status, + mojom::PushGetRegistrationStatus status, const base::Optional<GURL>& endpoint, - const base::Optional<content::PushSubscriptionOptions>& options, + const base::Optional<PushSubscriptionOptions>& options, const base::Optional<std::vector<uint8_t>>& p256dh, const base::Optional<std::vector<uint8_t>>& auth) { DCHECK(callbacks); - if (status == PUSH_GETREGISTRATION_STATUS_SUCCESS) { + if (status == mojom::PushGetRegistrationStatus::SUCCESS) { DCHECK(endpoint); DCHECK(options); DCHECK(p256dh);
diff --git a/content/child/push_messaging/push_provider.h b/content/child/push_messaging/push_provider.h index 6264fc18..07d3bda 100644 --- a/content/child/push_messaging/push_provider.h +++ b/content/child/push_messaging/push_provider.h
@@ -15,7 +15,6 @@ #include "base/memory/ref_counted.h" #include "content/common/push_messaging.mojom.h" #include "content/public/child/worker_thread.h" -#include "content/public/common/push_messaging_status.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushProvider.h" @@ -27,10 +26,15 @@ namespace content { +namespace mojom { +enum class PushGetRegistrationStatus; +enum class PushRegistrationStatus; +} // namespace mojom + struct PushSubscriptionOptions; blink::WebPushError PushRegistrationStatusToWebPushError( - PushRegistrationStatus status); + mojom::PushRegistrationStatus status); class PushProvider : public blink::WebPushProvider, public WorkerThread::Observer { @@ -70,9 +74,9 @@ void DidSubscribe( std::unique_ptr<blink::WebPushSubscriptionCallbacks> callbacks, - content::PushRegistrationStatus status, + mojom::PushRegistrationStatus status, const base::Optional<GURL>& endpoint, - const base::Optional<content::PushSubscriptionOptions>& options, + const base::Optional<PushSubscriptionOptions>& options, const base::Optional<std::vector<uint8_t>>& p256dh, const base::Optional<std::vector<uint8_t>>& auth); @@ -84,9 +88,9 @@ void DidGetSubscription( std::unique_ptr<blink::WebPushSubscriptionCallbacks> callbacks, - content::PushGetRegistrationStatus status, + mojom::PushGetRegistrationStatus status, const base::Optional<GURL>& endpoint, - const base::Optional<content::PushSubscriptionOptions>& options, + const base::Optional<PushSubscriptionOptions>& options, const base::Optional<std::vector<uint8_t>>& p256dh, const base::Optional<std::vector<uint8_t>>& auth);
diff --git a/content/common/push_messaging.mojom b/content/common/push_messaging.mojom index 94b0ea1..7b0b64c 100644 --- a/content/common/push_messaging.mojom +++ b/content/common/push_messaging.mojom
@@ -4,6 +4,7 @@ module content.mojom; +import "content/public/common/push_messaging_status.mojom"; import "url/mojo/url.mojom"; // TODO(heke): The type-mapping struct and enums are duplicately defined. Need @@ -14,75 +15,6 @@ string sender_info; }; -// Push registration success/error codes for internal use & reporting in UMA. -// Enum values can be added, but must never be renumbered or deleted and reused. -enum PushRegistrationStatus { - // New successful registration (there was not yet a registration cached in - // Service Worker storage, so the browser successfully registered with the - // push service. This is likely to be a new push registration, though it's - // possible that the push service had its own cache (for example if Chrome's - // app data was cleared, we might have forgotten about a registration that the - // push service still stores). - SUCCESS_FROM_PUSH_SERVICE = 0, - - // Registration failed because there is no Service Worker. - NO_SERVICE_WORKER = 1, - - // Registration failed because the push service is not available. - SERVICE_NOT_AVAILABLE = 2, - - // Registration failed because the maximum number of registratons has been - // reached. - LIMIT_REACHED = 3, - - // Registration failed because permission was denied. - PERMISSION_DENIED = 4, - - // Registration failed in the push service implemented by the embedder. - SERVICE_ERROR = 5, - - // Registration failed because no sender id was provided by the page. - NO_SENDER_ID = 6, - - // Registration succeeded, but we failed to persist it. - STORAGE_ERROR = 7, - - // A successful registration was already cached in Service Worker storage. - SUCCESS_FROM_CACHE = 8, - - // Registration failed due to a network error. - NETWORK_ERROR = 9, - - // Registration failed because the push service is not available in incognito, - // but we tell JS that permission was denied to not reveal incognito. - INCOGNITO_PERMISSION_DENIED = 10, - - // Registration failed because the public key could not be retrieved. - PUBLIC_KEY_UNAVAILABLE = 11, - - // Registration failed because the manifest could not be retrieved or was - // empty. - MANIFEST_EMPTY_OR_MISSING = 12, - - // Registration failed because a subscription with a different sender id - // already exists. - SENDER_ID_MISMATCH = 13, - - // Registration failed because storage was corrupt. It will be retried - // automatically after unsubscribing to fix the corruption. - STORAGE_CORRUPT = 14, - - // Registration failed because the renderer was shut down. - RENDERER_SHUTDOWN = 15, - - // NOTE: Do not renumber these as that would confuse interpretation of - // previously logged data. When making changes, also update the enum list - // in tools/metrics/histograms/histograms.xml to keep it in sync, and - // update LAST below. - - LAST = RENDERER_SHUTDOWN -}; - enum PushErrorType { ABORT = 0, NETWORK = 1, @@ -94,45 +26,6 @@ LAST = INVALID_STATE }; -// Push getregistration success/error codes for internal use & reporting in UMA. -// Enum values can be added, but must never be renumbered or deleted and reused. -enum PushGetRegistrationStatus { - // Getting the registration was successful. - SUCCESS = 0, - - // Getting the registration failed because the push service is not available. - SERVICE_NOT_AVAILABLE = 1, - - // Getting the registration failed because we failed to read from storage. - STORAGE_ERROR = 2, - - // Getting the registration failed because there is no push registration. - REGISTRATION_NOT_FOUND = 3, - - // Getting the registration failed because the push service isn't available in - // incognito, but we tell JS registration not found to not reveal incognito. - INCOGNITO_REGISTRATION_NOT_FOUND = 4, - - // Getting the registration failed because public key could not be retrieved. - // PUBLIC_KEY_UNAVAILABLE = 5, - - // Getting the registration failed because storage was corrupt. - STORAGE_CORRUPT = 6, - - // Getting the registration failed because the renderer was shut down. - RENDERER_SHUTDOWN = 7, - - // Getting the registration failed because there was no live service worker. - NO_LIVE_SERVICE_WORKER = 8, - - // NOTE: Do not renumber these as that would confuse interpretation of - // previously logged data. When making changes, also update the enum list - // in tools/metrics/histograms/histograms.xml to keep it in sync, and - // update LAST below. - - LAST = NO_LIVE_SERVICE_WORKER -}; - enum PushPermissionStatus { GRANTED = 0, DENIED = 1,
diff --git a/content/common/push_messaging.typemap b/content/common/push_messaging.typemap index c2afcc8..c3b94c6 100644 --- a/content/common/push_messaging.typemap +++ b/content/common/push_messaging.typemap
@@ -4,7 +4,6 @@ mojom = "//content/common/push_messaging.mojom" public_headers = [ - "//content/public/common/push_messaging_status.h", "//content/public/common/push_subscription_options.h", "//third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h", "//third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h", @@ -21,8 +20,6 @@ ] type_mappings = [ "content.mojom.PushErrorType=blink::WebPushError::ErrorType", - "content.mojom.PushGetRegistrationStatus=content::PushGetRegistrationStatus", "content.mojom.PushPermissionStatus=blink::WebPushPermissionStatus", - "content.mojom.PushRegistrationStatus=content::PushRegistrationStatus", "content.mojom.PushSubscriptionOptions=content::PushSubscriptionOptions", ]
diff --git a/content/common/push_messaging_param_traits.cc b/content/common/push_messaging_param_traits.cc index 882ab47..a0b6240 100644 --- a/content/common/push_messaging_param_traits.cc +++ b/content/common/push_messaging_param_traits.cc
@@ -4,121 +4,10 @@ #include "content/common/push_messaging_param_traits.h" +#include "content/public/common/push_messaging_status.mojom.h" + namespace mojo { -// PushRegistrationStatus -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE), - "PushRegistrationStatus enums must match, SUCCESS_FROM_PUSH_SERVICE"); - -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::NO_SERVICE_WORKER), - "PushRegistrationStatus enums must match, NO_SERVICE_WORKER"); - -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::SERVICE_NOT_AVAILABLE), - "PushRegistrationStatus enums must match, SERVICE_NOT_AVAILABLE"); - -static_assert( - content::PushRegistrationStatus::PUSH_REGISTRATION_STATUS_LIMIT_REACHED == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::LIMIT_REACHED), - "PushRegistrationStatus enums must match, LIMIT_REACHED"); - -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_PERMISSION_DENIED == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::PERMISSION_DENIED), - "PushRegistrationStatus enums must match, PERMISSION_DENIED"); - -static_assert( - content::PushRegistrationStatus::PUSH_REGISTRATION_STATUS_SERVICE_ERROR == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::SERVICE_ERROR), - "PushRegistrationStatus enums must match, SERVICE_ERROR"); - -static_assert( - content::PushRegistrationStatus::PUSH_REGISTRATION_STATUS_NO_SENDER_ID == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::NO_SENDER_ID), - "PushRegistrationStatus enums must match, NO_SENDER_ID"); - -static_assert( - content::PushRegistrationStatus::PUSH_REGISTRATION_STATUS_STORAGE_ERROR == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::STORAGE_ERROR), - "PushRegistrationStatus enums must match, STORAGE_ERROR"); - -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::SUCCESS_FROM_CACHE), - "PushRegistrationStatus enums must match, SUCCESS_FROM_CACHE"); - -static_assert( - content::PushRegistrationStatus::PUSH_REGISTRATION_STATUS_NETWORK_ERROR == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::NETWORK_ERROR), - "PushRegistrationStatus enums must match, NETWORK_ERROR"); - -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus:: - INCOGNITO_PERMISSION_DENIED), - "PushRegistrationStatus enums must match, INCOGNITO_PERMISSION_DENIED"); - -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::PUBLIC_KEY_UNAVAILABLE), - "PushRegistrationStatus enums must match, PUBLIC_KEY_UNAVAILABLE"); - -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_MANIFEST_EMPTY_OR_MISSING == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::MANIFEST_EMPTY_OR_MISSING), - "PushRegistrationStatus enums must match, MANIFEST_EMPTY_OR_MISSING"); - -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_SENDER_ID_MISMATCH == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::SENDER_ID_MISMATCH), - "PushRegistrationStatus enums must match, SENDER_ID_MISMATCH"); - -static_assert( - content::PushRegistrationStatus::PUSH_REGISTRATION_STATUS_STORAGE_CORRUPT == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::STORAGE_CORRUPT), - "PushRegistrationStatus enums must match, STORAGE_CORRUPT"); - -static_assert( - content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_RENDERER_SHUTDOWN == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::RENDERER_SHUTDOWN), - "PushRegistrationStatus enums must match, RENDERER_SHUTDOWN"); - -static_assert(content::PushRegistrationStatus::PUSH_REGISTRATION_STATUS_LAST == - static_cast<content::PushRegistrationStatus>( - content::mojom::PushRegistrationStatus::LAST), - "PushRegistrationStatus enums must match, LAST"); - // PushErrorType static_assert(blink::WebPushError::ErrorType::kErrorTypeAbort == static_cast<blink::WebPushError::ErrorType>( @@ -160,69 +49,6 @@ content::mojom::PushErrorType::LAST), "PushErrorType enums must match, LAST"); -// PushGetRegistrationStatus -static_assert( - content::PushGetRegistrationStatus::PUSH_GETREGISTRATION_STATUS_SUCCESS == - static_cast<content::PushGetRegistrationStatus>( - content::mojom::PushGetRegistrationStatus::SUCCESS), - "PushGetRegistrationStatus enums must match, SUCCESS"); - -static_assert( - content::PushGetRegistrationStatus:: - PUSH_GETREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE == - static_cast<content::PushGetRegistrationStatus>( - content::mojom::PushGetRegistrationStatus::SERVICE_NOT_AVAILABLE), - "PushGetRegistrationStatus enums must match, SERVICE_NOT_AVAILABLE"); - -static_assert(content::PushGetRegistrationStatus:: - PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR == - static_cast<content::PushGetRegistrationStatus>( - content::mojom::PushGetRegistrationStatus::STORAGE_ERROR), - "PushGetRegistrationStatus enums must match, STORAGE_ERROR"); - -static_assert( - content::PushGetRegistrationStatus:: - PUSH_GETREGISTRATION_STATUS_REGISTRATION_NOT_FOUND == - static_cast<content::PushGetRegistrationStatus>( - content::mojom::PushGetRegistrationStatus::REGISTRATION_NOT_FOUND), - "PushGetRegistrationStatus enums must match, REGISTRATION_NOT_FOUND"); - -static_assert( - content::PushGetRegistrationStatus:: - PUSH_GETREGISTRATION_STATUS_INCOGNITO_REGISTRATION_NOT_FOUND == - static_cast<content::PushGetRegistrationStatus>( - content::mojom::PushGetRegistrationStatus:: - INCOGNITO_REGISTRATION_NOT_FOUND), - "PushGetRegistrationStatus enums must match, " - "INCOGNITO_REGISTRATION_NOT_FOUND"); - -static_assert( - content::PushGetRegistrationStatus:: - PUSH_GETREGISTRATION_STATUS_STORAGE_CORRUPT == - static_cast<content::PushGetRegistrationStatus>( - content::mojom::PushGetRegistrationStatus::STORAGE_CORRUPT), - "PushGetRegistrationStatus enums must match, STORAGE_CORRUPT"); - -static_assert( - content::PushGetRegistrationStatus:: - PUSH_GETREGISTRATION_STATUS_NO_LIVE_SERVICE_WORKER == - static_cast<content::PushGetRegistrationStatus>( - content::mojom::PushGetRegistrationStatus::NO_LIVE_SERVICE_WORKER), - "PushGetRegistrationStatus enums must match, NO_LIVE_SERVICE_WORKER"); - -static_assert( - content::PushGetRegistrationStatus:: - PUSH_GETREGISTRATION_STATUS_RENDERER_SHUTDOWN == - static_cast<content::PushGetRegistrationStatus>( - content::mojom::PushGetRegistrationStatus::RENDERER_SHUTDOWN), - "PushGetRegistrationStatus enums must match, RENDERER_SHUTDOWN"); - -static_assert( - content::PushGetRegistrationStatus::PUSH_GETREGISTRATION_STATUS_LAST == - static_cast<content::PushGetRegistrationStatus>( - content::mojom::PushGetRegistrationStatus::LAST), - "PushGetRegistrationStatus enums must match, LAST"); - // PushPermissionStatus static_assert(blink::WebPushPermissionStatus::kWebPushPermissionStatusGranted == static_cast<blink::WebPushPermissionStatus>( @@ -257,37 +83,6 @@ } // static -content::mojom::PushRegistrationStatus EnumTraits< - content::mojom::PushRegistrationStatus, - content::PushRegistrationStatus>::ToMojom(content::PushRegistrationStatus - input) { - if (input >= content::PushRegistrationStatus:: - PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE && - input <= content::PushRegistrationStatus::PUSH_REGISTRATION_STATUS_LAST) { - return static_cast<content::mojom::PushRegistrationStatus>(input); - } - - NOTREACHED(); - return content::mojom::PushRegistrationStatus::SERVICE_ERROR; -} - -// static -bool EnumTraits<content::mojom::PushRegistrationStatus, - content::PushRegistrationStatus>:: - FromMojom(content::mojom::PushRegistrationStatus input, - content::PushRegistrationStatus* output) { - if (input >= - content::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE && - input <= content::mojom::PushRegistrationStatus::LAST) { - *output = static_cast<content::PushRegistrationStatus>(input); - return true; - } - - NOTREACHED(); - return false; -} - -// static content::mojom::PushErrorType EnumTraits<content::mojom::PushErrorType, blink::WebPushError::ErrorType>:: ToMojom(blink::WebPushError::ErrorType input) { @@ -315,37 +110,6 @@ } // static -content::mojom::PushGetRegistrationStatus -EnumTraits<content::mojom::PushGetRegistrationStatus, - content::PushGetRegistrationStatus>:: - ToMojom(content::PushGetRegistrationStatus input) { - if (input >= content::PushGetRegistrationStatus:: - PUSH_GETREGISTRATION_STATUS_SUCCESS && - input <= content::PushGetRegistrationStatus:: - PUSH_GETREGISTRATION_STATUS_LAST) { - return static_cast<content::mojom::PushGetRegistrationStatus>(input); - } - - NOTREACHED(); - return content::mojom::PushGetRegistrationStatus::SERVICE_NOT_AVAILABLE; -} - -// static -bool EnumTraits<content::mojom::PushGetRegistrationStatus, - content::PushGetRegistrationStatus>:: - FromMojom(content::mojom::PushGetRegistrationStatus input, - content::PushGetRegistrationStatus* output) { - if (input >= content::mojom::PushGetRegistrationStatus::SUCCESS && - input <= content::mojom::PushGetRegistrationStatus::LAST) { - *output = static_cast<content::PushGetRegistrationStatus>(input); - return true; - } - - NOTREACHED(); - return false; -} - -// static content::mojom::PushPermissionStatus EnumTraits< content::mojom::PushPermissionStatus, blink::WebPushPermissionStatus>::ToMojom(blink::WebPushPermissionStatus
diff --git a/content/common/push_messaging_param_traits.h b/content/common/push_messaging_param_traits.h index 1fd16a64..4845efd2 100644 --- a/content/common/push_messaging_param_traits.h +++ b/content/common/push_messaging_param_traits.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include "content/common/push_messaging.mojom.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "mojo/public/cpp/bindings/struct_traits.h" namespace mojo { @@ -27,15 +28,6 @@ }; template <> -struct EnumTraits<content::mojom::PushRegistrationStatus, - content::PushRegistrationStatus> { - static content::mojom::PushRegistrationStatus ToMojom( - content::PushRegistrationStatus input); - static bool FromMojom(content::mojom::PushRegistrationStatus input, - content::PushRegistrationStatus* output); -}; - -template <> struct EnumTraits<content::mojom::PushErrorType, blink::WebPushError::ErrorType> { static content::mojom::PushErrorType ToMojom( @@ -45,15 +37,6 @@ }; template <> -struct EnumTraits<content::mojom::PushGetRegistrationStatus, - content::PushGetRegistrationStatus> { - static content::mojom::PushGetRegistrationStatus ToMojom( - content::PushGetRegistrationStatus input); - static bool FromMojom(content::mojom::PushGetRegistrationStatus input, - content::PushGetRegistrationStatus* output); -}; - -template <> struct EnumTraits<content::mojom::PushPermissionStatus, blink::WebPushPermissionStatus> { static content::mojom::PushPermissionStatus ToMojom(
diff --git a/content/common/sandbox_mac.mm b/content/common/sandbox_mac.mm index 0eb7e2f..9156287 100644 --- a/content/common/sandbox_mac.mm +++ b/content/common/sandbox_mac.mm
@@ -54,11 +54,14 @@ // Mapping from sandbox process types to resource IDs containing the sandbox // profile for all process types known to content. +// TODO(tsepez): Implement profile for SANDBOX_TYPE_NETWORK. SandboxTypeToResourceIDMapping kDefaultSandboxTypeToResourceIDMapping[] = { - { SANDBOX_TYPE_RENDERER, IDR_RENDERER_SANDBOX_PROFILE }, - { SANDBOX_TYPE_UTILITY, IDR_UTILITY_SANDBOX_PROFILE }, - { SANDBOX_TYPE_GPU, IDR_GPU_SANDBOX_PROFILE }, - { SANDBOX_TYPE_PPAPI, IDR_PPAPI_SANDBOX_PROFILE }, + {SANDBOX_TYPE_NO_SANDBOX, -1}, + {SANDBOX_TYPE_RENDERER, IDR_RENDERER_SANDBOX_PROFILE}, + {SANDBOX_TYPE_UTILITY, IDR_UTILITY_SANDBOX_PROFILE}, + {SANDBOX_TYPE_GPU, IDR_GPU_SANDBOX_PROFILE}, + {SANDBOX_TYPE_PPAPI, IDR_PPAPI_SANDBOX_PROFILE}, + {SANDBOX_TYPE_NETWORK, -1}, }; static_assert(arraysize(kDefaultSandboxTypeToResourceIDMapping) == \
diff --git a/content/common/sandbox_mac_unittest_helper.mm b/content/common/sandbox_mac_unittest_helper.mm index 9d8ddd45..a888465 100644 --- a/content/common/sandbox_mac_unittest_helper.mm +++ b/content/common/sandbox_mac_unittest_helper.mm
@@ -15,6 +15,7 @@ #include "base/logging.h" #include "base/process/kill.h" #include "content/common/sandbox_mac.h" +#include "content/public/common/sandbox_type.h" #include "content/test/test_content_client.h" #include "testing/multiprocess_func_list.h" @@ -56,15 +57,17 @@ for(int i = static_cast<int>(SANDBOX_TYPE_FIRST_TYPE); i < SANDBOX_TYPE_AFTER_LAST_TYPE; ++i) { - if (!RunTestInSandbox(static_cast<SandboxType>(i), - test_name, test_data)) { - LOG(ERROR) << "Sandboxed test (" << test_name << ")" << - "Failed in sandbox type " << i << - "user data: (" << test_data << ")"; + if (IsUnsandboxedSandboxType(static_cast<SandboxType>(i))) + continue; + + if (!RunTestInSandbox(static_cast<SandboxType>(i), test_name, test_data)) { + LOG(ERROR) << "Sandboxed test (" << test_name << ")" + << "Failed in sandbox type " << i << "user data: (" + << test_data << ")"; return false; } } - return true; + return true; } bool MacSandboxTest::RunTestInSandbox(SandboxType sandbox_type,
diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc index 3963c6e..323e57e 100644 --- a/content/common/sandbox_win.cc +++ b/content/common/sandbox_win.cc
@@ -12,6 +12,7 @@ #include "base/command_line.h" #include "base/debug/activity_tracker.h" #include "base/debug/profiler.h" +#include "base/feature_list.h" #include "base/files/file_util.h" #include "base/hash.h" #include "base/logging.h" @@ -627,9 +628,24 @@ return SetJobMemoryLimit(cmd_line, policy); } +// This is for finch. See also crbug.com/464430 for details. +const base::Feature kEnableCsrssLockdownFeature{ + "EnableCsrssLockdown", base::FEATURE_DISABLED_BY_DEFAULT}; + // TODO(jschuh): Need get these restrictions applied to NaCl and Pepper. // Just have to figure out what needs to be warmed up first. sandbox::ResultCode AddBaseHandleClosePolicy(sandbox::TargetPolicy* policy) { + if (base::win::GetVersion() >= base::win::VERSION_WIN10) { + if (base::FeatureList::IsEnabled(kEnableCsrssLockdownFeature)) { + // Close all ALPC ports. + sandbox::ResultCode ret = + policy->AddKernelObjectToClose(L"ALPC Port", NULL); + if (ret != sandbox::SBOX_ALL_OK) { + return ret; + } + } + } + // TODO(cpu): Add back the BaseNamedObjects policy. base::string16 object_path = PrependWindowsSessionPath( L"\\BaseNamedObjects\\windows_shell_global_counters");
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h index bbcfad41..8503ee85 100644 --- a/content/public/browser/browser_context.h +++ b/content/public/browser/browser_context.h
@@ -18,8 +18,6 @@ #include "base/memory/linked_ptr.h" #include "base/supports_user_data.h" #include "content/common/content_export.h" -#include "content/public/common/push_event_payload.h" -#include "content/public/common/push_messaging_status.h" #include "net/url_request/url_request_interceptor.h" #include "net/url_request/url_request_job_factory.h" #include "services/service_manager/embedder/embedded_service_info.h" @@ -53,6 +51,10 @@ namespace content { +namespace mojom { +enum class PushDeliveryStatus; +} + class BackgroundSyncController; class BlobHandle; class BrowserPluginGuestManager; @@ -61,6 +63,7 @@ class DownloadManager; class DownloadManagerDelegate; class PermissionManager; +struct PushEventPayload; class PushMessagingService; class ResourceContext; class ServiceManagerConnection; @@ -140,7 +143,7 @@ const GURL& origin, int64_t service_worker_registration_id, const PushEventPayload& payload, - const base::Callback<void(PushDeliveryStatus)>& callback); + const base::Callback<void(mojom::PushDeliveryStatus)>& callback); static void NotifyWillBeDestroyed(BrowserContext* browser_context);
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 122447d..689af0c 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -23,6 +23,7 @@ #include "content/public/common/content_client.h" #include "content/public/common/media_stream_request.h" #include "content/public/common/resource_type.h" +#include "content/public/common/sandbox_type.h" #include "content/public/common/socket_permission_request.h" #include "content/public/common/window_container_type.mojom.h" #include "media/media_features.h" @@ -684,22 +685,18 @@ // Manager. virtual void RegisterInProcessServices(StaticServiceMap* services) {} - using OutOfProcessServiceMap = std::map<std::string, base::string16>; + using OutOfProcessServiceMap = + std::map<std::string, std::pair<base::string16, SandboxType>>; - // Registers services to be loaded out of the browser process, in a sandboxed - // utility process. The value of each map entry should be the process name to - // use for the service's host process when launched. - virtual void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) {} - - // Registers services to be loaded out of the browser process (in a utility - // process) without the sandbox. + // Registers services to be loaded out of the browser process, in an + // utility process. The value of each map entry should be a { process name, + // sandbox type } pair to use for the service's host process when launched. // - // WARNING: This path is NOT recommended! If a service needs another service - // that is only available out of the sandbox, it could ask the browser - // process to provide it. Only use this method when that approach does not - // work. - virtual void RegisterUnsandboxedOutOfProcessServices( - OutOfProcessServiceMap* services) {} + // WARNING: SANDBOX_TYPE_NO_SANDBOX is NOT recommended as it creates an + // unsandboxed process! If a service needs another service that is only + // available out of the sandbox, it could ask the browser process to provide + // it. Only use this method when that approach does not work. + virtual void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) {} // Allow the embedder to provide a dictionary loaded from a JSON file // resembling a service manifest whose capabilities section will be merged
diff --git a/content/public/browser/push_messaging_service.h b/content/public/browser/push_messaging_service.h index 3ca8ec5e..70ea159 100644 --- a/content/public/browser/push_messaging_service.h +++ b/content/public/browser/push_messaging_service.h
@@ -11,12 +11,17 @@ #include "base/callback_forward.h" #include "content/common/content_export.h" -#include "content/public/common/push_messaging_status.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h" #include "url/gurl.h" namespace content { +namespace mojom { +enum class PushRegistrationStatus; +enum class PushUnregistrationReason; +enum class PushUnregistrationStatus; +} // namespace mojom + class BrowserContext; struct PushSubscriptionOptions; @@ -28,8 +33,9 @@ base::Callback<void(const std::string& registration_id, const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth, - PushRegistrationStatus status)>; - using UnregisterCallback = base::Callback<void(PushUnregistrationStatus)>; + mojom::PushRegistrationStatus status)>; + using UnregisterCallback = + base::Callback<void(mojom::PushUnregistrationStatus)>; using SubscriptionInfoCallback = base::Callback<void(bool is_valid, const std::vector<uint8_t>& p256dh, @@ -80,7 +86,7 @@ // Unsubscribe the given |sender_id| from the push messaging service. Locally // deactivates the subscription, then runs |callback|, then asynchronously // attempts to unsubscribe with the push service. - virtual void Unsubscribe(PushUnregistrationReason reason, + virtual void Unsubscribe(mojom::PushUnregistrationReason reason, const GURL& requesting_origin, int64_t service_worker_registration_id, const std::string& sender_id,
diff --git a/content/public/browser/speech_recognition_manager_delegate.h b/content/public/browser/speech_recognition_manager_delegate.h index f2ea12d4..c8223d1 100644 --- a/content/public/browser/speech_recognition_manager_delegate.h +++ b/content/public/browser/speech_recognition_manager_delegate.h
@@ -24,7 +24,7 @@ // This is called on the IO thread. virtual void CheckRecognitionIsAllowed( int session_id, - base::Callback<void(bool ask_user, bool is_allowed)> callback) = 0; + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback) = 0; // Checks whether the delegate is interested (returning a non nullptr ptr) or // not (returning nullptr) in receiving a copy of all sessions events.
diff --git a/content/public/browser/utility_process_host.h b/content/public/browser/utility_process_host.h index fc1b97d..29559cc 100644 --- a/content/public/browser/utility_process_host.h +++ b/content/public/browser/utility_process_host.h
@@ -11,6 +11,7 @@ #include "build/build_config.h" #include "content/common/content_export.h" #include "content/public/common/bind_interface_helpers.h" +#include "content/public/common/sandbox_type.h" #include "ipc/ipc_sender.h" #include "mojo/public/cpp/bindings/interface_ptr.h" #include "mojo/public/cpp/bindings/interface_request.h" @@ -56,8 +57,9 @@ // the operation. virtual void SetExposedDir(const base::FilePath& dir) = 0; - // Make the process run without a sandbox. - virtual void DisableSandbox() = 0; + // Make the process run with a specific sandbox type, or unsandboxed if + // SANDBOX_TYPE_NO_SANDBOX is specified. + virtual void SetSandboxType(SandboxType sandbox_type) = 0; #if defined(OS_WIN) // Make the process run elevated.
diff --git a/content/public/browser/utility_process_mojo_client.h b/content/public/browser/utility_process_mojo_client.h index 164c1dd3..f13eb762 100644 --- a/content/public/browser/utility_process_mojo_client.h +++ b/content/public/browser/utility_process_mojo_client.h
@@ -136,7 +136,7 @@ utility_host_->SetExposedDir(exposed_directory_); if (disable_sandbox_) - utility_host_->DisableSandbox(); + utility_host_->SetSandboxType(SANDBOX_TYPE_NO_SANDBOX); #if defined(OS_WIN) if (run_elevated_) { DCHECK(disable_sandbox_);
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn index 2ce68b81d..60fc4bd 100644 --- a/content/public/common/BUILD.gn +++ b/content/public/common/BUILD.gn
@@ -193,8 +193,6 @@ "previews_state.h", "process_type.h", "push_event_payload.h", - "push_messaging_status.cc", - "push_messaging_status.h", "push_subscription_options.h", "quarantine.h", "referrer.cc", @@ -355,6 +353,7 @@ "mutable_network_traffic_annotation_tag.mojom", "network_service.mojom", "network_service_test.mojom", + "push_messaging_status.mojom", "url_loader.mojom", "url_loader_factory.mojom", "window_container_type.mojom",
diff --git a/content/public/common/push_messaging_status.cc b/content/public/common/push_messaging_status.cc deleted file mode 100644 index 5f75d8b..0000000 --- a/content/public/common/push_messaging_status.cc +++ /dev/null
@@ -1,103 +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 "content/public/common/push_messaging_status.h" - -#include "base/logging.h" - -namespace content { - -const char* PushRegistrationStatusToString(PushRegistrationStatus status) { - switch (status) { - case PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE: - return "Registration successful - from push service"; - - case PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER: - return "Registration failed - no Service Worker"; - - case PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE: - return "Registration failed - push service not available"; - - case PUSH_REGISTRATION_STATUS_LIMIT_REACHED: - return "Registration failed - registration limit has been reached"; - - case PUSH_REGISTRATION_STATUS_PERMISSION_DENIED: - return "Registration failed - permission denied"; - - case PUSH_REGISTRATION_STATUS_SERVICE_ERROR: - return "Registration failed - push service error"; - - case PUSH_REGISTRATION_STATUS_NO_SENDER_ID: - return "Registration failed - missing applicationServerKey, and " - "gcm_sender_id not found in manifest"; - - case PUSH_REGISTRATION_STATUS_STORAGE_ERROR: - return "Registration failed - storage error"; - - case PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE: - return "Registration successful - from cache"; - - case PUSH_REGISTRATION_STATUS_NETWORK_ERROR: - return "Registration failed - could not connect to push server"; - - case PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED: - // We split this out for UMA, but it must be indistinguishable to JS. - return PushRegistrationStatusToString( - PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); - - case PUSH_REGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE: - return "Registration failed - could not retrieve the public key"; - - case PUSH_REGISTRATION_STATUS_MANIFEST_EMPTY_OR_MISSING: - return "Registration failed - missing applicationServerKey, and manifest " - "empty or missing"; - - case PUSH_REGISTRATION_STATUS_SENDER_ID_MISMATCH: - return "Registration failed - A subscription with a different " - "applicationServerKey (or gcm_sender_id) already exists; to " - "change the applicationServerKey, unsubscribe then resubscribe."; - - case PUSH_REGISTRATION_STATUS_STORAGE_CORRUPT: - return "Registration failed - storage corrupt"; - - case PUSH_REGISTRATION_STATUS_RENDERER_SHUTDOWN: - return "Registration failed - renderer shutdown"; - } - NOTREACHED(); - return ""; -} - -const char* PushUnregistrationStatusToString(PushUnregistrationStatus status) { - switch (status) { - case PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED: - return "Unregistration successful - from push service"; - - case PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED: - return "Unregistration successful - was not registered"; - - case PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR: - return "Unregistration pending - a network error occurred, but it will " - "be retried until it succeeds"; - - case PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER: - return "Unregistration failed - no Service Worker"; - - case PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE: - return "Unregistration failed - push service not available"; - - case PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR: - return "Unregistration pending - a push service error occurred, but it " - "will be retried until it succeeds"; - - case PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR: - return "Unregistration failed - storage error"; - - case PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR: - return "Unregistration failed - could not connect to push server"; - } - NOTREACHED(); - return ""; -} - -} // namespace content
diff --git a/content/public/common/push_messaging_status.h b/content/public/common/push_messaging_status.mojom similarity index 63% rename from content/public/common/push_messaging_status.h rename to content/public/common/push_messaging_status.mojom index 64d0418..ed5ef56 100644 --- a/content/public/common/push_messaging_status.h +++ b/content/public/common/push_messaging_status.mojom
@@ -1,11 +1,80 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. +// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_PUBLIC_COMMON_PUSH_MESSAGING_STATUS_H_ -#define CONTENT_PUBLIC_COMMON_PUSH_MESSAGING_STATUS_H_ +module content.mojom; -namespace content { +// Push message event success/error codes for internal use & reporting in UMA. +// Enum values can be added, but must never be renumbered or deleted and reused. +enum PushDeliveryStatus { + // The message was successfully delivered. + SUCCESS = 0, + + // The message could not be delivered because the app id was unknown. + UNKNOWN_APP_ID = 2, + + // The message could not be delivered because origin no longer has permission. + PERMISSION_DENIED = 3, + + // The message could not be delivered because no service worker was found. + NO_SERVICE_WORKER = 4, + + // The message could not be delivered because of a service worker error. + SERVICE_WORKER_ERROR = 5, + + // The message was delivered, but the Service Worker passed a Promise to + // event.waitUntil that got rejected. + EVENT_WAITUNTIL_REJECTED = 6, + + // The message was delivered, but the Service Worker timed out processing it. + TIMEOUT = 7, + + // NOTE: Do not renumber these as that would confuse interpretation of + // previously logged data. When making changes, also update the enum list + // in tools/metrics/histograms/histograms.xml to keep it in sync, and + // update LAST below. + + LAST = TIMEOUT +}; + +// Push getregistration success/error codes for internal use & reporting in UMA. +// Enum values can be added, but must never be renumbered or deleted and reused. +enum PushGetRegistrationStatus { + // Getting the registration was successful. + SUCCESS = 0, + + // Getting the registration failed because the push service is not available. + SERVICE_NOT_AVAILABLE = 1, + + // Getting the registration failed because we failed to read from storage. + STORAGE_ERROR = 2, + + // Getting the registration failed because there is no push registration. + REGISTRATION_NOT_FOUND = 3, + + // Getting the registration failed because the push service isn't available in + // incognito, but we tell JS registration not found to not reveal incognito. + INCOGNITO_REGISTRATION_NOT_FOUND = 4, + + // Getting the registration failed because public key could not be retrieved. + // PUBLIC_KEY_UNAVAILABLE = 5, + + // Getting the registration failed because storage was corrupt. + STORAGE_CORRUPT = 6, + + // Getting the registration failed because the renderer was shut down. + RENDERER_SHUTDOWN = 7, + + // Getting the registration failed because there was no live service worker. + NO_LIVE_SERVICE_WORKER = 8, + + // NOTE: Do not renumber these as that would confuse interpretation of + // previously logged data. When making changes, also update the enum list + // in tools/metrics/histograms/histograms.xml to keep it in sync, and + // update LAST below. + + LAST = NO_LIVE_SERVICE_WORKER +}; // Push registration success/error codes for internal use & reporting in UMA. // Enum values can be added, but must never be renumbered or deleted and reused. @@ -16,255 +85,173 @@ // possible that the push service had its own cache (for example if Chrome's // app data was cleared, we might have forgotten about a registration that the // push service still stores). - PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE = 0, + SUCCESS_FROM_PUSH_SERVICE = 0, // Registration failed because there is no Service Worker. - PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER = 1, + NO_SERVICE_WORKER = 1, // Registration failed because the push service is not available. - PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE = 2, + SERVICE_NOT_AVAILABLE = 2, // Registration failed because the maximum number of registratons has been // reached. - PUSH_REGISTRATION_STATUS_LIMIT_REACHED = 3, + LIMIT_REACHED = 3, // Registration failed because permission was denied. - PUSH_REGISTRATION_STATUS_PERMISSION_DENIED = 4, + PERMISSION_DENIED = 4, // Registration failed in the push service implemented by the embedder. - PUSH_REGISTRATION_STATUS_SERVICE_ERROR = 5, + SERVICE_ERROR = 5, // Registration failed because no sender id was provided by the page. - PUSH_REGISTRATION_STATUS_NO_SENDER_ID = 6, + NO_SENDER_ID = 6, // Registration succeeded, but we failed to persist it. - PUSH_REGISTRATION_STATUS_STORAGE_ERROR = 7, + STORAGE_ERROR = 7, // A successful registration was already cached in Service Worker storage. - PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE = 8, + SUCCESS_FROM_CACHE = 8, // Registration failed due to a network error. - PUSH_REGISTRATION_STATUS_NETWORK_ERROR = 9, + NETWORK_ERROR = 9, // Registration failed because the push service is not available in incognito, // but we tell JS that permission was denied to not reveal incognito. - PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED = 10, + INCOGNITO_PERMISSION_DENIED = 10, // Registration failed because the public key could not be retrieved. - PUSH_REGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE = 11, + PUBLIC_KEY_UNAVAILABLE = 11, // Registration failed because the manifest could not be retrieved or was // empty. - PUSH_REGISTRATION_STATUS_MANIFEST_EMPTY_OR_MISSING = 12, + MANIFEST_EMPTY_OR_MISSING = 12, // Registration failed because a subscription with a different sender id // already exists. - PUSH_REGISTRATION_STATUS_SENDER_ID_MISMATCH = 13, + SENDER_ID_MISMATCH = 13, // Registration failed because storage was corrupt. It will be retried // automatically after unsubscribing to fix the corruption. - PUSH_REGISTRATION_STATUS_STORAGE_CORRUPT = 14, + STORAGE_CORRUPT = 14, // Registration failed because the renderer was shut down. - PUSH_REGISTRATION_STATUS_RENDERER_SHUTDOWN = 15, + RENDERER_SHUTDOWN = 15, // NOTE: Do not renumber these as that would confuse interpretation of // previously logged data. When making changes, also update the enum list // in tools/metrics/histograms/histograms.xml to keep it in sync, and - // update PUSH_REGISTRATION_STATUS_LAST below. + // update LAST below. - PUSH_REGISTRATION_STATUS_LAST = PUSH_REGISTRATION_STATUS_RENDERER_SHUTDOWN + LAST = RENDERER_SHUTDOWN }; // Push unregistration reason for reporting in UMA. Enum values can be added, // but must never be renumbered or deleted and reused. enum PushUnregistrationReason { // Should never happen. - PUSH_UNREGISTRATION_REASON_UNKNOWN = 0, + UNKNOWN = 0, // Unregistering because the website called the unsubscribe API. - PUSH_UNREGISTRATION_REASON_JAVASCRIPT_API = 1, + JAVASCRIPT_API = 1, // Unregistering because the user manually revoked permission. - PUSH_UNREGISTRATION_REASON_PERMISSION_REVOKED = 2, + PERMISSION_REVOKED = 2, // Automatic - incoming message's app id was unknown. - PUSH_UNREGISTRATION_REASON_DELIVERY_UNKNOWN_APP_ID = 3, + DELIVERY_UNKNOWN_APP_ID = 3, // Automatic - incoming message's origin no longer has permission. - PUSH_UNREGISTRATION_REASON_DELIVERY_PERMISSION_DENIED = 4, + DELIVERY_PERMISSION_DENIED = 4, // Automatic - incoming message's service worker was not found. - PUSH_UNREGISTRATION_REASON_DELIVERY_NO_SERVICE_WORKER = 5, + DELIVERY_NO_SERVICE_WORKER = 5, // Automatic - GCM Store reset due to corruption. - PUSH_UNREGISTRATION_REASON_GCM_STORE_RESET = 6, + GCM_STORE_RESET = 6, // Unregistering because the service worker was unregistered. - PUSH_UNREGISTRATION_REASON_SERVICE_WORKER_UNREGISTERED = 7, + SERVICE_WORKER_UNREGISTERED = 7, // Website called subscribe API and the stored subscription was corrupt, so // it is being unsubscribed in order to attempt a clean subscription. - PUSH_UNREGISTRATION_REASON_SUBSCRIBE_STORAGE_CORRUPT = 8, + SUBSCRIBE_STORAGE_CORRUPT = 8, // Website called getSubscription API and the stored subscription was corrupt. - PUSH_UNREGISTRATION_REASON_GET_SUBSCRIPTION_STORAGE_CORRUPT = 9, + GET_SUBSCRIPTION_STORAGE_CORRUPT = 9, // The Service Worker database got wiped, most likely due to corruption. - PUSH_UNREGISTRATION_REASON_SERVICE_WORKER_DATABASE_WIPED = 10, + SERVICE_WORKER_DATABASE_WIPED = 10, // NOTE: Do not renumber these as that would confuse interpretation of // previously logged data. When making changes, also update the enum list // in tools/metrics/histograms/histograms.xml to keep it in sync, and - // update PUSH_UNREGISTRATION_REASON_LAST below. + // update LAST below. - PUSH_UNREGISTRATION_REASON_LAST = - PUSH_UNREGISTRATION_REASON_SERVICE_WORKER_DATABASE_WIPED + LAST = SERVICE_WORKER_DATABASE_WIPED }; + // Push unregistration success/error codes for internal use & reporting in UMA. // Enum values can be added, but must never be renumbered or deleted and reused. enum PushUnregistrationStatus { // The unregistration was successful. - PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED = 0, + SUCCESS_UNREGISTERED = 0, // Unregistration was unnecessary, as the registration was not found. - PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED = 1, + SUCCESS_WAS_NOT_REGISTERED = 1, // The unregistration did not happen because of a network error, but will be // retried until it succeeds. - PUSH_UNREGISTRATION_STATUS_PENDING_NETWORK_ERROR = 2, + PENDING_NETWORK_ERROR = 2, // Unregistration failed because there is no Service Worker. - PUSH_UNREGISTRATION_STATUS_NO_SERVICE_WORKER = 3, + NO_SERVICE_WORKER = 3, // Unregistration failed because the push service is not available. - PUSH_UNREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE = 4, + SERVICE_NOT_AVAILABLE = 4, // Unregistration failed in the push service implemented by the embedder, but // will be retried until it succeeds. - PUSH_UNREGISTRATION_STATUS_PENDING_SERVICE_ERROR = 5, + PENDING_SERVICE_ERROR = 5, // Unregistration succeeded, but we failed to clear Service Worker storage. - PUSH_UNREGISTRATION_STATUS_STORAGE_ERROR = 6, + STORAGE_ERROR = 6, // Unregistration failed due to a network error. - PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR = 7, + NETWORK_ERROR = 7, // NOTE: Do not renumber these as that would confuse interpretation of // previously logged data. When making changes, also update the enum list // in tools/metrics/histograms/histograms.xml to keep it in sync, and - // update PUSH_UNREGISTRATION_STATUS_LAST below. + // update LAST below. - PUSH_UNREGISTRATION_STATUS_LAST = PUSH_UNREGISTRATION_STATUS_NETWORK_ERROR -}; - -// Push getregistration success/error codes for internal use & reporting in UMA. -// Enum values can be added, but must never be renumbered or deleted and reused. -enum PushGetRegistrationStatus { - // Getting the registration was successful. - PUSH_GETREGISTRATION_STATUS_SUCCESS = 0, - - // Getting the registration failed because the push service is not available. - PUSH_GETREGISTRATION_STATUS_SERVICE_NOT_AVAILABLE = 1, - - // Getting the registration failed because we failed to read from storage. - PUSH_GETREGISTRATION_STATUS_STORAGE_ERROR = 2, - - // Getting the registration failed because there is no push registration. - PUSH_GETREGISTRATION_STATUS_REGISTRATION_NOT_FOUND = 3, - - // Getting the registration failed because the push service isn't available in - // incognito, but we tell JS registration not found to not reveal incognito. - PUSH_GETREGISTRATION_STATUS_INCOGNITO_REGISTRATION_NOT_FOUND = 4, - - // Getting the registration failed because public key could not be retrieved. - // PUSH_GETREGISTRATION_STATUS_PUBLIC_KEY_UNAVAILABLE = 5, - - // Getting the registration failed because storage was corrupt. - PUSH_GETREGISTRATION_STATUS_STORAGE_CORRUPT = 6, - - // Getting the registration failed because the renderer was shut down. - PUSH_GETREGISTRATION_STATUS_RENDERER_SHUTDOWN = 7, - - // Getting the registration failed because there was no live service worker. - PUSH_GETREGISTRATION_STATUS_NO_LIVE_SERVICE_WORKER = 8, - - // NOTE: Do not renumber these as that would confuse interpretation of - // previously logged data. When making changes, also update the enum list - // in tools/metrics/histograms/histograms.xml to keep it in sync, and - // update PUSH_GETREGISTRATION_STATUS_LAST below. - - PUSH_GETREGISTRATION_STATUS_LAST = - PUSH_GETREGISTRATION_STATUS_NO_LIVE_SERVICE_WORKER -}; - -// Push message event success/error codes for internal use & reporting in UMA. -// Enum values can be added, but must never be renumbered or deleted and reused. -enum PushDeliveryStatus { - // The message was successfully delivered. - PUSH_DELIVERY_STATUS_SUCCESS = 0, - - // The message could not be delivered because the app id was unknown. - PUSH_DELIVERY_STATUS_UNKNOWN_APP_ID = 2, - - // The message could not be delivered because origin no longer has permission. - PUSH_DELIVERY_STATUS_PERMISSION_DENIED = 3, - - // The message could not be delivered because no service worker was found. - PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER = 4, - - // The message could not be delivered because of a service worker error. - PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR = 5, - - // The message was delivered, but the Service Worker passed a Promise to - // event.waitUntil that got rejected. - PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED = 6, - - // The message was delivered, but the Service Worker timed out processing it. - PUSH_DELIVERY_STATUS_TIMEOUT = 7, - - // NOTE: Do not renumber these as that would confuse interpretation of - // previously logged data. When making changes, also update the enum list - // in tools/metrics/histograms/histograms.xml to keep it in sync, and - // update PUSH_DELIVERY_STATUS_LAST below. - - PUSH_DELIVERY_STATUS_LAST = PUSH_DELIVERY_STATUS_TIMEOUT + LAST = NETWORK_ERROR }; // Push message user visible tracking for reporting in UMA. Enum values can be // added, but must never be renumbered or deleted and reused. enum PushUserVisibleStatus { // A notification was required and one (or more) were shown. - PUSH_USER_VISIBLE_STATUS_REQUIRED_AND_SHOWN = 0, + REQUIRED_AND_SHOWN = 0, // A notification was not required, but one (or more) were shown anyway. - PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_BUT_SHOWN = 1, + NOT_REQUIRED_BUT_SHOWN = 1, // A notification was not required and none were shown. - PUSH_USER_VISIBLE_STATUS_NOT_REQUIRED_AND_NOT_SHOWN = 2, + NOT_REQUIRED_AND_NOT_SHOWN = 2, // A notification was required, but none were shown. Fortunately, the site has // been well behaved recently so it was glossed over. - PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_USED_GRACE = 3, + REQUIRED_BUT_NOT_SHOWN_USED_GRACE = 3, // A notification was required, but none were shown. Unfortunately, the site // has run out of grace, so we had to show the user a generic notification. - PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED = 4, + REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED = 4, // NOTE: Do not renumber these as that would confuse interpretation of // previously logged data. When making changes, also update the enum list // in tools/metrics/histograms/histograms.xml to keep it in sync, and - // update PUSH_USER_VISIBLE_STATUS_LAST below. + // update LAST below. - PUSH_USER_VISIBLE_STATUS_LAST = - PUSH_USER_VISIBLE_STATUS_REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED + LAST = REQUIRED_BUT_NOT_SHOWN_GRACE_EXCEEDED }; - -const char* PushRegistrationStatusToString(PushRegistrationStatus status); - -const char* PushUnregistrationStatusToString(PushUnregistrationStatus status); - -} // namespace content - -#endif // CONTENT_PUBLIC_COMMON_PUSH_MESSAGING_STATUS_H_
diff --git a/content/public/common/sandbox_type.h b/content/public/common/sandbox_type.h index ef610fbe..f4cf91df 100644 --- a/content/public/common/sandbox_type.h +++ b/content/public/common/sandbox_type.h
@@ -16,7 +16,11 @@ SANDBOX_TYPE_FIRST_TYPE = 0, // Placeholder to ease iteration. - SANDBOX_TYPE_RENDERER = SANDBOX_TYPE_FIRST_TYPE, + // Do not apply any sandboxing to the process. + SANDBOX_TYPE_NO_SANDBOX = SANDBOX_TYPE_FIRST_TYPE, + + // Renderer or worker process. Most common case. + SANDBOX_TYPE_RENDERER, // Utility process is as restrictive as the worker process except full // access is allowed to one configurable directory. @@ -28,9 +32,18 @@ // The PPAPI plugin process. SANDBOX_TYPE_PPAPI, + // The network process. + SANDBOX_TYPE_NETWORK, + SANDBOX_TYPE_AFTER_LAST_TYPE, // Placeholder to ease iteration. }; +inline bool IsUnsandboxedSandboxType(SandboxType sandbox_type) { + // TODO(tsepez): Sandbox network process. + return sandbox_type == SANDBOX_TYPE_NO_SANDBOX || + sandbox_type == SANDBOX_TYPE_NETWORK; +} + } // namespace content #endif // CONTENT_PUBLIC_COMMON_SANDBOX_TYPE_H_
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc index 68d5e488..4311aff33 100644 --- a/content/public/common/web_preferences.cc +++ b/content/public/common/web_preferences.cc
@@ -179,6 +179,7 @@ animation_policy(IMAGE_ANIMATION_POLICY_ALLOWED), user_gesture_required_for_presentation(true), text_track_margin_percentage(0.0f), + page_popups_suppressed(false), #if defined(OS_ANDROID) text_autosizing_enabled(true), font_scale_factor(1.0f), @@ -205,7 +206,6 @@ video_rotate_to_fullscreen_enabled(false), video_fullscreen_detection_enabled(false), embedded_media_experience_enabled(false), - page_popups_suppressed(false), #endif // defined(OS_ANDROID) #if defined(OS_ANDROID) default_minimum_page_scale_factor(0.25f),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h index 0a275a92..643c288 100644 --- a/content/public/common/web_preferences.h +++ b/content/public/common/web_preferences.h
@@ -215,6 +215,8 @@ // Cues will not be placed in this margin area. float text_track_margin_percentage; + bool page_popups_suppressed; + #if defined(OS_ANDROID) bool text_autosizing_enabled; float font_scale_factor; @@ -251,7 +253,6 @@ // If enabled, video fullscreen detection will be enabled. bool video_fullscreen_detection_enabled; bool embedded_media_experience_enabled; - bool page_popups_suppressed; #else // defined(OS_ANDROID) #endif // defined(OS_ANDROID)
diff --git a/content/public/test/repeated_notification_observer.cc b/content/public/test/repeated_notification_observer.cc deleted file mode 100644 index 097ec901..0000000 --- a/content/public/test/repeated_notification_observer.cc +++ /dev/null
@@ -1,39 +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 "content/public/test/repeated_notification_observer.h" - -#include "base/auto_reset.h" -#include "base/macros.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_service.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace content { - -RepeatedNotificationObserver::RepeatedNotificationObserver(int type, int count) - : num_outstanding_(count), running_(false) { - registrar_.Add(this, type, NotificationService::AllSources()); -} - -void RepeatedNotificationObserver::Observe(int type, - const NotificationSource& source, - const NotificationDetails& details) { - ASSERT_GT(num_outstanding_, 0); - if (!--num_outstanding_ && running_) - run_loop_.QuitWhenIdle(); -} - -void RepeatedNotificationObserver::Wait() { - if (num_outstanding_ <= 0) - return; - - { - DCHECK(!running_); - base::AutoReset<bool> auto_reset(&running_, true); - run_loop_.Run(); - } -} - -} // namespace content
diff --git a/content/public/test/repeated_notification_observer.h b/content/public/test/repeated_notification_observer.h deleted file mode 100644 index 5e96dfaf8..0000000 --- a/content/public/test/repeated_notification_observer.h +++ /dev/null
@@ -1,39 +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 CONTENT_PUBLIC_TEST_REPEATED_NOTIFICATION_OBSERVER_H_ -#define CONTENT_PUBLIC_TEST_REPEATED_NOTIFICATION_OBSERVER_H_ - -#include "base/run_loop.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" - -namespace content { - -// RepeatedNotificationObserver allows code to wait until specified number -// of notifications of particular type are posted. -class RepeatedNotificationObserver : public NotificationObserver { - public: - RepeatedNotificationObserver(int type, int count); - - // NotificationObserver: - void Observe(int type, - const NotificationSource& source, - const NotificationDetails& details) override; - - // Wait until |count| events of |type| (both specified in constructor) happen. - void Wait(); - - private: - int num_outstanding_; - NotificationRegistrar registrar_; - bool running_; - base::RunLoop run_loop_; - - DISALLOW_COPY_AND_ASSIGN(RepeatedNotificationObserver); -}; - -} // namespace content - -#endif // CONTENT_PUBLIC_TEST_REPEATED_NOTIFICATION_OBSERVER_H_
diff --git a/content/renderer/media/mojo_audio_output_ipc.cc b/content/renderer/media/mojo_audio_output_ipc.cc index 7c5a7da5..203bd7c 100644 --- a/content/renderer/media/mojo_audio_output_ipc.cc +++ b/content/renderer/media/mojo_audio_output_ipc.cc
@@ -7,6 +7,7 @@ #include <utility> #include "media/audio/audio_device_description.h" +#include "media/base/scoped_callback_runner.h" #include "mojo/public/cpp/system/platform_handle.h" namespace content { @@ -44,22 +45,17 @@ DCHECK(!StreamCreationRequested()); delegate_ = delegate; - // We pass in a ScopedClosureRunner to detect the case when the mojo - // connection is terminated prior to receiving the response. In this case, - // the closure runner will be destructed and call ReceivedDeviceAuthorization - // with an error. + // We wrap the callback in a ScopedCallbackRunner to detect the case when the + // mojo connection is terminated prior to receiving the response. In this + // case, the callback runner will be destructed and call + // ReceivedDeviceAuthorization with an error. DoRequestDeviceAuthorization( session_id, device_id, - base::BindOnce( - &MojoAudioOutputIPC::ReceivedDeviceAuthorization, - weak_factory_.GetWeakPtr(), - base::ScopedClosureRunner(base::Bind( - &MojoAudioOutputIPC::ReceivedDeviceAuthorization, - weak_factory_.GetWeakPtr(), - base::Passed(base::ScopedClosureRunner()), - media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, - media::AudioParameters::UnavailableDeviceParams(), - std::string())))); + media::ScopedCallbackRunner( + base::BindOnce(&MojoAudioOutputIPC::ReceivedDeviceAuthorization, + weak_factory_.GetWeakPtr()), + media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, + media::AudioParameters::UnavailableDeviceParams(), std::string())); } void MojoAudioOutputIPC::CreateStream(media::AudioOutputIPCDelegate* delegate, @@ -167,13 +163,11 @@ } void MojoAudioOutputIPC::ReceivedDeviceAuthorization( - base::ScopedClosureRunner fallback_closure, media::OutputDeviceStatus status, const media::AudioParameters& params, const std::string& device_id) const { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(delegate_); - ignore_result(fallback_closure.Release()); delegate_->OnDeviceAuthorized(status, params, device_id); }
diff --git a/content/renderer/media/mojo_audio_output_ipc.h b/content/renderer/media/mojo_audio_output_ipc.h index b014e50..a8182651 100644 --- a/content/renderer/media/mojo_audio_output_ipc.h +++ b/content/renderer/media/mojo_audio_output_ipc.h
@@ -58,8 +58,7 @@ const std::string& device_id, AuthorizationCB callback); - void ReceivedDeviceAuthorization(base::ScopedClosureRunner fallback_closure, - media::OutputDeviceStatus status, + void ReceivedDeviceAuthorization(media::OutputDeviceStatus status, const media::AudioParameters& params, const std::string& device_id) const;
diff --git a/content/renderer/push_messaging/push_messaging_client.cc b/content/renderer/push_messaging/push_messaging_client.cc index 51785ca..0b51e3f 100644 --- a/content/renderer/push_messaging/push_messaging_client.cc +++ b/content/renderer/push_messaging/push_messaging_client.cc
@@ -13,6 +13,8 @@ #include "content/child/child_thread_impl.h" #include "content/child/push_messaging/push_provider.h" #include "content/child/service_worker/web_service_worker_registration_impl.h" +#include "content/common/push_messaging.mojom.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "content/public/common/service_names.mojom.h" #include "content/renderer/manifest/manifest_manager.h" #include "content/renderer/render_frame_impl.h" @@ -83,7 +85,7 @@ // the caller. if (manifest.IsEmpty()) { DidSubscribe(std::move(callbacks), - PUSH_REGISTRATION_STATUS_MANIFEST_EMPTY_OR_MISSING, + mojom::PushRegistrationStatus::MANIFEST_EMPTY_OR_MISSING, base::nullopt, base::nullopt, base::nullopt, base::nullopt); return; } @@ -110,8 +112,9 @@ ->RegistrationId(); if (options.sender_info.empty()) { - DidSubscribe(std::move(callbacks), PUSH_REGISTRATION_STATUS_NO_SENDER_ID, - base::nullopt, base::nullopt, base::nullopt, base::nullopt); + DidSubscribe(std::move(callbacks), + mojom::PushRegistrationStatus::NO_SENDER_ID, base::nullopt, + base::nullopt, base::nullopt, base::nullopt); return; } @@ -126,15 +129,15 @@ void PushMessagingClient::DidSubscribe( std::unique_ptr<blink::WebPushSubscriptionCallbacks> callbacks, - content::PushRegistrationStatus status, + mojom::PushRegistrationStatus status, const base::Optional<GURL>& endpoint, - const base::Optional<content::PushSubscriptionOptions>& options, + const base::Optional<PushSubscriptionOptions>& options, const base::Optional<std::vector<uint8_t>>& p256dh, const base::Optional<std::vector<uint8_t>>& auth) { DCHECK(callbacks); - if (status == PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE || - status == PUSH_REGISTRATION_STATUS_SUCCESS_FROM_CACHE) { + if (status == mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE || + status == mojom::PushRegistrationStatus::SUCCESS_FROM_CACHE) { DCHECK(endpoint); DCHECK(options); DCHECK(p256dh);
diff --git a/content/renderer/push_messaging/push_messaging_client.h b/content/renderer/push_messaging/push_messaging_client.h index 695479e0..d243ec2 100644 --- a/content/renderer/push_messaging/push_messaging_client.h +++ b/content/renderer/push_messaging/push_messaging_client.h
@@ -13,7 +13,6 @@ #include "base/macros.h" #include "content/common/push_messaging.mojom.h" -#include "content/public/common/push_messaging_status.h" #include "content/public/renderer/render_frame_observer.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushClient.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h" @@ -26,6 +25,10 @@ namespace content { +namespace mojom { +enum class PushRegistrationStatus; +} + struct Manifest; struct ManifestDebugInfo; struct PushSubscriptionOptions; @@ -64,9 +67,9 @@ void DidSubscribe( std::unique_ptr<blink::WebPushSubscriptionCallbacks> callbacks, - content::PushRegistrationStatus status, + mojom::PushRegistrationStatus status, const base::Optional<GURL>& endpoint, - const base::Optional<content::PushSubscriptionOptions>& options, + const base::Optional<PushSubscriptionOptions>& options, const base::Optional<std::vector<uint8_t>>& p256dh, const base::Optional<std::vector<uint8_t>>& auth);
diff --git a/content/shell/browser/layout_test/layout_test_push_messaging_service.cc b/content/shell/browser/layout_test/layout_test_push_messaging_service.cc index ec9e296..bea0626 100644 --- a/content/shell/browser/layout_test/layout_test_push_messaging_service.cc +++ b/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
@@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/macros.h" #include "content/public/browser/permission_type.h" +#include "content/public/common/push_messaging_status.mojom.h" #include "content/public/common/push_subscription_options.h" #include "content/shell/browser/layout_test/layout_test_browser_context.h" #include "content/shell/browser/layout_test/layout_test_content_browser_client.h" @@ -95,11 +96,11 @@ subscribed_service_worker_registration_ = service_worker_registration_id; callback.Run("layoutTestRegistrationId", p256dh, auth, - PUSH_REGISTRATION_STATUS_SUCCESS_FROM_PUSH_SERVICE); + mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE); } else { callback.Run("registration_id", std::vector<uint8_t>() /* p256dh */, std::vector<uint8_t>() /* auth */, - PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); + mojom::PushRegistrationStatus::PERMISSION_DENIED); } } @@ -131,7 +132,7 @@ } void LayoutTestPushMessagingService::Unsubscribe( - PushUnregistrationReason reason, + mojom::PushUnregistrationReason reason, const GURL& requesting_origin, int64_t service_worker_registration_id, const std::string& sender_id, @@ -139,11 +140,12 @@ ClearPushSubscriptionId( LayoutTestContentBrowserClient::Get()->browser_context(), requesting_origin, service_worker_registration_id, - base::Bind(callback, - service_worker_registration_id == - subscribed_service_worker_registration_ - ? PUSH_UNREGISTRATION_STATUS_SUCCESS_UNREGISTERED - : PUSH_UNREGISTRATION_STATUS_SUCCESS_WAS_NOT_REGISTERED)); + base::Bind( + callback, + service_worker_registration_id == + subscribed_service_worker_registration_ + ? mojom::PushUnregistrationStatus::SUCCESS_UNREGISTERED + : mojom::PushUnregistrationStatus::SUCCESS_WAS_NOT_REGISTERED)); if (service_worker_registration_id == subscribed_service_worker_registration_) { subscribed_service_worker_registration_ =
diff --git a/content/shell/browser/layout_test/layout_test_push_messaging_service.h b/content/shell/browser/layout_test/layout_test_push_messaging_service.h index 547cb418..5b61b17d 100644 --- a/content/shell/browser/layout_test/layout_test_push_messaging_service.h +++ b/content/shell/browser/layout_test/layout_test_push_messaging_service.h
@@ -12,7 +12,6 @@ #include "base/macros.h" #include "content/public/browser/push_messaging_service.h" -#include "content/public/common/push_messaging_status.h" #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h" namespace content { @@ -46,7 +45,7 @@ bool user_visible) override; bool SupportNonVisibleMessages() override; - void Unsubscribe(PushUnregistrationReason reason, + void Unsubscribe(mojom::PushUnregistrationReason reason, const GURL& requesting_origin, int64_t service_worker_registration_id, const std::string& sender_id,
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index f03cde3a..ed2e264 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc
@@ -246,8 +246,8 @@ void ShellContentBrowserClient::RegisterOutOfProcessServices( OutOfProcessServiceMap* services) { - services->insert(std::make_pair(kTestServiceUrl, - base::UTF8ToUTF16("Test Service"))); + (*services)[kTestServiceUrl] = {base::UTF8ToUTF16("Test Service"), + SANDBOX_TYPE_UTILITY}; } std::unique_ptr<base::Value>
diff --git a/content/shell/browser/shell_speech_recognition_manager_delegate.cc b/content/shell/browser/shell_speech_recognition_manager_delegate.cc index 0b0778d0..2d51634 100644 --- a/content/shell/browser/shell_speech_recognition_manager_delegate.cc +++ b/content/shell/browser/shell_speech_recognition_manager_delegate.cc
@@ -6,18 +6,19 @@ #include "content/public/browser/browser_thread.h" -using base::Callback; +using base::OnceCallback; namespace content { void ShellSpeechRecognitionManagerDelegate::CheckRecognitionIsAllowed( - int session_id, Callback<void(bool ask_user, bool is_allowed)> callback) { + int session_id, + OnceCallback<void(bool ask_user, bool is_allowed)> callback) { // In content_shell, we expect speech recognition to happen when requested. // Therefore we simply authorize it by calling back with is_allowed=true. The // first parameter, ask_user, is set to false because we don't want to prompt // the user for permission with an infobar. - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, base::Bind(callback, false, true)); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::BindOnce(std::move(callback), false, true)); } SpeechRecognitionEventListener*
diff --git a/content/shell/browser/shell_speech_recognition_manager_delegate.h b/content/shell/browser/shell_speech_recognition_manager_delegate.h index c1f6b9d9f..808a109 100644 --- a/content/shell/browser/shell_speech_recognition_manager_delegate.h +++ b/content/shell/browser/shell_speech_recognition_manager_delegate.h
@@ -25,7 +25,8 @@ // SpeechRecognitionManagerDelegate methods. void CheckRecognitionIsAllowed( int session_id, - base::Callback<void(bool ask_user, bool is_allowed)> callback) override; + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback) + override; SpeechRecognitionEventListener* GetEventListener() override; bool FilterProfanities(int render_process_id) override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index f55394f..0e70354 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -98,8 +98,6 @@ "../public/test/ppapi_test_utils.h", "../public/test/render_view_test.cc", "../public/test/render_view_test.h", - "../public/test/repeated_notification_observer.cc", - "../public/test/repeated_notification_observer.h", "../public/test/service_worker_test_helpers.cc", "../public/test/service_worker_test_helpers.h", "../public/test/test_browser_context.cc",
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index a6a0947..b450504 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -201,8 +201,6 @@ self.Skip('conformance2/textures/misc/' + 'copy-texture-image-webgl-specific.html', ['win', 'passthrough', 'd3d11'], bug=602688) - self.Skip('conformance2/reading/read-pixels-pack-parameters.html', - ['win', 'passthrough', 'd3d11'], bug=602688) self.Skip('conformance2/reading/read-pixels-into-pixel-pack-buffer.html', ['win', 'passthrough', 'd3d11'], bug=602688)
diff --git a/docs/ios/build_instructions.md b/docs/ios/build_instructions.md index 3a70ff0..f24adbf 100644 --- a/docs/ios/build_instructions.md +++ b/docs/ios/build_instructions.md
@@ -234,6 +234,18 @@ $ out/Debug-iphonesimulator/iossim out/Debug-iphonesimulator/Chromium.app ``` +### Running EarlGrey tests + +EarlGrey tests are run differently than other test targets, as there is an +XCTest bundle that is injected into the target application. Therefore you must +also pass in the test bundle: + +```shell +$ out/Debug-iphonesimulator/iossim \ + out/Debug-iphonesimulator/ios_chrome_ui_egtests.app \ + out/Debug-iphonesimulator/ios_chrome_ui_egtests.app/PlugIns/ios_chrome_ui_egtests_module.xctest +``` + ## Update your checkout To update an existing checkout, you can run
diff --git a/extensions/common/api/virtual_keyboard_private.json b/extensions/common/api/virtual_keyboard_private.json index ec7fdeb..90de6d4e 100644 --- a/extensions/common/api/virtual_keyboard_private.json +++ b/extensions/common/api/virtual_keyboard_private.json
@@ -41,12 +41,6 @@ "description": "The value of the virtual keyboard state to change to." }, { - "id": "OnTextInputBoxFocusedType", - "type": "string", - "description": "The value of type attribute of the focused text input box.", - "enum": ["text", "number", "password", "date", "url", "tel", "email"] - }, - { "id": "Bounds", "type": "object", "properties": { @@ -214,24 +208,6 @@ ], "events": [ { - "name": "onTextInputBoxFocused", - "type": "function", - "description": "This event is sent when focus enters a text input box.", - "parameters": [ - { - "type": "object", - "name": "context", - "description": "Describes the text input box that has acquired focus. Note only the type of text input box is passed. This API is intended to be used by non-ime virtual keyboard only. Normal ime virtual keyboard should use chrome.input.ime.onFocus to get the more detailed InputContext.", - "properties": { - "type": { - "$ref": "OnTextInputBoxFocusedType", - "description": "The value of type attribute of the focused text input box." - } - } - } - ] - }, - { "name": "onBoundsChanged", "type": "function", "description": "This event is sent when virtual keyboard bounds changed and overscroll/resize is enabled.",
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn index f3ea9b38..31f727b 100644 --- a/extensions/renderer/BUILD.gn +++ b/extensions/renderer/BUILD.gn
@@ -309,6 +309,7 @@ sources = [ "activity_log_converter_strategy_unittest.cc", "api/mojo_private/mojo_private_unittest.cc", + "api_activity_logger_unittest.cc", "api_test_base.cc", "api_test_base.h", "api_test_base_unittest.cc", @@ -362,6 +363,7 @@ "//base/test:test_support", "//components/crx_file:crx_file", "//content/public/child", + "//content/test:test_support", "//extensions:extensions_renderer_resources", "//extensions:test_support", "//gin:gin_test", @@ -370,6 +372,7 @@ "//extensions/browser", "//extensions/common", "//gin", + "//ipc:test_support", "//mojo/edk/js", "//testing/gmock", "//testing/gtest",
diff --git a/extensions/renderer/api_activity_logger.cc b/extensions/renderer/api_activity_logger.cc index 71cd1e4a..64f35d96 100644 --- a/extensions/renderer/api_activity_logger.cc +++ b/extensions/renderer/api_activity_logger.cc
@@ -19,6 +19,10 @@ namespace extensions { +namespace { +bool g_log_for_testing = false; +} + APIActivityLogger::APIActivityLogger(ScriptContext* context, Dispatcher* dispatcher) : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) { @@ -37,8 +41,9 @@ const std::vector<v8::Local<v8::Value>>& arguments) { const Dispatcher* dispatcher = ExtensionsRendererClient::Get()->GetDispatcher(); - if (!dispatcher || // dispatcher can be null in unittests. - !dispatcher->activity_logging_enabled()) { + if ((!dispatcher || // dispatcher can be null in unittests. + !dispatcher->activity_logging_enabled()) && + !g_log_for_testing) { return; } @@ -53,13 +58,21 @@ value_args->Reserve(arguments.size()); // TODO(devlin): This doesn't protect against custom properties, so it might // not perfectly reflect the passed arguments. - for (const auto& arg : arguments) - value_args->Append(converter->FromV8Value(arg, context)); + for (const auto& arg : arguments) { + std::unique_ptr<base::Value> converted_arg = + converter->FromV8Value(arg, context); + value_args->Append(converted_arg ? std::move(converted_arg) + : base::MakeUnique<base::Value>()); + } LogInternal(APICALL, script_context->GetExtensionID(), call_name, std::move(value_args), std::string()); } +void APIActivityLogger::set_log_for_testing(bool log) { + g_log_for_testing = log; +} + void APIActivityLogger::LogForJS( const CallType call_type, const v8::FunctionCallbackInfo<v8::Value>& args) { @@ -93,8 +106,12 @@ ActivityLogConverterStrategy strategy; converter->SetFunctionAllowed(true); converter->SetStrategy(&strategy); - for (size_t i = 0; i < arg_array->Length(); ++i) - arguments->Append(converter->FromV8Value(arg_array->Get(i), context)); + for (size_t i = 0; i < arg_array->Length(); ++i) { + std::unique_ptr<base::Value> converted_arg = + converter->FromV8Value(arg_array->Get(i), context); + arguments->Append(converted_arg ? std::move(converted_arg) + : base::MakeUnique<base::Value>()); + } } LogInternal(call_type, extension_id, call_name, std::move(arguments), extra);
diff --git a/extensions/renderer/api_activity_logger.h b/extensions/renderer/api_activity_logger.h index 2f586b53..e185b6d 100644 --- a/extensions/renderer/api_activity_logger.h +++ b/extensions/renderer/api_activity_logger.h
@@ -34,6 +34,8 @@ const std::string& call_name, const std::vector<v8::Local<v8::Value>>& arguments); + static void set_log_for_testing(bool log); + private: // Used to distinguish API calls & events from each other in LogInternal. enum CallType { APICALL, EVENT };
diff --git a/extensions/renderer/api_activity_logger_unittest.cc b/extensions/renderer/api_activity_logger_unittest.cc new file mode 100644 index 0000000..be64bb4 --- /dev/null +++ b/extensions/renderer/api_activity_logger_unittest.cc
@@ -0,0 +1,83 @@ +// 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 "extensions/renderer/api_activity_logger.h" + +#include "base/memory/ptr_util.h" +#include "content/public/test/mock_render_thread.h" +#include "extensions/common/extension_messages.h" +#include "extensions/common/features/feature.h" +#include "extensions/common/test_util.h" +#include "extensions/renderer/bindings/api_binding_test.h" +#include "extensions/renderer/bindings/api_binding_test_util.h" +#include "extensions/renderer/script_context.h" +#include "extensions/renderer/script_context_set.h" +#include "extensions/renderer/test_extensions_renderer_client.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_test_sink.h" + +namespace extensions { + +namespace { + +class ScopedAllowActivityLogging { + public: + ScopedAllowActivityLogging() { APIActivityLogger::set_log_for_testing(true); } + + ~ScopedAllowActivityLogging() { + APIActivityLogger::set_log_for_testing(false); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedAllowActivityLogging); +}; + +} // namespace + +using ActivityLoggerTest = APIBindingTest; + +// Regression test for crbug.com/740866. +TEST_F(ActivityLoggerTest, DontCrashOnUnconvertedValues) { + content::MockRenderThread mock_render_thread; + TestExtensionsRendererClient client; + std::set<ExtensionId> extension_ids; + ScriptContextSet script_context_set(&extension_ids); + + ScopedAllowActivityLogging scoped_allow_activity_logging; + + v8::HandleScope handle_scope(isolate()); + v8::Local<v8::Context> context = MainContext(); + + scoped_refptr<const Extension> extension = test_util::CreateEmptyExtension(); + extension_ids.insert(extension->id()); + const Feature::Context kContextType = Feature::BLESSED_EXTENSION_CONTEXT; + script_context_set.AddForTesting(base::MakeUnique<ScriptContext>( + context, nullptr, extension.get(), kContextType, extension.get(), + kContextType)); + + std::vector<v8::Local<v8::Value>> args = {v8::Undefined(isolate())}; + + IPC::TestSink& sink = mock_render_thread.sink(); + sink.ClearMessages(); + + APIActivityLogger::LogAPICall(context, "someApiMethod", args); + + ASSERT_EQ(1u, sink.message_count()); + const IPC::Message* message = sink.GetMessageAt(0u); + ASSERT_EQ(ExtensionHostMsg_AddAPIActionToActivityLog::ID, message->type()); + ExtensionHostMsg_AddAPIActionToActivityLog::Param full_params; + ASSERT_TRUE( + ExtensionHostMsg_AddAPIActionToActivityLog::Read(message, &full_params)); + std::string extension_id = std::get<0>(full_params); + ExtensionHostMsg_APIActionOrEvent_Params params = std::get<1>(full_params); + EXPECT_EQ(extension->id(), extension_id); + ASSERT_EQ(1u, params.arguments.GetList().size()); + EXPECT_EQ(base::Value::Type::NONE, params.arguments.GetList()[0].type()); + + ScriptContext* script_context = script_context_set.GetByV8Context(context); + script_context_set.Remove(script_context); + base::RunLoop().RunUntilIdle(); // Let script context destruction complete. +} + +} // namespace extensions
diff --git a/extensions/shell/browser/shell_speech_recognition_manager_delegate.cc b/extensions/shell/browser/shell_speech_recognition_manager_delegate.cc index 25d1b87..759d67af 100644 --- a/extensions/shell/browser/shell_speech_recognition_manager_delegate.cc +++ b/extensions/shell/browser/shell_speech_recognition_manager_delegate.cc
@@ -66,7 +66,7 @@ void ShellSpeechRecognitionManagerDelegate::CheckRecognitionIsAllowed( int session_id, - base::Callback<void(bool ask_user, bool is_allowed)> callback) { + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); const content::SpeechRecognitionSessionContext& context = @@ -76,11 +76,10 @@ // |render_process_id| field, which is needed later to retrieve the profile. DCHECK_NE(context.render_process_id, 0); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&CheckRenderViewType, - callback, - context.render_process_id, - context.render_view_id)); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::BindOnce(&CheckRenderViewType, std::move(callback), + context.render_process_id, context.render_view_id)); } content::SpeechRecognitionEventListener* @@ -96,7 +95,7 @@ // static void ShellSpeechRecognitionManagerDelegate::CheckRenderViewType( - base::Callback<void(bool ask_user, bool is_allowed)> callback, + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback, int render_process_id, int render_view_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -119,8 +118,9 @@ } } - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(callback, check_permission, allowed)); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::BindOnce(std::move(callback), check_permission, allowed)); } } // namespace speech
diff --git a/extensions/shell/browser/shell_speech_recognition_manager_delegate.h b/extensions/shell/browser/shell_speech_recognition_manager_delegate.h index 7c05813a..0a0577f2 100644 --- a/extensions/shell/browser/shell_speech_recognition_manager_delegate.h +++ b/extensions/shell/browser/shell_speech_recognition_manager_delegate.h
@@ -41,12 +41,13 @@ // SpeechRecognitionManagerDelegate methods. void CheckRecognitionIsAllowed( int session_id, - base::Callback<void(bool ask_user, bool is_allowed)> callback) override; + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback) + override; content::SpeechRecognitionEventListener* GetEventListener() override; bool FilterProfanities(int render_process_id) override; static void CheckRenderViewType( - base::Callback<void(bool ask_user, bool is_allowed)> callback, + base::OnceCallback<void(bool ask_user, bool is_allowed)> callback, int render_process_id, int render_view_id);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc index 005a523..6a1cbc9 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -250,6 +250,27 @@ GLint image_height_ = 0; }; +class ScopedPackStateRowLengthReset { + public: + ScopedPackStateRowLengthReset(bool enable) { + if (!enable) { + return; + } + + glGetIntegerv(GL_PACK_ROW_LENGTH, &row_length_); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + } + + ~ScopedPackStateRowLengthReset() { + if (row_length_ != 0) { + glPixelStorei(GL_PACK_ROW_LENGTH, row_length_); + } + } + + private: + GLint row_length_ = 0; +}; + } // anonymous namespace // Implementations of commands @@ -1757,6 +1778,8 @@ void* pixels, int32_t* success) { FlushErrors(); + ScopedPackStateRowLengthReset reset_row_length( + bufsize != 0 && feature_info_->gl_version_info().is_es3); glReadPixelsRobustANGLE(x, y, width, height, format, type, bufsize, length, columns, rows, pixels); *success = FlushErrors() ? 0 : 1;
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc index 49a68842..2601dea 100644 --- a/gpu/command_buffer/service/memory_program_cache.cc +++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -395,7 +395,8 @@ curr_size_bytes_ / 1024); } -void MemoryProgramCache::LoadProgram(const std::string& program) { +void MemoryProgramCache::LoadProgram(const std::string& key, + const std::string& program) { std::unique_ptr<GpuProgramProto> proto( GpuProgramProto::default_instance().New()); if (proto->ParseFromString(program)) {
diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h index e4fce94..03881f2 100644 --- a/gpu/command_buffer/service/memory_program_cache.h +++ b/gpu/command_buffer/service/memory_program_cache.h
@@ -50,7 +50,7 @@ GLenum transform_feedback_buffer_mode, GLES2DecoderClient* client) override; - void LoadProgram(const std::string& program) override; + void LoadProgram(const std::string& key, const std::string& program) override; size_t Trim(size_t limit) override;
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc index 62442c9..b2c2f001 100644 --- a/gpu/command_buffer/service/memory_program_cache_unittest.cc +++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -248,7 +248,8 @@ cache_->Clear(); - cache_->LoadProgram(shader_cache_shader()); + std::string blank; + cache_->LoadProgram(blank, shader_cache_shader()); EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( vertex_shader_->last_compiled_signature(), fragment_shader_->last_compiled_signature(), @@ -349,8 +350,9 @@ SetExpectationsForLoadLinkedProgram(kProgramId, &emulator); + std::string blank; cache_->Clear(); - cache_->LoadProgram(shader_cache_shader()); + cache_->LoadProgram(blank, shader_cache_shader()); EXPECT_EQ( ProgramCache::PROGRAM_LOAD_SUCCESS,
diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h index 0f55139..25c23f0 100644 --- a/gpu/command_buffer/service/mocks.h +++ b/gpu/command_buffer/service/mocks.h
@@ -138,7 +138,7 @@ const std::vector<std::string>& transform_feedback_varyings, GLenum transform_feedback_buffer_mode, GLES2DecoderClient* client)); - MOCK_METHOD1(LoadProgram, void(const std::string&)); + MOCK_METHOD2(LoadProgram, void(const std::string&, const std::string&)); MOCK_METHOD1(Trim, size_t(size_t)); private:
diff --git a/gpu/command_buffer/service/program_cache.h b/gpu/command_buffer/service/program_cache.h index 5ac9d87..bbed054 100644 --- a/gpu/command_buffer/service/program_cache.h +++ b/gpu/command_buffer/service/program_cache.h
@@ -71,7 +71,8 @@ GLenum transform_feedback_buffer_mode, GLES2DecoderClient* client) = 0; - virtual void LoadProgram(const std::string& program) = 0; + virtual void LoadProgram(const std::string& key, + const std::string& program) = 0; // clears the cache void Clear();
diff --git a/gpu/command_buffer/service/program_cache_unittest.cc b/gpu/command_buffer/service/program_cache_unittest.cc index ee80e3a..b4d99ed7 100644 --- a/gpu/command_buffer/service/program_cache_unittest.cc +++ b/gpu/command_buffer/service/program_cache_unittest.cc
@@ -35,7 +35,8 @@ GLenum /* transform_feedback_buffer_mode */, GLES2DecoderClient* /* client */) override {} - void LoadProgram(const std::string& /* program */) override {} + void LoadProgram(const std::string& /*key*/, + const std::string& /* program */) override {} void ClearBackend() override {}
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc index 51b0c853..6da1483 100644 --- a/gpu/ipc/service/gpu_channel_manager.cc +++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -167,9 +167,10 @@ } } -void GpuChannelManager::PopulateShaderCache(const std::string& program_proto) { +void GpuChannelManager::PopulateShaderCache(const std::string& key, + const std::string& program) { if (program_cache()) - program_cache()->LoadProgram(program_proto); + program_cache()->LoadProgram(key, program); } void GpuChannelManager::LoseAllContexts() {
diff --git a/gpu/ipc/service/gpu_channel_manager.h b/gpu/ipc/service/gpu_channel_manager.h index 54a1d21..6ec72c1 100644 --- a/gpu/ipc/service/gpu_channel_manager.h +++ b/gpu/ipc/service/gpu_channel_manager.h
@@ -85,7 +85,7 @@ uint64_t client_tracing_id, bool is_gpu_host); - void PopulateShaderCache(const std::string& shader); + void PopulateShaderCache(const std::string& key, const std::string& program); void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, int client_id, const SyncToken& sync_token);
diff --git a/ios/chrome/app/DEPS b/ios/chrome/app/DEPS index cb09f05..e9d61b1a 100644 --- a/ios/chrome/app/DEPS +++ b/ios/chrome/app/DEPS
@@ -17,6 +17,7 @@ "+components/reading_list/core", "+components/signin/core/browser", "+components/suggestions", + "+components/task_scheduler_util", "+components/url_formatter", "+components/web_resource", "+ios/chrome/browser",
diff --git a/ios/chrome/app/startup/BUILD.gn b/ios/chrome/app/startup/BUILD.gn index bbd7bea..8e236b6 100644 --- a/ios/chrome/app/startup/BUILD.gn +++ b/ios/chrome/app/startup/BUILD.gn
@@ -24,6 +24,7 @@ deps = [ "//base", "//components/crash/core/common", + "//components/task_scheduler_util/browser", "//ios/chrome/browser:chrome_paths", "//ios/web/public/app", "//skia",
diff --git a/ios/chrome/app/startup/ios_chrome_main.mm b/ios/chrome/app/startup/ios_chrome_main.mm index d3ff28a..df0f6785 100644 --- a/ios/chrome/app/startup/ios_chrome_main.mm +++ b/ios/chrome/app/startup/ios_chrome_main.mm
@@ -8,9 +8,11 @@ #include <vector> +#include "base/bind.h" #include "base/logging.h" #include "base/strings/sys_string_conversions.h" #include "base/time/time.h" +#include "components/task_scheduler_util/browser/initialization.h" #include "ios/web/public/app/web_main_runner.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -24,7 +26,7 @@ IOSChromeMain::IOSChromeMain() { web_main_runner_.reset(web::WebMainRunner::Create()); - web::WebMainParams main_params = web::WebMainParams(&main_delegate_); + web::WebMainParams main_params(&main_delegate_); // Copy NSProcessInfo arguments into WebMainParams in debug only, since // command line should be meaningless outside of developer builds. #if !defined(NDEBUG) @@ -47,10 +49,12 @@ main_params.argv = argv; #endif + main_params.get_task_scheduler_init_params_callback = base::Bind( + &task_scheduler_util::GetBrowserTaskSchedulerInitParamsFromVariations); // Chrome registers an AtExitManager in main in order to initialize breakpad // early, so prevent a second registration by WebMainRunner. main_params.register_exit_manager = false; - web_main_runner_->Initialize(main_params); + web_main_runner_->Initialize(std::move(main_params)); } IOSChromeMain::~IOSChromeMain() {
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 55bab02e..d8437f1 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1245,12 +1245,6 @@ <message name="IDS_IOS_CONFIRM_PASSWORD_DELETION" desc="Label of a confirmation dialogue button which allows the user to confirm deletion of a stored password. [Length: one line] [iOS only]"> Delete Saved Password </message> - <message name="IDS_IOS_SETTINGS_PASSWORDS_SAVED_HEADING" desc="The title for a list of username/site/password items. These items are already saved by the browser and can be deleted/edited. [Length: one line] [iOS only]"> - Saved Passwords - </message> - <message name="IDS_IOS_SETTINGS_PASSWORDS_EXCEPTIONS_HEADING" desc="The title for a list of sites where passwords will not be saved. These items are already saved by the browser and can only be deleted. [Length: one line] [iOS only]"> - Never Saved - </message> <message name="IDS_IOS_SIGNED_IN_ACCOUNTS_VIEW_OK_BUTTON" desc="The title of the OK button of the Signed In Accounts view [iOS only] [20em]"> OK, Got It </message>
diff --git a/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm b/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm index 6296993..27f20db 100644 --- a/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm +++ b/ios/chrome/browser/ntp_tiles/ntp_tiles_egtest.mm
@@ -11,6 +11,8 @@ #import "ios/chrome/test/earl_grey/chrome_matchers.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h" #import "ios/testing/wait_util.h" +#import "ios/web/public/test/http_server/html_response_provider.h" +#import "ios/web/public/test/http_server/html_response_provider_impl.h" #import "ios/web/public/test/http_server/http_server.h" #include "ios/web/public/test/http_server/http_server_util.h" @@ -18,12 +20,19 @@ #error "This file requires ARC support." #endif +using web::test::HttpServer; + // Test case for NTP tiles. @interface NTPTilesTest : ChromeTestCase @end @implementation NTPTilesTest +- (void)tearDown { + chrome_test_util::ClearBrowsingHistory(); + [[GREYUIThreadExecutor sharedInstance] drainUntilIdle]; +} + // Tests that loading a URL ends up creating an NTP tile. - (void)testTopSitesTileAfterLoadURL { std::map<GURL, std::string> responses; @@ -54,4 +63,55 @@ assertWithMatcher:grey_notNil()]; } +// Tests that only one NTP tile is displayed for a TopSite that involves a +// redirect. +- (void)testTopSitesTileAfterRedirect { + std::map<GURL, HtmlResponseProviderImpl::Response> responses; + const GURL firstRedirectURL = HttpServer::MakeUrl("http://firstRedirect/"); + const GURL destinationURL = HttpServer::MakeUrl("http://destination/"); + responses[firstRedirectURL] = HtmlResponseProviderImpl::GetRedirectResponse( + destinationURL, net::HTTP_MOVED_PERMANENTLY); + + // Add titles to both responses, which is what will show up on the NTP. + responses[firstRedirectURL].body = + "<head><title>title1</title></head>" + "<body>Should redirect away.</body>"; + + const char kFinalPageContent[] = + "<head><title>title2</title></head>" + "<body>redirect complete</body>"; + responses[destinationURL] = + HtmlResponseProviderImpl::GetSimpleResponse(kFinalPageContent); + std::unique_ptr<web::DataResponseProvider> provider( + new HtmlResponseProvider(responses)); + web::test::SetUpHttpServer(std::move(provider)); + + // Clear history and verify that the tile does not exist. + chrome_test_util::ClearBrowsingHistory(); + [[GREYUIThreadExecutor sharedInstance] drainUntilIdle]; + chrome_test_util::OpenNewTab(); + [[EarlGrey selectElementWithMatcher: + chrome_test_util::StaticTextWithAccessibilityLabel(@"title2")] + assertWithMatcher:grey_nil()]; + + // Load first URL and expect redirect to destination URL. + [ChromeEarlGrey loadURL:firstRedirectURL]; + [ChromeEarlGrey waitForWebViewContainingText:"redirect complete"]; + + // After loading URL, need to do another action before opening a new tab + // with the icon present. + [ChromeEarlGrey goBack]; + chrome_test_util::OpenNewTab(); + + // Which of the two tiles that is displayed is an implementation detail, and + // this test helps document it. The purpose of the test is to verify that only + // one tile is displayed. + [[EarlGrey selectElementWithMatcher: + chrome_test_util::StaticTextWithAccessibilityLabel(@"title2")] + assertWithMatcher:grey_notNil()]; + [[EarlGrey selectElementWithMatcher: + chrome_test_util::StaticTextWithAccessibilityLabel(@"title1")] + assertWithMatcher:grey_nil()]; +} + @end
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 d6ac1a2..b39ec12 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc +++ b/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc
@@ -10,6 +10,7 @@ #include "base/command_line.h" #include "base/memory/singleton.h" #include "base/sequenced_task_runner.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/sequenced_task_runner_handle.h" #include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/core/service_access_type.h" @@ -26,7 +27,6 @@ #include "ios/chrome/browser/sync/glue/sync_start_util.h" #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h" #include "ios/chrome/browser/web_data_service_factory.h" -#include "ios/web/public/web_thread.h" // static scoped_refptr<password_manager::PasswordStore> @@ -80,8 +80,14 @@ scoped_refptr<base::SequencedTaskRunner> main_thread_runner( base::SequencedTaskRunnerHandle::Get()); + // USER_VISIBLE priority is chosen for the background task runner, because + // the passwords obtained through tasks on the background runner influence + // what the user sees. + // TODO(crbug.com/741660): Create the task runner inside password_manager + // component instead. scoped_refptr<base::SequencedTaskRunner> db_thread_runner( - web::WebThread::GetTaskRunnerForThread(web::WebThread::DB)); + base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::USER_VISIBLE})); scoped_refptr<password_manager::PasswordStore> store = new password_manager::PasswordStoreDefault(
diff --git a/ios/chrome/browser/payments/payment_request.h b/ios/chrome/browser/payments/payment_request.h index 4f54940c..a851d44 100644 --- a/ios/chrome/browser/payments/payment_request.h +++ b/ios/chrome/browser/payments/payment_request.h
@@ -220,6 +220,10 @@ virtual PaymentsProfileComparator* profile_comparator(); + // Returns a const version of what the non-const |profile_comparator()| + // method above returns. + const PaymentsProfileComparator* profile_comparator() const; + // Returns whether the current PaymentRequest can be used to make a payment. bool CanMakePayment() const;
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm index 2d1661af..785c7f7 100644 --- a/ios/chrome/browser/payments/payment_request.mm +++ b/ios/chrome/browser/payments/payment_request.mm
@@ -105,9 +105,7 @@ } } - // TODO(crbug.com/702063): Change this code to prioritize payment methods by - // use count and other means. - auto first_complete_payment_method = + const auto first_complete_payment_method = std::find_if(payment_methods_.begin(), payment_methods_.end(), [this](PaymentInstrument* payment_method) { return payment_method->IsCompleteForPayment(); @@ -229,7 +227,8 @@ profile_cache_.push_back( base::MakeUnique<autofill::AutofillProfile>(profile)); - PopulateAvailableProfiles(); + contact_profiles_.push_back(profile_cache_.back().get()); + shipping_profiles_.push_back(profile_cache_.back().get()); return profile_cache_.back().get(); } @@ -241,6 +240,7 @@ if (profiles_to_suggest.empty()) return; + profile_cache_.clear(); profile_cache_.reserve(profiles_to_suggest.size()); for (const auto* profile : profiles_to_suggest) { @@ -305,7 +305,7 @@ method_name, credit_card, matches_merchant_card_type_exactly, billing_profiles(), GetApplicationLocale(), this)); - PopulateAvailablePaymentMethods(); + payment_methods_.push_back(payment_method_cache_.back().get()); return static_cast<AutofillPaymentInstrument*>( payment_method_cache_.back().get()); @@ -315,6 +315,12 @@ return &profile_comparator_; } +const PaymentsProfileComparator* PaymentRequest::profile_comparator() const { + // Return a const version of what the non-const |profile_comparator| method + // returns. + return const_cast<PaymentRequest*>(this)->profile_comparator(); +} + bool PaymentRequest::CanMakePayment() const { for (PaymentInstrument* payment_method : payment_methods_) { if (payment_method->IsValidForCanMakePayment()) { @@ -365,9 +371,10 @@ if (credit_cards_to_suggest.empty()) return; - // TODO(crbug.com/602666): Determine number of possible payments so - // that we can appropriate reserve space in the following vector. + // TODO(crbug.com/602666): Determine the number of possible payment methods so + // that we can reserve enough space in the following vector. + payment_method_cache_.clear(); payment_method_cache_.reserve(credit_cards_to_suggest.size()); for (const auto* credit_card : credit_cards_to_suggest) @@ -381,7 +388,6 @@ payment_methods_.clear(); payment_methods_.reserve(payment_method_cache_.size()); - // TODO(crbug.com/602666): Implement prioritization rules for payment methods. for (auto const& payment_method : payment_method_cache_) payment_methods_.push_back(payment_method.get()); }
diff --git a/ios/chrome/browser/payments/payment_request_util.h b/ios/chrome/browser/payments/payment_request_util.h index 5a054a1..ddb51672 100644 --- a/ios/chrome/browser/payments/payment_request_util.h +++ b/ios/chrome/browser/payments/payment_request_util.h
@@ -51,13 +51,13 @@ // Helper function to create a notification label for an address cell from an // autofill profile. Returns nil if the resulting label is empty. NSString* GetAddressNotificationLabelFromAutofillProfile( - payments::PaymentRequest& payment_request, + const payments::PaymentRequest& payment_request, const autofill::AutofillProfile& profile); // Helper function to create a notification label for what's missing from a // payment method. Returns nil if the resulting label is empty. NSString* GetPaymentMethodNotificationLabelFromPaymentMethod( - payments::PaymentInstrument& payment_method, + const payments::PaymentInstrument& payment_method, const std::vector<autofill::AutofillProfile*>& billing_profiles); // Returns the title for the shipping section of the payment summary view given @@ -74,6 +74,12 @@ NSString* GetShippingOptionSelectorErrorMessage( const payments::PaymentRequest& payment_request); +// Helper function to create a notification label for a contact info entry from +// an autofill profile. Returns nil if the resulting label is empty. +NSString* GetContactNotificationLabelFromAutofillProfile( + const payments::PaymentRequest& payment_request, + const autofill::AutofillProfile& profile); + } // namespace payment_request_util #endif // IOS_CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_UTIL_H_
diff --git a/ios/chrome/browser/payments/payment_request_util.mm b/ios/chrome/browser/payments/payment_request_util.mm index b272ae4..83b1eb0 100644 --- a/ios/chrome/browser/payments/payment_request_util.mm +++ b/ios/chrome/browser/payments/payment_request_util.mm
@@ -66,7 +66,7 @@ } NSString* GetAddressNotificationLabelFromAutofillProfile( - payments::PaymentRequest& payment_request, + const payments::PaymentRequest& payment_request, const autofill::AutofillProfile& profile) { base::string16 label = payment_request.profile_comparator()->GetStringForMissingShippingFields( @@ -75,7 +75,7 @@ } NSString* GetPaymentMethodNotificationLabelFromPaymentMethod( - payments::PaymentInstrument& payment_method, + const payments::PaymentInstrument& payment_method, const std::vector<autofill::AutofillProfile*>& billing_profiles) { base::string16 label = payment_method.GetMissingInfoLabel(); return !label.empty() ? base::SysUTF16ToNSString(label) : nil; @@ -131,4 +131,13 @@ } } +NSString* GetContactNotificationLabelFromAutofillProfile( + const payments::PaymentRequest& payment_request, + const autofill::AutofillProfile& profile) { + const base::string16 notification = + payment_request.profile_comparator()->GetStringForMissingContactFields( + profile); + return !notification.empty() ? base::SysUTF16ToNSString(notification) : nil; +} + } // namespace payment_request_util
diff --git a/ios/chrome/browser/reading_list/url_downloader.cc b/ios/chrome/browser/reading_list/url_downloader.cc index ddf99e64..135c014d 100644 --- a/ios/chrome/browser/reading_list/url_downloader.cc +++ b/ios/chrome/browser/reading_list/url_downloader.cc
@@ -12,12 +12,13 @@ #include "base/memory/ptr_util.h" #include "base/path_service.h" #include "base/stl_util.h" +#include "base/task_scheduler/post_task.h" +#include "base/threading/thread_restrictions.h" #include "components/reading_list/core/offline_url_utils.h" #include "ios/chrome/browser/chrome_paths.h" #include "ios/chrome/browser/dom_distiller/distiller_viewer.h" #include "ios/chrome/browser/reading_list/reading_list_distiller_page.h" #include "ios/chrome/browser/reading_list/reading_list_distiller_page_factory.h" -#include "ios/web/public/web_thread.h" #include "net/base/escape.h" #include "net/base/load_flags.h" #include "net/http/http_response_headers.h" @@ -60,6 +61,9 @@ base_directory_(chrome_profile_path), mime_type_(), url_request_context_getter_(url_request_context_getter), + task_runner_(base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})), task_tracker_() {} URLDownloader::~URLDownloader() { @@ -68,9 +72,9 @@ void URLDownloader::OfflinePathExists(const base::FilePath& path, base::Callback<void(bool)> callback) { - task_tracker_.PostTaskAndReplyWithResult( - web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(), - FROM_HERE, base::Bind(&base::PathExists, path), callback); + task_tracker_.PostTaskAndReplyWithResult(task_runner_.get(), FROM_HERE, + base::Bind(&base::PathExists, path), + callback); } void URLDownloader::RemoveOfflineURL(const GURL& url) { @@ -117,12 +121,12 @@ base::FilePath directory_path = reading_list::OfflineURLDirectoryAbsolutePath(base_directory_, url); task_tracker_.PostTaskAndReply( - web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(), - FROM_HERE, base::Bind( - [](const base::FilePath& offline_directory_path) { - base::DeleteFile(offline_directory_path, true); - }, - directory_path), + task_runner_.get(), FROM_HERE, + base::Bind( + [](const base::FilePath& offline_directory_path) { + base::DeleteFile(offline_directory_path, true); + }, + directory_path), post_delete); } else { post_delete.Run(); @@ -150,8 +154,8 @@ if (task.first == DELETE) { task_tracker_.PostTaskAndReplyWithResult( - web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(), - FROM_HERE, base::Bind(&base::DeleteFile, directory_path, true), + task_runner_.get(), FROM_HERE, + base::Bind(&base::DeleteFile, directory_path, true), base::Bind(&URLDownloader::DeleteCompletionHandler, base::Unretained(this), url)); } else if (task.first == DOWNLOAD) { @@ -212,9 +216,9 @@ fetcher_->GetResponseAsFilePath(false, &temporary_path); task_tracker_.PostTaskAndReplyWithResult( - web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(), - FROM_HERE, base::Bind(&URLDownloader::SavePDFFile, base::Unretained(this), - temporary_path), + task_runner_.get(), FROM_HERE, + base::Bind(&URLDownloader::SavePDFFile, base::Unretained(this), + temporary_path), base::Bind(&URLDownloader::DownloadCompletionHandler, base::Unretained(this), source->GetOriginalURL(), "", path)); } @@ -230,13 +234,13 @@ fetcher_ = net::URLFetcher::Create(0, pdf_url, net::URLFetcher::GET, this); fetcher_->SetRequestContext(url_request_context_getter_.get()); fetcher_->SetLoadFlags(net::LOAD_SKIP_CACHE_VALIDATION); - fetcher_->SaveResponseToTemporaryFile( - web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE)); + fetcher_->SaveResponseToTemporaryFile(task_runner_.get()); fetcher_->Start(); } URLDownloader::SuccessState URLDownloader::SavePDFFile( const base::FilePath& temporary_path) { + base::ThreadRestrictions::AssertIOAllowed(); if (CreateOfflineURLDirectory(original_url_)) { base::FilePath path = reading_list::OfflinePagePath( original_url_, reading_list::OFFLINE_TYPE_PDF); @@ -279,8 +283,7 @@ std::vector<dom_distiller::DistillerViewer::ImageInfo> images_block = images; std::string block_html = html; task_tracker_.PostTaskAndReplyWithResult( - web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(), - FROM_HERE, + task_runner_.get(), FROM_HERE, base::Bind(&URLDownloader::SaveDistilledHTML, base::Unretained(this), page_url, images_block, block_html), base::Bind(&URLDownloader::DownloadCompletionHandler, @@ -294,6 +297,7 @@ const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>& images, const std::string& html) { + base::ThreadRestrictions::AssertIOAllowed(); if (CreateOfflineURLDirectory(url)) { return SaveHTMLForURL(SaveAndReplaceImagesInHTML(url, html, images), url) ? DOWNLOAD_SUCCESS
diff --git a/ios/chrome/browser/reading_list/url_downloader.h b/ios/chrome/browser/reading_list/url_downloader.h index 24beb41..8bf83c43 100644 --- a/ios/chrome/browser/reading_list/url_downloader.h +++ b/ios/chrome/browser/reading_list/url_downloader.h
@@ -16,6 +16,7 @@ class GURL; namespace base { class FilePath; +class SequencedTaskRunner; } namespace net { @@ -192,6 +193,7 @@ // URLRequestContextGetter needed for the URLFetcher. scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; std::unique_ptr<dom_distiller::DistillerViewerInterface> distiller_; + scoped_refptr<base::SequencedTaskRunner> task_runner_; base::CancelableTaskTracker task_tracker_; DISALLOW_COPY_AND_ASSIGN(URLDownloader);
diff --git a/ios/chrome/browser/reading_list/url_downloader_unittest.mm b/ios/chrome/browser/reading_list/url_downloader_unittest.mm index 6905af9..4e0c5c46 100644 --- a/ios/chrome/browser/reading_list/url_downloader_unittest.mm +++ b/ios/chrome/browser/reading_list/url_downloader_unittest.mm
@@ -9,15 +9,14 @@ #include "base/files/file_util.h" #import "base/mac/bind_objc_block.h" #include "base/path_service.h" -#include "base/run_loop.h" #include "base/stl_util.h" #import "base/test/ios/wait_util.h" +#include "base/test/scoped_task_environment.h" #include "components/reading_list/core/offline_url_utils.h" #include "ios/chrome/browser/chrome_paths.h" #include "ios/chrome/browser/dom_distiller/distiller_viewer.h" #include "ios/chrome/browser/reading_list/offline_url_utils.h" #include "ios/chrome/browser/reading_list/reading_list_distiller_page.h" -#include "ios/web/public/test/test_web_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -136,15 +135,13 @@ namespace { class URLDownloaderTest : public testing::Test { public: - std::unique_ptr<MockURLDownloader> downloader_; - web::TestWebThreadBundle bundle_; - URLDownloaderTest() { base::FilePath data_dir; base::PathService::Get(ios::DIR_USER_DATA, &data_dir); RemoveOfflineFilesDirectory(data_dir); downloader_.reset(new MockURLDownloader(data_dir)); } + ~URLDownloaderTest() override {} void TearDown() override { @@ -154,10 +151,12 @@ downloader_->ClearCompletionTrackers(); } - void WaitUntilCondition(ConditionBlock condition) { - base::test::ios::WaitUntilCondition(condition, true, - base::TimeDelta::FromSeconds(1)); - } + protected: + base::test::ScopedTaskEnvironment task_environment_; + std::unique_ptr<MockURLDownloader> downloader_; + + private: + DISALLOW_COPY_AND_ASSIGN(URLDownloaderTest); }; TEST_F(URLDownloaderTest, SingleDownload) { @@ -168,9 +167,8 @@ downloader_->DownloadOfflineURL(url); - WaitUntilCondition(^bool { - return base::ContainsValue(downloader_->downloaded_files_, url); - }); + // Wait for all asynchronous tasks to complete. + task_environment_.RunUntilIdle(); ASSERT_TRUE(downloader_->CheckExistenceOfOfflineURLPagePath(url)); } @@ -187,9 +185,8 @@ downloader_->DownloadOfflineURL(url); - WaitUntilCondition(^bool { - return base::ContainsValue(downloader_->downloaded_files_, url); - }); + // Wait for all asynchronous tasks to complete. + task_environment_.RunUntilIdle(); EXPECT_TRUE(downloader_->CheckExistenceOfOfflineURLPagePath(url)); } @@ -205,9 +202,8 @@ downloader_->DownloadOfflineURL(url); - WaitUntilCondition(^bool { - return downloader_->fetching_pdf_; - }); + // Wait for all asynchronous tasks to complete. + task_environment_.RunUntilIdle(); EXPECT_FALSE(downloader_->CheckExistenceOfOfflineURLPagePath(url)); } @@ -225,9 +221,8 @@ downloader_->RemoveOfflineURL(url); downloader_->FakeEndWorking(); - WaitUntilCondition(^bool { - return base::ContainsValue(downloader_->removed_files_, url); - }); + // Wait for all asynchronous tasks to complete. + task_environment_.RunUntilIdle(); ASSERT_TRUE(!base::ContainsValue(downloader_->downloaded_files_, url)); ASSERT_EQ(1ul, downloader_->downloaded_files_.size()); @@ -245,9 +240,8 @@ downloader_->DownloadOfflineURL(url); downloader_->FakeEndWorking(); - WaitUntilCondition(^bool { - return base::ContainsValue(downloader_->removed_files_, url); - }); + // Wait for all asynchronous tasks to complete. + task_environment_.RunUntilIdle(); ASSERT_TRUE(base::ContainsValue(downloader_->downloaded_files_, url)); ASSERT_TRUE(base::ContainsValue(downloader_->removed_files_, url));
diff --git a/ios/chrome/browser/snapshots/BUILD.gn b/ios/chrome/browser/snapshots/BUILD.gn index 20d924e..8b4aecc6 100644 --- a/ios/chrome/browser/snapshots/BUILD.gn +++ b/ios/chrome/browser/snapshots/BUILD.gn
@@ -13,6 +13,8 @@ "snapshot_cache_internal.h", "snapshot_cache_web_state_list_observer.h", "snapshot_cache_web_state_list_observer.mm", + "snapshot_constants.h", + "snapshot_constants.mm", "snapshot_manager.h", "snapshot_manager.mm", "snapshot_overlay.h",
diff --git a/ios/chrome/browser/snapshots/snapshot_constants.h b/ios/chrome/browser/snapshots/snapshot_constants.h new file mode 100644 index 0000000..15e65e79 --- /dev/null +++ b/ios/chrome/browser/snapshots/snapshot_constants.h
@@ -0,0 +1,13 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_SNAPSHOTS_SNAPSHOT_CONSTANTS_H_ +#define IOS_CHROME_BROWSER_SNAPSHOTS_SNAPSHOT_CONSTANTS_H_ + +#import <CoreGraphics/CoreGraphics.h> + +// Size for thumbnail snapshots. +extern const CGSize kSnapshotThumbnailSize; + +#endif // IOS_CHROME_BROWSER_SNAPSHOTS_SNAPSHOT_CONSTANTS_H_
diff --git a/ios/chrome/browser/snapshots/snapshot_constants.mm b/ios/chrome/browser/snapshots/snapshot_constants.mm new file mode 100644 index 0000000..34e2925 --- /dev/null +++ b/ios/chrome/browser/snapshots/snapshot_constants.mm
@@ -0,0 +1,11 @@ +// 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/snapshots/snapshot_constants.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +const CGSize kSnapshotThumbnailSize = {250.0f, 250.0f};
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index 0f6e5177..ee0cd0a8 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -33,7 +33,9 @@ #include "base/metrics/user_metrics_action.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/sequenced_worker_pool.h" +#include "base/threading/thread_restrictions.h" #include "components/bookmarks/browser/base_bookmark_model_observer.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h" @@ -739,9 +741,12 @@ - (void)managePermissionAndSaveImage:(NSData*)data withFileExtension:(NSString*)fileExtension; // Saves the image. In order to keep the metadata of the image, the image is -// saved as a temporary file on disk then saved in photos. -// This should be called on FILE thread. -- (void)saveImage:(NSData*)data withFileExtension:(NSString*)fileExtension; +// saved as a temporary file on disk then saved in photos. Saving will happen +// on a background sequence and the completion block will be invoked on that +// sequence. +- (void)saveImage:(NSData*)data + withFileExtension:(NSString*)fileExtension + completion:(void (^)(BOOL, NSError*))completionBlock; // Called when Chrome has been denied access to the photos or videos and the // user can change it. // Shows a privacy alert on the main queue, allowing the user to go to Chrome's @@ -3319,50 +3324,62 @@ break; // The application has permission to access the photos. - default: { - web::WebThread::PostTask( - web::WebThread::FILE, FROM_HERE, base::BindBlockArc(^{ - [self saveImage:data withFileExtension:fileExtension]; - })); + default: + __weak BrowserViewController* weakSelf = self; + [self saveImage:data + withFileExtension:fileExtension + completion:^(BOOL success, NSError* error) { + [weakSelf finishSavingImageWithError:error]; + }]; break; - } } } -- (void)saveImage:(NSData*)data withFileExtension:(NSString*)fileExtension { - NSString* fileName = [[[NSProcessInfo processInfo] globallyUniqueString] - stringByAppendingString:fileExtension]; - NSURL* fileURL = - [NSURL fileURLWithPath:[NSTemporaryDirectory() - stringByAppendingPathComponent:fileName]]; - NSError* error = nil; - [data writeToURL:fileURL options:NSDataWritingAtomic error:&error]; +- (void)saveImage:(NSData*)data + withFileExtension:(NSString*)fileExtension + completion:(void (^)(BOOL, NSError*))completion { + base::PostTaskWithTraits( + FROM_HERE, + {base::MayBlock(), base::TaskPriority::BACKGROUND, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::BindBlockArc(^{ + base::ThreadRestrictions::AssertIOAllowed(); - // Error while writing the image to disk. - if (error) { - NSString* errorMessage = [NSString - stringWithFormat:@"%@ (%@ %" PRIdNS ")", [error localizedDescription], - [error domain], [error code]]; - [self displayPrivacyErrorAlertOnMainQueue:errorMessage]; - return; - } + NSString* fileName = [[[NSProcessInfo processInfo] globallyUniqueString] + stringByAppendingString:fileExtension]; + NSURL* fileURL = [NSURL + fileURLWithPath:[NSTemporaryDirectory() + stringByAppendingPathComponent:fileName]]; + NSError* error = nil; + [data writeToURL:fileURL options:NSDataWritingAtomic error:&error]; + if (error) { + if (completion) + completion(NO, error); + return; + } - // Save the image to photos. - [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ - [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:fileURL]; - } - completionHandler:^(BOOL success, NSError* error) { - // Callback for the image saving. - [self finishSavingImageWithError:error]; + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ + [PHAssetChangeRequest + creationRequestForAssetFromImageAtFileURL:fileURL]; + } + completionHandler:^(BOOL success, NSError* error) { + base::PostTaskWithTraits( + FROM_HERE, + {base::MayBlock(), base::TaskPriority::BACKGROUND, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::BindBlockArc(^{ + base::ThreadRestrictions::AssertIOAllowed(); + if (completion) + completion(success, error); - // Cleanup the temporary file. - web::WebThread::PostTask( - web::WebThread::FILE, FROM_HERE, base::BindBlockArc(^{ - NSError* error = nil; - [[NSFileManager defaultManager] removeItemAtURL:fileURL - error:&error]; - })); - }]; + // Cleanup the temporary file. + NSError* deleteFileError = nil; + [[NSFileManager defaultManager] + removeItemAtURL:fileURL + error:&deleteFileError]; + })); + }]; + })); } - (void)displayImageErrorAlertWithSettingsOnMainQueue {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm index 8ff51fb..7c53b521 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -70,7 +70,6 @@ if (self) { _collectionUpdater = [[ContentSuggestionsCollectionUpdater alloc] initWithDataSource:dataSource]; - self.collectionView.prefetchingEnabled = NO; } return self; }
diff --git a/ios/chrome/browser/ui/infobars/infobar_view.mm b/ios/chrome/browser/ui/infobars/infobar_view.mm index dc3471dd..d4b54623 100644 --- a/ios/chrome/browser/ui/infobars/infobar_view.mm +++ b/ios/chrome/browser/ui/infobars/infobar_view.mm
@@ -658,9 +658,7 @@ action:(SEL)action { DCHECK(!closeButton_); // TODO(crbug/228611): Add IDR_ constant and use GetNativeImageNamed(). - NSString* imagePath = - [[NSBundle mainBundle] pathForResource:@"infobar_close" ofType:@"png"]; - UIImage* image = [UIImage imageWithContentsOfFile:imagePath]; + UIImage* image = [UIImage imageNamed:@"infobar_close"]; closeButton_ = [UIButton buttonWithType:UIButtonTypeCustom]; [closeButton_ setExclusiveTouch:YES]; [closeButton_ setImage:image forState:UIControlStateNormal];
diff --git a/ios/chrome/browser/ui/keyboard/BUILD.gn b/ios/chrome/browser/ui/keyboard/BUILD.gn index 0a188fc..eec343de 100644 --- a/ios/chrome/browser/ui/keyboard/BUILD.gn +++ b/ios/chrome/browser/ui/keyboard/BUILD.gn
@@ -7,8 +7,6 @@ sources = [ "UIKeyCommand+Chrome.h", "UIKeyCommand+Chrome.mm", - "hardware_keyboard_watcher.h", - "hardware_keyboard_watcher.mm", ] deps = [ "//base", @@ -21,14 +19,11 @@ testonly = true sources = [ "UIKeyCommand+ChromeTest.mm", - "hardware_keyboard_watcher_unittest.mm", ] deps = [ ":keyboard", "//base", - "//base/test:test_support", "//ios/chrome/browser/ui/commands", "//testing/gtest", - "//third_party/ocmock", ] }
diff --git a/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.h b/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.h deleted file mode 100644 index 770181a0..0000000 --- a/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_KEYBOARD_HARDWARE_KEYBOARD_WATCHER_H_ -#define IOS_CHROME_BROWSER_UI_KEYBOARD_HARDWARE_KEYBOARD_WATCHER_H_ - -#import <UIKit/UIKit.h> - -// Watches keyboard events to determine if the keyboard is software (provided by -// iOS, fully visible on screen when showing) or hardware (external keyboard, -// only showing a potential input accessory view). -// It reports the mode for each keyboard frame change via an UMA histogram -// (Omnibox.HardwareKeyboardModeEnabled). -@interface HardwareKeyboardWatcher : NSObject - -// Pass an accessory view to check for presence in the view hierarchy. Keyboard -// presentation/dismissal with no input accessory view have a different code -// path between hardware and software keyboard mode, thus unreliable for -// metrics comparisons. -// |accessoryView| must not be nil. -- (instancetype)initWithAccessoryView:(UIView*)accessoryView - NS_DESIGNATED_INITIALIZER; - -// Detection of external keyboards only works when an input accessory view is -// set. -- (instancetype)init NS_UNAVAILABLE; - -@end - -#endif // IOS_CHROME_BROWSER_UI_KEYBOARD_HARDWARE_KEYBOARD_WATCHER_H_
diff --git a/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.mm b/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.mm deleted file mode 100644 index a13ee7fc..0000000 --- a/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.mm +++ /dev/null
@@ -1,96 +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 "ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.h" - -#import <CoreGraphics/CoreGraphics.h> - -#include "base/logging.h" -#include "base/mac/scoped_nsobject.h" -#include "base/metrics/histogram_macros.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -// Whether firstRect has a non null rect intersection with secondRect, yet does -// not fully include it. -bool IntersectsButDoesNotInclude(CGRect firstRect, CGRect secondRect) { - return CGRectIntersectsRect(firstRect, secondRect) && - !CGRectContainsRect(firstRect, secondRect); -} - -} // namespace - -@interface HardwareKeyboardWatcher () { - base::scoped_nsobject<UIView> _accessoryView; -} -@end - -@implementation HardwareKeyboardWatcher - -- (instancetype)init { - NOTREACHED(); - return nil; -} - -- (instancetype)initWithAccessoryView:(UIView*)accessoryView { - DCHECK(accessoryView); - self = [super init]; - if (self) { - _accessoryView.reset(accessoryView); - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(keyboardWillChangeFrame:) - name:UIKeyboardWillChangeFrameNotification - object:nil]; - } - return self; -} - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)keyboardWillChangeFrame:(NSNotification*)notification { - // Don't handle keyboard notifications not involving the set accessory view. - if ([_accessoryView window] == nil) - return; - - NSDictionary* userInfo = [notification userInfo]; - CGRect beginKeyboardFrame = - [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue]; - CGRect endKeyboardFrame = - [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; - CGRect screenBounds = [UIScreen mainScreen].bounds; - - // During rotations, the reported keyboard frames are in the screen - // coordinates *prior* to the rotation, while the screen already has its - // new coordinates. http://crbug.com/511267 - // To alleviate that, switch the screen bounds width and height if needed. - if (CGRectGetHeight(screenBounds) == CGRectGetWidth(beginKeyboardFrame)) { - screenBounds.size = - CGSizeMake(CGRectGetHeight(screenBounds), CGRectGetWidth(screenBounds)); - } - - // CGRectZero frames are seen when moving a split dock. Split keyboard means - // software keyboard. - bool hasCGRectZeroFrames = - CGRectEqualToRect(CGRectZero, beginKeyboardFrame) || - CGRectEqualToRect(CGRectZero, endKeyboardFrame); - - bool keyboardIsPartiallyOnScreen = - IntersectsButDoesNotInclude(screenBounds, beginKeyboardFrame) || - IntersectsButDoesNotInclude(screenBounds, endKeyboardFrame); - - bool isInHarwareKeyboardMode = - !hasCGRectZeroFrames && keyboardIsPartiallyOnScreen; - - UMA_HISTOGRAM_BOOLEAN("Omnibox.HardwareKeyboardModeEnabled", - isInHarwareKeyboardMode); -} - -@end
diff --git a/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher_unittest.mm b/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher_unittest.mm deleted file mode 100644 index a6a87a1..0000000 --- a/ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher_unittest.mm +++ /dev/null
@@ -1,122 +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. - -#import "ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.h" - -#include "base/mac/scoped_nsobject.h" -#include "base/test/histogram_tester.h" -#include "testing/gtest/include/gtest/gtest.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 - -namespace { - -void PostKeyboardWillChangeNotification(CGRect beginFrame, CGRect endFrame) { - [[NSNotificationCenter defaultCenter] - postNotificationName:UIKeyboardWillChangeFrameNotification - object:nil - userInfo:@{ - UIKeyboardFrameBeginUserInfoKey : - [NSValue valueWithCGRect:beginFrame], - UIKeyboardFrameEndUserInfoKey : - [NSValue valueWithCGRect:endFrame], - }]; -} - -typedef PlatformTest HardwareKeyboardWatcherTest; - -TEST_F(HardwareKeyboardWatcherTest, AccessoryViewNotInHierarchy_NoHistogram) { - base::HistogramTester histogram_tester; - id mockView = [OCMockObject niceMockForClass:[UIView class]]; - [[mockView stub] andReturn:nil]; - base::scoped_nsobject<HardwareKeyboardWatcher> watcher( - [[HardwareKeyboardWatcher alloc] initWithAccessoryView:mockView]); - - PostKeyboardWillChangeNotification(CGRectZero, CGRectZero); - PostKeyboardWillChangeNotification(CGRectInfinite, CGRectInfinite); - - histogram_tester.ExpectTotalCount("Omnibox.HardwareKeyboardModeEnabled", 0); -} - -TEST_F(HardwareKeyboardWatcherTest, EmptyBeginFrame_SoftwareKeyboardHistogram) { - base::HistogramTester histogram_tester; - id mockView = [OCMockObject niceMockForClass:[UIView class]]; - [[[mockView stub] andReturn:[[UIApplication sharedApplication] keyWindow]] - window]; - base::scoped_nsobject<HardwareKeyboardWatcher> watcher( - [[HardwareKeyboardWatcher alloc] initWithAccessoryView:mockView]); - - PostKeyboardWillChangeNotification(CGRectZero, CGRectInfinite); - - histogram_tester.ExpectUniqueSample("Omnibox.HardwareKeyboardModeEnabled", - false, 1); -} - -TEST_F(HardwareKeyboardWatcherTest, EmptyEndFrame_SoftwareKeyboardHistogram) { - base::HistogramTester histogram_tester; - id mockView = [OCMockObject niceMockForClass:[UIView class]]; - [[[mockView stub] andReturn:[[UIApplication sharedApplication] keyWindow]] - window]; - base::scoped_nsobject<HardwareKeyboardWatcher> watcher( - [[HardwareKeyboardWatcher alloc] initWithAccessoryView:mockView]); - - PostKeyboardWillChangeNotification(CGRectInfinite, CGRectZero); - - histogram_tester.ExpectUniqueSample("Omnibox.HardwareKeyboardModeEnabled", - false, 1); -} - -TEST_F(HardwareKeyboardWatcherTest, - KeyboardFullyOnScreen_SoftwareKeyboardHistogram) { - base::HistogramTester histogram_tester; - id mockView = [OCMockObject niceMockForClass:[UIView class]]; - [[[mockView stub] andReturn:[[UIApplication sharedApplication] keyWindow]] - window]; - base::scoped_nsobject<HardwareKeyboardWatcher> watcher( - [[HardwareKeyboardWatcher alloc] initWithAccessoryView:mockView]); - - PostKeyboardWillChangeNotification(CGRectMake(0, 0, 100, 100), - CGRectMake(0, 100, 100, 100)); - - histogram_tester.ExpectUniqueSample("Omnibox.HardwareKeyboardModeEnabled", - false, 1); -} - -TEST_F(HardwareKeyboardWatcherTest, - KeyboardFullyOffScreen_SoftwareKeyboardHistogram) { - base::HistogramTester histogram_tester; - id mockView = [OCMockObject niceMockForClass:[UIView class]]; - [[[mockView stub] andReturn:[[UIApplication sharedApplication] keyWindow]] - window]; - base::scoped_nsobject<HardwareKeyboardWatcher> watcher( - [[HardwareKeyboardWatcher alloc] initWithAccessoryView:mockView]); - - PostKeyboardWillChangeNotification(CGRectMake(0, -100, 100, 100), - CGRectMake(0, 0, 100, 100)); - - histogram_tester.ExpectUniqueSample("Omnibox.HardwareKeyboardModeEnabled", - false, 1); -} - -TEST_F(HardwareKeyboardWatcherTest, - KeyboardPartiallyOnScreen_SoftwareKeyboardHistogram) { - base::HistogramTester histogram_tester; - id mockView = [OCMockObject niceMockForClass:[UIView class]]; - [[[mockView stub] andReturn:[[UIApplication sharedApplication] keyWindow]] - window]; - base::scoped_nsobject<HardwareKeyboardWatcher> watcher( - [[HardwareKeyboardWatcher alloc] initWithAccessoryView:mockView]); - - PostKeyboardWillChangeNotification(CGRectMake(0, -50, 100, 100), - CGRectMake(0, 0, 100, 100)); - - histogram_tester.ExpectUniqueSample("Omnibox.HardwareKeyboardModeEnabled", - true, 1); -} - -} // namespace
diff --git a/ios/chrome/browser/ui/omnibox/location_bar_controller_impl.mm b/ios/chrome/browser/ui/omnibox/location_bar_controller_impl.mm index 73ae2e6..8e4da991 100644 --- a/ios/chrome/browser/ui/omnibox/location_bar_controller_impl.mm +++ b/ios/chrome/browser/ui/omnibox/location_bar_controller_impl.mm
@@ -193,7 +193,6 @@ } } UpdateRightDecorations(); - [delegate_ locationBarChanged]; NSString* placeholderText = show_hint_text_ ? l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT) : nil;
diff --git a/ios/chrome/browser/ui/payments/contact_info_selection_coordinator.mm b/ios/chrome/browser/ui/payments/contact_info_selection_coordinator.mm index 9e3fab3b..e73228e 100644 --- a/ios/chrome/browser/ui/payments/contact_info_selection_coordinator.mm +++ b/ios/chrome/browser/ui/payments/contact_info_selection_coordinator.mm
@@ -10,6 +10,8 @@ #include "components/strings/grit/components_strings.h" #include "ios/chrome/browser/payments/payment_request.h" #import "ios/chrome/browser/payments/payment_request_util.h" +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#import "ios/chrome/browser/ui/payments/cells/payments_is_selectable.h" #include "ios/chrome/browser/ui/payments/contact_info_selection_mediator.h" #include "ios/chrome/browser/ui/payments/payment_request_selector_view_controller.h" #include "ui/base/l10n/l10n_util.h" @@ -86,13 +88,24 @@ - (BOOL)paymentRequestSelectorViewController: (PaymentRequestSelectorViewController*)controller didSelectItemAtIndex:(NSUInteger)index { - // Update the data source with the selection. - self.mediator.selectedItemIndex = index; + CollectionViewItem<PaymentsIsSelectable>* selectedItem = + self.mediator.selectableItems[index]; DCHECK(index < self.paymentRequest->contact_profiles().size()); - [self delayedNotifyDelegateOfSelection:self.paymentRequest - ->contact_profiles()[index]]; - return YES; + autofill::AutofillProfile* selectedProfile = + self.paymentRequest->contact_profiles()[index]; + + // Proceed with item selection only if the item has all required info, or + // else bring up the contact info editor. + if (selectedItem.complete) { + // Update the data source with the selection. + self.mediator.selectedItemIndex = index; + [self delayedNotifyDelegateOfSelection:selectedProfile]; + return YES; + } else { + [self startContactInfoEditCoordinatorWithProfile:selectedProfile]; + return NO; + } } - (void)paymentRequestSelectorViewControllerDidFinish: @@ -126,6 +139,25 @@ // Update the data source with the new data. [self.mediator loadItems]; + const std::vector<autofill::AutofillProfile*>& contactProfiles = + self.paymentRequest->contact_profiles(); + const auto position = + std::find(contactProfiles.begin(), contactProfiles.end(), profile); + DCHECK(position != contactProfiles.end()); + + const size_t index = position - contactProfiles.begin(); + + // Mark the edited item as complete meaning all required information has been + // filled out. + CollectionViewItem<PaymentsIsSelectable>* editedItem = + self.mediator.selectableItems[index]; + editedItem.complete = YES; + + if (![self.viewController isEditing]) { + // Update the data source with the selection. + self.mediator.selectedItemIndex = index; + } + [self.viewController loadModel]; [self.viewController.collectionView reloadData];
diff --git a/ios/chrome/browser/ui/payments/contact_info_selection_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/contact_info_selection_coordinator_unittest.mm index ca6627e..9aff5c258 100644 --- a/ios/chrome/browser/ui/payments/contact_info_selection_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/payments/contact_info_selection_coordinator_unittest.mm
@@ -26,11 +26,16 @@ #error "This file requires ARC support." #endif +namespace { +const int kCompleteProfileIndex = 0; +const int kIncompleteProfileIndex = 1; +} // namespace + class PaymentRequestContactInfoSelectionCoordinatorTest : public PlatformTest { protected: PaymentRequestContactInfoSelectionCoordinatorTest() : autofill_profile_1_(autofill::test::GetFullProfile()), - autofill_profile_2_(autofill::test::GetFullProfile2()), + autofill_profile_2_(autofill::test::GetIncompleteProfile2()), chrome_browser_state_(TestChromeBrowserState::Builder().Build()) { // Add testing profiles to autofill::TestPersonalDataManager. personal_data_manager_.AddTestingProfile(&autofill_profile_1_); @@ -99,9 +104,14 @@ // Mock the coordinator delegate. id delegate = [OCMockObject mockForProtocol:@protocol(ContactInfoSelectionCoordinatorDelegate)]; - autofill::AutofillProfile* profile = payment_request_->contact_profiles()[1]; - [[delegate expect] contactInfoSelectionCoordinator:coordinator - didSelectContactProfile:profile]; + [[delegate expect] + contactInfoSelectionCoordinator:coordinator + didSelectContactProfile:payment_request_->contact_profiles() + [kCompleteProfileIndex]]; + [[delegate reject] + contactInfoSelectionCoordinator:coordinator + didSelectContactProfile:payment_request_->contact_profiles() + [kIncompleteProfileIndex]]; [coordinator setDelegate:delegate]; EXPECT_EQ(1u, navigation_controller.viewControllers.count); @@ -115,11 +125,15 @@ PaymentRequestSelectorViewController* view_controller = base::mac::ObjCCastStrict<PaymentRequestSelectorViewController>( navigation_controller.visibleViewController); - EXPECT_TRUE([coordinator paymentRequestSelectorViewController:view_controller - didSelectItemAtIndex:1]); + EXPECT_TRUE([coordinator + paymentRequestSelectorViewController:view_controller + didSelectItemAtIndex:kCompleteProfileIndex]); // Wait for the coordinator delegate to be notified. base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.5)); + EXPECT_FALSE([coordinator + paymentRequestSelectorViewController:view_controller + didSelectItemAtIndex:kIncompleteProfileIndex]); EXPECT_OCMOCK_VERIFY(delegate); }
diff --git a/ios/chrome/browser/ui/payments/contact_info_selection_mediator.mm b/ios/chrome/browser/ui/payments/contact_info_selection_mediator.mm index a0394d32..2e30016 100644 --- a/ios/chrome/browser/ui/payments/contact_info_selection_mediator.mm +++ b/ios/chrome/browser/ui/payments/contact_info_selection_mediator.mm
@@ -8,6 +8,7 @@ #include "base/logging.h" #include "components/autofill/core/browser/autofill_profile.h" +#include "components/payments/core/payments_profile_comparator.h" #include "components/strings/grit/components_strings.h" #include "ios/chrome/browser/payments/payment_request.h" #import "ios/chrome/browser/payments/payment_request_util.h" @@ -101,6 +102,12 @@ item.phoneNumber = GetPhoneNumberLabelFromAutofillProfile(*contactProfile); } + item.notification = + payment_request_util::GetContactNotificationLabelFromAutofillProfile( + *_paymentRequest, *contactProfile); + item.complete = + _paymentRequest->profile_comparator()->IsContactInfoComplete( + contactProfile); if (_paymentRequest->selected_contact_profile() == contactProfile) _selectedItemIndex = index;
diff --git a/ios/chrome/browser/ui/payments/contact_info_selection_mediator_unittest.mm b/ios/chrome/browser/ui/payments/contact_info_selection_mediator_unittest.mm index 8105cfa..e1c3bc9 100644 --- a/ios/chrome/browser/ui/payments/contact_info_selection_mediator_unittest.mm +++ b/ios/chrome/browser/ui/payments/contact_info_selection_mediator_unittest.mm
@@ -6,6 +6,7 @@ #include "base/mac/foundation_util.h" #include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/scoped_task_environment.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" @@ -28,6 +29,7 @@ using ::payment_request_util::GetNameLabelFromAutofillProfile; using ::payment_request_util::GetEmailLabelFromAutofillProfile; using ::payment_request_util::GetPhoneNumberLabelFromAutofillProfile; +using ::payment_request_util::GetContactNotificationLabelFromAutofillProfile; } // namespace class PaymentRequestContactInfoSelectionMediatorTest : public PlatformTest { @@ -35,14 +37,24 @@ PaymentRequestContactInfoSelectionMediatorTest() : autofill_profile_1_(autofill::test::GetFullProfile()), autofill_profile_2_(autofill::test::GetFullProfile2()), + autofill_profile_3_(autofill::test::GetFullProfile()), chrome_browser_state_(TestChromeBrowserState::Builder().Build()) { + // Change the name of the third profile (to avoid deduplication), and make + // it incomplete by removing the phone number. + autofill_profile_3_.SetInfo(autofill::AutofillType(autofill::NAME_FULL), + base::ASCIIToUTF16("Richard Roe"), "en-US"); + autofill_profile_3_.SetInfo( + autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), + base::string16(), "en-US"); + // Add testing profiles to autofill::TestPersonalDataManager. personal_data_manager_.AddTestingProfile(&autofill_profile_1_); personal_data_manager_.AddTestingProfile(&autofill_profile_2_); - + personal_data_manager_.AddTestingProfile(&autofill_profile_3_); payment_request_ = base::MakeUnique<payments::TestPaymentRequest>( payment_request_test_util::CreateTestWebPaymentRequest(), chrome_browser_state_.get(), &web_state_, &personal_data_manager_); + // Override the selected contact profile. payment_request_->set_selected_contact_profile( payment_request_->contact_profiles()[1]); @@ -61,6 +73,7 @@ autofill::AutofillProfile autofill_profile_1_; autofill::AutofillProfile autofill_profile_2_; + autofill::AutofillProfile autofill_profile_3_; web::TestWebState web_state_; autofill::TestPersonalDataManager personal_data_manager_; std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; @@ -73,8 +86,8 @@ NSArray<CollectionViewItem*>* selectable_items = [GetMediator() selectableItems]; - // There must be two selectable items. - ASSERT_EQ(2U, selectable_items.count); + // There must be three selectable items. + ASSERT_EQ(3U, selectable_items.count); // The second item must be selected. EXPECT_EQ(1U, GetMediator().selectedItemIndex); @@ -110,6 +123,23 @@ *payment_request_->contact_profiles()[1])]); EXPECT_EQ(nil, profile_item_2.address); EXPECT_EQ(nil, profile_item_2.notification); + + CollectionViewItem* item_3 = [selectable_items objectAtIndex:2]; + DCHECK([item_3 isKindOfClass:[AutofillProfileItem class]]); + AutofillProfileItem* profile_item_3 = + base::mac::ObjCCastStrict<AutofillProfileItem>(item_3); + EXPECT_TRUE([profile_item_3.name + isEqualToString:GetNameLabelFromAutofillProfile( + *payment_request_->contact_profiles()[2])]); + EXPECT_TRUE([profile_item_3.email + isEqualToString:GetEmailLabelFromAutofillProfile( + *payment_request_->contact_profiles()[2])]); + EXPECT_EQ(nil, profile_item_3.phoneNumber); + EXPECT_EQ(nil, profile_item_3.address); + EXPECT_TRUE([profile_item_3.notification + isEqualToString:GetContactNotificationLabelFromAutofillProfile( + *payment_request_.get(), + *payment_request_->contact_profiles()[2])]); } // Tests that the index of the selected item is as expected when there is no @@ -123,8 +153,8 @@ NSArray<CollectionViewItem*>* selectable_items = [GetMediator() selectableItems]; - // There must be two selectable items. - ASSERT_EQ(2U, selectable_items.count); + // There must be three selectable items. + ASSERT_EQ(3U, selectable_items.count); // The selected item index must be invalid. EXPECT_EQ(NSUIntegerMax, GetMediator().selectedItemIndex); @@ -149,6 +179,14 @@ EXPECT_EQ(nil, profile_item.address); EXPECT_EQ(nil, profile_item.notification); + // Incomplete item should display a notification since the phone number is + // missing. + CollectionViewItem* incomplete_item = [selectable_items objectAtIndex:2]; + DCHECK([incomplete_item isKindOfClass:[AutofillProfileItem class]]); + AutofillProfileItem* incomplete_profile_item = + base::mac::ObjCCastStrict<AutofillProfileItem>(incomplete_item); + EXPECT_NE(nil, incomplete_profile_item.notification); + // Update the web_payment_request and reload the items. payment_request_->web_payment_request().options.request_payer_email = false; [GetMediator() loadItems]; @@ -180,4 +218,12 @@ EXPECT_EQ(nil, profile_item.phoneNumber); EXPECT_EQ(nil, profile_item.address); EXPECT_EQ(nil, profile_item.notification); + + // Incomplete item should not display a notification, since the phone number + // is not requested. + incomplete_item = [selectable_items objectAtIndex:2]; + DCHECK([incomplete_item isKindOfClass:[AutofillProfileItem class]]); + profile_item = + base::mac::ObjCCastStrict<AutofillProfileItem>(incomplete_item); + EXPECT_EQ(nil, profile_item.notification); }
diff --git a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm index 555818db..64c58c9 100644 --- a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm +++ b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
@@ -51,6 +51,7 @@ using chrome_test_util::ButtonWithAccessibilityLabelId; using chrome_test_util::NavigationBarDoneButton; using chrome_test_util::SettingsMenuButton; +using chrome_test_util::SettingsMenuBackButton; namespace { @@ -365,16 +366,6 @@ performAction:grey_tap()]; } -// Tap back arrow, to get one level higher in settings. -- (void)tapBackArrow { - [[EarlGrey - selectElementWithMatcher:grey_allOf( - grey_accessibilityID(@"ic_arrow_back"), - grey_accessibilityTrait( - UIAccessibilityTraitButton), - nil)] performAction:grey_tap()]; -} - // Tap Edit in any settings view. - (void)tapEdit { [[EarlGrey selectElementWithMatcher:EditButton()] performAction:grey_tap()]; @@ -409,9 +400,11 @@ selectElementWithMatcher:Entry(@"https://example.com, concrete username")] performAction:grey_tap()]; chrome_test_util::VerifyAccessibilityForCurrentScreen(); - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -463,8 +456,10 @@ [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)] performAction:grey_tap()]; - [self tapBackArrow]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -496,8 +491,10 @@ [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)] performAction:grey_tap()]; - [self tapBackArrow]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -529,8 +526,10 @@ [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)] performAction:grey_tap()]; - [self tapBackArrow]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -580,7 +579,8 @@ selectElementWithMatcher:Entry(@"https://example.com, concrete username")] assertWithMatcher:grey_not(grey_sufficientlyVisible())]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -623,12 +623,14 @@ // Go back to the list view and verify that the password is still in the // list. - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [[EarlGrey selectElementWithMatcher:Entry(@"https://example.com, concrete username")] assertWithMatcher:grey_sufficientlyVisible()]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -654,7 +656,8 @@ [[EarlGrey selectElementWithMatcher:CopyPasswordButton()] assertWithMatcher:grey_nil()]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -691,8 +694,10 @@ [[EarlGrey selectElementWithMatcher:PasswordHeader()] assertWithMatcher:grey_nil()]; - [self tapBackArrow]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -732,8 +737,10 @@ [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)] performAction:grey_tap()]; - [self tapBackArrow]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -774,8 +781,10 @@ [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)] performAction:grey_tap()]; - [self tapBackArrow]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -823,8 +832,10 @@ [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)] performAction:grey_tap()]; - [self tapBackArrow]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -890,8 +901,10 @@ @"PasswordDetailsCollectionViewController")] assertWithMatcher:grey_sufficientlyVisible()]; - [self tapBackArrow]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; } @@ -956,8 +969,10 @@ [[EarlGrey selectElementWithMatcher:PasswordHeader()] assertWithMatcher:grey_nil()]; - [self tapBackArrow]; - [self tapBackArrow]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()] + performAction:grey_tap()]; [self tapDone]; [self clearPasswordStore]; }
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm index b38d68c..d34eb1c 100644 --- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
@@ -22,6 +22,7 @@ #include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/prefs/pref_member.h" #include "components/prefs/pref_service.h" +#include "components/strings/grit/components_strings.h" #include "components/url_formatter/url_formatter.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -208,7 +209,7 @@ CollectionViewTextItem* headerItem = [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader]; headerItem.text = - l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_SAVED_HEADING); + l10n_util::GetNSString(IDS_PASSWORD_MANAGER_SHOW_PASSWORDS_TAB_TITLE); headerItem.textColor = [[MDCPalette greyPalette] tint500]; [model setHeader:headerItem forSectionWithIdentifier:SectionIdentifierSavedPasswords]; @@ -222,7 +223,7 @@ CollectionViewTextItem* headerItem = [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader]; headerItem.text = - l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORDS_EXCEPTIONS_HEADING); + l10n_util::GetNSString(IDS_PASSWORD_MANAGER_EXCEPTIONS_TAB_TITLE); headerItem.textColor = [[MDCPalette greyPalette] tint500]; [model setHeader:headerItem forSectionWithIdentifier:SectionIdentifierBlacklist];
diff --git a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm index 318c8c49..2eb11dac 100644 --- a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
@@ -292,14 +292,6 @@ - (void)dealloc { [self stopBrowserStateServiceObservers]; - if (!_signinStarted && _signinPromoViewMediator) { - PrefService* prefs = _browserState->GetPrefs(); - int displayedCount = - prefs->GetInteger(prefs::kIosSettingsSigninPromoDisplayedCount); - UMA_HISTOGRAM_COUNTS_100( - "MobileSignInPromo.SettingsManager.ImpressionsTilDismiss", - displayedCount); - } } - (void)stopBrowserStateServiceObservers { @@ -1034,6 +1026,14 @@ #pragma mark SettingsControllerProtocol - (void)settingsWillBeDismissed { + if (!_signinStarted && _signinPromoViewMediator) { + PrefService* prefs = _browserState->GetPrefs(); + int displayedCount = + prefs->GetInteger(prefs::kIosSettingsSigninPromoDisplayedCount); + UMA_HISTOGRAM_COUNTS_100( + "MobileSignInPromo.SettingsManager.ImpressionsTilDismiss", + displayedCount); + } [_signinInteractionController cancel]; [self stopBrowserStateServiceObservers]; }
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn index 972beb4..f9b3f80 100644 --- a/ios/chrome/browser/ui/toolbar/BUILD.gn +++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -5,9 +5,7 @@ source_set("toolbar") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "keyboard_accessory_view.h", - "keyboard_accessory_view.mm", - "keyboard_accessory_view_protocol.h", + "keyboard_accessory_view_delegate.h", "new_keyboard_accessory_view.h", "new_keyboard_accessory_view.mm", "new_tab_button.h",
diff --git a/ios/chrome/browser/ui/toolbar/keyboard_accessory_view.h b/ios/chrome/browser/ui/toolbar/keyboard_accessory_view.h deleted file mode 100644 index d6510d1..0000000 --- a/ios/chrome/browser/ui/toolbar/keyboard_accessory_view.h +++ /dev/null
@@ -1,33 +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_TOOLBAR_KEYBOARD_ACCESSORY_VIEW_H_ -#define IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ACCESSORY_VIEW_H_ - -#import <UIKit/UIKIt.h> - -#import "ios/chrome/browser/ui/toolbar/keyboard_accessory_view_protocol.h" - -// Accessory View above the keyboard. -// Supports two modes: one where a Voice Search button is shown, and one where -// a list of buttons based on |buttonTitles| is shown. -// The default mode is the Voice Search mode. -@interface KeyboardAccessoryView - : UIInputView<KeyboardAccessoryViewProtocol, UIInputViewAudioFeedback> - -// Designated initializer. |buttonTitles| lists the titles of the buttons shown -// in the KEY_SHORTCUTS mode. Can be nil or empty. |delegate| receives the -// various events triggered in the view. Not retained, and can be nil. -- (instancetype)initWithButtons:(NSArray<NSString*>*)buttonTitles - delegate:(id<KeyboardAccessoryViewDelegate>)delegate - NS_DESIGNATED_INITIALIZER; - -- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; - -- (instancetype)initWithFrame:(CGRect)frame - inputViewStyle:(UIInputViewStyle)inputViewStyle NS_UNAVAILABLE; - -@end - -#endif // IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ACCESSORY_VIEW_H_
diff --git a/ios/chrome/browser/ui/toolbar/keyboard_accessory_view.mm b/ios/chrome/browser/ui/toolbar/keyboard_accessory_view.mm deleted file mode 100644 index 23221892..0000000 --- a/ios/chrome/browser/ui/toolbar/keyboard_accessory_view.mm +++ /dev/null
@@ -1,165 +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/toolbar/keyboard_accessory_view.h" - -#include "base/mac/foundation_util.h" -#include "ios/chrome/browser/ui/commands/ios_command_ids.h" -#include "ios/chrome/browser/ui/ui_util.h" -#import "ios/chrome/browser/ui/uikit_ui_util.h" -#include "ios/chrome/grit/ios_strings.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface KeyboardAccessoryView () - -@property(nonatomic, weak) id<KeyboardAccessoryViewDelegate> delegate; -@property(nonatomic, retain) UIButton* voiceSearchButton; - -// Creates a button with the same appearance as a keyboard key. -- (UIView*)keyboardButtonWithTitle:(NSString*)title frame:(CGRect)frame; -// Called when a keyboard shortcut button is pressed. -- (void)keyboardButtonPressed:(NSString*)title; - -@end - -@implementation KeyboardAccessoryView - -@synthesize mode = _mode; -@synthesize delegate = _delegate; -@synthesize voiceSearchButton = _voiceSearchButton; - -- (instancetype)initWithButtons:(NSArray<NSString*>*)buttonTitles - delegate:(id<KeyboardAccessoryViewDelegate>)delegate { - const CGFloat kViewHeight = 70.0; - const CGFloat kViewHeightCompact = 43.0; - const CGFloat kButtonInset = 5.0; - const CGFloat kButtonSizeX = 61.0; - const CGFloat kButtonSizeXCompact = 46.0; - const CGFloat kButtonSizeY = 62.0; - const CGFloat kButtonSizeYCompact = 35.0; - const CGFloat kBetweenButtonSpacing = 15.0; - const CGFloat kBetweenButtonSpacingCompact = 7.0; - const BOOL isCompact = IsCompact(); - - CGFloat width = [[UIScreen mainScreen] bounds].size.width; - CGFloat height = isCompact ? kViewHeightCompact : kViewHeight; - CGRect frame = CGRectMake(0.0, 0.0, width, height); - - self = [super initWithFrame:frame inputViewStyle:UIInputViewStyleKeyboard]; - if (self) { - _delegate = delegate; - - // Center buttons in available space by placing them within a parent view - // that auto-centers. - CGFloat betweenButtonSpacing = - isCompact ? kBetweenButtonSpacingCompact : kBetweenButtonSpacing; - const CGFloat buttonWidth = isCompact ? kButtonSizeXCompact : kButtonSizeX; - - CGFloat totalWidth = (buttonTitles.count * buttonWidth) + - ((buttonTitles.count - 1) * betweenButtonSpacing); - CGFloat indent = floor((width - totalWidth) / 2.0); - if (indent < kButtonInset) - indent = kButtonInset; - CGRect parentViewRect = CGRectMake(indent, 0.0, totalWidth, height); - UIView* parentView = [[UIView alloc] initWithFrame:parentViewRect]; - [parentView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | - UIViewAutoresizingFlexibleRightMargin]; - [self addSubview:parentView]; - - // Create the shortcut buttons, starting at the left edge of |parentView|. - CGRect currentFrame = - CGRectMake(0.0, kButtonInset, buttonWidth, - isCompact ? kButtonSizeYCompact : kButtonSizeY); - - for (NSString* title in buttonTitles) { - UIView* button = [self keyboardButtonWithTitle:title frame:currentFrame]; - [parentView addSubview:button]; - currentFrame.origin.x = - CGRectGetMaxX(currentFrame) + betweenButtonSpacing; - } - - // Create the voice search button and add it over the text buttons. - _voiceSearchButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [_voiceSearchButton setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; - SetA11yLabelAndUiAutomationName( - _voiceSearchButton, IDS_IOS_ACCNAME_VOICE_SEARCH, @"Voice Search"); - UIImage* voiceRow = [UIImage imageNamed:@"custom_row_voice"]; - UIImage* voiceRowPressed = [UIImage imageNamed:@"custom_row_voice_pressed"]; - [_voiceSearchButton setBackgroundImage:voiceRow - forState:UIControlStateNormal]; - [_voiceSearchButton setBackgroundImage:voiceRowPressed - forState:UIControlStateHighlighted]; - - UIImage* voiceIcon = [UIImage imageNamed:@"voice_icon_keyboard_accessory"]; - [_voiceSearchButton setAdjustsImageWhenHighlighted:NO]; - [_voiceSearchButton setImage:voiceIcon forState:UIControlStateNormal]; - [_voiceSearchButton setFrame:[self bounds]]; - - [_voiceSearchButton - addTarget:delegate - action:@selector(keyboardAccessoryVoiceSearchTouchDown) - forControlEvents:UIControlEventTouchDown]; - [_voiceSearchButton - addTarget:delegate - action:@selector(keyboardAccessoryVoiceSearchTouchUpInside) - forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_voiceSearchButton]; - } - - return self; -} - -- (void)setMode:(KeyboardAccessoryViewMode)mode { - _mode = mode; - switch (mode) { - case VOICE_SEARCH: - [_voiceSearchButton setHidden:NO]; - break; - case KEY_SHORTCUTS: - [_voiceSearchButton setHidden:YES]; - break; - } -} - -- (UIView*)keyboardButtonWithTitle:(NSString*)title frame:(CGRect)frame { - const CGFloat kIpadButtonTitleFontSize = 20.0; - const CGFloat kIphoneButtonTitleFontSize = 15.0; - - UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom]; - UIFont* font = nil; - UIImage* backgroundImage = nil; - if (IsIPadIdiom()) { - font = GetUIFont(FONT_HELVETICA, false, kIpadButtonTitleFontSize); - } else { - font = GetUIFont(FONT_HELVETICA, true, kIphoneButtonTitleFontSize); - } - backgroundImage = [UIImage imageNamed:@"keyboard_button"]; - - button.frame = frame; - [button setTitle:title forState:UIControlStateNormal]; - [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; - [button.titleLabel setFont:font]; - [button setBackgroundImage:backgroundImage forState:UIControlStateNormal]; - [button addTarget:self - action:@selector(keyboardButtonPressed:) - forControlEvents:UIControlEventTouchUpInside]; - button.isAccessibilityElement = YES; - [button setAccessibilityLabel:title]; - return button; -} - -- (BOOL)enableInputClicksWhenVisible { - return YES; -} - -- (void)keyboardButtonPressed:(id)sender { - UIButton* button = base::mac::ObjCCastStrict<UIButton>(sender); - [[UIDevice currentDevice] playInputClick]; - [_delegate keyPressed:[button currentTitle]]; -} - -@end
diff --git a/ios/chrome/browser/ui/toolbar/keyboard_accessory_view_delegate.h b/ios/chrome/browser/ui/toolbar/keyboard_accessory_view_delegate.h new file mode 100644 index 0000000..426be79 --- /dev/null +++ b/ios/chrome/browser/ui/toolbar/keyboard_accessory_view_delegate.h
@@ -0,0 +1,28 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ACCESSORY_VIEW_DELEGATE_H_ +#define IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ACCESSORY_VIEW_DELEGATE_H_ + +#import <UIKit/UIKIt.h> + +// Delegate protocol for the KeyboardAccessoryView. +@protocol KeyboardAccessoryViewDelegate + +// Notifies the delegate that the Voice Search button was pressed. +- (void)keyboardAccessoryVoiceSearchTouchDown:(UIView*)view; + +// Notifies the delegate that a touch up occured in the the Voice Search button. +- (void)keyboardAccessoryVoiceSearchTouchUpInside:(UIView*)view; + +// Notifies the delegate that a touch up occured in the the Camera Search +// button. +- (void)keyboardAccessoryCameraSearchTouchUpInside:(UIView*)view; + +// Notifies the delegate that a key with the title |title| was pressed. +- (void)keyPressed:(NSString*)title; + +@end + +#endif // IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ACCESSORY_VIEW_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/toolbar/keyboard_accessory_view_protocol.h b/ios/chrome/browser/ui/toolbar/keyboard_accessory_view_protocol.h deleted file mode 100644 index cca0c48b..0000000 --- a/ios/chrome/browser/ui/toolbar/keyboard_accessory_view_protocol.h +++ /dev/null
@@ -1,41 +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_TOOLBAR_KEYBOARD_ACCESSORY_VIEW_PROTOCOL_H_ -#define IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ACCESSORY_VIEW_PROTOCOL_H_ - -#import <UIKit/UIKIt.h> - -// Delegate protocol for the KeyboardAccessoryView. -@protocol KeyboardAccessoryViewDelegate - -// Notifies the delegate that the Voice Search button was pressed. -- (void)keyboardAccessoryVoiceSearchTouchDown; - -// Notifies the delegate that a touch up occured in the the Voice Search button. -- (void)keyboardAccessoryVoiceSearchTouchUpInside; - -// Notifies the delegate that a touch up occured in the the Camera Search -// button. -- (void)keyboardAccessoryCameraSearchTouchUpInside; - -// Notifies the delegate that a key with the title |title| was pressed. -- (void)keyPressed:(NSString*)title; - -@end - -typedef NS_ENUM(NSInteger, KeyboardAccessoryViewMode) { - VOICE_SEARCH = 0, - KEY_SHORTCUTS -}; - -// Protocol the keyboard accessory views must implement. -@protocol KeyboardAccessoryViewProtocol - -// The mode in which the KeyboardAccessoryView is in. -@property(nonatomic) KeyboardAccessoryViewMode mode; - -@end - -#endif // IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ACCESSORY_VIEW_PROTOCOL_H_
diff --git a/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.h b/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.h index 136bda0..242b6ff 100644 --- a/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.h +++ b/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.h
@@ -7,13 +7,12 @@ #import <UIKit/UIKIt.h> -#import "ios/chrome/browser/ui/toolbar/keyboard_accessory_view_protocol.h" +#import "ios/chrome/browser/ui/toolbar/keyboard_accessory_view_delegate.h" // Accessory View above the keyboard. // Shows keys that are shortcuts to commonly used characters or strings, // and buttons to start Voice Search or a Camera Search. -@interface NewKeyboardAccessoryView - : UIInputView<KeyboardAccessoryViewProtocol, UIInputViewAudioFeedback> +@interface NewKeyboardAccessoryView : UIInputView<UIInputViewAudioFeedback> // Designated initializer. |buttonTitles| lists the titles of the shortcut // buttons. |delegate| receives the various events triggered in the view. Not
diff --git a/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.mm b/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.mm index a87cfa0..8e5a007d 100644 --- a/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.mm +++ b/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.mm
@@ -34,9 +34,6 @@ @implementation NewKeyboardAccessoryView -// Unused by this implementation of |KeyboardAccessoryViewProtocol|. -@synthesize mode = _mode; - @synthesize buttonTitles = _buttonTitles; @synthesize delegate = _delegate; @@ -84,18 +81,18 @@ UIButton* voiceSearchButton = [self iconButton:@"keyboard_accessory_voice_search"]; [voiceSearchButton addTarget:_delegate - action:@selector(keyboardAccessoryVoiceSearchTouchDown) + action:@selector(keyboardAccessoryVoiceSearchTouchDown:) forControlEvents:UIControlEventTouchDown]; SetA11yLabelAndUiAutomationName(voiceSearchButton, IDS_IOS_KEYBOARD_ACCESSORY_VIEW_VOICE_SEARCH, @"Voice Search"); [voiceSearchButton addTarget:_delegate - action:@selector(keyboardAccessoryVoiceSearchTouchUpInside) + action:@selector(keyboardAccessoryVoiceSearchTouchUpInside:) forControlEvents:UIControlEventTouchUpInside]; UIButton* cameraButton = [self iconButton:@"keyboard_accessory_qr_scanner"]; [cameraButton addTarget:_delegate - action:@selector(keyboardAccessoryCameraSearchTouchUpInside) + action:@selector(keyboardAccessoryCameraSearchTouchUpInside:) forControlEvents:UIControlEventTouchUpInside]; SetA11yLabelAndUiAutomationName( cameraButton, IDS_IOS_KEYBOARD_ACCESSORY_VIEW_QR_CODE_SEARCH,
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm index df0c80ef..b7debf0 100644 --- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm +++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -42,14 +42,12 @@ #include "ios/chrome/browser/ui/commands/ios_command_ids.h" #import "ios/chrome/browser/ui/history/tab_history_popup_controller.h" #import "ios/chrome/browser/ui/image_util.h" -#import "ios/chrome/browser/ui/keyboard/hardware_keyboard_watcher.h" #include "ios/chrome/browser/ui/omnibox/location_bar_controller_impl.h" #include "ios/chrome/browser/ui/omnibox/omnibox_view_ios.h" #import "ios/chrome/browser/ui/popup_menu/popup_menu_view.h" #import "ios/chrome/browser/ui/reversed_animation.h" #include "ios/chrome/browser/ui/rtl_geometry.h" -#import "ios/chrome/browser/ui/toolbar/keyboard_accessory_view.h" -#import "ios/chrome/browser/ui/toolbar/keyboard_accessory_view_protocol.h" +#import "ios/chrome/browser/ui/toolbar/keyboard_accessory_view_delegate.h" #import "ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.h" #import "ios/chrome/browser/ui/toolbar/toolbar_controller+protected.h" #import "ios/chrome/browser/ui/toolbar/toolbar_controller.h" @@ -246,7 +244,6 @@ UIButton* _voiceSearchButton; OmniboxTextFieldIOS* _omniBox; UIButton* _cancelButton; - UIView<KeyboardAccessoryViewProtocol>* _keyboardAccessoryView; // Progress bar used to show what fraction of the page has loaded. MDCProgressView* _determinateProgressView; UIImageView* _omniboxBackground; @@ -286,10 +283,6 @@ // back or forward button. nil if not visible. TabHistoryPopupController* _tabHistoryPopupController; - // Hardware keyboard watcher, to detect the type of keyboard currently - // attached. - HardwareKeyboardWatcher* _hardwareKeyboardWatcher; - // The current browser state. ios::ChromeBrowserState* _browserState; // weak } @@ -901,11 +894,6 @@ [_stopButton setHidden:isCompactTabletView]; [self updateToolbarState]; - // Update keyboard accessory views. - auto mode = _keyboardAccessoryView.mode; - _keyboardAccessoryView = nil; - [self configureAssistiveKeyboardViews]; - _keyboardAccessoryView.mode = mode; if ([_omniBox isFirstResponder]) { [_omniBox reloadInputViews]; } @@ -1288,8 +1276,6 @@ [self.delegate locationBarDidBecomeFirstResponder:self]; [self animateMaterialOmnibox]; - _keyboardAccessoryView.mode = VOICE_SEARCH; - // Record the appropriate user action for focusing the omnibox. web::WebState* webState = [self.delegate currentWebState]; if (webState) { @@ -1318,24 +1304,6 @@ [self.delegate locationBarBeganEdit:self]; } -- (void)locationBarChanged { - // Hide the voice search button once the user starts editing the omnibox but - // show it if the omnibox is empty. - bool isEditingOrEmpty = _locationBar->GetLocationEntry()->IsEditingOrEmpty(); - BOOL editingAndNotEmpty = isEditingOrEmpty && _omniBox.text.length != 0; - // If the voice search button is visible but about to be hidden (i.e. - // the omnibox is no longer empty) then this is the first omnibox text so - // record a user action. - if (_keyboardAccessoryView.mode == VOICE_SEARCH && editingAndNotEmpty) { - base::RecordAction(UserMetricsAction("MobileFirstTextInOmnibox")); - } - if (editingAndNotEmpty) { - _keyboardAccessoryView.mode = KEY_SHORTCUTS; - } else { - _keyboardAccessoryView.mode = VOICE_SEARCH; - } -} - - (web::WebState*)getWebState { return [self.delegate currentWebState]; } @@ -1487,31 +1455,29 @@ #pragma mark - #pragma mark KeyboardAccessoryViewDelegate -- (void)keyboardAccessoryVoiceSearchTouchDown { +- (void)keyboardAccessoryVoiceSearchTouchDown:(UIView*)view { if (ios::GetChromeBrowserProvider() ->GetVoiceSearchProvider() ->IsVoiceSearchEnabled()) { - [self preloadVoiceSearch:_keyboardAccessoryView]; + [self preloadVoiceSearch:view]; } } -- (void)keyboardAccessoryVoiceSearchTouchUpInside { +- (void)keyboardAccessoryVoiceSearchTouchUpInside:(UIView*)view { if (ios::GetChromeBrowserProvider() ->GetVoiceSearchProvider() ->IsVoiceSearchEnabled()) { base::RecordAction(UserMetricsAction("MobileCustomRowVoiceSearch")); GenericChromeCommand* command = [[GenericChromeCommand alloc] initWithTag:IDC_VOICE_SEARCH]; - [_keyboardAccessoryView chromeExecuteCommand:command]; - } else { - _keyboardAccessoryView.mode = KEY_SHORTCUTS; + [view chromeExecuteCommand:command]; } } -- (void)keyboardAccessoryCameraSearchTouchUpInside { +- (void)keyboardAccessoryCameraSearchTouchUpInside:(UIView*)view { GenericChromeCommand* command = [[GenericChromeCommand alloc] initWithTag:IDC_SHOW_QR_SCANNER]; - [_keyboardAccessoryView chromeExecuteCommand:command]; + [view chromeExecuteCommand:command]; } - (void)keyPressed:(NSString*)title { @@ -1875,37 +1841,19 @@ } - (UIView*)keyboardAccessoryView { - if (!_keyboardAccessoryView) { - if (experimental_flags::IsKeyboardAccessoryViewWithCameraSearchEnabled()) { - // The '.' shortcut is left out because the new keyboard accessory view - // has less free space for the shortcut buttons, and the '.' is already - // present in the standard iOS keyboard. - NSArray<NSString*>* buttonTitles = @[ @":", @"-", @"/", kDotComTLD ]; - _keyboardAccessoryView = - [[NewKeyboardAccessoryView alloc] initWithButtons:buttonTitles - delegate:self]; - } else { - NSArray<NSString*>* buttonTitles = - @[ @":", @".", @"-", @"/", kDotComTLD ]; - _keyboardAccessoryView = - [[KeyboardAccessoryView alloc] initWithButtons:buttonTitles - delegate:self]; - } - [_keyboardAccessoryView - setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; - _hardwareKeyboardWatcher = [[HardwareKeyboardWatcher alloc] - initWithAccessoryView:_keyboardAccessoryView]; - } - return _keyboardAccessoryView; + NSArray<NSString*>* buttonTitles = @[ @":", @"-", @"/", kDotComTLD ]; + UIView* keyboardAccessoryView = + [[NewKeyboardAccessoryView alloc] initWithButtons:buttonTitles + delegate:self]; + [keyboardAccessoryView setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; + return keyboardAccessoryView; } - (void)configureAssistiveKeyboardViews { - if (experimental_flags::IsKeyboardAccessoryViewWithCameraSearchEnabled()) { - // The InputAssistantItems are disabled when the new Keyboard Accessory View - // is enabled. - _omniBox.inputAssistantItem.leadingBarButtonGroups = @[]; - _omniBox.inputAssistantItem.trailingBarButtonGroups = @[]; - } + // The InputAssistantItems are disabled when the new Keyboard Accessory View + // is enabled. + _omniBox.inputAssistantItem.leadingBarButtonGroups = @[]; + _omniBox.inputAssistantItem.trailingBarButtonGroups = @[]; [_omniBox setInputAccessoryView:[self keyboardAccessoryView]]; }
diff --git a/ios/chrome/browser/web/chrome_web_client.h b/ios/chrome/browser/web/chrome_web_client.h index 7a34dbd..e0105d46 100644 --- a/ios/chrome/browser/web/chrome_web_client.h +++ b/ios/chrome/browser/web/chrome_web_client.h
@@ -44,8 +44,6 @@ const GURL& request_url, bool overridable, const base::Callback<void(bool)>& callback) override; - std::unique_ptr<base::TaskScheduler::InitParams> GetTaskSchedulerInitParams() - override; bool IsSlimNavigationManagerEnabled() const override; private:
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm index 92f5cbb..2bb53aec 100644 --- a/ios/chrome/browser/web/chrome_web_client.mm +++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -15,7 +15,6 @@ #include "components/payments/core/features.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" -#include "components/task_scheduler_util/browser/initialization.h" #include "components/version_info/version_info.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_about_rewriter.h" @@ -187,11 +186,6 @@ overridable, callback); } -std::unique_ptr<base::TaskScheduler::InitParams> -ChromeWebClient::GetTaskSchedulerInitParams() { - return task_scheduler_util::GetBrowserTaskSchedulerInitParamsFromVariations(); -} - bool ChromeWebClient::IsSlimNavigationManagerEnabled() const { return experimental_flags::IsSlimNavigationManagerEnabled(); }
diff --git a/ios/clean/DEPS b/ios/clean/DEPS new file mode 100644 index 0000000..b273ae3 --- /dev/null +++ b/ios/clean/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+ui/gfx", +]
diff --git a/ios/clean/chrome/browser/ui/omnibox/location_bar_mediator.mm b/ios/clean/chrome/browser/ui/omnibox/location_bar_mediator.mm index f9ca92d6..d02227b 100644 --- a/ios/clean/chrome/browser/ui/omnibox/location_bar_mediator.mm +++ b/ios/clean/chrome/browser/ui/omnibox/location_bar_mediator.mm
@@ -123,11 +123,6 @@ // explanation of what this method needs to do. } -- (void)locationBarChanged { - // TODO(crbug.com/708341): Implement this method or edit this comment with an - // explanation of what this method needs to do. -} - - (web::WebState*)getWebState { return _webStateList->GetActiveWebState(); }
diff --git a/ios/clean/chrome/browser/ui/tab_collection/BUILD.gn b/ios/clean/chrome/browser/ui/tab_collection/BUILD.gn index 7bdd24da..565a91a3 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/BUILD.gn +++ b/ios/clean/chrome/browser/ui/tab_collection/BUILD.gn
@@ -10,9 +10,11 @@ deps = [ ":tab_collection_ui", "//base", + "//ios/chrome/browser/snapshots", "//ios/chrome/browser/web", "//ios/chrome/browser/web_state_list", "//ios/web", + "//ui/gfx", ] configs += [ "//build/config/compiler:enable_arc" ] }
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h index c771697..cd2a1b6b 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h
@@ -36,6 +36,10 @@ // of the selected item in the tab collection. - (void)populateItems:(NSArray<TabCollectionItem*>*)items selectedIndex:(int)selectedIndex; + +// Updates the snapshot |index|. +- (void)updateSnapshotAtIndex:(int)index; + @end #endif // IOS_CLEAN_CHROME_BROWSER_UI_TAB_COLLECTION_TAB_COLLECTION_CONSUMER_H_
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.h b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.h index 37f120f0..f761b679 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.h +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.h
@@ -7,6 +7,7 @@ #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h" +@class SnapshotCache; @protocol TabCollectionConsumer; class WebStateList; @@ -21,6 +22,9 @@ // list. @property(nonatomic, weak) id<TabCollectionConsumer> consumer; +// Takes a snapshot of the active webState and updates the consumer. +- (void)takeSnapshotWithCache:(SnapshotCache*)snapshotCache; + // Stops observing all objects. - (void)disconnect;
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm index d99ad20..248ab6e 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm
@@ -4,15 +4,19 @@ #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.h" +#include "base/mac/bind_objc_block.h" #include "base/memory/ptr_util.h" #include "base/scoped_observer.h" #include "base/strings/sys_string_conversions.h" +#import "ios/chrome/browser/snapshots/snapshot_cache.h" +#import "ios/chrome/browser/snapshots/snapshot_constants.h" #import "ios/chrome/browser/web/tab_id_tab_helper.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h" #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_item.h" #include "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." @@ -48,6 +52,21 @@ #pragma mark - Public +- (void)takeSnapshotWithCache:(SnapshotCache*)snapshotCache { + web::WebState* webState = self.webStateList->GetActiveWebState(); + TabIdTabHelper* tabHelper = TabIdTabHelper::FromWebState(webState); + DCHECK(tabHelper); + NSString* tabID = tabHelper->tab_id(); + int index = self.webStateList->active_index(); + __weak TabCollectionMediator* weakSelf = self; + webState->TakeSnapshot(base::BindBlockArc(^(const gfx::Image& snapshot) { + [snapshotCache setImage:snapshot.ToUIImage() + withSessionID:tabID]; + [weakSelf.consumer updateSnapshotAtIndex:index]; + }), + kSnapshotThumbnailSize); +} + - (void)disconnect { _webStateList = nullptr; _webStateObserver.reset();
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator_unittest.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator_unittest.mm index 2a74641..a9f98dfd 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator_unittest.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator_unittest.mm
@@ -5,6 +5,7 @@ #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.h" #include "base/memory/ptr_util.h" +#import "ios/chrome/browser/snapshots/snapshot_cache.h" #import "ios/chrome/browser/web/tab_id_tab_helper.h" #include "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h" #include "ios/chrome/browser/web_state_list/web_state_list.h" @@ -95,5 +96,23 @@ // webStateList. TEST_F(TabCollectionMediatorTest, TestChangeActiveWebState) { web_state_list_->ActivateWebStateAt(2); - [[consumer_ verify] setSelectedIndex:2]; + // Due to use of id for OCMock objects, naming collisions can exist. In this + // case, the method -setSelectedIndex: collides with a property setter in + // UIKit's UITabBarController class. The fix is to cast after calling -verify. + auto consumer = static_cast<id<TabCollectionConsumer>>([consumer_ verify]); + [consumer setSelectedIndex:2]; +} + +// Tests that the consumer is notified that a snapshot has been updated. +TEST_F(TabCollectionMediatorTest, TestTakeSnapshot) { + web::TestWebState* web_state = GetWebStateAt(0); + TabIdTabHelper::CreateForWebState(web_state); + TabIdTabHelper* tab_helper = TabIdTabHelper::FromWebState(web_state); + NSString* tab_id = tab_helper->tab_id(); + + id snapshot_cache = OCMClassMock([SnapshotCache class]); + [mediator_ takeSnapshotWithCache:snapshot_cache]; + + [[snapshot_cache verify] setImage:[OCMArg any] withSessionID:tab_id]; + [[consumer_ verify] updateSnapshotAtIndex:0]; }
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm index 686b367..aabb798 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm
@@ -64,7 +64,7 @@ callback:^(UIImage* snapshot) { // PLACEHOLDER: This operation will be cancellable. if ([weakSelf.item.tabID isEqualToString:item.tabID]) { - [weakSelf setSnapshot:snapshot]; + weakSelf.snapshot = snapshot; } }]; }
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.mm index 87b9107..eb433e9a 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.mm
@@ -157,6 +157,7 @@ - (void)insertItem:(TabCollectionItem*)item atIndex:(int)index selectedIndex:(int)selectedIndex { + DCHECK(item); DCHECK_GE(index, 0); DCHECK_LE(static_cast<NSUInteger>(index), self.items.count); [self.items insertObject:item atIndex:index]; @@ -204,4 +205,13 @@ self.selectedIndex = selectedIndex; } +- (void)updateSnapshotAtIndex:(int)index { + DCHECK_GE(index, 0); + DCHECK_LT(static_cast<NSUInteger>(index), self.items.count); + TabCollectionTabCell* cell = base::mac::ObjCCastStrict<TabCollectionTabCell>( + [self.tabs cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index + inSection:0]]); + [cell configureCell:self.items[index] snapshotCache:self.snapshotCache]; +} + @end
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller_unittest.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller_unittest.mm index f6b5cf8..b3dc7f7 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller_unittest.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller_unittest.mm
@@ -6,9 +6,11 @@ #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h" #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_item.h" +#import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.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" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -17,10 +19,12 @@ @interface TestTabCollectionViewController : TabCollectionViewController @property(nonatomic, readwrite) NSMutableArray<TabCollectionItem*>* items; +@property(nonatomic, readwrite) UICollectionView* tabs; @end @implementation TestTabCollectionViewController @dynamic items; +@dynamic tabs; @end class TabCollectionViewControllerTest : public PlatformTest { @@ -32,10 +36,14 @@ TabCollectionItem* item1 = [[TabCollectionItem alloc] init]; item1.title = @"Item1"; view_controller_.items = [@[ item0, item1 ] mutableCopy]; + + tabs_ = OCMClassMock([UICollectionView class]); + view_controller_.tabs = tabs_; } protected: TestTabCollectionViewController* view_controller_; + id tabs_; }; // Tests that an item is inserted. @@ -73,3 +81,13 @@ [view_controller_ populateItems:@[ item ] selectedIndex:0]; EXPECT_NSEQ(@"NewItem", view_controller_.items[0].title); } + +// Tests that a snapshot is updated. +TEST_F(TabCollectionViewControllerTest, TestUpdateSnapshot) { + id cell = OCMClassMock([TabCollectionTabCell class]); + NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; + OCMStub([tabs_ cellForItemAtIndexPath:indexPath]).andReturn(cell); + [view_controller_ updateSnapshotAtIndex:0]; + [[cell verify] configureCell:view_controller_.items[0] + snapshotCache:[OCMArg any]]; +}
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm index 26e1b554..cc51c6b 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm +++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -184,6 +184,7 @@ } - (void)showTabGrid { + [self.mediator takeSnapshotWithCache:self.snapshotCache]; // This object should only ever have at most one child. DCHECK_LE(self.children.count, 1UL); BrowserCoordinator* child = [self.children anyObject];
diff --git a/ios/public/provider/chrome/browser/signin/BUILD.gn b/ios/public/provider/chrome/browser/signin/BUILD.gn index fd8141a..8820007 100644 --- a/ios/public/provider/chrome/browser/signin/BUILD.gn +++ b/ios/public/provider/chrome/browser/signin/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. source_set("signin") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "chrome_identity.h", "chrome_identity.mm",
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity.h b/ios/public/provider/chrome/browser/signin/chrome_identity.h index d427bd4..c755a07 100644 --- a/ios/public/provider/chrome/browser/signin/chrome_identity.h +++ b/ios/public/provider/chrome/browser/signin/chrome_identity.h
@@ -14,19 +14,19 @@ // Identity/account email address. This can be shown to the user, but is not a // unique identifier (@see gaiaID). -@property(nonatomic, readonly) NSString* userEmail; +@property(strong, nonatomic, readonly) NSString* userEmail; // The unique GAIA user identifier for this identity/account. // You may use this as a unique identifier to remember a particular identity. -@property(nonatomic, readonly) NSString* gaiaID; +@property(strong, nonatomic, readonly) NSString* gaiaID; // Returns the full name of the identity. // Could be nil if no full name has been fetched for this account yet. -@property(nonatomic, readonly) NSString* userFullName; +@property(strong, nonatomic, readonly) NSString* userFullName; // Cached Hashed Gaia ID. This is used to pass the currently signed in account // between apps. -@property(nonatomic, readonly) NSString* hashedGaiaID; +@property(strong, nonatomic, readonly) NSString* hashedGaiaID; @end
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity.mm b/ios/public/provider/chrome/browser/signin/chrome_identity.mm index b2a04968..90284ad 100644 --- a/ios/public/provider/chrome/browser/signin/chrome_identity.mm +++ b/ios/public/provider/chrome/browser/signin/chrome_identity.mm
@@ -6,6 +6,10 @@ #include "base/logging.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + @implementation ChromeIdentity - (NSString*)userEmail {
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h b/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h index 4116256..1e259175 100644 --- a/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h +++ b/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h
@@ -30,7 +30,7 @@ @interface ChromeIdentityInteractionManager : NSObject // Delegate used to present and dismiss the view controllers. -@property(nonatomic, assign) id<ChromeIdentityInteractionManagerDelegate> +@property(nonatomic, weak) id<ChromeIdentityInteractionManagerDelegate> delegate; // Whether the manager is currently being canceled. Delegates may inquire if the
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.mm index 6e5b223..4be6723 100644 --- a/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.mm +++ b/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.mm
@@ -4,23 +4,14 @@ #import "ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h" -#import "base/ios/weak_nsobject.h" #include "base/logging.h" -@interface ChromeIdentityInteractionManager () { - base::WeakNSProtocol<id<ChromeIdentityInteractionManagerDelegate>> _delegate; -} -@end +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif @implementation ChromeIdentityInteractionManager - -- (id<ChromeIdentityInteractionManagerDelegate>)delegate { - return _delegate; -} - -- (void)setDelegate:(id<ChromeIdentityInteractionManagerDelegate>)delegate { - _delegate.reset(delegate); -} +@synthesize delegate = _delegate; - (BOOL)isCanceling { return NO;
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm index be02f63..d32e9ea 100644 --- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm +++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
@@ -6,6 +6,10 @@ #include "ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace ios { ChromeIdentityService::ChromeIdentityService() {}
diff --git a/ios/public/provider/chrome/browser/signin/signin_error_provider.mm b/ios/public/provider/chrome/browser/signin/signin_error_provider.mm index f9eeba60..fe49446 100644 --- a/ios/public/provider/chrome/browser/signin/signin_error_provider.mm +++ b/ios/public/provider/chrome/browser/signin/signin_error_provider.mm
@@ -4,6 +4,10 @@ #include "ios/public/provider/chrome/browser/signin/signin_error_provider.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace ios { SigninErrorProvider::SigninErrorProvider() {}
diff --git a/ios/public/provider/chrome/browser/signin/signin_resources_provider.mm b/ios/public/provider/chrome/browser/signin/signin_resources_provider.mm index 0d66297..ebd9bf056 100644 --- a/ios/public/provider/chrome/browser/signin/signin_resources_provider.mm +++ b/ios/public/provider/chrome/browser/signin/signin_resources_provider.mm
@@ -6,6 +6,10 @@ #include <MacTypes.h> +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace ios { SigninResourcesProvider::SigninResourcesProvider() {
diff --git a/ios/shared/chrome/browser/ui/omnibox/location_bar_delegate.h b/ios/shared/chrome/browser/ui/omnibox/location_bar_delegate.h index 7c86a1c..e4b3113 100644 --- a/ios/shared/chrome/browser/ui/omnibox/location_bar_delegate.h +++ b/ios/shared/chrome/browser/ui/omnibox/location_bar_delegate.h
@@ -24,7 +24,6 @@ - (void)locationBarHasBecomeFirstResponder; - (void)locationBarHasResignedFirstResponder; - (void)locationBarBeganEdit; -- (void)locationBarChanged; - (web::WebState*)getWebState; - (ToolbarModel*)toolbarModel; @end
diff --git a/ios/web/app/BUILD.gn b/ios/web/app/BUILD.gn index 801f351..10b9705 100644 --- a/ios/web/app/BUILD.gn +++ b/ios/web/app/BUILD.gn
@@ -19,6 +19,7 @@ "//base:i18n", "//crypto", "//ios/web", + "//ios/web/public/global_state", "//mojo/edk/system", "//net", "//ui/base",
diff --git a/ios/web/app/web_main.mm b/ios/web/app/web_main.mm index e0d7f99..4b60364 100644 --- a/ios/web/app/web_main.mm +++ b/ios/web/app/web_main.mm
@@ -11,9 +11,24 @@ namespace web { -WebMain::WebMain(const WebMainParams& params) { +WebMainParams::WebMainParams() : WebMainParams(nullptr) {} + +WebMainParams::WebMainParams(WebMainDelegate* delegate) + : delegate(delegate), + register_exit_manager(true), + get_task_scheduler_init_params_callback(nullptr), + argc(0), + argv(nullptr) {} + +WebMainParams::~WebMainParams() = default; + +WebMainParams::WebMainParams(WebMainParams&& other) = default; + +WebMainParams& WebMainParams::operator=(web::WebMainParams&& other) = default; + +WebMain::WebMain(WebMainParams params) { web_main_runner_.reset(WebMainRunner::Create()); - web_main_runner_->Initialize(params); + web_main_runner_->Initialize(std::move(params)); } WebMain::~WebMain() {
diff --git a/ios/web/app/web_main_loop.h b/ios/web/app/web_main_loop.h index 739bcd7..415da9c 100644 --- a/ios/web/app/web_main_loop.h +++ b/ios/web/app/web_main_loop.h
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "ios/web/public/app/task_scheduler_init_params_callback.h" namespace base { class MessageLoop; @@ -38,8 +39,10 @@ void EarlyInitialization(); void MainMessageLoopStart(); - // Creates and starts running the tasks needed to complete startup. - void CreateStartupTasks(); + // Creates and starts running the tasks needed to complete startup. The + // |init_params_callback| may be null or supply InitParams to be used to start + // the global TaskScheduler instead of using the defaults. + void CreateStartupTasks(TaskSchedulerInitParamsCallback init_params_callback); // Performs the shutdown sequence, starting with PostMainMessageLoopRun // through stopping threads to PostDestroyThreads. @@ -53,8 +56,10 @@ // Called just before creating the threads int PreCreateThreads(); - // Creates all secondary threads. - int CreateThreads(); + // Creates all secondary threads. The |init_params_callback| may be null or + // supply InitParams to be used to start the global TaskScheduler instead of + // using the defaults. + int CreateThreads(TaskSchedulerInitParamsCallback init_params_callback); // Called right after the web threads have been started. int WebThreadsStarted();
diff --git a/ios/web/app/web_main_loop.mm b/ios/web/app/web_main_loop.mm index eaa0ee0..6a259973 100644 --- a/ios/web/app/web_main_loop.mm +++ b/ios/web/app/web_main_loop.mm
@@ -18,13 +18,13 @@ #include "base/power_monitor/power_monitor_device_source.h" #include "base/process/process_metrics.h" #include "base/system_monitor/system_monitor.h" -#include "base/task_scheduler/initialization_util.h" #include "base/task_scheduler/scheduler_worker_pool_params.h" #include "base/task_scheduler/task_scheduler.h" #include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_restrictions.h" #import "ios/web/net/cookie_notification_bridge.h" #include "ios/web/public/app/web_main_parts.h" +#import "ios/web/public/global_state/ios_global_state.h" #import "ios/web/public/web_client.h" #include "ios/web/service_manager_context.h" #include "ios/web/web_thread_impl.h" @@ -37,33 +37,6 @@ namespace web { -namespace { - -std::unique_ptr<base::TaskScheduler::InitParams> -GetDefaultTaskSchedulerInitParams() { - using StandbyThreadPolicy = - base::SchedulerWorkerPoolParams::StandbyThreadPolicy; - return base::MakeUnique<base::TaskScheduler::InitParams>( - base::SchedulerWorkerPoolParams( - StandbyThreadPolicy::ONE, - base::RecommendedMaxNumberOfThreadsInPool(2, 8, 0.1, 0), - base::TimeDelta::FromSeconds(30)), - base::SchedulerWorkerPoolParams( - StandbyThreadPolicy::ONE, - base::RecommendedMaxNumberOfThreadsInPool(2, 8, 0.1, 0), - base::TimeDelta::FromSeconds(30)), - base::SchedulerWorkerPoolParams( - StandbyThreadPolicy::ONE, - base::RecommendedMaxNumberOfThreadsInPool(3, 8, 0.3, 0), - base::TimeDelta::FromSeconds(30)), - base::SchedulerWorkerPoolParams( - StandbyThreadPolicy::ONE, - base::RecommendedMaxNumberOfThreadsInPool(3, 8, 0.3, 0), - base::TimeDelta::FromSeconds(60))); -} - -} // namespace - // The currently-running WebMainLoop. There can be one or zero. // TODO(rohitrao): Desktop uses this to implement // ImmediateShutdownAndExitProcess. If we don't need that functionality, we can @@ -74,9 +47,7 @@ DCHECK(!g_current_web_main_loop); g_current_web_main_loop = this; - // Use an empty string as TaskScheduler name to match the suffix of browser - // process TaskScheduler histograms. - base::TaskScheduler::Create(""); + ios_global_state::Create(); } WebMainLoop::~WebMainLoop() { @@ -123,13 +94,14 @@ } } -void WebMainLoop::CreateStartupTasks() { +void WebMainLoop::CreateStartupTasks( + TaskSchedulerInitParamsCallback init_params_callback) { int result = 0; result = PreCreateThreads(); if (result > 0) return; - result = CreateThreads(); + result = CreateThreads(std::move(init_params_callback)); if (result > 0) return; @@ -150,16 +122,13 @@ return result_code_; } -int WebMainLoop::CreateThreads() { - { - auto task_scheduler_init_params = - GetWebClient()->GetTaskSchedulerInitParams(); - if (!task_scheduler_init_params) - task_scheduler_init_params = GetDefaultTaskSchedulerInitParams(); - DCHECK(task_scheduler_init_params); - base::TaskScheduler::GetInstance()->Start( - *task_scheduler_init_params.get()); +int WebMainLoop::CreateThreads( + TaskSchedulerInitParamsCallback init_params_callback) { + std::unique_ptr<base::TaskScheduler::InitParams> init_params; + if (!init_params_callback.is_null()) { + init_params = std::move(init_params_callback).Run(); } + ios_global_state::StartTaskScheduler(init_params.get()); base::SequencedWorkerPool::EnableWithRedirectionToTaskSchedulerForProcess();
diff --git a/ios/web/app/web_main_runner.mm b/ios/web/app/web_main_runner.mm index 53849ff..855dcf77 100644 --- a/ios/web/app/web_main_runner.mm +++ b/ios/web/app/web_main_runner.mm
@@ -36,7 +36,7 @@ } } - int Initialize(const WebMainParams& params) override { + int Initialize(WebMainParams params) override { //////////////////////////////////////////////////////////////////////// // ContentMainRunnerImpl::Initialize() // @@ -73,7 +73,8 @@ main_loop_->Init(); main_loop_->EarlyInitialization(); main_loop_->MainMessageLoopStart(); - main_loop_->CreateStartupTasks(); + main_loop_->CreateStartupTasks( + std::move(params.get_task_scheduler_init_params_callback)); int result_code = main_loop_->GetResultCode(); if (result_code > 0) return result_code;
diff --git a/ios/web/public/app/BUILD.gn b/ios/web/public/app/BUILD.gn index 45aa701..45fcc363 100644 --- a/ios/web/public/app/BUILD.gn +++ b/ios/web/public/app/BUILD.gn
@@ -6,6 +6,7 @@ source_set("app") { sources = [ + "task_scheduler_init_params_callback.h", "web_main.h", "web_main_delegate.h", "web_main_parts.h",
diff --git a/ios/web/public/app/task_scheduler_init_params_callback.h b/ios/web/public/app/task_scheduler_init_params_callback.h new file mode 100644 index 0000000..3fef718 --- /dev/null +++ b/ios/web/public/app/task_scheduler_init_params_callback.h
@@ -0,0 +1,19 @@ +// 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_WEB_PUBLIC_GLOBAL_STATE_TASK_SCHEDULER_INIT_PARAMS_CALLBACK_H_ +#define IOS_WEB_PUBLIC_GLOBAL_STATE_TASK_SCHEDULER_INIT_PARAMS_CALLBACK_H_ + +#include "base/callback_forward.h" +#include "base/task_scheduler/task_scheduler.h" + +namespace web { + +// Callback which returns a pointer to InitParams for base::TaskScheduler. +typedef base::OnceCallback<std::unique_ptr<base::TaskScheduler::InitParams>()> + TaskSchedulerInitParamsCallback; + +} // namespace web + +#endif // IOS_WEB_PUBLIC_GLOBAL_STATE_TASK_SCHEDULER_INIT_PARAMS_CALLBACK_H_
diff --git a/ios/web/public/app/web_main.h b/ios/web/public/app/web_main.h index 8ae8ce8..2b5db8b9 100644 --- a/ios/web/public/app/web_main.h +++ b/ios/web/public/app/web_main.h
@@ -7,6 +7,8 @@ #include <memory> +#include "base/macros.h" +#include "ios/web/public/app/task_scheduler_init_params_callback.h" #include "ios/web/public/app/web_main_delegate.h" namespace web { @@ -14,18 +16,23 @@ // Contains parameters passed to WebMain. struct WebMainParams { - explicit WebMainParams(WebMainDelegate* delegate) - : delegate(delegate), - register_exit_manager(true), - argc(0), - argv(nullptr) {} + WebMainParams(); + explicit WebMainParams(WebMainDelegate* delegate); + ~WebMainParams(); + + // WebMainParams is moveable. + WebMainParams(WebMainParams&& other); + WebMainParams& operator=(WebMainParams&& other); WebMainDelegate* delegate; bool register_exit_manager; + TaskSchedulerInitParamsCallback get_task_scheduler_init_params_callback; int argc; const char** argv; + + DISALLOW_COPY_AND_ASSIGN(WebMainParams); }; // Encapsulates any setup and initialization that is needed by common @@ -37,7 +44,7 @@ // in WebMainDelegate and WebMainParts. class WebMain { public: - explicit WebMain(const WebMainParams& params); + explicit WebMain(WebMainParams params); ~WebMain(); private:
diff --git a/ios/web/public/app/web_main_runner.h b/ios/web/public/app/web_main_runner.h index aa940f4..9cb5a9a 100644 --- a/ios/web/public/app/web_main_runner.h +++ b/ios/web/public/app/web_main_runner.h
@@ -18,7 +18,7 @@ static WebMainRunner* Create(); // Initialize all necessary web state. - virtual int Initialize(const WebMainParams& params) = 0; + virtual int Initialize(WebMainParams params) = 0; // Shut down the web state. virtual void ShutDown() = 0;
diff --git a/ios/web/public/global_state/BUILD.gn b/ios/web/public/global_state/BUILD.gn new file mode 100644 index 0000000..a433b21 --- /dev/null +++ b/ios/web/public/global_state/BUILD.gn
@@ -0,0 +1,16 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("global_state") { + configs += [ "//build/config/compiler:enable_arc" ] + + deps = [ + "//base", + ] + + sources = [ + "ios_global_state.h", + "ios_global_state.mm", + ] +}
diff --git a/ios/web/public/global_state/ios_global_state.h b/ios/web/public/global_state/ios_global_state.h new file mode 100644 index 0000000..35c6c62 --- /dev/null +++ b/ios/web/public/global_state/ios_global_state.h
@@ -0,0 +1,25 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_WEB_PUBLIC_GLOBAL_STATE_IOS_GLOBAL_STATE_H_ +#define IOS_WEB_PUBLIC_GLOBAL_STATE_IOS_GLOBAL_STATE_H_ + +#include "base/task_scheduler/task_scheduler.h" + +namespace ios_global_state { + +// Creates global state for iOS. This should be called as early as possible in +// the application lifecycle. It is safe to call this method more than once, the +// initialization will only be performed once. +void Create(); + +// Starts a global base::TaskScheduler. This method must be called to start +// the Task Scheduler that is created in |Create|. If |init_params| is null, +// default InitParams will be used. It is safe to call this method more than +// once, the task scheduler will only be started once. +void StartTaskScheduler(base::TaskScheduler::InitParams* init_params); + +} // namespace ios_global_state + +#endif // IOS_WEB_PUBLIC_GLOBAL_STATE_IOS_GLOBAL_STATE_H_
diff --git a/ios/web/public/global_state/ios_global_state.mm b/ios/web/public/global_state/ios_global_state.mm new file mode 100644 index 0000000..ab7ec88 --- /dev/null +++ b/ios/web/public/global_state/ios_global_state.mm
@@ -0,0 +1,59 @@ +// 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/web/public/global_state/ios_global_state.h" + +#include "base/memory/ptr_util.h" +#include "base/task_scheduler/initialization_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +base::TaskScheduler::InitParams GetDefaultTaskSchedulerInitParams() { + using StandbyThreadPolicy = + base::SchedulerWorkerPoolParams::StandbyThreadPolicy; + return base::TaskScheduler::InitParams( + base::SchedulerWorkerPoolParams( + StandbyThreadPolicy::ONE, + base::RecommendedMaxNumberOfThreadsInPool(2, 8, 0.1, 0), + base::TimeDelta::FromSeconds(30)), + base::SchedulerWorkerPoolParams( + StandbyThreadPolicy::ONE, + base::RecommendedMaxNumberOfThreadsInPool(2, 8, 0.1, 0), + base::TimeDelta::FromSeconds(30)), + base::SchedulerWorkerPoolParams( + StandbyThreadPolicy::ONE, + base::RecommendedMaxNumberOfThreadsInPool(3, 8, 0.3, 0), + base::TimeDelta::FromSeconds(30)), + base::SchedulerWorkerPoolParams( + StandbyThreadPolicy::ONE, + base::RecommendedMaxNumberOfThreadsInPool(3, 8, 0.3, 0), + base::TimeDelta::FromSeconds(60))); +} + +} // namespace + +namespace ios_global_state { + +void Create() { + static dispatch_once_t once_token; + dispatch_once(&once_token, ^{ + // Use an empty string as TaskScheduler name to match the suffix of browser + // process TaskScheduler histograms. + base::TaskScheduler::Create(""); + }); +} + +void StartTaskScheduler(base::TaskScheduler::InitParams* params) { + static dispatch_once_t once_token; + dispatch_once(&once_token, ^{ + auto init_params = params ? *params : GetDefaultTaskSchedulerInitParams(); + base::TaskScheduler::GetInstance()->Start(init_params); + }); +} + +} // namespace ios_global_state
diff --git a/ios/web/public/test/fakes/test_web_state.mm b/ios/web/public/test/fakes/test_web_state.mm index 97b631d..f5a4b995 100644 --- a/ios/web/public/test/fakes/test_web_state.mm +++ b/ios/web/public/test/fakes/test_web_state.mm
@@ -235,8 +235,7 @@ void TestWebState::TakeSnapshot(const SnapshotCallback& callback, CGSize target_size) const { - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, gfx::Image())); + callback.Run(gfx::Image([[UIImage alloc] init])); } base::WeakPtr<WebState> TestWebState::AsWeakPtr() {
diff --git a/ios/web/public/web_client.h b/ios/web/public/web_client.h index 400efa1..ff8b96e 100644 --- a/ios/web/public/web_client.h +++ b/ios/web/public/web_client.h
@@ -141,11 +141,6 @@ bool overridable, const base::Callback<void(bool)>& callback); - // Provides parameters for initializing the global task scheduler. Default - // params are used if this returns nullptr. - virtual std::unique_ptr<base::TaskScheduler::InitParams> - GetTaskSchedulerInitParams(); - // Allows upper layers to inject experimental flags to the web layer. // TODO(crbug.com/734150): Clean up this flag after experiment. If need for a // second flag arises before clean up, consider generalizing to an experiment
diff --git a/ios/web/public/web_client.mm b/ios/web/public/web_client.mm index 81bd02b2..ef02e6b 100644 --- a/ios/web/public/web_client.mm +++ b/ios/web/public/web_client.mm
@@ -91,11 +91,6 @@ callback.Run(false); } -std::unique_ptr<base::TaskScheduler::InitParams> -WebClient::GetTaskSchedulerInitParams() { - return nullptr; -} - bool WebClient::IsSlimNavigationManagerEnabled() const { return false; }
diff --git a/ios/web/shell/app_delegate.mm b/ios/web/shell/app_delegate.mm index abc7bac..4274183 100644 --- a/ios/web/shell/app_delegate.mm +++ b/ios/web/shell/app_delegate.mm
@@ -7,6 +7,7 @@ #include <memory> #import "base/mac/scoped_nsobject.h" +#include "base/memory/ptr_util.h" #include "ios/web/public/app/web_main.h" #import "ios/web/public/web_client.h" #import "ios/web/public/web_state/web_state.h" @@ -36,8 +37,9 @@ self.window.backgroundColor = [UIColor whiteColor]; _delegate.reset(new web::ShellMainDelegate()); + web::WebMainParams params(_delegate.get()); - _webMain.reset(new web::WebMain(params)); + _webMain = base::MakeUnique<web::WebMain>(std::move(params)); web::ShellWebClient* client = static_cast<web::ShellWebClient*>(web::GetWebClient());
diff --git a/ios/web_view/internal/web_view_global_state_util.mm b/ios/web_view/internal/web_view_global_state_util.mm index 49fd8500..8491b48 100644 --- a/ios/web_view/internal/web_view_global_state_util.mm +++ b/ios/web_view/internal/web_view_global_state_util.mm
@@ -24,7 +24,7 @@ web_main_delegate = base::MakeUnique<ios_web_view::WebViewWebMainDelegate>(); web::WebMainParams params(web_main_delegate.get()); - web_main = base::MakeUnique<web::WebMain>(params); + web_main = base::MakeUnique<web::WebMain>(std::move(params)); }); }
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc index 3a32303..a0bd452 100644 --- a/media/cdm/cdm_adapter.cc +++ b/media/cdm/cdm_adapter.cc
@@ -279,8 +279,14 @@ input_buffer->data = encrypted_buffer->data(); input_buffer->data_size = encrypted_buffer->data_size(); + input_buffer->timestamp = encrypted_buffer->timestamp().InMicroseconds(); const DecryptConfig* decrypt_config = encrypted_buffer->decrypt_config(); + if (!decrypt_config) { + DVLOG(2) << __func__ << ": Clear buffer."; + return; + } + input_buffer->key_id = reinterpret_cast<const uint8_t*>(decrypt_config->key_id().data()); input_buffer->key_id_size = decrypt_config->key_id().size(); @@ -300,7 +306,6 @@ input_buffer->subsamples = subsamples->data(); input_buffer->num_subsamples = num_subsamples; - input_buffer->timestamp = encrypted_buffer->timestamp().InMicroseconds(); } void* GetCdmHost(int host_interface_version, void* user_data) {
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc index c92214fa..f3c920d 100644 --- a/media/filters/gpu_video_decoder.cc +++ b/media/filters/gpu_video_decoder.cc
@@ -40,10 +40,6 @@ namespace media { namespace { -// Size of shared-memory segments we allocate. Since we reuse them we let them -// be on the beefy side. -static const size_t kSharedMemorySegmentBytes = 100 << 10; - #if defined(OS_ANDROID) && BUILDFLAG(USE_PROPRIETARY_CODECS) // Extract the SPS and PPS lists from |extra_data|. Each SPS and PPS is prefixed // with 0x0001, the Annex B framing bytes. The out parameters are not modified @@ -82,6 +78,10 @@ // resources. enum { kMaxInFlightDecodes = 4 }; +// Number of bitstream buffers returned before GC is attempted on shared memory +// segments. Value chosen arbitrarily. +enum { kBufferCountBeforeGC = 1024 }; + struct GpuVideoDecoder::PendingDecoderBuffer { PendingDecoderBuffer(std::unique_ptr<base::SharedMemory> s, const scoped_refptr<DecoderBuffer>& b, @@ -120,6 +120,8 @@ supports_deferred_initialization_(false), requires_texture_copy_(false), cdm_id_(CdmContext::kInvalidCdmId), + min_shared_memory_segment_size_(0), + bitstream_buffer_id_of_last_gc_(0), weak_factory_(this) { DCHECK(factories_); } @@ -244,6 +246,24 @@ VideoDecodeAccelerator::Capabilities::SUPPORTS_DEFERRED_INITIALIZATION); output_cb_ = output_cb; + // Attempt to choose a reasonable size for the shared memory segments based on + // the size of video. These values are chosen based on experiments with common + // videos from the web. Too small and you'll end up creating too many segments + // too large and you end up wasting significant amounts of memory. + const int height = config.coded_size().height(); + if (height >= 4000) // ~4320p + min_shared_memory_segment_size_ = 384 * 1024; + else if (height >= 2000) // ~2160p + min_shared_memory_segment_size_ = 192 * 1024; + else if (height >= 1000) // ~1080p + min_shared_memory_segment_size_ = 96 * 1024; + else if (height >= 700) // ~720p + min_shared_memory_segment_size_ = 72 * 1024; + else if (height >= 400) // ~480p + min_shared_memory_segment_size_ = 48 * 1024; + else // ~360p or less + min_shared_memory_segment_size_ = 32 * 1024; + if (config.is_encrypted() && !supports_deferred_initialization_) { DVLOG(1) << __func__ << " Encrypted stream requires deferred initialialization."; @@ -745,21 +765,40 @@ std::unique_ptr<base::SharedMemory> GpuVideoDecoder::GetSharedMemory( size_t min_size) { DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); - if (available_shm_segments_.empty() || - available_shm_segments_.back()->mapped_size() < min_size) { - size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); - // CreateSharedMemory() can return NULL during Shutdown. - return factories_->CreateSharedMemory(size_to_allocate); + auto it = std::lower_bound(available_shm_segments_.begin(), + available_shm_segments_.end(), min_size, + [](const ShMemEntry& entry, const size_t size) { + return entry.first->mapped_size() < size; + }); + if (it != available_shm_segments_.end()) { + auto ret = std::move(it->first); + available_shm_segments_.erase(it); + return ret; } - auto ret = std::move(available_shm_segments_.back()); - available_shm_segments_.pop_back(); - return ret; + + return factories_->CreateSharedMemory( + std::max(min_shared_memory_segment_size_, min_size)); } void GpuVideoDecoder::PutSharedMemory( - std::unique_ptr<base::SharedMemory> shared_memory) { + std::unique_ptr<base::SharedMemory> shared_memory, + int32_t last_bitstream_buffer_id) { DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); - available_shm_segments_.push_back(std::move(shared_memory)); + available_shm_segments_.emplace(std::move(shared_memory), + last_bitstream_buffer_id); + + if (next_bitstream_buffer_id_ < bitstream_buffer_id_of_last_gc_ || + next_bitstream_buffer_id_ - bitstream_buffer_id_of_last_gc_ > + kBufferCountBeforeGC) { + base::EraseIf(available_shm_segments_, [this](const ShMemEntry& entry) { + // Check for overflow rollover... + if (next_bitstream_buffer_id_ < entry.second) + return next_bitstream_buffer_id_ > kBufferCountBeforeGC; + + return next_bitstream_buffer_id_ - entry.second > kBufferCountBeforeGC; + }); + bitstream_buffer_id_of_last_gc_ = next_bitstream_buffer_id_; + } } void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32_t id) { @@ -774,7 +813,7 @@ return; } - PutSharedMemory(std::move(it->second.shared_memory)); + PutSharedMemory(std::move(it->second.shared_memory), id); it->second.done_cb.Run(state_ == kError ? DecodeStatus::DECODE_ERROR : DecodeStatus::OK); bitstream_buffers_in_decoder_.erase(it); @@ -811,6 +850,10 @@ DCHECK_EQ(state_, kDrainingDecoder); state_ = kDecoderDrained; base::ResetAndReturn(&eos_decode_cb_).Run(DecodeStatus::OK); + + // Assume flush is for a config change, so drop shared memory segments in + // anticipation of a resize occurring. + available_shm_segments_.clear(); } void GpuVideoDecoder::NotifyResetDone() {
diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h index c765d31c..4bc69d5 100644 --- a/media/filters/gpu_video_decoder.h +++ b/media/filters/gpu_video_decoder.h
@@ -8,12 +8,14 @@ #include <stddef.h> #include <stdint.h> +#include <deque> #include <list> #include <map> #include <set> #include <utility> #include <vector> +#include "base/containers/flat_set.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "gpu/command_buffer/common/sync_token.h" @@ -116,11 +118,12 @@ void DestroyVDA(); // Request a shared-memory segment of at least |min_size| bytes. Will - // allocate as necessary. + // allocate as necessary. May return nullptr during Shutdown. std::unique_ptr<base::SharedMemory> GetSharedMemory(size_t min_size); // Return a shared-memory segment to the available pool. - void PutSharedMemory(std::unique_ptr<base::SharedMemory> shm_buffer); + void PutSharedMemory(std::unique_ptr<base::SharedMemory> shm_buffer, + int32_t last_bitstream_buffer_id); // Destroy all PictureBuffers in |buffers|, and delete their textures. void DestroyPictureBuffers(PictureBufferMap* buffers); @@ -176,10 +179,20 @@ VideoDecoderConfig config_; - // Shared-memory buffer pool. Since allocating SHM segments requires a - // round-trip to the browser process, we keep allocation out of the - // steady-state of the decoder. - std::vector<std::unique_ptr<base::SharedMemory>> available_shm_segments_; + // Shared-memory buffer pool. Since allocating SHM segments requires a round- + // trip to the browser process, we try to keep allocation out of the steady- + // state of the decoder. + // + // The second value in the ShMemEntry is the last bitstream buffer id assigned + // to that segment; it's used to erase segments which are no longer active. + using ShMemEntry = std::pair<std::unique_ptr<base::SharedMemory>, int32_t>; + class ShMemEntrySortedBySize { + public: + bool operator()(const ShMemEntry& lhs, const ShMemEntry& rhs) const { + return lhs.first->mapped_size() < rhs.first->mapped_size(); + } + }; + base::flat_set<ShMemEntry, ShMemEntrySortedBySize> available_shm_segments_; // Placeholder sync token that was created and validated after the most // recent picture buffers were created. @@ -235,6 +248,16 @@ // encrypted content. int cdm_id_; + // Minimum size for shared memory segments. Ideally chosen to optimize the + // number of segments and total size of allocations over the course of a + // playback. See Initialize() for more details. + size_t min_shared_memory_segment_size_; + + // |next_bitstream_buffer_id_| at the time we last performed a GC of no longer + // used ShMemEntry objects in |available_shm_segments_|. Updated whenever + // PutSharedMemory() performs a GC. + int32_t bitstream_buffer_id_of_last_gc_; + // Bound to factories_->GetMessageLoop(). // NOTE: Weak pointers must be invalidated before all other member variables. base::WeakPtrFactory<GpuVideoDecoder> weak_factory_;
diff --git a/media/gpu/mojo/jpeg_decoder.mojom b/media/gpu/mojo/jpeg_decoder.mojom index c9532a3..d5a1fb0 100644 --- a/media/gpu/mojo/jpeg_decoder.mojom +++ b/media/gpu/mojo/jpeg_decoder.mojom
@@ -24,7 +24,7 @@ int32 id; handle<shared_buffer> memory_handle; uint32 size; - uint64 offset; + int64 offset; mojo.common.mojom.TimeDelta timestamp; string key_id; string iv;
diff --git a/media/gpu/mojo/jpeg_decoder_typemap_traits.cc b/media/gpu/mojo/jpeg_decoder_typemap_traits.cc index 7ef9d36..a16301a6 100644 --- a/media/gpu/mojo/jpeg_decoder_typemap_traits.cc +++ b/media/gpu/mojo/jpeg_decoder_typemap_traits.cc
@@ -102,7 +102,8 @@ return false; media::BitstreamBuffer bitstream_buffer( - input.id(), memory_handle, input.size(), input.offset(), timestamp); + input.id(), memory_handle, input.size(), + base::checked_cast<off_t>(input.offset()), timestamp); bitstream_buffer.SetDecryptConfig( media::DecryptConfig(key_id, iv, subsamples)); *output = bitstream_buffer;
diff --git a/media/gpu/mojo/jpeg_decoder_typemap_traits.h b/media/gpu/mojo/jpeg_decoder_typemap_traits.h index 6312993..b5ec4995 100644 --- a/media/gpu/mojo/jpeg_decoder_typemap_traits.h +++ b/media/gpu/mojo/jpeg_decoder_typemap_traits.h
@@ -34,8 +34,8 @@ return base::checked_cast<uint32_t>(input.size()); } - static uint64_t offset(const media::BitstreamBuffer& input) { - return input.offset(); + static int64_t offset(const media::BitstreamBuffer& input) { + return base::checked_cast<int64_t>(input.offset()); } static base::TimeDelta timestamp(const media::BitstreamBuffer& input) {
diff --git a/mojo/edk/system/ports/node.cc b/mojo/edk/system/ports/node.cc index 8554533..c2edd87 100644 --- a/mojo/edk/system/ports/node.cc +++ b/mojo/edk/system/ports/node.cc
@@ -722,17 +722,19 @@ // first as otherwise its peer receiving port could be left stranded // indefinitely. if (AcceptPort(event->new_port_name(), event->new_port_descriptor()) != OK) { - ClosePort(port_ref); + if (port_ref.is_valid()) + ClosePort(port_ref); return ERROR_PORT_STATE_UNEXPECTED; } PortRef new_port_ref; GetPort(event->new_port_name(), &new_port_ref); - DCHECK(new_port_ref.is_valid()); - - if (!port_ref.is_valid()) { - ClosePort(port_ref); + if (!port_ref.is_valid() && new_port_ref.is_valid()) { ClosePort(new_port_ref); + return ERROR_PORT_UNKNOWN; + } else if (port_ref.is_valid() && !new_port_ref.is_valid()) { + ClosePort(port_ref); + return ERROR_PORT_UNKNOWN; } return MergePortsInternal(port_ref, new_port_ref,
diff --git a/mojo/edk/system/ports/port_locker.cc b/mojo/edk/system/ports/port_locker.cc index f9c627c..e84d0d0 100644 --- a/mojo/edk/system/ports/port_locker.cc +++ b/mojo/edk/system/ports/port_locker.cc
@@ -37,9 +37,14 @@ #endif // Sort the ports by address to lock them in a globally consistent order. - std::sort(port_refs_, port_refs_ + num_ports_, ComparePortRefsByPortAddress); - for (size_t i = 0; i < num_ports_; ++i) + std::sort( + port_refs_, port_refs_ + num_ports_, + [](const PortRef* a, const PortRef* b) { return a->port() < b->port(); }); + for (size_t i = 0; i < num_ports_; ++i) { + // TODO(crbug.com/725605): Remove this CHECK. + CHECK(port_refs_[i]->port()); port_refs_[i]->port()->lock_.Acquire(); + } } PortLocker::~PortLocker() { @@ -59,12 +64,6 @@ } #endif -// static -bool PortLocker::ComparePortRefsByPortAddress(const PortRef* a, - const PortRef* b) { - return a->port() < b->port(); -} - SinglePortLocker::SinglePortLocker(const PortRef* port_ref) : port_ref_(port_ref), locker_(&port_ref_, 1) {}
diff --git a/mojo/edk/system/ports/port_locker.h b/mojo/edk/system/ports/port_locker.h index 0deeb87..38782068 100644 --- a/mojo/edk/system/ports/port_locker.h +++ b/mojo/edk/system/ports/port_locker.h
@@ -58,8 +58,6 @@ #endif private: - static bool ComparePortRefsByPortAddress(const PortRef* a, const PortRef* b); - const PortRef** const port_refs_; const size_t num_ports_;
diff --git a/mojo/edk/system/watcher_dispatcher.cc b/mojo/edk/system/watcher_dispatcher.cc index 4f7e982..3b8d156 100644 --- a/mojo/edk/system/watcher_dispatcher.cc +++ b/mojo/edk/system/watcher_dispatcher.cc
@@ -228,7 +228,10 @@ return MOJO_RESULT_FAILED_PRECONDITION; } -WatcherDispatcher::~WatcherDispatcher() {} +WatcherDispatcher::~WatcherDispatcher() { + // TODO(crbug.com/74044): Remove this. + CHECK(closed_); +} } // namespace edk } // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc index 819143f..4b68323 100644 --- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc +++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -167,6 +167,9 @@ InterfaceEndpointClient::~InterfaceEndpointClient() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // TODO(crbug.com/741047): Remove this. + CHECK(task_runner_->RunsTasksInCurrentSequence()); + if (controller_) handle_.group_controller()->DetachEndpointClient(handle_); }
diff --git a/net/http2/hpack/decoder/hpack_varint_decoder_test.cc b/net/http2/hpack/decoder/hpack_varint_decoder_test.cc index 91a3d3530..6ca7994 100644 --- a/net/http2/hpack/decoder/hpack_varint_decoder_test.cc +++ b/net/http2/hpack/decoder/hpack_varint_decoder_test.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include "net/http2/hpack/decoder/hpack_varint_decoder.h" -#include "net/http2/platform/api/http2_string_utils.h" // Tests of HpackVarintDecoder. @@ -20,6 +19,7 @@ #include "base/strings/string_number_conversions.h" #include "net/http2/hpack/tools/hpack_block_builder.h" #include "net/http2/platform/api/http2_string_piece.h" +#include "net/http2/platform/api/http2_string_utils.h" #include "net/http2/tools/failure.h" #include "net/http2/tools/http2_random.h" #include "net/http2/tools/random_decoder_test.h"
diff --git a/net/quic/core/quic_headers_stream_test.cc b/net/quic/core/quic_headers_stream_test.cc index 4f3b9d4..0993c61a 100644 --- a/net/quic/core/quic_headers_stream_test.cc +++ b/net/quic/core/quic_headers_stream_test.cc
@@ -133,69 +133,17 @@ DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener); }; -enum Http2DecoderChoice { - HTTP2_DECODER_SPDY, - HTTP2_DECODER_NEW -}; -std::ostream& operator<<(std::ostream& os, Http2DecoderChoice v) { - switch (v) { - case HTTP2_DECODER_SPDY: - return os << "SPDY"; - case HTTP2_DECODER_NEW: - return os << "NEW"; - } - return os; -} - -enum HpackDecoderChoice { HPACK_DECODER_SPDY, HPACK_DECODER3 }; -std::ostream& operator<<(std::ostream& os, HpackDecoderChoice v) { - switch (v) { - case HPACK_DECODER_SPDY: - return os << "SPDY"; - case HPACK_DECODER3: - return os << "HPACK_DECODER3"; - } - return os; -} - -typedef testing:: - tuple<QuicVersion, Perspective, Http2DecoderChoice, HpackDecoderChoice> - TestParamsTuple; +typedef testing::tuple<QuicVersion, Perspective> TestParamsTuple; struct TestParams { explicit TestParams(TestParamsTuple params) - : version(testing::get<0>(params)), - perspective(testing::get<1>(params)), - http2_decoder(testing::get<2>(params)), - hpack_decoder(testing::get<3>(params)) { - switch (http2_decoder) { - case HTTP2_DECODER_SPDY: - FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = false; - break; - case HTTP2_DECODER_NEW: - FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = true; - // Http2FrameDecoderAdapter needs the new header methods, else - // --use_http2_frame_decoder_adapter=true will be ignored. - break; - } - switch (hpack_decoder) { - case HPACK_DECODER_SPDY: - FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = false; - break; - case HPACK_DECODER3: - FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = true; - break; - } + : version(testing::get<0>(params)), perspective(testing::get<1>(params)) { QUIC_LOG(INFO) << "TestParams: version: " << QuicVersionToString(version) - << ", perspective: " << perspective - << ", http2_decoder: " << http2_decoder - << ", hpack_decoder: " << hpack_decoder; + << ", perspective: " << perspective; } QuicVersion version; Perspective perspective; - Http2DecoderChoice http2_decoder; - HpackDecoderChoice hpack_decoder; }; class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> { @@ -401,17 +349,13 @@ QuicStreamId next_stream_id_; }; -// Run all tests with each version, perspective (client or server), -// HTTP/2 and HPACK decoder. +// Run all tests with each version, perspective (client or server).. INSTANTIATE_TEST_CASE_P( Tests, QuicHeadersStreamTest, ::testing::Combine(::testing::ValuesIn(AllSupportedVersions()), ::testing::Values(Perspective::IS_CLIENT, - Perspective::IS_SERVER), - ::testing::Values(HTTP2_DECODER_SPDY, - HTTP2_DECODER_NEW), - ::testing::Values(HPACK_DECODER_SPDY, HPACK_DECODER3))); + Perspective::IS_SERVER))); TEST_P(QuicHeadersStreamTest, StreamId) { EXPECT_EQ(3u, headers_stream_->id());
diff --git a/net/spdy/chromium/spdy_flags.cc b/net/spdy/chromium/spdy_flags.cc index b2c279b..ba57f7a 100644 --- a/net/spdy/chromium/spdy_flags.cc +++ b/net/spdy/chromium/spdy_flags.cc
@@ -6,16 +6,6 @@ namespace net { -// Log compressed size of HTTP/2 requests. -bool FLAGS_chromium_http2_flag_log_compressed_size = true; - -// Use //net/http2/hpack/decoder as complete HPACK decoder. -bool FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = true; - -// Use Http2FrameDecoderAdapter. -// TODO(jamessynge): Remove flag once no longer set by scripts. -bool FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = true; - // Use NestedSpdyFramerDecoder. bool FLAGS_use_nested_spdy_framer_decoder = false;
diff --git a/net/spdy/chromium/spdy_flags.h b/net/spdy/chromium/spdy_flags.h index ab2907f..715331d 100644 --- a/net/spdy/chromium/spdy_flags.h +++ b/net/spdy/chromium/spdy_flags.h
@@ -9,11 +9,7 @@ namespace net { -NET_EXPORT_PRIVATE extern bool - FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3; NET_EXPORT_PRIVATE extern bool FLAGS_use_nested_spdy_framer_decoder; -NET_EXPORT_PRIVATE extern bool - FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter; } // namespace net
diff --git a/net/spdy/core/spdy_framer.cc b/net/spdy/core/spdy_framer.cc index fc131bb..68aee37 100644 --- a/net/spdy/core/spdy_framer.cc +++ b/net/spdy/core/spdy_framer.cc
@@ -20,7 +20,6 @@ #include "net/quic/platform/api/quic_flags.h" #include "net/spdy/chromium/spdy_flags.h" #include "net/spdy/core/hpack/hpack_constants.h" -#include "net/spdy/core/hpack/hpack_decoder.h" #include "net/spdy/core/hpack/hpack_decoder3.h" #include "net/spdy/core/http2_frame_decoder_adapter.h" #include "net/spdy/core/spdy_bitmasks.h" @@ -61,12 +60,8 @@ // used. This code is isolated to hopefully make merging into Chromium easier. std::unique_ptr<SpdyFramerDecoderAdapter> DecoderAdapterFactory( SpdyFramer* outer) { - if (FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter) { - DVLOG(1) << "Creating Http2FrameDecoderAdapter."; - return CreateHttp2FrameDecoderAdapter(outer); - } - - return nullptr; + DVLOG(1) << "Creating Http2FrameDecoderAdapter."; + return CreateHttp2FrameDecoderAdapter(outer); } // Used to indicate no flags in a HTTP2 flags field. @@ -2819,11 +2814,7 @@ HpackDecoderInterface* SpdyFramer::GetHpackDecoder() { if (hpack_decoder_.get() == nullptr) { - if (FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3) { - hpack_decoder_ = SpdyMakeUnique<HpackDecoder3>(); - } else { - hpack_decoder_ = SpdyMakeUnique<HpackDecoder>(); - } + hpack_decoder_ = SpdyMakeUnique<HpackDecoder3>(); } return hpack_decoder_.get(); }
diff --git a/net/spdy/core/spdy_framer_test.cc b/net/spdy/core/spdy_framer_test.cc index afcbc64..1002192f 100644 --- a/net/spdy/core/spdy_framer_test.cc +++ b/net/spdy/core/spdy_framer_test.cc
@@ -744,35 +744,15 @@ frame.size() - framer.GetHeadersMinimumSize()); } -enum DecoderChoice { DECODER_SELF, DECODER_HTTP2 }; -enum HpackChoice { HPACK_DECODER_1, HPACK_DECODER_3 }; enum Output { USE, NOT_USE }; -class SpdyFramerTest : public ::testing::TestWithParam< - std::tuple<DecoderChoice, HpackChoice, Output>> { +class SpdyFramerTest : public ::testing::TestWithParam<Output> { public: SpdyFramerTest() : output_(output_buffer, kSize) {} protected: void SetUp() override { - auto param = GetParam(); - switch (std::get<0>(param)) { - case DECODER_SELF: - FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = false; - break; - case DECODER_HTTP2: - FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = true; - break; - } - switch (std::get<1>(param)) { - case HPACK_DECODER_1: - FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = false; - break; - case HPACK_DECODER_3: - FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = true; - break; - } - switch (std::get<2>(param)) { + switch (GetParam()) { case USE: use_output_ = true; break; @@ -811,11 +791,7 @@ INSTANTIATE_TEST_CASE_P(SpdyFramerTests, SpdyFramerTest, - ::testing::Combine(::testing::Values(DECODER_SELF, - DECODER_HTTP2), - ::testing::Values(HPACK_DECODER_1, - HPACK_DECODER_3), - ::testing::Values(USE, NOT_USE))); + ::testing::Values(USE, NOT_USE)); // Test that we can encode and decode a SpdyHeaderBlock in serialized form. TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {
diff --git a/remoting/client/chromoting_session.cc b/remoting/client/chromoting_session.cc index ae7eda4..50e831e 100644 --- a/remoting/client/chromoting_session.cc +++ b/remoting/client/chromoting_session.cc
@@ -145,6 +145,12 @@ const std::string& device_name) { DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); + // TODO(nicholss): |pin| here is not used. Maybe there was an api refactor and + // this was not cleaned up. The auth pin providing mechanism seems to be call + // ProvideSecret, and then call the auth callback. When session moves to + // Connected state, this chromoing session calls RequestPairing based on + // create_pairing. + create_pairing_ = create_pairing; if (create_pairing)
diff --git a/remoting/ios/app/client_connection_view_controller.mm b/remoting/ios/app/client_connection_view_controller.mm index 272fc2f..ec589b0 100644 --- a/remoting/ios/app/client_connection_view_controller.mm +++ b/remoting/ios/app/client_connection_view_controller.mm
@@ -536,8 +536,12 @@ [[NSNotificationCenter defaultCenter] postNotificationName:kHostSessionPinProvided object:self - userInfo:[NSDictionary dictionaryWithObject:pin - forKey:kHostSessionPin]]; + userInfo:@{ + kHostSessionHostName : _remoteHostName, + kHostSessionPin : pin, + kHostSessionCreatePairing : + [NSNumber numberWithBool:createPairing] + }]; } - (void)didTapCancel:(id)sender { @@ -559,6 +563,8 @@ state = ClientViewConnecting; break; case SessionPinPrompt: + _pinEntryView.supportsPairing = [[[notification userInfo] + objectForKey:kSessionSupportsPairing] boolValue]; state = ClientViewPinPrompt; break; case SessionConnected: @@ -571,6 +577,9 @@ // If the session closes, offer the user to reconnect. state = ClientViewReconnect; break; + case SessionCancelled: + state = ClientViewClosed; + break; default: LOG(ERROR) << "Unknown State for Session, " << sessionDetails.state; return;
diff --git a/remoting/ios/app/pin_entry_view.h b/remoting/ios/app/pin_entry_view.h index 926831f..00c0551b 100644 --- a/remoting/ios/app/pin_entry_view.h +++ b/remoting/ios/app/pin_entry_view.h
@@ -26,6 +26,9 @@ // This delegate will handle interactions on the cells in the collection. @property(weak, nonatomic) id<PinEntryDelegate> delegate; +// |supportsPairing| false will hide the remember pin checkbox. +@property(nonatomic) BOOL supportsPairing; + @end #endif // REMOTING_IOS_APP_PIN_ENTRY_VIEW_H_
diff --git a/remoting/ios/app/pin_entry_view.mm b/remoting/ios/app/pin_entry_view.mm index 9037e0f..ee3c3ef 100644 --- a/remoting/ios/app/pin_entry_view.mm +++ b/remoting/ios/app/pin_entry_view.mm
@@ -28,6 +28,7 @@ @implementation PinEntryView @synthesize delegate = _delegate; +@synthesize supportsPairing = _supportsPairing; - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; @@ -82,6 +83,8 @@ initializeLayoutConstraintsWithViews:NSDictionaryOfVariableBindings( _pairingSwitch, _pairingLabel, _pinButton, _pinEntry)]; + + _supportsPairing = YES; } return self; } @@ -133,6 +136,15 @@ return [_pinEntry endEditing:force]; } +#pragma mark - Properties + +- (void)setSupportsPairing:(BOOL)supportsPairing { + _supportsPairing = supportsPairing; + _pairingSwitch.hidden = !_supportsPairing; + [_pairingSwitch setOn:NO animated:NO]; + _pairingLabel.hidden = !_supportsPairing; +} + #pragma mark - UITextFieldDelegate - (BOOL)textField:(UITextField*)textField
diff --git a/remoting/ios/domain/client_session_details.h b/remoting/ios/domain/client_session_details.h index ee839b8..b52f7df 100644 --- a/remoting/ios/domain/client_session_details.h +++ b/remoting/ios/domain/client_session_details.h
@@ -20,6 +20,7 @@ SessionConnected, SessionFailed, SessionClosed, + SessionCancelled, }; // Session states that map to |remoting::protocol::ConnectionToHost::Error|.
diff --git a/remoting/ios/facade/remoting_oauth_authentication.mm b/remoting/ios/facade/remoting_oauth_authentication.mm index 5c0045de..f5b93137 100644 --- a/remoting/ios/facade/remoting_oauth_authentication.mm +++ b/remoting/ios/facade/remoting_oauth_authentication.mm
@@ -93,7 +93,7 @@ - (instancetype)init { self = [super init]; if (self) { - _keychainWrapper = [[KeychainWrapper alloc] init]; + _keychainWrapper = KeychainWrapper.instance; _user = nil; _firstLoadUserAttempt = YES; }
diff --git a/remoting/ios/facade/remoting_service.mm b/remoting/ios/facade/remoting_service.mm index 79753a8..ba202b5 100644 --- a/remoting/ios/facade/remoting_service.mm +++ b/remoting/ios/facade/remoting_service.mm
@@ -168,7 +168,21 @@ [_authentication callbackWithAccessToken:^(RemotingAuthenticationStatus status, NSString* userEmail, NSString* accessToken) { - [self startHostListFetchWith:accessToken]; + switch (status) { + case RemotingAuthenticationStatusSuccess: + [self startHostListFetchWith:accessToken]; + break; + case RemotingAuthenticationStatusNetworkError: + NSLog( + @"TODO(nicholss): implement this, " + @"RemotingAuthenticationStatusNetworkError."); + break; + case RemotingAuthenticationStatusAuthError: + NSLog( + @"TODO(nicholss): implement this, " + @"RemotingAuthenticationStatusAuthError."); + break; + } }]; }
diff --git a/remoting/ios/keychain_wrapper.h b/remoting/ios/keychain_wrapper.h index e2cabbb4..51a57d0 100644 --- a/remoting/ios/keychain_wrapper.h +++ b/remoting/ios/keychain_wrapper.h
@@ -9,6 +9,12 @@ @class UserInfo; +extern NSString* const kKeychainPairingId; +extern NSString* const kKeychainPairingSecret; + +typedef void (^PairingCredentialsCallback)(NSString* pairingId, + NSString* secret); + // Class to abstract the details from how iOS wants to write to the keychain. // TODO(nicholss): This will have to be futher refactored when we integrate // with the private Google auth. @@ -18,9 +24,18 @@ - (void)setRefreshToken:(NSString*)refreshToken; // Get the refresh token from the keychain, if there is one. - (NSString*)refreshToken; +// Save the pairing credentials for the given host id. +- (void)commitPairingCredentialsForHost:(NSString*)host + id:(NSString*)pairingId + secret:(NSString*)secret; +// Get the pairing credentials for the given host id. +- (NSDictionary*)pairingCredentialsForHost:(NSString*)host; // Reset the keychain and the cache. - (void)resetKeychainItem; +// Access to the singleton shared instance from this property. +@property(nonatomic, readonly, class) KeychainWrapper* instance; + @end #endif // REMOTING_IOS_KEYCHAIN_WRAPPER_H_
diff --git a/remoting/ios/keychain_wrapper.mm b/remoting/ios/keychain_wrapper.mm index 1992e45..4e03b08 100644 --- a/remoting/ios/keychain_wrapper.mm +++ b/remoting/ios/keychain_wrapper.mm
@@ -8,10 +8,17 @@ #import "remoting/ios/keychain_wrapper.h" +#include "base/logging.h" + #import "remoting/ios/domain/host_info.h" static const UInt8 kKeychainItemIdentifier[] = "org.chromium.RemoteDesktop\0"; +NSString* const kPairingSecretSeperator = @"|"; + +NSString* const kKeychainPairingId = @"kKeychainPairingId"; +NSString* const kKeychainPairingSecret = @"kKeychainPairingSecret"; + @interface KeychainWrapper () { NSMutableDictionary* _keychainData; NSMutableDictionary* _userInfoQuery; @@ -20,6 +27,16 @@ @implementation KeychainWrapper +// KeychainWrapper is a singleton. ++ (KeychainWrapper*)instance { + static KeychainWrapper* sharedInstance = nil; + static dispatch_once_t guard; + dispatch_once(&guard, ^{ + sharedInstance = [[KeychainWrapper alloc] init]; + }); + return sharedInstance; +} + - (id)init { if ((self = [super init])) { OSStatus keychainErr = noErr; @@ -30,7 +47,7 @@ [NSData dataWithBytes:kKeychainItemIdentifier length:strlen((const char*)kKeychainItemIdentifier)]; [_userInfoQuery setObject:keychainItemID - forKey:(__bridge id)kSecAttrGeneric]; + forKey:(__bridge id)kSecAttrService]; [_userInfoQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; [_userInfoQuery setObject:(__bridge id)kCFBooleanTrue @@ -61,6 +78,8 @@ return self; } +#pragma mark - Public + - (void)setRefreshToken:(NSString*)refreshToken { [self setObject:refreshToken forKey:(__bridge id)kSecValueData]; } @@ -69,6 +88,74 @@ return [self objectForKey:(__bridge id)kSecValueData]; } +- (void)commitPairingCredentialsForHost:(NSString*)host + id:(NSString*)pairingId + secret:(NSString*)secret { + NSString* keysString = [self objectForKey:(__bridge id)kSecAttrGeneric]; + NSMutableDictionary* keys = [self stringToMap:keysString]; + NSString* pairingIdAndSecret = [NSString + stringWithFormat:@"%@%@%@", pairingId, kPairingSecretSeperator, secret]; + [keys setObject:pairingIdAndSecret forKey:host]; + [self setObject:[self mapToString:keys] forKey:(__bridge id)kSecAttrGeneric]; +} + +- (NSDictionary*)pairingCredentialsForHost:(NSString*)host { + NSString* keysString = [self objectForKey:(__bridge id)kSecAttrGeneric]; + NSMutableDictionary* keys = [self stringToMap:keysString]; + NSString* pairingIdAndSecret = [keys objectForKey:host]; + if (!pairingIdAndSecret || + [pairingIdAndSecret rangeOfString:kPairingSecretSeperator].location == + NSNotFound) { + return nil; + } + NSArray* components = + [pairingIdAndSecret componentsSeparatedByString:kPairingSecretSeperator]; + DCHECK(components.count == 2); + return @{ + kKeychainPairingId : components[0], + kKeychainPairingSecret : components[1], + }; +} + +#pragma mark - Map to String helpers + +- (NSMutableDictionary*)stringToMap:(NSString*)mapString { + NSError* err; + + if (mapString && + [mapString respondsToSelector:@selector(dataUsingEncoding:)]) { + NSData* data = [mapString dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary* pairingMap; + if (data) { + pairingMap = (NSDictionary*)[NSJSONSerialization + JSONObjectWithData:data + options:NSJSONReadingMutableContainers + error:&err]; + } + if (!err) { + return [NSMutableDictionary dictionaryWithDictionary:pairingMap]; + } + } + // failed to load a dictionary, make a new one. + return [NSMutableDictionary dictionaryWithCapacity:1]; +} + +- (NSString*)mapToString:(NSDictionary*)map { + if (map) { + NSError* err; + NSData* jsonData = + [NSJSONSerialization dataWithJSONObject:map options:0 error:&err]; + if (!err) { + return [[NSString alloc] initWithData:jsonData + encoding:NSUTF8StringEncoding]; + } + } + // failed to convert the map, make nil string. + return nil; +} + +#pragma mark - Private + // Implement the mySetObject:forKey method, which writes attributes to the // keychain: - (void)setObject:(id)inObject forKey:(id)key { @@ -106,6 +193,8 @@ [_keychainData setObject:@"Gaia fresh token" forKey:(__bridge id)kSecAttrDescription]; [_keychainData setObject:@"" forKey:(__bridge id)kSecValueData]; + [_keychainData setObject:@"" forKey:(__bridge id)kSecClass]; + [_keychainData setObject:@"" forKey:(__bridge id)kSecAttrGeneric]; } - (NSMutableDictionary*)dictionaryToSecItemFormat: @@ -117,7 +206,7 @@ [NSData dataWithBytes:kKeychainItemIdentifier length:strlen((const char*)kKeychainItemIdentifier)]; [returnDictionary setObject:keychainItemID - forKey:(__bridge id)kSecAttrGeneric]; + forKey:(__bridge id)kSecAttrService]; [returnDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
diff --git a/remoting/ios/session/remoting_client.h b/remoting/ios/session/remoting_client.h index b8dd100f..817ce146 100644 --- a/remoting/ios/session/remoting_client.h +++ b/remoting/ios/session/remoting_client.h
@@ -30,7 +30,11 @@ // List of keys in user info from events. extern NSString* const kSessionDetails; +extern NSString* const kSessionSupportsPairing; extern NSString* const kSessonStateErrorCode; + +extern NSString* const kHostSessionCreatePairing; +extern NSString* const kHostSessionHostName; extern NSString* const kHostSessionPin; // Remoting Client is the entry point for starting a session with a remote
diff --git a/remoting/ios/session/remoting_client.mm b/remoting/ios/session/remoting_client.mm index 3154bdc..10e6844 100644 --- a/remoting/ios/session/remoting_client.mm +++ b/remoting/ios/session/remoting_client.mm
@@ -12,9 +12,11 @@ #import "base/mac/bind_objc_block.h" #import "ios/third_party/material_components_ios/src/components/Dialogs/src/MaterialDialogs.h" +#import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h" #import "remoting/ios/display/gl_display_handler.h" #import "remoting/ios/domain/client_session_details.h" #import "remoting/ios/domain/host_info.h" +#import "remoting/ios/keychain_wrapper.h" #include "base/strings/sys_string_conversions.h" #include "remoting/client/chromoting_client_runtime.h" @@ -31,7 +33,11 @@ NSString* const kHostSessionPinProvided = @"kHostSessionPinProvided"; NSString* const kSessionDetails = @"kSessionDetails"; +NSString* const kSessionSupportsPairing = @"kSessionSupportsPairing"; NSString* const kSessonStateErrorCode = @"kSessonStateErrorCode"; + +NSString* const kHostSessionCreatePairing = @"kHostSessionCreatePairing"; +NSString* const kHostSessionHostName = @"kHostSessionHostName"; NSString* const kHostSessionPin = @"kHostSessionPin"; @interface RemotingClient () { @@ -91,10 +97,18 @@ info.host_os = base::SysNSStringToUTF8(hostInfo.hostOs); info.host_os_version = base::SysNSStringToUTF8(hostInfo.hostOsVersion); info.host_version = base::SysNSStringToUTF8(hostInfo.hostVersion); - // TODO(nicholss): If iOS supports pairing, pull the stored data and - // insert it here. - info.pairing_id = ""; - info.pairing_secret = ""; + + NSDictionary* pairing = + [KeychainWrapper.instance pairingCredentialsForHost:hostInfo.hostId]; + if (pairing) { + info.pairing_id = + base::SysNSStringToUTF8([pairing objectForKey:kKeychainPairingId]); + info.pairing_secret = + base::SysNSStringToUTF8([pairing objectForKey:kKeychainPairingSecret]); + } else { + info.pairing_id = ""; + info.pairing_secret = ""; + } // TODO(nicholss): I am not sure about the following fields yet. // info.capabilities = @@ -120,10 +134,11 @@ [[NSNotificationCenter defaultCenter] postNotificationName:kHostSessionStatusChanged object:weakSelf - userInfo:[NSDictionary - dictionaryWithObject:strongSelf - ->_sessionDetails - forKey:kSessionDetails]]; + userInfo:@{ + kSessionDetails : strongSelf->_sessionDetails, + kSessionSupportsPairing : + [NSNumber numberWithBool:pairing_supported], + }]; }); // TODO(nicholss): Add audio support to iOS. @@ -164,6 +179,18 @@ - (void)hostSessionPinProvided:(NSNotification*)notification { NSString* pin = [[notification userInfo] objectForKey:kHostSessionPin]; + NSString* name = UIDevice.currentDevice.name; + BOOL createPairing = [[[notification userInfo] + objectForKey:kHostSessionCreatePairing] boolValue]; + + // TODO(nicholss): Look into refactoring ProvideSecret. It is mis-named and + // does not use pin. + if (_session) { + _session->ProvideSecret(base::SysNSStringToUTF8(pin), + (createPairing == YES), + base::SysNSStringToUTF8(name)); + } + if (_secretFetchedCallback) { remoting::protocol::SecretFetchedCallback callback = _secretFetchedCallback; _runtime->network_task_runner()->PostTask( @@ -267,13 +294,26 @@ - (void)commitPairingCredentialsForHost:(NSString*)host id:(NSString*)id secret:(NSString*)secret { - NSLog(@"TODO(nicholss): implement this, commitPairingCredentialsForHost."); + [KeychainWrapper.instance commitPairingCredentialsForHost:host + id:id + secret:secret]; } - (void)fetchThirdPartyTokenForUrl:(NSString*)tokenUrl clientId:(NSString*)clientId scope:(NSString*)scope { - NSLog(@"TODO(nicholss): implement this, fetchThirdPartyTokenForUrl."); + // Not supported for iOS yet. + _sessionDetails.state = SessionCancelled; + [self disconnectFromHost]; + NSString* message = [NSString + stringWithFormat:@"[ThirdPartyAuth] Unable to authenticate with %@.", + _sessionDetails.hostInfo.hostName]; + [MDCSnackbarManager showMessage:[MDCSnackbarMessage messageWithText:message]]; + [[NSNotificationCenter defaultCenter] + postNotificationName:kHostSessionStatusChanged + object:self + userInfo:[NSDictionary dictionaryWithObject:_sessionDetails + forKey:kSessionDetails]]; } - (void)setCapabilities:(NSString*)capabilities {
diff --git a/services/ui/gpu/gpu_service.cc b/services/ui/gpu/gpu_service.cc index d466940..777a29a 100644 --- a/services/ui/gpu/gpu_service.cc +++ b/services/ui/gpu/gpu_service.cc
@@ -429,13 +429,13 @@ gpu_channel_manager_->RemoveChannel(client_id); } -void GpuService::LoadedShader(const std::string& data) { +void GpuService::LoadedShader(const std::string& key, const std::string& data) { if (io_runner_->BelongsToCurrentThread()) { main_runner_->PostTask( - FROM_HERE, base::Bind(&GpuService::LoadedShader, weak_ptr_, data)); + FROM_HERE, base::Bind(&GpuService::LoadedShader, weak_ptr_, key, data)); return; } - gpu_channel_manager_->PopulateShaderCache(data); + gpu_channel_manager_->PopulateShaderCache(key, data); } void GpuService::DestroyingVideoSurface(
diff --git a/services/ui/gpu/gpu_service.h b/services/ui/gpu/gpu_service.h index def7f70..e92a25a 100644 --- a/services/ui/gpu/gpu_service.h +++ b/services/ui/gpu/gpu_service.h
@@ -153,7 +153,7 @@ const GetVideoMemoryUsageStatsCallback& callback) override; void RequestCompleteGpuInfo( const RequestCompleteGpuInfoCallback& callback) override; - void LoadedShader(const std::string& data) override; + void LoadedShader(const std::string& key, const std::string& data) override; void DestroyingVideoSurface( int32_t surface_id, const DestroyingVideoSurfaceCallback& callback) override;
diff --git a/services/ui/gpu/interfaces/gpu_service.mojom b/services/ui/gpu/interfaces/gpu_service.mojom index b4020f6..2bf2abd 100644 --- a/services/ui/gpu/interfaces/gpu_service.mojom +++ b/services/ui/gpu/interfaces/gpu_service.mojom
@@ -47,8 +47,10 @@ RequestCompleteGpuInfo() => (gpu.mojom.GpuInfo gpu_info); - // Notify GPU that a shader was loaded from disk. - LoadedShader(string data); + // Notify GPU that a shader program was loaded from disk. Key is an + // SHA-1 hash, and data a binary blob with serialized program info. + // Note that this method is used only from a trusted process. + LoadedShader(string key, string data); // Tells GPU to release the surface because it's being destroyed. DestroyingVideoSurface(int32 surface_id) => ();
diff --git a/testing/scripts/run_telemetry_benchmark_as_googletest.py b/testing/scripts/run_telemetry_benchmark_as_googletest.py index cadb30bd..a1343b3 100755 --- a/testing/scripts/run_telemetry_benchmark_as_googletest.py +++ b/testing/scripts/run_telemetry_benchmark_as_googletest.py
@@ -66,6 +66,8 @@ failures = [] chartjson_results_present = '--output-format=chartjson' in rest_args chartresults = None + json_test_results_present = '--output-format=json-test-results' in rest_args + json_test_results = None results = None try: @@ -97,6 +99,11 @@ failures.append(name) valid = bool(rc == 0 or failures) + if json_test_results_present: + tempfile_name = os.path.join(tempfile_dir, 'test-results.json') + with open(tempfile_name) as f: + json_test_results = json.load(f) + except Exception: traceback.print_exc() if results: @@ -116,10 +123,13 @@ open(args.isolated_script_test_chartjson_output, 'w') json.dump(chartresults, chartjson_output_file) - json.dump({ - 'valid': valid, - 'failures': failures - }, args.isolated_script_test_output) + if not json_test_results_present: + json_test_results = { + 'valid': valid, + 'failures': failures + } + + json.dump(json_test_results, args.isolated_script_test_output) return rc finally:
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService index 3c5589f3..f6abf57a 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -1856,8 +1856,8 @@ Bug(none) http/tests/appcache/offline-access.html [ Timeout ] Bug(none) http/tests/appcache/online-fallback-layering.html [ Timeout ] Bug(none) http/tests/appcache/online-whitelist.html [ Failure ] -Bug(none) http/tests/appcache/reload.html [ Failure Timeout ] -Bug(none) http/tests/appcache/remove-cache.html [ Timeout ] +Bug(none) http/tests/appcache/reload.html [ Crash Failure Timeout ] +Bug(none) http/tests/appcache/remove-cache.html [ Crash Failure Timeout ] Bug(none) http/tests/appcache/simple.html [ Timeout ] Bug(none) http/tests/appcache/top-frame-1.html [ Timeout ] Bug(none) http/tests/appcache/top-frame-2.html [ Timeout ] @@ -2055,30 +2055,30 @@ Bug(none) http/tests/fetch/serviceworker/thorough/scheme-data-base-https-other-https.html [ Timeout ] Bug(none) http/tests/fetch/serviceworker/thorough/scheme-data-other-https.html [ Timeout ] Bug(none) http/tests/fetch/serviceworker/thorough/scheme-data.html [ Timeout ] -Bug(none) http/tests/fetch/window/block-mixed-content-base-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/block-mixed-content-nocors-base-https.html [ Timeout ] +Bug(none) http/tests/fetch/window/block-mixed-content-base-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/block-mixed-content-nocors-base-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/body-mixin-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/body-mixin.html [ Failure ] -Bug(none) http/tests/fetch/window/cache-override-base-https-other-https.html [ Timeout ] +Bug(none) http/tests/fetch/window/body-mixin.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/cache-override-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/fetch-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/fetch.html [ Failure ] -Bug(none) http/tests/fetch/window/filtered-response-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/filtered-response-other-https.html [ Failure ] -Bug(none) http/tests/fetch/window/headers-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/headers-guard-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/referrer-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/request-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/request.html [ Failure ] -Bug(none) http/tests/fetch/window/response-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/response-content-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/response-content.html [ Failure ] -Bug(none) http/tests/fetch/window/response.html [ Failure ] +Bug(none) http/tests/fetch/window/fetch.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/filtered-response-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/filtered-response-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/headers-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/headers-guard-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/referrer-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/request-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/request.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/response-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/response-content-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/response-content.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/response.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/stream-reader-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/stream-reader.html [ Failure ] +Bug(none) http/tests/fetch/window/stream-reader.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/access-control-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/thorough/access-control.html [ Timeout ] +Bug(none) http/tests/fetch/window/thorough/access-control.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/auth-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/thorough/auth-nocors-base-https-other-https.html [ Timeout ] +Bug(none) http/tests/fetch/window/thorough/auth-nocors-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/auth-nocors-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/auth-nocors.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/auth-other-https.html [ Failure Timeout ] @@ -2089,65 +2089,65 @@ Bug(none) http/tests/fetch/window/thorough/cookie-nocors.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/cookie-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/cookie.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/thorough/cors-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/cors-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/cors-preflight-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/cors-preflight-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/cors-preflight.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/cors-preflight2-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/cors-preflight2-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/cors-preflight2.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/cors.html [ Timeout ] +Bug(none) http/tests/fetch/window/thorough/cors-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/cors-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/cors-preflight-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/cors-preflight-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/cors-preflight.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/cors-preflight2-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/cors-preflight2-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/cors-preflight2.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/cors.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/nocors-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/thorough/nocors-other-https.html [ Timeout ] +Bug(none) http/tests/fetch/window/thorough/nocors-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/nocors.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/redirect-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/redirect-credentials-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/redirect-credentials-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/redirect-credentials.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/thorough/redirect-loop-base-https-other-https.html [ Timeout ] +Bug(none) http/tests/fetch/window/thorough/redirect-loop-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/redirect-loop-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/thorough/redirect-loop.html [ Timeout ] +Bug(none) http/tests/fetch/window/thorough/redirect-loop.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/redirect-nocors-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/redirect-nocors-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/redirect-nocors.html [ Failure Timeout ] Bug(none) http/tests/fetch/window/thorough/redirect-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/window/thorough/redirect-password-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/redirect-password-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/redirect-password.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/redirect.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/scheme-blob-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/scheme-blob-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/scheme-blob.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/scheme-data-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/scheme-data-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/window/thorough/scheme-data.html [ Timeout ] -Bug(none) http/tests/fetch/workers/block-mixed-content-base-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/block-mixed-content-nocors-base-https.html [ Timeout ] +Bug(none) http/tests/fetch/window/thorough/redirect-password-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/redirect-password-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/redirect-password.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/redirect.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/scheme-blob-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/scheme-blob-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/scheme-blob.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/scheme-data-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/scheme-data-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/window/thorough/scheme-data.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/block-mixed-content-base-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/block-mixed-content-nocors-base-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/body-mixin-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/workers/body-mixin.html [ Failure ] -Bug(none) http/tests/fetch/workers/cache-override-base-https-other-https.html [ Timeout ] +Bug(none) http/tests/fetch/workers/body-mixin.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/cache-override-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/fetch-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/workers/fetch.html [ Failure ] -Bug(none) http/tests/fetch/workers/filtered-response-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/filtered-response-other-https.html [ Failure ] -Bug(none) http/tests/fetch/workers/headers-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/headers-guard-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/referrer-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/request-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/request.html [ Failure ] -Bug(none) http/tests/fetch/workers/response-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/response-content-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/response-content.html [ Failure ] -Bug(none) http/tests/fetch/workers/response.html [ Failure ] +Bug(none) http/tests/fetch/workers/fetch.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/filtered-response-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/filtered-response-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/headers-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/headers-guard-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/referrer-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/request-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/request.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/response-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/response-content-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/response-content.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/response.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/stream-reader-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/workers/stream-reader.html [ Failure ] -Bug(none) http/tests/fetch/workers/thorough/access-control-base-https-other-https.html [ Timeout ] +Bug(none) http/tests/fetch/workers/stream-reader.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/access-control-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/access-control.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/auth-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/workers/thorough/auth-nocors-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/auth-nocors-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/auth-nocors.html [ Timeout ] +Bug(none) http/tests/fetch/workers/thorough/auth-nocors-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/auth-nocors-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/auth-nocors.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/auth-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/auth.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/cookie-base-https-other-https.html [ Failure Timeout ] @@ -2156,39 +2156,39 @@ Bug(none) http/tests/fetch/workers/thorough/cookie-nocors.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/cookie-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/cookie.html [ Failure Timeout ] -Bug(none) http/tests/fetch/workers/thorough/cors-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/cors-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/cors-preflight-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/cors-preflight-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/cors-preflight.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/cors-preflight2-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/cors-preflight2-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/cors-preflight2.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/cors.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/nocors-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/nocors-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/nocors.html [ Timeout ] +Bug(none) http/tests/fetch/workers/thorough/cors-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/cors-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/cors-preflight-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/cors-preflight-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/cors-preflight.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/cors-preflight2-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/cors-preflight2-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/cors-preflight2.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/cors.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/nocors-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/nocors-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/nocors.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/redirect-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/redirect-credentials-base-https-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/redirect-credentials-other-https.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/redirect-credentials.html [ Failure Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect-loop-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect-loop-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect-loop.html [ Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect-loop-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect-loop-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect-loop.html [ Failure Timeout ] Bug(none) http/tests/fetch/workers/thorough/redirect-nocors-base-https-other-https.html [ Failure Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect-nocors-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect-nocors.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect-password-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect-password-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect-password.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/redirect.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/scheme-blob-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/scheme-blob-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/scheme-blob.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/scheme-data-base-https-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/scheme-data-other-https.html [ Timeout ] -Bug(none) http/tests/fetch/workers/thorough/scheme-data.html [ Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect-nocors-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect-nocors.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect-password-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect-password-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect-password.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/redirect.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/scheme-blob-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/scheme-blob-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/scheme-blob.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/scheme-data-base-https-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/scheme-data-other-https.html [ Failure Timeout ] +Bug(none) http/tests/fetch/workers/thorough/scheme-data.html [ Failure Timeout ] Bug(none) http/tests/fileapi/blob-url-in-subframe.html [ Crash Timeout ] Bug(none) http/tests/history/post-replace-state-reload.html [ Failure ] Bug(none) http/tests/history/push-state-in-new-frame.html [ Timeout ] @@ -2291,7 +2291,7 @@ Bug(none) http/tests/media/video-controls-overflow-menu-download-button.html [ Timeout ] Bug(none) http/tests/media/video-cookie.html [ Timeout ] Bug(none) http/tests/media/video-error-abort.html [ Timeout ] -Bug(none) http/tests/media/video-in-iframe-crash.html [ Crash ] +Bug(none) http/tests/media/video-in-iframe-crash.html [ Crash Timeout ] Bug(none) http/tests/media/video-load-metadata-decode-error.html [ Timeout ] Bug(none) http/tests/media/video-load-suspend.html [ Timeout ] Bug(none) http/tests/media/video-load-twice.html [ Timeout ] @@ -2723,7 +2723,7 @@ Bug(none) inspector/console/console-log-short-hand-method.html [ Failure ] Bug(none) inspector/console/console-object-constructor-name.html [ Failure ] Bug(none) inspector/console/console-tests.html [ Failure ] -Bug(none) inspector/console/console-uncaught-promise.html [ Failure ] +Bug(none) inspector/console/console-uncaught-promise.html [ Failure Timeout ] Bug(none) inspector/coverage/coverage-repeated.html [ Failure Timeout ] Bug(none) inspector/coverage/coverage-view-filter.html [ Failure ] Bug(none) inspector/coverage/coverage-view.html [ Failure Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index b9e4821..36156a8 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -92,9 +92,6 @@ crbug.com/693568 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality.html [ Failure ] -# Can be broken into smaller tests, probably. -crbug.com/709009 virtual/gpu/fast/canvas/getPutImageDataPairTest.html [ Timeout Pass ] - # Looks like a filuare to get a paint on time. Test could be changed to use runAfterLayoutAndPaint # instead of a timeout, which may fix things. crbug.com/713049 images/color-profile-reflection.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/animations/font-size-using-ems.html b/third_party/WebKit/LayoutTests/animations/font-size-using-ems.html-disabled similarity index 100% rename from third_party/WebKit/LayoutTests/animations/font-size-using-ems.html rename to third_party/WebKit/LayoutTests/animations/font-size-using-ems.html-disabled
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/aes-cbc/decrypt-failures-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/aes-cbc/decrypt-failures-expected.txt index c2e4a20..ce29588 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/aes-cbc/decrypt-failures-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/aes-cbc/decrypt-failures-expected.txt
@@ -4,19 +4,19 @@ PASS: Decryption succeeded -error is: OperationError: +error is: OperationError PASS: decrypting failed. ciphertext length: 0 -error is: OperationError: +error is: OperationError PASS: decrypting failed. ciphertext length: 79 -error is: OperationError: +error is: OperationError PASS: decrypting failed. ciphertext length: 64 -error is: OperationError: +error is: OperationError PASS: decrypting failed. ciphertext length: 1 -error is: OperationError: +error is: OperationError PASS: decrypting failed. ciphertext length: 15 -error is: OperationError: +error is: OperationError PASS: decrypting failed. ciphertext length: 16 -error is: OperationError: +error is: OperationError PASS: decrypting failed. ciphertext length: 17 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/ecdh/import-export-raw-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/ecdh/import-export-raw-expected.txt index f5abcf0cf..9ef69a168 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/ecdh/import-export-raw-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/ecdh/import-export-raw-expected.txt
@@ -20,7 +20,7 @@ Exporting to raw... PASS: Exported to raw should be [044ea34391aa73885454bc45df3fdcc4a70262fa4621ffe25b5790590c340a4bd9265ef2b3f9a86e2959a960d90323465d60cd4a90d314c5de3f869ad0d4bf6c10] and was Importing invalid raw public key... -error is: DataError: +error is: DataError PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/rsa-oaep/plaintext-length-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/rsa-oaep/plaintext-length-expected.txt index 11f3ffd..6b6d992 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/rsa-oaep/plaintext-length-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/rsa-oaep/plaintext-length-expected.txt
@@ -7,7 +7,7 @@ Encrypting a 214 byte buffer with RSA-OAEP SHA-1, 2048 bit key... PASS Succeeded Encrypting a 215 byte buffer... -error is: OperationError: +error is: OperationError PASS Rejected PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/css-parser/line-break-values.html b/third_party/WebKit/LayoutTests/css-parser/line-break-values.html new file mode 100644 index 0000000..40c9493e --- /dev/null +++ b/third_party/WebKit/LayoutTests/css-parser/line-break-values.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script> +test(function() { + assert_true(CSS.supports("-webkit-line-break", "auto")); + assert_true(CSS.supports("-webkit-line-break", "loose")); + assert_true(CSS.supports("-webkit-line-break", "normal")); + assert_true(CSS.supports("-webkit-line-break", "strict")); +}, '-webkit-line-break accepts valid keyword properties.'); + +test(function() { + assert_true(CSS.supports("-webkit-line-break", "after-white-space")); +}, '-webkit-line-break accepts the value after-white-space.'); + +test(function() { + assert_false(CSS.supports("-webkit-line-break", "bogus")); +}, '-webkit-line-break does not except obviously invalid values.'); + +test(function() { + assert_true(CSS.supports("line-break", "auto")); + assert_true(CSS.supports("line-break", "loose")); + assert_true(CSS.supports("line-break", "normal")); + assert_true(CSS.supports("line-break", "strict")); +}, 'line-break accepts valid keyword properties.'); + +test(function() { + assert_false(CSS.supports("line-break", "after-white-space")); +}, 'line-break does not accept the value after-white-space.'); + +test(function() { + assert_false(CSS.supports("line-break", "bogus")); +}, 'line-break does not except obviously invalid values.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json index 92f98e3..85a7079e 100644 --- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json +++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -32381,6 +32381,150 @@ {} ] ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-001.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-001.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-002.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-002.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-003.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-003.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-004.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-004.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-005.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-005.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-006.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-006.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-007.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-007.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-008.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-008.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-009.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-009.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html": [ + [ + "/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "css/css-grid-1/grid-definition/fr-unit-with-percentage.html": [ [ "/css/css-grid-1/grid-definition/fr-unit-with-percentage.html", @@ -57701,6 +57845,66 @@ {} ] ], + "cssom-view/scrollingElement-quirks-dynamic-001.html": [ + [ + "/cssom-view/scrollingElement-quirks-dynamic-001.html", + [ + [ + "/cssom-view/scrollingElement-quirks-dynamic-001-ref.html", + "==" + ] + ], + {} + ] + ], + "cssom-view/scrollingElement-quirks-dynamic-002.html": [ + [ + "/cssom-view/scrollingElement-quirks-dynamic-002.html", + [ + [ + "/cssom-view/scrollingElement-quirks-dynamic-002-ref.html", + "==" + ] + ], + {} + ] + ], + "fonts/variations/variable-box-font.html": [ + [ + "/fonts/variations/variable-box-font.html", + [ + [ + "/fonts/variations/variable-box-font-ref.html", + "==" + ] + ], + {} + ] + ], + "fonts/variations/variable-gpos-m2b.html": [ + [ + "/fonts/variations/variable-gpos-m2b.html", + [ + [ + "/fonts/variations/variable-gpos-m2b-ref.html", + "==" + ] + ], + {} + ] + ], + "fonts/variations/variable-gsub.html": [ + [ + "/fonts/variations/variable-gsub.html", + [ + [ + "/fonts/variations/variable-gsub-ref.html", + "==" + ] + ], + {} + ] + ], "html/dom/elements/global-attributes/dir_auto-EN-L.html": [ [ "/html/dom/elements/global-attributes/dir_auto-EN-L.html", @@ -59405,6 +59609,18 @@ {} ] ], + "html/rendering/non-replaced-elements/tables/table-direction.html": [ + [ + "/html/rendering/non-replaced-elements/tables/table-direction.html", + [ + [ + "/html/rendering/non-replaced-elements/tables/table-direction-ref.html", + "==" + ] + ], + {} + ] + ], "html/rendering/non-replaced-elements/tables/table-layout.html": [ [ "/html/rendering/non-replaced-elements/tables/table-layout.html", @@ -59417,6 +59633,30 @@ {} ] ], + "html/rendering/non-replaced-elements/tables/table-row-direction.html": [ + [ + "/html/rendering/non-replaced-elements/tables/table-row-direction.html", + [ + [ + "/html/rendering/non-replaced-elements/tables/table-row-direction-ref.html", + "==" + ] + ], + {} + ] + ], + "html/rendering/non-replaced-elements/tables/table-row-group-direction.html": [ + [ + "/html/rendering/non-replaced-elements/tables/table-row-group-direction.html", + [ + [ + "/html/rendering/non-replaced-elements/tables/table-row-group-direction-ref.html", + "==" + ] + ], + {} + ] + ], "html/rendering/non-replaced-elements/tables/table-width-150percent.html": [ [ "/html/rendering/non-replaced-elements/tables/table-width-150percent.html", @@ -66359,11 +66599,6 @@ {} ] ], - "WebIDL/ecmascript-binding/es-exceptions/exceptions-expected.txt": [ - [ - {} - ] - ], "WebIDL/ecmascript-binding/interface-prototype-object-expected.txt": [ [ {} @@ -83744,6 +83979,16 @@ {} ] ], + "cssom-view/scrollingElement-quirks-dynamic-001-ref.html": [ + [ + {} + ] + ], + "cssom-view/scrollingElement-quirks-dynamic-002-ref.html": [ + [ + {} + ] + ], "cssom-view/support/1x1-green.png": [ [ {} @@ -84379,6 +84624,11 @@ {} ] ], + "dom/interfaces-expected.txt": [ + [ + {} + ] + ], "dom/lists/DOMTokenList-coverage-for-attributes-expected.txt": [ [ {} @@ -86919,6 +87169,26 @@ {} ] ], + "fonts/variations/resources/variabletest_box.ttf": [ + [ + {} + ] + ], + "fonts/variations/variable-box-font-ref.html": [ + [ + {} + ] + ], + "fonts/variations/variable-gpos-m2b-ref.html": [ + [ + {} + ] + ], + "fonts/variations/variable-gsub-ref.html": [ + [ + {} + ] + ], "fullscreen/api/document-exit-fullscreen-active-document-expected.txt": [ [ {} @@ -87004,6 +87274,11 @@ {} ] ], + "hr-time/idlharness-expected.txt": [ + [ + {} + ] + ], "hr-time/resources/now_frame.html": [ [ {} @@ -94924,6 +95199,11 @@ {} ] ], + "html/rendering/non-replaced-elements/tables/table-direction-ref.html": [ + [ + {} + ] + ], "html/rendering/non-replaced-elements/tables/table-layout-notref.html": [ [ {} @@ -94934,6 +95214,16 @@ {} ] ], + "html/rendering/non-replaced-elements/tables/table-row-direction-ref.html": [ + [ + {} + ] + ], + "html/rendering/non-replaced-elements/tables/table-row-group-direction-ref.html": [ + [ + {} + ] + ], "html/rendering/non-replaced-elements/tables/table-width-150percent-ref.html": [ [ {} @@ -100684,7 +100974,12 @@ {} ] ], - "payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub-expected.txt": [ + "payment-request/allowpaymentrequest/removing-allowpaymentrequest.https.sub-expected.txt": [ + [ + {} + ] + ], + "payment-request/allowpaymentrequest/setting-allowpaymentrequest.https.sub-expected.txt": [ [ {} ] @@ -100704,6 +100999,11 @@ {} ] ], + "payment-request/payment-request-canmakepayment-method.https-expected.txt": [ + [ + {} + ] + ], "payment-request/payment-request-response-id.html": [ [ {} @@ -100724,6 +101024,11 @@ {} ] ], + "performance-timeline/idlharness-expected.txt": [ + [ + {} + ] + ], "performance-timeline/performanceobservers.js": [ [ {} @@ -103584,6 +103889,11 @@ {} ] ], + "resource-timing/idlharness-expected.txt": [ + [ + {} + ] + ], "resource-timing/iframe-setdomain.sub.html": [ [ {} @@ -106384,6 +106694,11 @@ {} ] ], + "url/urlsearchparams-delete-expected.txt": [ + [ + {} + ] + ], "url/urlsearchparams-foreach-expected.txt": [ [ {} @@ -106639,11 +106954,26 @@ {} ] ], + "web-share/idlharness.https-expected.txt": [ + [ + {} + ] + ], "web-share/resources/manual-helper.js": [ [ {} ] ], + "web-share/share-empty.https-expected.txt": [ + [ + {} + ] + ], + "web-share/share-without-user-gesture.https-expected.txt": [ + [ + {} + ] + ], "webaudio/.gitignore": [ [ {} @@ -106894,6 +107224,11 @@ {} ] ], + "webrtc/RTCConfiguration-bundlePolicy-expected.txt": [ + [ + {} + ] + ], "webrtc/RTCConfiguration-iceCandidatePoolSize-expected.txt": [ [ {} @@ -106954,6 +107289,11 @@ {} ] ], + "webrtc/RTCPeerConnection-getDefaultIceServers-expected.txt": [ + [ + {} + ] + ], "webrtc/RTCPeerConnection-getTransceivers-expected.txt": [ [ {} @@ -106999,6 +107339,11 @@ {} ] ], + "webrtc/RTCRtpTransceiver-setDirection-expected.txt": [ + [ + {} + ] + ], "webrtc/RTCSctpTransport-constructor-expected.txt": [ [ {} @@ -160690,6 +161035,12 @@ {} ] ], + "shadow-dom/slotchange-customelements.html": [ + [ + "/shadow-dom/slotchange-customelements.html", + {} + ] + ], "shadow-dom/slotchange-event.html": [ [ "/shadow-dom/slotchange-event.html", @@ -178395,10 +178746,6 @@ "f20cbaff1efb774748241b90778a0964f5671fee", "testharness" ], - "WebIDL/ecmascript-binding/es-exceptions/exceptions-expected.txt": [ - "483ec81bab319fb4e50f4cdc5b1e8bb170e11d64", - "support" - ], "WebIDL/ecmascript-binding/es-exceptions/exceptions.html": [ "fc4d6cf93ff64192ee325d7309ac267cf8ff5d6c", "testharness" @@ -200395,6 +200742,54 @@ "749d78928a228bb67878b3c088d36bcfd010aa08", "testharness" ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-001.html": [ + "afb6c282b7e952878c52c198579541ddca6afdb6", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-002.html": [ + "67a739c055f22f9de478d7d62a56bb9e65415cfb", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-003.html": [ + "3ccf5136030949e11a305349d317af193fe4f0ff", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-004.html": [ + "30a0be3371587b0871bbc480aa7e7098c4bc51e6", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-005.html": [ + "b4782cea1a8ec242087271555d55bae0f574fa91", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-006.html": [ + "c6a597f7e720491cd09ba3007cc50234639cdc33", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-007.html": [ + "2593b5f169c3fd0778cda370821572057ae25f0d", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-008.html": [ + "0eb8c0b70ff376de7608cb843838ea35556bef08", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-009.html": [ + "bc146287841851768ff6040e5fbc1d829677413e", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html": [ + "2fe23a2f58c96b29b8741e35ca77b856431c5d19", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html": [ + "83b810467e538bb0b8982224e2008aef0f48e84a", + "reftest" + ], + "css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html": [ + "1b2f571a79fe01b247ade6d6ea8514c7b46e2fd6", + "reftest" + ], "css/css-grid-1/grid-definition/fr-unit-with-percentage.html": [ "e29ef66eb632f1f9834df3233f741fb51fed5eea", "reftest" @@ -218799,6 +219194,22 @@ "a799c737e7962865c3ed3e380a664cafe97dcfe8", "testharness" ], + "cssom-view/scrollingElement-quirks-dynamic-001-ref.html": [ + "61f1de81876db66564e3edb8945312ed213d0b30", + "support" + ], + "cssom-view/scrollingElement-quirks-dynamic-001.html": [ + "2bc3eee1754a051874ae5e8e229c661d7d8a9c1f", + "reftest" + ], + "cssom-view/scrollingElement-quirks-dynamic-002-ref.html": [ + "85d4a5786e41af9ff89d6622fa329fbf79303c35", + "support" + ], + "cssom-view/scrollingElement-quirks-dynamic-002.html": [ + "fcb2ceb93ba7b84c86e4c00e59e8febdc8ff8fed", + "reftest" + ], "cssom-view/scrollingElement.html": [ "e3bc7ab9a646c1275e5dab9394df97d72ef8a42e", "testharness" @@ -219931,6 +220342,10 @@ "144554e0a9d53cdbb2c1f01d3dc169010db693b3", "testharness" ], + "dom/interfaces-expected.txt": [ + "3c2b60141884d25035e1eadecff1f6d4fc815665", + "support" + ], "dom/interfaces.html": [ "aae8f328bc52cbb17f47f78ace6d20c25a9c3acc", "testharness" @@ -224743,6 +225158,34 @@ "eb192c5fe03811a1b69578c92bf77d8abab89f29", "support" ], + "fonts/variations/resources/variabletest_box.ttf": [ + "2fc122ff444d3ddef1f29ebde9a87827244ceeb0", + "support" + ], + "fonts/variations/variable-box-font-ref.html": [ + "65ccabcdeaa322eeceaa646863eba52654e3149b", + "support" + ], + "fonts/variations/variable-box-font.html": [ + "f3836fd9ea898b84bcef5dc259eeadbd4ecaeb68", + "reftest" + ], + "fonts/variations/variable-gpos-m2b-ref.html": [ + "769b04d218db5f7d882512b17c70683281499481", + "support" + ], + "fonts/variations/variable-gpos-m2b.html": [ + "af751a58338e49cc18b0b54c9451662d223f4977", + "reftest" + ], + "fonts/variations/variable-gsub-ref.html": [ + "1b80955335d4a14f3e0d545a6b5165aadff05a87", + "support" + ], + "fonts/variations/variable-gsub.html": [ + "2ae8392efc584c909f11ca04fb33a77f1b3c65ba", + "reftest" + ], "fullscreen/api/document-exit-fullscreen-active-document-expected.txt": [ "0fe00e0f1b873cef51a3c142190ce821a76549ed", "support" @@ -225059,6 +225502,10 @@ "5c727eed4efd84b4b280b2584b7338217971a9e7", "testharness" ], + "hr-time/idlharness-expected.txt": [ + "0e4c8b54fc09dce8b64143477ccb1253cc234f0c", + "support" + ], "hr-time/idlharness.html": [ "2f10557869a4841ec9d826906d542109f606df43", "testharness" @@ -234403,6 +234850,14 @@ "699050ab3bcc8fc11d51c2ae4b9b10aee46876a5", "reftest" ], + "html/rendering/non-replaced-elements/tables/table-direction-ref.html": [ + "97b303c46c7afcc29e0c56856028409c34682baa", + "support" + ], + "html/rendering/non-replaced-elements/tables/table-direction.html": [ + "4c890c9b43bfec7a82a6abeee94d558db2b8f83e", + "reftest" + ], "html/rendering/non-replaced-elements/tables/table-layout-notref.html": [ "a05fad3c06f94c3a617f2efdc589bbb3f5525983", "support" @@ -234415,6 +234870,22 @@ "ec05c435cfd09291184360db7e8b0c5af9c7ba31", "reftest" ], + "html/rendering/non-replaced-elements/tables/table-row-direction-ref.html": [ + "5cf01204381d870738a7454080ea40904b2d0f0c", + "support" + ], + "html/rendering/non-replaced-elements/tables/table-row-direction.html": [ + "433565959474b716d385c2d98d0976ae2121d6d5", + "reftest" + ], + "html/rendering/non-replaced-elements/tables/table-row-group-direction-ref.html": [ + "23616d2840feaafbc6d06b1a1db18dd75d221a23", + "support" + ], + "html/rendering/non-replaced-elements/tables/table-row-group-direction.html": [ + "d4b5cf18545eb48780d9a9a9bfa62ded7dc076bc", + "reftest" + ], "html/rendering/non-replaced-elements/tables/table-vspace-hspace-s.html": [ "a93cbe26a0c5b9a7aeda1faf9db618f79aae8715", "testharness" @@ -243744,7 +244215,7 @@ "support" ], "navigation-timing/nav2_idlharness-expected.txt": [ - "291fda445c50ea3938b8a381b014f1eec5f733cb", + "e917f77c64518a9fe633590941e455b3ae2b1437", "support" ], "navigation-timing/nav2_idlharness.html": [ @@ -243756,7 +244227,7 @@ "testharness" ], "navigation-timing/nav2_test_attributes_values.html": [ - "400c53f8d907e4eb8c9854ba73437510126d9074", + "e5f14ce9a725cbb3a88a73b5f137625334f1e3de", "testharness" ], "navigation-timing/nav2_test_document_open.html": [ @@ -250300,11 +250771,11 @@ "testharness" ], "payment-request/allowpaymentrequest/active-document-cross-origin.https.sub.html": [ - "7cb0cd48493781fe9a4f059365752fdc8d1ada6c", + "e96ac343e8533e8e90d3cbd4113a902b9e93e0bc", "testharness" ], "payment-request/allowpaymentrequest/active-document-same-origin.https.html": [ - "0bcf7a59e03f70b56cc448910acab4188e225c86", + "8bbacc77b15f179bfc7ec4e08809e07181675030", "testharness" ], "payment-request/allowpaymentrequest/allowpaymentrequest-attribute-cross-origin-bc-containers.https.html": [ @@ -250316,7 +250787,7 @@ "testharness" ], "payment-request/allowpaymentrequest/basic.https.html": [ - "fa308475bf7e81d897f39c5df4d0cd2795df7da7", + "0e8a08f2e25a1cc3302d68322f504930ebd3fc8f", "testharness" ], "payment-request/allowpaymentrequest/common.sub.js": [ @@ -250324,7 +250795,7 @@ "support" ], "payment-request/allowpaymentrequest/echo-PaymentRequest.html": [ - "f330e448c1ac380bcaa23bc5bc15c3253aba18c4", + "1c0428fd7d3bdc4302bb061f6f99ce98d0e400b2", "support" ], "payment-request/allowpaymentrequest/no-attribute-cross-origin-bc-containers.https.html": [ @@ -250335,18 +250806,22 @@ "2e42808a20c5ebe11720f01cdfab78dd2bf8221a", "testharness" ], + "payment-request/allowpaymentrequest/removing-allowpaymentrequest.https.sub-expected.txt": [ + "7a03ccde67f470aa9cddc2d51c8e4a2eb9561b37", + "support" + ], "payment-request/allowpaymentrequest/removing-allowpaymentrequest.https.sub.html": [ "41265b7c3d0e8d4c8f462f957627139f8aa5a3a3", "testharness" ], - "payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub-expected.txt": [ - "7225ff302b23bf9fcc85e8d0af66cfdf7d65ff73", - "support" - ], "payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub.html": [ "5eb37c0c6ad39187c4505a8cbe113c4b68e51c92", "testharness" ], + "payment-request/allowpaymentrequest/setting-allowpaymentrequest.https.sub-expected.txt": [ + "4454910deefcb86191abb62940d4ee619b48476f", + "support" + ], "payment-request/allowpaymentrequest/setting-allowpaymentrequest.https.sub.html": [ "e5be539c1b0ca1c571df1fc979fde5bf6482b43d", "testharness" @@ -250356,7 +250831,7 @@ "testharness" ], "payment-request/interfaces.https.html": [ - "29af302db74de64e2bd1352ad92092a309d28c92", + "8a171d3a4fb4a384b56caa8648f04451a65007fe", "testharness" ], "payment-request/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [ @@ -250368,7 +250843,7 @@ "testharness" ], "payment-request/payment-allowed-by-feature-policy.https.sub.html": [ - "f6c74e28d4f69c26215a81cdbd135ad448a8adce", + "a8d765889708b30535acb14c49ad186c1f56a4b5", "testharness" ], "payment-request/payment-allowed-by-feature-policy.https.sub.html.headers": [ @@ -250376,11 +250851,11 @@ "support" ], "payment-request/payment-default-feature-policy.https.sub.html": [ - "238606fd17c8c4a3ad90157cb5cf4b1b07b0016d", + "6980a706cca09eaeb2d63d6780a5e0a89ff52fa5", "testharness" ], "payment-request/payment-disabled-by-feature-policy.https.sub.html": [ - "79bc619acc377b65bb16f91b2374105288f0f2b6", + "942104579b3710532d35bab01f9f387d5ed04fe0", "testharness" ], "payment-request/payment-disabled-by-feature-policy.https.sub.html.headers": [ @@ -250392,39 +250867,43 @@ "support" ], "payment-request/payment-request-abort-method.https.html": [ - "c9ee5af2ccd5ad364090807c8427f1d4624d3747", + "5c1ddf4e9e2a896036912983462f51f8ff6aa82b", "testharness" ], + "payment-request/payment-request-canmakepayment-method.https-expected.txt": [ + "b03b33a8accbb265df006d5620f853ad118f0776", + "support" + ], "payment-request/payment-request-canmakepayment-method.https.html": [ - "b20131bc3f2717212f9940920183d650ee111333", + "3b145e1e2164d5201ded51ce138aeeb4163e0261", "testharness" ], "payment-request/payment-request-constructor-crash.https.html": [ - "dd2f95bd4d94a819c507e942b19a60de05a16971", + "9983391839ed64c41f9a7ecfb48a9b4abe6b497c", "testharness" ], "payment-request/payment-request-constructor.https.html": [ - "44d2656f2990c51063254326521a02218a7fc500", + "786872782a815dcc32c6e93a14e691e4b9541c21", "testharness" ], "payment-request/payment-request-id.https.html": [ - "3e74f97fdf39bb1ca9f2cb5596155705cd15b5b0", + "a90cf1e385cfee1c2090f4144e08b7cb051366d5", "testharness" ], "payment-request/payment-request-in-iframe.html": [ - "26f2715d33e6d00e5ce03d7b07f35db2ac027acf", + "0a7cd9d70a64331eef4277db7e5ee91934b50b11", "testharness" ], "payment-request/payment-request-onshippingaddresschange-attribute.https.html": [ - "9a16b563d8b5f355b73b84d01f61f910bab7eb18", + "c716788baf4b5e74c5bd5adbbd9f95d9ca98ce12", "testharness" ], "payment-request/payment-request-onshippingoptionchange-attribute.https.html": [ - "439c524e66216aad471ecea680a36430f89d9af9", + "fc4772725ab7cab838d0d7bb97d0febeef8d093c", "testharness" ], "payment-request/payment-request-response-id.html": [ - "88df88efdb1d44b56ac9758295f2e2920ae6c9ff", + "8feda1d3b4c071014d4c8c7898598c7d23086216", "support" ], "payment-request/payment-request-show-method.https-expected.txt": [ @@ -250432,7 +250911,7 @@ "support" ], "payment-request/payment-request-show-method.https.html": [ - "518136ad885f95172e578f6e2c165a559c51896b", + "7f58fa01b008be011158cbb834ef1ef1bec2bce5", "testharness" ], "payment-request/payment-request-update-event-constructor.http-expected.txt": [ @@ -250444,7 +250923,7 @@ "testharness" ], "payment-request/payment-request-update-event-constructor.https.html": [ - "6b546870fd384a5bf2106d25fd3159a72f8537b2", + "2a7df6827204f3dd03f5d4a3755f6ed96cdbbb0e", "testharness" ], "payment-request/payment-request-update-event-updatewith-method.https-expected.txt": [ @@ -250452,13 +250931,17 @@ "support" ], "payment-request/payment-request-update-event-updatewith-method.https.html": [ - "d85bca2ccb865c11c550a9d9c1d8770b2c68d6bd", + "08e63c4605bfa4838984aff13a82458ca2a6bdf8", "testharness" ], "performance-timeline/case-sensitivity.any.js": [ "9c6b6edf19800a2730de2dfe601a7cd2503cf87d", "testharness" ], + "performance-timeline/idlharness-expected.txt": [ + "f4d224a610cb977b6d28c0c9941f14e84b2e55c1", + "support" + ], "performance-timeline/idlharness.html": [ "b021a9528875942d44b33c3fc3f4cd643194fad5", "testharness" @@ -258743,6 +259226,10 @@ "07abff794b79e5ec3a82ae654c00c88d63742684", "support" ], + "resource-timing/idlharness-expected.txt": [ + "3a98bbc74b9ab03914d1f1bd5ee1c6acf55cfa6c", + "support" + ], "resource-timing/idlharness.html": [ "60e2a57792827713ffd1176a0793da97c1ccf599", "testharness" @@ -261579,6 +262066,10 @@ "b6073e01e2544ffe2a8bb26946ac1cb5538ed195", "testharness" ], + "shadow-dom/slotchange-customelements.html": [ + "8071607531cdb7c3881e08f5557ccd9a7ecf4e45", + "testharness" + ], "shadow-dom/slotchange-event.html": [ "c72d9d156bf6772c3e5ea054310810b34a049b94", "testharness" @@ -263543,6 +264034,10 @@ "854e06efa9598f66705605bdef20c4a500ab2e9b", "testharness" ], + "url/urlsearchparams-delete-expected.txt": [ + "68f39d2402b2f7590ae051d2d4ea4ab605b874d7", + "support" + ], "url/urlsearchparams-delete.html": [ "b1fcda755e2a9e3308a222fe213abf0a255f0777", "testharness" @@ -264267,6 +264762,10 @@ "83c52be8280bba314116ff1337028ea7835ddf43", "testharness" ], + "web-share/idlharness.https-expected.txt": [ + "97ec9fa4233da0c5332d43222fa25120aa188c9f", + "support" + ], "web-share/idlharness.https.html": [ "17e370aefd324ffac6a6f4b0211fbaecd1781ad4", "testharness" @@ -264279,6 +264778,10 @@ "b4dcc0ac05c2a14907d55058f7d51190842fe0d3", "manual" ], + "web-share/share-empty.https-expected.txt": [ + "95d08ab28f9a5139144b83005a1cd51444c23fad", + "support" + ], "web-share/share-empty.https.html": [ "aa25dc3fef3c62d9b128866a2c48df204bfaa548", "testharness" @@ -264343,6 +264846,10 @@ "41dd5d1a50c21f9e77c6832b56195561ee29106f", "manual" ], + "web-share/share-without-user-gesture.https-expected.txt": [ + "09e41666527d2016ca1499fd08cee5bdab25a990", + "support" + ], "web-share/share-without-user-gesture.https.html": [ "d883b2469759722cf76c4624a1a81908c9aa5ae0", "testharness" @@ -265031,6 +265538,10 @@ "76e0c5f601c8ba4aefb06d1ebab8454c78fe07df", "testharness" ], + "webrtc/RTCConfiguration-bundlePolicy-expected.txt": [ + "995ff82e73b802461b15b4717fabd9bbd1eac462", + "support" + ], "webrtc/RTCConfiguration-bundlePolicy.html": [ "260ead036b3f4facd720dafbcaaa11040c145228", "testharness" @@ -265112,7 +265623,7 @@ "testharness" ], "webrtc/RTCPeerConnection-constructor-expected.txt": [ - "62dfc7cd8198f45406d10afacdc13d539414801d", + "cf410b8c2f6faf04eb1985afa2ae5da6a3e42843", "support" ], "webrtc/RTCPeerConnection-constructor.html": [ @@ -265147,6 +265658,10 @@ "27fb46922255203da0fc26a63808aeb98a60b640", "testharness" ], + "webrtc/RTCPeerConnection-getDefaultIceServers-expected.txt": [ + "9d0ee7b3e0f71d1375e233516159b8216c58c324", + "support" + ], "webrtc/RTCPeerConnection-getDefaultIceServers.html": [ "3b8f625e068cfd6ec3fe80bab276b2216fa8eda5", "testharness" @@ -265231,6 +265746,10 @@ "9e8eca4fa11cc72471bc48d98bec8e5936111334", "testharness" ], + "webrtc/RTCRtpTransceiver-setDirection-expected.txt": [ + "ef8e1a07245c4387dcb2f15217b0fb2c3e8801a2", + "support" + ], "webrtc/RTCRtpTransceiver-setDirection.html": [ "539eaba516eef7419c5e543d7218a41f850f5e7b", "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/WebIDL/ecmascript-binding/es-exceptions/DOMException-custom-bindings.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/WebIDL/ecmascript-binding/es-exceptions/DOMException-custom-bindings.any-expected.txt deleted file mode 100644 index 2a61639..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/WebIDL/ecmascript-binding/es-exceptions/DOMException-custom-bindings.any-expected.txt +++ /dev/null
@@ -1,18 +0,0 @@ -This is a testharness.js-based test. -PASS Cannot construct without new -PASS inherits from Error: prototype-side -PASS does not inherit from Error: class-side -PASS message property descriptor -PASS message getter performs brand checks (i.e. is not [LenientThis] -PASS name property descriptor -PASS name getter performs brand checks (i.e. is not [LenientThis] -PASS code property descriptor -PASS code getter performs brand checks (i.e. is not [LenientThis] -PASS code property is not affected by shadowing the name property -PASS Object.prototype.toString behavior is like other interfaces -FAIL Inherits its toString() from Error.prototype assert_false: toString must not exist on DOMException.prototype expected false got true -FAIL toString() behavior from Error.prototype applies as expected assert_equals: The default Error.prototype.toString() behavior must work on shadowed names and messages expected "new name: new message" but got "name: message" -PASS DOMException.prototype.toString() applied to DOMException.prototype throws because of name/message brand checks -FAIL If the implementation has a stack property on normal errors, it also does on DOMExceptions assert_equals: The typeof values must match expected "string" but got "undefined" -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/WebIDL/ecmascript-binding/es-exceptions/DOMException-custom-bindings.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/WebIDL/ecmascript-binding/es-exceptions/DOMException-custom-bindings.any.worker-expected.txt deleted file mode 100644 index 2a61639..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/WebIDL/ecmascript-binding/es-exceptions/DOMException-custom-bindings.any.worker-expected.txt +++ /dev/null
@@ -1,18 +0,0 @@ -This is a testharness.js-based test. -PASS Cannot construct without new -PASS inherits from Error: prototype-side -PASS does not inherit from Error: class-side -PASS message property descriptor -PASS message getter performs brand checks (i.e. is not [LenientThis] -PASS name property descriptor -PASS name getter performs brand checks (i.e. is not [LenientThis] -PASS code property descriptor -PASS code getter performs brand checks (i.e. is not [LenientThis] -PASS code property is not affected by shadowing the name property -PASS Object.prototype.toString behavior is like other interfaces -FAIL Inherits its toString() from Error.prototype assert_false: toString must not exist on DOMException.prototype expected false got true -FAIL toString() behavior from Error.prototype applies as expected assert_equals: The default Error.prototype.toString() behavior must work on shadowed names and messages expected "new name: new message" but got "name: message" -PASS DOMException.prototype.toString() applied to DOMException.prototype throws because of name/message brand checks -FAIL If the implementation has a stack property on normal errors, it also does on DOMExceptions assert_equals: The typeof values must match expected "string" but got "undefined" -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-001-ref.html new file mode 100644 index 0000000..683198a --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-001-ref.html
@@ -0,0 +1,3 @@ +<!-- quirks mode --> +<html style="overflow:scroll"> +<body style="overflow:scroll">The body box should have scrollbars.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-001.html b/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-001.html new file mode 100644 index 0000000..344e299 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-001.html
@@ -0,0 +1,17 @@ +<!-- quirks mode --> +<html> + <head> + <meta charset="utf-8"> + <title>CSSOM View Test: Dynamically changing scrollingElement to html in quirks mode</title> + <link rel="author" title="Rune Lillesveen" href="mailto:rune@opera.com"> + <link rel="help" href="https://www.w3.org/TR/cssom-view-1/#dom-document-scrollingelement"> + <link rel="match" href="scrollingElement-quirks-dynamic-001-ref.html"> + <meta name="assert" content="Checks that setting the overflow on html to scroll will stop propagating body scrollbars to viewport."> + </head> + <body style="overflow:scroll">The body box should have scrollbars. + <script> + document.body.offsetTop; // force layout + document.documentElement.style.overflow = "scroll"; + </script> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-002-ref.html b/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-002-ref.html new file mode 100644 index 0000000..c8a78398 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-002-ref.html
@@ -0,0 +1,2 @@ +<!-- quirks mode --> +<body style="overflow:scroll">The body box should not have scrollbars.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-002.html b/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-002.html new file mode 100644 index 0000000..8495be2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/cssom-view/scrollingElement-quirks-dynamic-002.html
@@ -0,0 +1,17 @@ +<!-- quirks mode --> +<html style="overflow:scroll"> + <head> + <meta charset="utf-8"> + <title>CSSOM View Test: Dynamically changing scrollingElement to body in quirks mode</title> + <link rel="author" title="Rune Lillesveen" href="mailto:rune@opera.com"> + <link rel="help" href="https://www.w3.org/TR/cssom-view-1/#dom-document-scrollingelement"> + <link rel="match" href="scrollingElement-quirks-dynamic-002-ref.html"> + <meta name="assert" content="Checks that setting the overflow on html to visible will propagate body scrollbars to viewport."> + </head> + <body style="overflow:scroll">The body box should not have scrollbars. + <script> + document.body.offsetTop; // force layout + document.documentElement.style.overflow = "visible"; + </script> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/hr-timestamp/constructed-events.html b/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-timestamp-high-resolution.html similarity index 85% rename from third_party/WebKit/LayoutTests/fast/events/hr-timestamp/constructed-events.html rename to third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-timestamp-high-resolution.html index bbe5ed4..15aa014 100644 --- a/third_party/WebKit/LayoutTests/fast/events/hr-timestamp/constructed-events.html +++ b/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-timestamp-high-resolution.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> <script type="text/javascript"> 'use strict'; for (let eventType of [MouseEvent, KeyboardEvent, WheelEvent, GamepadEvent, FocusEvent]) {
diff --git a/third_party/WebKit/LayoutTests/fast/events/hr-timestamp/safe-resolution.html b/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-timestamp-safe-resolution.html similarity index 82% rename from third_party/WebKit/LayoutTests/fast/events/hr-timestamp/safe-resolution.html rename to third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-timestamp-safe-resolution.html index bc3d519e..c19c7a0 100644 --- a/third_party/WebKit/LayoutTests/fast/events/hr-timestamp/safe-resolution.html +++ b/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-timestamp-safe-resolution.html
@@ -1,14 +1,14 @@ <!DOCTYPE html> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> <script type="text/javascript"> 'use strict'; test(function() { let e1 = new MouseEvent('test1'); let e2 = new MouseEvent('test2'); - + while (e1.timeStamp == e2.timeStamp) e2 = new MouseEvent('test2');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/events/EventTarget-constructible.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/events/EventTarget-constructible.any-expected.txt deleted file mode 100644 index a19cf28..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/events/EventTarget-constructible.any-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -FAIL A constructed EventTarget can be used as expected Illegal constructor -FAIL EventTarget can be subclassed Illegal constructor -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/events/EventTarget-constructible.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/events/EventTarget-constructible.any.worker-expected.txt deleted file mode 100644 index a19cf28..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/events/EventTarget-constructible.any.worker-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -FAIL A constructed EventTarget can be used as expected Illegal constructor -FAIL EventTarget can be subclassed Illegal constructor -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/resources/variabletest_box.ttf b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/resources/variabletest_box.ttf new file mode 100644 index 0000000..53b5b242 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/resources/variabletest_box.ttf Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-box-font-ref.html b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-box-font-ref.html new file mode 100644 index 0000000..142b0aa --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-box-font-ref.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<meta charset="utf-8"> +<style> + @font-face { + font-family: variabletest_box; + src: url(resources/variabletest_box.ttf); + } + + body { + font-family: variabletest_box, sans-serif; + font-size: 200px; + } +</style> +â–„ â–€ +<script> + document.fonts.ready.then( + () => { document.documentElement.classList.remove("reftest-wait"); }); +</script> +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-box-font.html b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-box-font.html new file mode 100644 index 0000000..a9023fab --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-box-font.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<link rel="match" href="variable-box-font-ref.html"> +<meta charset="utf-8"> +<style> + @font-face { + font-family: variabletest_box; + src: url(resources/variabletest_box.ttf); + } + + body { + font-family: variabletest_box, + sans-serif; + font-size: 200px; + } + + .a_up { + font-variation-settings: "UPWD" 350; + } +</style> +<!-- The variabletest_box font has an A glyph that looks like a lower half box, + with deltas on the 'UPWD' variation axis that allow shifting the box up. At + 350, the box is at the top. The font also has two glyphs for UPPER HALF BLOCK + and LOWER HALF BLOCK, which look identical to the respective variations of A. +--> +A <span class="a_up">A</span> +<script> + document.fonts.ready.then( + () => { document.documentElement.classList.remove("reftest-wait"); }); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gpos-m2b-ref.html b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gpos-m2b-ref.html new file mode 100644 index 0000000..c6b80b1b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gpos-m2b-ref.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<meta charset="utf-8"> +<style> + @font-face { + font-family: variabletest_box; + src: url(resources/variabletest_box.ttf); + } + + body { + font-family: variabletest_box, sans-serif; + sans-serif; + font-size: 100px; + } +</style> +M̻ N̻ O̻ +<script> + document.fonts.ready.then( + () => { document.documentElement.classList.remove("reftest-wait"); }); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gpos-m2b.html b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gpos-m2b.html new file mode 100644 index 0000000..9b976e1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gpos-m2b.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<link rel="match" href="variable-gpos-m2b-ref.html"> +<meta charset="utf-8"> +<style> + @font-face { + font-family: variabletest_box; + src: url(resources/variabletest_box.ttf); + } + + body { + font-family: variabletest_box, sans-serif; + sans-serif; + font-size: 100px; + } + + .gpos_m2b_left { + font-variation-settings: "VM2B" 0; + } + + .gpos_m2b_middle { + font-variation-settings: "VM2B" 500; + } + + .gpos_m2b_right { + font-variation-settings: "VM2B" 1000; + } +</style> +<!-- The variabletest_box font has an M glyph saying "m2b pos" that combines + with the combining box below. And it has a glyph for combining box below + whose mark anchor can be shifted horizontally using the VM2B axis. The font + also has N and O glyphs which have fixed shifted base anchor points at the + middle and at the right position. In this ref test we check whether + applying the VM2B axis works as expected and shifts the mark anchor point + left so that the combining mark is placed correctly at the middle and at + the right position. The VM2B rendering must be identical to the + conventional rendering with the fixed base anchor points. --> +<span class="gpos_m2b_left">M̻</span> +<span class="gpos_m2b_middle">M̻</span> +<span class="gpos_m2b_right">M̻</span> +<script> + document.fonts.ready.then( + () => { document.documentElement.classList.remove("reftest-wait"); }); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gsub-ref.html b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gsub-ref.html new file mode 100644 index 0000000..3b1f7f43 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gsub-ref.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<meta charset="utf-8"> +<style> + @font-face { + font-family: variabletest_box; + src: url(resources/variabletest_box.ttf); + } + + body { + font-family: variabletest_box, sans-serif; + sans-serif; + font-size: 100px; + } +</style> +r R +<script> + document.fonts.ready.then( + () => { document.documentElement.classList.remove("reftest-wait"); }); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gsub.html b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gsub.html new file mode 100644 index 0000000..ed432f6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/fonts/variations/variable-gsub.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<link rel="match" href="variable-gsub-ref.html"> +<meta charset="utf-8"> +<style> + @font-face { + font-family: variabletest_box; + src: url(resources/variabletest_box.ttf); + } + + body { + font-family: variabletest_box, sans-serif; + sans-serif; + font-size: 100px; + } + + .rvrn_replaced { + font-variation-settings: "FVTT" 10; + } +</style> +<!-- The variabletest_box font has an r glyph that says "rvrn base" and has + this as a name as well. And it has a glyph for R that says "rvrn subst" + where rvrn stands for the required Required Variation Alternates + feature. The font has an 'FVTT' axis ranging from 0 to 10, where it uses + a single substitution glyph lookup table for axis values starting from + 5, which then replaces the rvrn_base glyph with the rvrn_subst + glyph. So in this reftest the substituted glyph for lowercase r + should visually match the uppercase R glyph, both show "rvrn subst". --> +r <span class="rvrn_replaced">r</span> +<script> + document.fonts.ready.then( + () => { document.documentElement.classList.remove("reftest-wait"); }); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-direction-ref.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-direction-ref.html new file mode 100644 index 0000000..2bbd6c0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-direction-ref.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<title>Table direction</title> + +<style> + table { + border-collapse: collapse; + } + + td { + border: 2px solid black; + width: 20px; + height: 20px; + } + + td.special { + border-left: 5px solid green; + border-right: 5px solid blue; + } +</style> + +Normal table: +<table> + <tr> + <td></td> + <td class="special"></td> + </tr> +</table> + +<hr> + +RTL table: +<table> + <tr> + <td class="special"></td> + <td></td> + </tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-direction.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-direction.html new file mode 100644 index 0000000..a3de413 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-direction.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<link rel="match" href="table-direction-ref.html"> +<title>Table direction</title> + +<style> + table { + border-collapse: collapse; + } + + td { + border: 2px solid black; + width: 20px; + height: 20px; + } + + td.special { + border-left: 5px solid green; + border-right: 5px solid blue; + } +</style> + +Normal table: +<table> + <tr> + <td></td> + <td class="special"></td> + </tr> +</table> + +<hr> + +RTL table: +<table style="direction: rtl"> + <tr> + <td></td> + <td class="special"></td> + </tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-direction-ref.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-direction-ref.html new file mode 100644 index 0000000..dab3163 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-direction-ref.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<title>Table row direction</title> + +<style> + table { + border-collapse: collapse; + } + + td { + border: 2px solid black; + width: 20px; + height: 20px; + } + + td.special { + border-left: 5px solid green; + border-right: 5px solid blue; + } +</style> + +Normal table with LTR and RTL rows: +<table> + <tr> + <td></td> + <td class="special"></td> + </tr> + <tr> + <td></td> + <td class="special"></td> + </tr> +</table> + +<hr> + +RTL table with LTR and RTL rows: +<table> + <tr> + <td class="special"></td> + <td></td> + </tr> + <tr> + <td class="special"></td> + <td></td> + </tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-direction.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-direction.html new file mode 100644 index 0000000..64ed5a6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-direction.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<link rel="match" href="table-row-direction-ref.html"> +<title>Table row direction</title> + +<style> + table { + border-collapse: collapse; + } + + td { + border: 2px solid black; + width: 20px; + height: 20px; + } + + td.special { + border-left: 5px solid green; + border-right: 5px solid blue; + } +</style> + +Normal table with LTR and RTL rows: +<table> + <tr style="direction: ltr"> + <td></td> + <td class="special"></td> + </tr> + <tr style="direction: rtl"> + <td></td> + <td class="special"></td> + </tr> +</table> + +<hr> + +RTL table with LTR and RTL rows: +<table style="direction: rtl"> + <tr style="direction: ltr"> + <td></td> + <td class="special"></td> + </tr> + <tr style="direction: rtl"> + <td></td> + <td class="special"></td> + </tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-group-direction-ref.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-group-direction-ref.html new file mode 100644 index 0000000..0f3e03f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-group-direction-ref.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<title>Table row-group direction</title> + +<style> + table { + border-collapse: collapse; + } + + td { + border: 2px solid black; + width: 20px; + height: 20px; + } + + td.special { + border-left: 5px solid green; + border-right: 5px solid blue; + } +</style> + +Normal table with LTR and RTL row groups: +<table> + <tr> + <td></td> + <td class="special"></td> + </tr> + <tr> + <td></td> + <td class="special"></td> + </tr> +</table> + +<hr> + +RTL table with LTR and RTL row groups: +<table> + <tr> + <td class="special"></td> + <td></td> + </tr> + <tr> + <td class="special"></td> + <td></td> + </tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-group-direction.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-group-direction.html new file mode 100644 index 0000000..385672f1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/tables/table-row-group-direction.html
@@ -0,0 +1,54 @@ +<!DOCTYPE html> +<link rel="match" href="table-row-group-direction-ref.html"> +<title>Table row-group direction</title> + +<style> + table { + border-collapse: collapse; + } + + td { + border: 2px solid black; + width: 20px; + height: 20px; + } + + td.special { + border-left: 5px solid green; + border-right: 5px solid blue; + } +</style> + +Normal table with LTR and RTL row groups: +<table> + <tbody style="direction: ltr"> + <tr> + <td></td> + <td class="special"></td> + </tr> + </tbody> + <tbody style="direction: rtl"> + <tr> + <td></td> + <td class="special"></td> + </tr> + </tbody> +</table> + +<hr> + +RTL table with LTR and RTL row groups: +<table style="direction: rtl"> + <tbody style="direction: ltr"> + <tr> + <td></td> + <td class="special"></td> + </tr> + </tbody> + <tbody style="direction: rtl"> + <tr> + <td></td> + <td class="special"></td> + </tr> + </tbody> +</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-cross-origin.https.sub-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-cross-origin.https.sub-expected.txt new file mode 100644 index 0000000..aaf8b3c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-cross-origin.https.sub-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL PaymentRequest <iframe allowpaymentrequest> in non-active document (cross-origin) assert_throws: function "() => { + new grabbedPaymentRequest(...paymentArgs); + }" threw object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." ("TypeError") expected object "[object Object]" ("SecurityError") +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-cross-origin.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-cross-origin.https.sub.html index fbb80e3..48f6d90 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-cross-origin.https.sub.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-cross-origin.https.sub.html
@@ -7,7 +7,7 @@ <script> async_test((t) => { const iframe = document.getElementById('iframe'); - const paymentArgs = [[{supportedMethods: ['foo']}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}]; + const paymentArgs = [[{supportedMethods: 'foo'}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}]; onload = () => { const win = window[0];
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-same-origin.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-same-origin.https-expected.txt new file mode 100644 index 0000000..1a3c4d6c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-same-origin.https-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL PaymentRequest <iframe allowpaymentrequest> in non-active document (same-origin) assert_throws: function "() => { + new grabbedPaymentRequest(...paymentArgs); + }" threw object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." ("TypeError") expected object "[object Object]" ("SecurityError") +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-same-origin.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-same-origin.https.html index 69a738a..bbcc026d5 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-same-origin.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/active-document-same-origin.https.html
@@ -6,7 +6,7 @@ <script> async_test((t) => { const iframe = document.getElementById('iframe'); - const paymentArgs = [[{supportedMethods: ['foo']}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}]; + const paymentArgs = [[{supportedMethods: 'foo'}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}]; onload = () => { const win = window[0];
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-cross-origin-bc-containers.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-cross-origin-bc-containers.https-expected.txt new file mode 100644 index 0000000..9ef152b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-cross-origin-bc-containers.https-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +FAIL iframe assert_equals: expected "Success" but got "Exception" +FAIL frame assert_array_equals: property 0, expected true but got false +FAIL object assert_array_equals: property 0, expected true but got false +FAIL embed assert_array_equals: property 0, expected true but got false +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-same-origin-bc-containers.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-same-origin-bc-containers.https-expected.txt new file mode 100644 index 0000000..ab65a93 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/allowpaymentrequest-attribute-same-origin-bc-containers.https-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +FAIL iframe assert_equals: expected "Success" but got "Exception" +FAIL frame assert_equals: expected "Success" but got "Exception" +FAIL object assert_equals: expected "Success" but got "Exception" +FAIL embed assert_equals: expected "Success" but got "Exception" +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/basic.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/basic.https-expected.txt new file mode 100644 index 0000000..c925dae --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/basic.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL PaymentRequest <iframe allowpaymentrequest> basic Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/basic.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/basic.https.html index 841880e..80a6a22 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/basic.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/basic.https.html
@@ -5,7 +5,7 @@ <iframe id="iframe" allowpaymentrequest></iframe> <script> async_test((t) => { - const paymentArgs = [[{supportedMethods: ['foo']}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}]; + const paymentArgs = [[{supportedMethods: 'foo'}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}]; onload = t.step_func_done(() => { new window[0].PaymentRequest(...paymentArgs);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/echo-PaymentRequest.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/echo-PaymentRequest.html index 15fa1a1e..f18b16e 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/echo-PaymentRequest.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/echo-PaymentRequest.html
@@ -1,7 +1,7 @@ <!doctype html> <script> window.onmessage = (e) => { - const paymentArgs = [[{supportedMethods: ['foo']}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}]; + const paymentArgs = [[{supportedMethods: 'foo'}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}]; if (e.data === 'What is the result of new PaymentRequest(...)?') { const result = {urlQuery: location.search.substring(1)}; // Used to distinguish subtests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/no-attribute-cross-origin-bc-containers.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/no-attribute-cross-origin-bc-containers.https-expected.txt new file mode 100644 index 0000000..d55bf82b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/no-attribute-cross-origin-bc-containers.https-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +FAIL iframe assert_array_equals: property 0, expected true but got false +FAIL frame assert_array_equals: property 0, expected true but got false +FAIL object assert_array_equals: property 0, expected true but got false +FAIL embed assert_array_equals: property 0, expected true but got false +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/no-attribute-same-origin-bc-containers.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/no-attribute-same-origin-bc-containers.https-expected.txt new file mode 100644 index 0000000..ab65a93 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/no-attribute-same-origin-bc-containers.https-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +FAIL iframe assert_equals: expected "Success" but got "Exception" +FAIL frame assert_equals: expected "Success" but got "Exception" +FAIL object assert_equals: expected "Success" but got "Exception" +FAIL embed assert_equals: expected "Success" but got "Exception" +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/removing-allowpaymentrequest.https.sub-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/removing-allowpaymentrequest.https.sub-expected.txt index 533d6d6..8754c0b 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/removing-allowpaymentrequest.https.sub-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/removing-allowpaymentrequest.https.sub-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL PaymentRequest removing allowpaymentrequest after load and then navigating assert_equals: after navigation expected "Exception" but got "Success" +FAIL PaymentRequest removing allowpaymentrequest after load and then navigating assert_equals: before navigation expected "Success" but got "Exception" Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub-expected.txt new file mode 100644 index 0000000..24a3a7fc --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL PaymentRequest setting allowpaymentrequest after document creation, before response assert_equals: expected "Success" but got "Exception" +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest.https.sub-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest.https.sub-expected.txt index b1372064..e6b6b53 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest.https.sub-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest.https.sub-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL PaymentRequest setting allowpaymentrequest after load and then navigating assert_equals: after navigation expected "Success" but got "Exception" +FAIL PaymentRequest setting allowpaymentrequest after load and then navigating assert_array_equals: before navigation property 0, expected true but got false Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt new file mode 100644 index 0000000..170486c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt
@@ -0,0 +1,64 @@ +This is a testharness.js-based test. +PASS PaymentRequest interface: existence and properties of interface object +PASS PaymentRequest interface object length +PASS PaymentRequest interface object name +PASS PaymentRequest interface: existence and properties of interface prototype object +PASS PaymentRequest interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentRequest interface: operation show() +PASS PaymentRequest interface: operation abort() +PASS PaymentRequest interface: operation canMakePayment() +PASS PaymentRequest interface: attribute id +PASS PaymentRequest interface: attribute shippingAddress +PASS PaymentRequest interface: attribute shippingOption +PASS PaymentRequest interface: attribute shippingType +PASS PaymentRequest interface: attribute onshippingaddresschange +PASS PaymentRequest interface: attribute onshippingoptionchange +FAIL PaymentRequest must be primary interface of new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL Stringification of new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "show" with the proper type (0) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "abort" with the proper type (1) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "canMakePayment" with the proper type (2) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "id" with the proper type (3) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "shippingAddress" with the proper type (4) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "shippingOption" with the proper type (5) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "shippingType" with the proper type (6) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "onshippingaddresschange" with the proper type (7) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "onshippingoptionchange" with the proper type (8) assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +PASS PaymentAddress interface: existence and properties of interface object +PASS PaymentAddress interface object length +PASS PaymentAddress interface object name +PASS PaymentAddress interface: existence and properties of interface prototype object +PASS PaymentAddress interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentAddress interface: attribute country +PASS PaymentAddress interface: attribute addressLine +PASS PaymentAddress interface: attribute region +PASS PaymentAddress interface: attribute city +PASS PaymentAddress interface: attribute dependentLocality +PASS PaymentAddress interface: attribute postalCode +PASS PaymentAddress interface: attribute sortingCode +PASS PaymentAddress interface: attribute languageCode +PASS PaymentAddress interface: attribute organization +PASS PaymentAddress interface: attribute recipient +PASS PaymentAddress interface: attribute phone +PASS PaymentResponse interface: existence and properties of interface object +PASS PaymentResponse interface object length +PASS PaymentResponse interface object name +PASS PaymentResponse interface: existence and properties of interface prototype object +PASS PaymentResponse interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentResponse interface: attribute requestId +PASS PaymentResponse interface: attribute methodName +PASS PaymentResponse interface: attribute details +PASS PaymentResponse interface: attribute shippingAddress +PASS PaymentResponse interface: attribute shippingOption +PASS PaymentResponse interface: attribute payerName +PASS PaymentResponse interface: attribute payerEmail +PASS PaymentResponse interface: attribute payerPhone +PASS PaymentResponse interface: operation complete(PaymentComplete) +PASS PaymentRequestUpdateEvent interface: existence and properties of interface object +PASS PaymentRequestUpdateEvent interface object length +PASS PaymentRequestUpdateEvent interface object name +PASS PaymentRequestUpdateEvent interface: existence and properties of interface prototype object +PASS PaymentRequestUpdateEvent interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentRequestUpdateEvent interface: operation updateWith([object Object]) +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https.html index bca60a6..bc76247 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https.html
@@ -29,8 +29,8 @@ attribute EventHandler onshippingoptionchange; }; dictionary PaymentMethodData { - required sequence<DOMString> supportedMethods; - object data; + required DOMString supportedMethods; + object data; }; dictionary PaymentCurrencyAmount { required DOMString currency; @@ -51,7 +51,7 @@ PaymentItem total; }; dictionary PaymentDetailsModifier { - required sequence<DOMString> supportedMethods; + required DOMString supportedMethods; PaymentItem total; sequence<PaymentItem> additionalDisplayItems; object data; @@ -134,7 +134,7 @@ } }); idlArray.add_objects({ - PaymentRequest: ["new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}})"] + PaymentRequest: ["new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}})"] }); idlArray.test(); </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html index b64cda813..68fc12d1 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html
@@ -11,7 +11,7 @@ var header = 'Feature-Policy header {"payment" : ["*"]}'; test(() => { - var supportedInstruments = [ { supportedMethods: [ 'visa' ] } ]; + var supportedInstruments = [ { supportedMethods: 'visa' } ]; var details = { total: { label: 'Test', amount: { currency: 'USD', value: '5.00' } } };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-default-feature-policy.https.sub-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-default-feature-policy.https.sub-expected.txt new file mode 100644 index 0000000..b76cfa77 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-default-feature-policy.https.sub-expected.txt
@@ -0,0 +1,8 @@ +This is a testharness.js-based test. +FAIL Default "payment" feature policy ["self"] allows the top-level document. assert_unreached: Reached unreachable code +PASS Default "payment" feature policy ["self"] allows same-origin iframes. +PASS Default "payment" feature policy ["self"] disallows cross-origin iframes. +PASS Default "payment" feature policy ["self"] allowpaymentrequest=true allows same-origin iframes. +PASS Default "payment" feature policy ["self"] allowpaymentrequest=true allows cross-origin iframes. +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-default-feature-policy.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-default-feature-policy.https.sub.html index ab9c8ca..ad4bbdc 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-default-feature-policy.https.sub.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-default-feature-policy.https.sub.html
@@ -11,7 +11,7 @@ var header = 'Default "payment" feature policy ["self"]'; test(() => { - var supportedInstruments = [ { supportedMethods: [ 'visa' ] } ]; + var supportedInstruments = [ { supportedMethods: 'visa' } ]; var details = { total: { label: 'Test', amount: { currency: 'USD', value: '5.00' } } };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html index 7379a5cb..98e434a 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html
@@ -11,7 +11,7 @@ var header = 'Feature-Policy header {"payment" : []}'; test(() => { - var supportedInstruments = [ { supportedMethods: [ 'visa' ] } ]; + var supportedInstruments = [ { supportedMethods: 'visa' } ]; var details = { total: { label: 'Test', amount: { currency: 'USD', value: '5.00' } } };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt index 4fe4e85c..4ddca24 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt
@@ -1,6 +1,6 @@ This is a testharness.js-based test. -PASS Throws if the promise [[state]] is not "interactive" -FAIL Calling abort must not change the [[state]] until after "interactive" assert_true: Unexpected promise rejection: Request failed expected true got false -FAIL calling .abort() causes acceptPromise to reject and closes the request. assert_true: Unexpected promise rejection: Request failed expected true got false +FAIL Throws if the promise [[state]] is not "interactive" promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL Calling abort must not change the [[state]] until after "interactive" promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL calling .abort() causes acceptPromise to reject and closes the request. promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html index f596800..8fc4baf 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html
@@ -12,7 +12,7 @@ // not being explicitly handled. allow_uncaught_exception: true, }); -const basicCard = Object.freeze({ supportedMethods: ["basic-card"] }); +const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const defaultMethods = Object.freeze([basicCard]); const defaultDetails = Object.freeze({ total: {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt index 26436ee..27bb743 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt
@@ -1,10 +1,9 @@ This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = Request failed -FAIL If request.[[state]] is "created", then return a promise that resolves to true for known method. promise_test: Unhandled rejection with value: object "ReferenceError: assert_equal is not defined" -FAIL If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "InvalidStateError: Never called show(), so nothing to abort" -FAIL If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "UnknownError: Request failed" -FAIL If payment method identifier and serialized parts are supported, resolve promise with true. promise_test: Unhandled rejection with value: object "UnknownError: Request failed" +FAIL If request.[[state]] is "created", then return a promise that resolves to true for known method. promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." +FAIL If payment method identifier and serialized parts are supported, resolve promise with true. promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." FAIL If payment method identifier is unknown, resolve promise with false. assert_true: Unexpected exception testing method this-is-not-supported, expected false. See error console. expected true got false -FAIL Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException. promise_test: Unhandled rejection with value: object "ReferenceError: assert_equal is not defined" +FAIL Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException. promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html index 86fae2e..891a62d2 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
@@ -6,7 +6,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> -const basicCard = Object.freeze({ supportedMethods: ["basic-card"] }); +const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const defaultMethods = Object.freeze([basicCard]); const defaultDetails = Object.freeze({ total: { @@ -101,7 +101,7 @@ for (const method of unsupportedMethods) { try { const request = new PaymentRequest( - [{ supportedMethods: [method] }], + [{ supportedMethods: method }], defaultDetails ); assert_false(
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https-expected.txt new file mode 100644 index 0000000..fea8439b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https-expected.txt
@@ -0,0 +1,53 @@ +This is a testharness.js-based test. +FAIL Don't crash if there is an abusive number of payment methods in the methodData sequence assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:82:5) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:78:1 expected true got false +FAIL Don't crash if PaymentMethodData.supportedMethods is an abusive length assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:103:5) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:99:1 expected true got false +FAIL Don't crash if the request id has an abusive length assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:124:5) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:120:1 expected true got false +FAIL Don't crash if PaymentDetailsInit.total.label is an abusive length assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:148:5) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:144:1 expected true got false +FAIL Don't crash if total.amount.value is an abusive length assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:169:5) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:165:1 expected true got false +FAIL Don't crash if details.displayItems has an abusive number of items assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:192:7) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:187:3 expected true got false +FAIL Don't crash if details.shippingOptions has an abusive number of items assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:192:7) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:187:3 expected true got false +FAIL Don't crash if PaymentShippingOptions.label is an abusive length assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:215:5) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:209:1 expected true got false +FAIL Don't crash if the PaymentShippingOptions.amount.value is an abusive length assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:235:5) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:229:1 expected true got false +FAIL Don't crash if PaymentItem.label is an abusive length assert_true: failed smoke test: TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. + at Test.test (https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:255:5) + at Test.step (https://web-platform.test:8444/resources/testharness.js:1413:25) + at test (https://web-platform.test:8444/resources/testharness.js:501:18) + at https://web-platform.test:8444/payment-request/payment-request-constructor-crash.https.html:249:1 expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https.html index 499fd95..1d0b88d 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https.html
@@ -10,7 +10,7 @@ dictionary PaymentItem { required DOMString label; required PaymentCurrencyAmount amount; - boolean pending = false; + boolean pending = false; }; dictionary PaymentDetailsBase { @@ -29,7 +29,7 @@ const ABUSIVE_AMOUNT = 100000; const basicCard = Object.freeze({ - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }); const defaultAmount = Object.freeze({ @@ -93,28 +93,28 @@ assert_equals(err.name, "TypeError", "must be a TypeError"); } assert_true(true, "Didn't crash"); -}, "Don't crash if there is a abusive number of payment methods in the methodData sequence"); +}, "Don't crash if there is an abusive number of payment methods in the methodData sequence"); +// PaymentMethodData.supportedMethods test(() => { - let supportedMethods = ["basic-card"]; + const supportedMethods = "basic-card"; // Smoke test try { new PaymentRequest([{ supportedMethods }], defaultDetails); } catch (err) { assert_true(false, "failed smoke test: " + err.stack); } - // Now, let's add an abusive number of supportedMethods to a single PaymentMethodData - for (let i = 0; i < ABUSIVE_AMOUNT; i++) { - supportedMethods.push(`https://example.com/${i}/evil_${Math.random()}`); - } - const evilMethodData = [{ supportedMethods }]; + // Now, we make supportedMethods super large + const evilMethodData = [{ + supportedMethods: supportedMethods.repeat(ABUSIVE_AMOUNT), + }]; try { new PaymentRequest(evilMethodData, defaultDetails); } catch (err) { assert_equals(err.name, "TypeError", "must be a TypeError"); } assert_true(true, "Didn't crash"); -}, "Don't crash if there is a abusive number of supported methods in one sequence"); +}, "Don't crash if PaymentMethodData.supportedMethods is an abusive length"); // PaymentDetailsInit.id test(() => {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https-expected.txt new file mode 100644 index 0000000..6e99643 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https-expected.txt
@@ -0,0 +1,132 @@ +This is a testharness.js-based test. +FAIL If details.id is missing, assign a identifier Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL If details.id is missing, assign a unique identifier Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL If the same id is provided, then use it Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL Use ids even if they are strange Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL Use provided request ID Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +PASS If the length of the methodData sequence is zero, then throw a TypeError +FAIL Method data must be JSON-serializable object (a list in this case) assert_false: shouldn't throw when using a list expected false got true +FAIL Method data must be JSON-serializable object (an object in this case) Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +PASS Rethrow any exceptions of JSON-serializing paymentMethod.data into a string +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "-"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "notdigits"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "ALSONOTDIGITS"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "10."), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case ".99"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "-10."), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "-.99"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "10-"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "1-0"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "1.0.0"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "1/3"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case ""), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "null"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "1.0 "), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "USD$1.0"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "$1.0"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case " 1.0"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "-1"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "-1.0"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "-1.00"), then throw a TypeError +PASS If details.total.amount.value is not a valid decimal monetary value (in this case "-1000.000"), then throw a TypeError +FAIL PaymentDetailsBase.0 can be 0 length assert_true: 0 can be zero length expected true got false +FAIL PaymentDetailsBase.1 can be 0 length assert_true: 1 can be zero length expected true got false +FAIL PaymentDetailsBase.2 can be 0 length assert_true: 2 can be zero length expected true got false +PASS If the first character of details.total.amount.value is U+002D HYPHEN-MINUS, then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "-"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "notdigits"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "ALSONOTDIGITS"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "10."), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case ".99"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "-10."), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "-.99"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "10-"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "1-0"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "1.0.0"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "1/3"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case ""), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "null"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "1.0 "), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "USD$1.0"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case "$1.0"), then throw a TypeError +PASS For each item in details.displayItems: if item.amount.value is not a valid decimal monetary value (in this case " 1.0"), then throw a TypeError +FAIL Negative values are allowed for displayItems.amount.value, irrespective of total amount assert_false: shouldn't throw when given a negative value expected false got true +FAIL it handles high precision currency values without throwing assert_false: shouldn't throw when given absurd monetary values expected false got true +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "-"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "notdigits"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "ALSONOTDIGITS"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "10."), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case ".99"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "-10."), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "-.99"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "10-"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "1-0"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "1.0.0"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "1/3"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case ""), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "null"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "1.0 "), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "USD$1.0"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case "$1.0"), then throw a TypeError +PASS For each option in details.shippingOptions: if option.amount.value is not a valid decimal monetary value (in this case " 1.0"), then throw a TypeError +FAIL If there is no selected shipping option, then PaymentRequest.shippingOption remains null Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL If there is a selected shipping option, then it becomes synchronously selected Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL If there is a multiple selected shipping options, only the last is selected Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL If there are any duplicate shipping option ids, then there are no shipping options Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "-"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "notdigits"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "ALSONOTDIGITS"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "10."), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case ".99"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "-10."), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "-.99"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "10-"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "1-0"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "1.0.0"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "1/3"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case ""), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "null"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "1.0 "), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "USD$1.0"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "$1.0"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case " 1.0"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "-1"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "-1.0"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "-1.00"), then throw a TypeError +PASS If modifier.total.amount.value is not a valid decimal monetary value (in this case "-1000.000"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "-"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "notdigits"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "ALSONOTDIGITS"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "10."), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case ".99"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "-10."), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "-.99"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "10-"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "1-0"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "1.0.0"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "1/3"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case ""), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "null"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case " 1.0 "), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "1.0 "), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "USD$1.0"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "$1.0"), then throw a TypeError +PASS If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case " 1.0"), then throw a TypeError +FAIL Modifier data must be JSON-serializable object (a list in this case) assert_false: shouldn't throw when given a list expected false got true +FAIL Modifier data must be JSON-serializable object (an object in this case) assert_false: shouldn't throw when given an object value expected false got true +PASS Rethrow any exceptions of JSON-serializing modifier.data into a string +PASS Shipping type should be valid +FAIL PaymentRequest.shippingAddress must initially be null Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL If options.requestShipping is not set, then request.shippingType attribute is null. Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL If options.requestShipping is true, request.shippingType will be options.shippingType. Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html index 971622e8..9f80c6d3 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html
@@ -7,7 +7,7 @@ <script src="/resources/testharnessreport.js"></script> <script> "use strict"; -const basicCard = Object.freeze({ supportedMethods: ["basic-card"] }); +const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const defaultMethods = Object.freeze([basicCard]); const defaultDetails = Object.freeze({ total: { @@ -56,7 +56,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -94,38 +94,12 @@ }, "If the length of the methodData sequence is zero, then throw a TypeError"); test(() => { - assert_throws( - { - name: "TypeError", - }, - () => { - new PaymentRequest( - [ - { - supportedMethods: [], - }, - ], - { - total: { - label: "", - amount: { - currency: "USD", - value: "1.00", - }, - }, - } - ); - } - ); -}, "If the length of the paymentMethod.supportedMethods sequence is zero, " + "then throw a TypeError"); - -test(() => { let itThrows = false; try { new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: ["some-data"], }, ], @@ -149,7 +123,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: { some: "data", }, @@ -178,7 +152,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: recursiveDictionary, }, ], @@ -202,7 +176,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: "a string", }, ], @@ -226,7 +200,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: null, }, ], @@ -287,7 +261,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -325,7 +299,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -352,7 +326,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -385,7 +359,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: { supportedTypes: ["debit"], }, @@ -431,7 +405,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -566,7 +540,7 @@ }, () => { const invalidModifier = { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", total: { label: "", amount: { @@ -578,7 +552,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -605,7 +579,7 @@ }, () => { const invalidModifier = { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", total: { label: "", amount: { @@ -626,7 +600,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -642,7 +616,7 @@ ); } ); - }, `If amount.value of additionalDisplayItems is is not a valid decimal monetary value (in this case "${amount}"), then throw a TypeError`); + }, `If amount.value of additionalDisplayItems is not a valid decimal monetary value (in this case "${amount}"), then throw a TypeError`); } test(() => { @@ -651,7 +625,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -664,7 +638,7 @@ }, modifiers: [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: ["some-data"], }, ], @@ -682,7 +656,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -695,7 +669,7 @@ }, modifiers: [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: { some: "data", }, @@ -707,7 +681,7 @@ itThrows = true; } assert_false(itThrows, "shouldn't throw when given an object value"); -}, "Modifier data must be JSON-serializable object (a object in this case)"); +}, "Modifier data must be JSON-serializable object (an object in this case)"); test(() => { const recursiveDictionary = {}; @@ -720,7 +694,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -733,7 +707,7 @@ }, modifiers: [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: recursiveDictionary, }, ], @@ -749,7 +723,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -762,7 +736,7 @@ }, modifiers: [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: "a string", }, ], @@ -778,7 +752,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], { @@ -791,7 +765,7 @@ }, modifiers: [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", data: null, }, ], @@ -811,7 +785,7 @@ new PaymentRequest( [ { - supportedMethods: ["basic-card"], + supportedMethods: "basic-card", }, ], {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https-expected.txt new file mode 100644 index 0000000..3740d2c8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL Test for PaymentRequest identifier usage Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https.html index 8e3c3446..7a99a03 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https.html
@@ -8,10 +8,10 @@ <script> async_test((t) => { onload = t.step_func_done(() => { - var request = new window[0].PaymentRequest([{supportedMethods: ['foo']}], {id: 'my_payment_id', total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}); + var request = new window[0].PaymentRequest([{supportedMethods: 'foo'}], {id: 'my_payment_id', total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}); assert_equals(request.id, 'my_payment_id', 'Payment identifier is not reflected correctly in PaymentRequest.id'); - request = new window[0].PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}); + request = new window[0].PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}); assert_equals(request.id.length, 36, 'Generated payment identifier is not of correct length.'); }); });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-in-iframe-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-in-iframe-expected.txt new file mode 100644 index 0000000..d4aa504 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-in-iframe-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +FAIL Test for PaymentRequest in an iframe (see also +https://github.com/w3c/browser-payment-api/issues/2) assert_throws: If the browsing context of the script calling the constructor is not a top-level browsing context, then throw a SecurityError. function "function () { + new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}); + }" threw object "TypeError: Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence." ("TypeError") expected object "[object Object]" ("SecurityError") +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-in-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-in-iframe.html index 9ca9f4b..8ee6928c 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-in-iframe.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-in-iframe.html
@@ -11,7 +11,7 @@ <script> window.top.test(function() { window.top.assert_throws({name: 'SecurityError'}, function() { - new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}); + new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}); }, 'If the browsing context of the script calling the constructor is not a top-level browsing context, then throw a SecurityError.'); }); </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https-expected.txt new file mode 100644 index 0000000..ac7a844c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL onshippingaddresschange attribute is a generic handler for "shippingaddresschange" Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL onshippingaddresschange attribute is a handler for PaymentRequestUpdateEvent Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL onshippingaddresschange attribute and listeners both work Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html index 7d5530a..6b68783 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html
@@ -7,7 +7,7 @@ <script src="/resources/testharnessreport.js"></script> <script> "use strict"; -const basicCard = Object.freeze({ supportedMethods: ["basic-card"] }); +const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const defaultMethods = Object.freeze([basicCard]); const defaultDetails = Object.freeze({ total: {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https-expected.txt new file mode 100644 index 0000000..1458d6d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL onshippingoptionchange attribute is a generic handler for "shippingoptionchange" Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL onshippingoptionchange attribute is a handler for PaymentRequestUpdateEvent Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +FAIL onshippingoptionchange attribute and listeners both work Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html index 05c3dbf..29c1189 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html
@@ -7,7 +7,7 @@ <script src="/resources/testharnessreport.js"></script> <script> "use strict"; -const basicCard = Object.freeze({ supportedMethods: ["basic-card"] }); +const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const defaultMethods = Object.freeze([basicCard]); const defaultDetails = Object.freeze({ total: {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-response-id.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-response-id.html index a28f3b24..90a2cfbb 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-response-id.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-response-id.html
@@ -32,7 +32,7 @@ } const supportedInstruments = [{ - supportedMethods: ['https://android.com/pay'], + supportedMethods: 'https://android.com/pay', data: { merchantName: 'Rouslan Solomakhin', merchantId: '00184145120947117657', @@ -47,7 +47,7 @@ }, }, }, { - supportedMethods: ['basic-card'], + supportedMethods: 'basic-card', data: { supportedNetworks: ['unionpay', 'visa', 'mastercard', 'amex', 'discover', 'diners', 'jcb', 'mir',
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html index 1bdbba4..01859c1b 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
@@ -7,7 +7,7 @@ <script src="/resources/testharnessreport.js"></script> <script> 'use strict'; -const basicCard = Object.freeze({ supportedMethods: ["basic-card"] }); +const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const defaultMethods = Object.freeze([basicCard]); const defaultDetails = Object.freeze({ total: {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-constructor.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-constructor.https-expected.txt new file mode 100644 index 0000000..720ad614 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-constructor.https-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +PASS PaymentRequestUpdateEvent can be constructed in secure-context +PASS PaymentRequestUpdateEvent can be constructed with an EventInitDict, even if not trusted +FAIL PaymentRequestUpdateEvent can be dispatched, even if not trusted Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-constructor.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-constructor.https.html index bb83e5d..e158a14 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-constructor.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-constructor.https.html
@@ -6,7 +6,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> -const basicCard = Object.freeze({ supportedMethods: ["basic-card"] }); +const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const defaultMethods = Object.freeze([basicCard]); const defaultDetails = Object.freeze({ total: {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-updatewith-method.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-updatewith-method.https-expected.txt index 4ffc7a1..383d733 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-updatewith-method.https-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-updatewith-method.https-expected.txt
@@ -1,10 +1,8 @@ This is a testharness.js-based test. -PASS Let target be the request which is dispatching the event. +FAIL Let target be the request which is dispatching the event. Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. FAIL Calling .updateWith() with an undispatched untrusted event throws "InvalidStateError" assert_throws: untrusted event of type "just a test" must throw "InvalidStateError" function "() => { ev.updateWith(Promise.resolve()); }" did not throw -FAIL Calling .updateWith() with a dispatched, untrusted event, throws "InvalidStateError" assert_throws: untrusted event of type "just a test" must throw "InvalidStateError" function "() => { - ev.updateWith(Promise.resolve()) - }" did not throw +FAIL Calling .updateWith() with a dispatched, untrusted event, throws "InvalidStateError" Failed to construct 'PaymentRequest': The provided value cannot be converted to a sequence. Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-updatewith-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-updatewith-method.https.html index 98a418c..adacdf3 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-updatewith-method.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-update-event-updatewith-method.https.html
@@ -6,7 +6,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> -const basicCard = Object.freeze({ supportedMethods: ["basic-card"] }); +const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const defaultMethods = Object.freeze([basicCard]); const defaultDetails = Object.freeze({ total: {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/slotchange-customelements.html b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/slotchange-customelements.html new file mode 100644 index 0000000..b0cf932 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/slotchange-customelements.html
@@ -0,0 +1,55 @@ +<!DOCTYPE html> +<html> +<head> +<title>Shadow DOM: slotchange customelements</title> +<meta name="author" title="Surma" href="mailto:surma@google.com"> +<link rel="help" href="https://dom.spec.whatwg.org/#signaling-slot-change"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<slots-in-constructor id="constructor-upgrade"><div></div></slots-in-constructor> +<slots-in-callback id="callback-upgrade"><div></div></slots-in-callback> +<script> +var calls = []; +class SlotsInConstructor extends HTMLElement { + constructor() { + super(); + this.attachShadow({mode: 'open'}); + this.shadowRoot.innerHTML = '<slot></slot>'; + var slot = this.shadowRoot.children[0]; + slot.addEventListener('slotchange', function() { + calls.push(this.id); + }.bind(this)); + } +} +customElements.define('slots-in-constructor', SlotsInConstructor); +class SlotsInCallback extends HTMLElement { + constructor() { + super(); + } + + connectedCallback() { + this.attachShadow({mode: 'open'}); + this.shadowRoot.innerHTML = '<slot></slot>'; + var slot = this.shadowRoot.children[0]; + slot.addEventListener('slotchange', function() { + calls.push(this.id); + }.bind(this)); + } +} +customElements.define('slots-in-callback', SlotsInCallback); +</script> +<slots-in-constructor id="constructor-parser"><div></div></slots-in-constructor> +<slots-in-callback id="callback-parser"><div></div></slots-in-callback> +<script> +test(function () { + assert_true(calls.includes("constructor-parser")); + assert_true(calls.includes("callback-parser")); + assert_true(calls.includes("constructor-upgrade")); + assert_true(calls.includes("callback-upgrade")); +}, 'slotchange must fire on initialization of custom elements with slotted children'); +done(); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest-expected.txt deleted file mode 100644 index beacd89..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = 1 duplicate test name: "GetPutImageDataTestCase " -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html b/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html index ab075af..630d6853 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html
@@ -3,6 +3,8 @@ <script> var canvas = document.createElement('canvas'); +canvas.width = 5; +canvas.height = 5; var ctx = canvas.getContext('2d'); function getPutImageData(numIters, ctx, rgba) { @@ -39,15 +41,15 @@ } var testScenarios = [ - ['GetPutImageDataTestCase ', 50, ctx, '0, 0, 0, 0.0'], - ['GetPutImageDataTestCase ', 50, ctx, '0, 0, 0, 0.5'], - ['GetPutImageDataTestCase ', 50, ctx, '0, 0, 0, 1.0'], - ['GetPutImageDataTestCase ', 50, ctx, '127, 128, 129, 0.49'], - ['GetPutImageDataTestCase ', 50, ctx, '127, 128, 129, 0.51'], - ['GetPutImageDataTestCase ', 50, ctx, '127, 128, 129, 0.5'], - ['GetPutImageDataTestCase ', 50, ctx, '128, 128, 128, 0.0'], - ['GetPutImageDataTestCase ', 50, ctx, '128, 128, 128, 0.5'], - ['GetPutImageDataTestCase ', 50, ctx, '128, 128, 128, 1.0'], + ['GetPutImageDataTestCase0 ', 50, ctx, '0, 0, 0, 0.0'], + ['GetPutImageDataTestCase1 ', 50, ctx, '0, 0, 0, 0.5'], + ['GetPutImageDataTestCase2 ', 50, ctx, '0, 0, 0, 1.0'], + ['GetPutImageDataTestCase3 ', 50, ctx, '127, 128, 129, 0.49'], + ['GetPutImageDataTestCase4 ', 50, ctx, '127, 128, 129, 0.51'], + ['GetPutImageDataTestCase5 ', 50, ctx, '127, 128, 129, 0.5'], + ['GetPutImageDataTestCase6 ', 50, ctx, '128, 128, 128, 0.0'], + ['GetPutImageDataTestCase7 ', 50, ctx, '128, 128, 128, 0.5'], + ['GetPutImageDataTestCase8 ', 50, ctx, '128, 128, 128, 1.0'], ]; generate_tests(getPutImageData, testScenarios);
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt index 182d8a9..d651bbc 100644 --- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
@@ -185,6 +185,7 @@ left: auto letter-spacing: normal lighting-color: rgb(255, 255, 255) +line-break: auto line-height: normal line-height-step: 0px list-style-image: none
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt index 9cd914c..e5a7c17 100644 --- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
@@ -185,6 +185,7 @@ left: auto letter-spacing: normal lighting-color: rgb(255, 255, 255) +line-break: auto line-height: normal line-height-step: 0px list-style-image: none
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/cross-frame-object-access-expected.txt b/third_party/WebKit/LayoutTests/http/tests/plugins/cross-frame-object-access-expected.txt index 6fef89e5..a4c1bbe 100644 --- a/third_party/WebKit/LayoutTests/http/tests/plugins/cross-frame-object-access-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/plugins/cross-frame-object-access-expected.txt
@@ -8,7 +8,7 @@ This tests that plugins can access objects in other frames as allowed by the security model enforced in WebCore. Error: Error: Failed conversion between PP_Var and V8 value -Error: Uncaught [object DOMException] +Error: Uncaught Error: Error: Failed conversion between PP_Var and V8 value -Error: Uncaught [object DOMException] +Error: Uncaught SUCCESS
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 3007e262..14fde4d 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
@@ -179,7 +179,6 @@ getter message getter name method constructor - method toString interface DOMMatrix : DOMMatrixReadOnly attribute @@toStringTag getter a
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/getPutImageDataPairTest-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/getPutImageDataPairTest-expected.txt deleted file mode 100644 index beacd89..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/getPutImageDataPairTest-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = 1 duplicate test name: "GetPutImageDataTestCase " -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/gpu/fast/canvas/getPutImageDataPairTest-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/gpu/fast/canvas/getPutImageDataPairTest-expected.txt deleted file mode 100644 index beacd89..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/gpu/fast/canvas/getPutImageDataPairTest-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = 1 duplicate test name: "GetPutImageDataTestCase " -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 798e4e8..08b3a3bc 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -112,7 +112,6 @@ getter message getter name method constructor - method toString interface DOMMatrix : DOMMatrixReadOnly attribute @@toStringTag getter a
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt index 4e696b1..95759b9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -103,7 +103,6 @@ [Worker] getter message [Worker] getter name [Worker] method constructor -[Worker] method toString [Worker] interface DOMMatrix : DOMMatrixReadOnly [Worker] attribute @@toStringTag [Worker] getter a
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt index 715eb4fc..3bc1c24 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -711,7 +711,6 @@ getter message getter name method constructor - method toString interface DOMImplementation attribute @@toStringTag method constructor
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt index 38903fe..b6e08c9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -103,7 +103,6 @@ [Worker] getter message [Worker] getter name [Worker] method constructor -[Worker] method toString [Worker] interface DOMMatrix : DOMMatrixReadOnly [Worker] attribute @@toStringTag [Worker] getter a
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt index 1a42282..da23fd5 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -640,7 +640,6 @@ getter message getter name method constructor - method toString interface DOMImplementation attribute @@toStringTag method constructor
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/gpu/fast/canvas/getPutImageDataPairTest-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/virtual/gpu/fast/canvas/getPutImageDataPairTest-expected.txt deleted file mode 100644 index beacd89..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/virtual/gpu/fast/canvas/getPutImageDataPairTest-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -Harness Error. harness_status.status = 1 , harness_status.message = 1 duplicate test name: "GetPutImageDataTestCase " -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -PASS GetPutImageDataTestCase -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt index b4ae6eb..49c9a86 100644 --- a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
@@ -185,6 +185,7 @@ left: auto letter-spacing: normal lighting-color: rgb(255, 255, 255) +line-break: auto line-height: normal line-height-step: 0px list-style-image: none
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 10cef54..3d3cb4c 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -179,7 +179,6 @@ getter message getter name method constructor - method toString interface DOMMatrix : DOMMatrixReadOnly attribute @@toStringTag getter a
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-dedicated-worker-expected.txt index 59e2341..7b49c67 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -141,7 +141,6 @@ [Worker] getter message [Worker] getter name [Worker] method constructor -[Worker] method toString [Worker] interface DOMMatrix : DOMMatrixReadOnly [Worker] attribute @@toStringTag [Worker] getter a
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt index 44e6215..ee312d3 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -346,6 +346,17 @@ method setValueAtTime method setValueCurveAtTime setter value +interface AudioParamMap + attribute @@toStringTag + getter size + method @@iterator + method constructor + method entries + method forEach + method get + method has + method keys + method values interface AudioProcessingEvent : Event attribute @@toStringTag getter inputBuffer @@ -1130,7 +1141,6 @@ getter message getter name method constructor - method toString interface DOMImplementation attribute @@toStringTag method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-shared-worker-expected.txt index d7d9625..bb7e134 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -141,7 +141,6 @@ [Worker] getter message [Worker] getter name [Worker] method constructor -[Worker] method toString [Worker] interface DOMMatrix : DOMMatrixReadOnly [Worker] attribute @@toStringTag [Worker] getter a
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 36c2af57..30f11f67 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -152,7 +152,6 @@ getter message getter name method constructor - method toString interface DOMMatrix : DOMMatrixReadOnly getter a getter b
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 09aa1e3..0055abc 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -112,7 +112,6 @@ getter message getter name method constructor - method toString interface DOMMatrix : DOMMatrixReadOnly attribute @@toStringTag getter a
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt index 1ae6a93..ae272a94 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt
@@ -165,6 +165,7 @@ length letterSpacing lightingColor +lineBreak lineHeight listStyle listStyleImage
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-property-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-property-listing-expected.txt index 1dcb8b0..81b5942 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-property-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-property-listing-expected.txt
@@ -223,6 +223,7 @@ left letter-spacing lighting-color + line-break line-height list-style-image list-style-position @@ -725,6 +726,4 @@ transition-timing-function -webkit-user-select user-select - line-break - -webkit-line-break
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt index 8247901..59343c3 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -103,7 +103,6 @@ [Worker] getter message [Worker] getter name [Worker] method constructor -[Worker] method toString [Worker] interface DOMMatrix : DOMMatrixReadOnly [Worker] attribute @@toStringTag [Worker] getter a
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt index d4f6a25f..580d086 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -103,7 +103,6 @@ [Worker] getter message [Worker] getter name [Worker] method constructor -[Worker] method toString [Worker] interface DOMMatrix : DOMMatrixReadOnly [Worker] attribute @@toStringTag [Worker] getter a
diff --git a/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt b/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt index 8f7aadd..14e521b2 100644 --- a/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt
@@ -169,6 +169,7 @@ length letterSpacing lightingColor +lineBreak lineHeight lineHeightStep listStyle
diff --git a/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt index 65a3817..b7c4d50b7 100644 --- a/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt
@@ -227,6 +227,7 @@ left letter-spacing lighting-color + line-break line-height line-height-step list-style-image @@ -781,6 +782,4 @@ transition-timing-function -webkit-user-select user-select - line-break - -webkit-line-break
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 7c83dff..7f223fac 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
@@ -141,7 +141,6 @@ [Worker] getter message [Worker] getter name [Worker] method constructor -[Worker] method toString [Worker] interface DOMMatrix : DOMMatrixReadOnly [Worker] attribute @@toStringTag [Worker] getter a
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 d530b63..1f08975 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -346,6 +346,17 @@ method setValueAtTime method setValueCurveAtTime setter value +interface AudioParamMap + attribute @@toStringTag + getter size + method @@iterator + method constructor + method entries + method forEach + method get + method has + method keys + method values interface AudioProcessingEvent : Event attribute @@toStringTag getter inputBuffer @@ -1130,7 +1141,6 @@ getter message getter name method constructor - method toString interface DOMImplementation attribute @@toStringTag method constructor
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 8c28435..361fdf5 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
@@ -141,7 +141,6 @@ [Worker] getter message [Worker] getter name [Worker] method constructor -[Worker] method toString [Worker] interface DOMMatrix : DOMMatrixReadOnly [Worker] attribute @@toStringTag [Worker] getter a
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializerTest.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializerTest.cpp index 52848148..a335321 100644 --- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializerTest.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializerTest.cpp
@@ -168,7 +168,7 @@ ASSERT_TRUE(HadDOMException("DataCloneError", script_state, exception_state)); DOMException* dom_exception = V8DOMException::toImpl(exception_state.GetException().As<v8::Object>()); - EXPECT_TRUE(dom_exception->toString().Contains("postMessage")); + EXPECT_TRUE(dom_exception->message().Contains("postMessage")); } TEST(V8ScriptValueSerializerTest, RethrowsScriptError) {
diff --git a/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl index ea50c0a..86d20601 100644 --- a/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl +++ b/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl
@@ -602,6 +602,30 @@ interfaceTemplate->Inherit(intrinsicIteratorPrototypeInterfaceTemplate); {% endif %} + {% if interface_name == 'DOMException' %} + // The WebIDL spec states that DOMException objects have a few peculiarities. + // One of them is similar to what it mandates for Iterator objects when it + // comes to the inheritance chain. Instead of + // DOMException -> prototype -> %ObjectPrototype% + // we have + // DOMException -> prototype -> %ErrorPrototype% -> %ObjectPrototype% + // so that DOMException objects "inherit" toString() and a few properties + // from %ErrorPrototype%. + // See https://heycam.github.io/webidl/#es-DOMException-specialness. + // + // We achieve this with the same hack we use for Iterators: create a new + // function template with no prototype, set its "prototype" property to + // %ErrorPrototype% and make |interfaceTemplate| inherit from it. When + // |interfaceTemplate| is instantiated, its prototype.__proto__ will point to + // |intrinsicErrorPrototypeInterfaceTemplate|'s "prototype" property. + v8::Local<v8::FunctionTemplate> intrinsicErrorPrototypeInterfaceTemplate = + v8::FunctionTemplate::New(isolate); + intrinsicErrorPrototypeInterfaceTemplate->RemovePrototype(); + intrinsicErrorPrototypeInterfaceTemplate->SetIntrinsicDataProperty( + V8AtomicString(isolate, "prototype"), v8::kErrorPrototype); + interfaceTemplate->Inherit(intrinsicErrorPrototypeInterfaceTemplate); + {% endif %} + {% if interface_name == 'Location' %} // Symbol.toPrimitive // Prevent author scripts to inject Symbol.toPrimitive property into location
diff --git a/third_party/WebKit/Source/build/scripts/make_names.py b/third_party/WebKit/Source/build/scripts/make_names.py index 19488fb0..95746bf 100755 --- a/third_party/WebKit/Source/build/scripts/make_names.py +++ b/third_party/WebKit/Source/build/scripts/make_names.py
@@ -40,7 +40,7 @@ # FIXME: Remove this special case for the ugly x-webkit-foo attributes. if entry['name'].startswith('-webkit-'): return entry['name'].replace('-', '_')[1:] - return name_utilities.cpp_name(entry).replace('-', '_') + return name_utilities.cpp_name(entry).replace('-', '_').replace(' ', '_') class MakeNamesWriter(json5_generator.Writer):
diff --git a/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp b/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp index b3d9c8a5..89709fa 100644 --- a/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp +++ b/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp
@@ -174,7 +174,7 @@ CSSPropertyVectorEffect, CSSPropertyPaintOrder, CSSPropertyD, CSSPropertyCx, CSSPropertyCy, CSSPropertyX, CSSPropertyY, CSSPropertyR, CSSPropertyRx, CSSPropertyRy, CSSPropertyTranslate, CSSPropertyRotate, CSSPropertyScale, - CSSPropertyCaretColor}; + CSSPropertyCaretColor, CSSPropertyLineBreak}; CSSValueID CssIdentifierForFontSizeKeyword(int keyword_size) { DCHECK_NE(keyword_size, 0);
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5 index a6edc158..968d9a4 100644 --- a/third_party/WebKit/Source/core/css/CSSProperties.json5 +++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -3043,6 +3043,11 @@ default_value: "auto", field_group: "rare-inherited", }, + { + name: "line-break", + inherited: true, + type_name: "LineBreak", + }, // An Apple extension. { name: "-webkit-line-clamp", @@ -4151,10 +4156,6 @@ alias_for: "justify-content", }, { - name: "line-break", - alias_for: "-webkit-line-break", - }, - { name: "-webkit-opacity", alias_for: "opacity", },
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp index 7aaf7c4..b7f4e48 100644 --- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp +++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -3002,6 +3002,7 @@ return ZoomAdjustedPixelValue(style.WordSpacing(), style); case CSSPropertyWordWrap: return CSSIdentifierValue::Create(style.OverflowWrap()); + case CSSPropertyLineBreak: case CSSPropertyWebkitLineBreak: return CSSIdentifierValue::Create(style.GetLineBreak()); case CSSPropertyResize:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp index d4d57bb..1a37b6e 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
@@ -806,6 +806,9 @@ return value_id == CSSValueAuto || value_id == CSSValueNone || value_id == CSSValueAntialiased || value_id == CSSValueSubpixelAntialiased; + case CSSPropertyLineBreak: + return value_id == CSSValueAuto || value_id == CSSValueLoose || + value_id == CSSValueNormal || value_id == CSSValueStrict; case CSSPropertyWebkitLineBreak: return value_id == CSSValueAuto || value_id == CSSValueLoose || value_id == CSSValueNormal || value_id == CSSValueStrict || @@ -952,6 +955,7 @@ case CSSPropertyFlexWrap: case CSSPropertyFontKerning: case CSSPropertyWebkitFontSmoothing: + case CSSPropertyLineBreak: case CSSPropertyWebkitLineBreak: case CSSPropertyWebkitMarginAfterCollapse: case CSSPropertyWebkitMarginBeforeCollapse:
diff --git a/third_party/WebKit/Source/core/dom/DOMException.cpp b/third_party/WebKit/Source/core/dom/DOMException.cpp index 739f80b..1f3ae0a 100644 --- a/third_party/WebKit/Source/core/dom/DOMException.cpp +++ b/third_party/WebKit/Source/core/dom/DOMException.cpp
@@ -195,10 +195,6 @@ return new DOMException(GetErrorCode(name), name, message, message); } -String DOMException::toString() const { - return name() + ": " + message(); -} - String DOMException::ToStringForConsole() const { return name() + ": " + MessageForConsole(); }
diff --git a/third_party/WebKit/Source/core/dom/DOMException.h b/third_party/WebKit/Source/core/dom/DOMException.h index c0c503c..74b61e5 100644 --- a/third_party/WebKit/Source/core/dom/DOMException.h +++ b/third_party/WebKit/Source/core/dom/DOMException.h
@@ -57,7 +57,6 @@ // This is the message that's exposed to JavaScript: never return unsanitized // data. String message() const { return sanitized_message_; } - String toString() const; // This is the message that's exposed to the console: if an unsanitized // message is present, we prefer it.
diff --git a/third_party/WebKit/Source/core/dom/DOMException.idl b/third_party/WebKit/Source/core/dom/DOMException.idl index 5056da9..bbf3701 100644 --- a/third_party/WebKit/Source/core/dom/DOMException.idl +++ b/third_party/WebKit/Source/core/dom/DOMException.idl
@@ -40,9 +40,6 @@ readonly attribute DOMString name; readonly attribute DOMString message; - // Override in a Mozilla compatible format - [NotEnumerable] DOMString toString(); - // ExceptionCode const unsigned short INDEX_SIZE_ERR = 1; const unsigned short DOMSTRING_SIZE_ERR = 2;
diff --git a/third_party/WebKit/Source/core/editing/markers/SpellingMarkerTest.cpp b/third_party/WebKit/Source/core/editing/markers/SpellingMarkerTest.cpp index bffeadfd..32d076c44 100644 --- a/third_party/WebKit/Source/core/editing/markers/SpellingMarkerTest.cpp +++ b/third_party/WebKit/Source/core/editing/markers/SpellingMarkerTest.cpp
@@ -8,23 +8,23 @@ namespace blink { -const char* const kDescription = "Test description"; +const char* const kTestDescription = "Test description"; class SpellingMarkerTest : public ::testing::Test {}; TEST_F(SpellingMarkerTest, MarkerType) { - DocumentMarker* marker = new SpellingMarker(0, 1, kDescription); + DocumentMarker* marker = new SpellingMarker(0, 1, kTestDescription); EXPECT_EQ(DocumentMarker::kSpelling, marker->GetType()); } TEST_F(SpellingMarkerTest, IsSpellCheckMarker) { - DocumentMarker* marker = new SpellingMarker(0, 1, kDescription); + DocumentMarker* marker = new SpellingMarker(0, 1, kTestDescription); EXPECT_TRUE(IsSpellCheckMarker(*marker)); } TEST_F(SpellingMarkerTest, ConstructorAndGetters) { - SpellingMarker* marker = new SpellingMarker(0, 1, kDescription); - EXPECT_EQ(kDescription, marker->Description()); + SpellingMarker* marker = new SpellingMarker(0, 1, kTestDescription); + EXPECT_EQ(kTestDescription, marker->Description()); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.cpp b/third_party/WebKit/Source/core/frame/UseCounter.cpp index 18456c9..f4d1b9b 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.cpp +++ b/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -1070,7 +1070,7 @@ return 554; case CSSPropertyMaxBlockSize: return 555; - case CSSPropertyAliasLineBreak: + case CSSPropertyLineBreak: return 556; case CSSPropertyPlaceContent: return 557;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp index 1180cfb0..f624e63 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
@@ -17,6 +17,7 @@ #include "platform/loader/fetch/ClientHintsPreferences.h" #include "platform/weborigin/SecurityOrigin.h" #include "public/platform/Platform.h" +#include "public/platform/WebClientHintsType.h" #include "public/platform/WebURLLoaderMockFactory.h" #include "testing/gtest/include/gtest/gtest.h" @@ -84,12 +85,15 @@ EXPECT_STREQ(base_url, preload_request_->BaseURL().GetString().Ascii().data()); EXPECT_EQ(width, preload_request_->ResourceWidth()); - EXPECT_EQ(preferences.ShouldSendDPR(), - preload_request_->Preferences().ShouldSendDPR()); - EXPECT_EQ(preferences.ShouldSendResourceWidth(), - preload_request_->Preferences().ShouldSendResourceWidth()); - EXPECT_EQ(preferences.ShouldSendViewportWidth(), - preload_request_->Preferences().ShouldSendViewportWidth()); + EXPECT_EQ( + preferences.ShouldSend(kWebClientHintsTypeDpr), + preload_request_->Preferences().ShouldSend(kWebClientHintsTypeDpr)); + EXPECT_EQ(preferences.ShouldSend(kWebClientHintsTypeResourceWidth), + preload_request_->Preferences().ShouldSend( + kWebClientHintsTypeResourceWidth)); + EXPECT_EQ(preferences.ShouldSend(kWebClientHintsTypeViewportWidth), + preload_request_->Preferences().ShouldSend( + kWebClientHintsTypeViewportWidth)); } } @@ -503,12 +507,12 @@ ClientHintsPreferences resource_width; ClientHintsPreferences all; ClientHintsPreferences viewport_width; - dpr.SetShouldSendDPR(true); - all.SetShouldSendDPR(true); - resource_width.SetShouldSendResourceWidth(true); - all.SetShouldSendResourceWidth(true); - viewport_width.SetShouldSendViewportWidth(true); - all.SetShouldSendViewportWidth(true); + dpr.SetShouldSendForTesting(kWebClientHintsTypeDpr); + all.SetShouldSendForTesting(kWebClientHintsTypeDpr); + resource_width.SetShouldSendForTesting(kWebClientHintsTypeResourceWidth); + all.SetShouldSendForTesting(kWebClientHintsTypeResourceWidth); + viewport_width.SetShouldSendForTesting(kWebClientHintsTypeViewportWidth); + all.SetShouldSendForTesting(kWebClientHintsTypeViewportWidth); TestCase test_cases[] = { {"http://example.test", "<meta http-equiv='accept-ch' content='bla'><img srcset='bla.gif 320w, "
diff --git a/third_party/WebKit/Source/core/inspector/AddStringToDigestor.cpp b/third_party/WebKit/Source/core/inspector/AddStringToDigestor.cpp new file mode 100644 index 0000000..2c59eba --- /dev/null +++ b/third_party/WebKit/Source/core/inspector/AddStringToDigestor.cpp
@@ -0,0 +1,18 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/inspector/AddStringToDigestor.h" + +#include "platform/wtf/text/WTFString.h" +#include "public/platform/WebCrypto.h" + +namespace blink { + +void AddStringToDigestor(WebCryptoDigestor* digestor, const String& string) { + const CString c_string = string.Utf8(); + digestor->Consume(reinterpret_cast<const unsigned char*>(c_string.data()), + c_string.length()); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/AddStringToDigestor.h b/third_party/WebKit/Source/core/inspector/AddStringToDigestor.h new file mode 100644 index 0000000..2981c38 --- /dev/null +++ b/third_party/WebKit/Source/core/inspector/AddStringToDigestor.h
@@ -0,0 +1,17 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef AddStringToDigestor_h +#define AddStringToDigestor_h + +namespace WTF { +class String; +} + +namespace blink { +class WebCryptoDigestor; +void AddStringToDigestor(WebCryptoDigestor*, const WTF::String&); +} // namespace blink + +#endif // AddStringToDigestor_h
diff --git a/third_party/WebKit/Source/core/inspector/BUILD.gn b/third_party/WebKit/Source/core/inspector/BUILD.gn index ca9d502..d824be26 100644 --- a/third_party/WebKit/Source/core/inspector/BUILD.gn +++ b/third_party/WebKit/Source/core/inspector/BUILD.gn
@@ -11,6 +11,8 @@ blink_core_sources("inspector") { sources = [ + "AddStringToDigestor.cpp", + "AddStringToDigestor.h", "ConsoleMessage.cpp", "ConsoleMessage.h", "ConsoleMessageStorage.cpp", @@ -95,18 +97,12 @@ ] jumbo_excluded_sources = [ - # Collides with DOMPatchSupport.cpp (patch incoming) - "InspectorAnimationAgent.cpp", - # Collides with InspectorPageAgent.cpp and # NetworkResourcesData.cpp (patch incoming) "InspectorNetworkAgent.cpp", # Collides with InspectorPageAgent.cpp (patch incoming) "MainThreadDebugger.cpp", - - "InspectorOverlayAgent.cpp", # Way too many different "Response" - "InspectorEmulationAgent.cpp", # Way too many different "Response" ] configs += [
diff --git a/third_party/WebKit/Source/core/inspector/DOMPatchSupport.cpp b/third_party/WebKit/Source/core/inspector/DOMPatchSupport.cpp index c406897..7de5ea5 100644 --- a/third_party/WebKit/Source/core/inspector/DOMPatchSupport.cpp +++ b/third_party/WebKit/Source/core/inspector/DOMPatchSupport.cpp
@@ -43,6 +43,7 @@ #include "core/html/HTMLDocument.h" #include "core/html/HTMLHeadElement.h" #include "core/html/parser/HTMLDocumentParser.h" +#include "core/inspector/AddStringToDigestor.h" #include "core/inspector/DOMEditor.h" #include "core/inspector/InspectorHistory.h" #include "core/xml/parser/XMLDocumentParser.h" @@ -427,13 +428,6 @@ return true; } -static void AddStringToDigestor(WebCryptoDigestor* digestor, - const String& string) { - digestor->Consume( - reinterpret_cast<const unsigned char*>(string.Utf8().data()), - string.length()); -} - DOMPatchSupport::Digest* DOMPatchSupport::CreateDigest( Node* node, UnusedNodesMap* unused_nodes_map) {
diff --git a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp index 8d2ea53..a4e464a 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
@@ -22,6 +22,7 @@ #include "core/css/resolver/StyleResolver.h" #include "core/dom/DOMNodeIds.h" #include "core/frame/LocalFrame.h" +#include "core/inspector/AddStringToDigestor.h" #include "core/inspector/InspectedFrames.h" #include "core/inspector/InspectorCSSAgent.h" #include "core/inspector/InspectorStyleSheet.h" @@ -454,13 +455,6 @@ CSSPropertyTransitionProperty, CSSPropertyTransitionTimingFunction, }; -static void AddStringToDigestor(WebCryptoDigestor* digestor, - const String& string) { - digestor->Consume( - reinterpret_cast<const unsigned char*>(string.Ascii().data()), - string.length()); -} - String InspectorAnimationAgent::CreateCSSId(blink::Animation& animation) { String type = id_to_animation_type_.at(String::Number(animation.SequenceNumber()));
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp index 811342a..8674241 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -786,19 +786,7 @@ if (!RuntimeEnabledFeatures::ClientHintsEnabled()) return; - bool should_send_device_ram = - GetClientHintsPreferences().ShouldSendDeviceRAM() || - hints_preferences.ShouldSendDeviceRAM(); - bool should_send_dpr = GetClientHintsPreferences().ShouldSendDPR() || - hints_preferences.ShouldSendDPR(); - bool should_send_resource_width = - GetClientHintsPreferences().ShouldSendResourceWidth() || - hints_preferences.ShouldSendResourceWidth(); - bool should_send_viewport_width = - GetClientHintsPreferences().ShouldSendViewportWidth() || - hints_preferences.ShouldSendViewportWidth(); - - if (should_send_device_ram) { + if (ShouldSendClientHint(kWebClientHintsTypeDeviceRam, hints_preferences)) { int64_t physical_memory = MemoryCoordinator::GetPhysicalMemoryMB(); request.AddHTTPHeaderField( "device-ram", @@ -806,11 +794,11 @@ } float dpr = GetDevicePixelRatio(); - if (should_send_dpr) { + if (ShouldSendClientHint(kWebClientHintsTypeDpr, hints_preferences)) request.AddHTTPHeaderField("DPR", AtomicString(String::Number(dpr))); - } - if (should_send_resource_width) { + if (ShouldSendClientHint(kWebClientHintsTypeResourceWidth, + hints_preferences)) { if (resource_width.is_set) { float physical_width = resource_width.width * dpr; request.AddHTTPHeaderField( @@ -818,7 +806,9 @@ } } - if (should_send_viewport_width && !IsDetached() && GetFrame()->View()) { + if (ShouldSendClientHint(kWebClientHintsTypeViewportWidth, + hints_preferences) && + !IsDetached() && GetFrame()->View()) { request.AddHTTPHeaderField( "Viewport-Width", AtomicString(String::Number(GetFrame()->View()->ViewportWidth()))); @@ -1095,6 +1085,13 @@ return document_->DevicePixelRatio(); } +bool FrameFetchContext::ShouldSendClientHint( + WebClientHintsType type, + const ClientHintsPreferences& hints_preferences) const { + return GetClientHintsPreferences().ShouldSend(type) || + hints_preferences.ShouldSend(type); +} + std::unique_ptr<WebURLLoader> FrameFetchContext::CreateURLLoader( const ResourceRequest& request) { DCHECK(!IsDetached());
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.h b/third_party/WebKit/Source/core/loader/FrameFetchContext.h index a9d3315..9699931 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.h +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.h
@@ -217,6 +217,8 @@ RefPtr<SecurityOrigin> GetRequestorOriginForFrameLoading(); ClientHintsPreferences GetClientHintsPreferences() const; float GetDevicePixelRatio() const; + bool ShouldSendClientHint(WebClientHintsType, + const ClientHintsPreferences&) const; Member<DocumentLoader> document_loader_; Member<Document> document_;
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp index 06bcc30..538c083 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
@@ -53,6 +53,7 @@ #include "platform/weborigin/SecurityViolationReportingPolicy.h" #include "public/platform/WebAddressSpace.h" #include "public/platform/WebCachePolicy.h" +#include "public/platform/WebClientHintsType.h" #include "public/platform/WebDocumentSubresourceFilter.h" #include "public/platform/WebInsecureRequestPolicy.h" #include "testing/gmock/include/gmock/gmock.h" @@ -541,7 +542,7 @@ TEST_F(FrameFetchContextHintsTest, MonitorDeviceRAMHints) { ExpectHeader("http://www.example.com/1.gif", "device-ram", false, ""); ClientHintsPreferences preferences; - preferences.SetShouldSendDeviceRAM(true); + preferences.SetShouldSendForTesting(kWebClientHintsTypeDeviceRam); document->GetClientHintsPreferences().UpdateFrom(preferences); MemoryCoordinator::SetPhysicalMemoryMBForTesting(4096); ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "4"); @@ -559,7 +560,7 @@ TEST_F(FrameFetchContextHintsTest, MonitorDPRHints) { ExpectHeader("http://www.example.com/1.gif", "DPR", false, ""); ClientHintsPreferences preferences; - preferences.SetShouldSendDPR(true); + preferences.SetShouldSendForTesting(kWebClientHintsTypeDpr); document->GetClientHintsPreferences().UpdateFrom(preferences); ExpectHeader("http://www.example.com/1.gif", "DPR", true, "1"); dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(2.5); @@ -571,7 +572,7 @@ TEST_F(FrameFetchContextHintsTest, MonitorResourceWidthHints) { ExpectHeader("http://www.example.com/1.gif", "Width", false, ""); ClientHintsPreferences preferences; - preferences.SetShouldSendResourceWidth(true); + preferences.SetShouldSendForTesting(kWebClientHintsTypeResourceWidth); document->GetClientHintsPreferences().UpdateFrom(preferences); ExpectHeader("http://www.example.com/1.gif", "Width", true, "500", 500); ExpectHeader("http://www.example.com/1.gif", "Width", true, "667", 666.6666); @@ -584,7 +585,7 @@ TEST_F(FrameFetchContextHintsTest, MonitorViewportWidthHints) { ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", false, ""); ClientHintsPreferences preferences; - preferences.SetShouldSendViewportWidth(true); + preferences.SetShouldSendForTesting(kWebClientHintsTypeViewportWidth); document->GetClientHintsPreferences().UpdateFrom(preferences); ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", true, "500"); dummy_page_holder->GetFrameView().SetLayoutSizeFixedToFrameSize(false); @@ -602,10 +603,10 @@ ExpectHeader("http://www.example.com/1.gif", "Width", false, ""); ClientHintsPreferences preferences; - preferences.SetShouldSendDeviceRAM(true); - preferences.SetShouldSendDPR(true); - preferences.SetShouldSendResourceWidth(true); - preferences.SetShouldSendViewportWidth(true); + preferences.SetShouldSendForTesting(kWebClientHintsTypeDeviceRam); + preferences.SetShouldSendForTesting(kWebClientHintsTypeDpr); + preferences.SetShouldSendForTesting(kWebClientHintsTypeResourceWidth); + preferences.SetShouldSendForTesting(kWebClientHintsTypeViewportWidth); MemoryCoordinator::SetPhysicalMemoryMBForTesting(4096); document->GetClientHintsPreferences().UpdateFrom(preferences); ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "4"); @@ -1241,18 +1242,25 @@ request.SetFetchCredentialsMode(WebURLRequest::kFetchCredentialsModeOmit); ClientHintsPreferences client_hints_preferences; - client_hints_preferences.SetShouldSendDeviceRAM(true); - client_hints_preferences.SetShouldSendDPR(true); - client_hints_preferences.SetShouldSendResourceWidth(true); - client_hints_preferences.SetShouldSendViewportWidth(true); + client_hints_preferences.SetShouldSendForTesting( + kWebClientHintsTypeDeviceRam); + client_hints_preferences.SetShouldSendForTesting(kWebClientHintsTypeDpr); + client_hints_preferences.SetShouldSendForTesting( + kWebClientHintsTypeResourceWidth); + client_hints_preferences.SetShouldSendForTesting( + kWebClientHintsTypeViewportWidth); FetchParameters::ResourceWidth resource_width; ResourceLoaderOptions options; - document->GetClientHintsPreferences().SetShouldSendDeviceRAM(true); - document->GetClientHintsPreferences().SetShouldSendDPR(true); - document->GetClientHintsPreferences().SetShouldSendResourceWidth(true); - document->GetClientHintsPreferences().SetShouldSendViewportWidth(true); + document->GetClientHintsPreferences().SetShouldSendForTesting( + kWebClientHintsTypeDeviceRam); + document->GetClientHintsPreferences().SetShouldSendForTesting( + kWebClientHintsTypeDpr); + document->GetClientHintsPreferences().SetShouldSendForTesting( + kWebClientHintsTypeResourceWidth); + document->GetClientHintsPreferences().SetShouldSendForTesting( + kWebClientHintsTypeViewportWidth); dummy_page_holder = nullptr;
diff --git a/third_party/WebKit/Source/core/loader/ImageLoader.cpp b/third_party/WebKit/Source/core/loader/ImageLoader.cpp index 4c7a48e..5fccbd9 100644 --- a/third_party/WebKit/Source/core/loader/ImageLoader.cpp +++ b/third_party/WebKit/Source/core/loader/ImageLoader.cpp
@@ -51,6 +51,7 @@ #include "platform/weborigin/SecurityPolicy.h" #include "platform/wtf/PtrUtil.h" #include "public/platform/WebCachePolicy.h" +#include "public/platform/WebClientHintsType.h" #include "public/platform/WebURLRequest.h" namespace blink { @@ -230,7 +231,7 @@ element.GetDocument().GetSecurityOrigin(), cross_origin); } - if (client_hints_preferences.ShouldSendResourceWidth() && + if (client_hints_preferences.ShouldSend(kWebClientHintsTypeResourceWidth) && isHTMLImageElement(element)) params.SetResourceWidth(toHTMLImageElement(element).GetResourceWidth()); }
diff --git a/third_party/WebKit/Source/core/loader/private/FrameClientHintsPreferencesContext.cpp b/third_party/WebKit/Source/core/loader/private/FrameClientHintsPreferencesContext.cpp index 1dbc12ce..c5538b10 100644 --- a/third_party/WebKit/Source/core/loader/private/FrameClientHintsPreferencesContext.cpp +++ b/third_party/WebKit/Source/core/loader/private/FrameClientHintsPreferencesContext.cpp
@@ -8,24 +8,28 @@ namespace blink { +namespace { + +// Mapping from WebClientHintsType to WebFeature. The ordering should match the +// ordering of enums in WebClientHintsType. +static constexpr WebFeature kWebFeatureMapping[] = { + WebFeature::kClientHintsDeviceRAM, WebFeature::kClientHintsDPR, + WebFeature::kClientHintsResourceWidth, + WebFeature::kClientHintsViewportWidth, +}; + +static_assert(kWebClientHintsTypeLast + 1 == arraysize(kWebFeatureMapping), + "unhandled client hint type"); + +} // namespace + FrameClientHintsPreferencesContext::FrameClientHintsPreferencesContext( LocalFrame* frame) : frame_(frame) {} -void FrameClientHintsPreferencesContext::CountClientHintsDeviceRAM() { - UseCounter::Count(frame_, WebFeature::kClientHintsDeviceRAM); -} - -void FrameClientHintsPreferencesContext::CountClientHintsDPR() { - UseCounter::Count(frame_, WebFeature::kClientHintsDPR); -} - -void FrameClientHintsPreferencesContext::CountClientHintsResourceWidth() { - UseCounter::Count(frame_, WebFeature::kClientHintsResourceWidth); -} - -void FrameClientHintsPreferencesContext::CountClientHintsViewportWidth() { - UseCounter::Count(frame_, WebFeature::kClientHintsViewportWidth); +void FrameClientHintsPreferencesContext::CountClientHints( + WebClientHintsType type) { + UseCounter::Count(frame_, kWebFeatureMapping[static_cast<int32_t>(type)]); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/private/FrameClientHintsPreferencesContext.h b/third_party/WebKit/Source/core/loader/private/FrameClientHintsPreferencesContext.h index 9949e034..af04a00 100644 --- a/third_party/WebKit/Source/core/loader/private/FrameClientHintsPreferencesContext.h +++ b/third_party/WebKit/Source/core/loader/private/FrameClientHintsPreferencesContext.h
@@ -19,10 +19,7 @@ public: explicit FrameClientHintsPreferencesContext(LocalFrame*); - void CountClientHintsDeviceRAM() override; - void CountClientHintsDPR() override; - void CountClientHintsResourceWidth() override; - void CountClientHintsViewportWidth() override; + void CountClientHints(WebClientHintsType) override; private: Member<LocalFrame> frame_;
diff --git a/third_party/WebKit/Source/core/scheduler/ThrottlingTest.cpp b/third_party/WebKit/Source/core/scheduler/ThrottlingTest.cpp index 32679ca..cae8d1a 100644 --- a/third_party/WebKit/Source/core/scheduler/ThrottlingTest.cpp +++ b/third_party/WebKit/Source/core/scheduler/ThrottlingTest.cpp
@@ -68,8 +68,7 @@ class BackgroundRendererThrottlingTest : public SimTest {}; -TEST_F(BackgroundRendererThrottlingTest, - DISABLED_BackgroundRenderersAreThrottled) { +TEST_F(BackgroundRendererThrottlingTest, BackgroundRenderersAreThrottled) { SimRequest main_resource("https://example.com/", "text/html"); LoadURL("https://example.com/");
diff --git a/third_party/WebKit/Source/core/svg/SVGAngleTearOff.cpp b/third_party/WebKit/Source/core/svg/SVGAngleTearOff.cpp index 928139d..a1b7b25 100644 --- a/third_party/WebKit/Source/core/svg/SVGAngleTearOff.cpp +++ b/third_party/WebKit/Source/core/svg/SVGAngleTearOff.cpp
@@ -135,7 +135,8 @@ } DEFINE_TRACE_WRAPPERS(SVGAngleTearOff) { - visitor->TraceWrappers(contextElement()); + SVGPropertyTearOff<SVGAngle>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedBoolean.h b/third_party/WebKit/Source/core/svg/SVGAnimatedBoolean.h index 4eccd57..328ea30 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedBoolean.h +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedBoolean.h
@@ -48,7 +48,8 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGBoolean>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } protected:
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedEnumeration.h b/third_party/WebKit/Source/core/svg/SVGAnimatedEnumeration.h index c2d20e8f..d9927d5 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedEnumeration.h +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedEnumeration.h
@@ -71,7 +71,7 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGAnimatedEnumerationBase::TraceWrappers(visitor); } protected:
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedEnumerationBase.h b/third_party/WebKit/Source/core/svg/SVGAnimatedEnumerationBase.h index 3f44dc8d..aff9408c 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedEnumerationBase.h +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedEnumerationBase.h
@@ -47,6 +47,11 @@ void setBaseVal(unsigned short, ExceptionState&); + DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { + SVGAnimatedProperty<SVGEnumerationBase>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); + } + protected: SVGAnimatedEnumerationBase(SVGElement* context_element, const QualifiedName& attribute_name,
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedInteger.cpp b/third_party/WebKit/Source/core/svg/SVGAnimatedInteger.cpp index f6454ce..14b9f642 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedInteger.cpp +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedInteger.cpp
@@ -50,7 +50,8 @@ } DEFINE_TRACE_WRAPPERS(SVGAnimatedInteger) { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGInteger>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedLength.cpp b/third_party/WebKit/Source/core/svg/SVGAnimatedLength.cpp index 9039789..23b4478 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedLength.cpp +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedLength.cpp
@@ -53,7 +53,8 @@ } DEFINE_TRACE_WRAPPERS(SVGAnimatedLength) { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGLength>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedLengthList.h b/third_party/WebKit/Source/core/svg/SVGAnimatedLengthList.h index 49e6c918..9acf97d 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedLengthList.h +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedLengthList.h
@@ -52,7 +52,8 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGLengthList>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } protected:
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedNumber.cpp b/third_party/WebKit/Source/core/svg/SVGAnimatedNumber.cpp index e8fe2c1..316471cc 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedNumber.cpp +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedNumber.cpp
@@ -50,7 +50,8 @@ } DEFINE_TRACE_WRAPPERS(SVGAnimatedNumber) { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGNumber>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedNumberList.h b/third_party/WebKit/Source/core/svg/SVGAnimatedNumberList.h index 61b99c6..b8838a0 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedNumberList.h +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedNumberList.h
@@ -50,7 +50,8 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGNumberList>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } protected:
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedPreserveAspectRatio.h b/third_party/WebKit/Source/core/svg/SVGAnimatedPreserveAspectRatio.h index cf681e9a..955183a 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedPreserveAspectRatio.h +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedPreserveAspectRatio.h
@@ -50,7 +50,8 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGPreserveAspectRatio>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } protected:
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedRect.h b/third_party/WebKit/Source/core/svg/SVGAnimatedRect.h index 62c97f6..2b7baf8f 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedRect.h +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedRect.h
@@ -48,7 +48,8 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGRect>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } protected:
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedString.cpp b/third_party/WebKit/Source/core/svg/SVGAnimatedString.cpp index dfe0edb..5f10195c 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedString.cpp +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedString.cpp
@@ -20,7 +20,8 @@ } DEFINE_TRACE_WRAPPERS(SVGAnimatedString) { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGString>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedTransformList.h b/third_party/WebKit/Source/core/svg/SVGAnimatedTransformList.h index f45df33..b348bad9 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimatedTransformList.h +++ b/third_party/WebKit/Source/core/svg/SVGAnimatedTransformList.h
@@ -54,7 +54,8 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGAnimatedProperty<SVGTransformList>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } protected:
diff --git a/third_party/WebKit/Source/core/svg/SVGLengthListTearOff.h b/third_party/WebKit/Source/core/svg/SVGLengthListTearOff.h index 514a99a..bf47f36 100644 --- a/third_party/WebKit/Source/core/svg/SVGLengthListTearOff.h +++ b/third_party/WebKit/Source/core/svg/SVGLengthListTearOff.h
@@ -52,7 +52,9 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGListPropertyTearOffHelper<SVGLengthListTearOff, + SVGLengthList>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } private:
diff --git a/third_party/WebKit/Source/core/svg/SVGLengthTearOff.cpp b/third_party/WebKit/Source/core/svg/SVGLengthTearOff.cpp index 9145a353..02afe89 100644 --- a/third_party/WebKit/Source/core/svg/SVGLengthTearOff.cpp +++ b/third_party/WebKit/Source/core/svg/SVGLengthTearOff.cpp
@@ -250,7 +250,8 @@ } DEFINE_TRACE_WRAPPERS(SVGLengthTearOff) { - visitor->TraceWrappers(contextElement()); + SVGPropertyTearOff<SVGLength>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGNumberListTearOff.h b/third_party/WebKit/Source/core/svg/SVGNumberListTearOff.h index ba394ef..d56b6be5 100644 --- a/third_party/WebKit/Source/core/svg/SVGNumberListTearOff.h +++ b/third_party/WebKit/Source/core/svg/SVGNumberListTearOff.h
@@ -52,7 +52,9 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGListPropertyTearOffHelper<SVGNumberListTearOff, + SVGNumberList>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } private:
diff --git a/third_party/WebKit/Source/core/svg/SVGNumberTearOff.cpp b/third_party/WebKit/Source/core/svg/SVGNumberTearOff.cpp index c274ff7e..abea236 100644 --- a/third_party/WebKit/Source/core/svg/SVGNumberTearOff.cpp +++ b/third_party/WebKit/Source/core/svg/SVGNumberTearOff.cpp
@@ -58,7 +58,8 @@ } DEFINE_TRACE_WRAPPERS(SVGNumberTearOff) { - visitor->TraceWrappers(contextElement()); + SVGPropertyTearOff<SVGNumber>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGPointListTearOff.h b/third_party/WebKit/Source/core/svg/SVGPointListTearOff.h index db3e349..d16a2ae 100644 --- a/third_party/WebKit/Source/core/svg/SVGPointListTearOff.h +++ b/third_party/WebKit/Source/core/svg/SVGPointListTearOff.h
@@ -51,7 +51,9 @@ } DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { - visitor->TraceWrappers(contextElement()); + SVGListPropertyTearOffHelper<SVGPointListTearOff, + SVGPointList>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } private:
diff --git a/third_party/WebKit/Source/core/svg/SVGPointTearOff.cpp b/third_party/WebKit/Source/core/svg/SVGPointTearOff.cpp index bc69419..efad53a 100644 --- a/third_party/WebKit/Source/core/svg/SVGPointTearOff.cpp +++ b/third_party/WebKit/Source/core/svg/SVGPointTearOff.cpp
@@ -73,7 +73,8 @@ } DEFINE_TRACE_WRAPPERS(SVGPointTearOff) { - visitor->TraceWrappers(contextElement()); + SVGPropertyTearOff<SVGPoint>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGPreserveAspectRatioTearOff.cpp b/third_party/WebKit/Source/core/svg/SVGPreserveAspectRatioTearOff.cpp index fe06339..8831f56d 100644 --- a/third_party/WebKit/Source/core/svg/SVGPreserveAspectRatioTearOff.cpp +++ b/third_party/WebKit/Source/core/svg/SVGPreserveAspectRatioTearOff.cpp
@@ -82,7 +82,8 @@ attribute_name) {} DEFINE_TRACE_WRAPPERS(SVGPreserveAspectRatioTearOff) { - visitor->TraceWrappers(contextElement()); + SVGPropertyTearOff<SVGPreserveAspectRatio>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGRectTearOff.cpp b/third_party/WebKit/Source/core/svg/SVGRectTearOff.cpp index 14820d6d..9a27b1eb 100644 --- a/third_party/WebKit/Source/core/svg/SVGRectTearOff.cpp +++ b/third_party/WebKit/Source/core/svg/SVGRectTearOff.cpp
@@ -85,7 +85,8 @@ } DEFINE_TRACE_WRAPPERS(SVGRectTearOff) { - visitor->TraceWrappers(contextElement()); + SVGPropertyTearOff<SVGRect>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGStringListTearOff.cpp b/third_party/WebKit/Source/core/svg/SVGStringListTearOff.cpp index 96bff941..5b2d2dc7a 100644 --- a/third_party/WebKit/Source/core/svg/SVGStringListTearOff.cpp +++ b/third_party/WebKit/Source/core/svg/SVGStringListTearOff.cpp
@@ -45,6 +45,7 @@ attribute_name) {} DEFINE_TRACE_WRAPPERS(SVGStringListTearOff) { - visitor->TraceWrappers(contextElement()); + SVGPropertyTearOff<SVGStringList>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } }
diff --git a/third_party/WebKit/Source/core/svg/SVGTransformListTearOff.cpp b/third_party/WebKit/Source/core/svg/SVGTransformListTearOff.cpp index 8619d137..2d507019 100644 --- a/third_party/WebKit/Source/core/svg/SVGTransformListTearOff.cpp +++ b/third_party/WebKit/Source/core/svg/SVGTransformListTearOff.cpp
@@ -62,7 +62,9 @@ } DEFINE_TRACE_WRAPPERS(SVGTransformListTearOff) { - visitor->TraceWrappers(contextElement()); + SVGListPropertyTearOffHelper<SVGTransformListTearOff, + SVGTransformList>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGTransformTearOff.cpp b/third_party/WebKit/Source/core/svg/SVGTransformTearOff.cpp index 4f2b54ca..417209b 100644 --- a/third_party/WebKit/Source/core/svg/SVGTransformTearOff.cpp +++ b/third_party/WebKit/Source/core/svg/SVGTransformTearOff.cpp
@@ -52,6 +52,11 @@ SVGPropertyTearOff<SVGTransform>::Trace(visitor); } +DEFINE_TRACE_WRAPPERS(SVGTransformTearOff) { + SVGPropertyTearOff<SVGTransform>::TraceWrappers(visitor); + ScriptWrappable::TraceWrappers(visitor); +} + SVGTransformTearOff* SVGTransformTearOff::CreateDetached() { return Create(SVGTransform::Create(blink::kSvgTransformMatrix), nullptr, kPropertyIsNotAnimVal, QualifiedName::Null()); @@ -130,8 +135,4 @@ CommitChange(); } -DEFINE_TRACE_WRAPPERS(SVGTransformTearOff) { - visitor->TraceWrappers(contextElement()); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.h b/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.h index 41138df..ce958184 100644 --- a/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.h +++ b/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.h
@@ -81,6 +81,10 @@ DEFINE_INLINE_VIRTUAL_TRACE() {} + DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { + visitor->TraceWrappersWithManualWriteBarrier(context_element_.Get()); + } + protected: SVGAnimatedPropertyBase(AnimatedPropertyType, SVGElement*,
diff --git a/third_party/WebKit/Source/core/svg/properties/SVGListPropertyTearOffHelper.h b/third_party/WebKit/Source/core/svg/properties/SVGListPropertyTearOffHelper.h index db00a87c..4117242 100644 --- a/third_party/WebKit/Source/core/svg/properties/SVGListPropertyTearOffHelper.h +++ b/third_party/WebKit/Source/core/svg/properties/SVGListPropertyTearOffHelper.h
@@ -182,6 +182,10 @@ return CreateItemTearOff(value); } + DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { + SVGPropertyTearOff<ListProperty>::TraceWrappers(visitor); + } + protected: SVGListPropertyTearOffHelper( ListPropertyType* target,
diff --git a/third_party/WebKit/Source/core/svg/properties/SVGPropertyTearOff.h b/third_party/WebKit/Source/core/svg/properties/SVGPropertyTearOff.h index 70edbe586..62140ec 100644 --- a/third_party/WebKit/Source/core/svg/properties/SVGPropertyTearOff.h +++ b/third_party/WebKit/Source/core/svg/properties/SVGPropertyTearOff.h
@@ -66,11 +66,18 @@ DCHECK(context_element); DCHECK(attribute_name != QualifiedName::Null()); context_element_ = context_element; + // Requires SVGPropertyTearOffBase to be the left-most class in the + // inheritance hierarchy. + ScriptWrappableVisitor::WriteBarrier(this, context_element_.Get()); attribute_name_ = attribute_name; } DEFINE_INLINE_VIRTUAL_TRACE() {} + DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { + visitor->TraceWrappersWithManualWriteBarrier(context_element_.Get()); + } + static void ThrowReadOnly(ExceptionState&); protected: @@ -108,6 +115,10 @@ SVGPropertyTearOffBase::Trace(visitor); } + DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { + SVGPropertyTearOffBase::TraceWrappers(visitor); + } + protected: SVGPropertyTearOff(Property* target, SVGElement* context_element,
diff --git a/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp b/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp index e56047d9..d2c2860 100644 --- a/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp +++ b/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp
@@ -30,9 +30,11 @@ #include "public/platform/modules/serviceworker/WebServiceWorkerResponse.h" using blink::protocol::Array; -using blink::protocol::CacheStorage::Cache; +// Renaming Cache since there is another blink::Cache. +using ProtocolCache = blink::protocol::CacheStorage::Cache; using blink::protocol::CacheStorage::DataEntry; -using blink::protocol::Response; +// Renaming Response since there is another blink::Response. +using ProtocolResponse = blink::protocol::Response; typedef blink::protocol::CacheStorage::Backend::DeleteCacheCallback DeleteCacheCallback; @@ -55,41 +57,44 @@ return id; } -Response ParseCacheId(const String& id, - String* security_origin, - String* cache_name) { +ProtocolResponse ParseCacheId(const String& id, + String* security_origin, + String* cache_name) { size_t pipe = id.find('|'); if (pipe == WTF::kNotFound) - return Response::Error("Invalid cache id."); + return ProtocolResponse::Error("Invalid cache id."); *security_origin = id.Substring(0, pipe); *cache_name = id.Substring(pipe + 1); - return Response::OK(); + return ProtocolResponse::OK(); } -Response AssertCacheStorage( +ProtocolResponse AssertCacheStorage( const String& security_origin, std::unique_ptr<WebServiceWorkerCacheStorage>& result) { RefPtr<SecurityOrigin> sec_origin = SecurityOrigin::CreateFromString(security_origin); // Cache Storage API is restricted to trustworthy origins. - if (!sec_origin->IsPotentiallyTrustworthy()) - return Response::Error(sec_origin->IsPotentiallyTrustworthyErrorMessage()); + if (!sec_origin->IsPotentiallyTrustworthy()) { + return ProtocolResponse::Error( + sec_origin->IsPotentiallyTrustworthyErrorMessage()); + } std::unique_ptr<WebServiceWorkerCacheStorage> cache = Platform::Current()->CreateCacheStorage(WebSecurityOrigin(sec_origin)); if (!cache) - return Response::Error("Could not find cache storage."); + return ProtocolResponse::Error("Could not find cache storage."); result = std::move(cache); - return Response::OK(); + return ProtocolResponse::OK(); } -Response AssertCacheStorageAndNameForId( +ProtocolResponse AssertCacheStorageAndNameForId( const String& cache_id, String* cache_name, std::unique_ptr<WebServiceWorkerCacheStorage>& result) { String security_origin; - Response response = ParseCacheId(cache_id, &security_origin, cache_name); + ProtocolResponse response = + ParseCacheId(cache_id, &security_origin, cache_name); if (!response.isSuccess()) return response; return AssertCacheStorage(security_origin, result); @@ -129,11 +134,12 @@ ~RequestCacheNames() override {} void OnSuccess(const WebVector<WebString>& caches) override { - std::unique_ptr<Array<Cache>> array = Array<Cache>::create(); + std::unique_ptr<Array<ProtocolCache>> array = + Array<ProtocolCache>::create(); for (size_t i = 0; i < caches.size(); i++) { String name = String(caches[i]); - std::unique_ptr<Cache> entry = - Cache::create() + std::unique_ptr<ProtocolCache> entry = + ProtocolCache::create() .setSecurityOrigin(security_origin_) .setCacheName(name) .setCacheId(BuildCacheId(security_origin_, name)) @@ -144,7 +150,7 @@ } void OnError(WebServiceWorkerCacheError error) override { - callback_->sendFailure(Response::Error( + callback_->sendFailure(ProtocolResponse::Error( String::Format("Error requesting cache names: %s", ServiceWorkerCacheErrorString(error).data()))); } @@ -218,7 +224,9 @@ callback_->sendSuccess(std::move(array), has_more); } - void SendFailure(const Response& error) { callback_->sendFailure(error); } + void SendFailure(const ProtocolResponse& error) { + callback_->sendFailure(error); + } private: DataRequestParams params_; @@ -243,7 +251,7 @@ } void OnError(WebServiceWorkerCacheError error) override { - accumulator_->SendFailure(Response::Error( + accumulator_->SendFailure(ProtocolResponse::Error( String::Format("Error requesting responses for cache %s: %s", params_.cache_name.Utf8().data(), ServiceWorkerCacheErrorString(error).data()))); @@ -289,7 +297,7 @@ } void OnError(WebServiceWorkerCacheError error) override { - callback_->sendFailure(Response::Error( + callback_->sendFailure(ProtocolResponse::Error( String::Format("Error requesting requests for cache %s: %s", params_.cache_name.Utf8().data(), ServiceWorkerCacheErrorString(error).data()))); @@ -320,7 +328,7 @@ } void OnError(WebServiceWorkerCacheError error) override { - callback_->sendFailure(Response::Error(String::Format( + callback_->sendFailure(ProtocolResponse::Error(String::Format( "Error requesting cache %s: %s", params_.cache_name.Utf8().data(), ServiceWorkerCacheErrorString(error).data()))); } @@ -341,7 +349,7 @@ void OnSuccess() override { callback_->sendSuccess(); } void OnError(WebServiceWorkerCacheError error) override { - callback_->sendFailure(Response::Error( + callback_->sendFailure(ProtocolResponse::Error( String::Format("Error requesting cache names: %s", ServiceWorkerCacheErrorString(error).data()))); } @@ -361,7 +369,7 @@ void OnSuccess() override { callback_->sendSuccess(); } void OnError(WebServiceWorkerCacheError error) override { - callback_->sendFailure(Response::Error( + callback_->sendFailure(ProtocolResponse::Error( String::Format("Error requesting cache names: %s", ServiceWorkerCacheErrorString(error).data()))); } @@ -397,7 +405,7 @@ } void OnError(WebServiceWorkerCacheError error) override { - callback_->sendFailure(Response::Error(String::Format( + callback_->sendFailure(ProtocolResponse::Error(String::Format( "Error requesting cache %s: %s", cache_name_.Utf8().data(), ServiceWorkerCacheErrorString(error).data()))); } @@ -428,12 +436,12 @@ if (!sec_origin->IsPotentiallyTrustworthy()) { // Don't treat this as an error, just don't attempt to open and enumerate // the caches. - callback->sendSuccess(Array<protocol::CacheStorage::Cache>::create()); + callback->sendSuccess(Array<ProtocolCache>::create()); return; } std::unique_ptr<WebServiceWorkerCacheStorage> cache; - Response response = AssertCacheStorage(security_origin, cache); + ProtocolResponse response = AssertCacheStorage(security_origin, cache); if (!response.isSuccess()) { callback->sendFailure(response); return; @@ -449,7 +457,7 @@ std::unique_ptr<RequestEntriesCallback> callback) { String cache_name; std::unique_ptr<WebServiceWorkerCacheStorage> cache; - Response response = + ProtocolResponse response = AssertCacheStorageAndNameForId(cache_id, &cache_name, cache); if (!response.isSuccess()) { callback->sendFailure(response); @@ -469,7 +477,7 @@ std::unique_ptr<DeleteCacheCallback> callback) { String cache_name; std::unique_ptr<WebServiceWorkerCacheStorage> cache; - Response response = + ProtocolResponse response = AssertCacheStorageAndNameForId(cache_id, &cache_name, cache); if (!response.isSuccess()) { callback->sendFailure(response); @@ -485,7 +493,7 @@ std::unique_ptr<DeleteEntryCallback> callback) { String cache_name; std::unique_ptr<WebServiceWorkerCacheStorage> cache; - Response response = + ProtocolResponse response = AssertCacheStorageAndNameForId(cache_id, &cache_name, cache); if (!response.isSuccess()) { callback->sendFailure(response);
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni index a5c52308..0e456bb 100644 --- a/third_party/WebKit/Source/modules/modules_idl_files.gni +++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -290,6 +290,7 @@ "webaudio/AudioListener.idl", "webaudio/AudioNode.idl", "webaudio/AudioParam.idl", + "webaudio/AudioParamMap.idl", "webaudio/AudioProcessingEvent.idl", "webaudio/AudioScheduledSourceNode.idl", "webaudio/AudioWorkletGlobalScope.idl",
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParamMap.cpp b/third_party/WebKit/Source/modules/webaudio/AudioParamMap.cpp new file mode 100644 index 0000000..5b5ba6f2 --- /dev/null +++ b/third_party/WebKit/Source/modules/webaudio/AudioParamMap.cpp
@@ -0,0 +1,65 @@ +// 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 "modules/webaudio/AudioParamMap.h" + +namespace blink { + +class AudioParamMapIterationSource final + : public PairIterable<String, AudioParam*>::IterationSource { + public: + AudioParamMapIterationSource( + const HeapHashMap<String, Member<AudioParam>>& map) { + for (const auto name : map.Keys()) { + parameter_names_.push_back(name); + parameter_objects_.push_back(map.at(name)); + } + } + + bool Next(ScriptState* scrip_state, + String& key, + AudioParam*& audio_param, + ExceptionState&) override { + if (current_index_ == parameter_names_.size()) + return false; + key = parameter_names_[current_index_]; + audio_param = parameter_objects_[current_index_]; + ++current_index_; + return true; + } + + DEFINE_INLINE_VIRTUAL_TRACE() { + visitor->Trace(parameter_objects_); + PairIterable<String, AudioParam*>::IterationSource::Trace(visitor); + } + + private: + // For sequential iteration (e.g. Next()). + Vector<String> parameter_names_; + HeapVector<Member<AudioParam>> parameter_objects_; + unsigned current_index_; +}; + +AudioParamMap::AudioParamMap( + const HeapHashMap<String, Member<AudioParam>>& parameter_map) + : parameter_map_(parameter_map) {} + +PairIterable<String, AudioParam*>::IterationSource* + AudioParamMap::StartIteration(ScriptState*, ExceptionState&) { + return new AudioParamMapIterationSource(parameter_map_); +} + +bool AudioParamMap::GetMapEntry(ScriptState*, + const String& key, + AudioParam*& audio_param, + ExceptionState&) { + if (parameter_map_.Contains(key)) { + audio_param = parameter_map_.at(key); + return true; + } + + return false; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParamMap.h b/third_party/WebKit/Source/modules/webaudio/AudioParamMap.h new file mode 100644 index 0000000..d263e7b --- /dev/null +++ b/third_party/WebKit/Source/modules/webaudio/AudioParamMap.h
@@ -0,0 +1,51 @@ +// 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 AudioParamMap_h +#define AudioParamMap_h + +#include "bindings/core/v8/ExceptionState.h" +#include "bindings/core/v8/Maplike.h" +#include "bindings/core/v8/V8BindingForCore.h" +#include "modules/webaudio/AudioParam.h" +#include "platform/bindings/ScriptWrappable.h" +#include "platform/heap/Handle.h" +#include "platform/wtf/text/WTFString.h" + +namespace blink { + +class AudioParam; + +class AudioParamMap final : public GarbageCollectedFinalized<AudioParamMap>, + public ScriptWrappable, + public Maplike<String, AudioParam*> { + DEFINE_WRAPPERTYPEINFO(); + + public: + explicit AudioParamMap( + const HeapHashMap<String, Member<AudioParam>>& parameter_map); + + // IDL attributes / methods + size_t size() const { return parameter_map_.size(); } + + AudioParam* At(String name) { return parameter_map_.at(name); } + bool Contains(String name) { return parameter_map_.Contains(name); } + + DEFINE_INLINE_VIRTUAL_TRACE() { visitor->Trace(parameter_map_); } + + private: + PairIterable<String, AudioParam*>::IterationSource* StartIteration( + ScriptState*, + ExceptionState&) override; + bool GetMapEntry(ScriptState*, + const String& key, + AudioParam*&, + ExceptionState&) override; + + const HeapHashMap<String, Member<AudioParam>> parameter_map_; +}; + +} // namespace blink + +#endif
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParamMap.idl b/third_party/WebKit/Source/modules/webaudio/AudioParamMap.idl new file mode 100644 index 0000000..740c70f --- /dev/null +++ b/third_party/WebKit/Source/modules/webaudio/AudioParamMap.idl
@@ -0,0 +1,10 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://webaudio.github.io/web-audio-api/#idl-def-AudioParamMap +[ + RuntimeEnabled=AudioWorklet +] interface AudioParamMap { + readonly maplike<DOMString, AudioParam>; +};
diff --git a/third_party/WebKit/Source/modules/webaudio/BUILD.gn b/third_party/WebKit/Source/modules/webaudio/BUILD.gn index 8cfcd64..e9ecd2a 100644 --- a/third_party/WebKit/Source/modules/webaudio/BUILD.gn +++ b/third_party/WebKit/Source/modules/webaudio/BUILD.gn
@@ -32,6 +32,8 @@ "AudioNodeOutput.h", "AudioParam.cpp", "AudioParam.h", + "AudioParamMap.cpp", + "AudioParamMap.h", "AudioParamTimeline.cpp", "AudioParamTimeline.h", "AudioProcessingEvent.cpp",
diff --git a/third_party/WebKit/Source/platform/bindings/V8PerContextData.cpp b/third_party/WebKit/Source/platform/bindings/V8PerContextData.cpp index 3a955b8..5aadd390 100644 --- a/third_party/WebKit/Source/platform/bindings/V8PerContextData.cpp +++ b/third_party/WebKit/Source/platform/bindings/V8PerContextData.cpp
@@ -51,18 +51,6 @@ activity_logger_(nullptr) { context_holder_->SetContext(context); - v8::Context::Scope context_scope(context); - DCHECK(error_prototype_.IsEmpty()); - v8::Local<v8::Value> object_value = - context->Global() - ->Get(context, V8AtomicString(isolate_, "Error")) - .ToLocalChecked(); - v8::Local<v8::Value> prototype_value = - object_value.As<v8::Object>() - ->Get(context, V8AtomicString(isolate_, "prototype")) - .ToLocalChecked(); - error_prototype_.Set(isolate_, prototype_value); - if (IsMainThread()) { InstanceCounters::IncrementCounter( InstanceCounters::kV8PerContextDataCounter); @@ -87,8 +75,6 @@ v8::Local<v8::Object> V8PerContextData::CreateWrapperFromCacheSlowCase( const WrapperTypeInfo* type) { - DCHECK(!error_prototype_.IsEmpty()); - v8::Context::Scope scope(GetContext()); v8::Local<v8::Function> interface_object = ConstructorForType(type); CHECK(!interface_object.IsEmpty()); @@ -101,8 +87,6 @@ v8::Local<v8::Function> V8PerContextData::ConstructorForTypeSlowCase( const WrapperTypeInfo* type) { - DCHECK(!error_prototype_.IsEmpty()); - v8::Local<v8::Context> current_context = GetContext(); v8::Context::Scope scope(current_context); const DOMWrapperWorld& world = DOMWrapperWorld::World(current_context); @@ -147,13 +131,6 @@ type->PreparePrototypeAndInterfaceObject(current_context, world, prototype_object, interface_object, interface_template); - if (type->wrapper_type_prototype == - WrapperTypeInfo::kWrapperTypeExceptionPrototype) { - if (!V8CallBoolean(prototype_object->SetPrototype( - current_context, error_prototype_.NewLocal(isolate_)))) { - return v8::Local<v8::Function>(); - } - } } // Origin Trials
diff --git a/third_party/WebKit/Source/platform/bindings/V8PerContextData.h b/third_party/WebKit/Source/platform/bindings/V8PerContextData.h index 8e016e2..787153b 100644 --- a/third_party/WebKit/Source/platform/bindings/V8PerContextData.h +++ b/third_party/WebKit/Source/platform/bindings/V8PerContextData.h
@@ -150,7 +150,6 @@ std::unique_ptr<gin::ContextHolder> context_holder_; ScopedPersistent<v8::Context> context_; - ScopedPersistent<v8::Value> error_prototype_; ScopedPersistent<v8::Private> private_custom_element_definition_id_;
diff --git a/third_party/WebKit/Source/platform/fonts/AlternateFontFamily.h b/third_party/WebKit/Source/platform/fonts/AlternateFontFamily.h index 6b7f0976b..133680c 100644 --- a/third_party/WebKit/Source/platform/fonts/AlternateFontFamily.h +++ b/third_party/WebKit/Source/platform/fonts/AlternateFontFamily.h
@@ -32,6 +32,7 @@ #define AlternateFontFamily_h #include "build/build_config.h" +#include "platform/FontFamilyNames.h" #include "platform/fonts/FontDescription.h" #include "platform/wtf/text/AtomicString.h" @@ -47,27 +48,20 @@ // 'Courier' is a bitmap font. On Mac on the other hand 'Courier' is // a truetype font. Thus pages asking for Courier are better of // using 'Courier New' on windows. - DEFINE_STATIC_LOCAL(AtomicString, courier, ("Courier")); - DEFINE_STATIC_LOCAL(AtomicString, courier_new, ("Courier New")); - if (DeprecatedEqualIgnoringCase(family_name, courier)) - return courier_new; + if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Courier)) + return FontFamilyNames::Courier_New; // Alias 'MS Sans Serif' (bitmap font) -> 'Microsoft Sans Serif' // (truetype font). - DEFINE_STATIC_LOCAL(AtomicString, ms_sans, ("MS Sans Serif")); - DEFINE_STATIC_LOCAL(AtomicString, microsoft_sans, ("Microsoft Sans Serif")); - if (DeprecatedEqualIgnoringCase(family_name, ms_sans)) - return microsoft_sans; + if (EqualIgnoringASCIICase(family_name, FontFamilyNames::MS_Sans_Serif)) + return FontFamilyNames::Microsoft_Sans_Serif; // Alias 'MS Serif' (bitmap) -> 'Times New Roman' (truetype font). // Alias 'Times' -> 'Times New Roman' (truetype font). // There's no 'Microsoft Sans Serif-equivalent' for Serif. - DEFINE_STATIC_LOCAL(AtomicString, ms_serif, ("MS Serif")); - DEFINE_STATIC_LOCAL(AtomicString, times, ("Times")); - DEFINE_STATIC_LOCAL(AtomicString, times_new_roman, ("Times New Roman")); - if (DeprecatedEqualIgnoringCase(family_name, ms_serif) || - DeprecatedEqualIgnoringCase(family_name, times)) - return times_new_roman; + if (EqualIgnoringASCIICase(family_name, FontFamilyNames::MS_Serif) || + EqualIgnoringASCIICase(family_name, FontFamilyNames::Times)) + return FontFamilyNames::Times_New_Roman; #endif return family_name; @@ -76,56 +70,44 @@ inline const AtomicString& AlternateFamilyName( const AtomicString& family_name) { // Alias Courier <-> Courier New - DEFINE_STATIC_LOCAL(AtomicString, courier, ("Courier")); - DEFINE_STATIC_LOCAL(AtomicString, courier_new, ("Courier New")); - if (DeprecatedEqualIgnoringCase(family_name, courier)) - return courier_new; + if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Courier)) + return FontFamilyNames::Courier_New; #if !defined(OS_WIN) // On Windows, Courier New (truetype font) is always present and // Courier is a bitmap font. So, we don't want to map Courier New to // Courier. - if (DeprecatedEqualIgnoringCase(family_name, courier_new)) - return courier; + if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Courier_New)) + return FontFamilyNames::Courier; #endif // Alias Times and Times New Roman. - DEFINE_STATIC_LOCAL(AtomicString, times, ("Times")); - DEFINE_STATIC_LOCAL(AtomicString, times_new_roman, ("Times New Roman")); - if (DeprecatedEqualIgnoringCase(family_name, times)) - return times_new_roman; - if (DeprecatedEqualIgnoringCase(family_name, times_new_roman)) - return times; + if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Times)) + return FontFamilyNames::Times_New_Roman; + if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Times_New_Roman)) + return FontFamilyNames::Times; // Alias Arial and Helvetica - DEFINE_STATIC_LOCAL(AtomicString, arial, ("Arial")); - DEFINE_STATIC_LOCAL(AtomicString, helvetica, ("Helvetica")); - if (DeprecatedEqualIgnoringCase(family_name, arial)) - return helvetica; - if (DeprecatedEqualIgnoringCase(family_name, helvetica)) - return arial; + if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Arial)) + return FontFamilyNames::Helvetica; + if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Helvetica)) + return FontFamilyNames::Arial; return g_empty_atom; } -inline const AtomicString GetFallbackFontFamily( +inline const AtomicString& GetFallbackFontFamily( const FontDescription& description) { - DEFINE_STATIC_LOCAL(const AtomicString, sans_str, ("sans-serif")); - DEFINE_STATIC_LOCAL(const AtomicString, serif_str, ("serif")); - DEFINE_STATIC_LOCAL(const AtomicString, monospace_str, ("monospace")); - DEFINE_STATIC_LOCAL(const AtomicString, cursive_str, ("cursive")); - DEFINE_STATIC_LOCAL(const AtomicString, fantasy_str, ("fantasy")); - switch (description.GenericFamily()) { case FontDescription::kSansSerifFamily: - return sans_str; + return FontFamilyNames::sans_serif; case FontDescription::kSerifFamily: - return serif_str; + return FontFamilyNames::serif; case FontDescription::kMonospaceFamily: - return monospace_str; + return FontFamilyNames::monospace; case FontDescription::kCursiveFamily: - return cursive_str; + return FontFamilyNames::cursive; case FontDescription::kFantasyFamily: - return fantasy_str; + return FontFamilyNames::fantasy; default: // Let the caller use the system default font. return g_empty_atom;
diff --git a/third_party/WebKit/Source/platform/fonts/FontFamilyNames.json5 b/third_party/WebKit/Source/platform/fonts/FontFamilyNames.json5 index fd34749..4d86dc7 100644 --- a/third_party/WebKit/Source/platform/fonts/FontFamilyNames.json5 +++ b/third_party/WebKit/Source/platform/fonts/FontFamilyNames.json5
@@ -13,5 +13,25 @@ "-webkit-pictograph", "-webkit-standard", "system-ui", + + "Arial", + "Calibri", + "Courier New", + "Courier", + "Helvetica", + "Microsoft Sans Serif", + "MS Sans Serif", + "MS Serif", + "MS UI Gothic", + "Sans", + "Segoe UI", + "Times New Roman", + "Times", + + "cursive", + "fantasy", + "monospace", + "sans-serif", + "serif", ], }
diff --git a/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp b/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp index 3a4e9fd..bf47c7b 100644 --- a/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp +++ b/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp
@@ -38,6 +38,7 @@ #include "SkTypeface.h" #include "build/build_config.h" +#include "platform/FontFamilyNames.h" #include "platform/Language.h" #include "platform/fonts/AlternateFontFamily.h" #include "platform/fonts/FontCache.h" @@ -156,59 +157,63 @@ // We should at least have Sans or Arial which is the last resort fallback of // SkFontHost ports. if (!font_platform_data) { - DEFINE_STATIC_LOCAL(const FontFaceCreationParams, sans_creation_params, - (AtomicString("Sans"))); + DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, + sans_creation_params, + (FontFamilyNames::Sans)); font_platform_data = GetFontPlatformData(description, sans_creation_params, AlternateFontName::kLastResort); } if (!font_platform_data) { - DEFINE_STATIC_LOCAL(const FontFaceCreationParams, arial_creation_params, - (AtomicString("Arial"))); + DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, + arial_creation_params, + (FontFamilyNames::Arial)); font_platform_data = GetFontPlatformData(description, arial_creation_params, AlternateFontName::kLastResort); } #if defined(OS_WIN) // Try some more Windows-specific fallbacks. if (!font_platform_data) { - DEFINE_STATIC_LOCAL(const FontFaceCreationParams, - msuigothic_creation_params, - (AtomicString("MS UI Gothic"))); + DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, + msuigothic_creation_params, + (FontFamilyNames::MS_UI_Gothic)); font_platform_data = GetFontPlatformData(description, msuigothic_creation_params, AlternateFontName::kLastResort); } if (!font_platform_data) { - DEFINE_STATIC_LOCAL(const FontFaceCreationParams, - mssansserif_creation_params, - (AtomicString("Microsoft Sans Serif"))); + DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, + mssansserif_creation_params, + (FontFamilyNames::Microsoft_Sans_Serif)); font_platform_data = GetFontPlatformData(description, mssansserif_creation_params, AlternateFontName::kLastResort); } if (!font_platform_data) { - DEFINE_STATIC_LOCAL(const FontFaceCreationParams, segoeui_creation_params, - (AtomicString("Segoe UI"))); + DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, + segoeui_creation_params, + (FontFamilyNames::Segoe_UI)); font_platform_data = GetFontPlatformData( description, segoeui_creation_params, AlternateFontName::kLastResort); } if (!font_platform_data) { - DEFINE_STATIC_LOCAL(const FontFaceCreationParams, calibri_creation_params, - (AtomicString("Calibri"))); + DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, + calibri_creation_params, + (FontFamilyNames::Calibri)); font_platform_data = GetFontPlatformData( description, calibri_creation_params, AlternateFontName::kLastResort); } if (!font_platform_data) { - DEFINE_STATIC_LOCAL(const FontFaceCreationParams, - timesnewroman_creation_params, - (AtomicString("Times New Roman"))); + DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, + timesnewroman_creation_params, + (FontFamilyNames::Times_New_Roman)); font_platform_data = GetFontPlatformData(description, timesnewroman_creation_params, AlternateFontName::kLastResort); } if (!font_platform_data) { - DEFINE_STATIC_LOCAL(const FontFaceCreationParams, - couriernew_creation_params, - (AtomicString("Courier New"))); + DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, + couriernew_creation_params, + (FontFamilyNames::Courier_New)); font_platform_data = GetFontPlatformData(description, couriernew_creation_params, AlternateFontName::kLastResort);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.cpp b/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.cpp index 5498b64db..fda1729cb 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.cpp
@@ -9,18 +9,38 @@ namespace blink { -ClientHintsPreferences::ClientHintsPreferences() - : should_send_device_ram_(false), - should_send_dpr_(false), - should_send_resource_width_(false), - should_send_viewport_width_(false) {} +namespace { + +// Mapping from WebClientHintsType to the header value for enabling the +// corresponding client hint. The ordering should match the ordering of enums in +// WebClientHintsType. +static constexpr const char* kHeaderMapping[] = {"device-ram", "dpr", "width", + "viewport-width"}; + +static_assert(kWebClientHintsTypeLast + 1 == arraysize(kHeaderMapping), + "unhandled client hint type"); + +void ParseAcceptChHeader(const String& header_value, + bool enabled_types[kWebClientHintsTypeLast + 1]) { + CommaDelimitedHeaderSet accept_client_hints_header; + ParseCommaDelimitedHeader(header_value, accept_client_hints_header); + + for (size_t i = 0; i < kWebClientHintsTypeLast + 1; ++i) + enabled_types[i] = accept_client_hints_header.Contains(kHeaderMapping[i]); + + enabled_types[kWebClientHintsTypeDeviceRam] = + enabled_types[kWebClientHintsTypeDeviceRam] && + RuntimeEnabledFeatures::DeviceRAMHeaderEnabled(); +} + +} // namespace + +ClientHintsPreferences::ClientHintsPreferences() {} void ClientHintsPreferences::UpdateFrom( const ClientHintsPreferences& preferences) { - should_send_device_ram_ = preferences.should_send_device_ram_; - should_send_dpr_ = preferences.should_send_dpr_; - should_send_resource_width_ = preferences.should_send_resource_width_; - should_send_viewport_width_ = preferences.should_send_viewport_width_; + for (size_t i = 0; i < kWebClientHintsTypeLast + 1; ++i) + enabled_types_[i] = preferences.enabled_types_[i]; } void ClientHintsPreferences::UpdateFromAcceptClientHintsHeader( @@ -29,31 +49,18 @@ if (!RuntimeEnabledFeatures::ClientHintsEnabled() || header_value.IsEmpty()) return; - CommaDelimitedHeaderSet accept_client_hints_header; - ParseCommaDelimitedHeader(header_value, accept_client_hints_header); - if (RuntimeEnabledFeatures::DeviceRAMHeaderEnabled() && - accept_client_hints_header.Contains("device-ram")) { - if (context) - context->CountClientHintsDeviceRAM(); - should_send_device_ram_ = true; - } + bool new_enabled_types[kWebClientHintsTypeLast + 1] = {}; - if (accept_client_hints_header.Contains("dpr")) { - if (context) - context->CountClientHintsDPR(); - should_send_dpr_ = true; - } + ParseAcceptChHeader(header_value, new_enabled_types); - if (accept_client_hints_header.Contains("width")) { - if (context) - context->CountClientHintsResourceWidth(); - should_send_resource_width_ = true; - } + for (size_t i = 0; i < kWebClientHintsTypeLast + 1; ++i) + enabled_types_[i] = enabled_types_[i] || new_enabled_types[i]; - if (accept_client_hints_header.Contains("viewport-width")) { - if (context) - context->CountClientHintsViewportWidth(); - should_send_viewport_width_ = true; + if (context) { + for (size_t i = 0; i < kWebClientHintsTypeLast + 1; ++i) { + if (enabled_types_[i]) + context->CountClientHints(static_cast<WebClientHintsType>(i)); + } } }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.h b/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.h index 3de29e0f..12e1f4b 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.h +++ b/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.h
@@ -8,6 +8,7 @@ #include "platform/PlatformExport.h" #include "platform/wtf/Allocator.h" #include "platform/wtf/text/WTFString.h" +#include "public/platform/WebClientHintsType.h" namespace blink { @@ -17,10 +18,7 @@ public: class Context { public: - virtual void CountClientHintsDeviceRAM() = 0; - virtual void CountClientHintsDPR() = 0; - virtual void CountClientHintsResourceWidth() = 0; - virtual void CountClientHintsViewportWidth() = 0; + virtual void CountClientHints(WebClientHintsType) = 0; protected: virtual ~Context() {} @@ -31,27 +29,15 @@ void UpdateFrom(const ClientHintsPreferences&); void UpdateFromAcceptClientHintsHeader(const String& header_value, Context*); - bool ShouldSendDeviceRAM() const { return should_send_device_ram_; } - void SetShouldSendDeviceRAM(bool should) { should_send_device_ram_ = should; } - - bool ShouldSendDPR() const { return should_send_dpr_; } - void SetShouldSendDPR(bool should) { should_send_dpr_ = should; } - - bool ShouldSendResourceWidth() const { return should_send_resource_width_; } - void SetShouldSendResourceWidth(bool should) { - should_send_resource_width_ = should; + bool ShouldSend(WebClientHintsType type) const { + return enabled_types_[type]; } - - bool ShouldSendViewportWidth() const { return should_send_viewport_width_; } - void SetShouldSendViewportWidth(bool should) { - should_send_viewport_width_ = should; + void SetShouldSendForTesting(WebClientHintsType type) { + enabled_types_[type] = true; } private: - bool should_send_device_ram_; - bool should_send_dpr_; - bool should_send_resource_width_; - bool should_send_viewport_width_; + bool enabled_types_[kWebClientHintsTypeLast + 1] = {}; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferencesTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferencesTest.cpp index 11e3c63..c6e8d3a 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferencesTest.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferencesTest.cpp
@@ -27,14 +27,34 @@ for (const auto& test_case : cases) { ClientHintsPreferences preferences; - const char* value = test_case.header_value; - - preferences.UpdateFromAcceptClientHintsHeader(value, nullptr); + preferences.UpdateFromAcceptClientHintsHeader(test_case.header_value, + nullptr); EXPECT_EQ(test_case.expectation_resource_width, - preferences.ShouldSendResourceWidth()); - EXPECT_EQ(test_case.expectation_dpr, preferences.ShouldSendDPR()); + preferences.ShouldSend(kWebClientHintsTypeResourceWidth)); + EXPECT_EQ(test_case.expectation_dpr, + preferences.ShouldSend(kWebClientHintsTypeDpr)); EXPECT_EQ(test_case.expectation_viewport_width, - preferences.ShouldSendViewportWidth()); + preferences.ShouldSend(kWebClientHintsTypeViewportWidth)); + + // Calling UpdateFromAcceptClientHintsHeader with empty header should have + // no impact on client hint preferences. + preferences.UpdateFromAcceptClientHintsHeader("", nullptr); + EXPECT_EQ(test_case.expectation_resource_width, + preferences.ShouldSend(kWebClientHintsTypeResourceWidth)); + EXPECT_EQ(test_case.expectation_dpr, + preferences.ShouldSend(kWebClientHintsTypeDpr)); + EXPECT_EQ(test_case.expectation_viewport_width, + preferences.ShouldSend(kWebClientHintsTypeViewportWidth)); + + // Calling UpdateFromAcceptClientHintsHeader with an invalid header should + // have no impact on client hint preferences. + preferences.UpdateFromAcceptClientHintsHeader("foobar", nullptr); + EXPECT_EQ(test_case.expectation_resource_width, + preferences.ShouldSend(kWebClientHintsTypeResourceWidth)); + EXPECT_EQ(test_case.expectation_dpr, + preferences.ShouldSend(kWebClientHintsTypeDpr)); + EXPECT_EQ(test_case.expectation_viewport_width, + preferences.ShouldSend(kWebClientHintsTypeViewportWidth)); } }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc index ca57b27a..489ea65 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -1215,6 +1215,11 @@ new_policy.timer_queue_policy().is_suspended = true; } + if (GetMainThreadOnly().renderer_backgrounded && + RuntimeEnabledFeatures::TimerThrottlingForBackgroundTabsEnabled()) { + new_policy.timer_queue_policy().is_throttled = true; + } + if (GetMainThreadOnly().use_virtual_time) { new_policy.compositor_queue_policy().use_virtual_time = true; new_policy.default_queue_policy().use_virtual_time = true;
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp index bb4f751..11ba85c 100644 --- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp +++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -41,6 +41,7 @@ #include "cc/blink/web_compositor_support_impl.h" #include "cc/test/ordered_simple_task_runner.h" #include "mojo/public/cpp/bindings/strong_binding.h" +#include "platform/FontFamilyNames.h" #include "platform/HTTPNames.h" #include "platform/Language.h" #include "platform/heap/Heap.h" @@ -358,6 +359,7 @@ FetchInitiatorTypeNames::init(); InitializePlatformLanguage(); + FontFamilyNames::init(); } ScopedUnittestsEnvironmentSetup::~ScopedUnittestsEnvironmentSetup() {}
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn index e46c9516..4a105f3 100644 --- a/third_party/WebKit/public/BUILD.gn +++ b/third_party/WebKit/public/BUILD.gn
@@ -139,6 +139,7 @@ "platform/WebCallbacks.h", "platform/WebCanvas.h", "platform/WebCanvasCaptureHandler.h", + "platform/WebClientHintsType.h", "platform/WebClipboard.h", "platform/WebCoalescedInputEvent.h", "platform/WebColor.h",
diff --git a/third_party/WebKit/public/platform/WebClientHintsType.h b/third_party/WebKit/public/platform/WebClientHintsType.h new file mode 100644 index 0000000..8d2ccab2 --- /dev/null +++ b/third_party/WebKit/public/platform/WebClientHintsType.h
@@ -0,0 +1,25 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WebClientHintsType_h +#define WebClientHintsType_h + +namespace blink { + +enum WebClientHintsType { + // The order of the enums or the values must not be changed. New values should + // only be added after the last value, and kWebClientHintsTypeLast should be + // updated accordingly. + kWebClientHintsTypeDeviceRam, + kWebClientHintsTypeDpr, + kWebClientHintsTypeResourceWidth, + kWebClientHintsTypeViewportWidth, + + // Last client hint type. + kWebClientHintsTypeLast = kWebClientHintsTypeViewportWidth +}; + +} // namespace blink + +#endif // WebClientHintsType_h
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index fb597db..1dcd239 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -27,14 +27,14 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md # Reverting problematic clang rolls is safe, though. -CLANG_REVISION = '305735' +CLANG_REVISION = '307486' use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ if use_head_revision: CLANG_REVISION = 'HEAD' # This is incremented when pushing a new build of Clang at the same revision. -CLANG_SUB_REVISION=3 +CLANG_SUB_REVISION=1 PACKAGE_VERSION = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION)
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index f36a0b4..23c96520 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -35605,6 +35605,20 @@ <int value="3" label="Iframe with different signon realm"/> </enum> +<enum name="SubprocessType"> + <int value="1" label="Unknown"/> + <int value="2" label="Browser"/> + <int value="3" label="Renderer"/> + <int value="4" label="Plugin (deprecated)"/> + <int value="5" label="Worker (deprecated)"/> + <int value="6" label="Utility"/> + <int value="7" label="Zygote"/> + <int value="8" label="Sandbox Helper"/> + <int value="9" label="GPU"/> + <int value="10" label="PPAPI Plugin"/> + <int value="11" label="PPAPI Broker"/> +</enum> + <enum name="SubresourceFilterActions"> <int value="0" label="New Navigation"/> <int value="1" label="UI Shown"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index e8f9de4e..d50fc40 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -48253,8 +48253,11 @@ <owner>dimich@chromium.org</owner> <summary> Enum-based buckets reflect the number of days the Chrome was used in each - specific way. This data is accumulated locally and reported when connection - is likely to succeed (usually after successful online navigation). + specific way: - Not used at all during whole day. - Started, but failed to + successfully navigate. - Only navigated to offline pages locally saved on + the device. - Only navigated online. - Navigated to both online and offline + pages. This data is accumulated locally and reported when connection is + likely to succeed (usually after successful online navigation). </summary> </histogram> @@ -57712,6 +57715,9 @@ </histogram> <histogram name="Precache.BatteryPercentage.Start" units="%"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>bengr@chromium.org</owner> <owner>rajendrant@chromium.org</owner> <summary> @@ -57720,6 +57726,9 @@ </histogram> <histogram name="Precache.BatteryPercentageDiff.End" units="%"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>bengr@chromium.org</owner> <owner>rajendrant@chromium.org</owner> <summary> @@ -57732,6 +57741,9 @@ </histogram> <histogram name="Precache.CacheSize.AllEntries" units="KB"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>jamartin@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57741,6 +57753,9 @@ </histogram> <histogram name="Precache.CacheStatus.NonPrefetch" enum="HttpCachePattern"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>jamartin@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57751,6 +57766,9 @@ <histogram name="Precache.CacheStatus.NonPrefetch.FromPrecache" enum="HttpCachePattern"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>jamartin@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57762,6 +57780,9 @@ <histogram name="Precache.CacheStatus.NonPrefetch.NonTopHosts" enum="HttpCachePattern"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>twifkak@chromium.org</owner> <owner>jamartin@chromium.org</owner> <summary> @@ -57773,6 +57794,9 @@ <histogram name="Precache.CacheStatus.NonPrefetch.TopHosts" enum="HttpCachePattern"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>twifkak@chromium.org</owner> <owner>jamartin@chromium.org</owner> <summary> @@ -57783,6 +57807,9 @@ </histogram> <histogram name="Precache.CacheStatus.Prefetch" enum="HttpCachePattern"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>jamartin@chromium.org</owner> <owner>twifkak@chromium.org</owner> <summary> @@ -57792,6 +57819,9 @@ </histogram> <histogram name="Precache.DownloadedNonPrecache" units="bytes"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>bengr@chromium.org</owner> <summary> The number of bytes that were downloaded over the network for HTTP/HTTPS @@ -57800,6 +57830,9 @@ </histogram> <histogram name="Precache.DownloadedPrecacheMotivated" units="bytes"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>bengr@chromium.org</owner> <summary> The number of bytes that were downloaded because of precaching. Logged @@ -57808,6 +57841,9 @@ </histogram> <histogram name="Precache.Events" enum="PrecacheEvents"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>rajendrant@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57818,6 +57854,9 @@ </histogram> <histogram name="Precache.Fetch.FailureReasons"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>twifkak@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57827,6 +57866,9 @@ </histogram> <histogram name="Precache.Fetch.MinWeight" units="thousandths"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>twifkak@chromium.org</owner> <summary> The minimum resource weight that is fetched in a given precache run. @@ -57837,6 +57879,9 @@ </histogram> <histogram name="Precache.Fetch.PercentCompleted" units="%"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>twifkak@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57858,6 +57903,9 @@ </histogram> <histogram name="Precache.Fetch.ResponseBytes.Daily" units="bytes"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>twifkak@chromium.org</owner> <summary> The total number of response bytes in 24 hours received over the network @@ -57867,6 +57915,9 @@ </histogram> <histogram name="Precache.Fetch.ResponseBytes.Network" units="bytes"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>twifkak@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57877,6 +57928,9 @@ </histogram> <histogram name="Precache.Fetch.ResponseBytes.NetworkWasted" units="bytes"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>rajendrant@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57888,6 +57942,9 @@ </histogram> <histogram name="Precache.Fetch.ResponseBytes.Total" units="bytes"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>twifkak@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57897,6 +57954,9 @@ </histogram> <histogram name="Precache.Fetch.TimeToComplete" units="ms"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>twifkak@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57906,6 +57966,9 @@ </histogram> <histogram name="Precache.Freshness.Prefetch" units="seconds"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>jamartin@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57966,6 +58029,9 @@ </histogram> <histogram name="Precache.PeriodicTaskInterval" units="minutes"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>rajendrant@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57976,6 +58042,9 @@ </histogram> <histogram name="Precache.Saved" units="bytes"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>bengr@chromium.org</owner> <summary> The number of bytes during user browsing that were served from the cache, @@ -57985,6 +58054,9 @@ </histogram> <histogram name="Precache.Saved.Freshness" units="seconds"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>jamartin@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -57997,6 +58069,9 @@ </histogram> <histogram name="Precache.TimeSinceLastPrecache" units="seconds"> + <obsolete> + Deprecated July 11 2017. + </obsolete> <owner>jamartin@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -65560,6 +65635,15 @@ </summary> </histogram> +<histogram name="SBClientDownload.DownloadFileHasDmgSignature" enum="Boolean"> + <owner>jialiul@chromium.org</owner> + <summary> + A Mac-only metric that records whether a given download file is a + cryptographically signed DMG archive. This metric is logged before Chrome + sends SafeBrowsing download pings. + </summary> +</histogram> + <histogram name="SBClientDownload.DownloadFileWithoutDiskImageExtensionHasKolySignature" enum="Boolean"> @@ -81119,13 +81203,14 @@ </histogram> <histogram name="UMA.SubprocessMetricsProvider.UntrackedProcesses" - units="subprocesses"> + enum="SubprocessType"> <owner>asvitkine@chromium.org</owner> <owner>bcwhite@chromium.org</owner> <summary> The number of subprocesses, by type, from which persistent metrics are NOT collected because there is no information about this (likely new) process - type. + type. Process numbers 1000 or greater are "custom" processes used + by embedders. </summary> </histogram> @@ -95507,6 +95592,9 @@ </histogram_suffixes> <histogram_suffixes name="PrecacheCellular" separator="."> + <obsolete> + Deprecated July 11 2017. + </obsolete> <suffix name="Cellular" label="covers fetches when connected to cellular networks"/> <affected-histogram name="Precache.DownloadedNonPrecache"/> @@ -97284,7 +97372,11 @@ <suffix name="History" label="History"/> <suffix name="OfflinePageMetadata" label="OfflinePageMetadata"/> <suffix name="Passwords" label="Passwords"/> - <suffix name="Precache" label="Precache"/> + <suffix name="Precache" label="Precache"> + <obsolete> + Deprecated July 11 2017. + </obsolete> + </suffix> <suffix name="PrefetchStore" label="PrefetchStore"/> <suffix name="Predictor" label="Predictor"/> <suffix name="PreviewsOptOut" label="PreviewsOptOut"/>
diff --git a/tools/perf/fetch_benchmark_deps.py b/tools/perf/fetch_benchmark_deps.py index 0a07d06..3a21c3d08 100755 --- a/tools/perf/fetch_benchmark_deps.py +++ b/tools/perf/fetch_benchmark_deps.py
@@ -6,6 +6,7 @@ """This module fetches and prints the dependencies given a benchmark.""" import argparse +import optparse import os import sys @@ -23,6 +24,9 @@ def _FetchDependenciesIfNeeded(story_set): """ Download files needed by a user story set. """ + if not story_set.wpr_archive_info: + return + # Download files in serving_dirs. serving_dirs = story_set.serving_dirs for directory in serving_dirs: @@ -60,9 +64,14 @@ def FetchDepsForBenchmark(benchmark, output): - # Download files according to specified benchmark. - story_set = benchmark().CreateStorySet(None) + # Create a dummy options object which hold default values that are expected + # by Benchmark.CreateStorySet(options) method. + parser = optparse.OptionParser() + benchmark.AddBenchmarkCommandLineArgs(parser) + options, _ = parser.parse_args([]) + story_set = benchmark().CreateStorySet(options) + # Download files according to specified benchmark. _FetchDependenciesIfNeeded(story_set) # Print files downloaded. @@ -96,9 +105,8 @@ raw_input( 'No benchmark name is specified. Fetching all benchmark deps. ' 'Press enter to continue...') - for b in benchmark_finders.GetAllBenchmarks(): - print >> output, ('Fetch dependencies for benchmark %s:' - % benchmark.Name()) + for b in benchmark_finders.GetAllPerfBenchmarks(): + print >> output, ('Fetch dependencies for benchmark %s' % b.Name()) FetchDepsForBenchmark(b, output) if __name__ == '__main__':
diff --git a/tools/perf/page_sets/data/chrome_signin_credentials.json b/tools/perf/page_sets/data/chrome_signin_credentials.json new file mode 100644 index 0000000..1f180cc --- /dev/null +++ b/tools/perf/page_sets/data/chrome_signin_credentials.json
@@ -0,0 +1,6 @@ +{ + "chrome": { + "username": "chrometelemetry@gmail.com", + "password": "signinfortelemetry" + } +}
diff --git a/tools/perf/page_sets/tough_video_cases.py b/tools/perf/page_sets/tough_video_cases.py index a66af42..2a280680 100644 --- a/tools/perf/page_sets/tough_video_cases.py +++ b/tools/perf/page_sets/tough_video_cases.py
@@ -22,9 +22,10 @@ # Other filter tags: 'is_50fps', 'is_4k', - # Play action + # Play action: 'seek', 'normal_play', + 'background', ] @@ -63,6 +64,31 @@ if self.page_set.measure_memory: action_runner.MeasureMemory() + def PlayInBackgroundTab(self, action_runner, background_time=10): + # Steps: + # 1. Play a video + # 2. Open new tab overtop to obscure the video + # 3. Close the tab to go back to the tab that is playing the video. + # This test case will work differently depending on whether the platform is + # desktop or Android and whether the video has sound or not. For example, + # the current Chrome video implementation (as of July 2017) pauses video on + # Android when the tab is backgrounded, but on desktop the video is not + # paused. + # TODO(crouleau): Use --disable-media-suspend flag to enable Android to + # play video in the background. + # The motivation for this test case is crbug.com/678663. + action_runner.PlayMedia( + playing_event_timeout_in_seconds=60) + action_runner.Wait(.5) + new_tab = action_runner.tab.browser.tabs.New() + new_tab.Activate() + action_runner.Wait(background_time) + new_tab.Close() + action_runner.Wait(.5) + # Generate memory dump for memoryMetric. + if self.page_set.measure_memory: + action_runner.MeasureMemory() + class Page2(ToughVideoCasesPage): @@ -387,6 +413,19 @@ self.SeekBeforeAndAfterPlayhead(action_runner, action_timeout_in_seconds=120) +class Page37(ToughVideoCasesPage): + + def __init__(self, page_set): + super(Page37, self).__init__( + url='file://tough_video_cases/video.html?src=tulip2.vp9.webm&background', + page_set=page_set, + tags=['vp9', 'opus', 'audio_video', 'background']) + + self.skip_basic_metrics = True + + def RunPageInteractions(self, action_runner): + self.PlayInBackgroundTab(action_runner) + class ToughVideoCasesPageSet(story.StorySet): """ @@ -426,17 +465,20 @@ self.AddStory(Page33(self)) self.AddStory(Page36(self)) + # Background playback tests: + self.AddStory(Page37(self)) + class ToughVideoCasesDesktopStoryExpectations( story.expectations.StoryExpectations): def SetExpectations(self): self.PermanentlyDisableBenchmark( - [story.expectations.ALL_MOBILE],'Desktop Benchmark') + [story.expectations.ALL_MOBILE], 'Desktop Benchmark') class ToughVideoCasesAndroidStoryExpectations( story.expectations.StoryExpectations): def SetExpectations(self): self.PermanentlyDisableBenchmark( - [story.expectations.ALL_DESKTOP],'Android Benchmark') + [story.expectations.ALL_DESKTOP], 'Android Benchmark')
diff --git a/tools/perf/page_sets/update_webrtc_cases b/tools/perf/page_sets/update_webrtc_cases index 4bed428..03a8218 100755 --- a/tools/perf/page_sets/update_webrtc_cases +++ b/tools/perf/page_sets/update_webrtc_cases
@@ -22,6 +22,7 @@ 'dirs': [ 'src/canvas-capture', 'src/multiple-peerconnections', + 'src/pause-play', ], }, 'samples': { @@ -60,7 +61,7 @@ HTML_COPYRIGHT_NOTICE = ' * '.join(['<!--\n'] + COPYRIGHT_NOTICE) + '-->\n' STRIPPED_TAGS_RE = ('( *<meta.*?>\n?| *<link.*?>\n?|' - ' *<script.*>.*?</script>\n?|</body>.*?</html>)') + ' *<script.*>.*?</script>\n?| *</body>.*?</html>)') class TemporaryDirectory(object):
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py index 456e572..9652750 100644 --- a/tools/perf/page_sets/webrtc_cases.py +++ b/tools/perf/page_sets/webrtc_cases.py
@@ -117,11 +117,29 @@ action_runner.Wait(20) +class PausePlayPeerConnections(WebrtcPage): + """Why: Ensures frequent pause and plays of peer connection streams work.""" + + def __init__(self, page_set, tags): + super(PausePlayPeerConnections, self).__init__( + url='file://webrtc_cases/pause-play.html', + name='pause_play_peerconnections', + page_set=page_set, tags=tags) + + def RunPageInteractions(self, action_runner): + action_runner.ExecuteJavaScript( + 'startTest({test_runtime_s}, {num_peerconnections},' + '{iteration_delay_ms}, "video");'.format( + test_runtime_s=20, num_peerconnections=10, iteration_delay_ms=20)) + action_runner.Wait(20) + + class WebrtcPageSet(story.StorySet): def __init__(self): super(WebrtcPageSet, self).__init__( cloud_storage_bucket=story.PUBLIC_BUCKET) + self.AddStory(PausePlayPeerConnections(self, tags=['pauseplay'])) self.AddStory(MultiplePeerConnections(self, tags=['stress'])) self.AddStory(DataChannel(self, tags=['datachannel'])) self.AddStory(GetUserMedia(self, tags=['getusermedia']))
diff --git a/tools/perf/page_sets/webrtc_cases/adapter.js b/tools/perf/page_sets/webrtc_cases/adapter.js index 3af94d04..a3c0b08 100644 --- a/tools/perf/page_sets/webrtc_cases/adapter.js +++ b/tools/perf/page_sets/webrtc_cases/adapter.js
@@ -54,7 +54,7 @@ var candidate = { foundation: parts[0], - component: parts[1], + component: parseInt(parts[1], 10), protocol: parts[2].toLowerCase(), priority: parseInt(parts[3], 10), ip: parts[4], @@ -74,7 +74,8 @@ case 'tcptype': candidate.tcpType = parts[i + 1]; break; - default: // Unknown extensions are silently ignored. + default: // extension handling, in particular ufrag + candidate[parts[i]] = parts[i + 1]; break; } } @@ -105,9 +106,19 @@ sdp.push('tcptype'); sdp.push(candidate.tcpType); } + if (candidate.ufrag) { + sdp.push('ufrag'); + sdp.push(candidate.ufrag); + } return 'candidate:' + sdp.join(' '); }; +// Parses an ice-options line, returns an array of option tags. +// a=ice-options:foo bar +SDPUtils.parseIceOptions = function(line) { + return line.substr(14).split(' '); +} + // Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: // a=rtpmap:111 opus/48000/2 SDPUtils.parseRtpMap = function(line) { @@ -138,10 +149,12 @@ // Parses an a=extmap line (headerextension from RFC 5285). Sample input: // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset +// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset SDPUtils.parseExtmap = function(line) { var parts = line.substr(9).split(' '); return { id: parseInt(parts[0], 10), + direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', uri: parts[1] }; }; @@ -150,7 +163,10 @@ // RTCRtpHeaderExtension. SDPUtils.writeExtmap = function(headerExtension) { return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + - ' ' + headerExtension.uri + '\r\n'; + (headerExtension.direction && headerExtension.direction !== 'sendrecv' + ? '/' + headerExtension.direction + : '') + + ' ' + headerExtension.uri + '\r\n'; }; // Parses an ftmp line, returns dictionary. Sample input: @@ -228,25 +244,35 @@ return parts; }; +// Extracts the MID (RFC 5888) from a media section. +// returns the MID or undefined if no mid line was found. +SDPUtils.getMid = function(mediaSection) { + var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; + if (mid) { + return mid.substr(6); + } +} + +SDPUtils.parseFingerprint = function(line) { + var parts = line.substr(14).split(' '); + return { + algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. + value: parts[1] + }; +}; + // Extracts DTLS parameters from SDP media section or sessionpart. // FIXME: for consistency with other functions this should only // get the fingerprint line as input. See also getIceParameters. SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.splitLines(mediaSection); - // Search in session part, too. - lines = lines.concat(SDPUtils.splitLines(sessionpart)); - var fpLine = lines.filter(function(line) { - return line.indexOf('a=fingerprint:') === 0; - })[0].substr(14); + var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=fingerprint:'); // Note: a=setup line is ignored since we use the 'auto' role. - var dtlsParameters = { + // Note2: 'algorithm' is not case sensitive except in Edge. + return { role: 'auto', - fingerprints: [{ - algorithm: fpLine.split(' ')[0], - value: fpLine.split(' ')[1] - }] + fingerprints: lines.map(SDPUtils.parseFingerprint) }; - return dtlsParameters; }; // Serializes DTLS parameters to SDP. @@ -429,7 +455,11 @@ if (bandwidth[0].indexOf('b=TIAS:') === 0) { bandwidth = parseInt(bandwidth[0].substr(7), 10); } else if (bandwidth[0].indexOf('b=AS:') === 0) { - bandwidth = parseInt(bandwidth[0].substr(5), 10); + // use formula from JSEP to convert b=AS to TIAS value. + bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 + - (50 * 40 * 8); + } else { + bandwidth = undefined; } encodingParameters.forEach(function(params) { params.maxBitrate = bandwidth; @@ -471,7 +501,7 @@ return rtcpParameters; }; -// parses either a=msid: or a=ssrc:... msid lines an returns +// parses either a=msid: or a=ssrc:... msid lines and returns // the id of the MediaStream and MediaStreamTrack. SDPUtils.parseMsid = function(mediaSection) { var parts; @@ -493,10 +523,29 @@ } }; -SDPUtils.writeSessionBoilerplate = function() { +// Generate a session ID for SDP. +// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 +// recommends using a cryptographically random +ve 64-bit value +// but right now this should be acceptable and within the right range +SDPUtils.generateSessionId = function() { + return Math.random().toString().substr(2, 21); +}; + +// Write boilder plate for start of SDP +// sessId argument is optional - if not supplied it will +// be generated randomly +// sessVersion is optional and defaults to 2 +SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { + var sessionId; + var version = sessVer !== undefined ? sessVer : 2; + if (sessId) { + sessionId = sessId; + } else { + sessionId = SDPUtils.generateSessionId(); + } // FIXME: sess-id should be an NTP timestamp. return 'v=0\r\n' + - 'o=thisisadapterortc 8169639915646943137 2 IN IP4 127.0.0.1\r\n' + + 'o=thisisadapterortc ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + 's=-\r\n' + 't=0 0\r\n'; }; @@ -515,7 +564,9 @@ sdp += 'a=mid:' + transceiver.mid + '\r\n'; - if (transceiver.rtpSender && transceiver.rtpReceiver) { + if (transceiver.direction) { + sdp += 'a=' + transceiver.direction + '\r\n'; + } else if (transceiver.rtpSender && transceiver.rtpReceiver) { sdp += 'a=sendrecv\r\n'; } else if (transceiver.rtpSender) { sdp += 'a=sendonly\r\n'; @@ -588,6 +639,23 @@ module.exports = SDPUtils; },{}],2:[function(require,module,exports){ +(function (global){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ + +'use strict'; + +var adapterFactory = require('./adapter_factory.js'); +module.exports = adapterFactory({window: global.window}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./adapter_factory.js":3}],3:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -600,15 +668,34 @@ 'use strict'; // Shimming starts here. -(function() { +module.exports = function(dependencies, opts) { + var window = dependencies && dependencies.window; + + var options = { + shimChrome: true, + shimFirefox: true, + shimEdge: true, + shimSafari: true, + }; + + for (var key in opts) { + if (hasOwnProperty.call(opts, key)) { + options[key] = opts[key]; + } + } + // Utils. var utils = require('./utils'); var logging = utils.log; - var browserDetails = utils.browserDetails; + var browserDetails = utils.detectBrowser(window); + // Export to the adapter global object visible in the browser. - module.exports.browserDetails = browserDetails; - module.exports.extractVersion = utils.extractVersion; - module.exports.disableLog = utils.disableLog; + var adapter = { + browserDetails: browserDetails, + extractVersion: utils.extractVersion, + disableLog: utils.disableLog, + disableWarnings: utils.disableWarnings + }; // Uncomment the line below if you want logging to occur, including logging // for the switch statement below. Can also be turned on in the browser via @@ -625,67 +712,79 @@ // Shim browser if found. switch (browserDetails.browser) { case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection) { + if (!chromeShim || !chromeShim.shimPeerConnection || + !options.shimChrome) { logging('Chrome shim is not included in this adapter release.'); - return; + return adapter; } logging('adapter.js shimming chrome.'); // Export to the adapter global object visible in the browser. - module.exports.browserShim = chromeShim; + adapter.browserShim = chromeShim; - chromeShim.shimGetUserMedia(); - chromeShim.shimMediaStream(); - utils.shimCreateObjectURL(); - chromeShim.shimSourceObject(); - chromeShim.shimPeerConnection(); - chromeShim.shimOnTrack(); - chromeShim.shimGetSendersWithDtmf(); + chromeShim.shimGetUserMedia(window); + chromeShim.shimMediaStream(window); + utils.shimCreateObjectURL(window); + chromeShim.shimSourceObject(window); + chromeShim.shimPeerConnection(window); + chromeShim.shimOnTrack(window); + chromeShim.shimAddTrackRemoveTrack(window); + chromeShim.shimGetSendersWithDtmf(window); break; case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection) { + if (!firefoxShim || !firefoxShim.shimPeerConnection || + !options.shimFirefox) { logging('Firefox shim is not included in this adapter release.'); - return; + return adapter; } logging('adapter.js shimming firefox.'); // Export to the adapter global object visible in the browser. - module.exports.browserShim = firefoxShim; + adapter.browserShim = firefoxShim; - firefoxShim.shimGetUserMedia(); - utils.shimCreateObjectURL(); - firefoxShim.shimSourceObject(); - firefoxShim.shimPeerConnection(); - firefoxShim.shimOnTrack(); + firefoxShim.shimGetUserMedia(window); + utils.shimCreateObjectURL(window); + firefoxShim.shimSourceObject(window); + firefoxShim.shimPeerConnection(window); + firefoxShim.shimOnTrack(window); break; case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection) { + if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { logging('MS edge shim is not included in this adapter release.'); - return; + return adapter; } logging('adapter.js shimming edge.'); // Export to the adapter global object visible in the browser. - module.exports.browserShim = edgeShim; + adapter.browserShim = edgeShim; - edgeShim.shimGetUserMedia(); - utils.shimCreateObjectURL(); - edgeShim.shimPeerConnection(); + edgeShim.shimGetUserMedia(window); + utils.shimCreateObjectURL(window); + edgeShim.shimPeerConnection(window); + edgeShim.shimReplaceTrack(window); break; case 'safari': - if (!safariShim) { + if (!safariShim || !options.shimSafari) { logging('Safari shim is not included in this adapter release.'); - return; + return adapter; } logging('adapter.js shimming safari.'); // Export to the adapter global object visible in the browser. - module.exports.browserShim = safariShim; - - safariShim.shimGetUserMedia(); + adapter.browserShim = safariShim; + // shim window.URL.createObjectURL Safari (technical preview) + utils.shimCreateObjectURL(window); + safariShim.shimRTCIceServerUrls(window); + safariShim.shimCallbacksAPI(window); + safariShim.shimLocalStreamsAPI(window); + safariShim.shimRemoteStreamsAPI(window); + safariShim.shimGetUserMedia(window); break; default: logging('Unsupported browser!'); + break; } -})(); -},{"./chrome/chrome_shim":3,"./edge/edge_shim":5,"./firefox/firefox_shim":7,"./safari/safari_shim":9,"./utils":10}],3:[function(require,module,exports){ + return adapter; +}; + +},{"./chrome/chrome_shim":4,"./edge/edge_shim":6,"./firefox/firefox_shim":9,"./safari/safari_shim":11,"./utils":12}],4:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. @@ -696,15 +795,15 @@ */ /* eslint-env node */ 'use strict'; -var logging = require('../utils.js').log; -var browserDetails = require('../utils.js').browserDetails; +var utils = require('../utils.js'); +var logging = utils.log; var chromeShim = { - shimMediaStream: function() { + shimMediaStream: function(window) { window.MediaStream = window.MediaStream || window.webkitMediaStream; }, - shimOnTrack: function() { + shimOnTrack: function(window) { if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) { Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { @@ -712,70 +811,124 @@ return this._ontrack; }, set: function(f) { - var self = this; if (this._ontrack) { this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); } this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { + } + }); + var origSetRemoteDescription = + window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function() { + var pc = this; + if (!pc._ontrackpoly) { + pc._ontrackpoly = function(e) { // onaddstream does not fire when a track is added to an existing // stream. But stream.onaddtrack is implemented so we use that. e.stream.addEventListener('addtrack', function(te) { + var receiver; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = pc.getReceivers().find(function(r) { + return r.track.id === te.track.id; + }); + } else { + receiver = {track: te.track}; + } + var event = new Event('track'); event.track = te.track; - event.receiver = {track: te.track}; + event.receiver = receiver; event.streams = [e.stream]; - self.dispatchEvent(event); + pc.dispatchEvent(event); }); e.stream.getTracks().forEach(function(track) { + var receiver; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = pc.getReceivers().find(function(r) { + return r.track.id === track.id; + }); + } else { + receiver = {track: track}; + } var event = new Event('track'); event.track = track; - event.receiver = {track: track}; + event.receiver = receiver; event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); + pc.dispatchEvent(event); + }); + }; + pc.addEventListener('addstream', pc._ontrackpoly); } - }); + return origSetRemoteDescription.apply(pc, arguments); + }; } }, - shimGetSendersWithDtmf: function() { + shimGetSendersWithDtmf: function(window) { + // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. if (typeof window === 'object' && window.RTCPeerConnection && - !('getSenders' in RTCPeerConnection.prototype) && - 'createDTMFSender' in RTCPeerConnection.prototype) { - RTCPeerConnection.prototype.getSenders = function() { - return this._senders; + !('getSenders' in window.RTCPeerConnection.prototype) && + 'createDTMFSender' in window.RTCPeerConnection.prototype) { + var shimSenderWithDtmf = function(pc, track) { + return { + track: track, + get dtmf() { + if (this._dtmf === undefined) { + if (track.kind === 'audio') { + this._dtmf = pc.createDTMFSender(track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + }, + _pc: pc + }; }; - var origAddStream = RTCPeerConnection.prototype.addStream; - var origRemoveStream = RTCPeerConnection.prototype.removeStream; - RTCPeerConnection.prototype.addStream = function(stream) { + // augment addTrack when getSenders is not available. + if (!window.RTCPeerConnection.prototype.getSenders) { + window.RTCPeerConnection.prototype.getSenders = function() { + this._senders = this._senders || []; + return this._senders.slice(); // return a copy of the internal state. + }; + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function(track, stream) { + var pc = this; + var sender = origAddTrack.apply(pc, arguments); + if (!sender) { + sender = shimSenderWithDtmf(pc, track); + pc._senders.push(sender); + } + return sender; + }; + + var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function(sender) { + var pc = this; + origRemoveTrack.apply(pc, arguments); + var idx = pc._senders.indexOf(sender); + if (idx !== -1) { + pc._senders.splice(idx, 1); + } + }; + } + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function(stream) { var pc = this; pc._senders = pc._senders || []; origAddStream.apply(pc, [stream]); stream.getTracks().forEach(function(track) { - pc._senders.push({ - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }); + pc._senders.push(shimSenderWithDtmf(pc, track)); }); }; - RTCPeerConnection.prototype.removeStream = function(stream) { + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function(stream) { var pc = this; pc._senders = pc._senders || []; - origRemoveStream.apply(pc, [stream]); + origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); + stream.getTracks().forEach(function(track) { var sender = pc._senders.find(function(s) { return s.track === track; @@ -785,10 +938,39 @@ } }); }; + } else if (typeof window === 'object' && window.RTCPeerConnection && + 'getSenders' in window.RTCPeerConnection.prototype && + 'createDTMFSender' in window.RTCPeerConnection.prototype && + window.RTCRtpSender && + !('dtmf' in window.RTCRtpSender.prototype)) { + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + window.RTCPeerConnection.prototype.getSenders = function() { + var pc = this; + var senders = origGetSenders.apply(pc, []); + senders.forEach(function(sender) { + sender._pc = pc; + }); + return senders; + }; + + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get: function() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = this._pc.createDTMFSender(this.track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + } + }); } }, - shimSourceObject: function() { + shimSourceObject: function(window) { + var URL = window && window.URL; + if (typeof window === 'object') { if (window.HTMLMediaElement && !('srcObject' in window.HTMLMediaElement.prototype)) { @@ -830,7 +1012,154 @@ } }, - shimPeerConnection: function() { + shimAddTrackRemoveTrack: function(window) { + // shim addTrack and removeTrack. + if (window.RTCPeerConnection.prototype.addTrack) { + return; + } + + // also shim pc.getLocalStreams when addTrack is shimmed + // to return the original streams. + var origGetLocalStreams = window.RTCPeerConnection.prototype + .getLocalStreams; + window.RTCPeerConnection.prototype.getLocalStreams = function() { + var self = this; + var nativeStreams = origGetLocalStreams.apply(this); + self._reverseStreams = self._reverseStreams || {}; + return nativeStreams.map(function(stream) { + return self._reverseStreams[stream.id]; + }); + }; + + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function(stream) { + var pc = this; + pc._streams = pc._streams || {}; + pc._reverseStreams = pc._reverseStreams || {}; + + stream.getTracks().forEach(function(track) { + var alreadyExists = pc.getSenders().find(function(s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', + 'InvalidAccessError'); + } + }); + // Add identity mapping for consistency with addTrack. + // Unless this is being used with a stream from addTrack. + if (!pc._reverseStreams[stream.id]) { + var newStream = new window.MediaStream(stream.getTracks()); + pc._streams[stream.id] = newStream; + pc._reverseStreams[newStream.id] = stream; + stream = newStream; + } + origAddStream.apply(pc, [stream]); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function(stream) { + var pc = this; + pc._streams = pc._streams || {}; + pc._reverseStreams = pc._reverseStreams || {}; + + origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); + delete pc._reverseStreams[(pc._streams[stream.id] ? + pc._streams[stream.id].id : stream.id)]; + delete pc._streams[stream.id]; + }; + + window.RTCPeerConnection.prototype.addTrack = function(track, stream) { + var pc = this; + if (pc.signalingState === 'closed') { + throw new DOMException( + 'The RTCPeerConnection\'s signalingState is \'closed\'.', + 'InvalidStateError'); + } + var streams = [].slice.call(arguments, 1); + if (streams.length !== 1 || + !streams[0].getTracks().find(function(t) { + return t === track; + })) { + // this is not fully correct but all we can manage without + // [[associated MediaStreams]] internal slot. + throw new DOMException( + 'The adapter.js addTrack polyfill only supports a single ' + + ' stream which is associated with the specified track.', + 'NotSupportedError'); + } + + var alreadyExists = pc.getSenders().find(function(s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', + 'InvalidAccessError'); + } + + pc._streams = pc._streams || {}; + pc._reverseStreams = pc._reverseStreams || {}; + var oldStream = pc._streams[stream.id]; + if (oldStream) { + // this is using odd Chrome behaviour, use with caution: + // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 + // Note: we rely on the high-level addTrack/dtmf shim to + // create the sender with a dtmf sender. + oldStream.addTrack(track); + pc.dispatchEvent(new Event('negotiationneeded')); + } else { + var newStream = new window.MediaStream([track]); + pc._streams[stream.id] = newStream; + pc._reverseStreams[newStream.id] = stream; + pc.addStream(newStream); + } + return pc.getSenders().find(function(s) { + return s.track === track; + }); + }; + + window.RTCPeerConnection.prototype.removeTrack = function(sender) { + var pc = this; + if (pc.signalingState === 'closed') { + throw new DOMException( + 'The RTCPeerConnection\'s signalingState is \'closed\'.', + 'InvalidStateError'); + } + var isLocal = sender._pc === pc; + if (!isLocal) { + throw new DOMException('Sender was not created by this connection.', + 'InvalidAccessError'); + } + + // Search for the native stream the senders track belongs to. + pc._streams = pc._streams || {}; + var stream; + Object.keys(pc._streams).forEach(function(streamid) { + var hasTrack = pc._streams[streamid].getTracks().find(function(track) { + return sender.track === track; + }); + if (hasTrack) { + stream = pc._streams[streamid]; + } + }); + + if (stream) { + if (stream.getTracks().length === 1) { + // if this is the last track of the stream, remove the stream. This + // takes care of any shimmed _senders. + pc.removeStream(stream); + } else { + // relying on the same odd chrome behaviour as above. + stream.removeTrack(sender.track); + } + pc.dispatchEvent(new Event('negotiationneeded')); + } + }; + }, + + shimPeerConnection: function(window) { + var browserDetails = utils.detectBrowser(window); + // The RTCPeerConnection object. if (!window.RTCPeerConnection) { window.RTCPeerConnection = function(pcConfig, pcConstraints) { @@ -842,21 +1171,51 @@ pcConfig.iceTransports = pcConfig.iceTransportPolicy; } - return new webkitRTCPeerConnection(pcConfig, pcConstraints); + return new window.webkitRTCPeerConnection(pcConfig, pcConstraints); }; - window.RTCPeerConnection.prototype = webkitRTCPeerConnection.prototype; + window.RTCPeerConnection.prototype = + window.webkitRTCPeerConnection.prototype; // wrap static methods. Currently just generateCertificate. - if (webkitRTCPeerConnection.generateCertificate) { + if (window.webkitRTCPeerConnection.generateCertificate) { Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { get: function() { - return webkitRTCPeerConnection.generateCertificate; + return window.webkitRTCPeerConnection.generateCertificate; } }); } + } else { + // migrate from non-spec RTCIceServer.url to RTCIceServer.urls + var OrigPeerConnection = window.RTCPeerConnection; + window.RTCPeerConnection = function(pcConfig, pcConstraints) { + if (pcConfig && pcConfig.iceServers) { + var newIceServers = []; + for (var i = 0; i < pcConfig.iceServers.length; i++) { + var server = pcConfig.iceServers[i]; + if (!server.hasOwnProperty('urls') && + server.hasOwnProperty('url')) { + console.warn('RTCIceServer.url is deprecated! Use urls instead.'); + server = JSON.parse(JSON.stringify(server)); + server.urls = server.url; + newIceServers.push(server); + } else { + newIceServers.push(pcConfig.iceServers[i]); + } + } + pcConfig.iceServers = newIceServers; + } + return new OrigPeerConnection(pcConfig, pcConstraints); + }; + window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; + // wrap static methods. Currently just generateCertificate. + Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { + get: function() { + return OrigPeerConnection.generateCertificate; + } + }); } - var origGetStats = RTCPeerConnection.prototype.getStats; - RTCPeerConnection.prototype.getStats = function(selector, + var origGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function(selector, successCallback, errorCallback) { var self = this; var args = arguments; @@ -898,7 +1257,7 @@ // shim getStats with maplike support var makeMapStats = function(stats) { return new Map(Object.keys(stats).map(function(key) { - return[key, stats[key]]; + return [key, stats[key]]; })); }; @@ -908,7 +1267,7 @@ }; return origGetStats.apply(this, [successCallbackWrapper_, - arguments[0]]); + arguments[0]]); } // promise-support @@ -924,8 +1283,8 @@ if (browserDetails.version < 51) { ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] .forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + window.RTCPeerConnection.prototype[method] = function() { var args = arguments; var self = this; var promise = new Promise(function(resolve, reject) { @@ -950,8 +1309,8 @@ // bugs) since M52: crbug/619289 if (browserDetails.version < 52) { ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + window.RTCPeerConnection.prototype[method] = function() { var self = this; if (arguments.length < 1 || (arguments.length === 1 && typeof arguments[0] === 'object')) { @@ -968,18 +1327,19 @@ // shim implicit creation of RTCSessionDescription/RTCIceCandidate ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] .forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + window.RTCPeerConnection.prototype[method] = function() { arguments[0] = new ((method === 'addIceCandidate') ? - RTCIceCandidate : RTCSessionDescription)(arguments[0]); + window.RTCIceCandidate : + window.RTCSessionDescription)(arguments[0]); return nativeMethod.apply(this, arguments); }; }); // support for addIceCandidate(null or undefined) var nativeAddIceCandidate = - RTCPeerConnection.prototype.addIceCandidate; - RTCPeerConnection.prototype.addIceCandidate = function() { + window.RTCPeerConnection.prototype.addIceCandidate; + window.RTCPeerConnection.prototype.addIceCandidate = function() { if (!arguments[0]) { if (arguments[1]) { arguments[1].apply(null); @@ -996,13 +1356,14 @@ module.exports = { shimMediaStream: chromeShim.shimMediaStream, shimOnTrack: chromeShim.shimOnTrack, + shimAddTrackRemoveTrack: chromeShim.shimAddTrackRemoveTrack, shimGetSendersWithDtmf: chromeShim.shimGetSendersWithDtmf, shimSourceObject: chromeShim.shimSourceObject, shimPeerConnection: chromeShim.shimPeerConnection, shimGetUserMedia: require('./getusermedia') }; -},{"../utils.js":10,"./getusermedia":4}],4:[function(require,module,exports){ +},{"../utils.js":12,"./getusermedia":5}],5:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -1012,11 +1373,14 @@ */ /* eslint-env node */ 'use strict'; -var logging = require('../utils.js').log; -var browserDetails = require('../utils.js').browserDetails; +var utils = require('../utils.js'); +var logging = utils.log; // Expose public methods. -module.exports = function() { +module.exports = function(window) { + var browserDetails = utils.detectBrowser(window); + var navigator = window && window.navigator; + var constraintsToChrome_ = function(c) { if (typeof c !== 'object' || c.mandatory || c.optional) { return c; @@ -1070,14 +1434,23 @@ var shimConstraints_ = function(constraints, func) { constraints = JSON.parse(JSON.stringify(constraints)); - if (constraints && constraints.audio) { + if (constraints && typeof constraints.audio === 'object') { + var remap = function(obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + constraints = JSON.parse(JSON.stringify(constraints)); + remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); + remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); constraints.audio = constraintsToChrome_(constraints.audio); } if (constraints && typeof constraints.video === 'object') { - // Shim facingMode for mobile, where it defaults to "user". + // Shim facingMode for mobile & surface pro. var face = constraints.video.facingMode; face = face && ((typeof face === 'object') ? face : {ideal: face}); - var getSupportedFacingModeLies = browserDetails.version < 59; + var getSupportedFacingModeLies = browserDetails.version < 61; if ((face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment')) && @@ -1085,19 +1458,30 @@ navigator.mediaDevices.getSupportedConstraints().facingMode && !getSupportedFacingModeLies)) { delete constraints.video.facingMode; + var matches; if (face.exact === 'environment' || face.ideal === 'environment') { - // Look for "back" in label, or use last cam (typically back cam). + matches = ['back', 'rear']; + } else if (face.exact === 'user' || face.ideal === 'user') { + matches = ['front']; + } + if (matches) { + // Look for matches in label, or use last cam for back (typical). return navigator.mediaDevices.enumerateDevices() .then(function(devices) { devices = devices.filter(function(d) { return d.kind === 'videoinput'; }); - var back = devices.find(function(d) { - return d.label.toLowerCase().indexOf('back') !== -1; - }) || (devices.length && devices[devices.length - 1]); - if (back) { - constraints.video.deviceId = face.exact ? {exact: back.deviceId} : - {ideal: back.deviceId}; + var dev = devices.find(function(d) { + return matches.some(function(match) { + return d.label.toLowerCase().indexOf(match) !== -1; + }); + }); + if (!dev && devices.length && matches.indexOf('back') !== -1) { + dev = devices[devices.length - 1]; // more likely the back cam + } + if (dev) { + constraints.video.deviceId = face.exact ? {exact: dev.deviceId} : + {ideal: dev.deviceId}; } constraints.video = constraintsToChrome_(constraints.video); logging('chrome: ' + JSON.stringify(constraints)); @@ -1115,7 +1499,12 @@ return { name: { PermissionDeniedError: 'NotAllowedError', - ConstraintNotSatisfiedError: 'OverconstrainedError' + InvalidStateError: 'NotReadableError', + DevicesNotFoundError: 'NotFoundError', + ConstraintNotSatisfiedError: 'OverconstrainedError', + TrackStartError: 'NotReadableError', + MediaDeviceFailedDueToShutdown: 'NotReadableError', + MediaDeviceKillSwitchOn: 'NotReadableError' }[e.name] || e.name, message: e.message, constraint: e.constraintName, @@ -1148,12 +1537,12 @@ enumerateDevices: function() { return new Promise(function(resolve) { var kinds = {audio: 'audioinput', video: 'videoinput'}; - return MediaStreamTrack.getSources(function(devices) { + return window.MediaStreamTrack.getSources(function(devices) { resolve(devices.map(function(device) { return {label: device.label, - kind: kinds[device.kind], - deviceId: device.id, - groupId: ''}; + kind: kinds[device.kind], + deviceId: device.id, + groupId: ''}; })); }); }); @@ -1211,7 +1600,7 @@ } }; -},{"../utils.js":10}],5:[function(require,module,exports){ +},{"../utils.js":12}],6:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -1222,8 +1611,125 @@ /* eslint-env node */ 'use strict'; +var utils = require('../utils'); +var shimRTCPeerConnection = require('./rtcpeerconnection_shim'); + +module.exports = { + shimGetUserMedia: require('./getusermedia'), + shimPeerConnection: function(window) { + var browserDetails = utils.detectBrowser(window); + + if (window.RTCIceGatherer) { + // ORTC defines an RTCIceCandidate object but no constructor. + // Not implemented in Edge. + if (!window.RTCIceCandidate) { + window.RTCIceCandidate = function(args) { + return args; + }; + } + // ORTC does not have a session description object but + // other browsers (i.e. Chrome) that will support both PC and ORTC + // in the future might have this defined already. + if (!window.RTCSessionDescription) { + window.RTCSessionDescription = function(args) { + return args; + }; + } + // this adds an additional event listener to MediaStrackTrack that signals + // when a tracks enabled property was changed. Workaround for a bug in + // addStream, see below. No longer required in 15025+ + if (browserDetails.version < 15025) { + var origMSTEnabled = Object.getOwnPropertyDescriptor( + window.MediaStreamTrack.prototype, 'enabled'); + Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { + set: function(value) { + origMSTEnabled.set.call(this, value); + var ev = new Event('enabled'); + ev.enabled = value; + this.dispatchEvent(ev); + } + }); + } + } + + // ORTC defines the DTMF sender a bit different. + // https://github.com/w3c/ortc/issues/714 + if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get: function() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = new window.RTCDtmfSender(this); + } else if (this.track.kind === 'video') { + this._dtmf = null; + } + } + return this._dtmf; + } + }); + } + + window.RTCPeerConnection = + shimRTCPeerConnection(window, browserDetails.version); + }, + shimReplaceTrack: function(window) { + // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 + if (window.RTCRtpSender && + !('replaceTrack' in window.RTCRtpSender.prototype)) { + window.RTCRtpSender.prototype.replaceTrack = + window.RTCRtpSender.prototype.setTrack; + } + } +}; + +},{"../utils":12,"./getusermedia":7,"./rtcpeerconnection_shim":8}],7:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ +'use strict'; + +// Expose public methods. +module.exports = function(window) { + var navigator = window && window.navigator; + + var shimError_ = function(e) { + return { + name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name, + message: e.message, + constraint: e.constraint, + toString: function() { + return this.name; + } + }; + }; + + // getUserMedia error shim. + var origGetUserMedia = navigator.mediaDevices.getUserMedia. + bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function(c) { + return origGetUserMedia(c).catch(function(e) { + return Promise.reject(shimError_(e)); + }); + }; +}; + +},{}],8:[function(require,module,exports){ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ +'use strict'; + var SDPUtils = require('sdp'); -var browserDetails = require('../utils').browserDetails; // sort tracks such that they follow an a-v-a-v... // pattern. @@ -1251,12 +1757,15 @@ // 2) turn: that does not have all of turn:host:port?transport=udp // 3) turn: with ipv6 addresses // 4) turn: occurring muliple times -function filterIceServers(iceServers) { +function filterIceServers(iceServers, edgeVersion) { var hasTurn = false; iceServers = JSON.parse(JSON.stringify(iceServers)); return iceServers.filter(function(server) { if (server && (server.urls || server.url)) { var urls = server.urls || server.url; + if (server.url && !server.urls) { + console.warn('RTCIceServer.url is deprecated! Use urls instead.'); + } var isString = typeof urls === 'string'; if (isString) { urls = [urls]; @@ -1271,8 +1780,7 @@ hasTurn = true; return true; } - return url.indexOf('stun:') === 0 && - browserDetails.version >= 14393; + return url.indexOf('stun:') === 0 && edgeVersion >= 14393; }); delete server.url; @@ -1283,1191 +1791,1325 @@ }); } -var edgeShim = { - shimPeerConnection: function() { - if (window.RTCIceGatherer) { - // ORTC defines an RTCIceCandidate object but no constructor. - // Not implemented in Edge. - if (!window.RTCIceCandidate) { - window.RTCIceCandidate = function(args) { - return args; - }; - } - // ORTC does not have a session description object but - // other browsers (i.e. Chrome) that will support both PC and ORTC - // in the future might have this defined already. - if (!window.RTCSessionDescription) { - window.RTCSessionDescription = function(args) { - return args; - }; - } - // this adds an additional event listener to MediaStrackTrack that signals - // when a tracks enabled property was changed. Workaround for a bug in - // addStream, see below. No longer required in 15025+ - if (browserDetails.version < 15025) { - var origMSTEnabled = Object.getOwnPropertyDescriptor( - MediaStreamTrack.prototype, 'enabled'); - Object.defineProperty(MediaStreamTrack.prototype, 'enabled', { - set: function(value) { - origMSTEnabled.set.call(this, value); - var ev = new Event('enabled'); - ev.enabled = value; - this.dispatchEvent(ev); - } - }); +// Determines the intersection of local and remote capabilities. +function getCommonCapabilities(localCapabilities, remoteCapabilities) { + var commonCapabilities = { + codecs: [], + headerExtensions: [], + fecMechanisms: [] + }; + + var findCodecByPayloadType = function(pt, codecs) { + pt = parseInt(pt, 10); + for (var i = 0; i < codecs.length; i++) { + if (codecs[i].payloadType === pt || + codecs[i].preferredPayloadType === pt) { + return codecs[i]; } } + }; - window.RTCPeerConnection = function(config) { - var self = this; + var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { + var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); + var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); + return lCodec && rCodec && + lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); + }; - var _eventTarget = document.createDocumentFragment(); - ['addEventListener', 'removeEventListener', 'dispatchEvent'] - .forEach(function(method) { - self[method] = _eventTarget[method].bind(_eventTarget); - }); - - this.onicecandidate = null; - this.onaddstream = null; - this.ontrack = null; - this.onremovestream = null; - this.onsignalingstatechange = null; - this.oniceconnectionstatechange = null; - this.onicegatheringstatechange = null; - this.onnegotiationneeded = null; - this.ondatachannel = null; - - this.localStreams = []; - this.remoteStreams = []; - this.getLocalStreams = function() { - return self.localStreams; - }; - this.getRemoteStreams = function() { - return self.remoteStreams; - }; - - this.localDescription = new RTCSessionDescription({ - type: '', - sdp: '' - }); - this.remoteDescription = new RTCSessionDescription({ - type: '', - sdp: '' - }); - this.signalingState = 'stable'; - this.iceConnectionState = 'new'; - this.iceGatheringState = 'new'; - - this.iceOptions = { - gatherPolicy: 'all', - iceServers: [] - }; - if (config && config.iceTransportPolicy) { - switch (config.iceTransportPolicy) { - case 'all': - case 'relay': - this.iceOptions.gatherPolicy = config.iceTransportPolicy; - break; - default: - // don't set iceTransportPolicy. - break; + localCapabilities.codecs.forEach(function(lCodec) { + for (var i = 0; i < remoteCapabilities.codecs.length; i++) { + var rCodec = remoteCapabilities.codecs[i]; + if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && + lCodec.clockRate === rCodec.clockRate) { + if (lCodec.name.toLowerCase() === 'rtx' && + lCodec.parameters && rCodec.parameters.apt) { + // for RTX we need to find the local rtx that has a apt + // which points to the same local codec as the remote one. + if (!rtxCapabilityMatches(lCodec, rCodec, + localCapabilities.codecs, remoteCapabilities.codecs)) { + continue; + } } - } - this.usingBundle = config && config.bundlePolicy === 'max-bundle'; + rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy + // number of channels is the highest common number of channels + rCodec.numChannels = Math.min(lCodec.numChannels, + rCodec.numChannels); + // push rCodec so we reply with offerer payload type + commonCapabilities.codecs.push(rCodec); - if (config && config.iceServers) { - this.iceOptions.iceServers = filterIceServers(config.iceServers); - } - this._config = config; - - // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... - // everything that is needed to describe a SDP m-line. - this.transceivers = []; - - // since the iceGatherer is currently created in createOffer but we - // must not emit candidates until after setLocalDescription we buffer - // them in this array. - this._localIceCandidatesBuffer = []; - }; - - window.RTCPeerConnection.prototype._emitGatheringStateChange = function() { - var event = new Event('icegatheringstatechange'); - this.dispatchEvent(event); - if (this.onicegatheringstatechange !== null) { - this.onicegatheringstatechange(event); - } - }; - - window.RTCPeerConnection.prototype._emitBufferedCandidates = function() { - var self = this; - var sections = SDPUtils.splitSections(self.localDescription.sdp); - // FIXME: need to apply ice candidates in a way which is async but - // in-order - this._localIceCandidatesBuffer.forEach(function(event) { - var end = !event.candidate || Object.keys(event.candidate).length === 0; - if (end) { - for (var j = 1; j < sections.length; j++) { - if (sections[j].indexOf('\r\na=end-of-candidates\r\n') === -1) { - sections[j] += 'a=end-of-candidates\r\n'; + // determine common feedback mechanisms + rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { + for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { + if (lCodec.rtcpFeedback[j].type === fb.type && + lCodec.rtcpFeedback[j].parameter === fb.parameter) { + return true; } } - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; + return false; + }); + // FIXME: also need to determine .parameters + // see https://github.com/openpeer/ortc/issues/569 + break; + } + } + }); + + localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { + for (var i = 0; i < remoteCapabilities.headerExtensions.length; + i++) { + var rHeaderExtension = remoteCapabilities.headerExtensions[i]; + if (lHeaderExtension.uri === rHeaderExtension.uri) { + commonCapabilities.headerExtensions.push(rHeaderExtension); + break; + } + } + }); + + // FIXME: fecMechanisms + return commonCapabilities; +} + +// is action=setLocalDescription with type allowed in signalingState +function isActionAllowedInSignalingState(action, type, signalingState) { + return { + offer: { + setLocalDescription: ['stable', 'have-local-offer'], + setRemoteDescription: ['stable', 'have-remote-offer'] + }, + answer: { + setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], + setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] + } + }[type][action].indexOf(signalingState) !== -1; +} + +module.exports = function(window, edgeVersion) { + var RTCPeerConnection = function(config) { + var self = this; + + var _eventTarget = document.createDocumentFragment(); + ['addEventListener', 'removeEventListener', 'dispatchEvent'] + .forEach(function(method) { + self[method] = _eventTarget[method].bind(_eventTarget); + }); + + this.needNegotiation = false; + + this.onicecandidate = null; + this.onaddstream = null; + this.ontrack = null; + this.onremovestream = null; + this.onsignalingstatechange = null; + this.oniceconnectionstatechange = null; + this.onicegatheringstatechange = null; + this.onnegotiationneeded = null; + this.ondatachannel = null; + this.canTrickleIceCandidates = null; + + this.localStreams = []; + this.remoteStreams = []; + this.getLocalStreams = function() { + return self.localStreams; + }; + this.getRemoteStreams = function() { + return self.remoteStreams; + }; + + this.localDescription = new window.RTCSessionDescription({ + type: '', + sdp: '' + }); + this.remoteDescription = new window.RTCSessionDescription({ + type: '', + sdp: '' + }); + this.signalingState = 'stable'; + this.iceConnectionState = 'new'; + this.iceGatheringState = 'new'; + + this.iceOptions = { + gatherPolicy: 'all', + iceServers: [] + }; + if (config && config.iceTransportPolicy) { + switch (config.iceTransportPolicy) { + case 'all': + case 'relay': + this.iceOptions.gatherPolicy = config.iceTransportPolicy; + break; + default: + // don't set iceTransportPolicy. + break; + } + } + this.usingBundle = config && config.bundlePolicy === 'max-bundle'; + + if (config && config.iceServers) { + this.iceOptions.iceServers = filterIceServers(config.iceServers, + edgeVersion); + } + this._config = config || {}; + + // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... + // everything that is needed to describe a SDP m-line. + this.transceivers = []; + + // since the iceGatherer is currently created in createOffer but we + // must not emit candidates until after setLocalDescription we buffer + // them in this array. + this._localIceCandidatesBuffer = []; + + this._sdpSessionId = SDPUtils.generateSessionId(); + }; + + RTCPeerConnection.prototype._emitGatheringStateChange = function() { + var event = new Event('icegatheringstatechange'); + this.dispatchEvent(event); + if (this.onicegatheringstatechange !== null) { + this.onicegatheringstatechange(event); + } + }; + + RTCPeerConnection.prototype._emitBufferedCandidates = function() { + var self = this; + var sections = SDPUtils.splitSections(self.localDescription.sdp); + // FIXME: need to apply ice candidates in a way which is async but + // in-order + this._localIceCandidatesBuffer.forEach(function(event) { + var end = !event.candidate || Object.keys(event.candidate).length === 0; + if (end) { + for (var j = 1; j < sections.length; j++) { + if (sections[j].indexOf('\r\na=end-of-candidates\r\n') === -1) { + sections[j] += 'a=end-of-candidates\r\n'; + } } - self.localDescription.sdp = sections.join(''); - self.dispatchEvent(event); - if (self.onicecandidate !== null) { - self.onicecandidate(event); + } else { + sections[event.candidate.sdpMLineIndex + 1] += + 'a=' + event.candidate.candidate + '\r\n'; + } + self.localDescription.sdp = sections.join(''); + self.dispatchEvent(event); + if (self.onicecandidate !== null) { + self.onicecandidate(event); + } + if (!event.candidate && self.iceGatheringState !== 'complete') { + var complete = self.transceivers.every(function(transceiver) { + return transceiver.iceGatherer && + transceiver.iceGatherer.state === 'completed'; + }); + if (complete && self.iceGatheringStateChange !== 'complete') { + self.iceGatheringState = 'complete'; + self._emitGatheringStateChange(); } - if (!event.candidate && self.iceGatheringState !== 'complete') { - var complete = self.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - if (complete && self.iceGatheringStateChange !== 'complete') { + } + }); + this._localIceCandidatesBuffer = []; + }; + + RTCPeerConnection.prototype.getConfiguration = function() { + return this._config; + }; + + // internal helper to create a transceiver object. + // (whih is not yet the same as the WebRTC 1.0 transceiver) + RTCPeerConnection.prototype._createTransceiver = function(kind) { + var hasBundleTransport = this.transceivers.length > 0; + var transceiver = { + track: null, + iceGatherer: null, + iceTransport: null, + dtlsTransport: null, + localCapabilities: null, + remoteCapabilities: null, + rtpSender: null, + rtpReceiver: null, + kind: kind, + mid: null, + sendEncodingParameters: null, + recvEncodingParameters: null, + stream: null, + wantReceive: true + }; + if (this.usingBundle && hasBundleTransport) { + transceiver.iceTransport = this.transceivers[0].iceTransport; + transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; + } else { + var transports = this._createIceAndDtlsTransports(); + transceiver.iceTransport = transports.iceTransport; + transceiver.dtlsTransport = transports.dtlsTransport; + } + this.transceivers.push(transceiver); + return transceiver; + }; + + RTCPeerConnection.prototype.addTrack = function(track, stream) { + var transceiver; + for (var i = 0; i < this.transceivers.length; i++) { + if (!this.transceivers[i].track && + this.transceivers[i].kind === track.kind) { + transceiver = this.transceivers[i]; + } + } + if (!transceiver) { + transceiver = this._createTransceiver(track.kind); + } + + transceiver.track = track; + transceiver.stream = stream; + transceiver.rtpSender = new window.RTCRtpSender(track, + transceiver.dtlsTransport); + + this._maybeFireNegotiationNeeded(); + return transceiver.rtpSender; + }; + + RTCPeerConnection.prototype.addStream = function(stream) { + var self = this; + if (edgeVersion >= 15025) { + this.localStreams.push(stream); + stream.getTracks().forEach(function(track) { + self.addTrack(track, stream); + }); + } else { + // Clone is necessary for local demos mostly, attaching directly + // to two different senders does not work (build 10547). + // Fixed in 15025 (or earlier) + var clonedStream = stream.clone(); + stream.getTracks().forEach(function(track, idx) { + var clonedTrack = clonedStream.getTracks()[idx]; + track.addEventListener('enabled', function(event) { + clonedTrack.enabled = event.enabled; + }); + }); + clonedStream.getTracks().forEach(function(track) { + self.addTrack(track, clonedStream); + }); + this.localStreams.push(clonedStream); + } + this._maybeFireNegotiationNeeded(); + }; + + RTCPeerConnection.prototype.removeStream = function(stream) { + var idx = this.localStreams.indexOf(stream); + if (idx > -1) { + this.localStreams.splice(idx, 1); + this._maybeFireNegotiationNeeded(); + } + }; + + RTCPeerConnection.prototype.getSenders = function() { + return this.transceivers.filter(function(transceiver) { + return !!transceiver.rtpSender; + }) + .map(function(transceiver) { + return transceiver.rtpSender; + }); + }; + + RTCPeerConnection.prototype.getReceivers = function() { + return this.transceivers.filter(function(transceiver) { + return !!transceiver.rtpReceiver; + }) + .map(function(transceiver) { + return transceiver.rtpReceiver; + }); + }; + + // Create ICE gatherer and hook it up. + RTCPeerConnection.prototype._createIceGatherer = function(mid, + sdpMLineIndex) { + var self = this; + var iceGatherer = new window.RTCIceGatherer(self.iceOptions); + iceGatherer.onlocalcandidate = function(evt) { + var event = new Event('icecandidate'); + event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; + + var cand = evt.candidate; + var end = !cand || Object.keys(cand).length === 0; + // Edge emits an empty object for RTCIceCandidateComplete‥ + if (end) { + // polyfill since RTCIceGatherer.state is not implemented in + // Edge 10547 yet. + if (iceGatherer.state === undefined) { + iceGatherer.state = 'completed'; + } + } else { + // RTCIceCandidate doesn't have a component, needs to be added + cand.component = 1; + event.candidate.candidate = SDPUtils.writeCandidate(cand); + } + + // update local description. + var sections = SDPUtils.splitSections(self.localDescription.sdp); + if (!end) { + sections[event.candidate.sdpMLineIndex + 1] += + 'a=' + event.candidate.candidate + '\r\n'; + } else { + sections[event.candidate.sdpMLineIndex + 1] += + 'a=end-of-candidates\r\n'; + } + self.localDescription.sdp = sections.join(''); + var transceivers = self._pendingOffer ? self._pendingOffer : + self.transceivers; + var complete = transceivers.every(function(transceiver) { + return transceiver.iceGatherer && + transceiver.iceGatherer.state === 'completed'; + }); + + // Emit candidate if localDescription is set. + // Also emits null candidate when all gatherers are complete. + switch (self.iceGatheringState) { + case 'new': + if (!end) { + self._localIceCandidatesBuffer.push(event); + } + if (end && complete) { + self._localIceCandidatesBuffer.push( + new Event('icecandidate')); + } + break; + case 'gathering': + self._emitBufferedCandidates(); + if (!end) { + self.dispatchEvent(event); + if (self.onicecandidate !== null) { + self.onicecandidate(event); + } + } + if (complete) { + self.dispatchEvent(new Event('icecandidate')); + if (self.onicecandidate !== null) { + self.onicecandidate(new Event('icecandidate')); + } self.iceGatheringState = 'complete'; self._emitGatheringStateChange(); } - } - }); - this._localIceCandidatesBuffer = []; - }; - - window.RTCPeerConnection.prototype.getConfiguration = function() { - return this._config; - }; - - window.RTCPeerConnection.prototype.addStream = function(stream) { - if (browserDetails.version >= 15025) { - this.localStreams.push(stream); - } else { - // Clone is necessary for local demos mostly, attaching directly - // to two different senders does not work (build 10547). - // Fixed in 15025 (or earlier) - var clonedStream = stream.clone(); - stream.getTracks().forEach(function(track, idx) { - var clonedTrack = clonedStream.getTracks()[idx]; - track.addEventListener('enabled', function(event) { - clonedTrack.enabled = event.enabled; - }); - }); - this.localStreams.push(clonedStream); - } - this._maybeFireNegotiationNeeded(); - }; - - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var idx = this.localStreams.indexOf(stream); - if (idx > -1) { - this.localStreams.splice(idx, 1); - this._maybeFireNegotiationNeeded(); + break; + case 'complete': + // should not happen... currently! + break; + default: // no-op. + break; } }; + return iceGatherer; + }; - window.RTCPeerConnection.prototype.getSenders = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpSender; - }) - .map(function(transceiver) { - return transceiver.rtpSender; - }); + // Create ICE transport and DTLS transport. + RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { + var self = this; + var iceTransport = new window.RTCIceTransport(null); + iceTransport.onicestatechange = function() { + self._updateConnectionState(); }; - window.RTCPeerConnection.prototype.getReceivers = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpReceiver; - }) - .map(function(transceiver) { - return transceiver.rtpReceiver; - }); + var dtlsTransport = new window.RTCDtlsTransport(iceTransport); + dtlsTransport.ondtlsstatechange = function() { + self._updateConnectionState(); + }; + dtlsTransport.onerror = function() { + // onerror does not set state to failed by itself. + Object.defineProperty(dtlsTransport, 'state', + {value: 'failed', writable: true}); + self._updateConnectionState(); }; - // Determines the intersection of local and remote capabilities. - window.RTCPeerConnection.prototype._getCommonCapabilities = - function(localCapabilities, remoteCapabilities) { - var commonCapabilities = { - codecs: [], - headerExtensions: [], - fecMechanisms: [] - }; - - var findCodecByPayloadType = function(pt, codecs) { - pt = parseInt(pt, 10); - for (var i = 0; i < codecs.length; i++) { - if (codecs[i].payloadType === pt || - codecs[i].preferredPayloadType === pt) { - return codecs[i]; - } - } - }; - - var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { - var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); - var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); - return lCodec && rCodec && - lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); - }; - - localCapabilities.codecs.forEach(function(lCodec) { - for (var i = 0; i < remoteCapabilities.codecs.length; i++) { - var rCodec = remoteCapabilities.codecs[i]; - if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && - lCodec.clockRate === rCodec.clockRate) { - if (lCodec.name.toLowerCase() === 'rtx' && - lCodec.parameters && rCodec.parameters.apt) { - // for RTX we need to find the local rtx that has a apt - // which points to the same local codec as the remote one. - if (!rtxCapabilityMatches(lCodec, rCodec, - localCapabilities.codecs, remoteCapabilities.codecs)) { - continue; - } - } - rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy - // number of channels is the highest common number of channels - rCodec.numChannels = Math.min(lCodec.numChannels, - rCodec.numChannels); - // push rCodec so we reply with offerer payload type - commonCapabilities.codecs.push(rCodec); - - // determine common feedback mechanisms - rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { - for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { - if (lCodec.rtcpFeedback[j].type === fb.type && - lCodec.rtcpFeedback[j].parameter === fb.parameter) { - return true; - } - } - return false; - }); - // FIXME: also need to determine .parameters - // see https://github.com/openpeer/ortc/issues/569 - break; - } - } - }); - - localCapabilities.headerExtensions - .forEach(function(lHeaderExtension) { - for (var i = 0; i < remoteCapabilities.headerExtensions.length; - i++) { - var rHeaderExtension = remoteCapabilities.headerExtensions[i]; - if (lHeaderExtension.uri === rHeaderExtension.uri) { - commonCapabilities.headerExtensions.push(rHeaderExtension); - break; - } - } - }); - - // FIXME: fecMechanisms - return commonCapabilities; - }; - - // Create ICE gatherer, ICE transport and DTLS transport. - window.RTCPeerConnection.prototype._createIceAndDtlsTransports = - function(mid, sdpMLineIndex) { - var self = this; - var iceGatherer = new RTCIceGatherer(self.iceOptions); - var iceTransport = new RTCIceTransport(iceGatherer); - iceGatherer.onlocalcandidate = function(evt) { - var event = new Event('icecandidate'); - event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; - - var cand = evt.candidate; - var end = !cand || Object.keys(cand).length === 0; - // Edge emits an empty object for RTCIceCandidateComplete‥ - if (end) { - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - if (iceGatherer.state === undefined) { - iceGatherer.state = 'completed'; - } - } else { - // RTCIceCandidate doesn't have a component, needs to be added - cand.component = iceTransport.component === 'RTCP' ? 2 : 1; - event.candidate.candidate = SDPUtils.writeCandidate(cand); - } - - // update local description. - var sections = SDPUtils.splitSections(self.localDescription.sdp); - if (!end) { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=end-of-candidates\r\n'; - } - self.localDescription.sdp = sections.join(''); - var transceivers = self._pendingOffer ? self._pendingOffer : - self.transceivers; - var complete = transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - - // Emit candidate if localDescription is set. - // Also emits null candidate when all gatherers are complete. - switch (self.iceGatheringState) { - case 'new': - if (!end) { - self._localIceCandidatesBuffer.push(event); - } - if (end && complete) { - self._localIceCandidatesBuffer.push( - new Event('icecandidate')); - } - break; - case 'gathering': - self._emitBufferedCandidates(); - if (!end) { - self.dispatchEvent(event); - if (self.onicecandidate !== null) { - self.onicecandidate(event); - } - } - if (complete) { - self.dispatchEvent(new Event('icecandidate')); - if (self.onicecandidate !== null) { - self.onicecandidate(new Event('icecandidate')); - } - self.iceGatheringState = 'complete'; - self._emitGatheringStateChange(); - } - break; - case 'complete': - // should not happen... currently! - break; - default: // no-op. - break; - } - }; - iceTransport.onicestatechange = function() { - self._updateConnectionState(); - }; - - var dtlsTransport = new RTCDtlsTransport(iceTransport); - dtlsTransport.ondtlsstatechange = function() { - self._updateConnectionState(); - }; - dtlsTransport.onerror = function() { - // onerror does not set state to failed by itself. - dtlsTransport.state = 'failed'; - self._updateConnectionState(); - }; - - return { - iceGatherer: iceGatherer, - iceTransport: iceTransport, - dtlsTransport: dtlsTransport - }; - }; - - // Start the RTP Sender and Receiver for a transceiver. - window.RTCPeerConnection.prototype._transceive = function(transceiver, - send, recv) { - var params = this._getCommonCapabilities(transceiver.localCapabilities, - transceiver.remoteCapabilities); - if (send && transceiver.rtpSender) { - params.encodings = transceiver.sendEncodingParameters; - params.rtcp = { - cname: SDPUtils.localCName - }; - if (transceiver.recvEncodingParameters.length) { - params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; - } - transceiver.rtpSender.send(params); - } - if (recv && transceiver.rtpReceiver) { - // remove RTX field in Edge 14942 - if (transceiver.kind === 'video' - && transceiver.recvEncodingParameters - && browserDetails.version < 15019) { - transceiver.recvEncodingParameters.forEach(function(p) { - delete p.rtx; - }); - } - params.encodings = transceiver.recvEncodingParameters; - params.rtcp = { - cname: transceiver.cname - }; - if (transceiver.sendEncodingParameters.length) { - params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; - } - transceiver.rtpReceiver.receive(params); - } + return { + iceTransport: iceTransport, + dtlsTransport: dtlsTransport }; + }; - window.RTCPeerConnection.prototype.setLocalDescription = - function(description) { - var self = this; - var sections; - var sessionpart; - if (description.type === 'offer') { - // FIXME: What was the purpose of this empty if statement? - // if (!this._pendingOffer) { - // } else { - if (this._pendingOffer) { - // VERY limited support for SDP munging. Limited to: - // * changing the order of codecs - sections = SDPUtils.splitSections(description.sdp); - sessionpart = sections.shift(); - sections.forEach(function(mediaSection, sdpMLineIndex) { - var caps = SDPUtils.parseRtpParameters(mediaSection); - self._pendingOffer[sdpMLineIndex].localCapabilities = caps; - }); - this.transceivers = this._pendingOffer; - delete this._pendingOffer; - } - } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(self.remoteDescription.sdp); - sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var transceiver = self.transceivers[sdpMLineIndex]; - var iceGatherer = transceiver.iceGatherer; - var iceTransport = transceiver.iceTransport; - var dtlsTransport = transceiver.dtlsTransport; - var localCapabilities = transceiver.localCapabilities; - var remoteCapabilities = transceiver.remoteCapabilities; + // Destroy ICE gatherer, ICE transport and DTLS transport. + // Without triggering the callbacks. + RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( + sdpMLineIndex) { + var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; + if (iceGatherer) { + delete iceGatherer.onlocalcandidate; + delete this.transceivers[sdpMLineIndex].iceGatherer; + } + var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; + if (iceTransport) { + delete iceTransport.onicestatechange; + delete this.transceivers[sdpMLineIndex].iceTransport; + } + var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; + if (dtlsTransport) { + delete dtlsTransport.ondtlsstatechange; + delete dtlsTransport.onerror; + delete this.transceivers[sdpMLineIndex].dtlsTransport; + } + }; - var rejected = mediaSection.split('\n', 1)[0] - .split(' ', 2)[1] === '0'; - - if (!rejected && !transceiver.isDatachannel) { - var remoteIceParameters = SDPUtils.getIceParameters( - mediaSection, sessionpart); - var remoteDtlsParameters = SDPUtils.getDtlsParameters( - mediaSection, sessionpart); - if (isIceLite) { - remoteDtlsParameters.role = 'server'; - } - - if (!self.usingBundle || sdpMLineIndex === 0) { - iceTransport.start(iceGatherer, remoteIceParameters, - isIceLite ? 'controlling' : 'controlled'); - dtlsTransport.start(remoteDtlsParameters); - } - - // Calculate intersection of capabilities. - var params = self._getCommonCapabilities(localCapabilities, - remoteCapabilities); - - // Start the RTCRtpSender. The RTCRtpReceiver for this - // transceiver has already been started in setRemoteDescription. - self._transceive(transceiver, - params.codecs.length > 0, - false); - } - }); - } - - this.localDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-local-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - - // If a success callback was provided, emit ICE candidates after it - // has been executed. Otherwise, emit callback after the Promise is - // resolved. - var hasCallback = arguments.length > 1 && - typeof arguments[1] === 'function'; - if (hasCallback) { - var cb = arguments[1]; - window.setTimeout(function() { - cb(); - if (self.iceGatheringState === 'new') { - self.iceGatheringState = 'gathering'; - self._emitGatheringStateChange(); - } - self._emitBufferedCandidates(); - }, 0); - } - var p = Promise.resolve(); - p.then(function() { - if (!hasCallback) { - if (self.iceGatheringState === 'new') { - self.iceGatheringState = 'gathering'; - self._emitGatheringStateChange(); - } - // Usually candidates will be emitted earlier. - window.setTimeout(self._emitBufferedCandidates.bind(self), 500); - } - }); - return p; - }; - - window.RTCPeerConnection.prototype.setRemoteDescription = - function(description) { - var self = this; - var stream = new MediaStream(); - var receiverList = []; - var sections = SDPUtils.splitSections(description.sdp); - var sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - this.usingBundle = SDPUtils.matchPrefix(sessionpart, - 'a=group:BUNDLE ').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].substr(2).split(' '); - var kind = mline[0]; - var rejected = mline[1] === '0'; - var direction = SDPUtils.getDirection(mediaSection, sessionpart); - - var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:'); - if (mid.length) { - mid = mid[0].substr(6); - } else { - mid = SDPUtils.generateIdentifier(); - } - - // Reject datachannels which are not implemented yet. - if (kind === 'application' && mline[2] === 'DTLS/SCTP') { - self.transceivers[sdpMLineIndex] = { - mid: mid, - isDatachannel: true - }; - return; - } - - var transceiver; - var iceGatherer; - var iceTransport; - var dtlsTransport; - var rtpSender; - var rtpReceiver; - var sendEncodingParameters; - var recvEncodingParameters; - var localCapabilities; - - var track; - // FIXME: ensure the mediaSection has rtcp-mux set. - var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); - var remoteIceParameters; - var remoteDtlsParameters; - if (!rejected) { - remoteIceParameters = SDPUtils.getIceParameters(mediaSection, - sessionpart); - remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, - sessionpart); - remoteDtlsParameters.role = 'client'; - } - recvEncodingParameters = - SDPUtils.parseRtpEncodingParameters(mediaSection); - - var cname; - // Gets the first SSRC. Note that with RTX there might be multiple - // SSRCs. - var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(obj) { - return obj.attribute === 'cname'; - })[0]; - if (remoteSsrc) { - cname = remoteSsrc.value; - } - - var isComplete = SDPUtils.matchPrefix(mediaSection, - 'a=end-of-candidates', sessionpart).length > 0; - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === '1'; - }); - if (description.type === 'offer' && !rejected) { - var transports = self.usingBundle && sdpMLineIndex > 0 ? { - iceGatherer: self.transceivers[0].iceGatherer, - iceTransport: self.transceivers[0].iceTransport, - dtlsTransport: self.transceivers[0].dtlsTransport - } : self._createIceAndDtlsTransports(mid, sdpMLineIndex); - - if (isComplete && (!self.usingBundle || sdpMLineIndex === 0)) { - transports.iceTransport.setRemoteCandidates(cands); - } - - localCapabilities = RTCRtpReceiver.getCapabilities(kind); - - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (browserDetails.version < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - - sendEncodingParameters = [{ - ssrc: (2 * sdpMLineIndex + 2) * 1001 - }]; - - if (direction === 'sendrecv' || direction === 'sendonly') { - rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, - kind); - - track = rtpReceiver.track; - receiverList.push([track, rtpReceiver]); - // FIXME: not correct when there are multiple streams but that - // is not currently supported in this shim. - stream.addTrack(track); - } - - // FIXME: look at direction. - if (self.localStreams.length > 0 && - self.localStreams[0].getTracks().length >= sdpMLineIndex) { - var localTrack; - if (kind === 'audio') { - localTrack = self.localStreams[0].getAudioTracks()[0]; - } else if (kind === 'video') { - localTrack = self.localStreams[0].getVideoTracks()[0]; - } - if (localTrack) { - // add RTX - if (browserDetails.version >= 15019 && kind === 'video') { - sendEncodingParameters[0].rtx = { - ssrc: (2 * sdpMLineIndex + 2) * 1001 + 1 - }; - } - rtpSender = new RTCRtpSender(localTrack, - transports.dtlsTransport); - } - } - - self.transceivers[sdpMLineIndex] = { - iceGatherer: transports.iceGatherer, - iceTransport: transports.iceTransport, - dtlsTransport: transports.dtlsTransport, - localCapabilities: localCapabilities, - remoteCapabilities: remoteCapabilities, - rtpSender: rtpSender, - rtpReceiver: rtpReceiver, - kind: kind, - mid: mid, - cname: cname, - sendEncodingParameters: sendEncodingParameters, - recvEncodingParameters: recvEncodingParameters - }; - // Start the RTCRtpReceiver now. The RTPSender is started in - // setLocalDescription. - self._transceive(self.transceivers[sdpMLineIndex], - false, - direction === 'sendrecv' || direction === 'sendonly'); - } else if (description.type === 'answer' && !rejected) { - transceiver = self.transceivers[sdpMLineIndex]; - iceGatherer = transceiver.iceGatherer; - iceTransport = transceiver.iceTransport; - dtlsTransport = transceiver.dtlsTransport; - rtpSender = transceiver.rtpSender; - rtpReceiver = transceiver.rtpReceiver; - sendEncodingParameters = transceiver.sendEncodingParameters; - localCapabilities = transceiver.localCapabilities; - - self.transceivers[sdpMLineIndex].recvEncodingParameters = - recvEncodingParameters; - self.transceivers[sdpMLineIndex].remoteCapabilities = - remoteCapabilities; - self.transceivers[sdpMLineIndex].cname = cname; - - if ((isIceLite || isComplete) && cands.length) { - iceTransport.setRemoteCandidates(cands); - } - if (!self.usingBundle || sdpMLineIndex === 0) { - iceTransport.start(iceGatherer, remoteIceParameters, - 'controlling'); - dtlsTransport.start(remoteDtlsParameters); - } - - self._transceive(transceiver, - direction === 'sendrecv' || direction === 'recvonly', - direction === 'sendrecv' || direction === 'sendonly'); - - if (rtpReceiver && - (direction === 'sendrecv' || direction === 'sendonly')) { - track = rtpReceiver.track; - receiverList.push([track, rtpReceiver]); - stream.addTrack(track); - } else { - // FIXME: actually the receiver should be created later. - delete transceiver.rtpReceiver; - } - } - }); - - this.remoteDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-remote-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - if (stream.getTracks().length) { - self.remoteStreams.push(stream); - window.setTimeout(function() { - var event = new Event('addstream'); - event.stream = stream; - self.dispatchEvent(event); - if (self.onaddstream !== null) { - window.setTimeout(function() { - self.onaddstream(event); - }, 0); - } - - receiverList.forEach(function(item) { - var track = item[0]; - var receiver = item[1]; - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.streams = [stream]; - self.dispatchEvent(trackEvent); - if (self.ontrack !== null) { - window.setTimeout(function() { - self.ontrack(trackEvent); - }, 0); - } - }); - }, 0); - } - if (arguments.length > 1 && typeof arguments[1] === 'function') { - window.setTimeout(arguments[1], 0); - } - return Promise.resolve(); - }; - - window.RTCPeerConnection.prototype.close = function() { - this.transceivers.forEach(function(transceiver) { - /* not yet - if (transceiver.iceGatherer) { - transceiver.iceGatherer.close(); - } - */ - if (transceiver.iceTransport) { - transceiver.iceTransport.stop(); - } - if (transceiver.dtlsTransport) { - transceiver.dtlsTransport.stop(); - } - if (transceiver.rtpSender) { - transceiver.rtpSender.stop(); - } - if (transceiver.rtpReceiver) { - transceiver.rtpReceiver.stop(); - } - }); - // FIXME: clean up tracks, local streams, remote streams, etc - this._updateSignalingState('closed'); - }; - - // Update the signaling state. - window.RTCPeerConnection.prototype._updateSignalingState = - function(newState) { - this.signalingState = newState; - var event = new Event('signalingstatechange'); - this.dispatchEvent(event); - if (this.onsignalingstatechange !== null) { - this.onsignalingstatechange(event); - } - }; - - // Determine whether to fire the negotiationneeded event. - window.RTCPeerConnection.prototype._maybeFireNegotiationNeeded = - function() { - // Fire away (for now). - var event = new Event('negotiationneeded'); - this.dispatchEvent(event); - if (this.onnegotiationneeded !== null) { - this.onnegotiationneeded(event); - } - }; - - // Update the connection state. - window.RTCPeerConnection.prototype._updateConnectionState = function() { - var self = this; - var newState; - var states = { - 'new': 0, - closed: 0, - connecting: 0, - checking: 0, - connected: 0, - completed: 0, - failed: 0 + // Start the RTP Sender and Receiver for a transceiver. + RTCPeerConnection.prototype._transceive = function(transceiver, + send, recv) { + var params = getCommonCapabilities(transceiver.localCapabilities, + transceiver.remoteCapabilities); + if (send && transceiver.rtpSender) { + params.encodings = transceiver.sendEncodingParameters; + params.rtcp = { + cname: SDPUtils.localCName, + compound: transceiver.rtcpParameters.compound }; - this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; - }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.connecting > 0 || states.checking > 0) { - newState = 'connecting'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0 || states.completed > 0) { - newState = 'connected'; + if (transceiver.recvEncodingParameters.length) { + params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; } - - if (newState !== self.iceConnectionState) { - self.iceConnectionState = newState; - var event = new Event('iceconnectionstatechange'); - this.dispatchEvent(event); - if (this.oniceconnectionstatechange !== null) { - this.oniceconnectionstatechange(event); - } - } - }; - - window.RTCPeerConnection.prototype.createOffer = function() { - var self = this; - if (this._pendingOffer) { - throw new Error('createOffer called while there is a pending offer.'); - } - var offerOptions; - if (arguments.length === 1 && typeof arguments[0] !== 'function') { - offerOptions = arguments[0]; - } else if (arguments.length === 3) { - offerOptions = arguments[2]; - } - - var tracks = []; - var numAudioTracks = 0; - var numVideoTracks = 0; - // Default to sendrecv. - if (this.localStreams.length) { - numAudioTracks = this.localStreams[0].getAudioTracks().length; - numVideoTracks = this.localStreams[0].getVideoTracks().length; - } - // Determine number of audio and video tracks we need to send/recv. - if (offerOptions) { - // Reject Chrome legacy constraints. - if (offerOptions.mandatory || offerOptions.optional) { - throw new TypeError( - 'Legacy mandatory/optional constraints not supported.'); - } - if (offerOptions.offerToReceiveAudio !== undefined) { - numAudioTracks = offerOptions.offerToReceiveAudio; - } - if (offerOptions.offerToReceiveVideo !== undefined) { - numVideoTracks = offerOptions.offerToReceiveVideo; - } - } - if (this.localStreams.length) { - // Push local streams. - this.localStreams[0].getTracks().forEach(function(track) { - tracks.push({ - kind: track.kind, - track: track, - wantReceive: track.kind === 'audio' ? - numAudioTracks > 0 : numVideoTracks > 0 - }); - if (track.kind === 'audio') { - numAudioTracks--; - } else if (track.kind === 'video') { - numVideoTracks--; - } + transceiver.rtpSender.send(params); + } + if (recv && transceiver.rtpReceiver) { + // remove RTX field in Edge 14942 + if (transceiver.kind === 'video' + && transceiver.recvEncodingParameters + && edgeVersion < 15019) { + transceiver.recvEncodingParameters.forEach(function(p) { + delete p.rtx; }); } - // Create M-lines for recvonly streams. - while (numAudioTracks > 0 || numVideoTracks > 0) { - if (numAudioTracks > 0) { - tracks.push({ - kind: 'audio', - wantReceive: true - }); - numAudioTracks--; + params.encodings = transceiver.recvEncodingParameters; + params.rtcp = { + cname: transceiver.rtcpParameters.cname, + compound: transceiver.rtcpParameters.compound + }; + if (transceiver.sendEncodingParameters.length) { + params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; + } + transceiver.rtpReceiver.receive(params); + } + }; + + RTCPeerConnection.prototype.setLocalDescription = function(description) { + var self = this; + + if (!isActionAllowedInSignalingState('setLocalDescription', + description.type, this.signalingState)) { + var e = new Error('Can not set local ' + description.type + + ' in state ' + this.signalingState); + e.name = 'InvalidStateError'; + if (arguments.length > 2 && typeof arguments[2] === 'function') { + window.setTimeout(arguments[2], 0, e); + } + return Promise.reject(e); + } + + var sections; + var sessionpart; + if (description.type === 'offer') { + // FIXME: What was the purpose of this empty if statement? + // if (!this._pendingOffer) { + // } else { + if (this._pendingOffer) { + // VERY limited support for SDP munging. Limited to: + // * changing the order of codecs + sections = SDPUtils.splitSections(description.sdp); + sessionpart = sections.shift(); + sections.forEach(function(mediaSection, sdpMLineIndex) { + var caps = SDPUtils.parseRtpParameters(mediaSection); + self._pendingOffer[sdpMLineIndex].localCapabilities = caps; + }); + this.transceivers = this._pendingOffer; + delete this._pendingOffer; + } + } else if (description.type === 'answer') { + sections = SDPUtils.splitSections(self.remoteDescription.sdp); + sessionpart = sections.shift(); + var isIceLite = SDPUtils.matchPrefix(sessionpart, + 'a=ice-lite').length > 0; + sections.forEach(function(mediaSection, sdpMLineIndex) { + var transceiver = self.transceivers[sdpMLineIndex]; + var iceGatherer = transceiver.iceGatherer; + var iceTransport = transceiver.iceTransport; + var dtlsTransport = transceiver.dtlsTransport; + var localCapabilities = transceiver.localCapabilities; + var remoteCapabilities = transceiver.remoteCapabilities; + + var rejected = SDPUtils.isRejected(mediaSection); + + if (!rejected && !transceiver.isDatachannel) { + var remoteIceParameters = SDPUtils.getIceParameters( + mediaSection, sessionpart); + var remoteDtlsParameters = SDPUtils.getDtlsParameters( + mediaSection, sessionpart); + if (isIceLite) { + remoteDtlsParameters.role = 'server'; + } + + if (!self.usingBundle || sdpMLineIndex === 0) { + iceTransport.start(iceGatherer, remoteIceParameters, + isIceLite ? 'controlling' : 'controlled'); + dtlsTransport.start(remoteDtlsParameters); + } + + // Calculate intersection of capabilities. + var params = getCommonCapabilities(localCapabilities, + remoteCapabilities); + + // Start the RTCRtpSender. The RTCRtpReceiver for this + // transceiver has already been started in setRemoteDescription. + self._transceive(transceiver, + params.codecs.length > 0, + false); } - if (numVideoTracks > 0) { - tracks.push({ - kind: 'video', - wantReceive: true + }); + } + + this.localDescription = { + type: description.type, + sdp: description.sdp + }; + switch (description.type) { + case 'offer': + this._updateSignalingState('have-local-offer'); + break; + case 'answer': + this._updateSignalingState('stable'); + break; + default: + throw new TypeError('unsupported type "' + description.type + + '"'); + } + + // If a success callback was provided, emit ICE candidates after it + // has been executed. Otherwise, emit callback after the Promise is + // resolved. + var hasCallback = arguments.length > 1 && + typeof arguments[1] === 'function'; + if (hasCallback) { + var cb = arguments[1]; + window.setTimeout(function() { + cb(); + if (self.iceGatheringState === 'new') { + self.iceGatheringState = 'gathering'; + self._emitGatheringStateChange(); + } + self._emitBufferedCandidates(); + }, 0); + } + var p = Promise.resolve(); + p.then(function() { + if (!hasCallback) { + if (self.iceGatheringState === 'new') { + self.iceGatheringState = 'gathering'; + self._emitGatheringStateChange(); + } + // Usually candidates will be emitted earlier. + window.setTimeout(self._emitBufferedCandidates.bind(self), 500); + } + }); + return p; + }; + + RTCPeerConnection.prototype.setRemoteDescription = function(description) { + var self = this; + + if (!isActionAllowedInSignalingState('setRemoteDescription', + description.type, this.signalingState)) { + var e = new Error('Can not set remote ' + description.type + + ' in state ' + this.signalingState); + e.name = 'InvalidStateError'; + if (arguments.length > 2 && typeof arguments[2] === 'function') { + window.setTimeout(arguments[2], 0, e); + } + return Promise.reject(e); + } + + var streams = {}; + var receiverList = []; + var sections = SDPUtils.splitSections(description.sdp); + var sessionpart = sections.shift(); + var isIceLite = SDPUtils.matchPrefix(sessionpart, + 'a=ice-lite').length > 0; + var usingBundle = SDPUtils.matchPrefix(sessionpart, + 'a=group:BUNDLE ').length > 0; + this.usingBundle = usingBundle; + var iceOptions = SDPUtils.matchPrefix(sessionpart, + 'a=ice-options:')[0]; + if (iceOptions) { + this.canTrickleIceCandidates = iceOptions.substr(14).split(' ') + .indexOf('trickle') >= 0; + } else { + this.canTrickleIceCandidates = false; + } + + sections.forEach(function(mediaSection, sdpMLineIndex) { + var lines = SDPUtils.splitLines(mediaSection); + var kind = SDPUtils.getKind(mediaSection); + var rejected = SDPUtils.isRejected(mediaSection); + var protocol = lines[0].substr(2).split(' ')[2]; + + var direction = SDPUtils.getDirection(mediaSection, sessionpart); + var remoteMsid = SDPUtils.parseMsid(mediaSection); + + var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); + + // Reject datachannels which are not implemented yet. + if (kind === 'application' && protocol === 'DTLS/SCTP') { + self.transceivers[sdpMLineIndex] = { + mid: mid, + isDatachannel: true + }; + return; + } + + var transceiver; + var iceGatherer; + var iceTransport; + var dtlsTransport; + var rtpReceiver; + var sendEncodingParameters; + var recvEncodingParameters; + var localCapabilities; + + var track; + // FIXME: ensure the mediaSection has rtcp-mux set. + var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); + var remoteIceParameters; + var remoteDtlsParameters; + if (!rejected) { + remoteIceParameters = SDPUtils.getIceParameters(mediaSection, + sessionpart); + remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, + sessionpart); + remoteDtlsParameters.role = 'client'; + } + recvEncodingParameters = + SDPUtils.parseRtpEncodingParameters(mediaSection); + + var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); + + var isComplete = SDPUtils.matchPrefix(mediaSection, + 'a=end-of-candidates', sessionpart).length > 0; + var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') + .map(function(cand) { + return SDPUtils.parseCandidate(cand); + }) + .filter(function(cand) { + return cand.component === '1' || cand.component === 1; }); - numVideoTracks--; + + // Check if we can use BUNDLE and dispose transports. + if ((description.type === 'offer' || description.type === 'answer') && + !rejected && usingBundle && sdpMLineIndex > 0 && + self.transceivers[sdpMLineIndex]) { + self._disposeIceAndDtlsTransports(sdpMLineIndex); + self.transceivers[sdpMLineIndex].iceGatherer = + self.transceivers[0].iceGatherer; + self.transceivers[sdpMLineIndex].iceTransport = + self.transceivers[0].iceTransport; + self.transceivers[sdpMLineIndex].dtlsTransport = + self.transceivers[0].dtlsTransport; + if (self.transceivers[sdpMLineIndex].rtpSender) { + self.transceivers[sdpMLineIndex].rtpSender.setTransport( + self.transceivers[0].dtlsTransport); + } + if (self.transceivers[sdpMLineIndex].rtpReceiver) { + self.transceivers[sdpMLineIndex].rtpReceiver.setTransport( + self.transceivers[0].dtlsTransport); } } - // reorder tracks - tracks = sortTracks(tracks); + if (description.type === 'offer' && !rejected) { + transceiver = self.transceivers[sdpMLineIndex] || + self._createTransceiver(kind); + transceiver.mid = mid; - var sdp = SDPUtils.writeSessionBoilerplate(); - var transceivers = []; - tracks.forEach(function(mline, sdpMLineIndex) { - // For each track, create an ice gatherer, ice transport, - // dtls transport, potentially rtpsender and rtpreceiver. - var track = mline.track; - var kind = mline.kind; - var mid = SDPUtils.generateIdentifier(); + if (!transceiver.iceGatherer) { + transceiver.iceGatherer = usingBundle && sdpMLineIndex > 0 ? + self.transceivers[0].iceGatherer : + self._createIceGatherer(mid, sdpMLineIndex); + } - var transports = self.usingBundle && sdpMLineIndex > 0 ? { - iceGatherer: transceivers[0].iceGatherer, - iceTransport: transceivers[0].iceTransport, - dtlsTransport: transceivers[0].dtlsTransport - } : self._createIceAndDtlsTransports(mid, sdpMLineIndex); + if (isComplete && cands.length && + (!usingBundle || sdpMLineIndex === 0)) { + transceiver.iceTransport.setRemoteCandidates(cands); + } - var localCapabilities = RTCRtpSender.getCapabilities(kind); + localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); + // filter RTX until additional stuff needed for RTX is implemented // in adapter.js - if (browserDetails.version < 15019) { + if (edgeVersion < 15019) { localCapabilities.codecs = localCapabilities.codecs.filter( function(codec) { return codec.name !== 'rtx'; }); } - localCapabilities.codecs.forEach(function(codec) { - // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 - // by adding level-asymmetry-allowed=1 - if (codec.name === 'H264' && - codec.parameters['level-asymmetry-allowed'] === undefined) { - codec.parameters['level-asymmetry-allowed'] = '1'; - } - }); - var rtpSender; - var rtpReceiver; - - // generate an ssrc now, to be used later in rtpSender.send - var sendEncodingParameters = [{ - ssrc: (2 * sdpMLineIndex + 1) * 1001 + sendEncodingParameters = [{ + ssrc: (2 * sdpMLineIndex + 2) * 1001 }]; - if (track) { - // add RTX - if (browserDetails.version >= 15019 && kind === 'video') { - sendEncodingParameters[0].rtx = { - ssrc: (2 * sdpMLineIndex + 1) * 1001 + 1 - }; - } - rtpSender = new RTCRtpSender(track, transports.dtlsTransport); - } - if (mline.wantReceive) { - rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind); - } + if (direction === 'sendrecv' || direction === 'sendonly') { + rtpReceiver = new window.RTCRtpReceiver(transceiver.dtlsTransport, + kind); - transceivers[sdpMLineIndex] = { - iceGatherer: transports.iceGatherer, - iceTransport: transports.iceTransport, - dtlsTransport: transports.dtlsTransport, - localCapabilities: localCapabilities, - remoteCapabilities: null, - rtpSender: rtpSender, - rtpReceiver: rtpReceiver, - kind: kind, - mid: mid, - sendEncodingParameters: sendEncodingParameters, - recvEncodingParameters: null - }; - }); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - tracks.forEach(function(mline, sdpMLineIndex) { - var transceiver = transceivers[sdpMLineIndex]; - sdp += SDPUtils.writeMediaSection(transceiver, - transceiver.localCapabilities, 'offer', self.localStreams[0]); - }); - - this._pendingOffer = transceivers; - var desc = new RTCSessionDescription({ - type: 'offer', - sdp: sdp - }); - if (arguments.length && typeof arguments[0] === 'function') { - window.setTimeout(arguments[0], 0, desc); - } - return Promise.resolve(desc); - }; - - window.RTCPeerConnection.prototype.createAnswer = function() { - var self = this; - - var sdp = SDPUtils.writeSessionBoilerplate(); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - this.transceivers.forEach(function(transceiver) { - if (transceiver.isDatachannel) { - sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + - 'c=IN IP4 0.0.0.0\r\n' + - 'a=mid:' + transceiver.mid + '\r\n'; - return; - } - // Calculate intersection of capabilities. - var commonCapabilities = self._getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities, - 'answer', self.localStreams[0]); - }); - - var desc = new RTCSessionDescription({ - type: 'answer', - sdp: sdp - }); - if (arguments.length && typeof arguments[0] === 'function') { - window.setTimeout(arguments[0], 0, desc); - } - return Promise.resolve(desc); - }; - - window.RTCPeerConnection.prototype.addIceCandidate = function(candidate) { - if (!candidate) { - for (var j = 0; j < this.transceivers.length; j++) { - this.transceivers[j].iceTransport.addRemoteCandidate({}); - if (this.usingBundle) { - return Promise.resolve(); - } - } - } else { - var mLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < this.transceivers.length; i++) { - if (this.transceivers[i].mid === candidate.sdpMid) { - mLineIndex = i; - break; + track = rtpReceiver.track; + // FIXME: does not work with Plan B. + if (remoteMsid) { + if (!streams[remoteMsid.stream]) { + streams[remoteMsid.stream] = new window.MediaStream(); + Object.defineProperty(streams[remoteMsid.stream], 'id', { + get: function() { + return remoteMsid.stream; + } + }); } - } - } - var transceiver = this.transceivers[mLineIndex]; - if (transceiver) { - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return Promise.resolve(); - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component !== '1') { - return Promise.resolve(); - } - transceiver.iceTransport.addRemoteCandidate(cand); - - // update the remoteDescription. - var sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[mLineIndex + 1] += (cand.type ? candidate.candidate.trim() - : 'a=end-of-candidates') + '\r\n'; - this.remoteDescription.sdp = sections.join(''); - } - } - if (arguments.length > 1 && typeof arguments[1] === 'function') { - window.setTimeout(arguments[1], 0); - } - return Promise.resolve(); - }; - - window.RTCPeerConnection.prototype.getStats = function() { - var promises = []; - this.transceivers.forEach(function(transceiver) { - ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', - 'dtlsTransport'].forEach(function(method) { - if (transceiver[method]) { - promises.push(transceiver[method].getStats()); + Object.defineProperty(track, 'id', { + get: function() { + return remoteMsid.track; } }); - }); - var cb = arguments.length > 1 && typeof arguments[1] === 'function' && - arguments[1]; - var fixStatsType = function(stat) { - return { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[stat.type] || stat.type; - }; - return new Promise(function(resolve) { - // shim getStats with maplike support - var results = new Map(); - Promise.all(promises).then(function(res) { - res.forEach(function(result) { - Object.keys(result).forEach(function(id) { - result[id].type = fixStatsType(result[id]); - results.set(id, result[id]); - }); - }); - if (cb) { - window.setTimeout(cb, 0, results); + streams[remoteMsid.stream].addTrack(track); + receiverList.push([track, rtpReceiver, + streams[remoteMsid.stream]]); + } else { + if (!streams.default) { + streams.default = new window.MediaStream(); + } + streams.default.addTrack(track); + receiverList.push([track, rtpReceiver, streams.default]); } - resolve(results); - }); - }); - }; - } -}; + } -// Expose public methods. -module.exports = { - shimPeerConnection: edgeShim.shimPeerConnection, - shimGetUserMedia: require('./getusermedia') -}; + transceiver.localCapabilities = localCapabilities; + transceiver.remoteCapabilities = remoteCapabilities; + transceiver.rtpReceiver = rtpReceiver; + transceiver.rtcpParameters = rtcpParameters; + transceiver.sendEncodingParameters = sendEncodingParameters; + transceiver.recvEncodingParameters = recvEncodingParameters; -},{"../utils":10,"./getusermedia":6,"sdp":1}],6:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; + // Start the RTCRtpReceiver now. The RTPSender is started in + // setLocalDescription. + self._transceive(self.transceivers[sdpMLineIndex], + false, + direction === 'sendrecv' || direction === 'sendonly'); + } else if (description.type === 'answer' && !rejected) { + transceiver = self.transceivers[sdpMLineIndex]; + iceGatherer = transceiver.iceGatherer; + iceTransport = transceiver.iceTransport; + dtlsTransport = transceiver.dtlsTransport; + rtpReceiver = transceiver.rtpReceiver; + sendEncodingParameters = transceiver.sendEncodingParameters; + localCapabilities = transceiver.localCapabilities; -// Expose public methods. -module.exports = function() { - var shimError_ = function(e) { - return { - name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name, - message: e.message, - constraint: e.constraint, - toString: function() { - return this.name; + self.transceivers[sdpMLineIndex].recvEncodingParameters = + recvEncodingParameters; + self.transceivers[sdpMLineIndex].remoteCapabilities = + remoteCapabilities; + self.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; + + if (!usingBundle || sdpMLineIndex === 0) { + if ((isIceLite || isComplete) && cands.length) { + iceTransport.setRemoteCandidates(cands); + } + iceTransport.start(iceGatherer, remoteIceParameters, + 'controlling'); + dtlsTransport.start(remoteDtlsParameters); + } + + self._transceive(transceiver, + direction === 'sendrecv' || direction === 'recvonly', + direction === 'sendrecv' || direction === 'sendonly'); + + if (rtpReceiver && + (direction === 'sendrecv' || direction === 'sendonly')) { + track = rtpReceiver.track; + if (remoteMsid) { + if (!streams[remoteMsid.stream]) { + streams[remoteMsid.stream] = new window.MediaStream(); + } + streams[remoteMsid.stream].addTrack(track); + receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); + } else { + if (!streams.default) { + streams.default = new window.MediaStream(); + } + streams.default.addTrack(track); + receiverList.push([track, rtpReceiver, streams.default]); + } + } else { + // FIXME: actually the receiver should be created later. + delete transceiver.rtpReceiver; + } } + }); + + this.remoteDescription = { + type: description.type, + sdp: description.sdp }; + switch (description.type) { + case 'offer': + this._updateSignalingState('have-remote-offer'); + break; + case 'answer': + this._updateSignalingState('stable'); + break; + default: + throw new TypeError('unsupported type "' + description.type + + '"'); + } + Object.keys(streams).forEach(function(sid) { + var stream = streams[sid]; + if (stream.getTracks().length) { + self.remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + self.dispatchEvent(event); + if (self.onaddstream !== null) { + window.setTimeout(function() { + self.onaddstream(event); + }, 0); + } + + receiverList.forEach(function(item) { + var track = item[0]; + var receiver = item[1]; + if (stream.id !== item[2].id) { + return; + } + var trackEvent = new Event('track'); + trackEvent.track = track; + trackEvent.receiver = receiver; + trackEvent.streams = [stream]; + self.dispatchEvent(trackEvent); + if (self.ontrack !== null) { + window.setTimeout(function() { + self.ontrack(trackEvent); + }, 0); + } + }); + } + }); + + // check whether addIceCandidate({}) was called within four seconds after + // setRemoteDescription. + window.setTimeout(function() { + if (!(self && self.transceivers)) { + return; + } + self.transceivers.forEach(function(transceiver) { + if (transceiver.iceTransport && + transceiver.iceTransport.state === 'new' && + transceiver.iceTransport.getRemoteCandidates().length > 0) { + console.warn('Timeout for addRemoteCandidate. Consider sending ' + + 'an end-of-candidates notification'); + transceiver.iceTransport.addRemoteCandidate({}); + } + }); + }, 4000); + + if (arguments.length > 1 && typeof arguments[1] === 'function') { + window.setTimeout(arguments[1], 0); + } + return Promise.resolve(); }; - // getUserMedia error shim. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).catch(function(e) { - return Promise.reject(shimError_(e)); + RTCPeerConnection.prototype.close = function() { + this.transceivers.forEach(function(transceiver) { + /* not yet + if (transceiver.iceGatherer) { + transceiver.iceGatherer.close(); + } + */ + if (transceiver.iceTransport) { + transceiver.iceTransport.stop(); + } + if (transceiver.dtlsTransport) { + transceiver.dtlsTransport.stop(); + } + if (transceiver.rtpSender) { + transceiver.rtpSender.stop(); + } + if (transceiver.rtpReceiver) { + transceiver.rtpReceiver.stop(); + } + }); + // FIXME: clean up tracks, local streams, remote streams, etc + this._updateSignalingState('closed'); + }; + + // Update the signaling state. + RTCPeerConnection.prototype._updateSignalingState = function(newState) { + this.signalingState = newState; + var event = new Event('signalingstatechange'); + this.dispatchEvent(event); + if (this.onsignalingstatechange !== null) { + this.onsignalingstatechange(event); + } + }; + + // Determine whether to fire the negotiationneeded event. + RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { + var self = this; + if (this.signalingState !== 'stable' || this.needNegotiation === true) { + return; + } + this.needNegotiation = true; + window.setTimeout(function() { + if (self.needNegotiation === false) { + return; + } + self.needNegotiation = false; + var event = new Event('negotiationneeded'); + self.dispatchEvent(event); + if (self.onnegotiationneeded !== null) { + self.onnegotiationneeded(event); + } + }, 0); + }; + + // Update the connection state. + RTCPeerConnection.prototype._updateConnectionState = function() { + var self = this; + var newState; + var states = { + 'new': 0, + closed: 0, + connecting: 0, + checking: 0, + connected: 0, + completed: 0, + disconnected: 0, + failed: 0 + }; + this.transceivers.forEach(function(transceiver) { + states[transceiver.iceTransport.state]++; + states[transceiver.dtlsTransport.state]++; + }); + // ICETransport.completed and connected are the same for this purpose. + states.connected += states.completed; + + newState = 'new'; + if (states.failed > 0) { + newState = 'failed'; + } else if (states.connecting > 0 || states.checking > 0) { + newState = 'connecting'; + } else if (states.disconnected > 0) { + newState = 'disconnected'; + } else if (states.new > 0) { + newState = 'new'; + } else if (states.connected > 0 || states.completed > 0) { + newState = 'connected'; + } + + if (newState !== self.iceConnectionState) { + self.iceConnectionState = newState; + var event = new Event('iceconnectionstatechange'); + this.dispatchEvent(event); + if (this.oniceconnectionstatechange !== null) { + this.oniceconnectionstatechange(event); + } + } + }; + + RTCPeerConnection.prototype.createOffer = function() { + var self = this; + if (this._pendingOffer) { + throw new Error('createOffer called while there is a pending offer.'); + } + var offerOptions; + if (arguments.length === 1 && typeof arguments[0] !== 'function') { + offerOptions = arguments[0]; + } else if (arguments.length === 3) { + offerOptions = arguments[2]; + } + + var numAudioTracks = this.transceivers.filter(function(t) { + return t.kind === 'audio'; + }).length; + var numVideoTracks = this.transceivers.filter(function(t) { + return t.kind === 'video'; + }).length; + + // Determine number of audio and video tracks we need to send/recv. + if (offerOptions) { + // Reject Chrome legacy constraints. + if (offerOptions.mandatory || offerOptions.optional) { + throw new TypeError( + 'Legacy mandatory/optional constraints not supported.'); + } + if (offerOptions.offerToReceiveAudio !== undefined) { + if (offerOptions.offerToReceiveAudio === true) { + numAudioTracks = 1; + } else if (offerOptions.offerToReceiveAudio === false) { + numAudioTracks = 0; + } else { + numAudioTracks = offerOptions.offerToReceiveAudio; + } + } + if (offerOptions.offerToReceiveVideo !== undefined) { + if (offerOptions.offerToReceiveVideo === true) { + numVideoTracks = 1; + } else if (offerOptions.offerToReceiveVideo === false) { + numVideoTracks = 0; + } else { + numVideoTracks = offerOptions.offerToReceiveVideo; + } + } + } + + this.transceivers.forEach(function(transceiver) { + if (transceiver.kind === 'audio') { + numAudioTracks--; + if (numAudioTracks < 0) { + transceiver.wantReceive = false; + } + } else if (transceiver.kind === 'video') { + numVideoTracks--; + if (numVideoTracks < 0) { + transceiver.wantReceive = false; + } + } + }); + + // Create M-lines for recvonly streams. + while (numAudioTracks > 0 || numVideoTracks > 0) { + if (numAudioTracks > 0) { + this._createTransceiver('audio'); + numAudioTracks--; + } + if (numVideoTracks > 0) { + this._createTransceiver('video'); + numVideoTracks--; + } + } + // reorder tracks + var transceivers = sortTracks(this.transceivers); + + var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId); + transceivers.forEach(function(transceiver, sdpMLineIndex) { + // For each track, create an ice gatherer, ice transport, + // dtls transport, potentially rtpsender and rtpreceiver. + var track = transceiver.track; + var kind = transceiver.kind; + var mid = SDPUtils.generateIdentifier(); + transceiver.mid = mid; + + if (!transceiver.iceGatherer) { + transceiver.iceGatherer = self.usingBundle && sdpMLineIndex > 0 ? + transceivers[0].iceGatherer : + self._createIceGatherer(mid, sdpMLineIndex); + } + + var localCapabilities = window.RTCRtpSender.getCapabilities(kind); + // filter RTX until additional stuff needed for RTX is implemented + // in adapter.js + if (edgeVersion < 15019) { + localCapabilities.codecs = localCapabilities.codecs.filter( + function(codec) { + return codec.name !== 'rtx'; + }); + } + localCapabilities.codecs.forEach(function(codec) { + // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 + // by adding level-asymmetry-allowed=1 + if (codec.name === 'H264' && + codec.parameters['level-asymmetry-allowed'] === undefined) { + codec.parameters['level-asymmetry-allowed'] = '1'; + } + }); + + // generate an ssrc now, to be used later in rtpSender.send + var sendEncodingParameters = [{ + ssrc: (2 * sdpMLineIndex + 1) * 1001 + }]; + if (track) { + // add RTX + if (edgeVersion >= 15019 && kind === 'video') { + sendEncodingParameters[0].rtx = { + ssrc: (2 * sdpMLineIndex + 1) * 1001 + 1 + }; + } + } + + if (transceiver.wantReceive) { + transceiver.rtpReceiver = new window.RTCRtpReceiver( + transceiver.dtlsTransport, + kind + ); + } + + transceiver.localCapabilities = localCapabilities; + transceiver.sendEncodingParameters = sendEncodingParameters; + }); + + // always offer BUNDLE and dispose on return if not supported. + if (this._config.bundlePolicy !== 'max-compat') { + sdp += 'a=group:BUNDLE ' + transceivers.map(function(t) { + return t.mid; + }).join(' ') + '\r\n'; + } + sdp += 'a=ice-options:trickle\r\n'; + + transceivers.forEach(function(transceiver, sdpMLineIndex) { + sdp += SDPUtils.writeMediaSection(transceiver, + transceiver.localCapabilities, 'offer', transceiver.stream); + sdp += 'a=rtcp-rsize\r\n'; + }); + + this._pendingOffer = transceivers; + var desc = new window.RTCSessionDescription({ + type: 'offer', + sdp: sdp + }); + if (arguments.length && typeof arguments[0] === 'function') { + window.setTimeout(arguments[0], 0, desc); + } + return Promise.resolve(desc); + }; + + RTCPeerConnection.prototype.createAnswer = function() { + var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId); + if (this.usingBundle) { + sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { + return t.mid; + }).join(' ') + '\r\n'; + } + this.transceivers.forEach(function(transceiver, sdpMLineIndex) { + if (transceiver.isDatachannel) { + sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + + 'c=IN IP4 0.0.0.0\r\n' + + 'a=mid:' + transceiver.mid + '\r\n'; + return; + } + + // FIXME: look at direction. + if (transceiver.stream) { + var localTrack; + if (transceiver.kind === 'audio') { + localTrack = transceiver.stream.getAudioTracks()[0]; + } else if (transceiver.kind === 'video') { + localTrack = transceiver.stream.getVideoTracks()[0]; + } + if (localTrack) { + // add RTX + if (edgeVersion >= 15019 && transceiver.kind === 'video') { + transceiver.sendEncodingParameters[0].rtx = { + ssrc: (2 * sdpMLineIndex + 2) * 1001 + 1 + }; + } + } + } + + // Calculate intersection of capabilities. + var commonCapabilities = getCommonCapabilities( + transceiver.localCapabilities, + transceiver.remoteCapabilities); + + var hasRtx = commonCapabilities.codecs.filter(function(c) { + return c.name.toLowerCase() === 'rtx'; + }).length; + if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { + delete transceiver.sendEncodingParameters[0].rtx; + } + + sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities, + 'answer', transceiver.stream); + if (transceiver.rtcpParameters && + transceiver.rtcpParameters.reducedSize) { + sdp += 'a=rtcp-rsize\r\n'; + } + }); + + var desc = new window.RTCSessionDescription({ + type: 'answer', + sdp: sdp + }); + if (arguments.length && typeof arguments[0] === 'function') { + window.setTimeout(arguments[0], 0, desc); + } + return Promise.resolve(desc); + }; + + RTCPeerConnection.prototype.addIceCandidate = function(candidate) { + if (!candidate) { + for (var j = 0; j < this.transceivers.length; j++) { + this.transceivers[j].iceTransport.addRemoteCandidate({}); + if (this.usingBundle) { + return Promise.resolve(); + } + } + } else { + var mLineIndex = candidate.sdpMLineIndex; + if (candidate.sdpMid) { + for (var i = 0; i < this.transceivers.length; i++) { + if (this.transceivers[i].mid === candidate.sdpMid) { + mLineIndex = i; + break; + } + } + } + var transceiver = this.transceivers[mLineIndex]; + if (transceiver) { + var cand = Object.keys(candidate.candidate).length > 0 ? + SDPUtils.parseCandidate(candidate.candidate) : {}; + // Ignore Chrome's invalid candidates since Edge does not like them. + if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { + return Promise.resolve(); + } + // Ignore RTCP candidates, we assume RTCP-MUX. + if (cand.component && + !(cand.component === '1' || cand.component === 1)) { + return Promise.resolve(); + } + transceiver.iceTransport.addRemoteCandidate(cand); + + // update the remoteDescription. + var sections = SDPUtils.splitSections(this.remoteDescription.sdp); + sections[mLineIndex + 1] += (cand.type ? candidate.candidate.trim() + : 'a=end-of-candidates') + '\r\n'; + this.remoteDescription.sdp = sections.join(''); + } + } + if (arguments.length > 1 && typeof arguments[1] === 'function') { + window.setTimeout(arguments[1], 0); + } + return Promise.resolve(); + }; + + RTCPeerConnection.prototype.getStats = function() { + var promises = []; + this.transceivers.forEach(function(transceiver) { + ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', + 'dtlsTransport'].forEach(function(method) { + if (transceiver[method]) { + promises.push(transceiver[method].getStats()); + } + }); + }); + var cb = arguments.length > 1 && typeof arguments[1] === 'function' && + arguments[1]; + var fixStatsType = function(stat) { + return { + inboundrtp: 'inbound-rtp', + outboundrtp: 'outbound-rtp', + candidatepair: 'candidate-pair', + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }[stat.type] || stat.type; + }; + return new Promise(function(resolve) { + // shim getStats with maplike support + var results = new Map(); + Promise.all(promises).then(function(res) { + res.forEach(function(result) { + Object.keys(result).forEach(function(id) { + result[id].type = fixStatsType(result[id]); + results.set(id, result[id]); + }); + }); + if (cb) { + window.setTimeout(cb, 0, results); + } + resolve(results); + }); }); }; + return RTCPeerConnection; }; -},{}],7:[function(require,module,exports){ +},{"sdp":1}],9:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -2478,10 +3120,10 @@ /* eslint-env node */ 'use strict'; -var browserDetails = require('../utils').browserDetails; +var utils = require('../utils'); var firefoxShim = { - shimOnTrack: function() { + shimOnTrack: function(window) { if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) { Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { @@ -2508,7 +3150,7 @@ } }, - shimSourceObject: function() { + shimSourceObject: function(window) { // Firefox has supported mozSrcObject since FF22, unprefixed in 42. if (typeof window === 'object') { if (window.HTMLMediaElement && @@ -2526,7 +3168,9 @@ } }, - shimPeerConnection: function() { + shimPeerConnection: function(window) { + var browserDetails = utils.detectBrowser(window); + if (typeof window !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) { return; // probably media.peerconnection.enabled=false in about:config @@ -2559,38 +3203,40 @@ pcConfig.iceServers = newIceServers; } } - return new mozRTCPeerConnection(pcConfig, pcConstraints); + return new window.mozRTCPeerConnection(pcConfig, pcConstraints); }; - window.RTCPeerConnection.prototype = mozRTCPeerConnection.prototype; + window.RTCPeerConnection.prototype = + window.mozRTCPeerConnection.prototype; // wrap static methods. Currently just generateCertificate. - if (mozRTCPeerConnection.generateCertificate) { + if (window.mozRTCPeerConnection.generateCertificate) { Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { get: function() { - return mozRTCPeerConnection.generateCertificate; + return window.mozRTCPeerConnection.generateCertificate; } }); } - window.RTCSessionDescription = mozRTCSessionDescription; - window.RTCIceCandidate = mozRTCIceCandidate; + window.RTCSessionDescription = window.mozRTCSessionDescription; + window.RTCIceCandidate = window.mozRTCIceCandidate; } // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] .forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + window.RTCPeerConnection.prototype[method] = function() { arguments[0] = new ((method === 'addIceCandidate') ? - RTCIceCandidate : RTCSessionDescription)(arguments[0]); + window.RTCIceCandidate : + window.RTCSessionDescription)(arguments[0]); return nativeMethod.apply(this, arguments); }; }); // support for addIceCandidate(null or undefined) var nativeAddIceCandidate = - RTCPeerConnection.prototype.addIceCandidate; - RTCPeerConnection.prototype.addIceCandidate = function() { + window.RTCPeerConnection.prototype.addIceCandidate; + window.RTCPeerConnection.prototype.addIceCandidate = function() { if (!arguments[0]) { if (arguments[1]) { arguments[1].apply(null); @@ -2618,8 +3264,12 @@ remotecandidate: 'remote-candidate' }; - var nativeGetStats = RTCPeerConnection.prototype.getStats; - RTCPeerConnection.prototype.getStats = function(selector, onSucc, onErr) { + var nativeGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function( + selector, + onSucc, + onErr + ) { return nativeGetStats.apply(this, [selector || null]) .then(function(stats) { if (browserDetails.version < 48) { @@ -2659,7 +3309,7 @@ shimGetUserMedia: require('./getusermedia') }; -},{"../utils":10,"./getusermedia":8}],8:[function(require,module,exports){ +},{"../utils":12,"./getusermedia":10}],10:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -2670,16 +3320,22 @@ /* eslint-env node */ 'use strict'; -var logging = require('../utils').log; -var browserDetails = require('../utils').browserDetails; +var utils = require('../utils'); +var logging = utils.log; // Expose public methods. -module.exports = function() { +module.exports = function(window) { + var browserDetails = utils.detectBrowser(window); + var navigator = window && window.navigator; + var MediaStreamTrack = window && window.MediaStreamTrack; + var shimError_ = function(e) { return { name: { - SecurityError: 'NotAllowedError', - PermissionDeniedError: 'NotAllowedError' + InternalError: 'NotReadableError', + NotSupportedError: 'TypeError', + PermissionDeniedError: 'NotAllowedError', + SecurityError: 'NotAllowedError' }[e.name] || e.name, message: { 'The operation is insecure.': 'The request is not allowed by the ' + @@ -2811,6 +3467,48 @@ }); }; } + if (!(browserDetails.version > 55 && + 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { + var remap = function(obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + + var nativeGetUserMedia = navigator.mediaDevices.getUserMedia. + bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function(c) { + if (typeof c === 'object' && typeof c.audio === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); + remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeGetUserMedia(c); + }; + + if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { + var nativeGetSettings = MediaStreamTrack.prototype.getSettings; + MediaStreamTrack.prototype.getSettings = function() { + var obj = nativeGetSettings.apply(this, arguments); + remap(obj, 'mozAutoGainControl', 'autoGainControl'); + remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); + return obj; + }; + } + + if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { + var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; + MediaStreamTrack.prototype.applyConstraints = function(c) { + if (this.kind === 'audio' && typeof c === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c, 'autoGainControl', 'mozAutoGainControl'); + remap(c, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeApplyConstraints.apply(this, [c]); + }; + } + } navigator.getUserMedia = function(constraints, onSuccess, onError) { if (browserDetails.version < 44) { return getUserMedia_(constraints, onSuccess, onError); @@ -2822,7 +3520,7 @@ }; }; -},{"../utils":10}],9:[function(require,module,exports){ +},{"../utils":12}],11:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -2831,15 +3529,194 @@ * tree. */ 'use strict'; +var utils = require('../utils'); + var safariShim = { // TODO: DrAlex, should be here, double check against LayoutTests - // shimOnTrack: function() { }, // TODO: once the back-end for the mac port is done, add. // TODO: check for webkitGTK+ // shimPeerConnection: function() { }, - shimGetUserMedia: function() { + shimLocalStreamsAPI: function(window) { + if (typeof window !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getLocalStreams = function() { + if (!this._localStreams) { + this._localStreams = []; + } + return this._localStreams; + }; + } + if (!('getStreamById' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getStreamById = function(id) { + var result = null; + if (this._localStreams) { + this._localStreams.forEach(function(stream) { + if (stream.id === id) { + result = stream; + } + }); + } + if (this._remoteStreams) { + this._remoteStreams.forEach(function(stream) { + if (stream.id === id) { + result = stream; + } + }); + } + return result; + }; + } + if (!('addStream' in window.RTCPeerConnection.prototype)) { + var _addTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addStream = function(stream) { + if (!this._localStreams) { + this._localStreams = []; + } + if (this._localStreams.indexOf(stream) === -1) { + this._localStreams.push(stream); + } + var self = this; + stream.getTracks().forEach(function(track) { + _addTrack.call(self, track, stream); + }); + }; + + window.RTCPeerConnection.prototype.addTrack = function(track, stream) { + if (stream) { + if (!this._localStreams) { + this._localStreams = [stream]; + } else if (this._localStreams.indexOf(stream) === -1) { + this._localStreams.push(stream); + } + } + _addTrack.call(this, track, stream); + }; + } + if (!('removeStream' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.removeStream = function(stream) { + if (!this._localStreams) { + this._localStreams = []; + } + var index = this._localStreams.indexOf(stream); + if (index === -1) { + return; + } + this._localStreams.splice(index, 1); + var self = this; + var tracks = stream.getTracks(); + this.getSenders().forEach(function(sender) { + if (tracks.indexOf(sender.track) !== -1) { + self.removeTrack(sender); + } + }); + }; + } + }, + shimRemoteStreamsAPI: function(window) { + if (typeof window !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getRemoteStreams = function() { + return this._remoteStreams ? this._remoteStreams : []; + }; + } + if (!('onaddstream' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { + get: function() { + return this._onaddstream; + }, + set: function(f) { + if (this._onaddstream) { + this.removeEventListener('addstream', this._onaddstream); + this.removeEventListener('track', this._onaddstreampoly); + } + this.addEventListener('addstream', this._onaddstream = f); + this.addEventListener('track', this._onaddstreampoly = function(e) { + var stream = e.streams[0]; + if (!this._remoteStreams) { + this._remoteStreams = []; + } + if (this._remoteStreams.indexOf(stream) >= 0) { + return; + } + this._remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = e.streams[0]; + this.dispatchEvent(event); + }.bind(this)); + } + }); + } + }, + shimCallbacksAPI: function(window) { + if (typeof window !== 'object' || !window.RTCPeerConnection) { + return; + } + var prototype = window.RTCPeerConnection.prototype; + var createOffer = prototype.createOffer; + var createAnswer = prototype.createAnswer; + var setLocalDescription = prototype.setLocalDescription; + var setRemoteDescription = prototype.setRemoteDescription; + var addIceCandidate = prototype.addIceCandidate; + + prototype.createOffer = function(successCallback, failureCallback) { + var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; + var promise = createOffer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + + prototype.createAnswer = function(successCallback, failureCallback) { + var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; + var promise = createAnswer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + + var withCallback = function(description, successCallback, failureCallback) { + var promise = setLocalDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setLocalDescription = withCallback; + + withCallback = function(description, successCallback, failureCallback) { + var promise = setRemoteDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setRemoteDescription = withCallback; + + withCallback = function(candidate, successCallback, failureCallback) { + var promise = addIceCandidate.apply(this, [candidate]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.addIceCandidate = withCallback; + }, + shimGetUserMedia: function(window) { + var navigator = window && window.navigator; + if (!navigator.getUserMedia) { if (navigator.webkitGetUserMedia) { navigator.getUserMedia = navigator.webkitGetUserMedia.bind(navigator); @@ -2851,18 +3728,52 @@ }.bind(navigator); } } + }, + shimRTCIceServerUrls: function(window) { + // migrate from non-spec RTCIceServer.url to RTCIceServer.urls + var OrigPeerConnection = window.RTCPeerConnection; + window.RTCPeerConnection = function(pcConfig, pcConstraints) { + if (pcConfig && pcConfig.iceServers) { + var newIceServers = []; + for (var i = 0; i < pcConfig.iceServers.length; i++) { + var server = pcConfig.iceServers[i]; + if (!server.hasOwnProperty('urls') && + server.hasOwnProperty('url')) { + utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); + server = JSON.parse(JSON.stringify(server)); + server.urls = server.url; + delete server.url; + newIceServers.push(server); + } else { + newIceServers.push(pcConfig.iceServers[i]); + } + } + pcConfig.iceServers = newIceServers; + } + return new OrigPeerConnection(pcConfig, pcConstraints); + }; + window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; + // wrap static methods. Currently just generateCertificate. + Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { + get: function() { + return OrigPeerConnection.generateCertificate; + } + }); } }; // Expose public methods. module.exports = { - shimGetUserMedia: safariShim.shimGetUserMedia + shimCallbacksAPI: safariShim.shimCallbacksAPI, + shimLocalStreamsAPI: safariShim.shimLocalStreamsAPI, + shimRemoteStreamsAPI: safariShim.shimRemoteStreamsAPI, + shimGetUserMedia: safariShim.shimGetUserMedia, + shimRTCIceServerUrls: safariShim.shimRTCIceServerUrls // TODO - // shimOnTrack: safariShim.shimOnTrack, // shimPeerConnection: safariShim.shimPeerConnection }; -},{}],10:[function(require,module,exports){ +},{"../utils":12}],12:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -2874,6 +3785,7 @@ 'use strict'; var logDisabled_ = true; +var deprecationWarnings_ = true; // Utility methods. var utils = { @@ -2887,6 +3799,19 @@ 'adapter.js logging enabled'; }, + /** + * Disable or enable deprecation warnings + * @param {!boolean} bool set to true to disable warnings. + */ + disableWarnings: function(bool) { + if (typeof bool !== 'boolean') { + return new Error('Argument type: ' + typeof bool + + '. Please use a boolean.'); + } + deprecationWarnings_ = !bool; + return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); + }, + log: function() { if (typeof window === 'object') { if (logDisabled_) { @@ -2899,6 +3824,17 @@ }, /** + * Shows a deprecation warning suggesting the modern and spec-compatible API. + */ + deprecated: function(oldMethod, newMethod) { + if (!deprecationWarnings_) { + return; + } + console.warn(oldMethod + ' is deprecated, please use ' + newMethod + + ' instead.'); + }, + + /** * Extract browser version out of the provided user agent string. * * @param {!string} uastring userAgent string. @@ -2917,7 +3853,9 @@ * @return {object} result containing browser and version * properties. */ - detectBrowser: function() { + detectBrowser: function(window) { + var navigator = window && window.navigator; + // Returned result object. var result = {}; result.browser = null; @@ -2972,7 +3910,9 @@ // shimCreateObjectURL must be called before shimSourceObject to avoid loop. - shimCreateObjectURL: function() { + shimCreateObjectURL: function(window) { + var URL = window && window.URL; + if (!(typeof window === 'object' && window.HTMLMediaElement && 'srcObject' in window.HTMLMediaElement.prototype)) { // Only shim CreateObjectURL using srcObject if srcObject exists. @@ -2987,8 +3927,8 @@ if ('getTracks' in stream) { var url = 'polyblob:' + (++newId); streams.set(url, stream); - console.log('URL.createObjectURL(stream) is deprecated! ' + - 'Use elem.srcObject = stream instead!'); + utils.deprecated('URL.createObjectURL(stream)', + 'elem.srcObject = stream'); return url; } return nativeCreateObjectURL(stream); @@ -3010,8 +3950,8 @@ } }); - var nativeSetAttribute = HTMLMediaElement.prototype.setAttribute; - HTMLMediaElement.prototype.setAttribute = function() { + var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute; + window.HTMLMediaElement.prototype.setAttribute = function() { if (arguments.length === 2 && ('' + arguments[0]).toLowerCase() === 'src') { this.srcObject = streams.get(arguments[1]) || null; @@ -3024,8 +3964,9 @@ // Export. module.exports = { log: utils.log, + deprecated: utils.deprecated, disableLog: utils.disableLog, - browserDetails: utils.detectBrowser(), + disableWarnings: utils.disableWarnings, extractVersion: utils.extractVersion, shimCreateObjectURL: utils.shimCreateObjectURL, detectBrowser: utils.detectBrowser.bind(utils)
diff --git a/tools/perf/page_sets/webrtc_cases/audio.js b/tools/perf/page_sets/webrtc_cases/audio.js index 2485837..588f643 100644 --- a/tools/perf/page_sets/webrtc_cases/audio.js +++ b/tools/perf/page_sets/webrtc_cases/audio.js
@@ -40,7 +40,14 @@ if (audioTracks.length > 0) { trace('Using Audio device: ' + audioTracks[0].label); } - pc1.addStream(localStream); + localStream.getTracks().forEach( + function(track) { + pc1.addTrack( + track, + localStream + ); + } + ); trace('Adding Local Stream to peer connection'); pc1.createOffer( @@ -81,7 +88,7 @@ pc2.onicecandidate = function(e) { onIceCandidate(pc2, e); }; - pc2.onaddstream = gotRemoteStream; + pc2.ontrack = gotRemoteStream; trace('Requesting local stream'); navigator.mediaDevices.getUserMedia({ audio: true, @@ -142,8 +149,10 @@ } function gotRemoteStream(e) { - audio2.srcObject = e.stream; - trace('Received remote stream'); + if (audio2.srcObject !== e.streams[0]) { + audio2.srcObject = e.streams[0]; + trace('Received remote stream'); + } } function getOtherPc(pc) {
diff --git a/tools/perf/page_sets/webrtc_cases/canvas-capture.html b/tools/perf/page_sets/webrtc_cases/canvas-capture.html index 340c6e16..018cb25 100644 --- a/tools/perf/page_sets/webrtc_cases/canvas-capture.html +++ b/tools/perf/page_sets/webrtc_cases/canvas-capture.html
@@ -11,8 +11,8 @@ <div id="container"> <h1>Canvas capture stream to peerConnection</h1> - <canvas id="canvas" width=32 height=24></canvas> - <video id="remoteVideo" width=32 height=24 autoplay=""></video> + <canvas id="canvas" width="32" height="24"></canvas> + <video id="remoteVideo" width="32" height="24" autoplay=""></video> <div> <button id="startButton" class="green">Start test</button>
diff --git a/tools/perf/page_sets/webrtc_cases/canvas-capture.js b/tools/perf/page_sets/webrtc_cases/canvas-capture.js index ce7e11d3..744e0e10 100644 --- a/tools/perf/page_sets/webrtc_cases/canvas-capture.js +++ b/tools/perf/page_sets/webrtc_cases/canvas-capture.js
@@ -29,12 +29,13 @@ context.rect(0, 0, canvas.clientWidth, canvas.clientHeight); var randomNumber = Math.random(); var hue; - if (randomNumber < 0.33) + if (randomNumber < 0.33) { hue = 'red'; - else if (randomNumber < 0.66) + } else if (randomNumber < 0.66) { hue = 'green'; - else + } else { hue = 'blue'; + } context.fillStyle = hue; context.fill(); }
diff --git a/tools/perf/page_sets/webrtc_cases/constraints.js b/tools/perf/page_sets/webrtc_cases/constraints.js index 16cf173..d19d2123 100644 --- a/tools/perf/page_sets/webrtc_cases/constraints.js +++ b/tools/perf/page_sets/webrtc_cases/constraints.js
@@ -140,7 +140,14 @@ timestampPrev = 0; localPeerConnection = new RTCPeerConnection(null); remotePeerConnection = new RTCPeerConnection(null); - localPeerConnection.addStream(localStream); + localStream.getTracks().forEach( + function(track) { + localPeerConnection.addTrack( + track, + localStream + ); + } + ); console.log('localPeerConnection creating offer'); localPeerConnection.onnegotiationeeded = function() { console.log('Negotiation needed - localPeerConnection'); @@ -150,27 +157,25 @@ }; localPeerConnection.onicecandidate = function(e) { console.log('Candidate localPeerConnection'); - if (e.candidate) { - remotePeerConnection.addIceCandidate(e.candidate) - .then( - onAddIceCandidateSuccess, - onAddIceCandidateError - ); - } + remotePeerConnection.addIceCandidate(e.candidate) + .then( + onAddIceCandidateSuccess, + onAddIceCandidateError + ); }; remotePeerConnection.onicecandidate = function(e) { console.log('Candidate remotePeerConnection'); - if (e.candidate) { - localPeerConnection.addIceCandidate(e.candidate) - .then( - onAddIceCandidateSuccess, - onAddIceCandidateError - ); - } + localPeerConnection.addIceCandidate(e.candidate) + .then( + onAddIceCandidateSuccess, + onAddIceCandidateError + ); }; - remotePeerConnection.onaddstream = function(e) { - console.log('remotePeerConnection got stream'); - remoteVideo.srcObject = e.stream; + remotePeerConnection.ontrack = function(e) { + if (remoteVideo.srcObject !== e.streams[0]) { + console.log('remotePeerConnection got stream'); + remoteVideo.srcObject = e.streams[0]; + } }; localPeerConnection.createOffer().then( function(desc) { @@ -239,22 +244,35 @@ var activeCandidatePair = null; var remoteCandidate = null; - // search for the candidate pair + // Search for the candidate pair, spec-way first. results.forEach(function(report) { - if (report.type === 'candidatepair' && report.selected || - report.type === 'googCandidatePair' && - report.googActiveConnection === 'true') { - activeCandidatePair = report; + if (report.type === 'transport') { + activeCandidatePair = results.get(report.selectedCandidatePairId); } }); - if (activeCandidatePair && activeCandidatePair.remoteCandidateId) { - remoteCandidate = results[activeCandidatePair.remoteCandidateId]; + // Fallback for Firefox and Chrome legacy stats. + if (!activeCandidatePair) { + results.forEach(function(report) { + if (report.type === 'candidate-pair' && report.selected || + report.type === 'googCandidatePair' && + report.googActiveConnection === 'true') { + activeCandidatePair = report; + } + }); } - if (remoteCandidate && remoteCandidate.ipAddress && - remoteCandidate.portNumber) { - peerDiv.innerHTML = '<strong>Connected to:</strong> ' + - remoteCandidate.ipAddress + - ':' + remoteCandidate.portNumber; + if (activeCandidatePair && activeCandidatePair.remoteCandidateId) { + remoteCandidate = results.get(activeCandidatePair.remoteCandidateId); + } + if (remoteCandidate) { + if (remoteCandidate.ip && remoteCandidate.port) { + peerDiv.innerHTML = '<strong>Connected to:</strong> ' + + remoteCandidate.ip + ':' + remoteCandidate.port; + } else if (remoteCandidate.ipAddress && remoteCandidate.portNumber) { + // Fall back to old names. + peerDiv.innerHTML = '<strong>Connected to:</strong> ' + + remoteCandidate.ipAddress + + ':' + remoteCandidate.portNumber; + } } }, function(err) { console.log(err);
diff --git a/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.js b/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.js index 4401d10..3af6c63 100644 --- a/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.js +++ b/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.js
@@ -3,7 +3,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -/*jshint esversion: 6 */ +/* jshint esversion: 6 */ 'use strict'; @@ -44,8 +44,8 @@ audio: true, video: true }) - .then(onGetUserMediaSuccess) - .catch(logError); + .then(onGetUserMediaSuccess) + .catch(logError); }; this.onGetUserMediaSuccess = function(stream) { @@ -79,7 +79,7 @@ offerToReceiveAudio: 1, offerToReceiveVideo: 1 }) - .then(onCreateOfferSuccess, logError); + .then(onCreateOfferSuccess, logError); }; this.onCreateOfferSuccess = function(desc) { @@ -88,7 +88,7 @@ var onCreateAnswerSuccess = this.onCreateAnswerSuccess.bind(this); this.remoteConnection.createAnswer() - .then(onCreateAnswerSuccess, logError); + .then(onCreateAnswerSuccess, logError); }; this.onCreateAnswerSuccess = function(desc) {
diff --git a/tools/perf/page_sets/webrtc_cases/pause-play.html b/tools/perf/page_sets/webrtc_cases/pause-play.html new file mode 100644 index 0000000..5b5825d --- /dev/null +++ b/tools/perf/page_sets/webrtc_cases/pause-play.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<!-- + * 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. +--> + <title>Pause Play Test</title> + </head> + <body> + <h1>Pause Play Test</h1> + <p>Status: <span id="status">not-started</span></p> + <table border="0" id="test-table"></table> + +<script src="pause-play.js"></script> +<script src="adapter.js"></script> +<script src="common.js"></script> +</body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/pause-play.js b/tools/perf/page_sets/webrtc_cases/pause-play.js new file mode 100644 index 0000000..cfc9083 --- /dev/null +++ b/tools/perf/page_sets/webrtc_cases/pause-play.js
@@ -0,0 +1,201 @@ +/* + * 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. + */ + +const $ = document.getElementById.bind(document); + +function logError(err) { + console.error(err); +} + +/** + * FeedTable stores all video elements. + */ +class FeedTable { + constructor() { + this.numCols = 5; + this.col = 0; + this.testTable = document.getElementById('test-table'); + this.row = this.testTable.insertRow(-1); + } + + addNewCell(elementType) { + if (this.col === this.numCols) { + this.row = this.testTable.insertRow(-1); + this.col = 0; + } + var newCell = this.row.insertCell(-1); + var element = document.createElement(elementType); + element.autoplay = false; + newCell.appendChild(element); + this.col++; + return element; + } +} + +/** + * A simple loopback connection; + * - localConnection is fed video from local camera + * - localConnection is linked to remoteConnection + * - remoteConnection is displayed in the given videoElement + */ +class PeerConnection { + /** + * @param {Object} element - An 'audio' or 'video' element. + * @param {Object} constraints - The constraints for the peer connection. + */ + constructor(element, constraints) { + this.localConnection = null; + this.remoteConnection = null; + this.remoteView = element; + this.constraints = constraints; + } + + start() { + return navigator.mediaDevices + .getUserMedia(this.constraints) + .then((stream) => { + this.onGetUserMediaSuccess(stream); + }); + } + + onGetUserMediaSuccess(stream) { + this.localConnection = new RTCPeerConnection(null); + this.localConnection.onicecandidate = (event) => { + this.onIceCandidate(this.remoteConnection, event); + }; + this.localConnection.addStream(stream); + + this.remoteConnection = new RTCPeerConnection(null); + this.remoteConnection.onicecandidate = (event) => { + this.onIceCandidate(this.localConnection, event); + }; + this.remoteConnection.onaddstream = (e) => { + this.remoteView.srcObject = e.stream; + }; + + this.localConnection + .createOffer({offerToReceiveAudio: 1, offerToReceiveVideo: 1}) + .then((offerDesc) => { + this.onCreateOfferSuccess(offerDesc); + }, logError); + } + + onCreateOfferSuccess(offerDesc) { + this.localConnection.setLocalDescription(offerDesc); + this.remoteConnection.setRemoteDescription(offerDesc); + + this.remoteConnection.createAnswer().then( + (answerDesc) => { + this.onCreateAnswerSuccess(answerDesc); + }, logError); + } + + onCreateAnswerSuccess(answerDesc) { + this.remoteConnection.setLocalDescription(answerDesc); + this.localConnection.setRemoteDescription(answerDesc); + } + + onIceCandidate(connection, event) { + if (event.candidate) { + connection.addIceCandidate(new RTCIceCandidate(event.candidate)); + } + } +} + +class TestRunner { + constructor(runtimeSeconds, pausePlayIterationDelayMillis) { + this.runtimeSeconds = runtimeSeconds; + this.pausePlayIterationDelayMillis = pausePlayIterationDelayMillis; + this.elements = []; + this.peerConnections = []; + this.feedTable = new FeedTable(); + this.iteration = 0; + this.startTime = null; + this.lastIterationTime = null; + } + + addPeerConnection(elementType) { + const element = this.feedTable.addNewCell(elementType); + const constraints = {audio: true}; + if (elementType === 'video') { + constraints.video = { + width: {exact: 300} + }; + } else if (elementType === 'audio') { + constraints.video = false; + } else { + throw new Error('elementType must be one of "audio" or "video"'); + } + this.elements.push(element); + this.peerConnections.push(new PeerConnection(element, constraints)); + } + + startTest() { + this.startTime = Date.now(); + let promises = testRunner.peerConnections.map((conn) => conn.start()); + Promise.all(promises) + .then(() => { + this.startTime = Date.now(); + this.pauseAndPlayLoop(); + }) + .catch((e) => { + throw e; + }); + } + + pauseAndPlayLoop() { + this.iteration++; + this.elements.forEach((feed) => { + if (Math.random() >= 0.5) { + feed.play(); + } else { + feed.pause(); + } + }); + const status = this.getStatus(); + this.lastIterationTime = Date.now(); + $('status').textContent = status; + if (status !== 'ok-done') { + setTimeout( + () => { + this.pauseAndPlayLoop(); + }, this.pausePlayIterationDelayMillis); + } else { // We're done. Pause all feeds. + this.elements.forEach((feed) => { + feed.pause(); + }); + } + } + + getStatus() { + if (this.iteration === 0) { + return 'not-started'; + } + const timeSpent = Date.now() - this.startTime; + if (timeSpent >= this.runtimeSeconds * 1000) { + return 'ok-done'; + } + return `running, iteration: ${this.iteration}`; + } + + getResults() { + const runTimeMillis = this.lastIterationTime - this.startTime; + return {'runTimeSeconds': runTimeMillis / 1000}; + } +} + +let testRunner; + +function startTest( + runtimeSeconds, numPeerConnections, pausePlayIterationDelayMillis, + elementType) { + testRunner = new TestRunner( + runtimeSeconds, pausePlayIterationDelayMillis); + for (let i = 0; i < numPeerConnections; i++) { + testRunner.addPeerConnection(elementType); + } + testRunner.startTest(); +}
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index b597ccf..15fc211 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -962,6 +962,570 @@ } // +// IAccessibleTable methods. +// + +STDMETHODIMP AXPlatformNodeWin::get_accessibleAt(long row, + long column, + IUnknown** accessible) { + if (!accessible) + return E_INVALIDARG; + + AXPlatformNodeBase* cell = + GetTableCell(static_cast<int>(row), static_cast<int>(column)); + if (cell) { + auto* node_win = static_cast<AXPlatformNodeWin*>(cell); + node_win->AddRef(); + + *accessible = static_cast<IAccessible*>(node_win); + return S_OK; + } + + *accessible = nullptr; + return E_INVALIDARG; +} + +STDMETHODIMP AXPlatformNodeWin::get_caption(IUnknown** accessible) { + if (!accessible) + return E_INVALIDARG; + + // TODO(dmazzoni): implement + *accessible = nullptr; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_childIndex(long row, + long column, + long* cell_index) { + if (!cell_index) + return E_INVALIDARG; + + auto* cell = GetTableCell(static_cast<int>(row), static_cast<int>(column)); + if (cell) { + *cell_index = static_cast<LONG>(cell->GetTableCellIndex()); + return S_OK; + } + + *cell_index = 0; + return E_INVALIDARG; +} + +STDMETHODIMP AXPlatformNodeWin::get_columnDescription(long column, + BSTR* description) { + if (!description) + return E_INVALIDARG; + + int columns = GetTableColumnCount(); + if (column < 0 || column >= columns) + return E_INVALIDARG; + + int rows = GetTableRowCount(); + if (rows <= 0) { + *description = nullptr; + return S_FALSE; + } + + for (int i = 0; i < rows; ++i) { + auto* cell = GetTableCell(i, column); + if (cell && cell->GetData().role == ui::AX_ROLE_COLUMN_HEADER) { + base::string16 cell_name = cell->GetString16Attribute(ui::AX_ATTR_NAME); + if (cell_name.size() > 0) { + *description = SysAllocString(cell_name.c_str()); + return S_OK; + } + + cell_name = cell->GetString16Attribute(ui::AX_ATTR_DESCRIPTION); + if (cell_name.size() > 0) { + *description = SysAllocString(cell_name.c_str()); + return S_OK; + } + } + } + + *description = nullptr; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_columnExtentAt(long row, + long column, + long* n_columns_spanned) { + if (!n_columns_spanned) + return E_INVALIDARG; + + auto* cell = GetTableCell(static_cast<int>(row), static_cast<int>(column)); + if (!cell) + return E_INVALIDARG; + + *n_columns_spanned = cell->GetTableColumnSpan(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_columnHeader( + IAccessibleTable** accessible_table, + long* starting_row_index) { + // TODO(dmazzoni): implement + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeWin::get_columnIndex(long cell_index, + long* column_index) { + if (!column_index) + return E_INVALIDARG; + + auto* cell = GetTableCell(cell_index); + if (!cell) + return E_INVALIDARG; + *column_index = cell->GetTableColumn(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_nColumns(long* column_count) { + if (!column_count) + return E_INVALIDARG; + + *column_count = GetTableColumnCount(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_nRows(long* row_count) { + if (!row_count) + return E_INVALIDARG; + + *row_count = GetTableRowCount(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_nSelectedChildren(long* cell_count) { + if (!cell_count) + return E_INVALIDARG; + + // TODO(dmazzoni): add support for selected cells/rows/columns in tables. + *cell_count = 0; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_nSelectedColumns(long* column_count) { + if (!column_count) + return E_INVALIDARG; + + *column_count = 0; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_nSelectedRows(long* row_count) { + if (!row_count) + return E_INVALIDARG; + + *row_count = 0; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_rowDescription(long row, + BSTR* description) { + if (!description) + return E_INVALIDARG; + + if (row < 0 || row >= GetTableRowCount()) + return E_INVALIDARG; + + int columns = GetTableColumnCount(); + if (columns <= 0) { + *description = nullptr; + return S_FALSE; + } + + for (int i = 0; i < columns; ++i) { + auto* cell = GetTableCell(row, i); + if (cell && cell->GetData().role == ui::AX_ROLE_ROW_HEADER) { + base::string16 cell_name = cell->GetString16Attribute(ui::AX_ATTR_NAME); + if (cell_name.size() > 0) { + *description = SysAllocString(cell_name.c_str()); + return S_OK; + } + cell_name = cell->GetString16Attribute(ui::AX_ATTR_DESCRIPTION); + if (cell_name.size() > 0) { + *description = SysAllocString(cell_name.c_str()); + return S_OK; + } + } + } + + *description = nullptr; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_rowExtentAt(long row, + long column, + long* n_rows_spanned) { + if (!n_rows_spanned) + return E_INVALIDARG; + + auto* cell = GetTableCell(row, column); + if (!cell) + return E_INVALIDARG; + + *n_rows_spanned = GetTableRowSpan(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_rowHeader( + IAccessibleTable** accessible_table, + long* starting_column_index) { + // TODO(dmazzoni): implement + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeWin::get_rowIndex(long cell_index, long* row_index) { + if (!row_index) + return E_INVALIDARG; + + auto* cell = GetTableCell(cell_index); + if (!cell) + return E_INVALIDARG; + + *row_index = cell->GetTableRow(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_selectedChildren(long max_children, + long** children, + long* n_children) { + if (!children || !n_children) + return E_INVALIDARG; + + // TODO(dmazzoni): Implement this. + *n_children = 0; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_selectedColumns(long max_columns, + long** columns, + long* n_columns) { + if (!columns || !n_columns) + return E_INVALIDARG; + + // TODO(dmazzoni): Implement this. + *n_columns = 0; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_selectedRows(long max_rows, + long** rows, + long* n_rows) { + if (!rows || !n_rows) + return E_INVALIDARG; + + // TODO(dmazzoni): Implement this. + *n_rows = 0; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_summary(IUnknown** accessible) { + if (!accessible) + return E_INVALIDARG; + + // TODO(dmazzoni): implement + *accessible = nullptr; + return S_FALSE; +} + +STDMETHODIMP AXPlatformNodeWin::get_isColumnSelected(long column, + boolean* is_selected) { + if (!is_selected) + return E_INVALIDARG; + + // TODO(dmazzoni): Implement this. + *is_selected = false; + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_isRowSelected(long row, + boolean* is_selected) { + if (!is_selected) + return E_INVALIDARG; + + // TODO(dmazzoni): Implement this. + *is_selected = false; + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_isSelected(long row, + long column, + boolean* is_selected) { + if (!is_selected) + return E_INVALIDARG; + + // TODO(dmazzoni): Implement this. + *is_selected = false; + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_rowColumnExtentsAtIndex( + long index, + long* row, + long* column, + long* row_extents, + long* column_extents, + boolean* is_selected) { + if (!row || !column || !row_extents || !column_extents || !is_selected) + return E_INVALIDARG; + + auto* cell = GetTableCell(index); + if (!cell) + return E_INVALIDARG; + + *row = cell->GetTableRow(); + *column = cell->GetTableColumn(); + *row_extents = GetTableRowSpan(); + *column_extents = GetTableColumnSpan(); + *is_selected = false; // Not supported. + + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::selectRow(long row) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeWin::selectColumn(long column) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeWin::unselectRow(long row) { + return E_NOTIMPL; +} + +STDMETHODIMP AXPlatformNodeWin::unselectColumn(long column) { + return E_NOTIMPL; +} + +STDMETHODIMP +AXPlatformNodeWin::get_modelChange(IA2TableModelChange* model_change) { + return E_NOTIMPL; +} + +// +// IAccessibleTable2 methods. +// + +STDMETHODIMP AXPlatformNodeWin::get_cellAt(long row, + long column, + IUnknown** cell) { + if (!cell) + return E_INVALIDARG; + + AXPlatformNodeBase* table_cell = + GetTableCell(static_cast<int>(row), static_cast<int>(column)); + if (table_cell) { + auto* node_win = static_cast<AXPlatformNodeWin*>(table_cell); + node_win->AddRef(); + *cell = static_cast<IAccessible*>(node_win); + return S_OK; + } + + *cell = nullptr; + return E_INVALIDARG; +} + +STDMETHODIMP AXPlatformNodeWin::get_nSelectedCells(long* cell_count) { + return get_nSelectedChildren(cell_count); +} + +STDMETHODIMP AXPlatformNodeWin::get_selectedCells(IUnknown*** cells, + long* n_selected_cells) { + if (!cells || !n_selected_cells) + return E_INVALIDARG; + + // TODO(dmazzoni): Implement this. + *n_selected_cells = 0; + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_selectedColumns(long** columns, + long* n_columns) { + if (!columns || !n_columns) + return E_INVALIDARG; + + // TODO(dmazzoni): Implement this. + *n_columns = 0; + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_selectedRows(long** rows, long* n_rows) { + if (!rows || !n_rows) + return E_INVALIDARG; + + // TODO(dmazzoni): Implement this. + *n_rows = 0; + return S_OK; +} + +// +// IAccessibleTableCell methods. +// + +STDMETHODIMP AXPlatformNodeWin::get_columnExtent(long* n_columns_spanned) { + if (!n_columns_spanned) + return E_INVALIDARG; + + *n_columns_spanned = GetTableColumnSpan(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_columnHeaderCells( + IUnknown*** cell_accessibles, + long* n_column_header_cells) { + if (!cell_accessibles || !n_column_header_cells) + return E_INVALIDARG; + + *n_column_header_cells = 0; + auto* table = GetTable(); + if (!table) { + NOTREACHED(); + return S_FALSE; + } + + int column = GetTableColumn(); + int columns = GetTableColumnCount(); + int rows = GetTableRowCount(); + if (columns <= 0 || rows <= 0 || column < 0 || column >= columns) + return S_FALSE; + + for (int i = 0; i < rows; ++i) { + auto* cell = GetTableCell(i, column); + if (cell && cell->GetData().role == ui::AX_ROLE_COLUMN_HEADER) + (*n_column_header_cells)++; + } + + *cell_accessibles = static_cast<IUnknown**>( + CoTaskMemAlloc((*n_column_header_cells) * sizeof(cell_accessibles[0]))); + int index = 0; + for (int i = 0; i < rows; ++i) { + AXPlatformNodeBase* cell = GetTableCell(i, column); + if (cell && cell->GetData().role == ui::AX_ROLE_COLUMN_HEADER) { + auto* node_win = static_cast<AXPlatformNodeWin*>(cell); + node_win->AddRef(); + + (*cell_accessibles)[index] = static_cast<IAccessible*>(node_win); + ++index; + } + } + + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_columnIndex(long* column_index) { + if (!column_index) + return E_INVALIDARG; + + *column_index = GetTableColumn(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_rowExtent(long* n_rows_spanned) { + if (!n_rows_spanned) + return E_INVALIDARG; + + *n_rows_spanned = GetTableRowSpan(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_rowHeaderCells(IUnknown*** cell_accessibles, + long* n_row_header_cells) { + if (!cell_accessibles || !n_row_header_cells) + return E_INVALIDARG; + + *n_row_header_cells = 0; + auto* table = GetTable(); + if (!table) { + NOTREACHED(); + return S_FALSE; + } + + int row = GetTableRow(); + int columns = GetTableColumnCount(); + int rows = GetTableRowCount(); + if (columns <= 0 || rows <= 0 || row < 0 || row >= rows) + return S_FALSE; + + for (int i = 0; i < columns; ++i) { + auto* cell = GetTableCell(row, i); + if (cell && cell->GetData().role == ui::AX_ROLE_ROW_HEADER) + (*n_row_header_cells)++; + } + + *cell_accessibles = static_cast<IUnknown**>( + CoTaskMemAlloc((*n_row_header_cells) * sizeof(cell_accessibles[0]))); + int index = 0; + for (int i = 0; i < columns; ++i) { + AXPlatformNodeBase* cell = GetTableCell(row, i); + if (cell && cell->GetData().role == ui::AX_ROLE_ROW_HEADER) { + auto* node_win = static_cast<AXPlatformNodeWin*>(cell); + node_win->AddRef(); + + (*cell_accessibles)[index] = static_cast<IAccessible*>(node_win); + ++index; + } + } + + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_rowIndex(long* row_index) { + if (!row_index) + return E_INVALIDARG; + + *row_index = GetTableRow(); + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_isSelected(boolean* is_selected) { + if (!is_selected) + return E_INVALIDARG; + + *is_selected = false; + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_rowColumnExtents(long* row_index, + long* column_index, + long* row_extents, + long* column_extents, + boolean* is_selected) { + if (!row_index || !column_index || !row_extents || !column_extents || + !is_selected) { + return E_INVALIDARG; + } + + *row_index = GetTableRow(); + *column_index = GetTableColumn(); + *row_extents = GetTableRowSpan(); + *column_extents = GetTableColumnSpan(); + *is_selected = false; // Not supported. + + return S_OK; +} + +STDMETHODIMP AXPlatformNodeWin::get_table(IUnknown** table) { + if (!table) + return E_INVALIDARG; + + auto* find_table = GetTable(); + if (!find_table) { + *table = nullptr; + return S_FALSE; + } + + // The IAccessibleTable interface is still on the AXPlatformNodeWin + // class. + auto* node_win = static_cast<AXPlatformNodeWin*>(find_table); + node_win->AddRef(); + + *table = static_cast<IAccessibleTable*>(node_win); + return S_OK; +} + +// // IAccessibleText //
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h index 2ca22ca..a08df79 100644 --- a/ui/accessibility/platform/ax_platform_node_win.h +++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -40,6 +40,9 @@ &IID_IAccessible2, &LIBID_IAccessible2Lib>, public IAccessibleText, + public IAccessibleTable, + public IAccessibleTable2, + public IAccessibleTableCell, public IServiceProvider, public AXPlatformNodeBase { public: @@ -50,6 +53,9 @@ COM_INTERFACE_ENTRY(IAccessible2) COM_INTERFACE_ENTRY(IAccessible2_2) COM_INTERFACE_ENTRY(IAccessibleText) + COM_INTERFACE_ENTRY(IAccessibleTable) + COM_INTERFACE_ENTRY(IAccessibleTable2) + COM_INTERFACE_ENTRY(IAccessibleTableCell) COM_INTERFACE_ENTRY(IServiceProvider) END_COM_MAP() @@ -228,6 +234,147 @@ LONG* offset) override; // + // IAccessibleTable methods. + // + + // get_description - also used by IAccessibleImage + + STDMETHODIMP get_accessibleAt(long row, + long column, + IUnknown** accessible) override; + + STDMETHODIMP get_caption(IUnknown** accessible) override; + + STDMETHODIMP get_childIndex(long row_index, + long column_index, + long* cell_index) override; + + STDMETHODIMP get_columnDescription(long column, BSTR* description) override; + + STDMETHODIMP + get_columnExtentAt(long row, long column, long* n_columns_spanned) override; + + STDMETHODIMP + get_columnHeader(IAccessibleTable** accessible_table, + long* starting_row_index) override; + + STDMETHODIMP get_columnIndex(long cell_index, long* column_index) override; + + STDMETHODIMP get_nColumns(long* column_count) override; + + STDMETHODIMP get_nRows(long* row_count) override; + + STDMETHODIMP get_nSelectedChildren(long* cell_count) override; + + STDMETHODIMP get_nSelectedColumns(long* column_count) override; + + STDMETHODIMP get_nSelectedRows(long* row_count) override; + + STDMETHODIMP get_rowDescription(long row, BSTR* description) override; + + STDMETHODIMP get_rowExtentAt(long row, + long column, + long* n_rows_spanned) override; + + STDMETHODIMP + get_rowHeader(IAccessibleTable** accessible_table, + long* starting_column_index) override; + + STDMETHODIMP get_rowIndex(long cell_index, long* row_index) override; + + STDMETHODIMP get_selectedChildren(long max_children, + long** children, + long* n_children) override; + + STDMETHODIMP get_selectedColumns(long max_columns, + long** columns, + long* n_columns) override; + + STDMETHODIMP get_selectedRows(long max_rows, + long** rows, + long* n_rows) override; + + STDMETHODIMP get_summary(IUnknown** accessible) override; + + STDMETHODIMP + get_isColumnSelected(long column, boolean* is_selected) override; + + STDMETHODIMP get_isRowSelected(long row, boolean* is_selected) override; + + STDMETHODIMP get_isSelected(long row, + long column, + boolean* is_selected) override; + + STDMETHODIMP + get_rowColumnExtentsAtIndex(long index, + long* row, + long* column, + long* row_extents, + long* column_extents, + boolean* is_selected) override; + + STDMETHODIMP selectRow(long row) override; + + STDMETHODIMP selectColumn(long column) override; + + STDMETHODIMP unselectRow(long row) override; + + STDMETHODIMP unselectColumn(long column) override; + + STDMETHODIMP + get_modelChange(IA2TableModelChange* model_change) override; + + // + // IAccessibleTable2 methods. + // + // (Most of these are duplicates of IAccessibleTable methods, only the + // unique ones are included here.) + // + + STDMETHODIMP get_cellAt(long row, long column, IUnknown** cell) override; + + STDMETHODIMP get_nSelectedCells(long* cell_count) override; + + STDMETHODIMP + get_selectedCells(IUnknown*** cells, long* n_selected_cells) override; + + STDMETHODIMP get_selectedColumns(long** columns, long* n_columns) override; + + STDMETHODIMP get_selectedRows(long** rows, long* n_rows) override; + + // + // IAccessibleTableCell methods. + // + + STDMETHODIMP + get_columnExtent(long* n_columns_spanned) override; + + STDMETHODIMP + get_columnHeaderCells(IUnknown*** cell_accessibles, + long* n_column_header_cells) override; + + STDMETHODIMP get_columnIndex(long* column_index) override; + + STDMETHODIMP get_rowExtent(long* n_rows_spanned) override; + + STDMETHODIMP + get_rowHeaderCells(IUnknown*** cell_accessibles, + long* n_row_header_cells) override; + + STDMETHODIMP get_rowIndex(long* row_index) override; + + STDMETHODIMP get_isSelected(boolean* is_selected) override; + + STDMETHODIMP + get_rowColumnExtents(long* row, + long* column, + long* row_extents, + long* column_extents, + boolean* is_selected) override; + + STDMETHODIMP get_table(IUnknown** table) override; + + // // IAccessibleText methods not implemented. //
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc index 0ccd3fa..b212248 100644 --- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -106,6 +106,16 @@ return IAccessibleFromNode(GetRootNode()); } + ScopedComPtr<IAccessible2> ToIAccessible2(ScopedComPtr<IUnknown> unknown) { + CHECK(unknown); + ScopedComPtr<IServiceProvider> service_provider; + unknown.CopyTo(service_provider.GetAddressOf()); + ScopedComPtr<IAccessible2> result; + CHECK(SUCCEEDED(service_provider->QueryService(IID_IAccessible2, + result.GetAddressOf()))); + return result; + } + ScopedComPtr<IAccessible2> ToIAccessible2( ScopedComPtr<IAccessible> accessible) { CHECK(accessible); @@ -117,6 +127,173 @@ return result; } + void CheckVariantHasName(ScopedVariant& variant, + const wchar_t* expected_name) { + ScopedComPtr<IAccessible> accessible; + HRESULT hr = + V_DISPATCH(variant.ptr())->QueryInterface(IID_PPV_ARGS(&accessible)); + EXPECT_EQ(S_OK, hr); + ScopedBstr name; + EXPECT_EQ(S_OK, accessible->get_accName(SELF, name.Receive())); + EXPECT_STREQ(expected_name, name); + } + + void CheckIUnknownHasName(ScopedComPtr<IUnknown> unknown, + const wchar_t* expected_name) { + ScopedComPtr<IAccessible2> accessible = ToIAccessible2(unknown); + ASSERT_NE(nullptr, accessible); + + ScopedBstr name; + EXPECT_EQ(S_OK, accessible->get_accName(SELF, name.Receive())); + EXPECT_STREQ(expected_name, name); + } + + void Build3X3Table() { + /* + Build a table the looks like: + + ---------------------- (A) Column Header + | | (A) | (B) | (B) Column Header + ---------------------- (C) Row Header + | (C) | 1 | 2 | (D) Row Header + ---------------------- + | (D) | 3 | 4 | + ---------------------- + */ + + AXNodeData table; + table.id = 0; + table.role = ui::AX_ROLE_TABLE; + + table.AddIntAttribute(AX_ATTR_TABLE_ROW_COUNT, 3); + table.AddIntAttribute(AX_ATTR_TABLE_COLUMN_COUNT, 3); + + // Ordering in this list matters. It is used in the calculation + // of where cells are by the following: + // int position = row * GetTableColumnCount() + column; + + std::vector<int32_t> ids{51, 52, 53, 2, 3, 4, 11, 12, 13}; + table.AddIntListAttribute(AX_ATTR_CELL_IDS, ids); + table.AddIntListAttribute(AX_ATTR_UNIQUE_CELL_IDS, ids); + + table.child_ids.push_back(50); // Header + table.child_ids.push_back(1); // Row 1 + table.child_ids.push_back(10); // Row 2 + + // Table column header + AXNodeData table_row_header; + table_row_header.id = 50; + table_row_header.role = ui::AX_ROLE_ROW; + table_row_header.child_ids.push_back(51); + table_row_header.child_ids.push_back(52); + table_row_header.child_ids.push_back(53); + + AXNodeData table_column_header_1; + table_column_header_1.id = 51; + table_column_header_1.role = ui::AX_ROLE_COLUMN_HEADER; + + AXNodeData table_column_header_2; + table_column_header_2.id = 52; + table_column_header_2.role = ui::AX_ROLE_COLUMN_HEADER; + table_column_header_2.AddStringAttribute(AX_ATTR_NAME, "column header 1"); + + AXNodeData table_column_header_3; + table_column_header_3.id = 53; + table_column_header_3.role = ui::AX_ROLE_COLUMN_HEADER; + // Either AX_ATTR_NAME -or- AX_ATTR_DESCRIPTION is acceptable for a + // description + table_column_header_3.AddStringAttribute(AX_ATTR_DESCRIPTION, + "column header 2"); + + // Row 1 + AXNodeData table_row_1; + table_row_1.id = 1; + table_row_1.role = ui::AX_ROLE_ROW; + table_row_1.child_ids.push_back(2); + table_row_1.child_ids.push_back(3); + table_row_1.child_ids.push_back(4); + + AXNodeData table_row_header_1; + table_row_header_1.id = 2; + table_row_header_1.role = ui::AX_ROLE_ROW_HEADER; + table_row_header_1.AddStringAttribute(AX_ATTR_NAME, "row header 1"); + + AXNodeData table_cell_1; + table_cell_1.id = 3; + table_cell_1.role = ui::AX_ROLE_CELL; + table_cell_1.AddStringAttribute(AX_ATTR_NAME, "1"); + + AXNodeData table_cell_2; + table_cell_2.id = 4; + table_cell_2.role = ui::AX_ROLE_CELL; + table_cell_2.AddStringAttribute(AX_ATTR_NAME, "2"); + + // Row 2 + AXNodeData table_row_2; + table_row_2.id = 10; + table_row_2.role = ui::AX_ROLE_ROW; + table_row_2.child_ids.push_back(11); + table_row_2.child_ids.push_back(12); + table_row_2.child_ids.push_back(13); + + AXNodeData table_row_header_2; + table_row_header_2.id = 11; + table_row_header_2.role = ui::AX_ROLE_ROW_HEADER; + // Either AX_ATTR_NAME -or- AX_ATTR_DESCRIPTION is acceptable for a + // description + table_row_header_2.AddStringAttribute(AX_ATTR_DESCRIPTION, "row header 2"); + + AXNodeData table_cell_3; + table_cell_3.id = 12; + table_cell_3.role = ui::AX_ROLE_CELL; + table_cell_3.AddStringAttribute(AX_ATTR_NAME, "3"); + + AXNodeData table_cell_4; + table_cell_4.id = 13; + table_cell_4.role = ui::AX_ROLE_CELL; + table_cell_4.AddStringAttribute(AX_ATTR_NAME, "4"); + + AXTreeUpdate update; + update.root_id = table.id; + + update.nodes.push_back(table); + + update.nodes.push_back(table_row_header); + update.nodes.push_back(table_column_header_1); + update.nodes.push_back(table_column_header_2); + update.nodes.push_back(table_column_header_3); + + update.nodes.push_back(table_row_1); + update.nodes.push_back(table_row_header_1); + update.nodes.push_back(table_cell_1); + update.nodes.push_back(table_cell_2); + + update.nodes.push_back(table_row_2); + update.nodes.push_back(table_row_header_2); + update.nodes.push_back(table_cell_3); + update.nodes.push_back(table_cell_4); + + Init(update); + } + + ScopedComPtr<IAccessibleTableCell> GetCellInTable() { + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable2> table; + root_obj.CopyTo(table.GetAddressOf()); + if (!table) + return ScopedComPtr<IAccessibleTableCell>(); + + ScopedComPtr<IUnknown> cell; + table->get_cellAt(1, 1, cell.GetAddressOf()); + if (!cell) + return ScopedComPtr<IAccessibleTableCell>(); + + ScopedComPtr<IAccessibleTableCell> table_cell; + cell.CopyTo(table_cell.GetAddressOf()); + return table_cell; + } + std::unique_ptr<AXTree> tree_; }; @@ -167,13 +344,7 @@ EXPECT_EQ(S_OK, root_obj->accHitTest(5, 5, obj.Receive())); ASSERT_NE(nullptr, obj.ptr()); - // We got something back, make sure that it has the correct name. - base::win::ScopedComPtr<IAccessible> accessible; - HRESULT hr = V_DISPATCH(obj.ptr())->QueryInterface(IID_PPV_ARGS(&accessible)); - EXPECT_EQ(S_OK, hr); - ScopedBstr name; - EXPECT_EQ(S_OK, accessible->get_accName(SELF, name.Receive())); - EXPECT_STREQ(L"Name1", name); + CheckVariantHasName(obj, L"Name1"); } TEST_F(AXPlatformNodeWinTest, TestIAccessibleName) { @@ -321,14 +492,7 @@ EXPECT_EQ(S_OK, root_obj->get_accSelection(selection.Receive())); ASSERT_NE(nullptr, selection.ptr()); - // We got something back, make sure that it has the correct name. - base::win::ScopedComPtr<IAccessible> accessible; - HRESULT hr = - V_DISPATCH(selection.ptr())->QueryInterface(IID_PPV_ARGS(&accessible)); - EXPECT_EQ(S_OK, hr); - ScopedBstr name; - EXPECT_EQ(S_OK, accessible->get_accName(SELF, name.Receive())); - EXPECT_STREQ(L"Name2", name); + CheckVariantHasName(selection, L"Name2"); } TEST_F(AXPlatformNodeWinTest, TestIAccessibleSelectionMultipleSelected) { @@ -366,8 +530,8 @@ EXPECT_EQ(S_OK, root_obj->get_accSelection(selection.Receive())); ASSERT_NE(nullptr, selection.ptr()); - // We got something back, make sure that it has the corrent name. - base::win::ScopedComPtr<IEnumVARIANT> accessibles; + // Loop through the selections and make sure we have the right ones + ScopedComPtr<IEnumVARIANT> accessibles; HRESULT hr = V_DISPATCH(selection.ptr())->QueryInterface(IID_PPV_ARGS(&accessibles)); EXPECT_EQ(S_OK, hr); @@ -379,7 +543,7 @@ hr = accessibles->Next(1, item.Receive(), &ignore); EXPECT_EQ(S_OK, hr); - base::win::ScopedComPtr<IAccessible> accessible; + ScopedComPtr<IAccessible> accessible; HRESULT hr = V_DISPATCH(item.ptr())->QueryInterface(IID_PPV_ARGS(&accessible)); EXPECT_EQ(S_OK, hr); @@ -394,7 +558,7 @@ hr = accessibles->Next(1, item.Receive(), &ignore); EXPECT_EQ(S_OK, hr); - base::win::ScopedComPtr<IAccessible> accessible; + ScopedComPtr<IAccessible> accessible; HRESULT hr = V_DISPATCH(item.ptr())->QueryInterface(IID_PPV_ARGS(&accessible)); EXPECT_EQ(S_OK, hr); @@ -737,4 +901,396 @@ EXPECT_HRESULT_FAILED(text_field->setSelection(0, 0, 5)); } +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetAccessibilityAt) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + ScopedComPtr<IUnknown> cell_1; + EXPECT_EQ(S_OK, result->get_accessibleAt(1, 1, cell_1.GetAddressOf())); + CheckIUnknownHasName(cell_1, L"1"); + + ScopedComPtr<IUnknown> cell_2; + EXPECT_EQ(S_OK, result->get_accessibleAt(1, 2, cell_2.GetAddressOf())); + CheckIUnknownHasName(cell_2, L"2"); + + ScopedComPtr<IUnknown> cell_3; + EXPECT_EQ(S_OK, result->get_accessibleAt(2, 1, cell_3.GetAddressOf())); + CheckIUnknownHasName(cell_3, L"3"); + + ScopedComPtr<IUnknown> cell_4; + EXPECT_EQ(S_OK, result->get_accessibleAt(2, 2, cell_4.GetAddressOf())); + CheckIUnknownHasName(cell_4, L"4"); +} + +TEST_F(AXPlatformNodeWinTest, + TestIAccessibleTableGetAccessibilityAtOutOfBounds) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + { + ScopedComPtr<IUnknown> cell; + EXPECT_EQ(E_INVALIDARG, + result->get_accessibleAt(-1, -1, cell.GetAddressOf())); + } + + { + ScopedComPtr<IUnknown> cell; + EXPECT_EQ(E_INVALIDARG, + result->get_accessibleAt(0, 5, cell.GetAddressOf())); + } + + { + ScopedComPtr<IUnknown> cell; + EXPECT_EQ(E_INVALIDARG, + result->get_accessibleAt(5, 0, cell.GetAddressOf())); + } + + { + ScopedComPtr<IUnknown> cell; + EXPECT_EQ(E_INVALIDARG, + result->get_accessibleAt(10, 10, cell.GetAddressOf())); + } +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetChildIndex) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + long id; + EXPECT_EQ(S_OK, result->get_childIndex(0, 0, &id)); + EXPECT_EQ(id, 0); + + EXPECT_EQ(S_OK, result->get_childIndex(0, 1, &id)); + EXPECT_EQ(id, 1); + + EXPECT_EQ(S_OK, result->get_childIndex(1, 0, &id)); + EXPECT_EQ(id, 3); + + EXPECT_EQ(S_OK, result->get_childIndex(1, 1, &id)); + EXPECT_EQ(id, 4); + + EXPECT_EQ(E_INVALIDARG, result->get_childIndex(-1, -1, &id)); + EXPECT_EQ(E_INVALIDARG, result->get_childIndex(0, 5, &id)); + EXPECT_EQ(E_INVALIDARG, result->get_childIndex(5, 0, &id)); + EXPECT_EQ(E_INVALIDARG, result->get_childIndex(5, 5, &id)); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetColumnDescription) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + { + ScopedBstr name; + EXPECT_EQ(S_FALSE, result->get_columnDescription(0, name.Receive())); + } + { + ScopedBstr name; + EXPECT_EQ(S_OK, result->get_columnDescription(1, name.Receive())); + EXPECT_STREQ(L"column header 1", name); + } + + { + ScopedBstr name; + EXPECT_EQ(S_OK, result->get_columnDescription(2, name.Receive())); + EXPECT_STREQ(L"column header 2", name); + } +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetColumnExtentAt) { + // TODO(dougt) This table doesn't have any spanning cells. This test + // tests get_columnExtentAt for (1) and an invalid input. + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + long columns_spanned; + EXPECT_EQ(S_OK, result->get_columnExtentAt(1, 1, &columns_spanned)); + EXPECT_EQ(columns_spanned, 1); + + EXPECT_EQ(E_INVALIDARG, result->get_columnExtentAt(-1, -1, &columns_spanned)); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetColumnIndex) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + long index; + EXPECT_EQ(S_OK, result->get_columnIndex(1, &index)); + EXPECT_EQ(index, 0); + + EXPECT_EQ(E_INVALIDARG, result->get_columnIndex(-1, &index)); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNColumns) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + long count; + EXPECT_EQ(S_OK, result->get_nColumns(&count)); + EXPECT_EQ(count, 3); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNRows) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + long count; + EXPECT_EQ(S_OK, result->get_nRows(&count)); + EXPECT_EQ(count, 3); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetRowDescription) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + { + ScopedBstr name; + EXPECT_EQ(S_FALSE, result->get_rowDescription(0, name.Receive())); + } + { + ScopedBstr name; + EXPECT_EQ(S_OK, result->get_rowDescription(1, name.Receive())); + EXPECT_STREQ(L"row header 1", name); + } + + { + ScopedBstr name; + EXPECT_EQ(S_OK, result->get_rowDescription(2, name.Receive())); + EXPECT_STREQ(L"row header 2", name); + } +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetRowExtentAt) { + // TODO(dougt) This table doesn't have any spanning cells. This test + // tests get_rowExtentAt for (1) and an invalid input. + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + long rows_spanned; + EXPECT_EQ(S_OK, result->get_rowExtentAt(0, 1, &rows_spanned)); + EXPECT_EQ(rows_spanned, 0); + + EXPECT_EQ(E_INVALIDARG, result->get_columnExtentAt(-1, -1, &rows_spanned)); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetRowIndex) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + long index; + EXPECT_EQ(S_OK, result->get_rowIndex(1, &index)); + EXPECT_EQ(index, 0); + + EXPECT_EQ(E_INVALIDARG, result->get_rowIndex(-1, &index)); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetRowColumnExtentsAtIndex) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + long row, column, row_extents, column_extents; + boolean is_selected; + EXPECT_EQ(S_OK, + result->get_rowColumnExtentsAtIndex(0, &row, &column, &row_extents, + &column_extents, &is_selected)); + + EXPECT_EQ(row, 0); + EXPECT_EQ(column, 0); + EXPECT_EQ(row_extents, 0); + EXPECT_EQ(column_extents, 0); + + EXPECT_EQ(E_INVALIDARG, + result->get_rowColumnExtentsAtIndex(-1, &row, &column, &row_extents, + &column_extents, &is_selected)); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetCellAt) { + Build3X3Table(); + + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible()); + + ScopedComPtr<IAccessibleTable2> result; + root_obj.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + { + ScopedComPtr<IUnknown> cell; + EXPECT_EQ(S_OK, result->get_cellAt(1, 1, cell.GetAddressOf())); + CheckIUnknownHasName(cell, L"1"); + } + + { + ScopedComPtr<IUnknown> cell; + EXPECT_EQ(E_INVALIDARG, result->get_cellAt(-1, -1, cell.GetAddressOf())); + } +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableCellGetColumnExtent) { + Build3X3Table(); + + ScopedComPtr<IAccessibleTableCell> cell = GetCellInTable(); + ASSERT_NE(nullptr, cell); + + long column_spanned; + EXPECT_EQ(S_OK, cell->get_columnExtent(&column_spanned)); + EXPECT_EQ(column_spanned, 1); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableCellGetColumnHeaderCells) { + Build3X3Table(); + + ScopedComPtr<IAccessibleTableCell> cell = GetCellInTable(); + ASSERT_NE(nullptr, cell); + + IUnknown** cell_accessibles; + + long number_cells; + EXPECT_EQ(S_OK, + cell->get_columnHeaderCells(&cell_accessibles, &number_cells)); + EXPECT_EQ(number_cells, 1); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableCellGetColumnIndex) { + Build3X3Table(); + + ScopedComPtr<IAccessibleTableCell> cell = GetCellInTable(); + ASSERT_NE(nullptr, cell); + + long index; + EXPECT_EQ(S_OK, cell->get_columnIndex(&index)); + EXPECT_EQ(index, 0); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableCellGetRowExtent) { + Build3X3Table(); + + ScopedComPtr<IAccessibleTableCell> cell = GetCellInTable(); + ASSERT_NE(nullptr, cell); + + long rows_spanned; + EXPECT_EQ(S_OK, cell->get_rowExtent(&rows_spanned)); + EXPECT_EQ(rows_spanned, 1); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableCellGetRowHeaderCells) { + Build3X3Table(); + + ScopedComPtr<IAccessibleTableCell> cell = GetCellInTable(); + ASSERT_NE(nullptr, cell); + + IUnknown** cell_accessibles; + + long number_cells; + EXPECT_EQ(S_OK, cell->get_rowHeaderCells(&cell_accessibles, &number_cells)); + + // Since we do not have AX_ATTR_TABLE_CELL_ROW_INDEX set, the evaluated row + // will be 0. In this case, we do not expect any row headers. + EXPECT_EQ(number_cells, 0); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableCellGetRowIndex) { + Build3X3Table(); + + ScopedComPtr<IAccessibleTableCell> cell = GetCellInTable(); + ASSERT_NE(nullptr, cell); + + long index; + EXPECT_EQ(S_OK, cell->get_rowIndex(&index)); + EXPECT_EQ(index, 0); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableCellGetRowColumnExtent) { + Build3X3Table(); + + ScopedComPtr<IAccessibleTableCell> cell = GetCellInTable(); + ASSERT_NE(nullptr, cell); + + long row, column, row_extents, column_extents; + boolean is_selected; + EXPECT_EQ(S_OK, cell->get_rowColumnExtents(&row, &column, &row_extents, + &column_extents, &is_selected)); + EXPECT_EQ(row, 0); + EXPECT_EQ(column, 0); + EXPECT_EQ(row_extents, 1); + EXPECT_EQ(column_extents, 1); +} + +TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableCellGetTable) { + Build3X3Table(); + + ScopedComPtr<IAccessibleTableCell> cell = GetCellInTable(); + ASSERT_NE(nullptr, cell); + + ScopedComPtr<IUnknown> table; + EXPECT_EQ(S_OK, cell->get_table(table.GetAddressOf())); + + ScopedComPtr<IAccessibleTable> result; + table.CopyTo(result.GetAddressOf()); + ASSERT_NE(nullptr, result); + + // Check to make sure that this is the right table by checking one cell. + ScopedComPtr<IUnknown> cell_1; + EXPECT_EQ(S_OK, result->get_accessibleAt(1, 1, cell_1.GetAddressOf())); + CheckIUnknownHasName(cell_1, L"1"); +} + } // namespace ui
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc index d1e33c7..e0b153ef 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.cc +++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -141,7 +141,28 @@ return nullptr; } +// Walk the AXTree and ensure that all wrappers are created +void TestAXNodeWrapper::BuildAllWrappers(AXTree* tree, AXNode* node) { + for (int i = 0; i < node->child_count(); i++) { + auto* child = node->children()[i]; + TestAXNodeWrapper::GetOrCreate(tree, child); + + BuildAllWrappers(tree, child); + } +} + AXPlatformNode* TestAXNodeWrapper::GetFromNodeID(int32_t id) { + // Force creating all of the wrappers for this tree. + BuildAllWrappers(tree_, node_); + + for (auto it = g_node_to_wrapper_map.begin(); + it != g_node_to_wrapper_map.end(); ++it) { + AXNode* node = it->first; + if (node->id() == id) { + TestAXNodeWrapper* wrapper = it->second; + return wrapper->ax_platform_node(); + } + } return nullptr; }
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h index 1e6da236..9ce258e3 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.h +++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -28,6 +28,8 @@ AXPlatformNode* ax_platform_node() { return platform_node_; } + void BuildAllWrappers(AXTree* tree, AXNode* node); + // AXPlatformNodeDelegate. const AXNodeData& GetData() const override; const ui::AXTreeData& GetTreeData() const override;
diff --git a/ui/arc/notification/arc_notification_delegate.cc b/ui/arc/notification/arc_notification_delegate.cc index fae1302..d13c3446 100644 --- a/ui/arc/notification/arc_notification_delegate.cc +++ b/ui/arc/notification/arc_notification_delegate.cc
@@ -51,4 +51,9 @@ return true; } +bool ArcNotificationDelegate::ShouldDisplaySettingsButton() { + DCHECK(item_); + return item_->IsOpeningSettingsSupported(); +} + } // namespace arc
diff --git a/ui/arc/notification/arc_notification_delegate.h b/ui/arc/notification/arc_notification_delegate.h index 9241fcec..48df295 100644 --- a/ui/arc/notification/arc_notification_delegate.h +++ b/ui/arc/notification/arc_notification_delegate.h
@@ -33,6 +33,7 @@ void Close(bool by_user) override; void Click() override; bool SettingsClick() override; + bool ShouldDisplaySettingsButton() override; private: // The destructor is private since this class is ref-counted.
diff --git a/ui/keyboard/content/keyboard_ui_content_unittest.cc b/ui/keyboard/content/keyboard_ui_content_unittest.cc index bbac466c..b9f295d 100644 --- a/ui/keyboard/content/keyboard_ui_content_unittest.cc +++ b/ui/keyboard/content/keyboard_ui_content_unittest.cc
@@ -22,7 +22,6 @@ ~TestKeyboardUIContent() override {} ui::InputMethod* GetInputMethod() override { return nullptr; } - void SetUpdateInputType(ui::TextInputType type) override {} void RequestAudioInput( content::WebContents* web_contents, const content::MediaStreamRequest& request,
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc index 3951c2a4..61cd6cb 100644 --- a/ui/keyboard/keyboard_controller.cc +++ b/ui/keyboard/keyboard_controller.cc
@@ -541,7 +541,6 @@ keyboard_visible_ = true; ChangeState(KeyboardControllerState::SHOWN); } - ui_->SetUpdateInputType(type); // Do not explicitly show the Virtual keyboard unless it is in the process // of hiding. Instead, the virtual keyboard is shown in response to a user // gesture (mouse or touch) that is received while an element has input
diff --git a/ui/keyboard/keyboard_controller_unittest.cc b/ui/keyboard/keyboard_controller_unittest.cc index 5822a8f..c3ba4cc 100644 --- a/ui/keyboard/keyboard_controller_unittest.cc +++ b/ui/keyboard/keyboard_controller_unittest.cc
@@ -135,7 +135,6 @@ return window_.get(); } ui::InputMethod* GetInputMethod() override { return input_method_; } - void SetUpdateInputType(ui::TextInputType type) override {} void ReloadKeyboardIfNeeded() override {} void InitInsets(const gfx::Rect& keyboard_bounds) override {} void ResetInsets() override {}
diff --git a/ui/keyboard/keyboard_ui.h b/ui/keyboard/keyboard_ui.h index b4fc21c6..8399c85 100644 --- a/ui/keyboard/keyboard_ui.h +++ b/ui/keyboard/keyboard_ui.h
@@ -55,9 +55,6 @@ // necesasry animation, or delay the visibility change as it desires. virtual void HideKeyboardContainer(aura::Window* container); - // Updates the type of the focused text input box. - virtual void SetUpdateInputType(ui::TextInputType type) = 0; - // Ensures caret in current work area (not occluded by virtual keyboard // window). virtual void EnsureCaretInWorkArea();
diff --git a/ui/views/controls/button/checkbox.cc b/ui/views/controls/button/checkbox.cc index a21d406d..d3535f0 100644 --- a/ui/views/controls/button/checkbox.cc +++ b/ui/views/controls/button/checkbox.cc
@@ -14,9 +14,11 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/native_theme/native_theme.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/controls/button/label_button_border.h" +#include "ui/views/controls/focus_ring.h" #include "ui/views/layout/layout_provider.h" #include "ui/views/painter.h" #include "ui/views/resources/grit/views_resources.h" @@ -25,6 +27,45 @@ namespace views { +// View used to paint the focus ring around the Checkbox icon. +// The icon is painted separately. +class IconFocusRing : public View { + public: + explicit IconFocusRing(Checkbox* checkbox); + ~IconFocusRing() override = default; + + private: + // View: + void Layout() override; + void OnPaint(gfx::Canvas* canvas) override; + + Checkbox* checkbox_; + + DISALLOW_COPY_AND_ASSIGN(IconFocusRing); +}; + +IconFocusRing::IconFocusRing(Checkbox* checkbox) : checkbox_(checkbox) { + FocusRing::InitFocusRing(this); +} + +void IconFocusRing::Layout() { + gfx::Rect focus_bounds = checkbox_->image()->bounds(); + focus_bounds.Inset(gfx::Insets(-2.f)); + SetBoundsRect(focus_bounds); +} + +void IconFocusRing::OnPaint(gfx::Canvas* canvas) { + cc::PaintFlags focus_flags; + focus_flags.setAntiAlias(true); + focus_flags.setColor( + SkColorSetA(GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_FocusedBorderColor), + 0x66)); + focus_flags.setStyle(cc::PaintFlags::kStroke_Style); + focus_flags.setStrokeWidth(2); + checkbox_->PaintFocusRing(this, canvas, focus_flags); +} + // static const char Checkbox::kViewClassName[] = "Checkbox"; @@ -39,6 +80,9 @@ set_request_focus_on_press(false); SetInkDropMode(InkDropMode::ON); set_has_ink_drop_action_on_click(true); + focus_ring_ = new IconFocusRing(this); + focus_ring_->SetVisible(false); + AddChildView(focus_ring_); } else { std::unique_ptr<LabelButtonBorder> button_border(new LabelButtonBorder()); // Inset the trailing side by a couple pixels for the focus border. @@ -128,12 +172,16 @@ LabelButton::OnFocus(); if (!UseMd()) UpdateImage(); + else + focus_ring_->SetVisible(true); } void Checkbox::OnBlur() { LabelButton::OnBlur(); if (!UseMd()) UpdateImage(); + else + focus_ring_->SetVisible(false); } void Checkbox::OnNativeThemeChanged(const ui::NativeTheme* theme) { @@ -161,21 +209,6 @@ ui::NativeTheme::kColorId_LabelEnabledColor); } -void Checkbox::PaintButtonContents(gfx::Canvas* canvas) { - if (!UseMd() || !HasFocus()) - return; - - cc::PaintFlags focus_flags; - focus_flags.setAntiAlias(true); - focus_flags.setColor( - SkColorSetA(GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_FocusedBorderColor), - 0x66)); - focus_flags.setStyle(cc::PaintFlags::kStroke_Style); - focus_flags.setStrokeWidth(2); - PaintFocusRing(canvas, focus_flags); -} - gfx::ImageSkia Checkbox::GetImage(ButtonState for_state) const { if (UseMd()) { return gfx::CreateVectorIcon( @@ -212,10 +245,10 @@ UpdateImage(); } -void Checkbox::PaintFocusRing(gfx::Canvas* canvas, +void Checkbox::PaintFocusRing(View* view, + gfx::Canvas* canvas, const cc::PaintFlags& flags) { - gfx::RectF focus_rect(image()->bounds()); - canvas->DrawRoundRect(focus_rect, 2.f, flags); + canvas->DrawRoundRect(view->GetLocalBounds(), 2.f, flags); } const gfx::VectorIcon& Checkbox::GetVectorIcon() const {
diff --git a/ui/views/controls/button/checkbox.h b/ui/views/controls/button/checkbox.h index 9622387..deb26a2 100644 --- a/ui/views/controls/button/checkbox.h +++ b/ui/views/controls/button/checkbox.h
@@ -49,7 +49,6 @@ std::unique_ptr<InkDrop> CreateInkDrop() override; std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override; SkColor GetInkDropBaseColor() const override; - void PaintButtonContents(gfx::Canvas* canvas) override; gfx::ImageSkia GetImage(ButtonState for_state) const override; std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const override; @@ -60,13 +59,17 @@ ButtonState for_state, const gfx::ImageSkia& image); - // Paints a focus indicator for the view. - virtual void PaintFocusRing(gfx::Canvas* canvas, const cc::PaintFlags& flags); + // Paints a focus indicator for the view. Overridden in RadioButton. + virtual void PaintFocusRing(View* view, + gfx::Canvas* canvas, + const cc::PaintFlags& flags); // Gets the vector icon to use based on the current state of |checked_|. virtual const gfx::VectorIcon& GetVectorIcon() const; private: + friend class IconFocusRing; + // Button: void NotifyClick(const ui::Event& event) override; @@ -76,6 +79,9 @@ // True if the checkbox is checked. bool checked_; + // FocusRing used in MD mode + View* focus_ring_ = nullptr; + // The images for each button node_data. gfx::ImageSkia images_[2][2][STATE_COUNT];
diff --git a/ui/views/controls/button/radio_button.cc b/ui/views/controls/button/radio_button.cc index ff6aaf60..aea68cf 100644 --- a/ui/views/controls/button/radio_button.cc +++ b/ui/views/controls/button/radio_button.cc
@@ -138,9 +138,10 @@ Checkbox::SetChecked(checked); } -void RadioButton::PaintFocusRing(gfx::Canvas* canvas, +void RadioButton::PaintFocusRing(View* view, + gfx::Canvas* canvas, const cc::PaintFlags& flags) { - canvas->DrawCircle(gfx::RectF(image()->bounds()).CenterPoint(), + canvas->DrawCircle(gfx::RectF(view->GetLocalBounds()).CenterPoint(), image()->width() / 2, flags); }
diff --git a/ui/views/controls/button/radio_button.h b/ui/views/controls/button/radio_button.h index 5117b69..8ce77391 100644 --- a/ui/views/controls/button/radio_button.h +++ b/ui/views/controls/button/radio_button.h
@@ -35,7 +35,8 @@ // Overridden from Checkbox: void SetChecked(bool checked) override; - void PaintFocusRing(gfx::Canvas* canvas, + void PaintFocusRing(View* view, + gfx::Canvas* canvas, const cc::PaintFlags& flags) override; const gfx::VectorIcon& GetVectorIcon() const override;
diff --git a/ui/views/controls/focus_ring.cc b/ui/views/controls/focus_ring.cc index b905823..a5a44ba 100644 --- a/ui/views/controls/focus_ring.cc +++ b/ui/views/controls/focus_ring.cc
@@ -5,7 +5,6 @@ #include "ui/views/controls/focus_ring.h" #include "ui/gfx/canvas.h" -#include "ui/native_theme/native_theme.h" #include "ui/views/controls/focusable_border.h" namespace views { @@ -21,7 +20,7 @@ constexpr float kFocusHaloCornerRadiusDp = FocusableBorder::kCornerRadiusDp + kFocusHaloThicknessDp / 2.f; -FocusRing* GetFocusRing(views::View* parent) { +FocusRing* GetFocusRing(View* parent) { for (int i = 0; i < parent->child_count(); ++i) { if (parent->child_at(i)->GetClassName() == FocusRing::kViewClassName) return static_cast<FocusRing*>(parent->child_at(i)); @@ -34,7 +33,7 @@ const char FocusRing::kViewClassName[] = "FocusRing"; // static -views::View* FocusRing::Install(views::View* parent, +views::View* FocusRing::Install(View* parent, ui::NativeTheme::ColorId override_color_id) { FocusRing* ring = GetFocusRing(parent); if (!ring) { @@ -48,18 +47,23 @@ } // static -void FocusRing::Uninstall(views::View* parent) { +void FocusRing::Uninstall(View* parent) { delete GetFocusRing(parent); } +// static +void FocusRing::InitFocusRing(View* view) { + // A layer is necessary to paint beyond the parent's bounds. + view->SetPaintToLayer(); + view->layer()->SetFillsBoundsOpaquely(false); + // Don't allow the view to process events. + view->set_can_process_events_within_subtree(false); +} + const char* FocusRing::GetClassName() const { return kViewClassName; } -bool FocusRing::CanProcessEventsWithinSubtree() const { - return false; -} - void FocusRing::Layout() { // The focus ring handles its own sizing, which is simply to fill the parent // and extend a little beyond its borders. @@ -86,9 +90,7 @@ FocusRing::FocusRing() : override_color_id_(ui::NativeTheme::kColorId_NumColors) { - // A layer is necessary to paint beyond the parent's bounds. - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); + InitFocusRing(this); } FocusRing::~FocusRing() {}
diff --git a/ui/views/controls/focus_ring.h b/ui/views/controls/focus_ring.h index 53aa19d3..f6ecc2a 100644 --- a/ui/views/controls/focus_ring.h +++ b/ui/views/controls/focus_ring.h
@@ -5,7 +5,6 @@ #ifndef UI_VIEWS_CONTROLS_FOCUS_RING_H_ #define UI_VIEWS_CONTROLS_FOCUS_RING_H_ -#include "base/optional.h" #include "ui/native_theme/native_theme.h" #include "ui/views/view.h" @@ -21,23 +20,26 @@ // Create a FocusRing and adds it to |parent|, or updates the one that already // exists. |override_color_id| will be used in place of the default coloration // when provided. - static View* Install(views::View* parent, - ui::NativeTheme::ColorId override_color_id = - ui::NativeTheme::kColorId_NumColors); + static View* Install(View* parent, + ui::NativeTheme::ColorId override_color_id = + ui::NativeTheme::kColorId_NumColors); // Removes the FocusRing from |parent|. - static void Uninstall(views::View* parent); + static void Uninstall(View* parent); + + // Configure |view| for painting focus ring highlights. + static void InitFocusRing(View* view); // View: const char* GetClassName() const override; - bool CanProcessEventsWithinSubtree() const override; void Layout() override; void OnPaint(gfx::Canvas* canvas) override; - private: + protected: FocusRing(); ~FocusRing() override; + private: ui::NativeTheme::ColorId override_color_id_; DISALLOW_COPY_AND_ASSIGN(FocusRing);
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc index ebd9b19..7cb6b9e 100644 --- a/ui/views/controls/textfield/textfield.cc +++ b/ui/views/controls/textfield/textfield.cc
@@ -975,6 +975,7 @@ GetRenderText()->SetDisplayRect(bounds); OnCaretBoundsChanged(); UpdateCursorViewPosition(); + UpdateCursorVisibility(); } bool Textfield::GetNeedsNotificationWhenVisibleBoundsChange() const {
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc index 7b49cf5..40eb797 100644 --- a/ui/views/controls/textfield/textfield_unittest.cc +++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -3212,6 +3212,7 @@ int prev_x = GetCursorBounds().x(); SendKeyEvent('a'); EXPECT_EQ(prev_x, GetCursorBounds().x()); + EXPECT_TRUE(test_api_->IsCursorVisible()); // Increase the textfield size and check if the cursor moves to the new end. textfield_->SetSize(gfx::Size(40, 100)); @@ -3223,6 +3224,31 @@ EXPECT_GT(prev_x, GetCursorBounds().x()); } +// Verify that after creating a new Textfield, the Textfield doesn't +// automatically receive focus and the text cursor is not visible. +TEST_F(TextfieldTest, TextfieldInitialization) { + TestTextfield* new_textfield = new TestTextfield(); + new_textfield->set_controller(this); + View* container = new View(); + Widget* widget(new Widget()); + Widget::InitParams params = + CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.bounds = gfx::Rect(100, 100, 100, 100); + widget->Init(params); + widget->SetContentsView(container); + container->AddChildView(new_textfield); + + new_textfield->SetBoundsRect(params.bounds); + new_textfield->set_id(1); + test_api_.reset(new TextfieldTestApi(new_textfield)); + widget->Show(); + EXPECT_FALSE(new_textfield->HasFocus()); + EXPECT_FALSE(test_api_->IsCursorVisible()); + new_textfield->RequestFocus(); + EXPECT_TRUE(test_api_->IsCursorVisible()); + widget->Close(); +} + // Verify that if a textfield gains focus during key dispatch that an edit // command only results when the event is not consumed. TEST_F(TextfieldTest, SwitchFocusInKeyDown) {