diff --git a/DEPS b/DEPS index 6a778af5..2aeb209 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'edbeb8b842aa86d18388f75a1dbf1e470a565680', + 'skia_revision': 'c8f1e3a5c08d58657dddccdeedbe5d6e8c16d891', # 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': 'd678037326492171f04895ffb360e16e5248182a', + 'v8_revision': '376fd4b2eb6a1ff398d4a8b58ce1ce9feb5273db', # 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. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '4f3d6da8af75d0aa3b0aa535319c13393269512f', + 'catapult_revision': '78c8d7338e35e82db61513bb2f328c0764d2fe00', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -232,7 +232,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'ecefa58dfa5b471817398f09c332a36e8ed8eeab', # commit position 16890 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '02830c5b02494ae3a4f8dcf45ea5c988dc5e5cf8', # commit position 16899 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/ash/virtual_keyboard_controller.cc b/ash/virtual_keyboard_controller.cc index 32391eb1..b483df6e5 100644 --- a/ash/virtual_keyboard_controller.cc +++ b/ash/virtual_keyboard_controller.cc
@@ -88,6 +88,7 @@ } else { UpdateKeyboardEnabled(); } + keyboard::SetOverscrollEnabledWithAccessibilityKeyboard(true); } void VirtualKeyboardController::OnMaximizeModeEnded() { @@ -96,6 +97,7 @@ } else { UpdateKeyboardEnabled(); } + keyboard::SetOverscrollEnabledWithAccessibilityKeyboard(false); } void VirtualKeyboardController::OnTouchscreenDeviceConfigurationChanged() {
diff --git a/cc/surfaces/compositor_frame_sink_support_unittest.cc b/cc/surfaces/compositor_frame_sink_support_unittest.cc index 5e8f1fc..efa9b1b 100644 --- a/cc/surfaces/compositor_frame_sink_support_unittest.cc +++ b/cc/surfaces/compositor_frame_sink_support_unittest.cc
@@ -111,10 +111,9 @@ return surface_manager().parent_to_child_refs_[surface_id]; } - // Returns all the temporary references for the given frame sink id. - std::vector<LocalSurfaceId> GetTempReferences( - const FrameSinkId& frame_sink_id) { - return surface_manager().temp_references_[frame_sink_id]; + // Returns true if there is a temporary reference for |surface_id|. + bool HasTemporaryReference(const SurfaceId& surface_id) { + return surface_manager().HasTemporaryReference(surface_id); } SurfaceDependencyTracker& dependency_tracker() { @@ -197,7 +196,7 @@ // A surface reference from the top-level root is added and there shouldn't be // a temporary reference. - EXPECT_THAT(GetTempReferences(kDisplayFrameSink), IsEmpty()); + EXPECT_FALSE(HasTemporaryReference(display_id_first)); EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()), UnorderedElementsAre(display_id_first)); @@ -208,7 +207,7 @@ // A surface reference from the top-level root to |display_id_second| should // be added and the reference to |display_root_first| removed. - EXPECT_THAT(GetTempReferences(kDisplayFrameSink), IsEmpty()); + EXPECT_FALSE(HasTemporaryReference(display_id_second)); EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()), UnorderedElementsAre(display_id_second)); @@ -612,7 +611,7 @@ // Verify that there is no temporary reference for the child and that // the reference from the parent to the child still exists. - EXPECT_THAT(GetTempReferences(child_id.frame_sink_id()), IsEmpty()); + EXPECT_FALSE(HasTemporaryReference(child_id)); EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id)); } @@ -695,7 +694,7 @@ // Verify that there is no temporary reference for the child and that // the reference from the parent to the child still exists. - EXPECT_THAT(GetTempReferences(child_id1.frame_sink_id()), IsEmpty()); + EXPECT_FALSE(HasTemporaryReference(child_id1)); EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1)); // The parent submits another CompositorFrame that depends on |child_id2|.
diff --git a/cc/surfaces/surface_manager.cc b/cc/surfaces/surface_manager.cc index 776ac2a4..e73e814 100644 --- a/cc/surfaces/surface_manager.cc +++ b/cc/surfaces/surface_manager.cc
@@ -47,15 +47,11 @@ SurfaceManager::~SurfaceManager() { DCHECK(thread_checker_.CalledOnValidThread()); - if (lifetime_type_ == LifetimeType::REFERENCES) { + if (using_surface_references()) { // Remove all temporary references on shutdown. - for (const auto& map_entry : temp_references_) { - const FrameSinkId& frame_sink_id = map_entry.first; - for (const auto& local_surface_id : map_entry.second) { - RemoveSurfaceReferenceImpl(GetRootSurfaceId(), - SurfaceId(frame_sink_id, local_surface_id)); - } - } + temporary_references_.clear(); + temporary_reference_ranges_.clear(); + GarbageCollectSurfaces(); } @@ -76,6 +72,10 @@ std::string SurfaceManager::SurfaceReferencesToString() { std::stringstream str; SurfaceReferencesToStringImpl(root_surface_id_, "", &str); + // Temporary references will have an asterisk in front of them. + for (auto& map_entry : temporary_references_) + SurfaceReferencesToStringImpl(map_entry.first, "* ", &str); + return str.str(); } #endif @@ -136,6 +136,20 @@ void SurfaceManager::InvalidateFrameSinkId(const FrameSinkId& frame_sink_id) { valid_frame_sink_ids_.erase(frame_sink_id); + + if (using_surface_references()) { + // Remove any temporary references owned by |frame_sink_id|. + std::vector<SurfaceId> temp_refs_to_clear; + for (auto& map_entry : temporary_references_) { + base::Optional<FrameSinkId>& owner = map_entry.second; + if (owner.has_value() && owner.value() == frame_sink_id) + temp_refs_to_clear.push_back(map_entry.first); + } + + for (auto& surface_id : temp_refs_to_clear) + RemoveTemporaryReference(surface_id, false); + } + GarbageCollectSurfaces(); } @@ -143,107 +157,52 @@ return root_surface_id_; } -void SurfaceManager::AddSurfaceReference(const SurfaceId& parent_id, - const SurfaceId& child_id) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES); - - // Check some conditions that should never happen. We don't want to crash on - // bad input from a compromised client so just return early. - if (parent_id.frame_sink_id() == child_id.frame_sink_id()) { - DLOG(ERROR) << "Cannot add self reference from " << parent_id << " to " - << child_id; - return; - } - - // There could be a temporary reference to |child_id| which we should now - // remove because a real reference is being added to it. To find out whether - // or not a temporary reference exists, we need to first look up the - // FrameSinkId of |child_id| in |temp_references_|, which returns a vector of - // LocalSurfaceIds, and then search for the LocalSurfaceId of |child_id| in - // the said vector. If there is no temporary reference, we can immediately add - // the reference from |parent_id| and return. - auto refs_iter = temp_references_.find(child_id.frame_sink_id()); - if (refs_iter == temp_references_.end()) { - AddSurfaceReferenceImpl(parent_id, child_id); - return; - } - std::vector<LocalSurfaceId>& refs = refs_iter->second; - auto temp_ref_iter = - std::find(refs.begin(), refs.end(), child_id.local_surface_id()); - if (temp_ref_iter == refs.end()) { - AddSurfaceReferenceImpl(parent_id, child_id); - return; - } - - // Temporary references are implemented by holding a reference from the top - // level root to the child. If |parent_id| is the top level root, we do - // nothing because the reference already exists. Otherwise, remove the - // temporary reference and add the reference. - if (parent_id != GetRootSurfaceId()) { - AddSurfaceReferenceImpl(parent_id, child_id); - RemoveSurfaceReference(GetRootSurfaceId(), child_id); - } - - // Remove temporary references for surfaces with the same FrameSinkId that - // were created before |child_id|. The earlier surfaces were never embedded in - // the parent and the parent is embedding a later surface, so we know the - // parent doesn't need them anymore. - for (auto iter = refs.begin(); iter != temp_ref_iter; ++iter) { - SurfaceId id = SurfaceId(child_id.frame_sink_id(), *iter); - RemoveSurfaceReference(GetRootSurfaceId(), id); - } - - // Remove markers for temporary references up to |child_id|, as the temporary - // references they correspond to were removed above. If |temp_ref_iter| points - // at the last element in |refs| then we are removing all temporary references - // for the FrameSinkId and can remove the map entry entirely. - if (++temp_ref_iter == refs.end()) - temp_references_.erase(child_id.frame_sink_id()); - else - refs.erase(refs.begin(), temp_ref_iter); -} - -void SurfaceManager::RemoveSurfaceReference(const SurfaceId& parent_id, - const SurfaceId& child_id) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES); - - // Check if we have the reference that is requested to be removed. We don't - // want to crash on bad input from a compromised client so just return early. - if (parent_to_child_refs_.count(parent_id) == 0 || - parent_to_child_refs_[parent_id].count(child_id) == 0) { - DLOG(ERROR) << "No reference from " << parent_id.ToString() << " to " - << child_id.ToString(); - return; - } - - RemoveSurfaceReferenceImpl(parent_id, child_id); -} - void SurfaceManager::AddSurfaceReferences( const std::vector<SurfaceReference>& references) { DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(using_surface_references()); for (const auto& reference : references) - AddSurfaceReference(reference.parent_id(), reference.child_id()); + AddSurfaceReferenceImpl(reference.parent_id(), reference.child_id()); } void SurfaceManager::RemoveSurfaceReferences( const std::vector<SurfaceReference>& references) { DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(using_surface_references()); for (const auto& reference : references) - RemoveSurfaceReference(reference.parent_id(), reference.child_id()); + RemoveSurfaceReferenceImpl(reference.parent_id(), reference.child_id()); GarbageCollectSurfaces(); } +void SurfaceManager::AssignTemporaryReference(const SurfaceId& surface_id, + const FrameSinkId& owner) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES); + + if (!HasTemporaryReference(surface_id)) + return; + + temporary_references_[surface_id] = owner; +} + +void SurfaceManager::DropTemporaryReference(const SurfaceId& surface_id) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES); + + if (!HasTemporaryReference(surface_id)) + return; + + RemoveTemporaryReference(surface_id, false); +} + void SurfaceManager::GarbageCollectSurfaces() { if (surfaces_to_destroy_.empty()) return; - SurfaceIdSet reachable_surfaces = lifetime_type_ == LifetimeType::REFERENCES + SurfaceIdSet reachable_surfaces = using_surface_references() ? GetLiveSurfacesForReferences() : GetLiveSurfacesForSequences(); @@ -267,13 +226,20 @@ } SurfaceManager::SurfaceIdSet SurfaceManager::GetLiveSurfacesForReferences() { - DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES); + DCHECK(using_surface_references()); SurfaceIdSet reachable_surfaces; // Walk down from the root and mark each SurfaceId we encounter as reachable. std::queue<SurfaceId> surface_queue; surface_queue.push(root_surface_id_); + + // All temporary references are also reachable. + for (auto& map_entry : temporary_references_) { + reachable_surfaces.insert(map_entry.first); + surface_queue.push(map_entry.first); + } + while (!surface_queue.empty()) { const SurfaceId& surface_id = surface_queue.front(); auto iter = parent_to_child_refs_.find(surface_id); @@ -341,12 +307,27 @@ void SurfaceManager::AddSurfaceReferenceImpl(const SurfaceId& parent_id, const SurfaceId& child_id) { + if (parent_id.frame_sink_id() == child_id.frame_sink_id()) { + DLOG(ERROR) << "Cannot add self reference from " << parent_id << " to " + << child_id; + return; + } + parent_to_child_refs_[parent_id].insert(child_id); child_to_parent_refs_[child_id].insert(parent_id); + + if (HasTemporaryReference(child_id)) + RemoveTemporaryReference(child_id, true); } void SurfaceManager::RemoveSurfaceReferenceImpl(const SurfaceId& parent_id, const SurfaceId& child_id) { + if (parent_to_child_refs_.count(parent_id) == 0 || + parent_to_child_refs_[parent_id].count(child_id) == 0) { + DLOG(ERROR) << "No reference from " << parent_id << " to " << child_id; + return; + } + parent_to_child_refs_[parent_id].erase(child_id); child_to_parent_refs_[child_id].erase(parent_id); } @@ -369,6 +350,50 @@ } } +bool SurfaceManager::HasTemporaryReference(const SurfaceId& surface_id) const { + return temporary_references_.count(surface_id) != 0; +} + +void SurfaceManager::AddTemporaryReference(const SurfaceId& surface_id) { + DCHECK(!HasTemporaryReference(surface_id)); + + // Add an entry to |temporary_references_| with no owner for the temporary + // reference. Also add a range tracking entry so we know the order that + // surfaces were created for the FrameSinkId. + temporary_references_[surface_id] = base::Optional<FrameSinkId>(); + temporary_reference_ranges_[surface_id.frame_sink_id()].push_back( + surface_id.local_surface_id()); +} + +void SurfaceManager::RemoveTemporaryReference(const SurfaceId& surface_id, + bool remove_range) { + DCHECK(HasTemporaryReference(surface_id)); + + const FrameSinkId& frame_sink_id = surface_id.frame_sink_id(); + std::vector<LocalSurfaceId>& frame_sink_temp_refs = + temporary_reference_ranges_[frame_sink_id]; + + // Find the iterator to the range tracking entry for |surface_id|. Use that + // iterator and |remove_range| to find the right begin and end iterators for + // the temporary references we want to remove. + auto surface_id_iter = + std::find(frame_sink_temp_refs.begin(), frame_sink_temp_refs.end(), + surface_id.local_surface_id()); + auto begin_iter = + remove_range ? frame_sink_temp_refs.begin() : surface_id_iter; + auto end_iter = surface_id_iter + 1; + + // Remove temporary references and range tracking information. + for (auto iter = begin_iter; iter != end_iter; ++iter) + temporary_references_.erase(SurfaceId(frame_sink_id, *iter)); + frame_sink_temp_refs.erase(begin_iter, end_iter); + + // If last temporary reference is removed for |frame_sink_id| then cleanup + // range tracking map entry. + if (frame_sink_temp_refs.empty()) + temporary_reference_ranges_.erase(frame_sink_id); +} + void SurfaceManager::RegisterSurfaceFactoryClient( const FrameSinkId& frame_sink_id, SurfaceFactoryClient* client) { @@ -586,11 +611,8 @@ // use array notation into maps in tests (see https://crbug.com/691115). bool has_real_reference = it != child_to_parent_refs_.end() && !it->second.empty(); - if (!has_real_reference) { - AddSurfaceReferenceImpl(GetRootSurfaceId(), surface_info.id()); - temp_references_[surface_info.id().frame_sink_id()].push_back( - surface_info.id().local_surface_id()); - } + if (!has_real_reference) + AddTemporaryReference(surface_info.id()); } for (auto& observer : observer_list_) @@ -607,21 +629,24 @@ Surface* surface = GetSurfaceForId(surface_id); if (surface) { *str << surface->surface_id().ToString(); - *str << (surface->destroyed() ? " destroyed " : " live "); + *str << (surface->destroyed() ? " destroyed" : " live"); if (surface->HasPendingFrame()) { // This provides the surface size from the root render pass. const CompositorFrame& frame = surface->GetPendingFrame(); - *str << "pending " - << frame.render_pass_list.back()->output_rect.size().ToString() - << " "; + if (!frame.render_pass_list.empty()) { + *str << " pending " + << frame.render_pass_list.back()->output_rect.size().ToString(); + } } if (surface->HasActiveFrame()) { // This provides the surface size from the root render pass. const CompositorFrame& frame = surface->GetActiveFrame(); - *str << "active " - << frame.render_pass_list.back()->output_rect.size().ToString(); + if (!frame.render_pass_list.empty()) { + *str << " active " + << frame.render_pass_list.back()->output_rect.size().ToString(); + } } } else { *str << surface_id;
diff --git a/cc/surfaces/surface_manager.h b/cc/surfaces/surface_manager.h index b4785a2..569c6e44 100644 --- a/cc/surfaces/surface_manager.h +++ b/cc/surfaces/surface_manager.h
@@ -139,15 +139,6 @@ // SurfaceId and will never correspond to a surface. const SurfaceId& GetRootSurfaceId() const; - // Adds a reference from |parent_id| to |child_id|. If there is a temporary - // references for |child_id| then it will be removed. - void AddSurfaceReference(const SurfaceId& parent_id, - const SurfaceId& child_id); - - // Removes a reference from |parent_id| to |child_id|. - void RemoveSurfaceReference(const SurfaceId& parent_id, - const SurfaceId& child_id); - // Adds all surface references in |references|. This will remove any temporary // references for child surface in a surface reference. void AddSurfaceReferences(const std::vector<SurfaceReference>& references); @@ -156,6 +147,18 @@ // collection to delete unreachable surfaces. void RemoveSurfaceReferences(const std::vector<SurfaceReference>& references); + // Assigns |frame_sink_id| as the owner of the temporary reference to + // |surface_id|. If |frame_sink_id| is invalidated the temporary reference + // will be removed. If a surface reference has already been added from the + // parent to |surface_id| then this will do nothing. + void AssignTemporaryReference(const SurfaceId& surface_id, + const FrameSinkId& owner); + + // Drops the temporary reference for |surface_id|. If a surface reference has + // already been added from the parent to |surface_id| then this will do + // nothing. + void DropTemporaryReference(const SurfaceId& surface_id); + scoped_refptr<SurfaceReferenceFactory> reference_factory() { return reference_factory_; } @@ -202,6 +205,17 @@ // surface is about to be deleted. void RemoveAllSurfaceReferences(const SurfaceId& surface_id); + bool HasTemporaryReference(const SurfaceId& surface_id) const; + + // Adds a temporary reference to |surface_id|. The reference will not have an + // owner initially. + void AddTemporaryReference(const SurfaceId& surface_id); + + // Removes temporary reference to |surface_id|. If |remove_range| is true then + // all temporary references to surfaces with the same FrameSinkId as + // |surface_id| that were added before |surface_id| will also be removed. + void RemoveTemporaryReference(const SurfaceId& surface_id, bool remove_range); + #if DCHECK_IS_ON() // Recursively prints surface references starting at |surface_id| to |str|. void SurfaceReferencesToStringImpl(const SurfaceId& surface_id, @@ -271,13 +285,23 @@ // references. scoped_refptr<SurfaceReferenceFactory> reference_factory_; - // SurfaceIds that have temporary references from top level root so they - // aren't GC'd before a real reference is added. This is basically a - // collection of surface ids, for example: + // A map of surfaces that have temporary references to them. The key is the + // SurfaceId and the value is the owner. The owner will initially be empty and + // set later by AssignTemporaryReference(). + std::unordered_map<SurfaceId, base::Optional<FrameSinkId>, SurfaceIdHash> + temporary_references_; + + // Range tracking information for temporary references. Each map entry is an + // is an ordered list of SurfaceIds that have temporary references with the + // same FrameSinkId. A SurfaceId can be reconstructed with: // SurfaceId surface_id(key, value[index]); - // The LocalSurfaceIds are stored in the order the surfaces are created in. + // The LocalSurfaceIds are stored in the order the surfaces are created in. If + // a reference is added to a later SurfaceId then all temporary references up + // to that point will be removed. This is to handle clients getting out of + // sync, for example the embedded client producing new SurfaceIds faster than + // the embedding client can use them. std::unordered_map<FrameSinkId, std::vector<LocalSurfaceId>, FrameSinkIdHash> - temp_references_; + temporary_reference_ranges_; std::unique_ptr<SurfaceDependencyTracker> dependency_tracker_;
diff --git a/cc/surfaces/surface_manager_ref_unittest.cc b/cc/surfaces/surface_manager_ref_unittest.cc index 5f68c16..fb21ce3 100644 --- a/cc/surfaces/surface_manager_ref_unittest.cc +++ b/cc/surfaces/surface_manager_ref_unittest.cc
@@ -71,6 +71,11 @@ manager_->RemoveSurfaceReferences({SurfaceReference(parent_id, child_id)}); } + void AddSurfaceReference(const SurfaceId& parent_id, + const SurfaceId& child_id) { + manager_->AddSurfaceReferences({SurfaceReference(parent_id, child_id)}); + } + // Returns all the references where |surface_id| is the parent. const SurfaceManager::SurfaceIdSet& GetReferencesFrom( const SurfaceId& surface_id) { @@ -83,24 +88,12 @@ return manager().child_to_parent_refs_[surface_id]; } - const SurfaceManager::SurfaceIdSet& GetReferencesFromRoot() { - return GetReferencesFrom(manager().GetRootSurfaceId()); - } - - // Returns all the temporary references for the given frame sink id. - std::vector<LocalSurfaceId> GetTempReferencesFor( - const FrameSinkId& frame_sink_id) { - return manager().temp_references_[frame_sink_id]; - } - // Temporary references are stored as a map in SurfaceManager. This method // converts the map to a vector. std::vector<SurfaceId> GetAllTempReferences() { std::vector<SurfaceId> temp_references; - for (auto& map_entry : manager().temp_references_) { - for (auto local_surface_id : map_entry.second) - temp_references.push_back(SurfaceId(map_entry.first, local_surface_id)); - } + for (auto& map_entry : manager().temporary_references_) + temp_references.push_back(map_entry.first); return temp_references; } @@ -128,7 +121,7 @@ TEST_F(SurfaceManagerRefTest, AddReference) { SurfaceId id1 = CreateSurface(kFrameSink1, 1); - manager().AddSurfaceReference(manager().GetRootSurfaceId(), id1); + AddSurfaceReference(manager().GetRootSurfaceId(), id1); EXPECT_THAT(GetReferencesFor(id1), UnorderedElementsAre(manager().GetRootSurfaceId())); @@ -138,8 +131,8 @@ TEST_F(SurfaceManagerRefTest, AddRemoveReference) { SurfaceId id1 = CreateSurface(kFrameSink1, 1); SurfaceId id2 = CreateSurface(kFrameSink2, 1); - manager().AddSurfaceReference(manager().GetRootSurfaceId(), id1); - manager().AddSurfaceReference(id1, id2); + AddSurfaceReference(manager().GetRootSurfaceId(), id1); + AddSurfaceReference(id1, id2); EXPECT_THAT(GetReferencesFor(id1), UnorderedElementsAre(manager().GetRootSurfaceId())); @@ -159,9 +152,9 @@ SurfaceId id2 = CreateSurface(kFrameSink2, 1); SurfaceId id3 = CreateSurface(kFrameSink3, 1); - manager().AddSurfaceReference(manager().GetRootSurfaceId(), id1); - manager().AddSurfaceReference(id1, id2); - manager().AddSurfaceReference(id2, id3); + AddSurfaceReference(manager().GetRootSurfaceId(), id1); + AddSurfaceReference(id1, id2); + AddSurfaceReference(id2, id3); // |kFramesink2| received a CompositorFrame with a new size, so it destroys // |id2| and creates |id2_next|. No reference have been removed yet. @@ -170,8 +163,8 @@ EXPECT_NE(nullptr, manager().GetSurfaceForId(id2_next)); // Add references to and from |id2_next|. - manager().AddSurfaceReference(id1, id2_next); - manager().AddSurfaceReference(id2_next, id3); + AddSurfaceReference(id1, id2_next); + AddSurfaceReference(id2_next, id3); EXPECT_THAT(GetReferencesFor(id2), UnorderedElementsAre(id1)); EXPECT_THAT(GetReferencesFor(id2_next), UnorderedElementsAre(id1)); EXPECT_THAT(GetReferencesFor(id3), UnorderedElementsAre(id2, id2_next)); @@ -192,12 +185,12 @@ SurfaceId id2 = CreateSurface(kFrameSink2, 1); SurfaceId id3 = CreateSurface(kFrameSink3, 1); - manager().AddSurfaceReference(manager().GetRootSurfaceId(), id1); - manager().AddSurfaceReference(id1, id2); - manager().AddSurfaceReference(id2, id3); + AddSurfaceReference(manager().GetRootSurfaceId(), id1); + AddSurfaceReference(id1, id2); + AddSurfaceReference(id2, id3); // This reference forms a cycle between id2 and id3. - manager().AddSurfaceReference(id3, id2); + AddSurfaceReference(id3, id2); DestroySurface(id3); DestroySurface(id2); @@ -212,12 +205,12 @@ EXPECT_EQ(nullptr, manager().GetSurfaceForId(id3)); } -TEST_F(SurfaceManagerRefTest, CheckGC) { +TEST_F(SurfaceManagerRefTest, SurfacesAreDeletedDuringGarbageCollection) { SurfaceId id1 = CreateSurface(kFrameSink1, 1); SurfaceId id2 = CreateSurface(kFrameSink2, 1); - manager().AddSurfaceReference(manager().GetRootSurfaceId(), id1); - manager().AddSurfaceReference(id1, id2); + AddSurfaceReference(manager().GetRootSurfaceId(), id1); + AddSurfaceReference(id1, id2); EXPECT_NE(nullptr, manager().GetSurfaceForId(id1)); EXPECT_NE(nullptr, manager().GetSurfaceForId(id2)); @@ -238,14 +231,14 @@ EXPECT_EQ(nullptr, manager().GetSurfaceForId(id1)); } -TEST_F(SurfaceManagerRefTest, CheckGCRecusiveFull) { +TEST_F(SurfaceManagerRefTest, GarbageCollectionWorksRecusively) { SurfaceId id1 = CreateSurface(kFrameSink1, 1); SurfaceId id2 = CreateSurface(kFrameSink2, 1); SurfaceId id3 = CreateSurface(kFrameSink3, 1); - manager().AddSurfaceReference(manager().GetRootSurfaceId(), id1); - manager().AddSurfaceReference(id1, id2); - manager().AddSurfaceReference(id2, id3); + AddSurfaceReference(manager().GetRootSurfaceId(), id1); + AddSurfaceReference(id1, id2); + AddSurfaceReference(id2, id3); DestroySurface(id3); DestroySurface(id2); @@ -266,43 +259,45 @@ EXPECT_EQ(nullptr, manager().GetSurfaceForId(id3)); } -TEST_F(SurfaceManagerRefTest, TryDoubleAddReference) { +TEST_F(SurfaceManagerRefTest, TryAddReferenceSameReferenceTwice) { SurfaceId id1 = CreateSurface(kFrameSink1, 1); SurfaceId id2 = CreateSurface(kFrameSink2, 1); - manager().AddSurfaceReference(manager().GetRootSurfaceId(), id1); - manager().AddSurfaceReference(id1, id2); + AddSurfaceReference(manager().GetRootSurfaceId(), id1); + AddSurfaceReference(id1, id2); EXPECT_THAT(GetReferencesFor(id2), SizeIs(1)); EXPECT_THAT(GetReferencesFrom(id1), SizeIs(1)); // The second request should be ignored without crashing. - manager().AddSurfaceReference(id1, id2); + AddSurfaceReference(id1, id2); EXPECT_THAT(GetReferencesFor(id2), SizeIs(1)); EXPECT_THAT(GetReferencesFrom(id1), SizeIs(1)); } -TEST_F(SurfaceManagerRefTest, TryAddSelfReference) { - SurfaceId id1 = CreateSurface(kFrameSink1, 1); +TEST_F(SurfaceManagerRefTest, AddingSelfReferenceFails) { + SurfaceId id1 = CreateSurface(kFrameSink2, 1); // A temporary reference must exist to |id1|. - EXPECT_THAT(GetReferencesFor(id1), SizeIs(1)); + EXPECT_THAT(GetAllTempReferences(), ElementsAre(id1)); + EXPECT_THAT(GetReferencesFrom(id1), IsEmpty()); + EXPECT_THAT(GetReferencesFor(id1), IsEmpty()); // Try to add a self reference. This should fail. - manager().AddSurfaceReference(id1, id1); + AddSurfaceReference(id1, id1); - // Adding a self reference should be ignored without crashing. + // Adding a self reference should be ignored without crashing. The temporary + // reference to |id1| must still exist. + EXPECT_THAT(GetAllTempReferences(), ElementsAre(id1)); EXPECT_THAT(GetReferencesFrom(id1), IsEmpty()); - - // The temporary reference to |id1| must still exist. - EXPECT_THAT(GetReferencesFor(id1), SizeIs(1)); + EXPECT_THAT(GetReferencesFor(id1), IsEmpty()); } -TEST_F(SurfaceManagerRefTest, TryRemoveBadReference) { +TEST_F(SurfaceManagerRefTest, RemovingNonexistantReferenceFails) { SurfaceId id1 = CreateSurface(kFrameSink1, 1); SurfaceId id2 = CreateSurface(kFrameSink2, 1); // Removing non-existent reference should be ignored. - manager().AddSurfaceReference(id1, id2); + AddSurfaceReference(id1, id2); RemoveSurfaceReference(id2, id1); EXPECT_THAT(GetReferencesFrom(id1), SizeIs(1)); EXPECT_THAT(GetReferencesFor(id2), SizeIs(1)); @@ -314,17 +309,15 @@ // A temporary reference must be added to |surface_id|. EXPECT_THAT(GetAllTempReferences(), ElementsAre(surface_id)); - EXPECT_THAT(GetReferencesFromRoot(), ElementsAre(surface_id)); // Create |parent_id| and add a real reference from it to |surface_id|. const SurfaceId parent_id = CreateSurface(kFrameSink1, 1); - manager().AddSurfaceReference(parent_id, surface_id); + AddSurfaceReference(parent_id, surface_id); // The temporary reference to |surface_id| should be gone. // The only temporary reference should be to |parent_id|. // There must be a real reference from |parent_id| to |child_id|. EXPECT_THAT(GetAllTempReferences(), ElementsAre(parent_id)); - EXPECT_THAT(GetReferencesFromRoot(), ElementsAre(parent_id)); EXPECT_THAT(GetReferencesFrom(parent_id), ElementsAre(surface_id)); } @@ -334,15 +327,15 @@ // Temporary reference should be added to |surface_id|. EXPECT_THAT(GetAllTempReferences(), ElementsAre(surface_id)); - EXPECT_THAT(GetReferencesFromRoot(), ElementsAre(surface_id)); // Add a real reference from root to |surface_id|. - manager().AddSurfaceReference(manager().GetRootSurfaceId(), surface_id); + AddSurfaceReference(manager().GetRootSurfaceId(), surface_id); - // The temporary reference should be gone. - // There should now be a real reference from root to |surface_id|. + // The temporary reference should be gone and there should now be a surface + // reference from root to |surface_id|. EXPECT_TRUE(GetAllTempReferences().empty()); - EXPECT_THAT(GetReferencesFromRoot(), ElementsAre(surface_id)); + EXPECT_THAT(GetReferencesFrom(manager().GetRootSurfaceId()), + ElementsAre(surface_id)); } TEST_F(SurfaceManagerRefTest, AddTwoSurfacesThenOneReference) { @@ -353,12 +346,10 @@ // Temporary reference should be added for both surfaces. EXPECT_THAT(GetAllTempReferences(), UnorderedElementsAre(surface_id1, surface_id2)); - EXPECT_THAT(GetReferencesFromRoot(), - UnorderedElementsAre(surface_id1, surface_id2)); // Create |parent_id| and add a real reference from it to |surface_id1|. const SurfaceId parent_id = CreateSurface(kFrameSink1, 1); - manager().AddSurfaceReference(parent_id, surface_id1); + AddSurfaceReference(parent_id, surface_id1); // Real reference must be added to |surface_id1| and the temporary reference // to it must be gone. @@ -366,8 +357,6 @@ // A temporary reference to |parent_id| must be created. EXPECT_THAT(GetAllTempReferences(), UnorderedElementsAre(parent_id, surface_id2)); - EXPECT_THAT(GetReferencesFromRoot(), - UnorderedElementsAre(parent_id, surface_id2)); EXPECT_THAT(GetReferencesFrom(parent_id), ElementsAre(surface_id1)); } @@ -380,26 +369,22 @@ // Temporary references should be added for both surfaces and they should be // stored in the order of creation. - EXPECT_THAT(GetTempReferencesFor(surface_id1.frame_sink_id()), - ElementsAre(surface_id1.local_surface_id(), - surface_id2.local_surface_id())); - EXPECT_THAT(GetReferencesFromRoot(), + EXPECT_THAT(GetAllTempReferences(), UnorderedElementsAre(surface_id1, surface_id2)); // Create |parent_id| and add a reference from it to |surface_id2| which was // created later. const SurfaceId parent_id = CreateSurface(kFrameSink1, 1); - manager().AddSurfaceReference(parent_id, surface_id2); + AddSurfaceReference(parent_id, surface_id2); // The real reference should be added for |surface_id2| and the temporary // references to both |surface_id1| and |surface_id2| should be gone. // There should be a temporary reference to |parent_id|. EXPECT_THAT(GetAllTempReferences(), ElementsAre(parent_id)); - EXPECT_THAT(GetReferencesFromRoot(), ElementsAre(parent_id)); EXPECT_THAT(GetReferencesFrom(parent_id), ElementsAre(surface_id2)); } -TEST_F(SurfaceManagerRefTest, RemoveFirstTempRefOnly) { +TEST_F(SurfaceManagerRefTest, RemoveFirstTempReferenceOnly) { // Add two surfaces that have the same FrameSinkId. This would happen when a // client submits two CFs before parent submits a new CF. const SurfaceId surface_id1 = CreateSurface(kFrameSink2, 1); @@ -407,25 +392,121 @@ // Temporary references should be added for both surfaces and they should be // stored in the order of creation. - EXPECT_THAT(GetTempReferencesFor(surface_id1.frame_sink_id()), - ElementsAre(surface_id1.local_surface_id(), - surface_id2.local_surface_id())); - EXPECT_THAT(GetReferencesFromRoot(), + EXPECT_THAT(GetAllTempReferences(), UnorderedElementsAre(surface_id1, surface_id2)); // Create |parent_id| and add a reference from it to |surface_id1| which was // created earlier. const SurfaceId parent_id = CreateSurface(kFrameSink1, 1); - manager().AddSurfaceReference(parent_id, surface_id1); + AddSurfaceReference(parent_id, surface_id1); // The real reference should be added for |surface_id1| and its temporary // reference should be removed. The temporary reference for |surface_id2| // should remain. A temporary reference must be added for |parent_id|. EXPECT_THAT(GetAllTempReferences(), UnorderedElementsAre(parent_id, surface_id2)); - EXPECT_THAT(GetReferencesFromRoot(), - UnorderedElementsAre(parent_id, surface_id2)); EXPECT_THAT(GetReferencesFrom(parent_id), ElementsAre(surface_id1)); } +TEST_F(SurfaceManagerRefTest, SurfaceWithTemporaryReferenceIsNotDeleted) { + const SurfaceId id1 = CreateSurface(kFrameSink1, 1); + AddSurfaceReference(manager().GetRootSurfaceId(), id1); + + // We create |id2| and never add a real reference to it. This leaves the + // temporary reference. + const SurfaceId id2 = CreateSurface(kFrameSink2, 1); + ASSERT_THAT(GetAllTempReferences(), UnorderedElementsAre(id2)); + EXPECT_NE(nullptr, manager().GetSurfaceForId(id2)); + + // Destroy both surfaces so they can be garbage collected. We remove the + // surface reference to |id1| which will run GarbageCollectSurfaces(). + DestroySurface(id1); + DestroySurface(id2); + RemoveSurfaceReference(manager().GetRootSurfaceId(), id1); + + // |id1| is destroyed and has no references, so it's deleted. + EXPECT_EQ(nullptr, manager().GetSurfaceForId(id1)); + + // |id2| is destroyed but has a temporary reference, it's not deleted. + EXPECT_NE(nullptr, manager().GetSurfaceForId(id2)); +} + +// Checks that when a temporary reference is assigned an owner, if the owner is +// invalidated then the temporary reference is also removed. +TEST_F(SurfaceManagerRefTest, InvalidateTempReferenceOwnerRemovesReference) { + // Surface |id1| should have a temporary reference on creation. + const SurfaceId id1 = CreateSurface(kFrameSink2, 1); + ASSERT_THAT(GetAllTempReferences(), UnorderedElementsAre(id1)); + + // |id1| should have a temporary reference after an owner is assigned. + manager().AssignTemporaryReference(id1, kFrameSink1); + ASSERT_THAT(GetAllTempReferences(), UnorderedElementsAre(id1)); + + // When |kFrameSink1| is invalidated the temporary reference will be removed. + manager().InvalidateFrameSinkId(kFrameSink1); + ASSERT_THAT(GetAllTempReferences(), IsEmpty()); +} + +// Checks that adding a surface reference clears the temporary reference and +// ownership. Invalidating the old owner shouldn't do anything. +TEST_F(SurfaceManagerRefTest, InvalidateHasNoEffectOnSurfaceReferences) { + const SurfaceId parent_id = CreateSurface(kFrameSink1, 1); + AddSurfaceReference(manager().GetRootSurfaceId(), parent_id); + + const SurfaceId id1 = CreateSurface(kFrameSink2, 1); + manager().AssignTemporaryReference(id1, kFrameSink1); + ASSERT_THAT(GetAllTempReferences(), UnorderedElementsAre(id1)); + + // Adding a real surface reference will remove the temporary reference. + AddSurfaceReference(parent_id, id1); + ASSERT_THAT(GetAllTempReferences(), IsEmpty()); + ASSERT_THAT(GetReferencesFor(id1), UnorderedElementsAre(parent_id)); + + // When |kFrameSink1| is invalidated it shouldn't change the surface + // references. + manager().InvalidateFrameSinkId(kFrameSink1); + ASSERT_THAT(GetReferencesFor(id1), UnorderedElementsAre(parent_id)); +} + +TEST_F(SurfaceManagerRefTest, CheckDropTemporaryReferenceWorks) { + const SurfaceId id1 = CreateSurface(kFrameSink1, 1); + ASSERT_THAT(GetAllTempReferences(), UnorderedElementsAre(id1)); + + // An example of why this could happen is the window server doesn't know the + // owner, maybe it has crashed and been cleanup already, and asks to drop the + // temporary reference. + manager().DropTemporaryReference(id1); + ASSERT_THAT(GetAllTempReferences(), IsEmpty()); +} + +// Checks that we handle ownership and temporary references correctly when there +// are multiple temporary references. This tests something like the parent +// client crashing, so it's +TEST_F(SurfaceManagerRefTest, TempReferencesWithClientCrash) { + const SurfaceId parent_id = CreateSurface(kFrameSink1, 1); + AddSurfaceReference(manager().GetRootSurfaceId(), parent_id); + + const SurfaceId id1a = CreateSurface(kFrameSink2, 1); + const SurfaceId id1b = CreateSurface(kFrameSink2, 2); + + ASSERT_THAT(GetAllTempReferences(), UnorderedElementsAre(id1a, id1b)); + + // Assign |id1a| to |kFrameSink1|. This doesn't change the temporary + // reference, it just assigns as owner to it. + manager().AssignTemporaryReference(id1a, kFrameSink1); + ASSERT_THAT(GetAllTempReferences(), UnorderedElementsAre(id1a, id1b)); + + // If the parent client crashes then the CompositorFrameSink connection will + // be closed and the FrameSinkId invalidated. The temporary reference + // |kFrameSink1| owns to |id2a| will be removed. + manager().InvalidateFrameSinkId(kFrameSink1); + ASSERT_THAT(GetAllTempReferences(), UnorderedElementsAre(id1b)); + + // If the parent has crashed then the window server will have already removed + // it from the ServerWindow hierarchy and won't have an owner for |id2b|. The + // window server will ask to drop the reference instead. + manager().DropTemporaryReference(id1b); + ASSERT_THAT(GetAllTempReferences(), IsEmpty()); +} + } // namespace cc
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index a186f87..6972694 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -890,6 +890,13 @@ ForcedSigninProcessor.checkCanSignIn(ChromeActivity.this); } }); + DeferredStartupHandler.getInstance().addDeferredTask(new Runnable() { + @Override + public void run() { + if (isActivityDestroyed() || mBottomSheet == null) return; + mBottomSheet.initializeDefaultContent(); + } + }); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java index 57a49d7..3ef166e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -260,6 +260,7 @@ // Set up snippets NewTabPageAdapter newTabPageAdapter = new NewTabPageAdapter(mManager, mNewTabPageLayout, mUiConfig, offlinePageBridge, mContextMenuManager, /* tileGroupDelegate = */ null); + newTabPageAdapter.refreshSuggestions(); mRecyclerView.setAdapter(newTabPageAdapter); int scrollOffset;
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 676f009c..166985f 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
@@ -175,6 +175,13 @@ return mRoot.getItemCount(); } + /** Resets suggestions, pulling the current state as known by the backend. */ + public void refreshSuggestions() { + // The NTP Tiles already update when changes occurs, they don't need to be explicitly reset, + // unlike the cards. + mSections.refreshSuggestions(); + } + public int getAboveTheFoldPosition() { if (mAboveTheFoldView == null) return RecyclerView.NO_POSITION;
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 2f3fe25..98e963a 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
@@ -42,7 +42,6 @@ mUiDelegate.getSuggestionsSource().setObserver(this); mUiDelegate.getMetricsReporter().setRanker(mSuggestionsRanker); mOfflinePageBridge = offlinePageBridge; - resetSections(/* alwaysAllowEmptySections = */ false); mUiDelegate.addDestructionObserver(new DestructionObserver() { @Override @@ -183,6 +182,14 @@ @Override public void onFullRefreshRequired() { + refreshSuggestions(); + } + + /** + * Resets all the sections, getting the current list of categories and the associated + * suggestions from the backend. + */ + public void refreshSuggestions() { resetSections(/* alwaysAllowEmptySections = */false); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java index ad72913..608f406 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -20,6 +20,7 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.widget.BottomSheet; +import org.chromium.chrome.browser.widget.BottomSheetObserver; import org.chromium.chrome.browser.widget.displaystyle.UiConfig; /** @@ -60,10 +61,13 @@ UiConfig uiConfig = new UiConfig(mRecyclerView); + // This mAdapter does not fetch until later requested, when the sheet is opened. NewTabPageAdapter adapter = new NewTabPageAdapter(mSuggestionsManager, /* aboveTheFoldView = */ null, uiConfig, OfflinePageBridge.getForProfile(profile), mContextMenuManager, mTileGroupDelegate); mRecyclerView.setAdapter(adapter); + + activity.getBottomSheet().addObserver(new BottomSheetObserverImpl(adapter)); } @Override @@ -119,4 +123,31 @@ return delegate; } + + // TODO(dgn): Extract for public usage if it turns out that implementing a single method from + // the interface becomes common. + private static class BottomSheetObserverImpl implements BottomSheetObserver { + private final NewTabPageAdapter mAdapter; + + public BottomSheetObserverImpl(NewTabPageAdapter adapter) { + mAdapter = adapter; + } + + @Override + public void onSheetOpened() { + mAdapter.refreshSuggestions(); + } + + @Override + public void onSheetClosed() {} + + @Override + public void onLoadUrl(String url) {} + + @Override + public void onSheetOffsetChanged(float heightFraction) {} + + @Override + public void onTransitionPeekToHalf(float transitionFraction) {} + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java index 8cb6a12..c84d09a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
@@ -391,6 +391,14 @@ mBottomSheetContentContainer.addView(mPlaceholder, placeHolderParams); } + /** Initialise the default bottom sheet content. */ + public void initializeDefaultContent() { + assert mSheetContent == null; + mSuggestionsContent = new SuggestionsBottomSheetContent( + mTabModelSelector.getCurrentTab().getActivity(), this, mTabModelSelector); + showContent(mSuggestionsContent); + } + @Override public int loadUrl(LoadUrlParams params, boolean incognito) { for (BottomSheetObserver o : mObservers) o.onLoadUrl(params.getUrl()); @@ -450,11 +458,6 @@ * A notification that the sheet is exiting the peek state into one that shows content. */ private void onSheetOpened() { - if (mSuggestionsContent == null) { - mSuggestionsContent = new SuggestionsBottomSheetContent( - mTabModelSelector.getCurrentTab().getActivity(), this, mTabModelSelector); - } - showContent(mSuggestionsContent); for (BottomSheetObserver o : mObservers) o.onSheetOpened();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java index 6ec28c3..13ba8b36 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -81,6 +81,7 @@ mAdapter = new NewTabPageAdapter(mUiDelegate, aboveTheFold, mUiConfig, OfflinePageBridge.getForProfile(Profile.getLastUsedProfile()), /* contextMenuManager = */ null, /* tileGroupDelegate = */ null); + mAdapter.refreshSuggestions(); mRecyclerView.setAdapter(mAdapter); } });
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 3ce31b2..f8fda0fd 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
@@ -903,7 +903,7 @@ // On Sign in, we should reset the sections, bring back suggestions instead of the All // Dismissed item. - mAdapter.getSectionListForTesting().onFullRefreshRequired(); + mAdapter.getSectionListForTesting().refreshSuggestions(); when(mMockSigninManager.isSignInAllowed()).thenReturn(true); signinObserver.onSignedIn(); // Adapter content: @@ -989,7 +989,9 @@ private void reloadNtp() { mAdapter = new NewTabPageAdapter(mUiDelegate, mock(View.class), makeUiConfig(), - mOfflinePageBridge, mock(ContextMenuManager.class), /* tileGroupDelegate = */ null); + mOfflinePageBridge, mock(ContextMenuManager.class), /* tileGroupDelegate = + */ null); + mAdapter.refreshSuggestions(); } private void assertArticlesEqual(List<SnippetArticle> articles, int start, int end) {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java index 5227ae5..3f4c828 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java
@@ -97,6 +97,7 @@ List<SnippetArticle> suggestions2 = registerCategory(mSuggestionSource, CATEGORY2, 4); SectionList sectionList = new SectionList(mUiDelegate, mOfflinePageBridge); + sectionList.refreshSuggestions(); bindViewHolders(sectionList); @@ -131,6 +132,7 @@ List<SnippetArticle> suggestions2 = registerCategory(mSuggestionSource, CATEGORY2, 4); SectionList sectionList = new SectionList(mUiDelegate, mOfflinePageBridge); + sectionList.refreshSuggestions(); bindViewHolders(sectionList, 0, 5); // Bind until after the third item from |suggestions1|. @@ -226,6 +228,7 @@ new CategoryInfoBuilder(CATEGORY2).withViewAllAction().build(), 3); SectionList sectionList = new SectionList(mUiDelegate, mOfflinePageBridge); + sectionList.refreshSuggestions(); bindViewHolders(sectionList); assertThat(sectionList.getSectionForTesting(CATEGORY1) @@ -246,6 +249,7 @@ new CategoryInfoBuilder(CATEGORY2).withViewAllAction().build(), 3); SectionList sectionList = new SectionList(mUiDelegate, mOfflinePageBridge); + sectionList.refreshSuggestions(); bindViewHolders(sectionList); ArgumentCaptor<DestructionObserver> argument = @@ -271,6 +275,7 @@ registerCategory(mSuggestionSource, KnownCategories.ARTICLES, 1); SectionList sectionList = new SectionList(mUiDelegate, mOfflinePageBridge); + sectionList.refreshSuggestions(); SuggestionsSection articles = sectionList.getSectionForTesting(KnownCategories.ARTICLES); assertFalse(articles.getHeaderItemForTesting().isVisible()); } @@ -281,6 +286,7 @@ registerCategory(mSuggestionSource, CATEGORY1, 1); SectionList sectionList = new SectionList(mUiDelegate, mOfflinePageBridge); + sectionList.refreshSuggestions(); SuggestionsSection section = sectionList.getSectionForTesting(CATEGORY1); assertTrue(section.getHeaderItemForTesting().isVisible()); } @@ -292,6 +298,7 @@ registerCategory(mSuggestionSource, CATEGORY1, 1); SectionList sectionList = new SectionList(mUiDelegate, mOfflinePageBridge); + sectionList.refreshSuggestions(); SuggestionsSection articles = sectionList.getSectionForTesting(KnownCategories.ARTICLES); assertTrue(articles.getHeaderItemForTesting().isVisible()); }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index f4f4ae9..1c9d173a0 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -14578,6 +14578,12 @@ </if> <!-- Web payments --> + <message name="IDS_FLAGS_WEB_PAYMENTS_NAME" desc="Name of the flag to enable Web Payments API." translateable="false"> + Web Payments + </message> + <message name="IDS_FLAGS_WEB_PAYMENTS_DESCRIPTION" desc="Description for the flag to enable Web Payments API" translateable="false"> + Enable Web Payments API integration, a JavaScript API for merchants. + </message> <if expr="is_android"> <message name="IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V1_NAME" desc="Name of the flag to enable the first version of Android Pay integration" translateable="false"> Enable Android Pay v1
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index e9dfb5e..bc9d0c29 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1692,8 +1692,6 @@ "guest_view/web_view/context_menu_content_type_web_view.h", "media/capture_access_handler_base.cc", "media/capture_access_handler_base.h", - "media/cast_transport_host_filter.cc", - "media/cast_transport_host_filter.h", "media/extension_media_access_handler.cc", "media/extension_media_access_handler.h", "media/webrtc/desktop_capture_access_handler.cc", @@ -1868,6 +1866,12 @@ "sync_file_system/task_logger.cc", "sync_file_system/task_logger.h", ] + if (enable_media_router) { + sources += [ + "media/cast_transport_host_filter.cc", + "media/cast_transport_host_filter.h", + ] + } public_deps += [ "//chrome/browser/extensions" ] allow_circular_includes_from += [ "//chrome/browser/extensions" ] deps += [ @@ -2509,10 +2513,6 @@ "profiles/profile_statistics_common.h", "profiles/profile_statistics_factory.cc", "profiles/profile_statistics_factory.h", - "signin/cross_device_promo.cc", - "signin/cross_device_promo.h", - "signin/cross_device_promo_factory.cc", - "signin/cross_device_promo_factory.h", "signin/signin_global_error.cc", "signin/signin_global_error.h", "signin/signin_global_error_factory.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 3670a71..da41720 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2067,6 +2067,9 @@ {"enable-framebusting-needs-sameorigin-or-usergesture", IDS_FLAGS_FRAMEBUSTING_NAME, IDS_FLAGS_FRAMEBUSTING_DESCRIPTION, kOsAll, FEATURE_VALUE_TYPE(features::kFramebustingNeedsSameOriginOrUserGesture)}, + {"web-payments", IDS_FLAGS_WEB_PAYMENTS_NAME, + IDS_FLAGS_WEB_PAYMENTS_DESCRIPTION, kOsDesktop, + FEATURE_VALUE_TYPE(features::kWebPayments)}, #if defined(OS_ANDROID) {"enable-android-pay-integration-v1", IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V1_NAME,
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc index d1b4381..84e26ca 100644 --- a/chrome/browser/certificate_manager_model.cc +++ b/chrome/browser/certificate_manager_model.cc
@@ -115,14 +115,13 @@ void CertificateManagerModel::Refresh() { DVLOG(1) << "refresh started"; - net::CryptoModuleList modules; + std::vector<crypto::ScopedPK11Slot> modules; cert_db_->ListModules(&modules, false); DVLOG(1) << "refresh waiting for unlocking..."; chrome::UnlockSlotsIfNecessary( - modules, - chrome::kCryptoModulePasswordListCerts, + std::move(modules), chrome::kCryptoModulePasswordListCerts, net::HostPortPair(), // unused. - NULL, // TODO(mattm): supply parent window. + NULL, // TODO(mattm): supply parent window. base::Bind(&CertificateManagerModel::RefreshSlotsUnlocked, base::Unretained(this)));
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 8adb92cdde..16647100 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -322,7 +322,6 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) #include "chrome/browser/accessibility/animation_policy_prefs.h" #include "chrome/browser/extensions/chrome_content_browser_client_extensions_part.h" -#include "chrome/browser/media/cast_transport_host_filter.h" #include "chrome/browser/speech/extension_api/tts_engine_extension_api.h" #include "components/guest_view/browser/guest_view_base.h" #include "components/guest_view/browser/guest_view_manager.h" @@ -342,6 +341,10 @@ #include "extensions/common/switches.h" #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) && defined(ENABLE_MEDIA_ROUTER) +#include "chrome/browser/media/cast_transport_host_filter.h" +#endif // BUILDFLAG(ENABLE_EXTENSIONS) && defined(ENABLE_MEDIA_ROUTER) + #if BUILDFLAG(ENABLE_PLUGINS) #include "chrome/browser/plugins/chrome_content_browser_client_plugins_part.h" #include "chrome/browser/plugins/flash_download_interception.h" @@ -1158,7 +1161,7 @@ Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext()); host->AddFilter(new ChromeRenderMessageFilter( id, profile, host->GetStoragePartition()->GetServiceWorkerContext())); -#if BUILDFLAG(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_EXTENSIONS) && defined(ENABLE_MEDIA_ROUTER) host->AddFilter(new cast::CastTransportHostFilter); #endif #if BUILDFLAG(ENABLE_PRINTING) @@ -3178,7 +3181,8 @@ web_contents->GetJavaInterfaces()->GetWeakPtr())); } #else - if (AreExperimentalWebPlatformFeaturesEnabled()) { + if (AreExperimentalWebPlatformFeaturesEnabled() && + base::FeatureList::IsEnabled(features::kWebPayments)) { content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); if (web_contents) {
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc index 58bedb7..48e114ff 100644 --- a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc +++ b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc
@@ -58,6 +58,8 @@ fetch_request_job_->GetRequest()->mutable_service_api_access_request(); request->set_oauth2_client_id(kAndoidClientId); request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope); + request->set_device_type( + enterprise_management::DeviceServiceApiAccessRequest::ANDROIDOS); fetch_request_job_->Start( base::Bind(&ArcRobotAuthCodeFetcher::OnFetchRobotAuthCodeCompleted,
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc index 595ea45..4b785c2 100644 --- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc +++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
@@ -159,13 +159,7 @@ << message_; } -// http://crbug.com/691449 -#if defined(OS_CHROMEOS) -#define MAYBE_ReadFile DISABLED_ReadFile -#else -#define MAYBE_ReadFile ReadFile -#endif -IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, MAYBE_ReadFile) { +IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, ReadFile) { ASSERT_TRUE(RunPlatformAppTestWithFlags("file_system_provider/read_file", kFlagLoadAsComponent)) << message_;
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index fa5f9b65..94dee68 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -829,7 +829,6 @@ "//chrome/app/theme:theme_resources", "//chrome/app/vector_icons", "//chrome/browser/devtools", - "//chrome/browser/media/router", "//chrome/common", "//chrome/common/extensions/api:api_registration", "//chrome/common/extensions/api:extensions_features", @@ -929,6 +928,10 @@ "//url", ] + if (enable_media_router) { + deps += [ "//chrome/browser/media/router" ] + } + if (!is_chromeos) { sources += [ "chrome_kiosk_delegate.cc" ] }
diff --git a/chrome/browser/extensions/api/tab_capture/offscreen_tab.cc b/chrome/browser/extensions/api/tab_capture/offscreen_tab.cc index aec99ad9..3adbdf05 100644 --- a/chrome/browser/extensions/api/tab_capture/offscreen_tab.cc +++ b/chrome/browser/extensions/api/tab_capture/offscreen_tab.cc
@@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h" -#include "chrome/browser/media/router/receiver_presentation_service_delegate_impl.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/web_contents_sizer.h" #include "content/public/browser/render_view_host.h" @@ -20,6 +19,10 @@ #include "extensions/browser/extension_host.h" #include "extensions/browser/process_manager.h" +#if defined(ENABLE_MEDIA_ROUTER) +#include "chrome/browser/media/router/receiver_presentation_service_delegate_impl.h" // nogncheck +#endif + using content::WebContents; DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::OffscreenTabsOwner); @@ -118,6 +121,7 @@ // automatically unmuted, but will be captured into the MediaStream. offscreen_tab_web_contents_->SetAudioMuted(true); +#if defined(ENABLE_MEDIA_ROUTER) if (!optional_presentation_id.empty()) { DVLOG(1) << " Register with ReceiverPresentationServiceDelegateImpl, " << "[presentation_id]: " << optional_presentation_id; @@ -134,6 +138,7 @@ render_view_host->UpdateWebkitPreferences(web_prefs); } } +#endif // defined(ENABLE_MEDIA_ROUTER) // Navigate to the initial URL. content::NavigationController::LoadURLParams load_params(start_url_);
diff --git a/chrome/browser/extensions/chrome_mojo_service_registration.cc b/chrome/browser/extensions/chrome_mojo_service_registration.cc index c280f2c14..0e35f1e 100644 --- a/chrome/browser/extensions/chrome_mojo_service_registration.cc +++ b/chrome/browser/extensions/chrome_mojo_service_registration.cc
@@ -14,8 +14,8 @@ #include "services/service_manager/public/cpp/interface_registry.h" #if defined(ENABLE_MEDIA_ROUTER) -#include "chrome/browser/media/router/media_router_feature.h" -#include "chrome/browser/media/router/mojo/media_router_mojo_impl.h" +#include "chrome/browser/media/router/media_router_feature.h" // nogncheck +#include "chrome/browser/media/router/mojo/media_router_mojo_impl.h" // nogncheck #endif namespace extensions {
diff --git a/chrome/browser/payments/site_per_process_payments_browsertest.cc b/chrome/browser/payments/site_per_process_payments_browsertest.cc index 330c4a3..cc1448e5c 100644 --- a/chrome/browser/payments/site_per_process_payments_browsertest.cc +++ b/chrome/browser/payments/site_per_process_payments_browsertest.cc
@@ -12,6 +12,7 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" @@ -34,6 +35,8 @@ command_line->AppendSwitch(switches::kIgnoreCertificateErrors); command_line->AppendSwitch( switches::kEnableExperimentalWebPlatformFeatures); + command_line->AppendSwitchASCII(switches::kEnableFeatures, + features::kWebPayments.name); // Append --site-per-process flag. content::IsolateAllSitesForTesting(command_line); }
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc index a2916ba..2069dbd 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -606,6 +606,9 @@ BrowserThread::IO, FROM_HERE, base::Bind(&ResourcePrefetcherManager::MaybeAddPrefetch, prefetch_manager_, url, prediction.subresource_urls)); + + if (observer_) + observer_->OnPrefetchingStarted(url); } void ResourcePrefetchPredictor::StopPrefetching(const GURL& url) { @@ -625,6 +628,9 @@ BrowserThread::IO, FROM_HERE, base::Bind(&ResourcePrefetcherManager::MaybeRemovePrefetch, prefetch_manager_, url)); + + if (observer_) + observer_->OnPrefetchingStopped(url); } void ResourcePrefetchPredictor::OnPrefetchingFinished( @@ -675,15 +681,22 @@ void ResourcePrefetchPredictor::OnMainFrameResponse( const URLRequestSummary& response) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (initialization_state_ != INITIALIZED) - return; + DCHECK_EQ(INITIALIZED, initialization_state_); - StopPrefetching(response.navigation_id.main_frame_url); + NavigationMap::iterator nav_it = + inflight_navigations_.find(response.navigation_id); + if (nav_it != inflight_navigations_.end()) { + // To match an URL in StartPrefetching(). + StopPrefetching(nav_it->second->initial_url); + } else { + StopPrefetching(response.navigation_id.main_frame_url); + } } void ResourcePrefetchPredictor::OnMainFrameRedirect( const URLRequestSummary& response) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_EQ(INITIALIZED, initialization_state_); const GURL& main_frame_url = response.navigation_id.main_frame_url; std::unique_ptr<PageRequestSummary> summary; @@ -715,6 +728,7 @@ void ResourcePrefetchPredictor::OnSubresourceResponse( const URLRequestSummary& response) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_EQ(INITIALIZED, initialization_state_); NavigationMap::const_iterator nav_it = inflight_navigations_.find(response.navigation_id); @@ -728,6 +742,7 @@ void ResourcePrefetchPredictor::OnNavigationComplete( const NavigationID& nav_id_without_timing_info) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_EQ(INITIALIZED, initialization_state_); NavigationMap::iterator nav_it = inflight_navigations_.find(nav_id_without_timing_info); @@ -903,10 +918,16 @@ for (auto it = inflight_prefetches_.begin(); it != inflight_prefetches_.end();) { - if (time_now - it->second > max_navigation_age) + base::TimeDelta prefetch_age = time_now - it->second; + if (prefetch_age > max_navigation_age) { + // It goes to the last bucket meaning that the duration was unlimited. + UMA_HISTOGRAM_TIMES( + internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, + prefetch_age); it = inflight_prefetches_.erase(it); - else + } else { ++it; + } } // Remove old prefetches that haven't been claimed.
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h index 60f057c..1bfdf871 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.h +++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -429,13 +429,17 @@ // De-registers itself from |predictor_| on destruction. virtual ~TestObserver(); + virtual void OnPredictorInitialized() {} + virtual void OnNavigationLearned( size_t url_visit_count, const ResourcePrefetchPredictor::PageRequestSummary& summary) {} - virtual void OnPrefetchingFinished(const GURL& main_frame_url) {} + virtual void OnPrefetchingStarted(const GURL& main_frame_url) {} - virtual void OnPredictorInitialized() {} + virtual void OnPrefetchingStopped(const GURL& main_frame_url) {} + + virtual void OnPrefetchingFinished(const GURL& main_frame_url) {} protected: // |predictor| must be non-NULL and has to outlive the TestObserver.
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_browsertest.cc b/chrome/browser/predictors/resource_prefetch_predictor_browsertest.cc index 872022f..44f7cd7 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_browsertest.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor_browsertest.cc
@@ -258,17 +258,30 @@ }; // Helper class to track and allow waiting for a single OnPrefetchingFinished -// event. No learning events should be fired while this observer is active. +// event. Checks also that {Start,Stop}Prefetching are called with the right +// argument. class PrefetchingObserver : public TestObserver { public: PrefetchingObserver(ResourcePrefetchPredictor* predictor, - const GURL& expected_main_frame_url) - : TestObserver(predictor), main_frame_url_(expected_main_frame_url) {} + const GURL& expected_main_frame_url, + bool is_learning_allowed) + : TestObserver(predictor), + main_frame_url_(expected_main_frame_url), + is_learning_allowed_(is_learning_allowed) {} // TestObserver: void OnNavigationLearned(size_t url_visit_count, const PageRequestSummary& summary) override { - ADD_FAILURE() << "Prefetching shouldn't activate learning"; + if (!is_learning_allowed_) + ADD_FAILURE() << "Prefetching shouldn't activate learning"; + } + + void OnPrefetchingStarted(const GURL& main_frame_url) override { + EXPECT_EQ(main_frame_url_, main_frame_url); + } + + void OnPrefetchingStopped(const GURL& main_frame_url) override { + EXPECT_EQ(main_frame_url_, main_frame_url); } void OnPrefetchingFinished(const GURL& main_frame_url) override { @@ -281,6 +294,7 @@ private: base::RunLoop run_loop_; GURL main_frame_url_; + bool is_learning_allowed_; DISALLOW_COPY_AND_ASSIGN(PrefetchingObserver); }; @@ -381,8 +395,18 @@ navigation_id_history_.insert(nav); } + void NavigateToURLAndCheckPrefetching(const GURL& main_frame_url) { + PrefetchingObserver observer(predictor_, main_frame_url, true); + ui_test_utils::NavigateToURL(browser(), main_frame_url); + observer.Wait(); + for (auto& kv : resources_) { + if (kv.second.is_observable) + kv.second.request.was_cached = true; + } + } + void PrefetchURL(const GURL& main_frame_url) { - PrefetchingObserver observer(predictor_, main_frame_url); + PrefetchingObserver observer(predictor_, main_frame_url, false); predictor_->StartPrefetching(main_frame_url, PrefetchOrigin::EXTERNAL); observer.Wait(); for (auto& kv : resources_) { @@ -637,6 +661,21 @@ std::set<NavigationID> navigation_id_history_; }; +// Subclass to test PrefetchOrigin::NAVIGATION. +class ResourcePrefetchPredictorPrefetchingBrowserTest + : public ResourcePrefetchPredictorBrowserTest { + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII("force-fieldtrials", "trial/group"); + std::string parameter = base::StringPrintf( + "trial.group:%s/%s", kModeParamName, kPrefetchingMode); + command_line->AppendSwitchASCII("force-fieldtrial-params", parameter); + std::string enabled_feature = base::StringPrintf( + "%s<trial", kSpeculativeResourcePrefetchingFeatureName); + command_line->AppendSwitchASCII("enable-features", enabled_feature); + } +}; + IN_PROC_BROWSER_TEST_F(ResourcePrefetchPredictorBrowserTest, Simple) { // These resources have default priorities that correspond to // blink::typeToPriority function. @@ -899,4 +938,43 @@ NavigateToURLAndCheckSubresourcesAllCached(GetURL(kHtmlSubresourcesPath)); } +// Makes sure that {Stop,Start}Prefetching are called with the same argument. +IN_PROC_BROWSER_TEST_F(ResourcePrefetchPredictorPrefetchingBrowserTest, + Simple) { + AddResource(GetURL(kImagePath), content::RESOURCE_TYPE_IMAGE, net::LOWEST); + AddResource(GetURL(kStylePath), content::RESOURCE_TYPE_STYLESHEET, + net::HIGHEST); + AddResource(GetURL(kScriptPath), content::RESOURCE_TYPE_SCRIPT, net::MEDIUM); + AddResource(GetURL(kFontPath), content::RESOURCE_TYPE_FONT_RESOURCE, + net::HIGHEST); + + GURL main_frame_url = GetURL(kHtmlSubresourcesPath); + NavigateToURLAndCheckSubresources(main_frame_url); + ClearCache(); + NavigateToURLAndCheckSubresources(main_frame_url); + ClearCache(); + NavigateToURLAndCheckPrefetching(main_frame_url); +} + +// Makes sure that {Stop,Start}Prefetching are called with the same argument in +// presence of redirect. +IN_PROC_BROWSER_TEST_F(ResourcePrefetchPredictorPrefetchingBrowserTest, + Redirect) { + GURL initial_url = embedded_test_server()->GetURL(kFooHost, kRedirectPath); + AddRedirectChain(initial_url, {{net::HTTP_MOVED_PERMANENTLY, + GetURL(kHtmlSubresourcesPath)}}); + AddResource(GetURL(kImagePath), content::RESOURCE_TYPE_IMAGE, net::LOWEST); + AddResource(GetURL(kStylePath), content::RESOURCE_TYPE_STYLESHEET, + net::HIGHEST); + AddResource(GetURL(kScriptPath), content::RESOURCE_TYPE_SCRIPT, net::MEDIUM); + AddResource(GetURL(kFontPath), content::RESOURCE_TYPE_FONT_RESOURCE, + net::HIGHEST); + + NavigateToURLAndCheckSubresources(initial_url); + ClearCache(); + NavigateToURLAndCheckSubresources(initial_url); + ClearCache(); + NavigateToURLAndCheckPrefetching(initial_url); +} + } // namespace predictors
diff --git a/chrome/browser/prefs/pref_service_syncable_util.cc b/chrome/browser/prefs/pref_service_syncable_util.cc index 68c2f27..2a40fa9e 100644 --- a/chrome/browser/prefs/pref_service_syncable_util.cc +++ b/chrome/browser/prefs/pref_service_syncable_util.cc
@@ -36,7 +36,9 @@ // or behavior of the user should have this property. std::vector<const char*> overlay_pref_names; overlay_pref_names.push_back(prefs::kBrowserWindowPlacement); +#if defined(ENABLE_MEDIA_ROUTER) overlay_pref_names.push_back(prefs::kMediaRouterTabMirroringSources); +#endif overlay_pref_names.push_back(prefs::kSaveFileDefaultDirectory); #if defined(OS_ANDROID) overlay_pref_names.push_back(proxy_config::prefs::kProxy);
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index d775c529..77e005b 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -115,10 +115,6 @@ #endif #endif -#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) -#include "chrome/browser/signin/cross_device_promo_factory.h" -#endif - #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/printer_detector/printer_detector_factory.h" #include "chrome/browser/chromeos/printing/cups_print_job_manager_factory.h" @@ -216,9 +212,6 @@ CloudPrintProxyServiceFactory::GetInstance(); #endif CookieSettingsFactory::GetInstance(); -#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) - CrossDevicePromoFactory::GetInstance(); -#endif #if BUILDFLAG(ENABLE_EXTENSIONS) ExtensionWelcomeNotificationFactory::GetInstance(); #endif
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index c3707d93..eda7c36 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc
@@ -49,8 +49,6 @@ #include "chrome/browser/signin/account_fetcher_service_factory.h" #include "chrome/browser/signin/account_reconcilor_factory.h" #include "chrome/browser/signin/account_tracker_service_factory.h" -#include "chrome/browser/signin/cross_device_promo.h" -#include "chrome/browser/signin/cross_device_promo_factory.h" #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/sync/profile_sync_service_factory.h" @@ -1634,13 +1632,6 @@ ProfileAttributesEntry* entry; if (GetProfileAttributesStorage(). GetProfileAttributesWithPath(last_active->GetPath(), &entry)) { -#if !defined(OS_CHROMEOS) - // Incognito Profiles don't have ProfileKeyedServices. - if (!last_active->IsOffTheRecord()) { - CrossDevicePromoFactory::GetForProfile(last_active)-> - MaybeBrowsingSessionStarted(entry->GetActiveTime()); - } -#endif entry->SetActiveTimeToNow(); } }
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index f86db71..0589a34 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -853,6 +853,13 @@ ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW)) { AppendPrintPreviewItems(); } + + // Remove any redundant trailing separator. + if (menu_model_.GetItemCount() > 0 && + menu_model_.GetTypeAt(menu_model_.GetItemCount() - 1) == + ui::MenuModel::TYPE_SEPARATOR) { + menu_model_.RemoveItemAt(menu_model_.GetItemCount() - 1); + } } Profile* RenderViewContextMenu::GetProfile() { @@ -1297,10 +1304,12 @@ } void RenderViewContextMenu::AppendMediaRouterItem() { +#if defined(ENABLE_MEDIA_ROUTER) if (media_router::MediaRouterEnabled(browser_context_)) { menu_model_.AddItemWithStringId(IDC_ROUTE_MEDIA, IDS_MEDIA_ROUTER_MENU_ITEM_TITLE); } +#endif // defined(ENABLE_MEDIA_ROUTER) } void RenderViewContextMenu::AppendRotationItems() { @@ -2142,6 +2151,7 @@ } bool RenderViewContextMenu::IsRouteMediaEnabled() const { +#if defined(ENABLE_MEDIA_ROUTER) if (!media_router::MediaRouterEnabled(browser_context_)) return false; @@ -2161,6 +2171,9 @@ const web_modal::WebContentsModalDialogManager* manager = web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); return !manager || !manager->IsDialogActive(); +#else + return false; +#endif // defined(ENABLE_MEDIA_ROUTER) } bool RenderViewContextMenu::IsOpenLinkOTREnabled() const {
diff --git a/chrome/browser/signin/cross_device_promo.cc b/chrome/browser/signin/cross_device_promo.cc deleted file mode 100644 index 889b75d..0000000 --- a/chrome/browser/signin/cross_device_promo.cc +++ /dev/null
@@ -1,459 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/signin/cross_device_promo.h" - -#include <stdint.h> - -#include "base/metrics/histogram_macros.h" -#include "base/rand_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/time/time.h" -#include "chrome/common/pref_names.h" -#include "components/prefs/pref_service.h" -#include "components/signin/core/browser/signin_client.h" -#include "components/signin/core/browser/signin_manager.h" -#include "components/signin/core/browser/signin_metrics.h" -#include "components/variations/variations_associated_data.h" - -namespace { - -// Helper method to set a |local_parameter| to the result of fetching a -// |variation_parameter| from the variation seed, converting to an int, and then -// applying |conversion| to create a TimeDelta. Returns false if the -// |variation_parameter| was not found or the string could not be parsed to an -// int. -bool SetParameterFromVariation( - const std::string& variation_parameter, - base::Callback<base::TimeDelta(int)> conversion, - base::TimeDelta* local_parameter) { - std::string parameter_as_string = variations::GetVariationParamValue( - CrossDevicePromo::kCrossDevicePromoFieldTrial, variation_parameter); - if (parameter_as_string.empty()) - return false; - - int parameter_as_int; - if (!base::StringToInt(parameter_as_string, ¶meter_as_int)) - return false; - - *local_parameter = conversion.Run(parameter_as_int); - return true; -} - -} // namespace - -// static -const char CrossDevicePromo::kCrossDevicePromoFieldTrial[] = "CrossDevicePromo"; -const char CrossDevicePromo::kParamHoursBetweenDeviceActivityChecks[] = - "HoursBetweenDeviceActivityChecks"; -const char CrossDevicePromo::kParamDaysToVerifySingleUserProfile[] = - "DaysToVerifySingleUserProfile"; -const char CrossDevicePromo::kParamMinutesBetweenBrowsingSessions[] = - "MinutesBetweenBrowsingSessions"; -const char CrossDevicePromo::kParamMinutesMaxContextSwitchDuration[] = - "MinutesMaxContextSwitchDuration"; -const char CrossDevicePromo::kParamRPCThrottle[] = - "RPCThrottle"; - -CrossDevicePromo::CrossDevicePromo( - SigninManager* signin_manager, - GaiaCookieManagerService* cookie_manager_service, - SigninClient* signin_client, - PrefService* pref_service) - : initialized_(false), - signin_manager_(signin_manager), - cookie_manager_service_(cookie_manager_service), - prefs_(pref_service), - signin_client_(signin_client), - is_throttled_(true), - start_last_browsing_session_(base::Time()) { - VLOG(1) << "CrossDevicePromo::CrossDevicePromo."; - DCHECK(signin_manager_); - DCHECK(cookie_manager_service_); - DCHECK(prefs_); - DCHECK(signin_client_); - Init(); -} - -CrossDevicePromo::~CrossDevicePromo() { -} - -void CrossDevicePromo::Shutdown() { - VLOG(1) << "CrossDevicePromo::Shutdown."; - UnregisterForCookieChanges(); - if (start_last_browsing_session_ != base::Time()) - signin_metrics::LogBrowsingSessionDuration(start_last_browsing_session_); -} - -void CrossDevicePromo::AddObserver(CrossDevicePromo::Observer* observer) { - observer_list_.AddObserver(observer); -} - -void CrossDevicePromo::RemoveObserver(CrossDevicePromo::Observer* observer) { - observer_list_.RemoveObserver(observer); -} - -void CrossDevicePromo::OnGaiaAccountsInCookieUpdated( - const std::vector<gaia::ListedAccount>& accounts, - const std::vector<gaia::ListedAccount>& signed_out_accounts, - const GoogleServiceAuthError& error) { - VLOG(1) << "CrossDevicePromo::OnGaiaAccountsInCookieUpdated. " - << accounts.size() << " accounts with auth error " << error.state(); - if (error.state() != GoogleServiceAuthError::State::NONE) - return; - - const bool single_account = accounts.size() == 1; - const bool has_pref = - prefs_->HasPrefPath(prefs::kCrossDevicePromoObservedSingleAccountCookie); - if (!single_account && has_pref) { - prefs_->ClearPref(prefs::kCrossDevicePromoObservedSingleAccountCookie); - MarkPromoShouldNotBeShown(); - } else if (single_account && !has_pref) { - SetTimePref(prefs::kCrossDevicePromoObservedSingleAccountCookie, - base::Time::Now()); - } -} - -void CrossDevicePromo::OnFetchDeviceActivitySuccess( - const std::vector<DeviceActivityFetcher::DeviceActivity>& devices) { - VLOG(1) << "CrossDevicePromo::OnFetchDeviceActivitySuccess. " - << devices.size() << " devices."; - DetermineEligibilityFromDeviceActivity(devices); - - // |device_activity_fetcher_| must be destroyed last as that object is what - // called OnFetchDeviceActivitySuccess(). - // TODO(mlerman): Mark the DeviceActivityFetcher as stopped() or completed() - // rather than deleting the object. - device_activity_fetcher_.reset(); -} - -void CrossDevicePromo::OnFetchDeviceActivityFailure() { - VLOG(1) << "CrossDevicePromo::OnFetchDeviceActivityFailure."; - signin_metrics::LogXDevicePromoEligible( - signin_metrics::ERROR_FETCHING_DEVICE_ACTIVITY); - - // |device_activity_fetcher_| must be destroyed last as that object is what - // called OnFetchDeviceActivityFailure(). - device_activity_fetcher_.reset(); -} - -bool CrossDevicePromo::ShouldShowPromo() const { - return prefs_->GetBoolean(prefs::kCrossDevicePromoShouldBeShown); -} - -void CrossDevicePromo::OptOut() { - VLOG(1) << "CrossDevicePromo::OptOut."; - UnregisterForCookieChanges(); - prefs_->SetBoolean(prefs::kCrossDevicePromoOptedOut, true); - MarkPromoShouldNotBeShown(); -} - -void CrossDevicePromo::MaybeBrowsingSessionStarted( - const base::Time& previous_last_active) { - // In tests, or the first call for a profile, do nothing. - if (previous_last_active == base::Time()) - return; - - const base::Time time_now = base::Time::Now(); - // Determine how often this method is called as an upper bound for how often - // back end servers might be called. - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Signin.XDevicePromo.BrowsingSessionDurationComputed", - (base::Time::Now() - previous_last_active).InMinutes(), 1, - base::TimeDelta::FromDays(30).InMinutes(), 50); - - // Check if this is a different browsing session since the last call. - if (time_now - previous_last_active < - inactivity_between_browsing_sessions_) { - VLOG(1) << "CrossDevicePromo::MaybeBrowsingSessionStarted. Same browsing " - "session as the last call."; - return; - } - - if (start_last_browsing_session_ != base::Time()) - signin_metrics::LogBrowsingSessionDuration(previous_last_active); - - start_last_browsing_session_ = time_now; - - if (!CheckPromoEligibility()) { - VLOG(1) << "CrossDevicePromo::MaybeBrowsingSessionStarted; " - << "Ineligible for promo."; - if (ShouldShowPromo()) - MarkPromoShouldNotBeShown(); - return; - } - - // Check if there is a record of recent browsing activity on another device. - const base::Time device_last_active = GetTimePref( - prefs::kCrossDevicePromoLastDeviceActiveTime); - if (time_now - device_last_active < context_switch_duration_) { - VLOG(1) << "CrossDevicePromo::MaybeBrowsingSessionStarted; promo active."; - signin_metrics::LogXDevicePromoEligible(signin_metrics::ELIGIBLE); - MarkPromoShouldBeShown(); - return; - } - - // Check for recency of device activity unless a check is already being - // executed because the number of devices is being updated. Use a small delay - // to ensure server-side data is synchronized. - if (!device_activity_fetcher_) { - VLOG(1) << "CrossDevicePromo::MaybeBrowsingSessionStarted; " - << "Check device activity."; - const int kDelayUntilGettingDeviceActivityInMS = 3000; - device_activity_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kDelayUntilGettingDeviceActivityInMS), - this, &CrossDevicePromo::GetDevicesActivityForGAIAAccountInCookieJar); - } -} - -bool CrossDevicePromo::CheckPromoEligibilityForTesting() { - // The field trial may not have been present when Init() was called from the - // constructor. - if (!initialized_) - Init(); - - return CheckPromoEligibility(); -} - -void CrossDevicePromo::Init() { - DCHECK(!initialized_); - // We need a default value for |inactivity_between_browsing_sessions_| - // as it is referenced early in MaybeBrowsingSessionStarted and we want to - // gather as many stats about browsing sessions as possible. - const int kDefaultBrowsingSessionDurationInMinutes = 15; - inactivity_between_browsing_sessions_ = - base::TimeDelta::FromMinutes(kDefaultBrowsingSessionDurationInMinutes); - - if (prefs_->GetBoolean(prefs::kCrossDevicePromoOptedOut)) { - signin_metrics::LogXDevicePromoInitialized( - signin_metrics::UNINITIALIZED_OPTED_OUT); - return; - } - - if (!SetParameterFromVariation(kParamHoursBetweenDeviceActivityChecks, - base::Bind(&base::TimeDelta::FromHours), - &delay_until_next_device_activity_fetch_) || - !SetParameterFromVariation(kParamDaysToVerifySingleUserProfile, - base::Bind(&base::TimeDelta::FromDays), - &single_account_duration_threshold_) || - !SetParameterFromVariation(kParamMinutesBetweenBrowsingSessions, - base::Bind(&base::TimeDelta::FromMinutes), - &inactivity_between_browsing_sessions_) || - !SetParameterFromVariation(kParamMinutesMaxContextSwitchDuration, - base::Bind(&base::TimeDelta::FromMinutes), - &context_switch_duration_)) { - signin_metrics::LogXDevicePromoInitialized( - signin_metrics::NO_VARIATIONS_CONFIG); - return; - } - - const std::string throttle = variations::GetVariationParamValue( - kCrossDevicePromoFieldTrial, kParamRPCThrottle); - int throttle_percent; - if (throttle.empty() || !base::StringToInt(throttle, &throttle_percent)) { - signin_metrics::LogXDevicePromoInitialized( - signin_metrics::NO_VARIATIONS_CONFIG); - return; - } - - is_throttled_ = throttle_percent && base::RandInt(0, 99) < throttle_percent; - - VLOG(1) << "CrossDevicePromo::Init. Service initialized. Parameters: " - << "Hour between RPC checks: " - << delay_until_next_device_activity_fetch_.InHours() - << " Days to verify an account in the cookie: " - << single_account_duration_threshold_.InDays() - << " Minutes between browsing sessions: " - << inactivity_between_browsing_sessions_.InMinutes() - << " Window (in minutes) for a context switch: " - << context_switch_duration_.InMinutes() - << " Throttle rate for RPC calls: " << throttle_percent - << " This promo is throttled: " << is_throttled_; - RegisterForCookieChanges(); - initialized_ = true; - signin_metrics::LogXDevicePromoInitialized(signin_metrics::INITIALIZED); - return; -} - -void CrossDevicePromo::MarkPromoShouldBeShown() { - VLOG(1) << "CrossDevicePromo::MarkPromoShouldBeShown."; - DCHECK(!prefs_->GetBoolean(prefs::kCrossDevicePromoOptedOut)); - - if (!prefs_->GetBoolean(prefs::kCrossDevicePromoShouldBeShown)) { - prefs_->SetBoolean(prefs::kCrossDevicePromoShouldBeShown, true); - for (CrossDevicePromo::Observer& observer : observer_list_) - observer.OnPromoEligibilityChanged(true); - } -} - -void CrossDevicePromo::MarkPromoShouldNotBeShown() { - VLOG(1) << "CrossDevicePromo::MarkPromoShouldNotBeShown."; - if (prefs_->GetBoolean(prefs::kCrossDevicePromoShouldBeShown)) { - prefs_->SetBoolean(prefs::kCrossDevicePromoShouldBeShown, false); - for (CrossDevicePromo::Observer& observer : observer_list_) - observer.OnPromoEligibilityChanged(false); - } -} - -bool CrossDevicePromo::CheckPromoEligibility() { - if (!initialized_) - return false; - - if (prefs_->GetBoolean(prefs::kCrossDevicePromoOptedOut)) { - signin_metrics::LogXDevicePromoEligible(signin_metrics::OPTED_OUT); - return false; - } - - if (signin_manager_->IsAuthenticated()) { - signin_metrics::LogXDevicePromoEligible(signin_metrics::SIGNED_IN); - return false; - } - - if (!prefs_->HasPrefPath( - prefs::kCrossDevicePromoObservedSingleAccountCookie) || - (GetTimePref(prefs::kCrossDevicePromoObservedSingleAccountCookie) + - single_account_duration_threshold_ > base::Time::Now())) { - signin_metrics::LogXDevicePromoEligible( - signin_metrics::NOT_SINGLE_GAIA_ACCOUNT); - return false; - } - - if (!prefs_->HasPrefPath(prefs::kCrossDevicePromoNextFetchListDevicesTime)) { - // The missing preference indicates CheckPromoEligibility() has never been - // called. Determine when to call the DeviceActivityFetcher for the first - // time. - const uint64_t milliseconds_until_next_activity_fetch = base::RandGenerator( - delay_until_next_device_activity_fetch_.InMilliseconds()); - const base::Time time_of_next_device_activity_fetch = base::Time::Now() + - base::TimeDelta::FromMilliseconds( - milliseconds_until_next_activity_fetch); - SetTimePref(prefs::kCrossDevicePromoNextFetchListDevicesTime, - time_of_next_device_activity_fetch); - signin_metrics::LogXDevicePromoEligible( - signin_metrics::UNKNOWN_COUNT_DEVICES); - return false; - } - - if (!prefs_->HasPrefPath(prefs::kCrossDevicePromoNumDevices)) { - // The missing pref indicates no knowledge of other device activity yet. - const base::Time time_next_list_devices = GetTimePref( - prefs::kCrossDevicePromoNextFetchListDevicesTime); - // Not time yet to poll the list of devices. - if (base::Time::Now() < time_next_list_devices) { - signin_metrics::LogXDevicePromoEligible( - signin_metrics::UNKNOWN_COUNT_DEVICES); - return false; - } - // We're not eligible... yet! Track metrics in the results. - GetDevicesActivityForGAIAAccountInCookieJar(); - return false; - } - - int num_devices = prefs_->GetInteger(prefs::kCrossDevicePromoNumDevices); - const base::Time time_next_list_devices = GetTimePref( - prefs::kCrossDevicePromoNextFetchListDevicesTime); - if (base::Time::Now() > time_next_list_devices) { - GetDevicesActivityForGAIAAccountInCookieJar(); - } else if (num_devices == 0) { - signin_metrics::LogXDevicePromoEligible(signin_metrics::ZERO_DEVICES); - return false; - } - - DCHECK(VerifyPromoEligibleReadOnly()); - return true; -} - -void CrossDevicePromo::DetermineEligibilityFromDeviceActivity( - const std::vector<DeviceActivityFetcher::DeviceActivity>& devices) { - - const base::Time time_now = base::Time::Now(); - SetTimePref(prefs::kCrossDevicePromoNextFetchListDevicesTime, - time_now + delay_until_next_device_activity_fetch_); - prefs_->SetInteger(prefs::kCrossDevicePromoNumDevices, devices.size()); - - if (devices.empty()) { - signin_metrics::LogXDevicePromoEligible(signin_metrics::ZERO_DEVICES); - return; - } - - const base::Time most_recent_last_active = - std::max_element(devices.begin(), devices.end(), - [](const DeviceActivityFetcher::DeviceActivity& first, - const DeviceActivityFetcher::DeviceActivity& second) { - return first.last_active < second.last_active; - })->last_active; - - SetTimePref(prefs::kCrossDevicePromoLastDeviceActiveTime, - most_recent_last_active); - - if (time_now - most_recent_last_active < context_switch_duration_) { - // Make sure that while the DeviceActivityFetcher was executing the promo - // wasn't found as ineligible to be shown. - if (!VerifyPromoEligibleReadOnly()) - return; - - // The context switch will only be valid for so long. Schedule another - // device activity check for when our switch would expire to check for more - // recent activity. - if (!device_activity_timer_.IsRunning()) { - base::TimeDelta time_to_next_check = most_recent_last_active + - context_switch_duration_ - - time_now; - device_activity_timer_.Start( - FROM_HERE, time_to_next_check, this, - &CrossDevicePromo::GetDevicesActivityForGAIAAccountInCookieJar); - } - - signin_metrics::LogXDevicePromoEligible(signin_metrics::ELIGIBLE); - MarkPromoShouldBeShown(); - } else { - signin_metrics::LogXDevicePromoEligible(signin_metrics::NO_ACTIVE_DEVICES); - MarkPromoShouldNotBeShown(); - } -} - -base::Time CrossDevicePromo::GetTimePref(const std::string& pref) const { - return base::Time::FromInternalValue(prefs_->GetInt64(pref)); -} - -void CrossDevicePromo::SetTimePref(const std::string& pref, - const base::Time& value) { - prefs_->SetInt64(pref, value.ToInternalValue()); -} - -bool CrossDevicePromo::VerifyPromoEligibleReadOnly() const { - return initialized_ && - !prefs_->GetBoolean(prefs::kCrossDevicePromoOptedOut) && - prefs_->HasPrefPath( - prefs::kCrossDevicePromoObservedSingleAccountCookie) && - GetTimePref(prefs::kCrossDevicePromoObservedSingleAccountCookie) + - single_account_duration_threshold_ <= base::Time::Now(); -} - -void CrossDevicePromo::GetDevicesActivityForGAIAAccountInCookieJar() { - // Don't start a fetch while one is processing. - if (device_activity_fetcher_) - return; - - if (is_throttled_) { - signin_metrics::LogXDevicePromoEligible( - signin_metrics::THROTTLED_FETCHING_DEVICE_ACTIVITY); - return; - } - - VLOG(1) << "CrossDevicePromo::GetDevicesActivityForGAIAAccountInCookieJar."; - DCHECK(VerifyPromoEligibleReadOnly()); - device_activity_fetcher_.reset( - new DeviceActivityFetcher(signin_client_, this)); - device_activity_fetcher_->Start(); -} - -void CrossDevicePromo::RegisterForCookieChanges() { - cookie_manager_service_->AddObserver(this); -} - -void CrossDevicePromo::UnregisterForCookieChanges() { - cookie_manager_service_->RemoveObserver(this); -}
diff --git a/chrome/browser/signin/cross_device_promo.h b/chrome/browser/signin/cross_device_promo.h deleted file mode 100644 index f6a5c55..0000000 --- a/chrome/browser/signin/cross_device_promo.h +++ /dev/null
@@ -1,239 +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 CHROME_BROWSER_SIGNIN_CROSS_DEVICE_PROMO_H_ -#define CHROME_BROWSER_SIGNIN_CROSS_DEVICE_PROMO_H_ - -#include "base/macros.h" -#include "base/observer_list.h" -#include "base/timer/timer.h" -#include "components/keyed_service/core/keyed_service.h" -#include "components/signin/core/browser/device_activity_fetcher.h" -#include "components/signin/core/browser/gaia_cookie_manager_service.h" - -class PrefService; -class SigninClient; -class SigninManager; - -// The Cross Device Promo promotes Chrome Signin within a profile where there is -// one GAIA account signed in to the content area for a long period of time -// (indicating that this profile is used by only one user) and where that -// account uses Chrome Sync on other devices but is not signed in here. -// -// This class determines whether the above criteria have been met and thus -// whether the promo should be displayed. This class imposes additional criteria -// such that the promo is only displayed if there is sufficiently recent -// activity on another device, indicating the user is switching contexts but -// continuing their browsing activity. This class's behavior is controlled by -// the "CrossDevicePromo" field trial. -// The UI is defined elsewhere. -// -// This class implements the preferences necessary to track whether a profile -// meets the above criteria, and whether the user has permanently opted out of -// the promo. -// -// The class relies on the GaiaCookieManagerService to determine if there has -// been a single GAIA account signed in to the content area for a long period of -// time, and relies on the DeviceActivityFetcher to determine if that account -// uses Chrome Sync on other devices. -class CrossDevicePromo : public KeyedService, - public GaiaCookieManagerService::Observer, - public DeviceActivityFetcher::Observer { - public: - class Observer { - public: - // Called when the profile moves from being ineligible to eligible for the - // promo or vice versa; the new state is noted in the |eligible| parameter. - virtual void OnPromoEligibilityChanged(bool eligible) = 0; - }; - - // The following constants are the parameters for a particular experiment - // within the field trial that controls this class's behaviors. - static const char kCrossDevicePromoFieldTrial[]; - // This field trial parameter specifies how often the device activity should - // be fetched. - static const char kParamHoursBetweenDeviceActivityChecks[]; - // This field trial parameter defines for how long the profile's cookie must - // contain exactly one GAIA account before the profile is considered - // single-user. - static const char kParamDaysToVerifySingleUserProfile[]; - // This field trial parameter defines how much time must pass between calls - // to MaybeBrowsingSessionStarted() before the code considers a new browsing - // session to have started and re-evaluates if the promo should be shown. - static const char kParamMinutesBetweenBrowsingSessions[]; - // This field trial parameter defines how much time may pass between the last - // observed device activity and the start of a new browsing session for the - // promo to consider the new browsing session to be a context switch. - static const char kParamMinutesMaxContextSwitchDuration[]; - // This field trial parameter defines what percentage of all device activity - // fetches should be not be executed, to throttle requests to the server. - static const char kParamRPCThrottle[]; - - // Constructor takes non-null pointers to required services. This object does - // not take ownership of any of the passed objects. This also calls Init(). - explicit CrossDevicePromo(SigninManager* signin_manager, - GaiaCookieManagerService* cookie_manager_service, - SigninClient* signin_client, - PrefService* pref_service); - ~CrossDevicePromo() override; - - // KeyedService: - // Ends observation of other services and records the length of any current - // browsing session (see signin_metrics::LogBrowsingSessionDuration()). This - // is called only during Chrome shutdown. - void Shutdown() override; - - // GaiaCookieManagerService::Observer: - // This supports monitoring whether the content area is signed into exactly - // one GAIA account for a long period of time. This tracks the earliest time - // |accounts| contained (and still contains) exactly one account, so that - // other methods can use kParamDaysToVerifySingleUserProfile to verify if this - // Profile is considered single-user. - void OnGaiaAccountsInCookieUpdated( - const std::vector<gaia::ListedAccount>& accounts, - const std::vector<gaia::ListedAccount>& signed_out_accounts, - const GoogleServiceAuthError& error) override; - - // DeviceActivityFetcher::Observer: - // OnFetchDeviceActivity* are called from |device_activity_fetcher_| which - // was created in GetDevicesActivityForGAIAAccountInCookieJar(). Deletes - // |device_activity_fetcher_| at the end of the method. - // See DetermineEligibilityFromDeviceActivity() for details. - void OnFetchDeviceActivitySuccess( - const std::vector<DeviceActivityFetcher::DeviceActivity>& devices) - override; - void OnFetchDeviceActivityFailure() override; - - // Callable by third parties to register or unregister for callbacks when the - // promo's eligibility-to-be-shown state changes. - void AddObserver(CrossDevicePromo::Observer* observer); - void RemoveObserver(CrossDevicePromo::Observer* observer); - - // Returns whether the profile has been marked as eligible to be shown the - // promo. - bool ShouldShowPromo() const; - - // Called when the user requests to opt out of the promo. This will set a pref - // that forever marks the profile ineligible for the promo. - void OptOut(); - - // Called whenever a browser becomes active. Notes the start of a new browsing - // session if the last call to this method (noted in |previous_last_active|) - // was more than |inactivity_between_browsing_sessions_| ago. For new browsing - // sessions, will either determine if the promo is eligible to be shown, or - // will use |device_activity_timer_| to schedule getting more information with - // GetDevicesActivityForGAIAAccountInCookieJar(). - void MaybeBrowsingSessionStarted(const base::Time& previous_last_active); - - // Called only in tests; calls Init() if not already initialized. See comments - // on |initialized_| for details. - bool CheckPromoEligibilityForTesting(); - - private: - // Initializes configuration parameters from the "CrossDevicePromo" field - // trial and registers for changes to the relevant GAIA cookie. In tests, this - // may be called more than once; see |initialized_| for details. - void Init(); - - // Called when the determination of whether to show the promo has been made. - // This both stores that decision and notifies all registered observers of any - // change. - void MarkPromoShouldBeShown(); - void MarkPromoShouldNotBeShown(); - - // Performs all checks to determine if this profile could be shown the promo - // except for initiating a fetch for additional data. This will return false - // if the data available locally indicates the profile should not be shown - // the promo; returns true if the profile could be shown the promo (even if - // additional checks are to be performed). - bool CheckPromoEligibility(); - - // Called whenever new device activity is available. Checks that there is at - // least one device that had activity within the past - // kParamMinutesMaxContextSwitchDuration to determine if the promo should be - // shown. Once determined, the MarkPromoShould[Not]BeShown() method is called. - // Note that if the device is in a context switch, a followup call to - // GetDevicesActivityForGAIAAccountInCookieJar() will be scheduled for when - // the context switch would expire. - void DetermineEligibilityFromDeviceActivity( - const std::vector<DeviceActivityFetcher::DeviceActivity>& devices); - - // Helpers to get and set the time value stored in a pref. - base::Time GetTimePref(const std::string& pref) const; - void SetTimePref(const std::string& pref, const base::Time& value); - - // Performs checks if the promo is eligible to be displayed to this profile. - // This will not write any prefs or initiate any checks that are otherwise - // called in CheckPromoEligibility(). Records no metrics. Used for DCHECKs. - bool VerifyPromoEligibleReadOnly() const; - - // Adds or removes |this| as an observer of |cookie_manager_service_|. - // We observe the |cookie_manager_service_| for its lifetime. - void RegisterForCookieChanges(); - void UnregisterForCookieChanges(); - - // Creates a new DeviceActivityFetcher to get the list of devices, and the - // details of the devices (see DeviceActivityFetcher.h) where the GAIA account - // in this profile's cookie jar is signed in to Chrome Sync. - // If a |device_activity_fetcher_| is already executing a fetch, this method - // will not start a second fetch, as the results would be the same. - void GetDevicesActivityForGAIAAccountInCookieJar(); - - // Set by Init() to indicate if the promo service has been successfully - // initialized. Initialization will not occur if the user has previously opted - // out of the promo. Also, successful initialization requires all necessary - // parameters that control the promo to be read from the field trial. - // In testing an initial call to Init() may fail and a future call may succeed - // (see Init()); in non-test scenarios, however, failed initialization is - // unrecoverable and future calls to other class methods should be no-ops. - bool initialized_; - - // These four pointers are weak pointers; they are not owned by this object - // and will outlive this object. - SigninManager* signin_manager_; - GaiaCookieManagerService* cookie_manager_service_; - PrefService* prefs_; - SigninClient* signin_client_; - - std::unique_ptr<DeviceActivityFetcher> device_activity_fetcher_; - base::ObserverList<CrossDevicePromo::Observer> observer_list_; - - // Initialized from the |kParamMinutesMaxContextSwitchDuration| field trial - // parameter. See |kParamMinutesMaxContextSwitchDuration| for details. - base::TimeDelta context_switch_duration_; - - // If the device activity has never been fetched, the delay until the check - // will be a random duration between zero and - // |kParamHoursBetweenDeviceActivityChecks|. For all other - // fetches, the delay will be |kParamHoursBetweenDeviceActivityChecks|. See - // |kParamHoursBetweenDeviceActivityChecks| for details. - base::TimeDelta delay_until_next_device_activity_fetch_; - - // Initialized from the |kParamDaysToVerifySingleUserProfile| field trial - // parameter. See |kParamDaysToVerifySingleUserProfile| for details. - base::TimeDelta single_account_duration_threshold_; - - // Initialized from the |kParamMinutesBetweenBrowsingSessions| field trial - // parameter. See |kParamMinutesBetweenBrowsingSessions| for details. - base::TimeDelta inactivity_between_browsing_sessions_; - - // Randomly initialized from the |kParamRPCThrottle| field trial parameter. - // See |kParamRPCThrottle| for details. If true, |device_activity_fetcher_| - // should never be initialized. - bool is_throttled_; - - // Metric to help us track how long a browsing session is. This is set in - // MaybeBrowsingSessionStarted(), see that method for details. - // Useful for configuring the field trial to manage our server quota. - base::Time start_last_browsing_session_; - - // Used to delay the check of device activity. See - // OnFetchDeviceActivitySuccess() or MaybeBrowsingSessionStarted(), as well as - // |delay_until_next_device_activity_fetch_|, for details. - base::OneShotTimer device_activity_timer_; - - DISALLOW_COPY_AND_ASSIGN(CrossDevicePromo); -}; - -#endif // CHROME_BROWSER_SIGNIN_CROSS_DEVICE_PROMO_H_
diff --git a/chrome/browser/signin/cross_device_promo_factory.cc b/chrome/browser/signin/cross_device_promo_factory.cc deleted file mode 100644 index 92a89282..0000000 --- a/chrome/browser/signin/cross_device_promo_factory.cc +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/signin/cross_device_promo_factory.h" - -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/signin/chrome_signin_client_factory.h" -#include "chrome/browser/signin/cross_device_promo.h" -#include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" -#include "chrome/browser/signin/signin_manager_factory.h" -#include "chrome/common/pref_names.h" -#include "components/keyed_service/content/browser_context_dependency_manager.h" -#include "components/pref_registry/pref_registry_syncable.h" -#include "components/prefs/pref_service.h" -#include "components/signin/core/browser/signin_manager.h" -#include "components/sync_preferences/pref_service_syncable.h" -#include "google_apis/gaia/gaia_constants.h" - -CrossDevicePromoFactory::CrossDevicePromoFactory() - : BrowserContextKeyedServiceFactory( - "CrossDevicePromo", - BrowserContextDependencyManager::GetInstance()) { - DependsOn(ChromeSigninClientFactory::GetInstance()); - DependsOn(GaiaCookieManagerServiceFactory::GetInstance()); - DependsOn(SigninManagerFactory::GetInstance()); -} - -CrossDevicePromoFactory::~CrossDevicePromoFactory() { -} - -// static -CrossDevicePromo* CrossDevicePromoFactory::GetForProfile(Profile* profile) { - return static_cast<CrossDevicePromo*>( - GetInstance()->GetServiceForBrowserContext(profile, true)); -} - -// static -CrossDevicePromoFactory* CrossDevicePromoFactory::GetInstance() { - return base::Singleton<CrossDevicePromoFactory>::get(); -} - -void CrossDevicePromoFactory::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* user_prefs) { - user_prefs->RegisterBooleanPref(prefs::kCrossDevicePromoOptedOut, false); - user_prefs->RegisterBooleanPref(prefs::kCrossDevicePromoShouldBeShown, false); - user_prefs->RegisterInt64Pref( - prefs::kCrossDevicePromoObservedSingleAccountCookie, - base::Time().ToInternalValue()); - user_prefs->RegisterInt64Pref( - prefs::kCrossDevicePromoNextFetchListDevicesTime, - base::Time().ToInternalValue()); - user_prefs->RegisterIntegerPref(prefs::kCrossDevicePromoNumDevices, 0); - user_prefs->RegisterInt64Pref(prefs::kCrossDevicePromoLastDeviceActiveTime, - base::Time().ToInternalValue()); -} - -KeyedService* CrossDevicePromoFactory::BuildServiceInstanceFor( - content::BrowserContext* context) const { - Profile* profile = Profile::FromBrowserContext(context); - CrossDevicePromo* service = new CrossDevicePromo( - SigninManagerFactory::GetForProfile(profile), - GaiaCookieManagerServiceFactory::GetForProfile(profile), - ChromeSigninClientFactory::GetForProfile(profile), profile->GetPrefs()); - return service; -}
diff --git a/chrome/browser/signin/cross_device_promo_factory.h b/chrome/browser/signin/cross_device_promo_factory.h deleted file mode 100644 index 1f9a5fe..0000000 --- a/chrome/browser/signin/cross_device_promo_factory.h +++ /dev/null
@@ -1,43 +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 CHROME_BROWSER_SIGNIN_CROSS_DEVICE_PROMO_FACTORY_H_ -#define CHROME_BROWSER_SIGNIN_CROSS_DEVICE_PROMO_FACTORY_H_ - -#include "base/macros.h" -#include "base/memory/singleton.h" -#include "components/keyed_service/content/browser_context_keyed_service_factory.h" - -class CrossDevicePromo; -class Profile; - -// Singleton that owns all CrossDevicePromos and associates them with -// Profiles. -class CrossDevicePromoFactory : public BrowserContextKeyedServiceFactory { - public: - // Returns the instance of CrossDevicePromo associated with this profile, - // creating one if none exists. - static CrossDevicePromo* GetForProfile(Profile* profile); - - // Returns an instance of the CrossDevicePromoFactory singleton. - static CrossDevicePromoFactory* GetInstance(); - - // Implementation of BrowserContextKeyedServiceFactory. - void RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) override; - - private: - friend struct base::DefaultSingletonTraits<CrossDevicePromoFactory>; - - CrossDevicePromoFactory(); - ~CrossDevicePromoFactory() override; - - // BrowserContextKeyedServiceFactory - KeyedService* BuildServiceInstanceFor( - content::BrowserContext* context) const override; - - DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoFactory); -}; - -#endif // CHROME_BROWSER_SIGNIN_CROSS_DEVICE_PROMO_FACTORY_H_
diff --git a/chrome/browser/signin/cross_device_promo_unittest.cc b/chrome/browser/signin/cross_device_promo_unittest.cc deleted file mode 100644 index 611fe7a..0000000 --- a/chrome/browser/signin/cross_device_promo_unittest.cc +++ /dev/null
@@ -1,679 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/signin/cross_device_promo.h" - -#include <stdint.h> - -#include <map> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/field_trial.h" -#include "base/run_loop.h" -#include "base/test/histogram_tester.h" -#include "chrome/browser/prefs/browser_prefs.h" -#include "chrome/browser/signin/chrome_signin_client_factory.h" -#include "chrome/browser/signin/cross_device_promo_factory.h" -#include "chrome/browser/signin/fake_gaia_cookie_manager_service_builder.h" -#include "chrome/browser/signin/fake_signin_manager_builder.h" -#include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" -#include "chrome/browser/signin/signin_manager_factory.h" -#include "chrome/browser/signin/test_signin_client_builder.h" -#include "chrome/common/pref_names.h" -#include "chrome/test/base/testing_browser_process.h" -#include "chrome/test/base/testing_profile.h" -#include "chrome/test/base/testing_profile_manager.h" -#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h" -#include "components/signin/core/browser/signin_manager.h" -#include "components/signin/core/browser/signin_metrics.h" -#include "components/signin/core/browser/test_signin_client.h" -#include "components/sync_preferences/pref_service_syncable.h" -#include "components/sync_preferences/testing_pref_service_syncable.h" -#include "components/variations/entropy_provider.h" -#include "components/variations/variations_associated_data.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "google_apis/gaia/gaia_constants.h" -#include "google_apis/gaia/gaia_urls.h" -#include "net/url_request/test_url_fetcher_factory.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -typedef std::map<std::string, std::string> VariationsMap; - -int64_t InTwoHours() { - return (base::Time::Now() + base::TimeDelta::FromHours(2)).ToInternalValue(); -} - -} // namespace - -class CrossDevicePromoObserver : public CrossDevicePromo::Observer { - public: - explicit CrossDevicePromoObserver(CrossDevicePromo* promo) - : eligible_(false), - times_set_eligible_(0), - times_set_ineligible_(0), - promo_(promo) { - promo->AddObserver(this); - } - - ~CrossDevicePromoObserver() { promo_->RemoveObserver(this); } - - void OnPromoEligibilityChanged(bool eligible) override { - eligible_ = eligible; - if (eligible) - ++times_set_eligible_; - else - ++times_set_ineligible_; - } - - bool is_eligible() const { return eligible_; } - int times_set_eligible() const { return times_set_eligible_; } - int times_set_inactive() const { return times_set_ineligible_; } - - private: - bool eligible_; - int times_set_eligible_; - int times_set_ineligible_; - CrossDevicePromo* promo_; - - DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoObserver); -}; - -class CrossDevicePromoTest : public ::testing::Test { - public: - CrossDevicePromoTest(); - - void SetUp() override; - - // Destroys any variations which might be defined, and starts fresh. - void ResetFieldTrialList(); - - // Defines a default set of variation parameters for promo initialization. - void InitPromoVariation(); - - CrossDevicePromo* promo() { return cross_device_promo_; } - TestingProfile* profile() { return profile_; } - FakeSigninManagerForTesting* signin_manager() { return signin_manager_; } - base::HistogramTester* histogram_tester() { return &histogram_tester_; } - sync_preferences::TestingPrefServiceSyncable* prefs() { - return pref_service_; - } - FakeGaiaCookieManagerService* cookie_manager_service() { - return cookie_manager_service_; - } - net::FakeURLFetcherFactory* fetcher_factory() { - return &fake_url_fetcher_factory_; - } - - private: - content::TestBrowserThreadBundle bundle_; - CrossDevicePromo* cross_device_promo_; - TestingProfile* profile_; - FakeSigninManagerForTesting* signin_manager_; - FakeGaiaCookieManagerService* cookie_manager_service_; - sync_preferences::TestingPrefServiceSyncable* pref_service_; - std::unique_ptr<TestingProfileManager> testing_profile_manager_; - base::HistogramTester histogram_tester_; - std::unique_ptr<base::FieldTrialList> field_trial_list_; - net::FakeURLFetcherFactory fake_url_fetcher_factory_; - - DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoTest); -}; - -CrossDevicePromoTest::CrossDevicePromoTest() : fake_url_fetcher_factory_(NULL) { - ResetFieldTrialList(); -} - -void CrossDevicePromoTest::SetUp() { - testing_profile_manager_.reset( - new TestingProfileManager(TestingBrowserProcess::GetGlobal())); - ASSERT_TRUE(testing_profile_manager_.get()->SetUp()); - - TestingProfile::TestingFactories factories; - factories.push_back(std::make_pair(ChromeSigninClientFactory::GetInstance(), - signin::BuildTestSigninClient)); - factories.push_back( - std::make_pair(GaiaCookieManagerServiceFactory::GetInstance(), - BuildFakeGaiaCookieManagerService)); - factories.push_back(std::make_pair(SigninManagerFactory::GetInstance(), - BuildFakeSigninManagerBase)); - - pref_service_ = new sync_preferences::TestingPrefServiceSyncable(); - chrome::RegisterUserProfilePrefs(pref_service_->registry()); - - profile_ = testing_profile_manager_.get()->CreateTestingProfile( - "name", - base::WrapUnique<sync_preferences::PrefServiceSyncable>(pref_service_), - base::UTF8ToUTF16("name"), 0, std::string(), factories); - - cookie_manager_service_ = static_cast<FakeGaiaCookieManagerService*>( - GaiaCookieManagerServiceFactory::GetForProfile(profile())); - cookie_manager_service_->Init(&fake_url_fetcher_factory_); - - signin_manager_ = static_cast<FakeSigninManagerForTesting*>( - SigninManagerFactory::GetForProfile(profile())); - - cross_device_promo_ = CrossDevicePromoFactory::GetForProfile(profile()); -} - -void CrossDevicePromoTest::ResetFieldTrialList() { - // Destroy the existing FieldTrialList before creating a new one to avoid - // a DCHECK. - field_trial_list_.reset(); - field_trial_list_.reset( - new base::FieldTrialList( - base::MakeUnique<metrics::SHA1EntropyProvider>("foo"))); - variations::testing::ClearAllVariationParams(); -} - -void CrossDevicePromoTest::InitPromoVariation() { - VariationsMap variations_params; - variations_params[ - CrossDevicePromo::kParamHoursBetweenDeviceActivityChecks] = "2"; - variations_params[ - CrossDevicePromo::kParamDaysToVerifySingleUserProfile] = "0"; - variations_params[ - CrossDevicePromo::kParamMinutesBetweenBrowsingSessions] = "0"; - variations_params[ - CrossDevicePromo::kParamMinutesMaxContextSwitchDuration] = "10"; - variations_params[ - CrossDevicePromo::kParamRPCThrottle] = "0"; - EXPECT_TRUE(variations::AssociateVariationParams( - CrossDevicePromo::kCrossDevicePromoFieldTrial, "A", variations_params)); - base::FieldTrialList::CreateFieldTrial( - CrossDevicePromo::kCrossDevicePromoFieldTrial, "A"); -} - -// Tests for incrementally large portions flow that determines if the promo -// should be shown. - -TEST_F(CrossDevicePromoTest, Uninitialized) { - ASSERT_TRUE(promo()); - histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", - signin_metrics::NO_VARIATIONS_CONFIG, - 1); - - promo()->CheckPromoEligibilityForTesting(); - histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", - signin_metrics::NO_VARIATIONS_CONFIG, - 2); - histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0); - EXPECT_FALSE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut)); -} - -TEST_F(CrossDevicePromoTest, UnitializedOptedOut) { - CrossDevicePromoObserver observer(promo()); - - promo()->OptOut(); - // Opting out doesn't de-activate a never-active promo. - EXPECT_EQ(0, observer.times_set_inactive()); - EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut)); - - // An opted-out promo will never be initialized. - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", - signin_metrics::NO_VARIATIONS_CONFIG, - 1); - histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", - signin_metrics::UNINITIALIZED_OPTED_OUT, - 1); - histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0); -} - -TEST_F(CrossDevicePromoTest, PartiallyInitialized) { - histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", - signin_metrics::NO_VARIATIONS_CONFIG, - 1); - - VariationsMap variations_params; - variations_params[ - CrossDevicePromo::kParamHoursBetweenDeviceActivityChecks] = "1"; - variations_params[ - CrossDevicePromo::kParamDaysToVerifySingleUserProfile] = "1"; - EXPECT_TRUE(variations::AssociateVariationParams( - CrossDevicePromo::kCrossDevicePromoFieldTrial, "A", variations_params)); - base::FieldTrialList::CreateFieldTrial( - CrossDevicePromo::kCrossDevicePromoFieldTrial, "A"); - - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", - signin_metrics::NO_VARIATIONS_CONFIG, - 2); - histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0); -} - -TEST_F(CrossDevicePromoTest, FullyInitialized) { - histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", - signin_metrics::NO_VARIATIONS_CONFIG, - 1); - - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", - signin_metrics::NO_VARIATIONS_CONFIG, - 2); - - InitPromoVariation(); - signin_manager()->SignIn("12345", "foo@bar.com", "password"); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", - signin_metrics::INITIALIZED, 1); - histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", - signin_metrics::NO_VARIATIONS_CONFIG, - 2); - - histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Eligibility", - signin_metrics::SIGNED_IN, 1); -} - -TEST_F(CrossDevicePromoTest, InitializedOptOut) { - // In a normal browser, the variations get set before the CrossDevicePromo is - // created. Here, we need to force another Init() by calling - // CheckPromoEligibilityForTesting(). - InitPromoVariation(); - signin_manager()->SignIn("12345", "foo@bar.com", "password"); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - - histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", - signin_metrics::INITIALIZED, 1); - histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Eligibility", - signin_metrics::SIGNED_IN, 1); - - // After opting out the initialized state remains; eligibility changes. - promo()->OptOut(); - promo()->CheckPromoEligibilityForTesting(); - histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", - signin_metrics::INITIALIZED, 1); - histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Eligibility", - signin_metrics::OPTED_OUT, 1); -} - -TEST_F(CrossDevicePromoTest, SignedInAndOut) { - InitPromoVariation(); - - { - base::HistogramTester test_signed_in; - signin_manager()->SignIn("12345", "foo@bar.com", "password"); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - test_signed_in.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", - signin_metrics::SIGNED_IN, 1); - } - - { - base::HistogramTester test_signed_out; - signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST, - signin_metrics::SignoutDelete::IGNORE_METRIC); - promo()->CheckPromoEligibilityForTesting(); - test_signed_out.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", - signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, - 1); - } -} - -TEST_F(CrossDevicePromoTest, TrackAccountsInCookie) { - InitPromoVariation(); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - - ASSERT_FALSE(prefs()->HasPrefPath( - prefs::kCrossDevicePromoObservedSingleAccountCookie)); - std::vector<gaia::ListedAccount> accounts; - - // Setting a single cookie sets the time. - base::Time before_setting_cookies = base::Time::Now(); - cookie_manager_service()->set_list_accounts_stale_for_testing(true); - cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1"); - EXPECT_FALSE(cookie_manager_service()->ListAccounts( - &accounts, nullptr, GaiaConstants::kChromeSource)); - base::RunLoop().RunUntilIdle(); - - base::Time after_setting_cookies = base::Time::Now(); - EXPECT_TRUE(prefs()->HasPrefPath( - prefs::kCrossDevicePromoObservedSingleAccountCookie)); - EXPECT_LE( - before_setting_cookies.ToInternalValue(), - prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); - EXPECT_GE( - after_setting_cookies.ToInternalValue(), - prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); - - // A single cookie a second time doesn't change the time. - cookie_manager_service()->set_list_accounts_stale_for_testing(true); - cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1"); - EXPECT_FALSE(cookie_manager_service()->ListAccounts( - &accounts, nullptr, GaiaConstants::kChromeSource)); - base::RunLoop().RunUntilIdle(); - - EXPECT_TRUE(prefs()->HasPrefPath( - prefs::kCrossDevicePromoObservedSingleAccountCookie)); - EXPECT_GE( - after_setting_cookies.ToInternalValue(), - prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); - - // Setting accounts with an auth error doesn't change the time. - cookie_manager_service()->set_list_accounts_stale_for_testing(true); - cookie_manager_service()->SetListAccountsResponseWebLoginRequired(); - EXPECT_FALSE(cookie_manager_service()->ListAccounts( - &accounts, nullptr, GaiaConstants::kChromeSource)); - base::RunLoop().RunUntilIdle(); - - EXPECT_TRUE(prefs()->HasPrefPath( - prefs::kCrossDevicePromoObservedSingleAccountCookie)); - EXPECT_LE( - before_setting_cookies.ToInternalValue(), - prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); - EXPECT_GE( - after_setting_cookies.ToInternalValue(), - prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); - - // Seeing zero accounts clears the pref. - cookie_manager_service()->set_list_accounts_stale_for_testing(true); - cookie_manager_service()->SetListAccountsResponseNoAccounts(); - EXPECT_FALSE(cookie_manager_service()->ListAccounts( - &accounts, nullptr, GaiaConstants::kChromeSource)); - base::RunLoop().RunUntilIdle(); - - EXPECT_FALSE(prefs()->HasPrefPath( - prefs::kCrossDevicePromoObservedSingleAccountCookie)); -} - -TEST_F(CrossDevicePromoTest, SingleAccountEligibility) { - InitPromoVariation(); - - { - base::HistogramTester test_single_account; - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - test_single_account.ExpectUniqueSample( - "Signin.XDevicePromo.Eligibility", - signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, 1); - } - - // Notice a single account. - { - base::HistogramTester test_single_account; - std::vector<gaia::ListedAccount> accounts; - cookie_manager_service()->set_list_accounts_stale_for_testing(true); - cookie_manager_service()->SetListAccountsResponseOneAccount("a@b.com", "1"); - EXPECT_FALSE(cookie_manager_service()->ListAccounts( - &accounts, nullptr, GaiaConstants::kChromeSource)); - base::RunLoop().RunUntilIdle(); - - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - test_single_account.ExpectUniqueSample( - "Signin.XDevicePromo.Eligibility", - signin_metrics::UNKNOWN_COUNT_DEVICES, 1); - } - - // Set a single account that hasn't been around for "long enough". - { - base::HistogramTester test_single_account; - prefs()->SetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie, - InTwoHours()); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - test_single_account.ExpectBucketCount( - "Signin.XDevicePromo.Eligibility", - signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, 1); - } -} - -TEST_F(CrossDevicePromoTest, NumDevicesEligibility) { - // Start with a variation, signed in, and one account in the cookie jar. - InitPromoVariation(); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - cookie_manager_service()->set_list_accounts_stale_for_testing(true); - cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1"); - std::vector<gaia::ListedAccount> accounts; - EXPECT_FALSE(cookie_manager_service()->ListAccounts( - &accounts, nullptr, GaiaConstants::kChromeSource)); - base::RunLoop().RunUntilIdle(); - - // Ensure we appropriate schedule a check for device activity. - { - base::HistogramTester test_missing_list_devices; - int64_t earliest_time_to_check_list_devices = - base::Time::Now().ToInternalValue(); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - int64_t latest_time_to_check_list_devices = InTwoHours(); - test_missing_list_devices.ExpectUniqueSample( - "Signin.XDevicePromo.Eligibility", - signin_metrics::UNKNOWN_COUNT_DEVICES, 1); - EXPECT_TRUE( - prefs()->HasPrefPath(prefs::kCrossDevicePromoNextFetchListDevicesTime)); - int64_t when_to_check_list_devices = - prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime); - EXPECT_LT(earliest_time_to_check_list_devices, when_to_check_list_devices); - EXPECT_GT(latest_time_to_check_list_devices, when_to_check_list_devices); - } - - // Don't reschedule the device activity check if there's one pending. - { - base::HistogramTester test_unknown_devices; - int64_t list_devices_time = InTwoHours(); - prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, - list_devices_time); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - test_unknown_devices.ExpectUniqueSample( - "Signin.XDevicePromo.Eligibility", - signin_metrics::UNKNOWN_COUNT_DEVICES, 1); - // The scheduled time to fetch device activity should not have changed. - EXPECT_EQ( - list_devices_time, - prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); - } - - // Execute the device activity fetch if it's time. - { - base::HistogramTester test_unknown_devices; - prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, - base::Time::Now().ToInternalValue()); - // The DeviceActivityFetcher will return an error to the promo service. - fetcher_factory()->SetFakeResponse( - GaiaUrls::GetInstance()->oauth2_iframe_url(), "not json", net::HTTP_OK, - net::URLRequestStatus::SUCCESS); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - base::RunLoop().RunUntilIdle(); - test_unknown_devices.ExpectUniqueSample( - "Signin.XDevicePromo.Eligibility", - signin_metrics::ERROR_FETCHING_DEVICE_ACTIVITY, 1); - } -} - -TEST_F(CrossDevicePromoTest, ThrottleDeviceActivityCall) { - // Start with a variation (fully throttled), signed in, one account in cookie. - VariationsMap variations_params; - variations_params[ - CrossDevicePromo::kParamHoursBetweenDeviceActivityChecks] = "1"; - variations_params[ - CrossDevicePromo::kParamDaysToVerifySingleUserProfile] = "0"; - variations_params[ - CrossDevicePromo::kParamMinutesBetweenBrowsingSessions] = "0"; - variations_params[ - CrossDevicePromo::kParamMinutesMaxContextSwitchDuration] = "10"; - variations_params[ - CrossDevicePromo::kParamRPCThrottle] = "100"; - EXPECT_TRUE(variations::AssociateVariationParams( - CrossDevicePromo::kCrossDevicePromoFieldTrial, "A", variations_params)); - base::FieldTrialList::CreateFieldTrial( - CrossDevicePromo::kCrossDevicePromoFieldTrial, "A"); - - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - cookie_manager_service()->set_list_accounts_stale_for_testing(true); - cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1"); - std::vector<gaia::ListedAccount> accounts; - EXPECT_FALSE(cookie_manager_service()->ListAccounts( - &accounts, nullptr, GaiaConstants::kChromeSource)); - base::RunLoop().RunUntilIdle(); - - // Ensure device activity fetches get throttled. - { - base::HistogramTester test_throttle_rpc; - prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, - base::Time::Now().ToInternalValue()); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - test_throttle_rpc.ExpectUniqueSample( - "Signin.XDevicePromo.Eligibility", - signin_metrics::THROTTLED_FETCHING_DEVICE_ACTIVITY, 1); - } -} - -TEST_F(CrossDevicePromoTest, NumDevicesKnown) { - // Start with a variation, signed in, and one account, fetch device activity - // in two hours. - InitPromoVariation(); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - cookie_manager_service()->set_list_accounts_stale_for_testing(true); - cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1"); - std::vector<gaia::ListedAccount> accounts; - EXPECT_FALSE(cookie_manager_service()->ListAccounts( - &accounts, nullptr, GaiaConstants::kChromeSource)); - base::RunLoop().RunUntilIdle(); - prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, - InTwoHours()); - - // Verify that knowing there are no devices for this account logs the - // appropriate metric for ineligibility. - { - base::HistogramTester test_no_devices; - prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices, 0); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - test_no_devices.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", - signin_metrics::ZERO_DEVICES, 1); - } - - // Verify that knowing there is another device for this account results in the - // promo being eligible to be shown. - { - prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices, 1); - EXPECT_TRUE(promo()->CheckPromoEligibilityForTesting()); - } -} - -TEST_F(CrossDevicePromoTest, FetchDeviceResults) { - // Start with a variation, signed in, and one account, fetch device activity - // in 2 hours. - InitPromoVariation(); - EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); - cookie_manager_service()->set_list_accounts_stale_for_testing(true); - cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1"); - std::vector<gaia::ListedAccount> accounts; - EXPECT_FALSE(cookie_manager_service()->ListAccounts( - &accounts, nullptr, GaiaConstants::kChromeSource)); - base::RunLoop().RunUntilIdle(); - prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, - base::Time::Now().ToInternalValue()); - prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices, 1); - - // Verify that if the device activity fetcher returns zero devices the - // eligibility metric will report a ZERO_DEVICES event, and will not report - // the promo as eligible to be shown. - { - base::HistogramTester test_no_devices; - std::vector<DeviceActivityFetcher::DeviceActivity> devices; - int64_t in_two_hours = InTwoHours(); - promo()->OnFetchDeviceActivitySuccess(devices); - EXPECT_LE( - in_two_hours, - prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); - EXPECT_EQ(0, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices)); - test_no_devices.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", - signin_metrics::ZERO_DEVICES, 1); - } - - // Verify that if the device activity fetcher returns one device that was - // recently active, the promo is marked as eligible and the eligibility - // metric reports an ELIGIBLE event. - { - CrossDevicePromoObserver observer(promo()); - EXPECT_FALSE(observer.is_eligible()); - base::HistogramTester test_one_device; - std::vector<DeviceActivityFetcher::DeviceActivity> devices; - base::Time device_last_active = - base::Time::Now() - base::TimeDelta::FromMinutes(4); - DeviceActivityFetcher::DeviceActivity device; - device.last_active = device_last_active; - device.name = "Aslan"; - devices.push_back(device); - - int64_t in_two_hours = InTwoHours(); - promo()->OnFetchDeviceActivitySuccess(devices); - EXPECT_LE( - in_two_hours, - prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); - EXPECT_EQ(1, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices)); - EXPECT_EQ(device_last_active.ToInternalValue(), - prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime)); - EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoShouldBeShown)); - test_one_device.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", - signin_metrics::ELIGIBLE, 1); - EXPECT_TRUE(observer.is_eligible()); - EXPECT_EQ(1, observer.times_set_eligible()); - } - - // Verify that if the device activity fetcher returns one device that was not - // recently active then the eligibility metric will report a NO_ACTIVE_DEVICES - // event, and will not report the promo as eligible to be shown. - { - CrossDevicePromoObserver observer(promo()); - EXPECT_FALSE(observer.is_eligible()); - base::HistogramTester test_one_device; - std::vector<DeviceActivityFetcher::DeviceActivity> devices; - base::Time device_last_active = - base::Time::Now() - base::TimeDelta::FromMinutes(30); - DeviceActivityFetcher::DeviceActivity device; - device.last_active = device_last_active; - device.name = "Aslan"; - devices.push_back(device); - - int64_t in_two_hours = InTwoHours(); - promo()->OnFetchDeviceActivitySuccess(devices); - EXPECT_LE( - in_two_hours, - prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); - EXPECT_EQ(1, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices)); - EXPECT_EQ(device_last_active.ToInternalValue(), - prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime)); - EXPECT_FALSE(prefs()->GetBoolean(prefs::kCrossDevicePromoShouldBeShown)); - test_one_device.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", - signin_metrics::NO_ACTIVE_DEVICES, 1); - EXPECT_FALSE(observer.is_eligible()); - } - - // Verify that if the device activity fetcher returns two devices and one was - // recently active, that the promo is eligible to be shown and the last active - // time is stored properly. - { - CrossDevicePromoObserver observer(promo()); - EXPECT_FALSE(observer.is_eligible()); - base::HistogramTester test_two_devices; - std::vector<DeviceActivityFetcher::DeviceActivity> devices; - base::Time device1_last_active = - base::Time::Now() - base::TimeDelta::FromMinutes(30); - base::Time device2_last_active = - base::Time::Now() - base::TimeDelta::FromMinutes(3); - DeviceActivityFetcher::DeviceActivity device1; - device1.last_active = device1_last_active; - device1.name = "Aslan"; - devices.push_back(device1); - DeviceActivityFetcher::DeviceActivity device2; - device2.last_active = device2_last_active; - device2.name = "Balrog"; - devices.push_back(device2); - - int64_t in_two_hours = InTwoHours(); - promo()->OnFetchDeviceActivitySuccess(devices); - EXPECT_LE( - in_two_hours, - prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); - EXPECT_EQ(2, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices)); - EXPECT_EQ(device2_last_active.ToInternalValue(), - prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime)); - EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoShouldBeShown)); - test_two_devices.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", - signin_metrics::ELIGIBLE, 1); - EXPECT_TRUE(observer.is_eligible()); - EXPECT_EQ(1, observer.times_set_eligible()); - } -}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 970a1108..a63e782 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1252,8 +1252,6 @@ "views/select_file_dialog_extension.h", "views/select_file_dialog_extension_factory.cc", "views/select_file_dialog_extension_factory.h", - "webui/cast/cast_ui.cc", - "webui/cast/cast_ui.h", ] deps += [ "//chrome/browser/chromeos", @@ -2415,8 +2413,6 @@ "passwords/manage_passwords_icon.cc", "passwords/manage_passwords_icon.h", "web_contents_sizer.mm", - "webui/cast/cast_ui.cc", - "webui/cast/cast_ui.h", ] deps += [ "//chrome/app/nibs:localizer_table", @@ -3062,8 +3058,6 @@ "views/settings_reset_prompt_dialog.h", "views/uninstall_view.cc", "views/uninstall_view.h", - "webui/cast/cast_ui.cc", - "webui/cast/cast_ui.h", "webui/conflicts_ui.cc", "webui/conflicts_ui.h", "webui/welcome_win10_handler.cc", @@ -3436,6 +3430,12 @@ "views/toolbar/media_router_action_platform_delegate_views.h", ] } + if (is_chromeos || is_mac || is_win) { + sources += [ + "webui/cast/cast_ui.cc", + "webui/cast/cast_ui.h", + ] + } deps += [ "//chrome/browser/media/router", "//components/web_modal",
diff --git a/chrome/browser/ui/crypto_module_password_dialog_nss.cc b/chrome/browser/ui/crypto_module_password_dialog_nss.cc index a6270dc..b211d9f 100644 --- a/chrome/browser/ui/crypto_module_password_dialog_nss.cc +++ b/chrome/browser/ui/crypto_module_password_dialog_nss.cc
@@ -17,10 +17,9 @@ namespace { -bool ShouldShowDialog(const net::CryptoModule* module) { +bool ShouldShowDialog(PK11SlotInfo* slot) { // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc. - return (PK11_NeedLogin(module->os_module_handle()) && - !PK11_IsLoggedIn(module->os_module_handle(), NULL /* wincx */)); + return (PK11_NeedLogin(slot) && !PK11_IsLoggedIn(slot, NULL /* wincx */)); } // Basically an asynchronous implementation of NSS's PK11_DoPassword. @@ -28,7 +27,7 @@ // GotPassword for what is yet unimplemented. class SlotUnlocker { public: - SlotUnlocker(const net::CryptoModuleList& modules, + SlotUnlocker(std::vector<crypto::ScopedPK11Slot> modules, chrome::CryptoModulePasswordReason reason, const net::HostPortPair& server, gfx::NativeWindow parent, @@ -41,7 +40,7 @@ void Done(); size_t current_; - net::CryptoModuleList modules_; + std::vector<crypto::ScopedPK11Slot> modules_; chrome::CryptoModulePasswordReason reason_; net::HostPortPair server_; gfx::NativeWindow parent_; @@ -49,13 +48,13 @@ PRBool retry_; }; -SlotUnlocker::SlotUnlocker(const net::CryptoModuleList& modules, +SlotUnlocker::SlotUnlocker(std::vector<crypto::ScopedPK11Slot> modules, chrome::CryptoModulePasswordReason reason, const net::HostPortPair& server, gfx::NativeWindow parent, const base::Closure& callback) : current_(0), - modules_(modules), + modules_(std::move(modules)), reason_(reason), server_(server), parent_(parent), @@ -70,11 +69,8 @@ for (; current_ < modules_.size(); ++current_) { if (ShouldShowDialog(modules_[current_].get())) { ShowCryptoModulePasswordDialog( - modules_[current_]->GetTokenName(), - retry_, - reason_, - server_.host(), - parent_, + PK11_GetTokenName(modules_[current_].get()), retry_, reason_, + server_.host(), parent_, base::Bind(&SlotUnlocker::GotPassword, base::Unretained(this))); return; } @@ -95,8 +91,8 @@ } // TODO(mattm): handle protectedAuthPath - SECStatus rv = PK11_CheckUserPassword(modules_[current_]->os_module_handle(), - password.c_str()); + SECStatus rv = + PK11_CheckUserPassword(modules_[current_].get(), password.c_str()); if (rv == SECWouldBlock) { // Incorrect password. Try again. retry_ = PR_TRUE; @@ -123,7 +119,7 @@ namespace chrome { -void UnlockSlotsIfNecessary(const net::CryptoModuleList& modules, +void UnlockSlotsIfNecessary(std::vector<crypto::ScopedPK11Slot> modules, chrome::CryptoModulePasswordReason reason, const net::HostPortPair& server, gfx::NativeWindow parent, @@ -131,7 +127,8 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); for (size_t i = 0; i < modules.size(); ++i) { if (ShouldShowDialog(modules[i].get())) { - (new SlotUnlocker(modules, reason, server, parent, callback))->Start(); + (new SlotUnlocker(std::move(modules), reason, server, parent, callback)) + ->Start(); return; } } @@ -143,10 +140,10 @@ const net::HostPortPair& server, gfx::NativeWindow parent, const base::Closure& callback) { - net::CryptoModuleList modules; - modules.push_back(net::CryptoModule::CreateFromHandle( - cert->os_cert_handle()->slot)); - UnlockSlotsIfNecessary(modules, reason, server, parent, callback); + std::vector<crypto::ScopedPK11Slot> modules; + modules.push_back( + crypto::ScopedPK11Slot(PK11_ReferenceSlot(cert->os_cert_handle()->slot))); + UnlockSlotsIfNecessary(std::move(modules), reason, server, parent, callback); } } // namespace chrome
diff --git a/chrome/browser/ui/crypto_module_password_dialog_nss.h b/chrome/browser/ui/crypto_module_password_dialog_nss.h index 6d871f3..9fb2d8ed 100644 --- a/chrome/browser/ui/crypto_module_password_dialog_nss.h +++ b/chrome/browser/ui/crypto_module_password_dialog_nss.h
@@ -11,12 +11,11 @@ #include "base/callback_forward.h" #include "base/memory/ref_counted.h" #include "chrome/browser/ui/crypto_module_password_dialog.h" +#include "crypto/scoped_nss_types.h" #include "net/base/host_port_pair.h" #include "ui/gfx/native_widget_types.h" namespace net { -class CryptoModule; -typedef std::vector<scoped_refptr<CryptoModule> > CryptoModuleList; class X509Certificate; } @@ -25,7 +24,7 @@ // Asynchronously unlock |modules|, if necessary. |callback| is called when // done (regardless if any modules were successfully unlocked or not). Should // only be called on UI thread. -void UnlockSlotsIfNecessary(const net::CryptoModuleList& modules, +void UnlockSlotsIfNecessary(std::vector<crypto::ScopedPK11Slot> modules, CryptoModulePasswordReason reason, const net::HostPortPair& server, gfx::NativeWindow parent,
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc index 673351f..7c6bd92 100644 --- a/chrome/browser/ui/toolbar/app_menu_model.cc +++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -732,8 +732,11 @@ CreateZoomMenu(); AddItemWithStringId(IDC_PRINT, IDS_PRINT); + +#if defined(ENABLE_MEDIA_ROUTER) if (media_router::MediaRouterEnabled(browser()->profile())) AddItemWithStringId(IDC_ROUTE_MEDIA, IDS_MEDIA_ROUTER_MENU_ITEM_TITLE); +#endif // defined(ENABLE_MEDIA_ROUTER) AddItemWithStringId(IDC_FIND, IDS_FIND); if (base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc index 0f03b7b..1e7552b8 100644 --- a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc +++ b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc
@@ -26,6 +26,7 @@ #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "services/service_manager/public/cpp/interface_registry.h" @@ -50,6 +51,8 @@ base::CommandLine* command_line) { InProcessBrowserTest::SetUpCommandLine(command_line); command_line->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures); + command_line->AppendSwitchASCII(switches::kEnableFeatures, + features::kWebPayments.name); } void PaymentRequestInteractiveTestBase::SetUpOnMainThread() {
diff --git a/chrome/browser/ui/webui/options/certificate_manager_handler.cc b/chrome/browser/ui/webui/options/certificate_manager_handler.cc index 1ff301c..d23446bf 100644 --- a/chrome/browser/ui/webui/options/certificate_manager_handler.cc +++ b/chrome/browser/ui/webui/options/certificate_manager_handler.cc
@@ -839,11 +839,10 @@ slot_ = certificate_manager_model_->cert_db()->GetPublicSlot(); } - net::CryptoModuleList modules; - modules.push_back(net::CryptoModule::CreateFromHandle(slot_.get())); + std::vector<crypto::ScopedPK11Slot> modules; + modules.push_back(crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get()))); chrome::UnlockSlotsIfNecessary( - modules, - chrome::kCryptoModulePasswordCertImport, + std::move(modules), chrome::kCryptoModulePasswordCertImport, net::HostPortPair(), // unused. GetParentWindow(), base::Bind(&CertificateManagerHandler::ImportPersonalSlotUnlocked,
diff --git a/chrome/browser/ui/webui/settings/certificates_handler.cc b/chrome/browser/ui/webui/settings/certificates_handler.cc index 62a4191..24e40be 100644 --- a/chrome/browser/ui/webui/settings/certificates_handler.cc +++ b/chrome/browser/ui/webui/settings/certificates_handler.cc
@@ -723,10 +723,10 @@ slot_ = certificate_manager_model_->cert_db()->GetPublicSlot(); } - net::CryptoModuleList modules; - modules.push_back(net::CryptoModule::CreateFromHandle(slot_.get())); + std::vector<crypto::ScopedPK11Slot> modules; + modules.push_back(crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get()))); chrome::UnlockSlotsIfNecessary( - modules, chrome::kCryptoModulePasswordCertImport, + std::move(modules), chrome::kCryptoModulePasswordCertImport, net::HostPortPair(), // unused. GetParentWindow(), base::Bind(&CertificatesHandler::ImportPersonalSlotUnlocked,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 92cf7fe..e62cad0 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2116,7 +2116,6 @@ "../browser/ui/ash/shelf_browsertest.cc", "../browser/ui/ash/system_tray_client_browsertest.cc", "../browser/ui/ash/system_tray_delegate_chromeos_browsertest_chromeos.cc", - "../browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc", "../browser/ui/ash/volume_controller_browsertest.cc", "../browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc", ] @@ -2128,6 +2127,10 @@ if (enable_app_list) { deps += [ ":test_support_applist_ash" ] } + + if (enable_media_router) { + sources += [ "../browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc" ] + } } if (use_aura || toolkit_views) { deps += [ "//ui/events:test_support" ] @@ -2166,13 +2169,15 @@ "../browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc", "../browser/ui/views/frame/browser_view_browsertest.cc", "../browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc", - "../browser/ui/views/media_router/media_router_ui_browsertest.cc", "../browser/ui/views/passwords/password_dialog_view_browsertest.cc", "../browser/ui/views/task_manager_view_browsertest.cc", "../browser/ui/views/toolbar/browser_actions_container_browsertest.cc", "../browser/ui/views/translate/translate_bubble_view_browsertest.cc", "../browser/ui/views/web_dialog_view_browsertest.cc", ] + if (enable_media_router) { + sources += [ "../browser/ui/views/media_router/media_router_ui_browsertest.cc" ] + } } } @@ -3696,8 +3701,6 @@ "../browser/ui/toolbar/component_toolbar_actions_factory_unittest.cc", "../browser/ui/toolbar/mock_component_toolbar_actions_factory.cc", "../browser/ui/toolbar/mock_component_toolbar_actions_factory.h", - "../browser/ui/toolbar/mock_media_router_action_controller.cc", - "../browser/ui/toolbar/mock_media_router_action_controller.h", "../browser/ui/toolbar/recent_tabs_builder_test_helper.cc", "../browser/ui/toolbar/recent_tabs_builder_test_helper.h", "../browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc", @@ -3990,8 +3993,6 @@ "../browser/extensions/webstore_inline_installer_unittest.cc", "../browser/extensions/webstore_installer_unittest.cc", "../browser/extensions/zipfile_installer_unittest.cc", - "../browser/media/cast_remoting_sender_unittest.cc", - "../browser/media/cast_transport_host_filter_unittest.cc", "../browser/media_galleries/chromeos/mtp_device_object_enumerator_unittest.cc", "../browser/metrics/extensions_metrics_provider_unittest.cc", "../browser/notifications/extension_welcome_notification_unittest.cc", @@ -4144,6 +4145,12 @@ "../browser/extensions/api/messaging/native_messaging_policy_handler_unittest.cc", ] } + if (enable_media_router) { + sources += [ + "../browser/media/cast_remoting_sender_unittest.cc", + "../browser/media/cast_transport_host_filter_unittest.cc", + ] + } } if (use_ash) { sources += [ @@ -4405,6 +4412,8 @@ "../browser/ui/toolbar/media_router_action_controller_unittest.cc", "../browser/ui/toolbar/media_router_action_unittest.cc", "../browser/ui/toolbar/media_router_contextual_menu_unittest.cc", + "../browser/ui/toolbar/mock_media_router_action_controller.cc", + "../browser/ui/toolbar/mock_media_router_action_controller.h", "../browser/ui/webui/media_router/cast_modes_with_media_sources_unittest.cc", "../browser/ui/webui/media_router/media_cast_mode_unittest.cc", "../browser/ui/webui/media_router/media_router_dialog_controller_impl_unittest.cc", @@ -4776,7 +4785,6 @@ sources += [ "../browser/media/webrtc/native_desktop_media_list_unittest.cc", "../browser/metrics/desktop_session_duration/desktop_session_duration_tracker_unittest.cc", - "../browser/signin/cross_device_promo_unittest.cc", "../browser/signin/signin_global_error_unittest.cc", "../browser/sync/sync_global_error_unittest.cc", "../browser/ui/webui/signin/signin_create_profile_handler_unittest.cc",
diff --git a/chrome/test/data/webrtc/peerconnection_getstats.js b/chrome/test/data/webrtc/peerconnection_getstats.js index b1cc9246..b46cff2 100644 --- a/chrome/test/data/webrtc/peerconnection_getstats.js +++ b/chrome/test/data/webrtc/peerconnection_getstats.js
@@ -17,9 +17,7 @@ * @private */ var kRTCRTPStreamStats = new RTCStats_(null, { - // TODO(hbos): As soon as |ssrc| has changed into a number, change to - // 'number'. https://bugs.chromium.org/p/webrtc/issues/detail?id=7065, 7066 - ssrc: 'any', + ssrc: 'number', associateStatsId: 'string', isRemote: 'boolean', mediaType: 'string', @@ -40,10 +38,13 @@ */ var kRTCCodecStats = new RTCStats_(null, { payloadType: 'number', + mimeType: 'string', + // TODO(hbos): As soon as |codec| has been renamed |mimeType| in the webrtc + // repo, remove this line. https://bugs.webrtc.org/7061 codec: 'string', clockRate: 'number', channels: 'number', - parameters: 'string', + sdpFmtpLine: 'string', implementation: 'string', }); gStatsWhitelist.set('codec', kRTCCodecStats);
diff --git a/chromecast/app/BUILD.gn b/chromecast/app/BUILD.gn index 8de02c8..55c8287 100644 --- a/chromecast/app/BUILD.gn +++ b/chromecast/app/BUILD.gn
@@ -92,6 +92,7 @@ grit("resources") { source = "//chromecast/app/resources/shell_resources.grd" + use_qualified_include = true resource_ids = "//chromecast/app/resources/resource_ids" @@ -104,6 +105,8 @@ grit("chromecast_settings") { source = "//chromecast/app/resources/chromecast_settings.grd" resource_ids = "//chromecast/app/resources/resource_ids" + + # TODO(thakis): Consider removing this in favor of the default directory. output_dir = "$root_gen_dir/chromecast_strings" outputs = [
diff --git a/chromecast/browser/DEPS b/chromecast/browser/DEPS index ab3d80066b..49dff6b9 100644 --- a/chromecast/browser/DEPS +++ b/chromecast/browser/DEPS
@@ -2,6 +2,7 @@ "+cc/base/switches.h", "+chromecast/common", "+chromecast/graphics", + "+chromecast/app/resources/grit/shell_resources.h", "+chromecast/media", "+chromecast/net", "+chromecast/service", @@ -17,7 +18,6 @@ "+gin/v8_initializer.h", "+gpu/command_buffer/service/gpu_switches.h", "+grit/chromecast_settings.h", - "+grit/shell_resources.h", "+media/audio", "+media/base", "+media/mojo",
diff --git a/chromecast/browser/devtools/cast_devtools_manager_delegate.cc b/chromecast/browser/devtools/cast_devtools_manager_delegate.cc index ef3c6b13..d58e8be 100644 --- a/chromecast/browser/devtools/cast_devtools_manager_delegate.cc +++ b/chromecast/browser/devtools/cast_devtools_manager_delegate.cc
@@ -6,8 +6,8 @@ #include "base/macros.h" #include "build/build_config.h" +#include "chromecast/app/grit/shell_resources.h" #include "content/public/browser/devtools_agent_host.h" -#include "grit/shell_resources.h" #include "ui/base/resource/resource_bundle.h" namespace chromecast {
diff --git a/cloud_print/DEPS b/cloud_print/DEPS index 0f0c1a6..edd33b74 100644 --- a/cloud_print/DEPS +++ b/cloud_print/DEPS
@@ -1,5 +1,5 @@ include_rules = [ "+chrome/common", "+chrome/installer/launcher_support", - "+grit", + "+virtual_driver_setup_resources", ]
diff --git a/cloud_print/virtual_driver/win/install/BUILD.gn b/cloud_print/virtual_driver/win/install/BUILD.gn index 3018a21..2762974b 100644 --- a/cloud_print/virtual_driver/win/install/BUILD.gn +++ b/cloud_print/virtual_driver/win/install/BUILD.gn
@@ -59,7 +59,9 @@ visibility = [ ":*" ] source = "virtual_driver_setup_resources.grd" + use_qualified_include = true + # TODO(thakis): Consider removing this in favor of the default directory. output_dir = "$root_gen_dir/virtual_driver_setup_resources" outputs = [
diff --git a/cloud_print/virtual_driver/win/install/setup.cc b/cloud_print/virtual_driver/win/install/setup.cc index 99c0bef3..64eef52 100644 --- a/cloud_print/virtual_driver/win/install/setup.cc +++ b/cloud_print/virtual_driver/win/install/setup.cc
@@ -23,7 +23,7 @@ #include "cloud_print/common/win/install_utils.h" #include "cloud_print/virtual_driver/win/virtual_driver_consts.h" #include "cloud_print/virtual_driver/win/virtual_driver_helpers.h" -#include "grit/virtual_driver_setup_resources.h" +#include "virtual_driver_setup_resources/grit/virtual_driver_setup_resources.h" #include <strsafe.h> // Must be after base headers to avoid deprecation // warnings.
diff --git a/components/doodle/BUILD.gn b/components/doodle/BUILD.gn index 6f4f06ab..1eec0e3 100644 --- a/components/doodle/BUILD.gn +++ b/components/doodle/BUILD.gn
@@ -7,6 +7,9 @@ "doodle_fetcher.h", "doodle_fetcher_impl.cc", "doodle_fetcher_impl.h", + "doodle_service.cc", + "doodle_service.h", + "doodle_types.cc", "doodle_types.h", ] @@ -22,6 +25,7 @@ testonly = true sources = [ "doodle_fetcher_impl_unittest.cc", + "doodle_service_unittest.cc", ] deps = [
diff --git a/components/doodle/doodle_fetcher.h b/components/doodle/doodle_fetcher.h index 5745d6c..f5ef780 100644 --- a/components/doodle/doodle_fetcher.h +++ b/components/doodle/doodle_fetcher.h
@@ -29,7 +29,7 @@ // Fetches a doodle asynchronously. The |callback| is called with a // DoodleState indicating whether the request succeded in fetching a doodle. // If a fetch is already running, the callback will be queued and invoked with - // result from the next completed request. + // the result from the next completed request. virtual void FetchDoodle(FinishedCallback callback) = 0; };
diff --git a/components/doodle/doodle_fetcher_impl.cc b/components/doodle/doodle_fetcher_impl.cc index 90fcdde..a618ec8 100644 --- a/components/doodle/doodle_fetcher_impl.cc +++ b/components/doodle/doodle_fetcher_impl.cc
@@ -7,7 +7,6 @@ #include <utility> #include "base/strings/string_number_conversions.h" -#include "base/time/clock.h" #include "base/time/default_clock.h" #include "base/time/time.h" #include "base/values.h" @@ -130,14 +129,14 @@ std::unique_ptr<base::DictionaryValue> config = base::DictionaryValue::From(std::move(json)); if (!config.get()) { - DLOG(WARNING) << "Doodle JSON is not valid"; + DLOG(WARNING) << "Doodle JSON is not valid."; RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::nullopt); return; } const base::DictionaryValue* ddljson = nullptr; if (!config->GetDictionary("ddljson", &ddljson)) { - DLOG(WARNING) << "Doodle JSON reponse did not contain 'ddljson' key."; + DLOG(WARNING) << "Doodle JSON response did not contain 'ddljson' key."; RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::nullopt); return; } @@ -159,6 +158,8 @@ base::Optional<DoodleConfig> DoodleFetcherImpl::ParseDoodle( const base::DictionaryValue& ddljson) const { DoodleConfig doodle; + // The |large_image| field is required (it's the "default" representation for + // the doodle). if (!ParseImage(ddljson, "large_image", &doodle.large_image)) { return base::nullopt; }
diff --git a/components/doodle/doodle_fetcher_impl.h b/components/doodle/doodle_fetcher_impl.h index 82c9c3f8..53dcbd5 100644 --- a/components/doodle/doodle_fetcher_impl.h +++ b/components/doodle/doodle_fetcher_impl.h
@@ -15,6 +15,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" +#include "base/time/clock.h" #include "components/doodle/doodle_fetcher.h" #include "components/doodle/doodle_types.h" #include "net/url_request/url_fetcher_delegate.h" @@ -24,7 +25,6 @@ class GoogleURLTracker; namespace base { -class Clock; class DictionaryValue; class Value; } @@ -91,7 +91,7 @@ ParseJSONCallback json_parsing_callback_; GoogleURLTracker* google_url_tracker_; - // Allow for an injectable tick clock for testing. + // Allow for an injectable clock for testing. std::unique_ptr<base::Clock> clock_; std::vector<FinishedCallback> callbacks_;
diff --git a/components/doodle/doodle_service.cc b/components/doodle/doodle_service.cc new file mode 100644 index 0000000..fee586c --- /dev/null +++ b/components/doodle/doodle_service.cc
@@ -0,0 +1,62 @@ +// 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 "components/doodle/doodle_service.h" + +#include <utility> + +#include "base/bind.h" + +namespace doodle { + +DoodleService::DoodleService(std::unique_ptr<DoodleFetcher> fetcher) + : fetcher_(std::move(fetcher)) { + DCHECK(fetcher_); +} + +DoodleService::~DoodleService() = default; + +void DoodleService::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void DoodleService::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +void DoodleService::Refresh() { + fetcher_->FetchDoodle( + base::BindOnce(&DoodleService::DoodleFetched, base::Unretained(this))); +} + +void DoodleService::DoodleFetched( + DoodleState state, + const base::Optional<DoodleConfig>& doodle_config) { + if (!cached_config_.has_value() && !doodle_config.has_value()) { + // There was no config before and we didn't get a new one, so there's + // nothing to do. + return; + } + + bool notify = false; + if (cached_config_.has_value() != doodle_config.has_value()) { + // We got a new config, or an existing one went away. + notify = true; + } else { + // There was a config both before and after the update. Notify observers + // only if something relevant changed. + notify = !cached_config_.value().IsEquivalent(doodle_config.value()); + } + + // In any case, update the cache. + cached_config_ = doodle_config; + + if (notify) { + for (auto& observer : observers_) { + observer.OnDoodleConfigUpdated(cached_config_); + } + } +} + +} // namespace doodle
diff --git a/components/doodle/doodle_service.h b/components/doodle/doodle_service.h new file mode 100644 index 0000000..09e1ae1f --- /dev/null +++ b/components/doodle/doodle_service.h
@@ -0,0 +1,62 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOODLE_DOODLE_SERVICE_H_ +#define COMPONENTS_DOODLE_DOODLE_SERVICE_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/observer_list.h" +#include "base/optional.h" +#include "components/doodle/doodle_fetcher.h" +#include "components/doodle/doodle_types.h" + +namespace doodle { + +class DoodleService { + public: + class Observer { + public: + virtual void OnDoodleConfigUpdated(const base::Optional<DoodleConfig>&) = 0; + }; + + DoodleService(std::unique_ptr<DoodleFetcher> fetcher); + ~DoodleService(); + + // Returns the current (cached) config, if any. + const base::Optional<DoodleConfig>& config() const { return cached_config_; } + + // Adds a new observer to the service. It'll only be called when the config + // changes; to get the current (cached) config, call |config()|. + void AddObserver(Observer* observer); + + // Prevents |observer| from receiving future updates. This is safe to call + // even when the observer is being notified of an update. + void RemoveObserver(Observer* observer); + + // Requests an asynchronous refresh of the DoodleConfig from the network. + // After the update completes, the observers will be notified only if the + // config changed. + void Refresh(); + + private: + void DoodleFetched(DoodleState state, + const base::Optional<DoodleConfig>& doodle_config); + + // The fetcher for getting fresh DoodleConfigs from the network. + std::unique_ptr<DoodleFetcher> fetcher_; + + // The result of the last network fetch. + base::Optional<DoodleConfig> cached_config_; + + // The list of observers to be notified when the DoodleConfig changes. + base::ObserverList<Observer> observers_; + + DISALLOW_COPY_AND_ASSIGN(DoodleService); +}; + +} // namespace doodle + +#endif // COMPONENTS_DOODLE_DOODLE_SERVICE_H_
diff --git a/components/doodle/doodle_service_unittest.cc b/components/doodle/doodle_service_unittest.cc new file mode 100644 index 0000000..48b3a10 --- /dev/null +++ b/components/doodle/doodle_service_unittest.cc
@@ -0,0 +1,202 @@ +// 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 "components/doodle/doodle_service.h" + +#include <memory> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/memory/ptr_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::Eq; +using testing::StrictMock; + +namespace doodle { + +namespace { + +class FakeDoodleFetcher : public DoodleFetcher { + public: + FakeDoodleFetcher() = default; + ~FakeDoodleFetcher() override = default; + + void FetchDoodle(FinishedCallback callback) override { + callbacks_.push_back(std::move(callback)); + } + + size_t num_pending_callbacks() const { return callbacks_.size(); } + + void ServeAllCallbacks(DoodleState state, + const base::Optional<DoodleConfig>& config) { + for (auto& callback : callbacks_) { + std::move(callback).Run(state, config); + } + callbacks_.clear(); + } + + private: + std::vector<FinishedCallback> callbacks_; +}; + +class MockDoodleObserver : public DoodleService::Observer { + public: + MOCK_METHOD1(OnDoodleConfigUpdated, + void(const base::Optional<DoodleConfig>&)); +}; + +} // namespace + +// Equality operator for DoodleConfigs, for use by testing::Eq. +// Note: This must be outside of the anonymous namespace. +bool operator==(const DoodleConfig& lhs, const DoodleConfig& rhs) { + return lhs.IsEquivalent(rhs); +} + +class DoodleServiceTest : public testing::Test { + public: + DoodleServiceTest() : fetcher_(nullptr) { + auto fetcher = base::MakeUnique<FakeDoodleFetcher>(); + fetcher_ = fetcher.get(); + service_ = base::MakeUnique<DoodleService>(std::move(fetcher)); + } + + DoodleService* service() { return service_.get(); } + FakeDoodleFetcher* fetcher() { return fetcher_; } + + private: + std::unique_ptr<DoodleService> service_; + FakeDoodleFetcher* fetcher_; +}; + +TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) { + ASSERT_THAT(service()->config(), Eq(base::nullopt)); + + // Request a refresh of the doodle config. + service()->Refresh(); + // The request should have arrived at the fetcher. + EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); + + // Serve it (with an arbitrary config). + DoodleConfig config; + config.doodle_type = DoodleType::SIMPLE; + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config); + + // The config should be available. + EXPECT_THAT(service()->config(), Eq(config)); + + // Request a refresh again. + service()->Refresh(); + // The request should have arrived at the fetcher again. + EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); + + // Serve it with a different config. + DoodleConfig other_config; + other_config.doodle_type = DoodleType::SLIDESHOW; + DCHECK(!config.IsEquivalent(other_config)); + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, other_config); + + // The config should have been updated. + EXPECT_THAT(service()->config(), Eq(other_config)); +} + +TEST_F(DoodleServiceTest, CallsObserverOnConfigReceived) { + StrictMock<MockDoodleObserver> observer; + service()->AddObserver(&observer); + + ASSERT_THAT(service()->config(), Eq(base::nullopt)); + + // Request a refresh of the doodle config. + service()->Refresh(); + // The request should have arrived at the fetcher. + ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); + + // Serve it (with an arbitrary config). The observer should get notified. + DoodleConfig config; + config.doodle_type = DoodleType::SIMPLE; + EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(config))); + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config); + + // Remove the observer before the service gets destroyed. + service()->RemoveObserver(&observer); +} + +TEST_F(DoodleServiceTest, CallsObserverOnConfigRemoved) { + // Load some doodle config. + service()->Refresh(); + DoodleConfig config; + config.doodle_type = DoodleType::SIMPLE; + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config); + ASSERT_THAT(service()->config(), Eq(config)); + + // Register an observer and request a refresh. + StrictMock<MockDoodleObserver> observer; + service()->AddObserver(&observer); + service()->Refresh(); + ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); + + // Serve the request with an empty doodle config. The observer should get + // notified. + EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt))); + fetcher()->ServeAllCallbacks(DoodleState::NO_DOODLE, base::nullopt); + + // Remove the observer before the service gets destroyed. + service()->RemoveObserver(&observer); +} + +TEST_F(DoodleServiceTest, CallsObserverOnConfigUpdated) { + // Load some doodle config. + service()->Refresh(); + DoodleConfig config; + config.doodle_type = DoodleType::SIMPLE; + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config); + ASSERT_THAT(service()->config(), Eq(config)); + + // Register an observer and request a refresh. + StrictMock<MockDoodleObserver> observer; + service()->AddObserver(&observer); + service()->Refresh(); + ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); + + // Serve the request with a different doodle config. The observer should get + // notified. + DoodleConfig other_config; + other_config.doodle_type = DoodleType::SLIDESHOW; + DCHECK(!config.IsEquivalent(other_config)); + EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(other_config))); + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, other_config); + + // Remove the observer before the service gets destroyed. + service()->RemoveObserver(&observer); +} + +TEST_F(DoodleServiceTest, DoesNotCallObserverWhenConfigEquivalent) { + // Load some doodle config. + service()->Refresh(); + DoodleConfig config; + config.doodle_type = DoodleType::SIMPLE; + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config); + ASSERT_THAT(service()->config(), Eq(config)); + + // Register an observer and request a refresh. + StrictMock<MockDoodleObserver> observer; + service()->AddObserver(&observer); + service()->Refresh(); + ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); + + // Serve the request with an equivalent doodle config. The observer should + // *not* get notified. + DoodleConfig equivalent_config; + equivalent_config.doodle_type = DoodleType::SIMPLE; + DCHECK(config.IsEquivalent(equivalent_config)); + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, equivalent_config); + + // Remove the observer before the service gets destroyed. + service()->RemoveObserver(&observer); +} + +} // namespace doodle
diff --git a/components/doodle/doodle_types.cc b/components/doodle/doodle_types.cc new file mode 100644 index 0000000..c0a1dff --- /dev/null +++ b/components/doodle/doodle_types.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 "components/doodle/doodle_types.h" + +namespace doodle { + +bool DoodleImage::operator==(const DoodleImage& other) const { + return url == other.url && height == other.height && width == other.width && + is_animated_gif == other.is_animated_gif && is_cta == other.is_cta; +} + +bool DoodleImage::operator!=(const DoodleImage& other) const { + return !(*this == other); +} + +bool DoodleConfig::IsEquivalent(const DoodleConfig& other) const { + // Note: This compares all fields except for |expiry_date|. The reason is that + // |expiry_date| gets computed as "now + time_to_live", so when an identical + // config gets re-fetched, the expiry date will generally end up slightly + // different. + return doodle_type == other.doodle_type && alt_text == other.alt_text && + interactive_html == other.interactive_html && + search_url == other.search_url && target_url == other.target_url && + fullpage_interactive_url == other.fullpage_interactive_url && + large_image == other.large_image && + large_cta_image == other.large_cta_image && + transparent_large_image == other.transparent_large_image; +} + +} // namespace doodle
diff --git a/components/doodle/doodle_types.h b/components/doodle/doodle_types.h index a4d92ff..49c749d8 100644 --- a/components/doodle/doodle_types.h +++ b/components/doodle/doodle_types.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_DOODLE_DOODLE_TYPES_H_ #define COMPONENTS_DOODLE_DOODLE_TYPES_H_ +#include "base/time/time.h" #include "url/gurl.h" namespace doodle { @@ -32,6 +33,9 @@ DoodleImage(); ~DoodleImage(); + bool operator==(const DoodleImage& other) const; + bool operator!=(const DoodleImage& other) const; + GURL url; int height; int width; @@ -48,11 +52,14 @@ DoodleConfig(const DoodleConfig& config); // = default; ~DoodleConfig(); + // Checks whether this config is "equivalent" to the other. This compares all + // fields for equality, except for |expiry_date|. + bool IsEquivalent(const DoodleConfig& other) const; + DoodleType doodle_type; std::string alt_text; std::string interactive_html; - base::Time expiry_date; GURL search_url; GURL target_url; GURL fullpage_interactive_url; @@ -60,6 +67,11 @@ DoodleImage large_image; DoodleImage large_cta_image; DoodleImage transparent_large_image; + + // TODO(treib,fhorschig): Don't expose this? Clients don't care about it. + base::Time expiry_date; + + // Copying and assignment allowed. }; } // namespace doodle
diff --git a/components/policy/core/common/cloud/cloud_policy_client.cc b/components/policy/core/common/cloud/cloud_policy_client.cc index 79cca40..f28872d 100644 --- a/components/policy/core/common/cloud/cloud_policy_client.cc +++ b/components/policy/core/common/cloud/cloud_policy_client.cc
@@ -287,6 +287,7 @@ request->set_oauth2_client_id( GaiaUrls::GetInstance()->oauth2_chrome_client_id()); request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope); + request->set_device_type(em::DeviceServiceApiAccessRequest::CHROME); policy_fetch_request_job_->Start( base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto index bb08d88..d35f3268 100644 --- a/components/policy/proto/device_management_backend.proto +++ b/components/policy/proto/device_management_backend.proto
@@ -165,6 +165,19 @@ // OAuth2 client ID to which the returned authorization code is bound. optional string oauth2_client_id = 2; + + // Enumerates different flavors of registration. + enum DeviceType { + // Authcode will be used by Chrome OS + // (this is typically requested during device enrollment) + CHROME = 0; + // Authcode will be used by Android (ARC) subsystem + // (this is typically requested during ARC Kiosk session setup) + ANDROIDOS = 1; + }; + + // Device type indicates the intended use of the auth code. + optional DeviceType device_type = 3; } // Response from server to API access request.
diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn index c06173b2..5265026b 100644 --- a/components/signin/core/browser/BUILD.gn +++ b/components/signin/core/browser/BUILD.gn
@@ -32,8 +32,6 @@ "child_account_info_fetcher_android.h", "child_account_info_fetcher_impl.cc", "child_account_info_fetcher_impl.h", - "device_activity_fetcher.cc", - "device_activity_fetcher.h", "gaia_cookie_manager_service.cc", "gaia_cookie_manager_service.h", "profile_identity_provider.cc",
diff --git a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/MockAccountManager.java b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/MockAccountManager.java index d5b9249..6aa4198 100644 --- a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/MockAccountManager.java +++ b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/MockAccountManager.java
@@ -23,9 +23,6 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; /** * The MockAccountManager helps out if you want to mock out all calls to the Android AccountManager. @@ -47,7 +44,7 @@ protected final Context mContext; - private final Set<AccountHolder> mAccounts; + private final Set<AccountHolder> mAccounts = new HashSet<>(); // Tracks the number of in-progress getAccountsByType() tasks so that tests can wait for // their completion. @@ -57,7 +54,6 @@ public MockAccountManager(Context context, Context testContext, Account... accounts) { mContext = context; mGetAccountsTaskCounter = new ZeroCounter(); - mAccounts = new HashSet<AccountHolder>(); if (accounts != null) { for (Account account : accounts) { mAccounts.add(AccountHolder.create().account(account).alwaysAccept(true).build()); @@ -65,34 +61,18 @@ } } - private static class SingleThreadedExecutor extends ThreadPoolExecutor { - public SingleThreadedExecutor() { - super(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>()); - } - } - @Override public Account[] getAccountsByType(String type) { if (!AccountManagerHelper.GOOGLE_ACCOUNT_TYPE.equals(type)) { throw new IllegalArgumentException("Invalid account type: " + type); } - if (mAccounts == null) { - return new Account[0]; - } else { - ArrayList<Account> validAccounts = new ArrayList<Account>(); - for (AccountHolder ah : mAccounts) { - if (type.equals(ah.getAccount().type)) { - validAccounts.add(ah.getAccount()); - } + ArrayList<Account> validAccounts = new ArrayList<>(); + for (AccountHolder ah : mAccounts) { + if (type.equals(ah.getAccount().type)) { + validAccounts.add(ah.getAccount()); } - - Account[] accounts = new Account[validAccounts.size()]; - int i = 0; - for (Account account : validAccounts) { - accounts[i++] = account; - } - return accounts; } + return validAccounts.toArray(new Account[0]); } @Override
diff --git a/components/signin/core/browser/device_activity_fetcher.cc b/components/signin/core/browser/device_activity_fetcher.cc deleted file mode 100644 index 39b7433..0000000 --- a/components/signin/core/browser/device_activity_fetcher.cc +++ /dev/null
@@ -1,204 +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 "components/signin/core/browser/device_activity_fetcher.h" - -#include "base/strings/stringprintf.h" -#include "components/signin/core/browser/signin_client.h" -#include "google_apis/gaia/gaia_auth_fetcher.h" -#include "google_apis/gaia/gaia_constants.h" -#include "google_apis/gaia/gaia_urls.h" -#include "google_apis/gaia/google_service_auth_error.h" -#include "net/http/http_status_code.h" -#include "net/url_request/url_fetcher.h" - -namespace { - -// TODO(mlerman,anthonyvd): Replace the three parameters following with the -// necessary parameters for calling the ListDevices endpoint, once live. -// crbug.com/463611 for details! -const char kSyncListDevicesScope[] = - "https://www.googleapis.com/auth/chromesynclistdevices"; -const char kChromeDomain[] = "http://www.chrome.com"; -const char kListDevicesEndpoint[] = "http://127.0.0.1"; -// Template for optional authorization header when using an OAuth access token. -const char kAuthorizationHeader[] = "Authorization: Bearer %s"; - -// In case of an error while fetching using the GaiaAuthFetcher, retry with -// exponential backoff. Try up to 9 times within 10 minutes. -const net::BackoffEntry::Policy kBackoffPolicy = { - // Number of initial errors (in sequence) to ignore before applying - // exponential back-off rules. - 0, - // Initial delay for exponential backoff in ms. - 1000, - // Factor by which the waiting time will be multiplied. - 2, - // Fuzzing percentage. ex: 10% will spread requests randomly - // between 90%-100% of the calculated time. - 0.1, // 10% - // Maximum amount of time we are willing to delay our request in ms. - 1000 * 60 * 15, // 15 minutes. - // Time to keep an entry from being discarded even when it - // has no significant state, -1 to never discard. - -1, - // Don't use initial delay unless the last request was an error. - false, -}; - -const int kMaxFetcherRetries = 9; - -} // namespace - -DeviceActivityFetcher::DeviceActivityFetcher( - SigninClient* signin_client, - DeviceActivityFetcher::Observer* observer) - : fetcher_backoff_(&kBackoffPolicy), - fetcher_retries_(0), - signin_client_(signin_client), - observer_(observer) { -} - -DeviceActivityFetcher::~DeviceActivityFetcher() { -} - -void DeviceActivityFetcher::Start() { - fetcher_retries_ = 0; - login_hint_ = std::string(); - StartFetchingListIdpSessions(); -} - -void DeviceActivityFetcher::Stop() { - if (gaia_auth_fetcher_) - gaia_auth_fetcher_->CancelRequest(); - if (url_fetcher_) - url_fetcher_.reset(); -} - -void DeviceActivityFetcher::StartFetchingListIdpSessions() { - gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher( - this, GaiaConstants::kChromeSource, - signin_client_->GetURLRequestContext())); - gaia_auth_fetcher_->StartListIDPSessions(kSyncListDevicesScope, - kChromeDomain); -} - -void DeviceActivityFetcher::StartFetchingGetTokenResponse() { - gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher( - this, GaiaConstants::kChromeSource, - signin_client_->GetURLRequestContext())); - gaia_auth_fetcher_->StartGetTokenResponse(kSyncListDevicesScope, - kChromeDomain, login_hint_); -} - -void DeviceActivityFetcher::StartFetchingListDevices() { - // Call the Sync Endpoint. - url_fetcher_ = net::URLFetcher::Create(GURL(kListDevicesEndpoint), - net::URLFetcher::GET, this); - url_fetcher_->SetRequestContext(signin_client_->GetURLRequestContext()); - if (!access_token_.empty()) { - url_fetcher_->SetExtraRequestHeaders( - base::StringPrintf(kAuthorizationHeader, access_token_.c_str())); - } - url_fetcher_->Start(); -} - -void DeviceActivityFetcher::OnURLFetchComplete(const net::URLFetcher* source) { - // TODO(mlerman): Uncomment the code below once we have a working proto. - // Work done under crbug.com/463611 - - // std::string response_string; - // ListDevices list_devices; - - // if (!source->GetStatus().is_success()) { - // VLOG(1) << "Failed to fetch listdevices response. Retrying."; - // if (++fetcher_retries_ < kMaxFetcherRetries) { - // fetcher_backoff_.InformOfRequest(false); - // fetcher_timer_.Start( - // FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(), this, - // &DeviceActivityFetcher::StartFetchingListDevices); - // return; - // } else { - // observer_->OnFetchDeviceActivityFailure(); - // return; - // } - // } - - // net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>( - // source->GetResponseCode()); - // if (response_status == net::HTTP_BAD_REQUEST || - // response_status == net::HTTP_UNAUTHORIZED) { - // // BAD_REQUEST indicates that the request was malformed. - // // UNAUTHORIZED indicates that security token didn't match the id. - // VLOG(1) << "No point retrying the checkin with status: " - // << response_status << ". Checkin failed."; - // CheckinRequestStatus status = response_status == net::HTTP_BAD_REQUEST ? - // HTTP_BAD_REQUEST : HTTP_UNAUTHORIZED; - // RecordCheckinStatusAndReportUMA(status, recorder_, false); - // callback_.Run(response_proto); - // return; - // } - - // if (response_status != net::HTTP_OK || - // !source->GetResponseAsString(&response_string) || - // !list_devices.ParseFromString(response_string)) { - // LOG(ERROR) << "Failed to get list devices response. HTTP Status: " - // << response_status; - // if (++fetcher_retries_ < kMaxFetcherRetries) { - // fetcher_backoff_.InformOfRequest(false); - // fetcher_timer_.Start( - // FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(), this, - // &DeviceActivityFetcher::StartFetchingListDevices); - // return; - // } else { - // observer_->OnFetchDeviceActivityFailure(); - // return; - // } - // } - - std::vector<DeviceActivity> devices; - // TODO(mlerman): Fill |devices| from the proto in |source|. - - // Call this last as OnFetchDeviceActivitySuccess will delete |this|. - observer_->OnFetchDeviceActivitySuccess(devices); -} - -void DeviceActivityFetcher::OnListIdpSessionsSuccess( - const std::string& login_hint) { - fetcher_backoff_.InformOfRequest(true); - login_hint_ = login_hint; - access_token_ = std::string(); - StartFetchingGetTokenResponse(); -} - -void DeviceActivityFetcher::OnListIdpSessionsError( - const GoogleServiceAuthError& error) { - if (++fetcher_retries_ < kMaxFetcherRetries && error.IsTransientError()) { - fetcher_backoff_.InformOfRequest(false); - fetcher_timer_.Start(FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(), - this, - &DeviceActivityFetcher::StartFetchingListIdpSessions); - return; - } - observer_->OnFetchDeviceActivityFailure(); -} - -void DeviceActivityFetcher::OnGetTokenResponseSuccess( - const ClientOAuthResult& result) { - fetcher_backoff_.InformOfRequest(true); - access_token_ = result.access_token; - StartFetchingListDevices(); -} - -void DeviceActivityFetcher::OnGetTokenResponseError( - const GoogleServiceAuthError& error) { - if (++fetcher_retries_ < kMaxFetcherRetries && error.IsTransientError()) { - fetcher_backoff_.InformOfRequest(false); - fetcher_timer_.Start(FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(), - this, - &DeviceActivityFetcher::StartFetchingGetTokenResponse); - return; - } - observer_->OnFetchDeviceActivityFailure(); -}
diff --git a/components/signin/core/browser/device_activity_fetcher.h b/components/signin/core/browser/device_activity_fetcher.h deleted file mode 100644 index f91e7dfc..0000000 --- a/components/signin/core/browser/device_activity_fetcher.h +++ /dev/null
@@ -1,81 +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 COMPONENTS_SIGNIN_CORE_BROWSER_DEVICE_ACTVITIY_FETCHER_H_ -#define COMPONENTS_SIGNIN_CORE_BROWSER_DEVICE_ACTVITIY_FETCHER_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/time/time.h" -#include "base/timer/timer.h" -#include "google_apis/gaia/gaia_auth_consumer.h" -#include "net/base/backoff_entry.h" -#include "net/url_request/url_fetcher_delegate.h" - -class GaiaAuthFetcher; -class SigninClient; - -namespace net { -class URLFetcher; -} - -class DeviceActivityFetcher : public GaiaAuthConsumer, - public net::URLFetcherDelegate { - public: - struct DeviceActivity { - base::Time last_active; - std::string name; - }; - - class Observer { - public: - virtual void OnFetchDeviceActivitySuccess( - const std::vector<DeviceActivityFetcher::DeviceActivity>& devices) = 0; - virtual void OnFetchDeviceActivityFailure() {} - }; - - DeviceActivityFetcher(SigninClient* signin_client, - DeviceActivityFetcher::Observer* observer); - ~DeviceActivityFetcher() override; - - void Start(); - void Stop(); - - // GaiaAuthConsumer: - void OnListIdpSessionsSuccess(const std::string& login_hint) override; - void OnListIdpSessionsError(const GoogleServiceAuthError& error) override; - void OnGetTokenResponseSuccess(const ClientOAuthResult& result) override; - void OnGetTokenResponseError(const GoogleServiceAuthError& error) override; - - // net::URLFetcherDelegate: - void OnURLFetchComplete(const net::URLFetcher* source) override; - - private: - void StartFetchingListIdpSessions(); - void StartFetchingGetTokenResponse(); - void StartFetchingListDevices(); - - // Gaia fetcher used for acquiring an access token. - std::unique_ptr<GaiaAuthFetcher> gaia_auth_fetcher_; - // URL Fetcher used for calling List Devices. - std::unique_ptr<net::URLFetcher> url_fetcher_; - - // If either fetcher fails, retry with exponential backoff. - net::BackoffEntry fetcher_backoff_; - base::OneShotTimer fetcher_timer_; - int fetcher_retries_; - - std::string access_token_; - std::string login_hint_; - - SigninClient* signin_client_; // Weak pointer. - Observer* observer_; - - DISALLOW_COPY_AND_ASSIGN(DeviceActivityFetcher); -}; - -#endif // COMPONENTS_SIGNIN_CORE_BROWSER_DEVICE_ACTVITIY_FETCHER_H_
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 4a5e874..2d3d66f 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -290,7 +290,10 @@ // The JavaScript API for payments on the web. const base::Feature kWebPayments{"WebPayments", base::FEATURE_ENABLED_BY_DEFAULT}; - +#else +// The JavaScript API for payments on the web. +const base::Feature kWebPayments{"WebPayments", + base::FEATURE_DISABLED_BY_DEFAULT}; #endif #if !defined(OS_ANDROID)
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index d2c13ef3..5017bbc 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -64,6 +64,7 @@ CONTENT_EXPORT extern const base::Feature kVrShell; CONTENT_EXPORT extern const base::Feature kWebAssembly; CONTENT_EXPORT extern const base::Feature kWebGLImageChromium; +CONTENT_EXPORT extern const base::Feature kWebPayments; CONTENT_EXPORT extern const base::Feature kWebRtcEcdsaDefault; CONTENT_EXPORT extern const base::Feature kWebRtcHWH264Encoding; CONTENT_EXPORT extern const base::Feature kWebRtcUseEchoCanceller3; @@ -78,7 +79,6 @@ CONTENT_EXPORT extern const base::Feature kImeThread; CONTENT_EXPORT extern const base::Feature kSeccompSandboxAndroid; CONTENT_EXPORT extern const base::Feature kServiceWorkerPaymentApps; -CONTENT_EXPORT extern const base::Feature kWebPayments; #endif // defined(OS_ANDROID) #if !defined(OS_ANDROID)
diff --git a/device/bluetooth/DEPS b/device/bluetooth/DEPS index 94bd004..4e151328 100644 --- a/device/bluetooth/DEPS +++ b/device/bluetooth/DEPS
@@ -2,7 +2,6 @@ "+chromeos/dbus", "+crypto", "+dbus", - "+grit", "+jni", "+net/base", "+net/log",
diff --git a/device/bluetooth/bluetooth_device.cc b/device/bluetooth/bluetooth_device.cc index 9aaf8e4..587fcb7c 100644 --- a/device/bluetooth/bluetooth_device.cc +++ b/device/bluetooth/bluetooth_device.cc
@@ -19,7 +19,7 @@ #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h" #include "device/bluetooth/bluetooth_remote_gatt_service.h" #include "device/bluetooth/string_util_icu.h" -#include "grit/bluetooth_strings.h" +#include "device/bluetooth/strings/grit/bluetooth_strings.h" #include "ui/base/l10n/l10n_util.h" namespace device {
diff --git a/device/bluetooth/strings/BUILD.gn b/device/bluetooth/strings/BUILD.gn index 6eaeb0ce..2c27693 100644 --- a/device/bluetooth/strings/BUILD.gn +++ b/device/bluetooth/strings/BUILD.gn
@@ -6,6 +6,7 @@ grit("strings") { source = "../bluetooth_strings.grd" + use_qualified_include = true outputs = [ "grit/bluetooth_strings.h", "bluetooth_strings_am.pak",
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn index 5766031..ce5f6a9 100644 --- a/extensions/shell/BUILD.gn +++ b/extensions/shell/BUILD.gn
@@ -13,6 +13,7 @@ grit("resources") { source = "app_shell_resources.grd" + use_qualified_include = true outputs = [ "grit/app_shell_resources.h", "app_shell_resources.pak",
diff --git a/extensions/shell/DEPS b/extensions/shell/DEPS index 74cb6bb..eeb99ae5 100644 --- a/extensions/shell/DEPS +++ b/extensions/shell/DEPS
@@ -16,10 +16,5 @@ # the embedder before being used by the extension. "+components/storage_monitor", - # Only allow app_shell and extensions resources, not general Chrome ones. - "-grit", - "+grit/app_shell_resources.h", - "+grit/extensions_resources.h", - # Real DEPS go in subdirectories, for example extensions/shell/browser/DEPS. ]
diff --git a/extensions/shell/common/DEPS b/extensions/shell/common/DEPS index bee8c47a..fe06bdc 100644 --- a/extensions/shell/common/DEPS +++ b/extensions/shell/common/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+components/nacl/common", "+components/nacl/renderer/plugin", + "+extensions/shell/grit", "+ppapi", ]
diff --git a/extensions/shell/common/shell_extensions_client.cc b/extensions/shell/common/shell_extensions_client.cc index 6ecb7d78..210d6cf 100644 --- a/extensions/shell/common/shell_extensions_client.cc +++ b/extensions/shell/common/shell_extensions_client.cc
@@ -27,7 +27,7 @@ #include "extensions/shell/common/api/shell_behavior_features.h" #include "extensions/shell/common/api/shell_manifest_features.h" #include "extensions/shell/common/api/shell_permission_features.h" -#include "grit/app_shell_resources.h" +#include "extensions/shell/grit/app_shell_resources.h" namespace extensions {
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index b8b8280..127c96fc 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn
@@ -108,6 +108,7 @@ "command_buffer/client/gles2_interface_stub.h", "command_buffer/service/error_state_mock.cc", "command_buffer/service/gles2_cmd_decoder_mock.cc", + "test_message_loop_type.h", ] public_deps = [ @@ -119,6 +120,9 @@ "//testing/gtest", "//ui/gl:gl_unittest_utils", ] + if (use_ozone) { + deps += [ "//ui/ozone" ] + } } test("gl_tests") {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index e9558e0..8cdeb34 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -23,6 +23,7 @@ #include "gpu/command_buffer/service/program_manager.h" #include "gpu/command_buffer/service/test_helper.h" #include "gpu/command_buffer/service/vertex_attrib_manager.h" +#include "gpu/test_message_loop_type.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_mock.h" #include "ui/gl/init/gl_factory.h" @@ -90,7 +91,7 @@ const uint32_t kMaxColorAttachments = 16; const uint32_t kMaxDrawBuffers = 16; -} // namespace Anonymous +} // namespace namespace gpu { namespace gles2 { @@ -123,7 +124,8 @@ cached_depth_mask_(true), cached_stencil_front_mask_(static_cast<GLuint>(-1)), cached_stencil_back_mask_(static_cast<GLuint>(-1)), - shader_language_version_(100) { + shader_language_version_(100), + message_loop_(test::GetMessageLoopTypeForGpu()) { memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_)); }
diff --git a/gpu/command_buffer/service/gpu_service_test.cc b/gpu/command_buffer/service/gpu_service_test.cc index d91a81a..f4e38dc 100644 --- a/gpu/command_buffer/service/gpu_service_test.cc +++ b/gpu/command_buffer/service/gpu_service_test.cc
@@ -5,6 +5,7 @@ #include "gpu/command_buffer/service/gpu_service_test.h" #include "gpu/command_buffer/service/test_helper.h" +#include "gpu/test_message_loop_type.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_context_stub.h" #include "ui/gl/gl_implementation.h" @@ -16,8 +17,10 @@ namespace gpu { namespace gles2 { -GpuServiceTest::GpuServiceTest() : ran_setup_(false), ran_teardown_(false) { -} +GpuServiceTest::GpuServiceTest() + : ran_setup_(false), + ran_teardown_(false), + message_loop_(test::GetMessageLoopTypeForGpu()) {} GpuServiceTest::~GpuServiceTest() { DCHECK(ran_teardown_);
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn index 887bb5f..ce81b1693 100644 --- a/gpu/ipc/service/BUILD.gn +++ b/gpu/ipc/service/BUILD.gn
@@ -153,6 +153,7 @@ ":test_support", "//base", "//base/test:test_support", + "//gpu:test_support", "//gpu/command_buffer/common", "//gpu/command_buffer/common:gles2_utils", "//gpu/command_buffer/service",
diff --git a/gpu/ipc/service/gpu_channel_unittest.cc b/gpu/ipc/service/gpu_channel_unittest.cc index d8d0bf4..8e913f5 100644 --- a/gpu/ipc/service/gpu_channel_unittest.cc +++ b/gpu/ipc/service/gpu_channel_unittest.cc
@@ -10,6 +10,7 @@ #include "gpu/ipc/service/gpu_channel.h" #include "gpu/ipc/service/gpu_channel_manager.h" #include "gpu/ipc/service/gpu_channel_test_common.h" +#include "gpu/test_message_loop_type.h" #include "ipc/ipc_test_sink.h" #include "ui/gl/gl_surface_stub.h" #include "ui/gl/init/gl_factory.h" @@ -19,7 +20,9 @@ class GpuChannelTest : public GpuChannelTestCommon { public: - GpuChannelTest() : GpuChannelTestCommon() {} + GpuChannelTest() + : GpuChannelTestCommon(), + message_loop_(test::GetMessageLoopTypeForGpu()) {} ~GpuChannelTest() override {} void SetUp() override {
diff --git a/gpu/test_message_loop_type.h b/gpu/test_message_loop_type.h new file mode 100644 index 0000000..b2d97ff --- /dev/null +++ b/gpu/test_message_loop_type.h
@@ -0,0 +1,30 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GPU_TEST_MESSAGE_LOOP_TYPE_H_ +#define GPU_TEST_MESSAGE_LOOP_TYPE_H_ + +#include "base/message_loop/message_loop.h" + +#if defined(USE_OZONE) +#include "ui/ozone/public/ozone_platform.h" +#endif + +namespace gpu { +namespace test { + +// Returns the MessageLoop type needed for GPU tests. The Ozone platform may not +// work with TYPE_DEFAULT and this needs to be checked at runtime. +inline base::MessageLoop::Type GetMessageLoopTypeForGpu() { +#if defined(USE_OZONE) + return ui::OzonePlatform::EnsureInstance()->GetMessageLoopTypeForGpu(); +#else + return base::MessageLoop::TYPE_DEFAULT; +#endif +} + +} // namespace test +} // namespace gpu + +#endif // GPU_TEST_MESSAGE_LOOP_TYPE_H_
diff --git a/headless/BUILD.gn b/headless/BUILD.gn index 8b8c6a9..cea651df 100644 --- a/headless/BUILD.gn +++ b/headless/BUILD.gn
@@ -267,6 +267,8 @@ if (use_aura) { sources += [ "lib/browser/headless_browser_impl_aura.cc", + "lib/browser/headless_focus_client.cc", + "lib/browser/headless_focus_client.h", "lib/browser/headless_screen.cc", "lib/browser/headless_screen.h", "lib/browser/headless_window_parenting_client.cc",
diff --git a/headless/lib/browser/headless_browser_impl.cc b/headless/lib/browser/headless_browser_impl.cc index e0546b1..71b79a0 100644 --- a/headless/lib/browser/headless_browser_impl.cc +++ b/headless/lib/browser/headless_browser_impl.cc
@@ -19,6 +19,7 @@ #include "headless/lib/browser/headless_browser_main_parts.h" #include "headless/lib/browser/headless_web_contents_impl.h" #include "headless/lib/headless_content_main_delegate.h" +#include "ui/aura/client/focus_client.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/events/devices/device_data_manager.h"
diff --git a/headless/lib/browser/headless_browser_impl.h b/headless/lib/browser/headless_browser_impl.h index e622227..864e49c 100644 --- a/headless/lib/browser/headless_browser_impl.h +++ b/headless/lib/browser/headless_browser_impl.h
@@ -19,6 +19,12 @@ #if defined(USE_AURA) #include "headless/lib/browser/headless_window_tree_host.h" + +namespace aura { +namespace client { +class FocusClient; +} +} #endif namespace headless { @@ -81,7 +87,9 @@ // is used for all web contents. We should probably use one // window per web contents, but additional investigation is needed. std::unique_ptr<HeadlessWindowTreeHost> window_tree_host_; + std::unique_ptr<aura::client::FocusClient> focus_client_; #endif + base::Callback<void(HeadlessBrowser*)> on_start_callback_; HeadlessBrowser::Options options_; HeadlessBrowserMainParts* browser_main_parts_; // Not owned.
diff --git a/headless/lib/browser/headless_browser_impl_aura.cc b/headless/lib/browser/headless_browser_impl_aura.cc index 9237e34..4718d491 100644 --- a/headless/lib/browser/headless_browser_impl_aura.cc +++ b/headless/lib/browser/headless_browser_impl_aura.cc
@@ -6,7 +6,9 @@ #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" +#include "headless/lib/browser/headless_focus_client.h" #include "headless/lib/browser/headless_screen.h" +#include "ui/aura/client/focus_client.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/display/screen.h" @@ -29,6 +31,10 @@ window_tree_host_->InitHost(); window_tree_host_->window()->Show(); window_tree_host_->SetParentWindow(window_tree_host_->window()); + + focus_client_.reset(new HeadlessFocusClient()); + aura::client::SetFocusClient(window_tree_host_->window(), + focus_client_.get()); } void HeadlessBrowserImpl::PlatformInitializeWebContents(
diff --git a/headless/lib/browser/headless_focus_client.cc b/headless/lib/browser/headless_focus_client.cc new file mode 100644 index 0000000..9a4e806 --- /dev/null +++ b/headless/lib/browser/headless_focus_client.cc
@@ -0,0 +1,63 @@ +// 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 "headless/lib/browser/headless_focus_client.h" + +#include "ui/aura/client/focus_change_observer.h" +#include "ui/aura/window.h" + +namespace headless { + +HeadlessFocusClient::HeadlessFocusClient() + : focused_window_(NULL), observer_manager_(this) {} + +HeadlessFocusClient::~HeadlessFocusClient() {} + +void HeadlessFocusClient::AddObserver( + aura::client::FocusChangeObserver* observer) { + focus_observers_.AddObserver(observer); +} + +void HeadlessFocusClient::RemoveObserver( + aura::client::FocusChangeObserver* observer) { + focus_observers_.RemoveObserver(observer); +} + +void HeadlessFocusClient::FocusWindow(aura::Window* window) { + if (window && !window->CanFocus()) + return; + + if (focused_window_) + observer_manager_.Remove(focused_window_); + aura::Window* old_focused_window = focused_window_; + focused_window_ = window; + if (focused_window_) + observer_manager_.Add(focused_window_); + + for (aura::client::FocusChangeObserver& observer : focus_observers_) + observer.OnWindowFocused(focused_window_, old_focused_window); + aura::client::FocusChangeObserver* observer = + aura::client::GetFocusChangeObserver(old_focused_window); + if (observer) + observer->OnWindowFocused(focused_window_, old_focused_window); + observer = aura::client::GetFocusChangeObserver(focused_window_); + if (observer) + observer->OnWindowFocused(focused_window_, old_focused_window); +} + +void HeadlessFocusClient::ResetFocusWithinActiveWindow(aura::Window* window) { + if (!window->Contains(focused_window_)) + FocusWindow(window); +} + +aura::Window* HeadlessFocusClient::GetFocusedWindow() { + return focused_window_; +} + +void HeadlessFocusClient::OnWindowDestroying(aura::Window* window) { + DCHECK_EQ(window, focused_window_); + FocusWindow(NULL); +} + +} // namespace headless
diff --git a/headless/lib/browser/headless_focus_client.h b/headless/lib/browser/headless_focus_client.h new file mode 100644 index 0000000..a218089e --- /dev/null +++ b/headless/lib/browser/headless_focus_client.h
@@ -0,0 +1,42 @@ +// 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 HEADLESS_LIB_BROWSER_HEADLESS_FOCUS_CLIENT_H_ +#define HEADLESS_LIB_BROWSER_HEADLESS_FOCUS_CLIENT_H_ + +#include "base/macros.h" +#include "base/observer_list.h" +#include "base/scoped_observer.h" +#include "ui/aura/client/focus_client.h" +#include "ui/aura/window_observer.h" + +namespace headless { + +class HeadlessFocusClient : public aura::client::FocusClient, + public aura::WindowObserver { + public: + HeadlessFocusClient(); + ~HeadlessFocusClient() override; + + private: + // Overridden from aura::client::FocusClient: + void AddObserver(aura::client::FocusChangeObserver* observer) override; + void RemoveObserver(aura::client::FocusChangeObserver* observer) override; + void FocusWindow(aura::Window* window) override; + void ResetFocusWithinActiveWindow(aura::Window* window) override; + aura::Window* GetFocusedWindow() override; + + // Overridden from aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override; + + aura::Window* focused_window_; + ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_; + base::ObserverList<aura::client::FocusChangeObserver> focus_observers_; + + DISALLOW_COPY_AND_ASSIGN(HeadlessFocusClient); +}; + +} // namespace headless + +#endif // HEADLESS_LIB_BROWSER_HEADLESS_FOCUS_CLIENT_H_
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc index 9d4b7ad..710fc84 100644 --- a/headless/lib/browser/headless_web_contents_impl.cc +++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -21,6 +21,7 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/bindings_policy.h" @@ -97,6 +98,10 @@ security_style_explanations); } + void ActivateContents(content::WebContents* contents) override { + contents->GetRenderViewHost()->GetWidget()->Focus(); + } + private: HeadlessBrowserContextImpl* browser_context_; // Not owned. DISALLOW_COPY_AND_ASSIGN(Delegate);
diff --git a/headless/lib/headless_web_contents_browsertest.cc b/headless/lib/headless_web_contents_browsertest.cc index 693e2dc..3bb6265 100644 --- a/headless/lib/headless_web_contents_browsertest.cc +++ b/headless/lib/headless_web_contents_browsertest.cc
@@ -61,6 +61,45 @@ browser_context->GetAllWebContents().size()); } +IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, Focus) { + EXPECT_TRUE(embedded_test_server()->Start()); + + HeadlessBrowserContext* browser_context = + browser()->CreateBrowserContextBuilder().Build(); + + HeadlessWebContents* web_contents = + browser_context->CreateWebContentsBuilder() + .SetInitialURL(embedded_test_server()->GetURL("/hello.html")) + .Build(); + EXPECT_TRUE(WaitForLoad(web_contents)); + + bool result; + EXPECT_TRUE(EvaluateScript(web_contents, "document.hasFocus()") + ->GetResult() + ->GetValue() + ->GetAsBoolean(&result)); + EXPECT_TRUE(result); + + HeadlessWebContents* web_contents2 = + browser_context->CreateWebContentsBuilder() + .SetInitialURL(embedded_test_server()->GetURL("/hello.html")) + .Build(); + EXPECT_TRUE(WaitForLoad(web_contents2)); + + // TODO(irisu): Focus of two web contents should be independent of the other. + // Both web_contents and web_contents2 should be focused at this point. + EXPECT_TRUE(EvaluateScript(web_contents, "document.hasFocus()") + ->GetResult() + ->GetValue() + ->GetAsBoolean(&result)); + EXPECT_FALSE(result); + EXPECT_TRUE(EvaluateScript(web_contents2, "document.hasFocus()") + ->GetResult() + ->GetValue() + ->GetAsBoolean(&result)); + EXPECT_TRUE(result); +} + namespace { bool DecodePNG(std::string base64_data, SkBitmap* bitmap) { std::string png_data;
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist index ef88327..21aaa2e 100644 --- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist +++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -300,28 +300,6 @@ </dict> <dict> <key>Type</key> - <string>PSMultiValueSpecifier</string> - <key>Title</key> - <string>Enable Passwords Link</string> - <key>Key</key> - <string>EnablePasswordsLink</string> - <key>DefaultValue</key> - <string></string> - <key>Values</key> - <array> - <string></string> - <string>Enabled</string> - <string>Disabled</string> - </array> - <key>Titles</key> - <array> - <string>Default</string> - <string>Enabled</string> - <string>Disabled</string> - </array> - </dict> - <dict> - <key>Type</key> <string>PSToggleSwitchSpecifier</string> <key>Title</key> <string>Force reset Contextual Search</string>
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn index 2e80c05..74e62dd6 100644 --- a/ios/chrome/browser/ui/settings/BUILD.gn +++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -346,6 +346,7 @@ "//components/search_engines", "//components/signin/core/browser", "//components/strings", + "//ios/chrome/app:app_internal", "//ios/chrome/app/strings", "//ios/chrome/app/theme", "//ios/chrome/browser", @@ -353,6 +354,7 @@ "//ios/chrome/browser/content_settings", "//ios/chrome/browser/search_engines", "//ios/chrome/browser/signin", + "//ios/chrome/browser/ui:ui_internal", "//ios/chrome/browser/ui/tools_menu", "//ios/chrome/test/app:test_support", "//ios/chrome/test/earl_grey:test_support",
diff --git a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm index a67ab23..ebd4ba10 100644 --- a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
@@ -16,6 +16,7 @@ #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" +#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" #import "ios/chrome/browser/ui/settings/cells/password_details_item.h" #import "ios/chrome/browser/ui/settings/reauthentication_module.h" #import "ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.h" @@ -296,7 +297,22 @@ textCell.textLabel.textColor = [[MDCPalette greyPalette] tint500]; } return view; -}; +} + +- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView + cellForItemAtIndexPath:(NSIndexPath*)indexPath { + UICollectionViewCell* cell = + [super collectionView:collectionView cellForItemAtIndexPath:indexPath]; + + NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; + if (type == ItemTypeDelete) { + MDCCollectionViewTextCell* textCell = + base::mac::ObjCCastStrict<MDCCollectionViewTextCell>(cell); + textCell.textLabel.textColor = [[MDCPalette cr_redPalette] tint500]; + } + + return cell; +} #pragma mark - UICollectionViewDelegate
diff --git a/ios/chrome/browser/ui/settings/settings_egtest.mm b/ios/chrome/browser/ui/settings/settings_egtest.mm index 02994b8..c3d83aa 100644 --- a/ios/chrome/browser/ui/settings/settings_egtest.mm +++ b/ios/chrome/browser/ui/settings/settings_egtest.mm
@@ -17,9 +17,11 @@ #include "components/prefs/pref_member.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" +#import "ios/chrome/app/main_controller.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" #include "ios/chrome/browser/pref_names.h" +#import "ios/chrome/browser/ui/browser_view_controller.h" #import "ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h" #import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h" #import "ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.h" @@ -1007,4 +1009,48 @@ performAction:grey_tap()]; } +// Verifies that the Settings UI registers keyboard commands when presented, but +// not when it itslef presents something. +- (void)testSettingsKeyboardCommands { + // Open Settings. + [ChromeEarlGreyUI openToolsMenu]; + [[EarlGrey selectElementWithMatcher:SettingsButton()] + performAction:grey_tap()]; + [[EarlGrey + selectElementWithMatcher:grey_accessibilityID(kSettingsCollectionViewId)] + assertWithMatcher:grey_notNil()]; + + // Verify that the Settings register keyboard commands. + MainController* mainController = chrome_test_util::GetMainController(); + BrowserViewController* bvc = + [[mainController browserViewInformation] currentBVC]; + UIViewController* settings = bvc.presentedViewController; + GREYAssertNotNil(settings.keyCommands, + @"Settings should register key commands when presented."); + + // Present the Sign-in UI. + id<GREYMatcher> matcher = + grey_allOf(grey_accessibilityID(kSettingsSignInCellId), + grey_sufficientlyVisible(), nil); + [[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()]; + // Wait for UI to finish loading the Sign-in screen. + [[GREYUIThreadExecutor sharedInstance] drainUntilIdle]; + + // Verify that the Settings register keyboard commands. + GREYAssertNil(settings.keyCommands, + @"Settings should not register key commands when presented."); + + // Dismiss the Sign-in UI. + id<GREYMatcher> cancelButton = + grey_allOf(grey_accessibilityID(@"cancel"), + grey_accessibilityTrait(UIAccessibilityTraitButton), nil); + [[EarlGrey selectElementWithMatcher:cancelButton] performAction:grey_tap()]; + // Wait for UI to finish closing the Sign-in screen. + [[GREYUIThreadExecutor sharedInstance] drainUntilIdle]; + + // Verify that the Settings register keyboard commands. + GREYAssertNotNil(settings.keyCommands, + @"Settings should register key commands when presented."); +} + @end
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm index b1b25e5..035118e 100644 --- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -542,6 +542,9 @@ #pragma mark - UIResponder - (NSArray*)keyCommands { + if ([self presentedViewController]) { + return nil; + } base::WeakNSObject<SettingsNavigationController> weakSelf(self); return @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm index 3129e99..93de808 100644 --- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm +++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm
@@ -65,6 +65,7 @@ _cancelButton.reset([[UIButton buttonWithType:UIButtonTypeCustom] retain]); [_cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; + [_cancelButton setAccessibilityIdentifier:@"cancel"]; [_cancelButton addTarget:self action:@selector(didTapCancel:) forControlEvents:UIControlEventTouchUpInside];
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index 15e6e868..2774610 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc
@@ -737,8 +737,6 @@ EXPECT_CALL(*this, OnDurationChange()).Times(AnyNumber()); EXPECT_CALL(*this, OnVideoNaturalSizeChange(_)).Times(AtMost(1)); EXPECT_CALL(*this, OnVideoOpacityChange(_)).Times(AtMost(1)); - EXPECT_CALL(*this, OnVideoAverageKeyframeDistanceUpdate()) - .Times(AnyNumber()); source->set_demuxer_failure_cb(base::Bind( &PipelineIntegrationTest::OnStatusCallback, base::Unretained(this)));
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc index 6115e472..2c7776f 100644 --- a/media/test/pipeline_integration_test_base.cc +++ b/media/test/pipeline_integration_test_base.cc
@@ -53,6 +53,7 @@ last_video_frame_color_space_(COLOR_SPACE_UNSPECIFIED), current_duration_(kInfiniteDuration) { ResetVideoHash(); + EXPECT_CALL(*this, OnVideoAverageKeyframeDistanceUpdate()).Times(AnyNumber()); } PipelineIntegrationTestBase::~PipelineIntegrationTestBase() {
diff --git a/net/base/crypto_module.h b/net/base/crypto_module.h index e3765e9..67e8a17 100644 --- a/net/base/crypto_module.h +++ b/net/base/crypto_module.h
@@ -20,8 +20,6 @@ class CryptoModule; -typedef std::vector<scoped_refptr<CryptoModule> > CryptoModuleList; - class NET_EXPORT CryptoModule : public base::RefCountedThreadSafe<CryptoModule> { public:
diff --git a/net/cert/nss_cert_database.cc b/net/cert/nss_cert_database.cc index 98f6882..7a580d6 100644 --- a/net/cert/nss_cert_database.cc +++ b/net/cert/nss_cert_database.cc
@@ -140,7 +140,7 @@ return crypto::ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())); } -void NSSCertDatabase::ListModules(CryptoModuleList* modules, +void NSSCertDatabase::ListModules(std::vector<crypto::ScopedPK11Slot>* modules, bool need_rw) const { modules->clear(); @@ -157,7 +157,8 @@ PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list.get()); while (slot_element) { - modules->push_back(CryptoModule::CreateFromHandle(slot_element->slot)); + modules->push_back( + crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_element->slot))); slot_element = PK11_GetNextSafe(slot_list.get(), slot_element, PR_FALSE); // restart }
diff --git a/net/cert/nss_cert_database.h b/net/cert/nss_cert_database.h index a9f5c8ac..27b06aa7 100644 --- a/net/cert/nss_cert_database.h +++ b/net/cert/nss_cert_database.h
@@ -30,9 +30,6 @@ namespace net { -class CryptoModule; -typedef std::vector<scoped_refptr<CryptoModule> > CryptoModuleList; - // Provides functions to manipulate the NSS certificate stores. // Forwards notifications about certificate changes to the global CertDatabase // singleton. @@ -146,8 +143,8 @@ // Get all modules. // If |need_rw| is true, only writable modules will be returned. - // TODO(mattm): come up with better alternative to CryptoModuleList. - virtual void ListModules(CryptoModuleList* modules, bool need_rw) const; + virtual void ListModules(std::vector<crypto::ScopedPK11Slot>* modules, + bool need_rw) const; // Import certificates and private keys from PKCS #12 blob into the module. // If |is_extractable| is false, mark the private key as being unextractable
diff --git a/net/cert/nss_cert_database_chromeos.cc b/net/cert/nss_cert_database_chromeos.cc index d3bb89c..9f4f916 100644 --- a/net/cert/nss_cert_database_chromeos.cc +++ b/net/cert/nss_cert_database_chromeos.cc
@@ -61,8 +61,9 @@ return crypto::ScopedPK11Slot(); } -void NSSCertDatabaseChromeOS::ListModules(CryptoModuleList* modules, - bool need_rw) const { +void NSSCertDatabaseChromeOS::ListModules( + std::vector<crypto::ScopedPK11Slot>* modules, + bool need_rw) const { NSSCertDatabase::ListModules(modules, need_rw); size_t pre_size = modules->size();
diff --git a/net/cert/nss_cert_database_chromeos.h b/net/cert/nss_cert_database_chromeos.h index fa440575..df2585f 100644 --- a/net/cert/nss_cert_database_chromeos.h +++ b/net/cert/nss_cert_database_chromeos.h
@@ -28,7 +28,8 @@ // NSSCertDatabase implementation. void ListCertsSync(CertificateList* certs) override; void ListCerts(const NSSCertDatabase::ListCertsCallback& callback) override; - void ListModules(CryptoModuleList* modules, bool need_rw) const override; + void ListModules(std::vector<crypto::ScopedPK11Slot>* modules, + bool need_rw) const override; crypto::ScopedPK11Slot GetSystemSlot() const override; // TODO(mattm): handle trust setting, deletion, etc correctly when certs exist
diff --git a/net/cert/nss_cert_database_chromeos_unittest.cc b/net/cert/nss_cert_database_chromeos_unittest.cc index 89b5c23..f4a35d6 100644 --- a/net/cert/nss_cert_database_chromeos_unittest.cc +++ b/net/cert/nss_cert_database_chromeos_unittest.cc
@@ -105,26 +105,26 @@ // and does not include the software slot of the other user. (Does not check the // private slot, since it is the same as the public slot in tests.) TEST_F(NSSCertDatabaseChromeOSTest, ListModules) { - CryptoModuleList modules_1; - CryptoModuleList modules_2; + std::vector<crypto::ScopedPK11Slot> modules_1; + std::vector<crypto::ScopedPK11Slot> modules_2; db_1_->ListModules(&modules_1, false /* need_rw */); db_2_->ListModules(&modules_2, false /* need_rw */); bool found_1 = false; - for (CryptoModuleList::iterator it = modules_1.begin(); it != modules_1.end(); - ++it) { - EXPECT_NE(db_2_->GetPublicSlot().get(), (*it)->os_module_handle()); - if ((*it)->os_module_handle() == db_1_->GetPublicSlot().get()) + for (std::vector<crypto::ScopedPK11Slot>::iterator it = modules_1.begin(); + it != modules_1.end(); ++it) { + EXPECT_NE(db_2_->GetPublicSlot().get(), (*it).get()); + if ((*it).get() == db_1_->GetPublicSlot().get()) found_1 = true; } EXPECT_TRUE(found_1); bool found_2 = false; - for (CryptoModuleList::iterator it = modules_2.begin(); it != modules_2.end(); - ++it) { - EXPECT_NE(db_1_->GetPublicSlot().get(), (*it)->os_module_handle()); - if ((*it)->os_module_handle() == db_2_->GetPublicSlot().get()) + for (std::vector<crypto::ScopedPK11Slot>::iterator it = modules_2.begin(); + it != modules_2.end(); ++it) { + EXPECT_NE(db_1_->GetPublicSlot().get(), (*it).get()); + if ((*it).get() == db_2_->GetPublicSlot().get()) found_2 = true; } EXPECT_TRUE(found_2);
diff --git a/net/cert/nss_profile_filter_chromeos.cc b/net/cert/nss_profile_filter_chromeos.cc index 71eeab2..ebde973 100644 --- a/net/cert/nss_profile_filter_chromeos.cc +++ b/net/cert/nss_profile_filter_chromeos.cc
@@ -153,8 +153,8 @@ : filter_(filter) {} bool NSSProfileFilterChromeOS::ModuleNotAllowedForProfilePredicate::operator()( - const scoped_refptr<CryptoModule>& module) const { - return !filter_.IsModuleAllowed(module->os_module_handle()); + const crypto::ScopedPK11Slot& module) const { + return !filter_.IsModuleAllowed(module.get()); } } // namespace net
diff --git a/net/cert/nss_profile_filter_chromeos.h b/net/cert/nss_profile_filter_chromeos.h index 149f081..20bcf5bf 100644 --- a/net/cert/nss_profile_filter_chromeos.h +++ b/net/cert/nss_profile_filter_chromeos.h
@@ -7,8 +7,8 @@ #include <memory> +#include "base/memory/ref_counted.h" #include "crypto/scoped_nss_types.h" -#include "net/base/crypto_module.h" #include "net/base/net_export.h" namespace net { @@ -57,7 +57,7 @@ public: explicit ModuleNotAllowedForProfilePredicate( const NSSProfileFilterChromeOS& filter); - bool operator()(const scoped_refptr<CryptoModule>& module) const; + bool operator()(const crypto::ScopedPK11Slot& module) const; private: const NSSProfileFilterChromeOS& filter_;
diff --git a/net/websockets/websocket_deflate_stream_fuzzer.cc b/net/websockets/websocket_deflate_stream_fuzzer.cc index ca401d1..4f9bed3 100644 --- a/net/websockets/websocket_deflate_stream_fuzzer.cc +++ b/net/websockets/websocket_deflate_stream_fuzzer.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/test/fuzzed_data_provider.h" #include "net/base/completion_callback.h" @@ -28,16 +29,30 @@ namespace { +// If there are less random bytes left than MIN_BYTES_TO_CREATE_A_FRAME then +// CreateFrame() will always create an empty frame. Since the fuzzer can create +// the same empty frame with MIN_BYTES_TO_CREATE_A_FRAME bytes of input, save it +// from exploring a large space of ways to do the same thing. +constexpr size_t MIN_BYTES_TO_CREATE_A_FRAME = 3; + +constexpr size_t BYTES_CONSUMED_BY_PARAMS = 2; + +// If there are exactly BYTES_CONSUMED_BY_PARAMS + MIN_BYTES_TO_CREATE_A_FRAME +// bytes of input, then the fuzzer will test a single frame. In order to also +// test the case with zero frames, allow one less byte than this. +constexpr size_t MIN_USEFUL_SIZE = + BYTES_CONSUMED_BY_PARAMS + MIN_BYTES_TO_CREATE_A_FRAME - 1; + class WebSocketFuzzedStream final : public WebSocketStream { public: - WebSocketFuzzedStream(const uint8_t* data, size_t size) - : fuzzed_data_provider_(data, size) {} + WebSocketFuzzedStream(base::FuzzedDataProvider* fuzzed_data_provider) + : fuzzed_data_provider_(fuzzed_data_provider) {} int ReadFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames, const CompletionCallback& callback) override { - if (fuzzed_data_provider_.remaining_bytes() == 0) + if (fuzzed_data_provider_->remaining_bytes() < MIN_BYTES_TO_CREATE_A_FRAME) return ERR_CONNECTION_CLOSED; - while (fuzzed_data_provider_.remaining_bytes() > 0) + while (fuzzed_data_provider_->remaining_bytes() > 0) frames->push_back(CreateFrame()); return OK; } @@ -54,38 +69,54 @@ private: std::unique_ptr<WebSocketFrame> CreateFrame() { WebSocketFrameHeader::OpCode opcode = - fuzzed_data_provider_.ConsumeInt32InRange( + fuzzed_data_provider_->ConsumeUint32InRange( WebSocketFrameHeader::kOpCodeContinuation, WebSocketFrameHeader::kOpCodeControlUnused); auto frame = base::MakeUnique<WebSocketFrame>(opcode); // Bad news: ConsumeBool actually consumes a whole byte per call, so do // something hacky to conserve precious bits. - uint8_t flags = fuzzed_data_provider_.ConsumeUint8(); + uint8_t flags = fuzzed_data_provider_->ConsumeUint8(); frame->header.final = flags & 0x1; frame->header.reserved1 = (flags >> 1) & 0x1; frame->header.reserved2 = (flags >> 2) & 0x1; frame->header.reserved3 = (flags >> 3) & 0x1; frame->header.masked = (flags >> 4) & 0x1; - uint64_t payload_length = fuzzed_data_provider_.ConsumeInt32InRange(0, 64); - std::string payload = fuzzed_data_provider_.ConsumeBytes(payload_length); + uint64_t payload_length = + fuzzed_data_provider_->ConsumeUint32InRange(0, 64); + std::string payload = fuzzed_data_provider_->ConsumeBytes(payload_length); frame->data = new StringIOBuffer(payload); frame->header.payload_length = payload.size(); return frame; } - base::FuzzedDataProvider fuzzed_data_provider_; + base::FuzzedDataProvider* fuzzed_data_provider_; }; void WebSocketDeflateStreamFuzz(const uint8_t* data, size_t size) { + base::FuzzedDataProvider fuzzed_data_provider(data, size); + uint8_t flags = fuzzed_data_provider.ConsumeUint8(); + bool server_no_context_takeover = flags & 0x1; + bool client_no_context_takeover = (flags >> 1) & 0x1; + uint8_t window_bits = fuzzed_data_provider.ConsumeUint8(); + int server_max_window_bits = (window_bits & 0x7) + 8; + int client_max_window_bits = ((window_bits >> 3) & 0x7) + 8; // WebSocketDeflateStream needs to be constructed on each call because it // has state. + WebSocketExtension params("permessage-deflate"); + if (server_no_context_takeover) + params.Add(WebSocketExtension::Parameter("server_no_context_takeover")); + if (client_no_context_takeover) + params.Add(WebSocketExtension::Parameter("client_no_context_takeover")); + params.Add(WebSocketExtension::Parameter( + "server_max_window_bits", base::IntToString(server_max_window_bits))); + params.Add(WebSocketExtension::Parameter( + "client_max_window_bits", base::IntToString(client_max_window_bits))); std::string failure_message; WebSocketDeflateParameters parameters; - parameters.Initialize(WebSocketExtension("permessage-deflate"), - &failure_message); + DCHECK(parameters.Initialize(params, &failure_message)) << failure_message; WebSocketDeflateStream deflate_stream( - base::MakeUnique<WebSocketFuzzedStream>(data, size), parameters, - base::MakeUnique<WebSocketDeflatePredictorImpl>()); + base::MakeUnique<WebSocketFuzzedStream>(&fuzzed_data_provider), + parameters, base::MakeUnique<WebSocketDeflatePredictorImpl>()); std::vector<std::unique_ptr<net::WebSocketFrame>> frames; deflate_stream.ReadFrames(&frames, CompletionCallback()); } @@ -96,6 +127,8 @@ // Entry point for LibFuzzer. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < net::MIN_USEFUL_SIZE) + return 0; net::WebSocketDeflateStreamFuzz(data, size); return 0;
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 1b338e05..a30c753 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1913,7 +1913,6 @@ crbug.com/626703 external/wpt/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html [ Timeout ] # ====== New tests from w3c-test-autoroller added here ====== -crbug.com/626703 external/wpt/pointerevents/pointerevent_click_during_capture-manual.html [ Timeout ] crbug.com/626703 external/wpt/streams/writable-streams/reentrant-strategy.dedicatedworker.html [ Timeout ] crbug.com/626703 external/wpt/streams/writable-streams/reentrant-strategy.html [ Timeout ] crbug.com/626703 external/wpt/streams/writable-streams/reentrant-strategy.serviceworker.https.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/bluetooth/characteristic/getDescriptor/descriptor-not-found.html b/third_party/WebKit/LayoutTests/bluetooth/characteristic/getDescriptor/descriptor-not-found.html index e78b249f..9982902 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/characteristic/getDescriptor/descriptor-not-found.html +++ b/third_party/WebKit/LayoutTests/bluetooth/characteristic/getDescriptor/descriptor-not-found.html
@@ -4,6 +4,7 @@ <script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> <script> 'use strict'; + let descriptorUUID = '00002906-0000-1000-8000-00805f9b34fb'; promise_test(() => { return setBluetoothFakeAdapter('DisconnectingHealthThermometerAdapter') .then(() => requestDeviceWithKeyDown({ @@ -12,11 +13,12 @@ .then(gattServer => gattServer.getPrimaryService('health_thermometer')) .then(service => service.getCharacteristic('measurement_interval')) .then(characteristic => { - assert_promise_rejects_with_message( + return assert_promise_rejects_with_message( // Valid Range is not present in this characteristic - characteristic.getDescriptor(2906), + characteristic.getDescriptor(descriptorUUID), new DOMException( - 'No Descriptors with specified UUID found in Characteristic.', + 'No Descriptors matching UUID ' + descriptorUUID + + ' found in Characteristic with UUID ' + measurement_interval.uuid + '.', 'NotFoundError')); }) }, 'Request for absent descriptor. Reject with NotFoundError.');
diff --git a/third_party/WebKit/LayoutTests/bluetooth/script-tests/server/device-disconnects-invalidates-objects.js b/third_party/WebKit/LayoutTests/bluetooth/script-tests/server/device-disconnects-invalidates-objects.js index dfd37d5..6bc6b1d 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/script-tests/server/device-disconnects-invalidates-objects.js +++ b/third_party/WebKit/LayoutTests/bluetooth/script-tests/server/device-disconnects-invalidates-objects.js
@@ -28,7 +28,8 @@ continue; } let error = new DOMException( - 'Service is no longer valid. Remember to retrieve the service ' + + 'Service with UUID ' + service.uuid + + ' is no longer valid. Remember to retrieve the service ' + 'again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/script-tests/server/disconnect-invalidates-objects.js b/third_party/WebKit/LayoutTests/bluetooth/script-tests/server/disconnect-invalidates-objects.js index 98454d4..db410ed 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/script-tests/server/disconnect-invalidates-objects.js +++ b/third_party/WebKit/LayoutTests/bluetooth/script-tests/server/disconnect-invalidates-objects.js
@@ -23,7 +23,8 @@ let promises = Promise.resolve(); for (let service of services) { let error = new DOMException( - 'Service is no longer valid. Remember to retrieve the service ' + + 'Service with UUID ' + service.uuid + + ' is no longer valid. Remember to retrieve the service ' + 'again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/script-tests/service/device-disconnects-invalidates-objects.js b/third_party/WebKit/LayoutTests/bluetooth/script-tests/service/device-disconnects-invalidates-objects.js index bbbb0b1..666fb54 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/script-tests/service/device-disconnects-invalidates-objects.js +++ b/third_party/WebKit/LayoutTests/bluetooth/script-tests/service/device-disconnects-invalidates-objects.js
@@ -25,7 +25,8 @@ let promises = Promise.resolve(); for (let characteristic of characteristics) { let error = new DOMException( - 'Characteristic is no longer valid. Remember to retrieve the ' + + 'Characteristic with UUID ' + characteristic.uuid + + ' is no longer valid. Remember to retrieve the ' + 'characteristic again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/script-tests/service/disconnect-invalidates-objects.js b/third_party/WebKit/LayoutTests/bluetooth/script-tests/service/disconnect-invalidates-objects.js index bf7a8c8..10061f10 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/script-tests/service/disconnect-invalidates-objects.js +++ b/third_party/WebKit/LayoutTests/bluetooth/script-tests/service/disconnect-invalidates-objects.js
@@ -23,7 +23,8 @@ let promises = Promise.resolve(); for (let characteristic of characteristics) { let error = new DOMException( - 'Characteristic is no longer valid. Remember to retrieve the ' + + 'Characteristic with UUID ' + characteristic.uuid + + ' is no longer valid. Remember to retrieve the ' + 'characteristic again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/delayed-discovery-service-not-found.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/delayed-discovery-service-not-found.html index f53da55..f919af15 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/delayed-discovery-service-not-found.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/delayed-discovery-service-not-found.html
@@ -13,7 +13,7 @@ .then(gattServer => { return assert_promise_rejects_with_message( gattServer.getPrimaryService('battery_service'), - new DOMException('No Services with specified UUID found in Device.', + new DOMException('No Services matching UUID ' + battery_service.uuid + ' found in Device.', 'NotFoundError')); }); }, 'Request for absent service. Must reject with NotFoundError even when the ' +
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/gen-device-disconnects-invalidates-objects.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/gen-device-disconnects-invalidates-objects.html index ce1c1078..c55cbc69 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/gen-device-disconnects-invalidates-objects.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/gen-device-disconnects-invalidates-objects.html
@@ -31,7 +31,8 @@ continue; } let error = new DOMException( - 'Service is no longer valid. Remember to retrieve the service ' + + 'Service with UUID ' + service.uuid + + ' is no longer valid. Remember to retrieve the service ' + 'again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/gen-disconnect-invalidates-objects.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/gen-disconnect-invalidates-objects.html index 36865b2b..6bdd14cb 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/gen-disconnect-invalidates-objects.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/gen-disconnect-invalidates-objects.html
@@ -26,7 +26,8 @@ let promises = Promise.resolve(); for (let service of services) { let error = new DOMException( - 'Service is no longer valid. Remember to retrieve the service ' + + 'Service with UUID ' + service.uuid + + ' is no longer valid. Remember to retrieve the service ' + 'again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/service-not-found.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/service-not-found.html index 09ab7b4..51b6ce9 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/service-not-found.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryService/service-not-found.html
@@ -12,7 +12,7 @@ .then(device => device.gatt.connect()) .then(gattServer => assert_promise_rejects_with_message( gattServer.getPrimaryService('glucose'), - new DOMException('No Services with specified UUID found in Device.', + new DOMException('No Services matching UUID ' + glucose.uuid + ' found in Device.', 'NotFoundError'))); }, 'Request for absent service. Reject with NotFoundError.'); </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/delayed-discovery-service-with-uuid-not-found.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/delayed-discovery-service-with-uuid-not-found.html index 15219a95..69141c0 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/delayed-discovery-service-with-uuid-not-found.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/delayed-discovery-service-with-uuid-not-found.html
@@ -13,7 +13,7 @@ .then(gattServer => { return assert_promise_rejects_with_message( gattServer.getPrimaryServices('battery_service'), - new DOMException('No Services with specified UUID found in Device.', + new DOMException('No Services matching UUID ' + battery_service.uuid + ' found in Device.', 'NotFoundError')); }); }, 'Request for absent service with UUID. Must reject with NotFoundError ' +
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-device-disconnects-invalidates-objects-with-uuid.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-device-disconnects-invalidates-objects-with-uuid.html index fa1b568..f1426b1 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-device-disconnects-invalidates-objects-with-uuid.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-device-disconnects-invalidates-objects-with-uuid.html
@@ -31,7 +31,8 @@ continue; } let error = new DOMException( - 'Service is no longer valid. Remember to retrieve the service ' + + 'Service with UUID ' + service.uuid + + ' is no longer valid. Remember to retrieve the service ' + 'again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-device-disconnects-invalidates-objects.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-device-disconnects-invalidates-objects.html index 60af7661..fbe41394 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-device-disconnects-invalidates-objects.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-device-disconnects-invalidates-objects.html
@@ -31,7 +31,8 @@ continue; } let error = new DOMException( - 'Service is no longer valid. Remember to retrieve the service ' + + 'Service with UUID ' + service.uuid + + ' is no longer valid. Remember to retrieve the service ' + 'again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects-with-uuid.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects-with-uuid.html index 471fe2ca..eeb4815 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects-with-uuid.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects-with-uuid.html
@@ -26,7 +26,8 @@ let promises = Promise.resolve(); for (let service of services) { let error = new DOMException( - 'Service is no longer valid. Remember to retrieve the service ' + + 'Service with UUID ' + service.uuid + + ' is no longer valid. Remember to retrieve the service ' + 'again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects.html index d9c15cb..4e9f3c9 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects.html
@@ -26,7 +26,8 @@ let promises = Promise.resolve(); for (let service of services) { let error = new DOMException( - 'Service is no longer valid. Remember to retrieve the service ' + + 'Service with UUID ' + service.uuid + + ' is no longer valid. Remember to retrieve the service ' + 'again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/services-not-found-with-uuid.html b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/services-not-found-with-uuid.html index 688813e..4b41012 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/services-not-found-with-uuid.html +++ b/third_party/WebKit/LayoutTests/bluetooth/server/getPrimaryServices/services-not-found-with-uuid.html
@@ -12,7 +12,7 @@ .then(device => device.gatt.connect()) .then(gattServer => assert_promise_rejects_with_message( gattServer.getPrimaryServices('glucose'), - new DOMException('No Services with specified UUID found in Device.', + new DOMException('No Services matching UUID ' + glucose.uuid + ' found in Device.', 'NotFoundError'))); }, 'Request for absent service. Reject with NotFoundError.'); </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/characteristic-not-found.html b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/characteristic-not-found.html index b16d10f..dcbf0ab2 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/characteristic-not-found.html +++ b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/characteristic-not-found.html
@@ -14,7 +14,8 @@ .then(service => assert_promise_rejects_with_message( service.getCharacteristic('battery_level'), new DOMException( - 'No Characteristics with specified UUID found in Service.', + 'No Characteristics matching UUID ' + battery_level.uuid + ' found in Service with UUID ' + + generic_access.uuid + '.', 'NotFoundError'))); }, 'Request for absent characteristic. Reject with NotFoundError.'); </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/gen-device-disconnects-invalidates-objects.html b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/gen-device-disconnects-invalidates-objects.html index 6628f20..0f19f49 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/gen-device-disconnects-invalidates-objects.html +++ b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/gen-device-disconnects-invalidates-objects.html
@@ -28,7 +28,8 @@ let promises = Promise.resolve(); for (let characteristic of characteristics) { let error = new DOMException( - 'Characteristic is no longer valid. Remember to retrieve the ' + + 'Characteristic with UUID ' + characteristic.uuid + + ' is no longer valid. Remember to retrieve the ' + 'characteristic again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/gen-disconnect-invalidates-objects.html b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/gen-disconnect-invalidates-objects.html index 801dfc1..e05d356 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/gen-disconnect-invalidates-objects.html +++ b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/gen-disconnect-invalidates-objects.html
@@ -26,7 +26,8 @@ let promises = Promise.resolve(); for (let characteristic of characteristics) { let error = new DOMException( - 'Characteristic is no longer valid. Remember to retrieve the ' + + 'Characteristic with UUID ' + characteristic.uuid + + ' is no longer valid. Remember to retrieve the ' + 'characteristic again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-not-found-with-uuid.html b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-not-found-with-uuid.html index 70834546..c6f49d7e 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-not-found-with-uuid.html +++ b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-not-found-with-uuid.html
@@ -6,7 +6,8 @@ 'use strict'; promise_test(() => { let expected = new DOMException( - 'No Characteristics with specified UUID found in Service.', + 'No Characteristics matching UUID ' + battery_level.uuid + ' found in Service with UUID ' + + heart_rate.uuid + '.', 'NotFoundError'); return setBluetoothFakeAdapter('HeartRateAdapter') .then(() => requestDeviceWithKeyDown({
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-device-disconnects-invalidates-objects-with-uuid.html b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-device-disconnects-invalidates-objects-with-uuid.html index 2ed03f9..3fb1fc9 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-device-disconnects-invalidates-objects-with-uuid.html +++ b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-device-disconnects-invalidates-objects-with-uuid.html
@@ -28,7 +28,8 @@ let promises = Promise.resolve(); for (let characteristic of characteristics) { let error = new DOMException( - 'Characteristic is no longer valid. Remember to retrieve the ' + + 'Characteristic with UUID ' + characteristic.uuid + + ' is no longer valid. Remember to retrieve the ' + 'characteristic again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-device-disconnects-invalidates-objects.html b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-device-disconnects-invalidates-objects.html index eeb6f22a..15fce456 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-device-disconnects-invalidates-objects.html +++ b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-device-disconnects-invalidates-objects.html
@@ -28,7 +28,8 @@ let promises = Promise.resolve(); for (let characteristic of characteristics) { let error = new DOMException( - 'Characteristic is no longer valid. Remember to retrieve the ' + + 'Characteristic with UUID ' + characteristic.uuid + + ' is no longer valid. Remember to retrieve the ' + 'characteristic again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-disconnect-invalidates-objects-with-uuid.html b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-disconnect-invalidates-objects-with-uuid.html index b7eb08f..fea309f 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-disconnect-invalidates-objects-with-uuid.html +++ b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-disconnect-invalidates-objects-with-uuid.html
@@ -26,7 +26,8 @@ let promises = Promise.resolve(); for (let characteristic of characteristics) { let error = new DOMException( - 'Characteristic is no longer valid. Remember to retrieve the ' + + 'Characteristic with UUID ' + characteristic.uuid + + ' is no longer valid. Remember to retrieve the ' + 'characteristic again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-disconnect-invalidates-objects.html b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-disconnect-invalidates-objects.html index 2941a44..995d2894 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-disconnect-invalidates-objects.html +++ b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/gen-disconnect-invalidates-objects.html
@@ -26,7 +26,8 @@ let promises = Promise.resolve(); for (let characteristic of characteristics) { let error = new DOMException( - 'Characteristic is no longer valid. Remember to retrieve the ' + + 'Characteristic with UUID ' + characteristic.uuid + + ' is no longer valid. Remember to retrieve the ' + 'characteristic again after reconnecting.', 'InvalidStateError'); promises = promises.then(() =>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-removeChild-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-removeChild-expected.txt deleted file mode 100644 index f751f73..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-removeChild-expected.txt +++ /dev/null
@@ -1,31 +0,0 @@ -This is a testharness.js-based test. -PASS Passing a detached element from the main document to removeChild should not affect it. -PASS Passing a non-detached element from the main document to removeChild should not affect it. -PASS Calling removeChild on a element from the main document with no children should throw NOT_FOUND_ERR. -PASS Passing a detached text from the main document to removeChild should not affect it. -PASS Passing a non-detached text from the main document to removeChild should not affect it. -PASS Calling removeChild on a text from the main document with no children should throw NOT_FOUND_ERR. -PASS Passing a detached comment from the main document to removeChild should not affect it. -PASS Passing a non-detached comment from the main document to removeChild should not affect it. -PASS Calling removeChild on a comment from the main document with no children should throw NOT_FOUND_ERR. -PASS Passing a detached element from a frame document to removeChild should not affect it. -PASS Passing a non-detached element from a frame document to removeChild should not affect it. -PASS Calling removeChild on a element from a frame document with no children should throw NOT_FOUND_ERR. -PASS Passing a detached text from a frame document to removeChild should not affect it. -PASS Passing a non-detached text from a frame document to removeChild should not affect it. -PASS Calling removeChild on a text from a frame document with no children should throw NOT_FOUND_ERR. -PASS Passing a detached comment from a frame document to removeChild should not affect it. -PASS Passing a non-detached comment from a frame document to removeChild should not affect it. -PASS Calling removeChild on a comment from a frame document with no children should throw NOT_FOUND_ERR. -PASS Passing a detached element from a synthetic document to removeChild should not affect it. -PASS Passing a non-detached element from a synthetic document to removeChild should not affect it. -PASS Calling removeChild on a element from a synthetic document with no children should throw NOT_FOUND_ERR. -PASS Passing a detached text from a synthetic document to removeChild should not affect it. -PASS Passing a non-detached text from a synthetic document to removeChild should not affect it. -PASS Calling removeChild on a text from a synthetic document with no children should throw NOT_FOUND_ERR. -PASS Passing a detached comment from a synthetic document to removeChild should not affect it. -PASS Passing a non-detached comment from a synthetic document to removeChild should not affect it. -PASS Calling removeChild on a comment from a synthetic document with no children should throw NOT_FOUND_ERR. -PASS Passing a value that is not a Node reference to removeChild should throw TypeError. -Harness: the test ran to completion. -b
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/javascript-url-return-value-handling-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/javascript-url-return-value-handling-expected.txt deleted file mode 100644 index c1e6453..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/javascript-url-return-value-handling-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -PASS Test that javascript: evaluation only performs a navigation to the - result when the result is a string value. -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_click_during_capture-manual-automation.js b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_click_during_capture-manual-automation.js new file mode 100644 index 0000000..75ca5848 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_click_during_capture-manual-automation.js
@@ -0,0 +1,12 @@ +importAutomationScript('/pointerevents/pointerevent_common_input.js'); + +function inject_input() { + return mouseClickInTarget('#green').then(function() { + return mouseDragInTargets(['#blue', '#green']); + }).then(function() { + return mouseClickInTarget('#green'); + }).then(function() { + return mouseDragInTargets(['#blue', '#green']); + }); +} +
diff --git a/third_party/WebKit/LayoutTests/fast/css/beforeSelectorOnCodeElement.html b/third_party/WebKit/LayoutTests/fast/css/beforeSelectorOnCodeElement.html index 6d68504..cd3e64b 100644 --- a/third_party/WebKit/LayoutTests/fast/css/beforeSelectorOnCodeElement.html +++ b/third_party/WebKit/LayoutTests/fast/css/beforeSelectorOnCodeElement.html
@@ -3,7 +3,7 @@ <style> @font-face { font-family: '-webkit-monospace'; - src: local('Courier'); + src: local('Courier'), local('Courier New'); } /* Match Mac OS X's font fallback behavior on Windows */
diff --git a/third_party/WebKit/LayoutTests/fast/css/font-face-multiple-ranges-for-unicode-range.html b/third_party/WebKit/LayoutTests/fast/css/font-face-multiple-ranges-for-unicode-range.html index e2295266..428f5db 100644 --- a/third_party/WebKit/LayoutTests/fast/css/font-face-multiple-ranges-for-unicode-range.html +++ b/third_party/WebKit/LayoutTests/fast/css/font-face-multiple-ranges-for-unicode-range.html
@@ -10,77 +10,77 @@ /* Test 0: Comma-separated list, which is valid. */ @font-face { font-family:myfont_0; - src: local('Times'); + src: local('Times New Roman'), local('Times'); } @font-face { font-family:myfont_0; - src: local('Courier'); + src: local('Courier New'), local('Courier'); unicode-range: u+69, u+6a; /* 'i' and 'j' */ } /* Test 1: Comma-separated list with three elements, which is valid. */ @font-face { font-family:myfont_1; - src: local('Times'); + src: local('Times New Roman'), local('Times'); } @font-face { font-family:myfont_1; - src: local('Courier'); + src: local('Courier New'), local('Courier'); unicode-range: u+69 , u+6a ,u+6c; /* 'i', 'j', and 'l' */ } /* Test 2: Comma-separated list with two consecutive commas, which is invalid. */ @font-face { font-family:myfont_2; - src: local('Times'); + src: local('Times New Roman'), local('Times'); } @font-face { font-family:myfont_2; - src: local('Courier'); + src: local('Courier New'), local('Courier'); unicode-range: u+69, , u+6a; /* 'i' and 'j' */ } /* Test 3: Comma-separated list with a trailing comma, which is invalid. */ @font-face { font-family:myfont_3; - src: local('Times'); + src: local('Times New Roman'), local('Times'); } @font-face { font-family:myfont_3; - src: local('Courier'); + src: local('Courier New'), local('Courier'); unicode-range: u+69, u+6a,; /* 'i' and 'j' */ } /* Test 4: Comma-separated list with a leading comma, which is invalid. */ @font-face { font-family:myfont_4; - src: local('Times'); + src: local('Times New Roman'), local('Times'); } @font-face { font-family:myfont_4; - src: local('Courier'); + src: local('Courier New'), local('Courier'); unicode-range: , u+69, u+6a; /* 'i' and 'j' */ } /* Test 5: Space-separated list, which is invalid. */ @font-face { font-family:myfont_5; - src: local('Times'); + src: local('Times New Roman'), local('Times'); } @font-face { font-family:myfont_5; - src: local('Courier'); + src: local('Courier New'), local('Courier'); unicode-range: u+69 u+6a ; /* 'i' and 'j' */ } /* Test 6: Slash-separated list, which is invalid. */ @font-face { font-family:myfont_6; - src: local('Times'); + src: local('Times New Roman'), local('Times'); } @font-face { font-family:myfont_6; - src: local('Courier'); + src: local('Courier New'), local('Courier'); unicode-range: u+69/u+6a; /* 'i' and 'j' */ }
diff --git a/third_party/WebKit/LayoutTests/media/controls/settings-disable-controls.html b/third_party/WebKit/LayoutTests/media/controls/settings-disable-controls.html index 5bd7c115..2aac53bc 100644 --- a/third_party/WebKit/LayoutTests/media/controls/settings-disable-controls.html +++ b/third_party/WebKit/LayoutTests/media/controls/settings-disable-controls.html
@@ -6,6 +6,11 @@ <script src="../media-controls.js"></script> <video controls></video> <script> +// |orphanedVideo| is used to check that the setting should not be despatched +// if the MediaControls of a video haven't been initialized. +var orphanedVideo = document.createElement('video'); +orphanedVideo.controls = true; + async_test(t => { var video = document.querySelector('video');
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange-expected.txt deleted file mode 100644 index dad3fa4b..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange-expected.txt +++ /dev/null
@@ -1,49 +0,0 @@ -This is a testharness.js-based test. -PASS test of input.setSelectionRange -PASS input typeof(input.setSelectionRange)' -PASS input setSelectionRange return void -PASS input setSelectionRange(0,1) -PASS input setSelectionRange(0,input.value.length+1) -PASS input setSelectionRange(input.value.length+1,input.value.length+1) -PASS input setSelectionRange(input.value.length+1,1) -PASS input setSelectionRange(2,2) -PASS input setSelectionRange(2,1) -PASS input direction of setSelectionRange(0,1,"backward") -PASS input direction of setSelectionRange(0,1,"forward") -PASS input direction of setSelectionRange(0,1,"none") -PASS input direction of setSelectionRange(0,1,"hoge") -PASS input direction of setSelectionRange(0,1,"BACKWARD") -PASS input direction of setSelectionRange(0,1) -PASS input setSelectionRange(1,-1) -PASS input setSelectionRange(-1,1) -PASS input setSelectionRange("string",1) -PASS input setSelectionRange(true,1) -PASS input setSelectionRange([],1) -PASS input setSelectionRange({},1) -PASS input setSelectionRange(NaN,1) -PASS input setSelectionRange(null,1) -PASS input setSelectionRange(undefined,1) -PASS input setSelectionRange fires a select event -PASS test of textarea.setSelectionRange -PASS textarea typeof(input.setSelectionRange)' -PASS textarea setSelectionRange return void -PASS textarea setSelectionRange(0,1) -PASS textarea setSelectionRange(0,textarea.value.length+1) -PASS textarea setSelectionRange(2,2) -PASS textarea setSelectionRange(2,1) -PASS textarea direction of setSelectionRange(0,1,"backward") -PASS textarea direction of setSelectionRange(0,1,"forward") -PASS textarea direction of setSelectionRange(0,1,"none") -PASS textarea direction of setSelectionRange(0,1,"hoge") -PASS textarea direction of setSelectionRange(0,1,"BACKWARD") -PASS textarea direction of setSelectionRange(0,1) -PASS textarea setSelectionRange("string",1) -PASS textarea setSelectionRange(true,1) -PASS textarea setSelectionRange([],1) -PASS textarea setSelectionRange({},1) -PASS textarea setSelectionRange(NaN,1) -PASS textarea setSelectionRange(null,1) -PASS textarea setSelectionRange(undefined,1) -PASS textarea setSelectionRange fires a select event -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js index 1f0c13d..9b6fae0 100644 --- a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js +++ b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
@@ -64,6 +64,11 @@ name: 'gatt.client_characteristic_configuration', uuid: '00002902-0000-1000-8000-00805f9b34fb' }; +var measurement_interval = { + alias: 0x2a21, + name: 'measurement_interval', + uuid: '00002a21-0000-1000-8000-00805f9b34fb' +}; // The following tests make sure the Web Bluetooth implementation // responds correctly to the different types of errors the
diff --git a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp index e2ff890..d654662e 100644 --- a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp
@@ -36,9 +36,11 @@ #include "bindings/core/v8/ToV8.h" #include "bindings/core/v8/V8Binding.h" #include "bindings/core/v8/V8DOMActivityLogger.h" +#include "bindings/core/v8/V8GCForContextDispose.h" #include "bindings/core/v8/V8HTMLDocument.h" #include "bindings/core/v8/V8HiddenValue.h" #include "bindings/core/v8/V8Initializer.h" +#include "bindings/core/v8/V8PagePopupControllerBinding.h" #include "bindings/core/v8/V8PrivateProperty.h" #include "bindings/core/v8/V8Window.h" #include "core/dom/Modulator.h" @@ -74,7 +76,36 @@ m_world->worldId()); MainThreadDebugger::instance()->contextWillBeDestroyed(m_scriptState.get()); - WindowProxy::disposeContext(behavior); + if (behavior == DetachGlobal) { + v8::Local<v8::Context> context = m_scriptState->context(); + // Clean up state on the global proxy, which will be reused. + if (!m_globalProxy.isEmpty()) { + // TODO(yukishiino): This DCHECK failed on Canary (M57) and Dev (M56). + // We need to figure out why m_globalProxy != context->Global(). + DCHECK(m_globalProxy == context->Global()); + DCHECK_EQ(toScriptWrappable(context->Global()), + toScriptWrappable( + context->Global()->GetPrototype().As<v8::Object>())); + m_globalProxy.get().SetWrapperClassId(0); + } + V8DOMWrapper::clearNativeInfo(isolate(), context->Global()); + m_scriptState->detachGlobalObject(); + +#if DCHECK_IS_ON() + didDetachGlobalProxy(); +#endif + } + + m_scriptState->disposePerContextData(); + + // It's likely that disposing the context has created a lot of + // garbage. Notify V8 about this so it'll have a chance of cleaning + // it up when idle. + V8GCForContextDispose::instance().notifyContextDisposed( + frame()->isMainFrame()); + + DCHECK(m_lifecycle == Lifecycle::ContextInitialized); + m_lifecycle = Lifecycle::ContextDetached; } void LocalWindowProxy::initialize() { @@ -130,12 +161,54 @@ frame()->loader().dispatchDidClearWindowObjectInMainWorld(); } +void LocalWindowProxy::setupWindowPrototypeChain() { + // Associate the window wrapper object and its prototype chain with the + // corresponding native DOMWindow object. + LocalDOMWindow* window = frame()->domWindow(); + const WrapperTypeInfo* wrapperTypeInfo = window->wrapperTypeInfo(); + v8::Local<v8::Context> context = m_scriptState->context(); + + // The global proxy object. Note this is not the global object. + v8::Local<v8::Object> globalProxy = context->Global(); + CHECK(m_globalProxy == globalProxy); + V8DOMWrapper::setNativeInfo(isolate(), globalProxy, wrapperTypeInfo, window); + // Mark the handle to be traced by Oilpan, since the global proxy has a + // reference to the DOMWindow. + m_globalProxy.get().SetWrapperClassId(wrapperTypeInfo->wrapperClassId); + +#if DCHECK_IS_ON() + didAttachGlobalProxy(); +#endif + + // The global object, aka window wrapper object. + v8::Local<v8::Object> windowWrapper = + globalProxy->GetPrototype().As<v8::Object>(); + V8DOMWrapper::setNativeInfo(isolate(), windowWrapper, wrapperTypeInfo, + window); + + // The prototype object of Window interface. + v8::Local<v8::Object> windowPrototype = + windowWrapper->GetPrototype().As<v8::Object>(); + CHECK(!windowPrototype.IsEmpty()); + V8DOMWrapper::setNativeInfo(isolate(), windowPrototype, wrapperTypeInfo, + window); + + // The named properties object of Window interface. + v8::Local<v8::Object> windowProperties = + windowPrototype->GetPrototype().As<v8::Object>(); + CHECK(!windowProperties.IsEmpty()); + V8DOMWrapper::setNativeInfo(isolate(), windowProperties, wrapperTypeInfo, + window); + + // TODO(keishi): Remove installPagePopupController and implement + // PagePopupController in another way. + V8PagePopupControllerBinding::installPagePopupController(context, + windowWrapper); +} + void LocalWindowProxy::createContext() { // Create a new v8::Context with the window object as the global object - // (aka the inner global). Reuse the global proxy object (aka the outer - // global) if it already exists. See the comments in - // setupWindowPrototypeChain for the structure of the prototype chain of - // the global object. + // (aka the inner global). Reuse the outer global proxy if it already exists. v8::Local<v8::ObjectTemplate> globalTemplate = V8Window::domTemplate(isolate(), *m_world)->InstanceTemplate(); CHECK(!globalTemplate.IsEmpty());
diff --git a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.h b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.h index 5283aa6..c6b8cd6 100644 --- a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.h +++ b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.h
@@ -62,6 +62,11 @@ // (e.g., after setting docoument.domain). void updateSecurityOrigin(SecurityOrigin*); + ScriptState* getScriptState() const { return m_scriptState.get(); } + v8::Local<v8::Context> contextIfInitialized() const { + return m_scriptState ? m_scriptState->context() : v8::Local<v8::Context>(); + } + private: LocalWindowProxy(v8::Isolate*, LocalFrame&, RefPtr<DOMWrapperWorld>); @@ -74,6 +79,10 @@ // wrapper is not yet associated with the native DOMWindow object. void createContext(); + // Associates the window wrapper and its prototype chain with the native + // DOMWindow object. Also does some more Window-specific initialization. + void setupWindowPrototypeChain(); + void setSecurityToken(SecurityOrigin*); // The JavaScript wrapper for the document object is cached on the global @@ -85,6 +94,8 @@ void updateActivityLogger(); LocalFrame* frame() const { return toLocalFrame(WindowProxy::frame()); } + + RefPtr<ScriptState> m_scriptState; }; } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/RemoteWindowProxy.cpp b/third_party/WebKit/Source/bindings/core/v8/RemoteWindowProxy.cpp index d5c6f4a2..eaa8bbe 100644 --- a/third_party/WebKit/Source/bindings/core/v8/RemoteWindowProxy.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/RemoteWindowProxy.cpp
@@ -28,50 +28,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "bindings/core/v8/WindowProxy.h" +#include "bindings/core/v8/RemoteWindowProxy.h" -#include <algorithm> #include <utility> -#include "bindings/core/v8/ConditionalFeatures.h" #include "bindings/core/v8/DOMWrapperWorld.h" -#include "bindings/core/v8/ScriptController.h" -#include "bindings/core/v8/ToV8.h" -#include "bindings/core/v8/V8Binding.h" -#include "bindings/core/v8/V8DOMActivityLogger.h" -#include "bindings/core/v8/V8Document.h" #include "bindings/core/v8/V8GCForContextDispose.h" -#include "bindings/core/v8/V8HTMLCollection.h" -#include "bindings/core/v8/V8HTMLDocument.h" -#include "bindings/core/v8/V8HiddenValue.h" -#include "bindings/core/v8/V8Initializer.h" -#include "bindings/core/v8/V8ObjectConstructor.h" -#include "bindings/core/v8/V8PagePopupControllerBinding.h" -#include "bindings/core/v8/V8PrivateProperty.h" #include "bindings/core/v8/V8Window.h" -#include "core/frame/LocalFrame.h" -#include "core/frame/LocalFrameClient.h" -#include "core/frame/csp/ContentSecurityPolicy.h" -#include "core/html/DocumentNameCollection.h" -#include "core/html/HTMLCollection.h" -#include "core/html/HTMLIFrameElement.h" -#include "core/inspector/InspectorInstrumentation.h" -#include "core/inspector/MainThreadDebugger.h" -#include "core/loader/DocumentLoader.h" -#include "core/loader/FrameLoader.h" -#include "core/origin_trials/OriginTrialContext.h" #include "platform/Histogram.h" #include "platform/RuntimeEnabledFeatures.h" #include "platform/ScriptForbiddenScope.h" #include "platform/heap/Handle.h" #include "platform/instrumentation/tracing/TraceEvent.h" -#include "platform/weborigin/SecurityOrigin.h" -#include "public/platform/Platform.h" -#include "v8/include/v8-debug.h" #include "v8/include/v8.h" #include "wtf/Assertions.h" -#include "wtf/StringExtras.h" -#include "wtf/text/CString.h" namespace blink { @@ -84,7 +54,36 @@ if (m_lifecycle != Lifecycle::ContextInitialized) return; - WindowProxy::disposeContext(behavior); + if (behavior == DetachGlobal) { + v8::Local<v8::Context> context = m_scriptState->context(); + // Clean up state on the global proxy, which will be reused. + if (!m_globalProxy.isEmpty()) { + // TODO(yukishiino): This DCHECK failed on Canary (M57) and Dev (M56). + // We need to figure out why m_globalProxy != context->Global(). + DCHECK(m_globalProxy == context->Global()); + DCHECK_EQ(toScriptWrappable(context->Global()), + toScriptWrappable( + context->Global()->GetPrototype().As<v8::Object>())); + m_globalProxy.get().SetWrapperClassId(0); + } + V8DOMWrapper::clearNativeInfo(isolate(), context->Global()); + m_scriptState->detachGlobalObject(); + +#if DCHECK_IS_ON() + didDetachGlobalProxy(); +#endif + } + + m_scriptState->disposePerContextData(); + + // It's likely that disposing the context has created a lot of + // garbage. Notify V8 about this so it'll have a chance of cleaning + // it up when idle. + V8GCForContextDispose::instance().notifyContextDisposed( + frame()->isMainFrame()); + + DCHECK(m_lifecycle == Lifecycle::ContextInitialized); + m_lifecycle = Lifecycle::ContextDetached; } void RemoteWindowProxy::initialize() { @@ -113,12 +112,49 @@ context->UseDefaultSecurityToken(); } +void RemoteWindowProxy::setupWindowPrototypeChain() { + // Associate the window wrapper object and its prototype chain with the + // corresponding native DOMWindow object. + DOMWindow* window = frame()->domWindow(); + const WrapperTypeInfo* wrapperTypeInfo = window->wrapperTypeInfo(); + v8::Local<v8::Context> context = m_scriptState->context(); + + // The global proxy object. Note this is not the global object. + v8::Local<v8::Object> globalProxy = context->Global(); + CHECK(m_globalProxy == globalProxy); + V8DOMWrapper::setNativeInfo(isolate(), globalProxy, wrapperTypeInfo, window); + // Mark the handle to be traced by Oilpan, since the global proxy has a + // reference to the DOMWindow. + m_globalProxy.get().SetWrapperClassId(wrapperTypeInfo->wrapperClassId); + +#if DCHECK_IS_ON() + didAttachGlobalProxy(); +#endif + + // The global object, aka window wrapper object. + v8::Local<v8::Object> windowWrapper = + globalProxy->GetPrototype().As<v8::Object>(); + V8DOMWrapper::setNativeInfo(isolate(), windowWrapper, wrapperTypeInfo, + window); + + // The prototype object of Window interface. + v8::Local<v8::Object> windowPrototype = + windowWrapper->GetPrototype().As<v8::Object>(); + CHECK(!windowPrototype.IsEmpty()); + V8DOMWrapper::setNativeInfo(isolate(), windowPrototype, wrapperTypeInfo, + window); + + // The named properties object of Window interface. + v8::Local<v8::Object> windowProperties = + windowPrototype->GetPrototype().As<v8::Object>(); + CHECK(!windowProperties.IsEmpty()); + V8DOMWrapper::setNativeInfo(isolate(), windowProperties, wrapperTypeInfo, + window); +} + void RemoteWindowProxy::createContext() { // Create a new v8::Context with the window object as the global object - // (aka the inner global). Reuse the global proxy object (aka the outer - // global) if it already exists. See the comments in - // setupWindowPrototypeChain for the structure of the prototype chain of - // the global object. + // (aka the inner global). Reuse the outer global proxy if it already exists. v8::Local<v8::ObjectTemplate> globalTemplate = V8Window::domTemplate(isolate(), *m_world)->InstanceTemplate(); CHECK(!globalTemplate.IsEmpty());
diff --git a/third_party/WebKit/Source/bindings/core/v8/RemoteWindowProxy.h b/third_party/WebKit/Source/bindings/core/v8/RemoteWindowProxy.h index 6e6a394c..7e7fde4 100644 --- a/third_party/WebKit/Source/bindings/core/v8/RemoteWindowProxy.h +++ b/third_party/WebKit/Source/bindings/core/v8/RemoteWindowProxy.h
@@ -32,12 +32,25 @@ #define RemoteWindowProxy_h #include "bindings/core/v8/DOMWrapperWorld.h" +#include "bindings/core/v8/ScriptState.h" +#include "bindings/core/v8/WindowProxy.h" #include "core/frame/RemoteFrame.h" #include "v8/include/v8.h" +#include "wtf/RefPtr.h" namespace blink { // Subclass of WindowProxy that only handles RemoteFrame. +// TODO(dcheng): This class currently duplicates a lot of logic from +// LocalWindowPoxy: +// - contextIfInitialized +// - initialize +// - disposeContext +// - setupWindowPrototypeChain +// - createContext +// This is currently duplicated to make it easier to stage the switch to using +// v8::RemoteContext::NewRemoteContext, and will be removed once the switch +// is complete. class RemoteWindowProxy final : public WindowProxy { public: static RemoteWindowProxy* create(v8::Isolate* isolate, @@ -47,17 +60,27 @@ return new RemoteWindowProxy(isolate, frame, std::move(world)); } + v8::Local<v8::Context> contextIfInitialized() const { + return m_scriptState ? m_scriptState->context() : v8::Local<v8::Context>(); + } + private: RemoteWindowProxy(v8::Isolate*, RemoteFrame&, RefPtr<DOMWrapperWorld>); void initialize() override; void disposeContext(GlobalDetachmentBehavior) override; + // Associates the window wrapper and its prototype chain with the native + // DOMWindow object. Also does some more Window-specific initialization. + void setupWindowPrototypeChain(); + // Creates a new v8::Context with the window wrapper object as the global // object (aka the inner global). Note that the window wrapper and its // prototype chain do not get fully initialized yet, e.g. the window // wrapper is not yet associated with the native DOMWindow object. void createContext(); + + RefPtr<ScriptState> m_scriptState; }; } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp index 4dcdb81..561d28e3 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp
@@ -36,8 +36,7 @@ : m_isolate(context->GetIsolate()), m_context(m_isolate, context), m_world(world), - m_perContextData(V8PerContextData::create(context)) -{ + m_perContextData(V8PerContextData::create(context)) { DCHECK(m_world); m_context.setWeak(this, &contextCollectedCallback); context->SetAlignedPointerInEmbedderData(v8ContextPerContextDataIndex, this); @@ -51,9 +50,6 @@ void ScriptState::detachGlobalObject() { ASSERT(!m_context.isEmpty()); context()->DetachGlobal(); -#if DCHECK_IS_ON() - m_globalObjectDetached = true; -#endif } void ScriptState::disposePerContextData() {
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptState.h b/third_party/WebKit/Source/bindings/core/v8/ScriptState.h index cbe01ec0..9b60146 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptState.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptState.h
@@ -156,9 +156,6 @@ } void detachGlobalObject(); void clearContext() { return m_context.clear(); } -#if DCHECK_IS_ON() - bool isGlobalObjectDetached() const { return m_globalObjectDetached; } -#endif V8PerContextData* perContextData() const { return m_perContextData.get(); } void disposePerContextData(); @@ -184,10 +181,6 @@ // disposePerContextData() once you no longer need V8PerContextData. // Otherwise, the v8::Context will leak. std::unique_ptr<V8PerContextData> m_perContextData; - -#if DCHECK_IS_ON() - bool m_globalObjectDetached = false; -#endif }; // ScriptStateProtectingContext keeps the context associated with the
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp index 5cd2bab1..0ccf6f2 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp
@@ -811,7 +811,7 @@ return v8::Local<v8::Context>(); } -v8::Local<v8::Context> toV8Context(Frame* frame, DOMWrapperWorld& world) { +v8::Local<v8::Context> toV8Context(LocalFrame* frame, DOMWrapperWorld& world) { if (!frame) return v8::Local<v8::Context>(); v8::Local<v8::Context> context = toV8ContextEvenIfDetached(frame, world); @@ -825,10 +825,10 @@ return v8::Local<v8::Context>(); } -v8::Local<v8::Context> toV8ContextEvenIfDetached(Frame* frame, +v8::Local<v8::Context> toV8ContextEvenIfDetached(LocalFrame* frame, DOMWrapperWorld& world) { ASSERT(frame); - return frame->windowProxy(world)->contextIfInitialized(); + return frame->script().windowProxy(world)->contextIfInitialized(); } bool isValidEnum(const String& value,
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Binding.h b/third_party/WebKit/Source/bindings/core/v8/V8Binding.h index 24321bd..1df7fae 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8Binding.h +++ b/third_party/WebKit/Source/bindings/core/v8/V8Binding.h
@@ -1010,10 +1010,10 @@ DOMWrapperWorld&); // Returns a V8 context associated with a Frame and a DOMWrapperWorld. // This method returns an empty context if the frame is already detached. -CORE_EXPORT v8::Local<v8::Context> toV8Context(Frame*, DOMWrapperWorld&); +CORE_EXPORT v8::Local<v8::Context> toV8Context(LocalFrame*, DOMWrapperWorld&); // Like toV8Context but also returns the context if the frame is already // detached. -CORE_EXPORT v8::Local<v8::Context> toV8ContextEvenIfDetached(Frame*, +CORE_EXPORT v8::Local<v8::Context> toV8ContextEvenIfDetached(LocalFrame*, DOMWrapperWorld&); // Returns the frame object of the window object associated with
diff --git a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp index 1614e622..4a31146 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp
@@ -32,11 +32,7 @@ #include <utility> -#include "bindings/core/v8/V8Binding.h" #include "bindings/core/v8/V8DOMWrapper.h" -#include "bindings/core/v8/V8GCForContextDispose.h" -#include "bindings/core/v8/V8PagePopupControllerBinding.h" -#include "core/frame/DOMWindow.h" #include "core/frame/Frame.h" #include "v8/include/v8.h" #include "wtf/Assertions.h" @@ -62,37 +58,6 @@ m_world(std::move(world)), m_lifecycle(Lifecycle::ContextUninitialized) {} -void WindowProxy::disposeContext(GlobalDetachmentBehavior behavior) { - DCHECK(m_lifecycle == Lifecycle::ContextInitialized); - - if (behavior == DetachGlobal) { - v8::Local<v8::Context> context = m_scriptState->context(); - // Clean up state on the global proxy, which will be reused. - if (!m_globalProxy.isEmpty()) { - // TODO(yukishiino): This DCHECK failed on Canary (M57) and Dev (M56). - // We need to figure out why m_globalProxy != context->Global(). - DCHECK(m_globalProxy == context->Global()); - DCHECK_EQ(toScriptWrappable(context->Global()), - toScriptWrappable( - context->Global()->GetPrototype().As<v8::Object>())); - m_globalProxy.get().SetWrapperClassId(0); - } - V8DOMWrapper::clearNativeInfo(m_isolate, context->Global()); - m_scriptState->detachGlobalObject(); - } - - m_scriptState->disposePerContextData(); - - // It's likely that disposing the context has created a lot of - // garbage. Notify V8 about this so it'll have a chance of cleaning - // it up when idle. - V8GCForContextDispose::instance().notifyContextDisposed( - m_frame->isMainFrame()); - - DCHECK(m_lifecycle == Lifecycle::ContextInitialized); - m_lifecycle = Lifecycle::ContextDetached; -} - void WindowProxy::clearForClose() { disposeContext(DoNotDetachGlobal); } @@ -102,20 +67,15 @@ } v8::Local<v8::Object> WindowProxy::globalIfNotDetached() { - if (m_lifecycle == Lifecycle::ContextInitialized) { - DCHECK(m_scriptState->contextIsValid()); - DCHECK(m_globalProxy == m_scriptState->context()->Global()); + if (m_lifecycle == Lifecycle::ContextInitialized) return m_globalProxy.newLocal(m_isolate); - } return v8::Local<v8::Object>(); } v8::Local<v8::Object> WindowProxy::releaseGlobal() { DCHECK(m_lifecycle != Lifecycle::ContextInitialized); - // Make sure the global object was detached from the proxy by calling - // clearForNavigation(). - if (m_lifecycle == Lifecycle::ContextDetached) - ASSERT(m_scriptState->isGlobalObjectDetached()); + DLOG_IF(FATAL, m_isGlobalProxyAttached) + << "Context not detached by calling clearForNavigation()"; v8::Local<v8::Object> global = m_globalProxy.newLocal(m_isolate); m_globalProxy.clear(); @@ -177,71 +137,4 @@ } } -void WindowProxy::setupWindowPrototypeChain() { - // Associate the window wrapper object and its prototype chain with the - // corresponding native DOMWindow object. - // The full structure of the global object's prototype chain is as follows: - // - // global proxy object [1] - // -- has prototype --> global object (window wrapper object) [2] - // -- has prototype --> Window.prototype - // -- has prototype --> WindowProperties [3] - // -- has prototype --> EventTarget.prototype - // -- has prototype --> Object.prototype - // -- has prototype --> null - // - // [1] Global proxy object is as known as "outer global object". It's an - // empty object and remains after navigation. When navigated, points to - // a different global object as the prototype object. - // [2] Global object is as known as "inner global object" or "window wrapper - // object". The prototype chain between global proxy object and global - // object is NOT observable from user JavaScript code. All other - // prototype chains are observable. Global proxy object and global object - // together appear to be the same single JavaScript object. See also: - // https://wiki.mozilla.org/Gecko:SplitWindow - // global object (= window wrapper object) provides most of Window's DOM - // attributes and operations. Also global variables defined by user - // JavaScript are placed on this object. When navigated, a new global - // object is created together with a new v8::Context, but the global proxy - // object doesn't change. - // [3] WindowProperties is a named properties object of Window interface. - - DOMWindow* window = m_frame->domWindow(); - const WrapperTypeInfo* wrapperTypeInfo = window->wrapperTypeInfo(); - v8::Local<v8::Context> context = m_scriptState->context(); - - // The global proxy object. Note this is not the global object. - v8::Local<v8::Object> globalProxy = context->Global(); - CHECK(m_globalProxy == globalProxy); - V8DOMWrapper::setNativeInfo(m_isolate, globalProxy, wrapperTypeInfo, window); - // Mark the handle to be traced by Oilpan, since the global proxy has a - // reference to the DOMWindow. - m_globalProxy.get().SetWrapperClassId(wrapperTypeInfo->wrapperClassId); - - // The global object, aka window wrapper object. - v8::Local<v8::Object> windowWrapper = - globalProxy->GetPrototype().As<v8::Object>(); - windowWrapper = V8DOMWrapper::associateObjectWithWrapper( - m_isolate, window, wrapperTypeInfo, windowWrapper); - - // The prototype object of Window interface. - v8::Local<v8::Object> windowPrototype = - windowWrapper->GetPrototype().As<v8::Object>(); - CHECK(!windowPrototype.IsEmpty()); - V8DOMWrapper::setNativeInfo(m_isolate, windowPrototype, wrapperTypeInfo, - window); - - // The named properties object of Window interface. - v8::Local<v8::Object> windowProperties = - windowPrototype->GetPrototype().As<v8::Object>(); - CHECK(!windowProperties.IsEmpty()); - V8DOMWrapper::setNativeInfo(m_isolate, windowProperties, wrapperTypeInfo, - window); - - // TODO(keishi): Remove installPagePopupController and implement - // PagePopupController in another way. - V8PagePopupControllerBinding::installPagePopupController(context, - windowWrapper); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.h b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.h index 0a52e8e..f0771472 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.h +++ b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.h
@@ -33,7 +33,7 @@ #include "bindings/core/v8/DOMWrapperWorld.h" #include "bindings/core/v8/ScopedPersistent.h" -#include "bindings/core/v8/ScriptState.h" +#include "core/CoreExport.h" #include "platform/heap/Handle.h" #include "v8/include/v8.h" #include "wtf/RefPtr.h" @@ -41,25 +41,98 @@ namespace blink { class Frame; -class ScriptController; -// WindowProxy represents all the per-global object state for a Frame that -// persist between navigations. +// WindowProxy implements the split window model of a window for a frame. In the +// HTML standard, the split window model is composed of the Window interface +// (the inner global object) and the WindowProxy interface (the outer global +// proxy). +// +// The Window interface is backed by the Blink DOMWindow C++ implementation. +// In contrast, the WindowProxy interface does not have a corresponding +// C++ implementation in Blink: the WindowProxy class defined here only manages +// context initialization and detach. Instead, the behavior of the WindowProxy +// interface is defined by JSGlobalProxy in v8 and the prototype chain set up +// during context initialization. +// +// ====== Inner Global Object ====== +// The inner global object is the global for the script environment of a Frame. +// Since Window and Document also have a 1:1 relationship, this means that each +// inner global object has an associated Document which does not change. On +// navigation, the new Document receives a new inner global object. +// +// However, there is one exception to the 1:1 DOMWindow:Document rule. If: +// - the previous Document is the initial empty document +// - the new Document is same-origin to the previous Document +// then the inner global object will be reused for the new Document. This is the +// only case where the associated Document of an inner global object can change. +// +// All methods and attributes defined on the Window interface are exposed via +// the inner global object. Global variables defined by script running in the +// Document also live on the inner global object. +// +// ====== Outer Global Proxy ==== +// The outer global proxy is reused across navigations. It implements the +// security checks for same-origin/cross-origin access to the Window interface. +// When the check passes (i.e. the access is same-origin), the access is +// forwarded to the inner global object of the active Document in this +// WindowProxy's Frame). +// +// When the security check fails, the access is delegated to the outer global +// proxy's cross-origin interceptors. The cross-origin interceptors may choose +// to return a value (if the property is exposed cross-origin) or throw an +// exception otherwise. +// +// Note that the cross-origin interceptors are only used for cross-origin +// accesses: a same-origin access to a method that is available cross-origin, +// such as Window.postMessage, will be delegated to the inner global object. +// +// ====== LocalWindowProxy vs RemoteWindowProxy ====== +// WindowProxy has two concrete subclasses: +// - LocalWindowProxy: implements the split window model for a frame in the same +// process, i.e. a LocalFrame. +// - RemoteWindowProxy: implements the split window model for a frame in a +// different process, i.e. a RemoteFrame. +// +// While having a RemoteFrame implies the frame must be cross-origin, the +// opposite is not true: a LocalFrame can be same-origin or cross-origin. One +// additional complexity (which slightly violates the HTML standard): it is +// possible to have SecurityOrigin::canAccess() return true for a RemoteFrame's +// security origin; however, it is important to still deny access as if the +// frame were cross-origin. This is due to complexities in the process +// allocation model for renderer processes. See https://crbug.com/601629. +// +// ====== LocalWindowProxy/RemoteWindowProxy ====== +// Currently, the prototype chain for LocalWindowProxy and RemoteWindowProxy +// look the same: +// +// outer global proxy +// -- has prototype --> inner global object +// -- has prototype --> Window.prototype +// -- has prototype --> WindowProperties [1] +// -- has prototype --> EventTarget.prototype +// -- has prototype --> Object.prototype +// -- has prototype --> null +// +// [1] WindowProperties is the named properties object of the Window interface. +// +// There is work in progress to refactor RemoteWindowProxy to use remote v8 +// contexts, to reduce the overhead of remote frames. +// +// ====== References ====== +// https://wiki.mozilla.org/Gecko:SplitWindow +// https://whatwg.org/C/browsers.html#the-windowproxy-exotic-object class WindowProxy : public GarbageCollectedFinalized<WindowProxy> { public: virtual ~WindowProxy(); DECLARE_TRACE(); - v8::Local<v8::Context> contextIfInitialized() const { - return m_scriptState ? m_scriptState->context() : v8::Local<v8::Context>(); - } void initializeIfNeeded(); void clearForClose(); void clearForNavigation(); - v8::Local<v8::Object> globalIfNotDetached(); + CORE_EXPORT v8::Local<v8::Object> globalIfNotDetached(); v8::Local<v8::Object> releaseGlobal(); void setGlobal(v8::Local<v8::Object>); @@ -68,10 +141,6 @@ DOMWrapperWorld& world() { return *m_world; } protected: - // TODO(dcheng): Remove this friend declaration once LocalWindowProxyManager - // and ScriptController are merged. - friend class ScriptController; - // A valid transition is from ContextUninitialized to ContextInitialized, // and then ContextDetached. Other transitions are forbidden. enum class Lifecycle { @@ -85,24 +154,24 @@ virtual void initialize() = 0; enum GlobalDetachmentBehavior { DoNotDetachGlobal, DetachGlobal }; - virtual void disposeContext(GlobalDetachmentBehavior); - - // Associates the window wrapper and its prototype chain with the native - // DOMWindow object. Also does some more Window-specific initialization. - void setupWindowPrototypeChain(); + virtual void disposeContext(GlobalDetachmentBehavior) = 0; v8::Isolate* isolate() const { return m_isolate; } Frame* frame() const { return m_frame.get(); } - ScriptState* getScriptState() const { return m_scriptState.get(); } + +#if DCHECK_IS_ON() + void didAttachGlobalProxy() { m_isGlobalProxyAttached = true; } + void didDetachGlobalProxy() { m_isGlobalProxyAttached = false; } +#endif private: v8::Isolate* const m_isolate; const Member<Frame> m_frame; +#if DCHECK_IS_ON() + bool m_isGlobalProxyAttached = false; +#endif protected: - // TODO(dcheng): Move this to LocalWindowProxy once RemoteWindowProxy uses - // remote contexts. - RefPtr<ScriptState> m_scriptState; // TODO(dcheng): Consider making these private and using getters. const RefPtr<DOMWrapperWorld> m_world; ScopedPersistent<v8::Object> m_globalProxy;
diff --git a/third_party/WebKit/Source/core/css/CSSFontSelector.cpp b/third_party/WebKit/Source/core/css/CSSFontSelector.cpp index 815048f..eef8eb1 100644 --- a/third_party/WebKit/Source/core/css/CSSFontSelector.cpp +++ b/third_party/WebKit/Source/core/css/CSSFontSelector.cpp
@@ -152,15 +152,15 @@ face->willUseRange(fontDescription, rangeSet); } -bool CSSFontSelector::isPlatformFontAvailable( +bool CSSFontSelector::isPlatformFamilyMatchAvailable( const FontDescription& fontDescription, const AtomicString& passedFamily) { AtomicString family = familyNameFromSettings(m_genericFontFamilySettings, fontDescription, passedFamily); if (family.isEmpty()) family = passedFamily; - return FontCache::fontCache()->isPlatformFontAvailable(fontDescription, - family); + return FontCache::fontCache()->isPlatformFamilyMatchAvailable(fontDescription, + family); } void CSSFontSelector::updateGenericFontFamilySettings(Document& document) {
diff --git a/third_party/WebKit/Source/core/css/CSSFontSelector.h b/third_party/WebKit/Source/core/css/CSSFontSelector.h index 6a590fd8..efc427b 100644 --- a/third_party/WebKit/Source/core/css/CSSFontSelector.h +++ b/third_party/WebKit/Source/core/css/CSSFontSelector.h
@@ -60,8 +60,8 @@ void willUseRange(const FontDescription&, const AtomicString& familyName, const FontDataForRangeSet&) override; - bool isPlatformFontAvailable(const FontDescription&, - const AtomicString& family); + bool isPlatformFamilyMatchAvailable(const FontDescription&, + const AtomicString& family); void fontFaceInvalidated();
diff --git a/third_party/WebKit/Source/core/css/FontFace.cpp b/third_party/WebKit/Source/core/css/FontFace.cpp index 8aabfcb5..b9b5f639 100644 --- a/third_party/WebKit/Source/core/css/FontFace.cpp +++ b/third_party/WebKit/Source/core/css/FontFace.cpp
@@ -157,12 +157,12 @@ } FontFace::FontFace(ExecutionContext* context) - : ContextLifecycleObserver(context), m_status(Unloaded) {} + : ContextClient(context), m_status(Unloaded) {} FontFace::FontFace(ExecutionContext* context, const AtomicString& family, const FontFaceDescriptors& descriptors) - : ContextLifecycleObserver(context), m_family(family), m_status(Unloaded) { + : ContextClient(context), m_family(family), m_status(Unloaded) { Document* document = toDocument(context); setPropertyFromString(document, descriptors.style(), CSSPropertyFontStyle); setPropertyFromString(document, descriptors.weight(), CSSPropertyFontWeight); @@ -666,7 +666,7 @@ visitor->trace(m_loadedProperty); visitor->trace(m_cssFontFace); visitor->trace(m_callbacks); - ContextLifecycleObserver::trace(visitor); + ContextClient::trace(visitor); } bool FontFace::hadBlankText() const {
diff --git a/third_party/WebKit/Source/core/css/FontFace.h b/third_party/WebKit/Source/core/css/FontFace.h index a72fdb6..88e6850 100644 --- a/third_party/WebKit/Source/core/css/FontFace.h +++ b/third_party/WebKit/Source/core/css/FontFace.h
@@ -59,7 +59,7 @@ class CORE_EXPORT FontFace : public GarbageCollectedFinalized<FontFace>, public ScriptWrappable, public ActiveScriptWrappable<FontFace>, - public ContextLifecycleObserver { + public ContextClient { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(FontFace); WTF_MAKE_NONCOPYABLE(FontFace);
diff --git a/third_party/WebKit/Source/core/css/FontFaceSet.cpp b/third_party/WebKit/Source/core/css/FontFaceSet.cpp index 96ffcdc..7e06f57 100644 --- a/third_party/WebKit/Source/core/css/FontFaceSet.cpp +++ b/third_party/WebKit/Source/core/css/FontFaceSet.cpp
@@ -427,8 +427,8 @@ return true; for (const FontFamily* f = &font.getFontDescription().family(); f; f = f->next()) { - if (fontSelector->isPlatformFontAvailable(font.getFontDescription(), - f->family())) + if (fontSelector->isPlatformFamilyMatchAvailable(font.getFontDescription(), + f->family())) return true; } return false;
diff --git a/third_party/WebKit/Source/core/css/LocalFontFaceSource.cpp b/third_party/WebKit/Source/core/css/LocalFontFaceSource.cpp index 51bafcc3..44e71876 100644 --- a/third_party/WebKit/Source/core/css/LocalFontFaceSource.cpp +++ b/third_party/WebKit/Source/core/css/LocalFontFaceSource.cpp
@@ -13,16 +13,14 @@ bool LocalFontFaceSource::isLocalFontAvailable( const FontDescription& fontDescription) { - return FontCache::fontCache()->isPlatformFontAvailable(fontDescription, - m_fontName); + return FontCache::fontCache()->isPlatformFontUniqueNameMatchAvailable( + fontDescription, m_fontName); } PassRefPtr<SimpleFontData> LocalFontFaceSource::createFontData( const FontDescription& fontDescription) { - // We don't want to check alternate font family names here, so pass true as - // the checkingAlternateName parameter. RefPtr<SimpleFontData> fontData = FontCache::fontCache()->getFontData( - fontDescription, m_fontName, AlternateFontName::NoAlternate); + fontDescription, m_fontName, AlternateFontName::LocalUniqueFace); m_histograms.record(fontData.get()); return fontData.release(); }
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp index c706599c..a84be9c1 100644 --- a/third_party/WebKit/Source/core/editing/SelectionController.cpp +++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -784,9 +784,9 @@ const MouseEventWithHitTestResults& event) { // If we got the event back, that must mean it wasn't prevented, // so it's allowed to start a drag or selection if it wasn't in a scrollbar. - m_mouseDownMayStartSelect = - (canMouseDownStartSelect(event.innerNode()) || isLinkSelection(event)) && - !event.scrollbar(); + m_mouseDownMayStartSelect = (canMouseDownStartSelect(event.innerNode()) || + isSelectionOverLink(event)) && + !event.scrollbar(); m_mouseDownWasSingleClickInSelection = false; if (!selection().isAvailable()) { // "gesture-tap-frame-removed.html" reaches here. @@ -1079,7 +1079,7 @@ return m_frame->selection(); } -bool isLinkSelection(const MouseEventWithHitTestResults& event) { +bool isSelectionOverLink(const MouseEventWithHitTestResults& event) { return (event.event().modifiers() & WebInputEvent::Modifiers::AltKey) != 0 && event.isOverLink(); }
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.h b/third_party/WebKit/Source/core/editing/SelectionController.h index 69abbddc..3c300d4 100644 --- a/third_party/WebKit/Source/core/editing/SelectionController.h +++ b/third_party/WebKit/Source/core/editing/SelectionController.h
@@ -144,7 +144,7 @@ SelectionState m_selectionState; }; -bool isLinkSelection(const MouseEventWithHitTestResults&); +bool isSelectionOverLink(const MouseEventWithHitTestResults&); bool isExtendingSelection(const MouseEventWithHitTestResults&); } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp index 50de723..2afc55a 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -1747,6 +1747,39 @@ return honorEditingBoundaryAtOrAfter(next, c.deepEquivalent()); } +EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) { + DCHECK(range.isNotNull()); + const VisiblePosition& visibleEnd = + createVisiblePosition(range.endPosition()); + DCHECK(visibleEnd.isNotNull()); + const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); + // TODO(xiaochengh): |sentenceEnd < range.endPosition()| is possible, + // which would trigger a DCHECK in EphemeralRange's constructor if we return + // it directly. However, this shouldn't happen and needs to be fixed. + return EphemeralRange( + range.startPosition(), + sentenceEnd.isNotNull() && sentenceEnd > range.endPosition() + ? sentenceEnd + : range.endPosition()); +} + +EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange& range) { + DCHECK(range.isNotNull()); + const VisiblePosition& visibleStart = + createVisiblePosition(range.startPosition()); + DCHECK(visibleStart.isNotNull()); + const Position& sentenceStart = + startOfSentence(visibleStart).deepEquivalent(); + // TODO(xiaochengh): |sentenceStart > range.startPosition()| is possible, + // which would trigger a DCHECK in EphemeralRange's constructor if we return + // it directly. However, this shouldn't happen and needs to be fixed. + return expandEndToSentenceBoundary(EphemeralRange( + sentenceStart.isNotNull() && sentenceStart < range.startPosition() + ? sentenceStart + : range.startPosition(), + range.endPosition())); +} + static bool nodeIsUserSelectAll(const Node* node) { return node && node->layoutObject() && node->layoutObject()->style()->userSelect() == SELECT_ALL;
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.h b/third_party/WebKit/Source/core/editing/VisibleUnits.h index 42a0bafe..d53d38b 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.h +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.h
@@ -28,6 +28,7 @@ #include "core/CoreExport.h" #include "core/editing/EditingBoundary.h" +#include "core/editing/EphemeralRange.h" #include "core/editing/PositionWithAffinity.h" #include "core/editing/VisiblePosition.h" #include "platform/text/TextDirection.h" @@ -180,6 +181,8 @@ endOfSentence(const VisiblePositionInFlatTree&); VisiblePosition previousSentencePosition(const VisiblePosition&); VisiblePosition nextSentencePosition(const VisiblePosition&); +EphemeralRange expandEndToSentenceBoundary(const EphemeralRange&); +EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange&); // lines // TODO(yosin) Return values of |VisiblePosition| version of |startOfLine()|
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp index 4d83f7fa..25f60f1 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -80,40 +80,6 @@ return SpellChecker::isSpellCheckingEnabledAt(selection.start()); } -static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) { - DCHECK(range.isNotNull()); - const VisiblePosition& visibleEnd = - createVisiblePosition(range.endPosition()); - DCHECK(visibleEnd.isNotNull()); - const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); - // TODO(xiaochengh): |sentenceEnd < range.endPosition()| is possible, - // which would trigger a DCHECK in EphemeralRange's constructor if we return - // it directly. However, this shouldn't happen and needs to be fixed. - return EphemeralRange( - range.startPosition(), - sentenceEnd.isNotNull() && sentenceEnd > range.endPosition() - ? sentenceEnd - : range.endPosition()); -} - -static EphemeralRange expandRangeToSentenceBoundary( - const EphemeralRange& range) { - DCHECK(range.isNotNull()); - const VisiblePosition& visibleStart = - createVisiblePosition(range.startPosition()); - DCHECK(visibleStart.isNotNull()); - const Position& sentenceStart = - startOfSentence(visibleStart).deepEquivalent(); - // TODO(xiaochengh): |sentenceStart > range.startPosition()| is possible, - // which would trigger a DCHECK in EphemeralRange's constructor if we return - // it directly. However, this shouldn't happen and needs to be fixed. - return expandEndToSentenceBoundary(EphemeralRange( - sentenceStart.isNotNull() && sentenceStart < range.startPosition() - ? sentenceStart - : range.startPosition(), - range.endPosition())); -} - SelectionInDOMTree selectWord(const VisiblePosition& position) { // TODO(yosin): We should fix |startOfWord()| and |endOfWord()| not to return // null position.
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp index 600874c7..d38bd6f0 100644 --- a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp +++ b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
@@ -277,9 +277,7 @@ // and enable this DCHECK again. // DCHECK_EQ(mouseEvent.id, coalescedMouseEvent.id); - // TODO(crbug.com/684292): We need further investigation of why the - // following DCHECK fails. - // DCHECK_EQ(mouseEvent.pointerType, coalescedMouseEvent.pointerType); + DCHECK_EQ(mouseEvent.pointerType, coalescedMouseEvent.pointerType); PointerEventInit coalescedEventInit = pointerEventInit; updateMousePointerEventInit(coalescedMouseEvent, view, &coalescedEventInit);
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp index e18b4b81..b20a17e 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -381,7 +381,8 @@ WeakMediaElementSet& elements = *it->value; for (const auto& element : elements) { element->updateControlsVisibility(); - element->mediaControls()->onMediaControlsEnabledChange(); + if (element->mediaControls()) + element->mediaControls()->onMediaControlsEnabledChange(); } }
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp index 88afa39..7909e8d 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp
@@ -363,6 +363,22 @@ // The parser is unprepared to be told, and doesn't need to be. if (isExecutingScript() && pendingScript->resource()->wasCanceled()) { pendingScript->dispose(); + + if (pendingScript == parserBlockingScript()) { + m_parserBlockingScript = nullptr; + } else { + CHECK_EQ(pendingScript, m_scriptsToExecuteAfterParsing.first()); + + // TODO(hiroshige): Remove this CHECK() before going to beta. + // This is only to make clusterfuzz to find a test case that executes + // this code path. + CHECK(false); + + m_scriptsToExecuteAfterParsing.removeFirst(); + // TODO(hiroshige): executeScriptsWaitingForParsing() should be + // called later at the appropriate time. https://crbug.com/696775 + } + return; }
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp index e07154a..39d1f5e2 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.cpp +++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -978,10 +978,9 @@ WebInputEventResult eventResult = updatePointerTargetAndDispatchEvents( EventTypeNames::mouseup, mev.innerNode(), mev.canvasRegionId(), - mev.event(), Vector<WebMouseEvent>()); - - WebInputEventResult clickEventResult = - m_mouseEventManager->dispatchMouseClickIfNeeded(mev); + mev.event(), Vector<WebMouseEvent>(), + !(selectionController().hasExtendedSelection() && + isSelectionOverLink(mev))); m_scrollManager->clearResizeScrollableArea(false); @@ -991,7 +990,7 @@ m_mouseEventManager->invalidateClick(); - return EventHandlingUtil::mergeEventResult(clickEventResult, eventResult); + return eventResult; } static bool targetIsFrame(Node* target, LocalFrame*& frame) { @@ -1266,14 +1265,15 @@ Node* targetNode, const String& canvasRegionId, const WebMouseEvent& mouseEvent, - const Vector<WebMouseEvent>& coalescedEvents) { + const Vector<WebMouseEvent>& coalescedEvents, + bool selectionOverLink) { ASSERT(mouseEventType == EventTypeNames::mousedown || mouseEventType == EventTypeNames::mousemove || mouseEventType == EventTypeNames::mouseup); const auto& eventResult = m_pointerEventManager->sendMousePointerEvent( updateMouseEventTargetNode(targetNode), canvasRegionId, mouseEventType, - mouseEvent, coalescedEvents); + mouseEvent, coalescedEvents, selectionOverLink); return eventResult; }
diff --git a/third_party/WebKit/Source/core/input/EventHandler.h b/third_party/WebKit/Source/core/input/EventHandler.h index 813ea35..e3c9ce7 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.h +++ b/third_party/WebKit/Source/core/input/EventHandler.h
@@ -305,7 +305,8 @@ Node* target, const String& canvasRegionId, const WebMouseEvent&, - const Vector<WebMouseEvent>& coalescedEvents); + const Vector<WebMouseEvent>& coalescedEvents, + bool selectionOverLink = false); // Clears drag target and related states. It is called when drag is done or // canceled.
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.cpp b/third_party/WebKit/Source/core/input/MouseEventManager.cpp index 524f298..d33f5a8 100644 --- a/third_party/WebKit/Source/core/input/MouseEventManager.cpp +++ b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
@@ -230,50 +230,50 @@ } WebInputEventResult MouseEventManager::dispatchMouseClickIfNeeded( - const MouseEventWithHitTestResults& mev) { + Node* target, + const WebMouseEvent& mouseEvent, + const String& canvasRegionId) { // We only prevent click event when the click may cause contextmenu to popup. // However, we always send auxclick. bool contextMenuEvent = !RuntimeEnabledFeatures::auxclickEnabled() && - mev.event().button == WebPointerProperties::Button::Right; + mouseEvent.button == WebPointerProperties::Button::Right; #if OS(MACOSX) // FIXME: The Mac port achieves the same behavior by checking whether the // context menu is currently open in WebPage::mouseEvent(). Consider merging // the implementations. - if (mev.event().button == WebPointerProperties::Button::Left && - mev.event().modifiers() & WebInputEvent::Modifiers::ControlKey) + if (mouseEvent.button == WebPointerProperties::Button::Left && + mouseEvent.modifiers() & WebInputEvent::Modifiers::ControlKey) contextMenuEvent = true; #endif WebInputEventResult clickEventResult = WebInputEventResult::NotHandled; - const bool shouldDispatchClickEvent = - m_clickCount > 0 && !contextMenuEvent && mev.innerNode() && m_clickNode && - mev.innerNode()->canParticipateInFlatTree() && - m_clickNode->canParticipateInFlatTree() && - !(m_frame->eventHandler().selectionController().hasExtendedSelection() && - isLinkSelection(mev)); + const bool shouldDispatchClickEvent = m_clickCount > 0 && !contextMenuEvent && + target && m_clickNode && + target->canParticipateInFlatTree() && + m_clickNode->canParticipateInFlatTree(); if (shouldDispatchClickEvent) { Node* clickTargetNode = nullptr; // Updates distribution because a 'mouseup' event listener can make the // tree dirty at dispatchMouseEvent() invocation above. // Unless distribution is updated, commonAncestor would hit ASSERT. - if (m_clickNode == mev.innerNode()) { + if (m_clickNode == target) { clickTargetNode = m_clickNode; clickTargetNode->updateDistribution(); - } else if (m_clickNode->document() == mev.innerNode()->document()) { + } else if (m_clickNode->document() == target->document()) { m_clickNode->updateDistribution(); - mev.innerNode()->updateDistribution(); - clickTargetNode = mev.innerNode()->commonAncestor( + target->updateDistribution(); + clickTargetNode = target->commonAncestor( *m_clickNode, EventHandlingUtil::parentForClickEvent); } if (clickTargetNode) { clickEventResult = dispatchMouseEvent( clickTargetNode, !RuntimeEnabledFeatures::auxclickEnabled() || - (mev.event().button == WebPointerProperties::Button::Left) + (mouseEvent.button == WebPointerProperties::Button::Left) ? EventTypeNames::click : EventTypeNames::auxclick, - mev.event(), mev.canvasRegionId(), nullptr); + mouseEvent, canvasRegionId, nullptr); } } return clickEventResult; @@ -573,8 +573,8 @@ bool singleClick = event.event().clickCount <= 1; - m_mouseDownMayStartDrag = - singleClick && !isLinkSelection(event) && !isExtendingSelection(event); + m_mouseDownMayStartDrag = singleClick && !isSelectionOverLink(event) && + !isExtendingSelection(event); m_frame->eventHandler().selectionController().handleMousePressEvent(event);
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.h b/third_party/WebKit/Source/core/input/MouseEventManager.h index f144769f..87dfb19 100644 --- a/third_party/WebKit/Source/core/input/MouseEventManager.h +++ b/third_party/WebKit/Source/core/input/MouseEventManager.h
@@ -56,8 +56,9 @@ const AtomicString& eventType, const WebMouseEvent&); - WebInputEventResult dispatchMouseClickIfNeeded( - const MouseEventWithHitTestResults&); + WebInputEventResult dispatchMouseClickIfNeeded(Node* target, + const WebMouseEvent&, + const String& canvasRegionId); WebInputEventResult dispatchDragSrcEvent(const AtomicString& eventType, const WebMouseEvent&);
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.cpp b/third_party/WebKit/Source/core/input/PointerEventManager.cpp index f0fca95..6e62a16 100644 --- a/third_party/WebKit/Source/core/input/PointerEventManager.cpp +++ b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
@@ -447,7 +447,8 @@ const String& canvasRegionId, const AtomicString& mouseEventType, const WebMouseEvent& mouseEvent, - const Vector<WebMouseEvent>& coalescedEvents) { + const Vector<WebMouseEvent>& coalescedEvents, + bool selectionOverLink) { PointerEvent* pointerEvent = m_pointerEventFactory.create(mouseEventType, mouseEvent, coalescedEvents, m_frame->document()->domWindow()); @@ -500,6 +501,14 @@ result, m_mouseEventManager->dispatchMouseEvent( mouseTarget, mouseEventType, mouseEvent, canvasRegionId, nullptr)); + + if (selectionOverLink && mouseTarget && + mouseEventType == EventTypeNames::mouseup) { + WebInputEventResult clickEventResult = + m_mouseEventManager->dispatchMouseClickIfNeeded( + mouseTarget->toNode(), mouseEvent, canvasRegionId); + result = EventHandlingUtil::mergeEventResult(clickEventResult, result); + } } if (pointerEvent->type() == EventTypeNames::pointerup ||
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.h b/third_party/WebKit/Source/core/input/PointerEventManager.h index bc24fe9..1ee3acc 100644 --- a/third_party/WebKit/Source/core/input/PointerEventManager.h +++ b/third_party/WebKit/Source/core/input/PointerEventManager.h
@@ -39,7 +39,8 @@ const String& canvasRegionId, const AtomicString& type, const WebMouseEvent&, - const Vector<WebMouseEvent>& coalescedEvents); + const Vector<WebMouseEvent>& coalescedEvents, + bool selectionOverLink); WebInputEventResult handleTouchEvents( const WebTouchEvent&,
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp index 53831b7..eeec1a0 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -84,7 +84,7 @@ #include "core/svg/SVGElement.h" #include "platform/fonts/Font.h" #include "platform/fonts/FontCache.h" -#include "platform/fonts/GlyphBuffer.h" +#include "platform/fonts/shaping/CachingWordShaper.h" #include "platform/text/TextRun.h" #include "wtf/CurrentTime.h" #include "wtf/text/CString.h" @@ -1136,16 +1136,15 @@ const ComputedStyle& style = layoutText->styleRef(box->isFirstLineStyle()); const Font& font = style.font(); TextRun run = box->constructTextRunForInspector(style); - TextRunPaintInfo paintInfo(run); - GlyphBuffer glyphBuffer; - font.buildGlyphBuffer(paintInfo, glyphBuffer); - for (unsigned i = 0; i < glyphBuffer.size(); ++i) { - const SimpleFontData* simpleFontData = glyphBuffer.fontDataAt(i); + CachingWordShaper shaper(font); + for (const auto& runFontData : shaper.runFontData(run)) { + const auto* simpleFontData = runFontData.m_fontData; String familyName = simpleFontData->platformData().fontFamilyName(); if (familyName.isNull()) familyName = ""; fontStats->add( - std::make_pair(simpleFontData->isCustomFont() ? 1 : 0, familyName)); + std::make_pair(simpleFontData->isCustomFont() ? 1 : 0, familyName), + runFontData.m_glyphCount); } } }
diff --git a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp index 750fdca..4cd27f84 100644 --- a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp
@@ -150,7 +150,7 @@ getBluetoothDeviceRepresentingDevice(std::move(device), resolver); resolver->resolve(bluetoothDevice); } else { - resolver->reject(BluetoothError::take(resolver, result)); + resolver->reject(BluetoothError::createDOMException(result)); } }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp index 383649d..bae9bb8c 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp
@@ -9,15 +9,41 @@ namespace blink { -DOMException* BluetoothError::take(ScriptPromiseResolver*, - mojom::blink::WebBluetoothResult error) { +// static +DOMException* BluetoothError::createDOMException( + BluetoothErrorCode error, + const String& detailedMessage) { + switch (error) { + case BluetoothErrorCode::InvalidService: + case BluetoothErrorCode::InvalidCharacteristic: + case BluetoothErrorCode::InvalidDescriptor: + return DOMException::create(InvalidStateError, detailedMessage); + case BluetoothErrorCode::ServiceNotFound: + case BluetoothErrorCode::CharacteristicNotFound: + case BluetoothErrorCode::DescriptorNotFound: + return DOMException::create(NotFoundError, detailedMessage); + } + NOTREACHED(); + return DOMException::create(UnknownError); +} + +// static +DOMException* BluetoothError::createDOMException( + mojom::blink::WebBluetoothResult error) { switch (error) { case mojom::blink::WebBluetoothResult::SUCCESS: - ASSERT_NOT_REACHED(); + case mojom::blink::WebBluetoothResult::SERVICE_NOT_FOUND: + case mojom::blink::WebBluetoothResult::CHARACTERISTIC_NOT_FOUND: + case mojom::blink::WebBluetoothResult::DESCRIPTOR_NOT_FOUND: + // The above result codes are not expected here. SUCCESS is not + // an error and the others have a detailed message and are + // expected to be redirected to the switch above that handles + // BluetoothErrorCode. + NOTREACHED(); return DOMException::create(UnknownError); #define MAP_ERROR(enumeration, name, message) \ case mojom::blink::WebBluetoothResult::enumeration: \ - return DOMException::create(name, message) + return DOMException::create(name, message); // InvalidModificationErrors: MAP_ERROR(GATT_INVALID_ATTRIBUTE_LENGTH, InvalidModificationError, @@ -68,6 +94,17 @@ "GATT operation already in progress."); MAP_ERROR(UNTRANSLATED_CONNECT_ERROR_CODE, NetworkError, "Unknown ConnectErrorCode."); + MAP_ERROR(GATT_SERVER_NOT_CONNECTED, NetworkError, + "GATT Server is disconnected. Cannot perform GATT operations."); + MAP_ERROR(GATT_SERVER_DISCONNECTED, NetworkError, + "GATT Server disconnected while performing a GATT operation."); + MAP_ERROR(GATT_SERVER_DISCONNECTED_WHILE_RETRIEVING_CHARACTERISTICS, + NetworkError, + "GATT Server disconnected while retrieving characteristics."); + MAP_ERROR( + GATT_SERVER_NOT_CONNECTED_CANNOT_RETRIEVE_CHARACTERISTICS, + NetworkError, + "GATT Server is disconnected. Cannot retrieve characteristics."); // NotFoundErrors: MAP_ERROR(WEB_BLUETOOTH_NOT_SUPPORTED, NotFoundError, @@ -86,16 +123,10 @@ MAP_ERROR( CHOOSER_NOT_SHOWN_USER_DENIED_PERMISSION_TO_SCAN, NotFoundError, "User denied the browser permission to scan for Bluetooth devices."); - MAP_ERROR(SERVICE_NOT_FOUND, NotFoundError, - "No Services with specified UUID found in Device."); MAP_ERROR(NO_SERVICES_FOUND, NotFoundError, "No Services found in device."); - MAP_ERROR(CHARACTERISTIC_NOT_FOUND, NotFoundError, - "No Characteristics with specified UUID found in Service."); MAP_ERROR(NO_CHARACTERISTICS_FOUND, NotFoundError, "No Characteristics found in service."); - MAP_ERROR(DESCRIPTOR_NOT_FOUND, NotFoundError, - "No Descriptors with specified UUID found in Characteristic."); MAP_ERROR(NO_DESCRIPTORS_FOUND, NotFoundError, "No Descriptors found in Characteristic."); MAP_ERROR(BLUETOOTH_LOW_ENERGY_NOT_AVAILABLE, NotFoundError, @@ -140,13 +171,11 @@ "UUID. https://goo.gl/4NeimX"); MAP_ERROR(REQUEST_DEVICE_FROM_CROSS_ORIGIN_IFRAME, SecurityError, "requestDevice() called from cross-origin iframe."); - MAP_ERROR(REQUEST_DEVICE_WITHOUT_FRAME, SecurityError, - "No window to show the requestDevice() dialog."); #undef MAP_ERROR } - ASSERT_NOT_REACHED(); + NOTREACHED(); return DOMException::create(UnknownError); }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.h index c9374283..8e98950 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.h
@@ -11,8 +11,17 @@ namespace blink { +// These error codes requires detailed error messages. +enum class BluetoothErrorCode { + InvalidService, + InvalidCharacteristic, + InvalidDescriptor, + ServiceNotFound, + CharacteristicNotFound, + DescriptorNotFound +}; + class DOMException; -class ScriptPromiseResolver; // BluetoothError is used with CallbackPromiseAdapter to receive // WebBluetoothResult responses. See CallbackPromiseAdapter class comments. @@ -20,9 +29,11 @@ STATIC_ONLY(BluetoothError); public: - // Interface required by CallbackPromiseAdapter: - static DOMException* take(ScriptPromiseResolver*, - mojom::blink::WebBluetoothResult); + static DOMException* createDOMException(BluetoothErrorCode, + const String& detailedMessage); + + static DOMException* createDOMException( + mojom::blink::WebBluetoothResult error); }; } // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp index c462463ac..0088df16 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp
@@ -6,6 +6,7 @@ #include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptPromiseResolver.h" +#include "core/dom/DOMException.h" #include "core/events/Event.h" #include "core/inspector/ConsoleMessage.h" #include "modules/bluetooth/Bluetooth.h" @@ -105,8 +106,8 @@ // If the device is disconnected, reject. if (!getGatt()->RemoveFromActiveAlgorithms(resolver)) { - resolver->reject(BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerDisconnected)); + resolver->reject(BluetoothError::createDOMException( + blink::mojom::WebBluetoothResult::GATT_SERVER_DISCONNECTED)); return; } @@ -117,7 +118,7 @@ setValue(domDataView); resolver->resolve(domDataView); } else { - resolver->reject(BluetoothError::take(resolver, result)); + resolver->reject(BluetoothError::createDOMException(result)); } } @@ -126,16 +127,14 @@ if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerNotConnected)); + BluetoothError::createDOMException( + blink::mojom::WebBluetoothResult::GATT_SERVER_NOT_CONNECTED)); } if (!getGatt()->device()->isValidCharacteristic( m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( - scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kInvalidCharacteristic)); + scriptState, createInvalidCharacteristicError()); } ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); @@ -162,8 +161,8 @@ // If the device is disconnected, reject. if (!getGatt()->RemoveFromActiveAlgorithms(resolver)) { - resolver->reject(BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerDisconnected)); + resolver->reject(BluetoothError::createDOMException( + blink::mojom::WebBluetoothResult::GATT_SERVER_DISCONNECTED)); return; } @@ -171,7 +170,7 @@ setValue(BluetoothRemoteGATTUtils::ConvertWTFVectorToDataView(value)); resolver->resolve(); } else { - resolver->reject(BluetoothError::take(resolver, result)); + resolver->reject(BluetoothError::createDOMException(result)); } } @@ -181,16 +180,14 @@ if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerNotConnected)); + BluetoothError::createDOMException( + blink::mojom::WebBluetoothResult::GATT_SERVER_NOT_CONNECTED)); } if (!getGatt()->device()->isValidCharacteristic( m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( - scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kInvalidCharacteristic)); + scriptState, createInvalidCharacteristicError()); } // Partial implementation of writeValue algorithm: @@ -231,15 +228,15 @@ // If the device is disconnected, reject. if (!getGatt()->RemoveFromActiveAlgorithms(resolver)) { - resolver->reject(BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerDisconnected)); + resolver->reject(BluetoothError::createDOMException( + blink::mojom::WebBluetoothResult::GATT_SERVER_DISCONNECTED)); return; } if (result == mojom::blink::WebBluetoothResult::SUCCESS) { resolver->resolve(this); } else { - resolver->reject(BluetoothError::take(resolver, result)); + resolver->reject(BluetoothError::createDOMException(result)); } } @@ -248,16 +245,14 @@ if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerNotConnected)); + BluetoothError::createDOMException( + blink::mojom::WebBluetoothResult::GATT_SERVER_NOT_CONNECTED)); } if (!getGatt()->device()->isValidCharacteristic( m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( - scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kInvalidCharacteristic)); + scriptState, createInvalidCharacteristicError()); } ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); @@ -279,16 +274,14 @@ if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerNotConnected)); + BluetoothError::createDOMException( + blink::mojom::WebBluetoothResult::GATT_SERVER_NOT_CONNECTED)); } if (!getGatt()->device()->isValidCharacteristic( m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( - scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kInvalidCharacteristic)); + scriptState, createInvalidCharacteristicError()); } ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); @@ -347,16 +340,14 @@ if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerNotConnected)); + BluetoothError::createDOMException( + blink::mojom::WebBluetoothResult::GATT_SERVER_NOT_CONNECTED)); } if (!getGatt()->device()->isValidCharacteristic( m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( - scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kInvalidCharacteristic)); + scriptState, createInvalidCharacteristicError()); } ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); @@ -366,10 +357,10 @@ mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); service->RemoteCharacteristicGetDescriptors( m_characteristic->instance_id, quantity, descriptorsUUID, - convertToBaseCallback( - WTF::bind(&BluetoothRemoteGATTCharacteristic::GetDescriptorsCallback, - wrapPersistent(this), m_characteristic->instance_id, - quantity, wrapPersistent(resolver)))); + convertToBaseCallback(WTF::bind( + &BluetoothRemoteGATTCharacteristic::GetDescriptorsCallback, + wrapPersistent(this), descriptorsUUID, m_characteristic->instance_id, + quantity, wrapPersistent(resolver)))); return promise; } @@ -377,6 +368,7 @@ // Callback that allows us to resolve the promise with a single descriptor // or with a vector owning the descriptors. void BluetoothRemoteGATTCharacteristic::GetDescriptorsCallback( + const String& requestedDescriptorUUID, const String& characteristicInstanceId, mojom::blink::WebBluetoothGATTQueryQuantity quantity, ScriptPromiseResolver* resolver, @@ -389,8 +381,8 @@ // If the device is disconnected, reject. if (!service()->device()->gatt()->RemoveFromActiveAlgorithms(resolver)) { - resolver->reject(BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerDisconnected)); + resolver->reject(BluetoothError::createDOMException( + blink::mojom::WebBluetoothResult::GATT_SERVER_DISCONNECTED)); return; } @@ -414,10 +406,26 @@ } resolver->resolve(gattDescriptors); } else { - resolver->reject(BluetoothError::take(resolver, result)); + if (result == mojom::blink::WebBluetoothResult::DESCRIPTOR_NOT_FOUND) { + resolver->reject(BluetoothError::createDOMException( + BluetoothErrorCode::DescriptorNotFound, + "No Descriptors matching UUID " + requestedDescriptorUUID + + " found in Characteristic with UUID " + uuid() + ".")); + } else { + resolver->reject(BluetoothError::createDOMException(result)); + } } } +DOMException* +BluetoothRemoteGATTCharacteristic::createInvalidCharacteristicError() { + return BluetoothError::createDOMException( + BluetoothErrorCode::InvalidCharacteristic, + "Characteristic with UUID " + uuid() + + " is no longer valid. Remember to retrieve the characteristic again " + "after reconnecting."); +} + DEFINE_TRACE(BluetoothRemoteGATTCharacteristic) { visitor->trace(m_service); visitor->trace(m_properties);
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h index c4aaabd..ca7efb1 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h
@@ -118,6 +118,7 @@ const String& descriptorUUID = String()); void GetDescriptorsCallback( + const String& requestedDescriptorUUID, const String& characteristicInstanceId, mojom::blink::WebBluetoothGATTQueryQuantity, ScriptPromiseResolver*, @@ -125,6 +126,8 @@ Optional<Vector<mojom::blink::WebBluetoothRemoteGATTDescriptorPtr>> descriptors); + DOMException* createInvalidCharacteristicError(); + mojom::blink::WebBluetoothRemoteGATTCharacteristicPtr m_characteristic; Member<BluetoothRemoteGATTService> m_service; bool m_stopped;
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp index 9bb73d6..ad14abb 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp
@@ -38,8 +38,8 @@ // If the device is disconnected, reject. if (!getGatt()->RemoveFromActiveAlgorithms(resolver)) { - resolver->reject(BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerDisconnected)); + resolver->reject(BluetoothError::createDOMException( + mojom::blink::WebBluetoothResult::GATT_SERVER_DISCONNECTED)); return; } @@ -50,7 +50,7 @@ m_value = domDataView; resolver->resolve(domDataView); } else { - resolver->reject(BluetoothError::take(resolver, result)); + resolver->reject(BluetoothError::createDOMException(result)); } } @@ -59,15 +59,13 @@ if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerNotConnected)); + BluetoothError::createDOMException( + mojom::blink::WebBluetoothResult::GATT_SERVER_NOT_CONNECTED)); } if (!getGatt()->device()->isValidDescriptor(m_descriptor->instance_id)) { return ScriptPromise::rejectWithDOMException( - scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kInvalidDescriptor)); + scriptState, createInvalidDescriptorError()); } ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); @@ -93,8 +91,8 @@ // If the resolver is not in the set of ActiveAlgorithms then the frame // disconnected so we reject. if (!getGatt()->RemoveFromActiveAlgorithms(resolver)) { - resolver->reject(BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerDisconnected)); + resolver->reject(BluetoothError::createDOMException( + mojom::blink::WebBluetoothResult::GATT_SERVER_DISCONNECTED)); return; } @@ -102,7 +100,7 @@ m_value = BluetoothRemoteGATTUtils::ConvertWTFVectorToDataView(value); resolver->resolve(); } else { - resolver->reject(BluetoothError::take(resolver, result)); + resolver->reject(BluetoothError::createDOMException(result)); } } @@ -112,15 +110,13 @@ if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kGATTServerNotConnected)); + BluetoothError::createDOMException( + mojom::blink::WebBluetoothResult::GATT_SERVER_NOT_CONNECTED)); } if (!getGatt()->device()->isValidDescriptor(m_descriptor->instance_id)) { return ScriptPromise::rejectWithDOMException( - scriptState, - BluetoothRemoteGATTUtils::CreateDOMException( - BluetoothRemoteGATTUtils::ExceptionType::kInvalidDescriptor)); + scriptState, createInvalidDescriptorError()); } // Partial implementation of writeValue algorithm: @@ -151,6 +147,14 @@ return promise; } +DOMException* BluetoothRemoteGATTDescriptor::createInvalidDescriptorError() { + return BluetoothError::createDOMException( + BluetoothErrorCode::InvalidDescriptor, + "Descriptor with UUID " + uuid() + + " is no longer valid. Remember to retrieve the Descriptor again " + "after reconnecting."); +} + DEFINE_TRACE(BluetoothRemoteGATTDescriptor) { visitor->trace(m_characteristic); visitor->trace(m_value);
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.h index 175db616..289fefd 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.h
@@ -67,6 +67,8 @@ const Vector<uint8_t>&, mojom::blink::WebBluetoothResult); + DOMException* createInvalidDescriptorError(); + mojom::blink::WebBluetoothRemoteGATTDescriptorPtr m_descriptor; Member<BluetoothRemoteGATTCharacteristic> m_characteristic; Member<DOMDataView> m_value;
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.cpp index 8f52294..8b2185a 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.cpp
@@ -67,7 +67,7 @@ setConnected(true); resolver->resolve(this); } else { - resolver->reject(BluetoothError::take(resolver, result)); + resolver->reject(BluetoothError::createDOMException(result)); } } @@ -96,6 +96,7 @@ // Callback that allows us to resolve the promise with a single service or // with a vector owning the services. void BluetoothRemoteGATTServer::GetPrimaryServicesCallback( + const String& requestedServiceUUID, mojom::blink::WebBluetoothGATTQueryQuantity quantity, ScriptPromiseResolver* resolver, mojom::blink::WebBluetoothResult result, @@ -131,7 +132,14 @@ } resolver->resolve(gattServices); } else { - resolver->reject(BluetoothError::take(resolver, result)); + if (result == mojom::blink::WebBluetoothResult::SERVICE_NOT_FOUND) { + resolver->reject(BluetoothError::createDOMException( + BluetoothErrorCode::ServiceNotFound, "No Services matching UUID " + + requestedServiceUUID + + " found in Device.")); + } else { + resolver->reject(BluetoothError::createDOMException(result)); + } } } @@ -187,7 +195,8 @@ device()->id(), quantity, servicesUUID, convertToBaseCallback( WTF::bind(&BluetoothRemoteGATTServer::GetPrimaryServicesCallback, - wrapPersistent(this), quantity, wrapPersistent(resolver)))); + wrapPersistent(this), servicesUUID, quantity, + wrapPersistent(resolver)))); return promise; }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h index 1e33026c..7379ad6 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h
@@ -72,6 +72,7 @@ void ConnectCallback(ScriptPromiseResolver*, mojom::blink::WebBluetoothResult); void GetPrimaryServicesCallback( + const String& requestedServiceUUID, mojom::blink::WebBluetoothGATTQueryQuantity, ScriptPromiseResolver*, mojom::blink::WebBluetoothResult,
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.cpp index cfcd631..fcdf5d3 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.cpp
@@ -18,18 +18,6 @@ namespace blink { -namespace { - -const char kGATTServerDisconnected[] = - "GATT Server disconnected while retrieving characteristics."; -const char kGATTServerNotConnected[] = - "GATT Server is disconnected. Cannot retrieve characteristics."; -const char kInvalidService[] = - "Service is no longer valid. Remember to retrieve the service again after " - "reconnecting."; - -} // namespace - BluetoothRemoteGATTService::BluetoothRemoteGATTService( mojom::blink::WebBluetoothRemoteGATTServicePtr service, bool isPrimary, @@ -48,6 +36,7 @@ // or with a vector owning the characteristics. void BluetoothRemoteGATTService::GetCharacteristicsCallback( const String& serviceInstanceId, + const String& requestedCharacteristicUUID, mojom::blink::WebBluetoothGATTQueryQuantity quantity, ScriptPromiseResolver* resolver, mojom::blink::WebBluetoothResult result, @@ -59,8 +48,9 @@ // If the device is disconnected, reject. if (!device()->gatt()->RemoveFromActiveAlgorithms(resolver)) { - resolver->reject( - DOMException::create(NetworkError, kGATTServerDisconnected)); + resolver->reject(BluetoothError::createDOMException( + mojom::blink::WebBluetoothResult:: + GATT_SERVER_DISCONNECTED_WHILE_RETRIEVING_CHARACTERISTICS)); return; } @@ -85,7 +75,14 @@ } resolver->resolve(gattCharacteristics); } else { - resolver->reject(BluetoothError::take(resolver, result)); + if (result == mojom::blink::WebBluetoothResult::CHARACTERISTIC_NOT_FOUND) { + resolver->reject(BluetoothError::createDOMException( + BluetoothErrorCode::CharacteristicNotFound, + "No Characteristics matching UUID " + requestedCharacteristicUUID + + " found in Service with UUID " + uuid() + ".")); + } else { + resolver->reject(BluetoothError::createDOMException(result)); + } } } @@ -131,12 +128,18 @@ if (!device()->gatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, - DOMException::create(NetworkError, kGATTServerNotConnected)); + BluetoothError::createDOMException( + mojom::blink::WebBluetoothResult:: + GATT_SERVER_NOT_CONNECTED_CANNOT_RETRIEVE_CHARACTERISTICS)); } if (!device()->isValidService(m_service->instance_id)) { return ScriptPromise::rejectWithDOMException( - scriptState, DOMException::create(InvalidStateError, kInvalidService)); + scriptState, BluetoothError::createDOMException( + BluetoothErrorCode::InvalidService, + "Service with UUID " + m_service->uuid + + " is no longer valid. Remember to retrieve " + "the service again after reconnecting.")); } ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); @@ -148,8 +151,8 @@ m_service->instance_id, quantity, characteristicsUUID, convertToBaseCallback( WTF::bind(&BluetoothRemoteGATTService::GetCharacteristicsCallback, - wrapPersistent(this), m_service->instance_id, quantity, - wrapPersistent(resolver)))); + wrapPersistent(this), m_service->instance_id, + characteristicsUUID, quantity, wrapPersistent(resolver)))); return promise; }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h index 2884d1f..b3a8fcc9 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h
@@ -56,6 +56,7 @@ private: void GetCharacteristicsCallback( const String& serviceInstanceId, + const String& requestedCharacteristicUUID, mojom::blink::WebBluetoothGATTQueryQuantity, ScriptPromiseResolver*, mojom::blink::WebBluetoothResult,
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTUtils.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTUtils.cpp index f417871..6f00640 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTUtils.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTUtils.cpp
@@ -16,35 +16,4 @@ return DOMDataView::create(domBuffer, 0, wtfVector.size()); } -// static -DOMException* BluetoothRemoteGATTUtils::CreateDOMException(ExceptionType type) { - switch (type) { - case ExceptionType::kGATTServerDisconnected: - return DOMException::create( - NetworkError, - "GATT Server disconnected while performing a GATT operation."); - - case ExceptionType::kGATTServerNotConnected: - return DOMException::create( - NetworkError, - "GATT Server is disconnected. Cannot perform GATT operations."); - - case ExceptionType::kInvalidCharacteristic: - return DOMException::create( - InvalidStateError, - "Characteristic is no longer valid. Remember to retrieve the " - "characteristic again after reconnecting."); - - case ExceptionType::kInvalidDescriptor: - return DOMException::create( - InvalidStateError, - "Descriptor is no longer valid. Remember to retrieve the " - "Descriptor again after reconnecting."); - - default: - NOTREACHED(); - return nullptr; - } -} - } // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTUtils.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTUtils.h index de176f3ba..03c365e 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTUtils.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTUtils.h
@@ -6,7 +6,6 @@ #define BluetoothRemoteGATTUtils_h #include "core/dom/DOMDataView.h" -#include "core/dom/DOMException.h" #include "wtf/Vector.h" namespace blink { @@ -14,15 +13,6 @@ class BluetoothRemoteGATTUtils final { public: static DOMDataView* ConvertWTFVectorToDataView(const WTF::Vector<uint8_t>&); - - enum ExceptionType { - kGATTServerDisconnected, - kGATTServerNotConnected, - kInvalidCharacteristic, - kInvalidDescriptor - }; - - static DOMException* CreateDOMException(ExceptionType); }; } // namespace blink
diff --git a/third_party/WebKit/Source/modules/filesystem/DOMFileSystem.cpp b/third_party/WebKit/Source/modules/filesystem/DOMFileSystem.cpp index e894cd2..a013f6b 100644 --- a/third_party/WebKit/Source/modules/filesystem/DOMFileSystem.cpp +++ b/third_party/WebKit/Source/modules/filesystem/DOMFileSystem.cpp
@@ -108,7 +108,7 @@ FileSystemType type, const KURL& rootURL) : DOMFileSystemBase(context, name, type, rootURL), - ContextLifecycleObserver(context), + ContextClient(context), m_numberOfPendingCallbacks(0), m_rootEntry(DirectoryEntry::create(this, DOMFilePath::root)) {} @@ -217,9 +217,9 @@ } DEFINE_TRACE(DOMFileSystem) { - DOMFileSystemBase::trace(visitor); - ContextLifecycleObserver::trace(visitor); visitor->trace(m_rootEntry); + DOMFileSystemBase::trace(visitor); + ContextClient::trace(visitor); } } // namespace blink
diff --git a/third_party/WebKit/Source/modules/filesystem/DOMFileSystem.h b/third_party/WebKit/Source/modules/filesystem/DOMFileSystem.h index 60170324..f47fb4bf 100644 --- a/third_party/WebKit/Source/modules/filesystem/DOMFileSystem.h +++ b/third_party/WebKit/Source/modules/filesystem/DOMFileSystem.h
@@ -55,7 +55,7 @@ : public DOMFileSystemBase, public ScriptWrappable, public ActiveScriptWrappable<DOMFileSystem>, - public ContextLifecycleObserver { + public ContextClient { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(DOMFileSystem);
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp index 22cc3db..f9ce3ff1 100644 --- a/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp +++ b/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp
@@ -108,7 +108,7 @@ int64_t id, const HashSet<String>& scope, IDBDatabase* db) - : ContextLifecycleObserver(executionContext), + : ContextClient(executionContext), m_id(id), m_database(db), m_mode(WebIDBTransactionModeReadOnly), @@ -125,7 +125,7 @@ const HashSet<String>& scope, WebIDBTransactionMode mode, IDBDatabase* db) - : ContextLifecycleObserver(scriptState->getExecutionContext()), + : ContextClient(scriptState->getExecutionContext()), m_id(id), m_database(db), m_mode(mode), @@ -149,7 +149,7 @@ IDBDatabase* db, IDBOpenDBRequest* openDBRequest, const IDBDatabaseMetadata& oldMetadata) - : ContextLifecycleObserver(executionContext), + : ContextClient(executionContext), m_id(id), m_database(db), m_openDBRequest(openDBRequest), @@ -177,7 +177,7 @@ visitor->trace(m_oldStoreMetadata); visitor->trace(m_deletedIndexes); EventTargetWithInlineData::trace(visitor); - ContextLifecycleObserver::trace(visitor); + ContextClient::trace(visitor); } void IDBTransaction::setError(DOMException* error) { @@ -479,7 +479,7 @@ } ExecutionContext* IDBTransaction::getExecutionContext() const { - return ContextLifecycleObserver::getExecutionContext(); + return ContextClient::getExecutionContext(); } DispatchEventResult IDBTransaction::dispatchEventInternal(Event* event) {
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.h b/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.h index 148d947..0b9e006 100644 --- a/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.h +++ b/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.h
@@ -56,7 +56,7 @@ class MODULES_EXPORT IDBTransaction final : public EventTargetWithInlineData, public ActiveScriptWrappable<IDBTransaction>, - public ContextLifecycleObserver { + public ContextClient { USING_GARBAGE_COLLECTED_MIXIN(IDBTransaction); DEFINE_WRAPPERTYPEINFO();
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationRequest.cpp b/third_party/WebKit/Source/modules/presentation/PresentationRequest.cpp index 7f2e17e..3614224 100644 --- a/third_party/WebKit/Source/modules/presentation/PresentationRequest.cpp +++ b/third_party/WebKit/Source/modules/presentation/PresentationRequest.cpp
@@ -109,7 +109,7 @@ } ExecutionContext* PresentationRequest::getExecutionContext() const { - return ContextLifecycleObserver::getExecutionContext(); + return ContextClient::getExecutionContext(); } void PresentationRequest::addedEventListener( @@ -221,12 +221,12 @@ DEFINE_TRACE(PresentationRequest) { visitor->trace(m_availabilityProperty); EventTargetWithInlineData::trace(visitor); - ContextLifecycleObserver::trace(visitor); + ContextClient::trace(visitor); } PresentationRequest::PresentationRequest(ExecutionContext* executionContext, const Vector<KURL>& urls) - : ContextLifecycleObserver(executionContext), m_urls(urls) { + : ContextClient(executionContext), m_urls(urls) { recordOriginTypeAccess(executionContext); }
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationRequest.h b/third_party/WebKit/Source/modules/presentation/PresentationRequest.h index ac3d2d9b..6f8aef20 100644 --- a/third_party/WebKit/Source/modules/presentation/PresentationRequest.h +++ b/third_party/WebKit/Source/modules/presentation/PresentationRequest.h
@@ -23,7 +23,7 @@ class MODULES_EXPORT PresentationRequest final : public EventTargetWithInlineData, public ActiveScriptWrappable<PresentationRequest>, - public ContextLifecycleObserver { + public ContextClient { USING_GARBAGE_COLLECTED_MIXIN(PresentationRequest); DEFINE_WRAPPERTYPEINFO();
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp index c7e4ac21..1f4cc61b 100644 --- a/third_party/WebKit/Source/platform/fonts/Font.cpp +++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -109,13 +109,13 @@ GlyphBuffer& glyphBuffer, const GlyphData* emphasisData) const { float width; - CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription)); + CachingWordShaper shaper(*this); if (emphasisData) { - width = shaper.fillGlyphBufferForTextEmphasis(this, runInfo.run, + width = shaper.fillGlyphBufferForTextEmphasis(runInfo.run, emphasisData, &glyphBuffer, runInfo.from, runInfo.to); } else { - width = shaper.fillGlyphBuffer(this, runInfo.run, nullptr, &glyphBuffer, + width = shaper.fillGlyphBuffer(runInfo.run, &glyphBuffer, runInfo.from, runInfo.to); } return width; @@ -224,9 +224,8 @@ HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* glyphBounds) const { FontCachePurgePreventer purgePreventer; - CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription)); - float width = shaper.width(this, run, fallbackFonts, glyphBounds); - return width; + CachingWordShaper shaper(*this); + return shaper.width(run, fallbackFonts, glyphBounds); } namespace { @@ -439,8 +438,8 @@ FontCachePurgePreventer purgePreventer; - CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription)); - CharacterRange range = shaper.getCharacterRange(this, run, from, to); + CachingWordShaper shaper(*this); + CharacterRange range = shaper.getCharacterRange(run, from, to); return pixelSnappedSelectionRect( FloatRect(point.x() + range.start, point.y(), range.width(), height)); @@ -450,8 +449,8 @@ float xFloat, bool includePartialGlyphs) const { FontCachePurgePreventer purgePreventer; - CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription)); - return shaper.offsetForPosition(this, run, xFloat, includePartialGlyphs); + CachingWordShaper shaper(*this); + return shaper.offsetForPosition(run, xFloat, includePartialGlyphs); } ShapeCache* Font::shapeCache() const { @@ -562,15 +561,15 @@ unsigned from, unsigned to) const { FontCachePurgePreventer purgePreventer; - CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription)); - return shaper.getCharacterRange(this, run, from, to); + CachingWordShaper shaper(*this); + return shaper.getCharacterRange(run, from, to); } Vector<CharacterRange> Font::individualCharacterRanges( const TextRun& run) const { FontCachePurgePreventer purgePreventer; - CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription)); - auto ranges = shaper.individualCharacterRanges(this, run); + CachingWordShaper shaper(*this); + auto ranges = shaper.individualCharacterRanges(run); // The shaper should return ranges.size == run.length but on some platforms // (OSX10.9.5) we are seeing cases in the upper end of the unicode range // where this is not true (see: crbug.com/620952). To catch these cases on
diff --git a/third_party/WebKit/Source/platform/fonts/Font.h b/third_party/WebKit/Source/platform/fonts/Font.h index 8ba2ca3..6afe042 100644 --- a/third_party/WebKit/Source/platform/fonts/Font.h +++ b/third_party/WebKit/Source/platform/fonts/Font.h
@@ -208,9 +208,8 @@ mutable unsigned m_canShapeWordByWord : 1; mutable unsigned m_shapeWordByWordComputed : 1; - // For accessing buildGlyphBuffer and retrieving fonts used in rendering a - // node. - friend class InspectorCSSAgent; + // For m_fontDescription & m_fontFallbackList access. + friend class CachingWordShaper; }; inline Font::~Font() {}
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.cpp b/third_party/WebKit/Source/platform/fonts/FontCache.cpp index d5a4e3d..9208ac44 100644 --- a/third_party/WebKit/Source/platform/fonts/FontCache.cpp +++ b/third_party/WebKit/Source/platform/fonts/FontCache.cpp
@@ -172,7 +172,7 @@ foundResult = result || !addResult.isNewEntry; } - if (!foundResult && alternateFontName != AlternateFontName::NoAlternate && + if (!foundResult && alternateFontName == AlternateFontName::AllowAlternate && creationParams.creationType() == CreateFontByFamily) { // We were unable to find a font. We have a small set of fonts that we alias // to other names, e.g., Arial/Helvetica, Courier/Courier New, etc. Try @@ -296,14 +296,23 @@ return gFontDataCache->get(platformData, shouldRetain, subpixelAscentDescent); } -bool FontCache::isPlatformFontAvailable(const FontDescription& fontDescription, - const AtomicString& family) { +bool FontCache::isPlatformFamilyMatchAvailable( + const FontDescription& fontDescription, + const AtomicString& family) { return getFontPlatformData( fontDescription, FontFaceCreationParams(adjustFamilyNameToAvoidUnsupportedFonts(family)), AlternateFontName::NoAlternate); } +bool FontCache::isPlatformFontUniqueNameMatchAvailable( + const FontDescription& fontDescription, + const AtomicString& uniqueFontName) { + return getFontPlatformData(fontDescription, + FontFaceCreationParams(uniqueFontName), + AlternateFontName::LocalUniqueFace); +} + String FontCache::firstAvailableOrFirst(const String& families) { // The conversions involve at least two string copies, and more if non-ASCII. // For now we prefer shared code over the cost because a) inputs are
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.h b/third_party/WebKit/Source/platform/fonts/FontCache.h index d345988..d015e5e 100644 --- a/third_party/WebKit/Source/platform/fonts/FontCache.h +++ b/third_party/WebKit/Source/platform/fonts/FontCache.h
@@ -69,7 +69,12 @@ enum ShouldRetain { Retain, DoNotRetain }; enum PurgeSeverity { PurgeIfNeeded, ForcePurge }; -enum class AlternateFontName { AllowAlternate, NoAlternate, LastResort }; +enum class AlternateFontName { + AllowAlternate, + NoAlternate, + LocalUniqueFace, + LastResort +}; class PLATFORM_EXPORT FontCache { friend class FontCachePurgePreventer; @@ -101,7 +106,22 @@ PassRefPtr<SimpleFontData> getLastResortFallbackFont(const FontDescription&, ShouldRetain = Retain); SimpleFontData* getNonRetainedLastResortFallbackFont(const FontDescription&); - bool isPlatformFontAvailable(const FontDescription&, const AtomicString&); + + // Should be used in determining whether family names listed in font-family: + // ... are available locally. Only returns true if family name matches. + bool isPlatformFamilyMatchAvailable(const FontDescription&, + const AtomicString& family); + + // Should be used in determining whether the <abc> argument to local in + // @font-face { ... src: local(<abc>) } are available locally, which should + // match Postscript name or full font name. Compare + // https://drafts.csswg.org/css-fonts-3/#src-desc + // TODO crbug.com/627143 complete this and actually look at the right + // namerecords. + bool isPlatformFontUniqueNameMatchAvailable( + const FontDescription&, + const AtomicString& uniqueFontName); + static String firstAvailableOrFirst(const String&); // Returns the ShapeCache instance associated with the given cache key.
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp index 5cc8b7f..f6ab60ad 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp
@@ -35,13 +35,16 @@ namespace blink { -float CachingWordShaper::width(const Font* font, - const TextRun& run, +ShapeCache* CachingWordShaper::shapeCache() const { + return m_font.m_fontFallbackList->shapeCache(m_font.m_fontDescription); +} + +float CachingWordShaper::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* glyphBounds) { float width = 0; RefPtr<const ShapeResult> wordResult; - CachingWordShapeIterator iterator(m_shapeCache, run, font); + CachingWordShapeIterator iterator(shapeCache(), run, &m_font); while (iterator.next(&wordResult)) { if (wordResult) { if (glyphBounds) { @@ -64,7 +67,6 @@ ShapeCache* shapeCache, const Font* font, const TextRun& run, - HashSet<const SimpleFontData*>* fallbackFonts, ShapeResultBuffer* resultsBuffer) { CachingWordShapeIterator iterator(shapeCache, run, font); RefPtr<const ShapeResult> wordResult; @@ -72,68 +74,60 @@ while (iterator.next(&wordResult)) { if (wordResult) { totalWidth += wordResult->width(); - if (fallbackFonts) - wordResult->fallbackFonts(fallbackFonts); resultsBuffer->appendResult(std::move(wordResult)); } } return totalWidth; } -int CachingWordShaper::offsetForPosition(const Font* font, - const TextRun& run, +int CachingWordShaper::offsetForPosition(const TextRun& run, float targetX, bool includePartialGlyphs) { ShapeResultBuffer buffer; - shapeResultsForRun(m_shapeCache, font, run, nullptr, &buffer); + shapeResultsForRun(shapeCache(), &m_font, run, &buffer); return buffer.offsetForPosition(run, targetX, includePartialGlyphs); } float CachingWordShaper::fillGlyphBuffer( - const Font* font, const TextRun& run, - HashSet<const SimpleFontData*>* fallbackFonts, GlyphBuffer* glyphBuffer, unsigned from, unsigned to) { ShapeResultBuffer buffer; - shapeResultsForRun(m_shapeCache, font, run, fallbackFonts, &buffer); + shapeResultsForRun(shapeCache(), &m_font, run, &buffer); return buffer.fillGlyphBuffer(glyphBuffer, run, from, to); } float CachingWordShaper::fillGlyphBufferForTextEmphasis( - const Font* font, const TextRun& run, const GlyphData* emphasisData, GlyphBuffer* glyphBuffer, unsigned from, unsigned to) { ShapeResultBuffer buffer; - shapeResultsForRun(m_shapeCache, font, run, nullptr, &buffer); + shapeResultsForRun(shapeCache(), &m_font, run, &buffer); return buffer.fillGlyphBufferForTextEmphasis(glyphBuffer, run, emphasisData, from, to); } -CharacterRange CachingWordShaper::getCharacterRange(const Font* font, - const TextRun& run, +CharacterRange CachingWordShaper::getCharacterRange(const TextRun& run, unsigned from, unsigned to) { ShapeResultBuffer buffer; float totalWidth = - shapeResultsForRun(m_shapeCache, font, run, nullptr, &buffer); + shapeResultsForRun(shapeCache(), &m_font, run, &buffer); return buffer.getCharacterRange(run.direction(), totalWidth, from, to); } Vector<CharacterRange> CachingWordShaper::individualCharacterRanges( - const Font* font, const TextRun& run) { ShapeResultBuffer buffer; float totalWidth = - shapeResultsForRun(m_shapeCache, font, run, nullptr, &buffer); + shapeResultsForRun(shapeCache(), &m_font, run, &buffer); auto ranges = buffer.individualCharacterRanges(run.direction(), totalWidth); // The shaper can fail to return glyph metrics for all characters (see @@ -144,4 +138,12 @@ return ranges; } +Vector<ShapeResultBuffer::RunFontData> CachingWordShaper::runFontData( + const TextRun& run) const { + ShapeResultBuffer buffer; + shapeResultsForRun(shapeCache(), &m_font, run, &buffer); + + return buffer.runFontData(); +} + }; // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h index f3c4225..bf17fa12 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h +++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h
@@ -26,18 +26,21 @@ #ifndef CachingWordShaper_h #define CachingWordShaper_h +#include "platform/fonts/shaping/ShapeResultBuffer.h" #include "platform/geometry/FloatRect.h" #include "platform/text/TextRun.h" #include "wtf/Allocator.h" #include "wtf/PassRefPtr.h" +#include "wtf/Vector.h" +#include <tuple> namespace blink { struct CharacterRange; class Font; class GlyphBuffer; -class SimpleFontData; class ShapeCache; +class SimpleFontData; struct GlyphData; class PLATFORM_EXPORT CachingWordShaper final { @@ -45,37 +48,35 @@ WTF_MAKE_NONCOPYABLE(CachingWordShaper); public: - CachingWordShaper(ShapeCache* cache) : m_shapeCache(cache) {} + explicit CachingWordShaper(const Font& font) : m_font(font) {} ~CachingWordShaper() {} - float width(const Font*, - const TextRun&, + float width(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* glyphBounds); - int offsetForPosition(const Font*, - const TextRun&, + int offsetForPosition(const TextRun&, float targetX, bool includePartialGlyphs); - float fillGlyphBuffer(const Font*, - const TextRun&, - HashSet<const SimpleFontData*>*, + float fillGlyphBuffer(const TextRun&, GlyphBuffer*, unsigned from, unsigned to); - float fillGlyphBufferForTextEmphasis(const Font*, - const TextRun&, + float fillGlyphBufferForTextEmphasis(const TextRun&, const GlyphData* emphasisData, GlyphBuffer*, unsigned from, unsigned to); - CharacterRange getCharacterRange(const Font*, - const TextRun&, + CharacterRange getCharacterRange(const TextRun&, unsigned from, unsigned to); - Vector<CharacterRange> individualCharacterRanges(const Font*, const TextRun&); + Vector<CharacterRange> individualCharacterRanges(const TextRun&); + + Vector<ShapeResultBuffer::RunFontData> runFontData(const TextRun&) const; private: - ShapeCache* m_shapeCache; + ShapeCache* shapeCache() const; + + const Font& m_font; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp index 733586e..31f30f6 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
@@ -116,16 +116,16 @@ const UChar str[] = {0x2F, 0x301, 0x2E, 0x20, 0x2E, 0x0}; TextRun textRun(str, 5); - CachingWordShaper shaper(cache.get()); + CachingWordShaper shaper(font); GlyphBuffer glyphBuffer; - shaper.fillGlyphBuffer(&font, textRun, fallbackFonts, &glyphBuffer, 0, 3); + shaper.fillGlyphBuffer(textRun, &glyphBuffer, 0, 3); - std::unique_ptr<ShapeCache> referenceCache = WTF::makeUnique<ShapeCache>(); - CachingWordShaper referenceShaper(referenceCache.get()); + Font referenceFont(fontDescription); + referenceFont.update(nullptr); + CachingWordShaper referenceShaper(referenceFont); GlyphBuffer referenceGlyphBuffer; - font.setCanShapeWordByWordForTesting(false); - referenceShaper.fillGlyphBuffer(&font, textRun, fallbackFonts, - &referenceGlyphBuffer, 0, 3); + referenceFont.setCanShapeWordByWordForTesting(false); + referenceShaper.fillGlyphBuffer(textRun, &referenceGlyphBuffer, 0, 3); ASSERT_EQ(referenceGlyphBuffer.glyphAt(0), glyphBuffer.glyphAt(0)); ASSERT_EQ(referenceGlyphBuffer.glyphAt(1), glyphBuffer.glyphAt(1)); @@ -140,16 +140,16 @@ TextRun textRun(str, 6); textRun.setDirection(TextDirection::kRtl); - CachingWordShaper shaper(cache.get()); + CachingWordShaper shaper(font); GlyphBuffer glyphBuffer; - shaper.fillGlyphBuffer(&font, textRun, fallbackFonts, &glyphBuffer, 1, 6); + shaper.fillGlyphBuffer(textRun, &glyphBuffer, 1, 6); - std::unique_ptr<ShapeCache> referenceCache = WTF::makeUnique<ShapeCache>(); - CachingWordShaper referenceShaper(referenceCache.get()); + Font referenceFont(fontDescription); + referenceFont.update(nullptr); + CachingWordShaper referenceShaper(referenceFont); GlyphBuffer referenceGlyphBuffer; - font.setCanShapeWordByWordForTesting(false); - referenceShaper.fillGlyphBuffer(&font, textRun, fallbackFonts, - &referenceGlyphBuffer, 1, 6); + referenceFont.setCanShapeWordByWordForTesting(false); + referenceShaper.fillGlyphBuffer(textRun, &referenceGlyphBuffer, 1, 6); ASSERT_EQ(5u, referenceGlyphBuffer.size()); ASSERT_EQ(referenceGlyphBuffer.size(), glyphBuffer.size()); @@ -169,14 +169,14 @@ 0x20, 0x62, 0x61, 0x71, 0x0}; TextRun textRun(str, 9); - CachingWordShaper shaper(cache.get()); + CachingWordShaper shaper(font); FloatRect glyphBounds; - ASSERT_GT(shaper.width(&font, textRun, nullptr, &glyphBounds), 0); + ASSERT_GT(shaper.width(textRun, nullptr, &glyphBounds), 0); GlyphBuffer glyphBuffer; - shaper.fillGlyphBuffer(&font, textRun, fallbackFonts, &glyphBuffer, 0, 8); + shaper.fillGlyphBuffer(textRun, &glyphBuffer, 0, 8); - shaper.getCharacterRange(&font, textRun, 0, 8); + shaper.getCharacterRange(textRun, 0, 8); } TEST_F(CachingWordShaperTest, SegmentCJKByCharacter) { @@ -442,27 +442,26 @@ verticalMixedFont.update(nullptr); ASSERT_TRUE(verticalMixedFont.canShapeWordByWord()); - CachingWordShaper shaper(cache.get()); + CachingWordShaper shaper(verticalMixedFont); FloatRect glyphBounds; HashSet<const SimpleFontData*> fallbackFonts; ASSERT_GT( - shaper.width(&verticalMixedFont, textRun, &fallbackFonts, &glyphBounds), + shaper.width(textRun, &fallbackFonts, &glyphBounds), 0); EXPECT_EQ(0u, fallbackFonts.size()); } TEST_F(CachingWordShaperTest, GlyphBoundsWithSpaces) { - CachingWordShaper shaper(cache.get()); + CachingWordShaper shaper(font); TextRun periods(reinterpret_cast<const LChar*>(".........."), 10); FloatRect periodsGlyphBounds; - float periodsWidth = - shaper.width(&font, periods, nullptr, &periodsGlyphBounds); + float periodsWidth = shaper.width(periods, nullptr, &periodsGlyphBounds); TextRun periodsAndSpaces( reinterpret_cast<const LChar*>(". . . . . . . . . ."), 19); FloatRect periodsAndSpacesGlyphBounds; - float periodsAndSpacesWidth = shaper.width(&font, periodsAndSpaces, nullptr, + float periodsAndSpacesWidth = shaper.width(periodsAndSpaces, nullptr, &periodsAndSpacesGlyphBounds); // The total width of periods and spaces should be longer than the width of
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp index 1c0b74dc..a093da6 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp
@@ -208,10 +208,10 @@ GlyphBuffer* glyphBuffer, const TextRun& textRun) const { DCHECK(!hasVerticalOffsets()); + DCHECK_NE(glyphBuffer->type(), GlyphBuffer::Type::TextIntercepts); float advance = 0; - unsigned characterIndex = 0; for (unsigned i = 0; i < m_results.size(); ++i) { const auto& wordResult = isLeftToRightDirection(textRun.direction()) ? m_results[i] @@ -228,16 +228,11 @@ float totalAdvance) -> bool { DCHECK(!glyphData.offset.height()); - if (!isSkipInkException( - *glyphBuffer, textRun, - characterIndex + glyphData.characterIndex)) { - glyphBuffer->add(glyphData.glyph, run->m_fontData.get(), - totalAdvance + glyphData.offset.width()); - } + glyphBuffer->add(glyphData.glyph, run->m_fontData.get(), + totalAdvance + glyphData.offset.width()); return true; }); } - characterIndex += wordResult->m_numCharacters; } ASSERT(!glyphBuffer->hasVerticalOffsets()); @@ -249,8 +244,9 @@ const TextRun& textRun, unsigned from, unsigned to) const { - // Fast path: full run with no vertical offsets - if (!from && to == textRun.length() && !hasVerticalOffsets()) + // Fast path: full run with no vertical offsets, no text intercepts. + if (!from && to == textRun.length() && !hasVerticalOffsets() && + glyphBuffer->type() != GlyphBuffer::Type::TextIntercepts) return fillFastHorizontalGlyphBuffer(glyphBuffer, textRun); float advance = 0; @@ -488,4 +484,17 @@ return totalOffset; } +Vector<ShapeResultBuffer::RunFontData> +ShapeResultBuffer::runFontData() const { + Vector<RunFontData> fontData; + + for (const auto& result : m_results) { + for (const auto& run : result->m_runs) { + fontData.push_back(RunFontData({run->m_fontData.get(), + run->m_glyphData.size()})); + } + } + return fontData; +} + } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h index 573e548f..fb94c45 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h
@@ -10,6 +10,7 @@ #include "wtf/Allocator.h" #include "wtf/RefPtr.h" #include "wtf/Vector.h" +#include <tuple> namespace blink { @@ -57,6 +58,13 @@ unsigned from, unsigned to); + struct RunFontData { + SimpleFontData* m_fontData; + size_t m_glyphCount; + }; + + Vector<RunFontData> runFontData() const; + private: static CharacterRange getCharacterRangeInternal( const Vector<RefPtr<const ShapeResult>, 64>&,
diff --git a/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp b/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp index be0a9b7..d9a6692 100644 --- a/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp +++ b/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp
@@ -347,6 +347,20 @@ FontWeight variantWeight; FontStretch variantStretch; + // TODO: crbug.com/627143 LocalFontFaceSource.cpp, which implements + // retrieving src: local() font data uses getFontData, which in turn comes + // here, to retrieve fonts from the cache and specifies the argument to + // local() as family name. So we do not match by full font name or + // postscript name as the spec says: + // https://drafts.csswg.org/css-fonts-3/#src-desc + + // Prevent one side effect of the suffix translation below where when + // matching local("Roboto Regular") it tries to find the closest match even + // though that can be a bold font in case of Roboto Bold. + if (alternateFontName == AlternateFontName::LocalUniqueFace) { + return nullptr; + } + if (alternateFontName == AlternateFontName::LastResort) { if (!tf) return nullptr;
diff --git a/third_party/WebKit/Source/platform/image-decoders/FastSharedBufferReader.cpp b/third_party/WebKit/Source/platform/image-decoders/FastSharedBufferReader.cpp index 2120daa..a8c14ae 100644 --- a/third_party/WebKit/Source/platform/image-decoders/FastSharedBufferReader.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/FastSharedBufferReader.cpp
@@ -86,7 +86,7 @@ void FastSharedBufferReader::getSomeDataInternal(size_t dataPosition) const { m_dataPosition = dataPosition; m_segmentLength = m_data->getSomeData(m_segment, dataPosition); - ASSERT(m_segmentLength); + DCHECK(m_segmentLength); } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp index 06910757..7e4e93e9 100644 --- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
@@ -425,7 +425,7 @@ size_t ImageDecoder::findRequiredPreviousFrame(size_t frameIndex, bool frameRectIsOpaque) { - ASSERT(frameIndex <= m_frameBufferCache.size()); + DCHECK_LT(frameIndex, m_frameBufferCache.size()); if (!frameIndex) { // The first frame doesn't rely on any previous data. return kNotFound; @@ -467,7 +467,7 @@ ? kNotFound : prevFrame; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); return kNotFound; } } @@ -487,12 +487,14 @@ } void* ImagePlanes::plane(int i) { - ASSERT((i >= 0) && i < 3); + DCHECK_GE(i, 0); + DCHECK_LT(i, 3); return m_planes[i]; } size_t ImagePlanes::rowBytes(int i) const { - ASSERT((i >= 0) && i < 3); + DCHECK_GE(i, 0); + DCHECK_LT(i, 3); return m_rowBytes[i]; }
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h index 85e1649..3131b5f 100644 --- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h +++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
@@ -149,14 +149,14 @@ // Image decoders that support YUV decoding must override this to // provide the size of each component. virtual IntSize decodedYUVSize(int component) const { - ASSERT(false); + NOTREACHED(); return IntSize(); } // Image decoders that support YUV decoding must override this to // return the width of each row of the memory allocation. virtual size_t decodedYUVWidthBytes(int component) const { - ASSERT(false); + NOTREACHED(); return 0; }
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h index 64de184..5b5eb8a 100644 --- a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h +++ b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h
@@ -108,10 +108,10 @@ // same X-coordinates on each subsequent row up to but not including // endY. void copyRowNTimes(int startX, int endX, int startY, int endY) { - ASSERT(startX < width()); - ASSERT(endX <= width()); - ASSERT(startY < height()); - ASSERT(endY <= height()); + DCHECK_LT(startX, width()); + DCHECK_LE(endX, width()); + DCHECK_LT(startY, height()); + DCHECK_LE(endY, height()); const int rowBytes = (endX - startX) * sizeof(PixelData); const PixelData* const startAddr = getAddr(startX, startY); for (int destY = startY + 1; destY < endY; ++destY)
diff --git a/third_party/WebKit/Source/platform/image-decoders/SegmentReader.cpp b/third_party/WebKit/Source/platform/image-decoders/SegmentReader.cpp index 7857158..1f157379 100644 --- a/third_party/WebKit/Source/platform/image-decoders/SegmentReader.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/SegmentReader.cpp
@@ -128,7 +128,7 @@ for (size_t sizeOfBlock = m_iter.size(); sizeOfBlock != 0; m_positionOfBlock += sizeOfBlock, sizeOfBlock = m_iter.size()) { - ASSERT(m_positionOfBlock <= position); + DCHECK_LE(m_positionOfBlock, position); if (m_positionOfBlock + sizeOfBlock > position) { // |position| is in this block.
diff --git a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageDecoder.cpp index 3686236..c4bb3dd 100644 --- a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageDecoder.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageDecoder.cpp
@@ -91,7 +91,7 @@ bool BMPImageDecoder::processFileHeader(size_t& imgDataOffset) { // Read file header. - ASSERT(!m_decodedOffset); + DCHECK(!m_decodedOffset); if (m_data->size() < sizeOfFileHeader) return false;
diff --git a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.cpp b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.cpp index c6dacc9..a23eca7 100644 --- a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.cpp
@@ -115,7 +115,7 @@ return false; // Initialize the framebuffer if needed. - ASSERT(m_buffer); // Parent should set this before asking us to decode! + DCHECK(m_buffer); // Parent should set this before asking us to decode! if (m_buffer->getStatus() == ImageFrame::FrameEmpty) { if (!m_buffer->setSizeAndColorSpace(m_parent->size().width(), m_parent->size().height(), @@ -175,7 +175,7 @@ bool BMPImageReader::readInfoHeaderSize() { // Get size of info header. - ASSERT(m_decodedOffset == m_headerOffset); + DCHECK_EQ(m_decodedOffset, m_headerOffset); if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < 4)) return false; @@ -211,7 +211,7 @@ bool BMPImageReader::processInfoHeader() { // Read info header. - ASSERT(m_decodedOffset == m_headerOffset); + DCHECK_EQ(m_decodedOffset, m_headerOffset); if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < m_infoHeader.biSize) || !readInfoHeader()) @@ -261,7 +261,7 @@ if (m_isOS21x) { m_infoHeader.biWidth = readUint16(4); m_infoHeader.biHeight = readUint16(6); - ASSERT(!m_isInICO); // ICO is a Windows format, not OS/2! + DCHECK(!m_isInICO); // ICO is a Windows format, not OS/2! m_infoHeader.biBitCount = readUint16(10); return true; } @@ -398,7 +398,7 @@ default: // Some type we don't understand. This should have been caught in // readInfoHeader(). - ASSERT_NOT_REACHED(); + NOTREACHED(); return false; }
diff --git a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.h b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.h index 50437be..7df8112 100644 --- a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.h +++ b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.h
@@ -226,7 +226,7 @@ return readUint32(encodedPixel); default: - ASSERT_NOT_REACHED(); + NOTREACHED(); return 0; } }
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp index ea4acb2..8c4e988 100644 --- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp
@@ -236,13 +236,13 @@ referenceDecoder->setData(referenceData.get(), true); EXPECT_EQ(1u, referenceDecoder->frameCount()); ImageFrame* referenceFrame = referenceDecoder->frameBufferAtIndex(0); - ASSERT(referenceFrame); + DCHECK(referenceFrame); std::unique_ptr<ImageDecoder> testDecoder = createDecoder(); testDecoder->setData(testData.get(), true); EXPECT_EQ(1u, testDecoder->frameCount()); ImageFrame* testFrame = testDecoder->frameBufferAtIndex(0); - ASSERT(testFrame); + DCHECK(testFrame); EXPECT_EQ(hashBitmap(referenceFrame->bitmap()), hashBitmap(testFrame->bitmap()));
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp index dabfd44..d518c747 100644 --- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp
@@ -312,7 +312,7 @@ RELEASE_ASSERT(m_position + m_colors * BYTES_PER_COLORMAP_ENTRY <= reader->size()); - ASSERT(m_colors <= MAX_COLORS); + DCHECK_LE(m_colors, MAX_COLORS); char buffer[MAX_COLORS * BYTES_PER_COLORMAP_ENTRY]; const unsigned char* srcColormap = reinterpret_cast<const unsigned char*>(reader->getConsecutiveData( @@ -441,7 +441,7 @@ switch (m_state) { case GIFLZW: - ASSERT(!m_frames.isEmpty()); + DCHECK(!m_frames.isEmpty()); // m_bytesToConsume is the current component size because it hasn't been // updated. m_frames.back()->addLzwBlock(currentComponentPosition, @@ -450,7 +450,7 @@ break; case GIFLZWStart: { - ASSERT(!m_frames.isEmpty()); + DCHECK(!m_frames.isEmpty()); m_frames.back()->setDataSize(static_cast<unsigned char>( reader.getOneByte(currentComponentPosition))); GETN(1, GIFSubBlock); @@ -789,7 +789,7 @@ } case GIFImageColormap: { - ASSERT(!m_frames.isEmpty()); + DCHECK(!m_frames.isEmpty()); m_frames.back()->localColorMap().setDefined(); GETN(1, GIFLZWStart); break; @@ -802,7 +802,7 @@ GETN(bytesInBlock, GIFLZW); else { // Finished parsing one frame; Process next frame. - ASSERT(!m_frames.isEmpty()); + DCHECK(!m_frames.isEmpty()); // Note that some broken GIF files do not have enough LZW blocks to // fully decode all rows; we treat this case as "frame complete". m_frames.back()->setComplete(); @@ -828,7 +828,7 @@ } void GIFImageReader::setRemainingBytes(size_t remainingBytes) { - ASSERT(remainingBytes <= m_data->size()); + DCHECK_LE(remainingBytes, m_data->size()); m_bytesRead = m_data->size() - remainingBytes; } @@ -839,8 +839,8 @@ // FIXME: Move this method to close to doLZW(). bool GIFLZWContext::prepareToDecode() { - ASSERT(m_frameContext->isDataSizeDefined() && - m_frameContext->isHeaderDefined()); + DCHECK(m_frameContext->isDataSizeDefined()); + DCHECK(m_frameContext->isHeaderDefined()); // Since we use a codesize of 1 more than the datasize, we need to ensure // that our datasize is strictly less than the MAX_DICTIONARY_ENTRY_BITS.
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.h b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.h index de91c1a..9525fe7 100644 --- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.h +++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.h
@@ -49,7 +49,7 @@ #define MAX_DICTIONARY_ENTRY_BITS 12 #define MAX_DICTIONARY_ENTRIES 4096 // 2^MAX_DICTIONARY_ENTRY_BITS -#define MAX_COLORS 256 +#define MAX_COLORS 256u #define BYTES_PER_COLORMAP_ENTRY 3 const int cLoopCountNotSeen = -2;
diff --git a/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp index 0288899..75944c4 100644 --- a/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp
@@ -228,7 +228,7 @@ bool ICOImageDecoder::processDirectory() { // Read directory. - ASSERT(!m_decodedOffset); + DCHECK(!m_decodedOffset); if (m_data->size() < sizeOfDirectory) return false; const uint16_t fileType = readUint16(2); @@ -246,7 +246,7 @@ bool ICOImageDecoder::processDirectoryEntries() { // Read directory entries. - ASSERT(m_decodedOffset == sizeOfDirectory); + DCHECK_EQ(m_decodedOffset, sizeOfDirectory); if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < (m_dirEntriesCount * sizeOfDirEntry)))
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp index 84609d6e..64101275 100644 --- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -528,7 +528,7 @@ return false; // I/O suspension. // If we've completed image output... - ASSERT(m_info.output_scanline == m_info.output_height); + DCHECK_EQ(m_info.output_scanline, m_info.output_height); m_state = JPEG_DONE; } // FALL THROUGH @@ -737,18 +737,22 @@ } IntSize JPEGImageDecoder::decodedYUVSize(int component) const { - ASSERT((component >= 0) && (component <= 2) && m_reader); + DCHECK_GE(component, 0); + DCHECK_LE(component, 2); + DCHECK(m_reader); const jpeg_decompress_struct* info = m_reader->info(); - ASSERT(info->out_color_space == JCS_YCbCr); + DCHECK_EQ(info->out_color_space, JCS_YCbCr); return computeYUVSize(info, component); } size_t JPEGImageDecoder::decodedYUVWidthBytes(int component) const { - ASSERT((component >= 0) && (component <= 2) && m_reader); + DCHECK_GE(component, 0); + DCHECK_LE(component, 2); + DCHECK(m_reader); const jpeg_decompress_struct* info = m_reader->info(); - ASSERT(info->out_color_space == JCS_YCbCr); + DCHECK_EQ(info->out_color_space, JCS_YCbCr); return computeYUVWidthBytes(info, component); } @@ -793,7 +797,7 @@ ImageFrame::PixelData* pixel, JSAMPARRAY samples, int column) { - ASSERT_NOT_REACHED(); + NOTREACHED(); } // Used only for debugging with libjpeg (instead of libjpeg-turbo). @@ -928,10 +932,10 @@ // Initialize the framebuffer if needed. ImageFrame& buffer = m_frameBufferCache[0]; if (buffer.getStatus() == ImageFrame::FrameEmpty) { - ASSERT(info->output_width == - static_cast<JDIMENSION>(m_decodedSize.width())); - ASSERT(info->output_height == - static_cast<JDIMENSION>(m_decodedSize.height())); + DCHECK_EQ(info->output_width, + static_cast<JDIMENSION>(m_decodedSize.width())); + DCHECK_EQ(info->output_height, + static_cast<JDIMENSION>(m_decodedSize.height())); if (!buffer.setSizeAndColorSpace(info->output_width, info->output_height, colorSpaceForSkImages())) @@ -971,7 +975,7 @@ case JCS_CMYK: return outputRows<JCS_CMYK>(m_reader.get(), buffer); default: - ASSERT_NOT_REACHED(); + NOTREACHED(); } return setFailed();
diff --git a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp index c9045baf..27757d08 100644 --- a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
@@ -199,7 +199,7 @@ return setFailed(); } - ASSERT(m_demuxState > WEBP_DEMUX_PARSING_HEADER); + DCHECK_GT(m_demuxState, WEBP_DEMUX_PARSING_HEADER); if (!WebPDemuxGetI(m_demux, WEBP_FF_FRAME_COUNT)) return false; // Wait until the encoded image frame data arrives. @@ -218,7 +218,7 @@ // an ANIM chunk must precede the ANMF frame chunks. m_repetitionCount = WebPDemuxGetI(m_demux, WEBP_FF_LOOP_COUNT); // Repetition count is always <= 16 bits. - ASSERT(m_repetitionCount == (m_repetitionCount & 0xffff)); + DCHECK_EQ(m_repetitionCount, m_repetitionCount & 0xffff); if (!m_repetitionCount) m_repetitionCount = cAnimationLoopInfinite; // FIXME: Implement ICC profile support for animated images. @@ -229,7 +229,7 @@ readColorProfile(); } - ASSERT(isDecodedSizeAvailable()); + DCHECK(isDecodedSizeAvailable()); size_t frameCount = WebPDemuxGetI(m_demux, WEBP_FF_FRAME_COUNT); updateAggressivePurging(frameCount); @@ -344,7 +344,7 @@ buffer.getAlphaBlendSource() == ImageFrame::BlendAtopPreviousFrame && buffer.requiredPreviousFrameIndex() != kNotFound) { ImageFrame& prevBuffer = m_frameBufferCache[frameIndex - 1]; - ASSERT(prevBuffer.getStatus() == ImageFrame::FrameComplete); + DCHECK_EQ(prevBuffer.getStatus(), ImageFrame::FrameComplete); ImageFrame::DisposalMethod prevDisposalMethod = prevBuffer.getDisposalMethod(); if (prevDisposalMethod == ImageFrame::DisposeKeep) { @@ -385,12 +385,12 @@ void WEBPImageDecoder::initializeNewFrame(size_t index) { if (!(m_formatFlags & ANIMATION_FLAG)) { - ASSERT(!index); + DCHECK(!index); return; } WebPIterator animatedFrame; WebPDemuxGetFrame(m_demux, index + 1, &animatedFrame); - ASSERT(animatedFrame.complete == 1); + DCHECK_EQ(animatedFrame.complete, 1); ImageFrame* buffer = &m_frameBufferCache[index]; IntRect frameRect(animatedFrame.x_offset, animatedFrame.y_offset, animatedFrame.width, animatedFrame.height); @@ -415,7 +415,7 @@ Vector<size_t> framesToDecode = findFramesToDecode(index); - ASSERT(m_demux); + DCHECK(m_demux); for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(*i)) return; @@ -447,11 +447,11 @@ if (failed()) return false; - ASSERT(isDecodedSizeAvailable()); + DCHECK(isDecodedSizeAvailable()); - ASSERT(m_frameBufferCache.size() > frameIndex); + DCHECK_GT(m_frameBufferCache.size(), frameIndex); ImageFrame& buffer = m_frameBufferCache[frameIndex]; - ASSERT(buffer.getStatus() != ImageFrame::FrameComplete); + DCHECK_NE(buffer.getStatus(), ImageFrame::FrameComplete); if (buffer.getStatus() == ImageFrame::FrameEmpty) { if (!buffer.setSizeAndColorSpace(size().width(), size().height(),
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp index e43dcc01..3fcba55 100644 --- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
@@ -4,6 +4,7 @@ #include "web/WebRemoteFrameImpl.h" +#include "bindings/core/v8/RemoteWindowProxy.h" #include "core/dom/Fullscreen.h" #include "core/dom/RemoteSecurityContext.h" #include "core/dom/SecurityContext.h" @@ -21,10 +22,10 @@ #include "public/web/WebPerformance.h" #include "public/web/WebRange.h" #include "public/web/WebTreeScopeType.h" +#include "v8/include/v8.h" #include "web/RemoteFrameOwner.h" #include "web/WebLocalFrameImpl.h" #include "web/WebViewImpl.h" -#include <v8/include/v8.h> namespace blink { @@ -214,7 +215,9 @@ v8::Local<v8::Context> WebRemoteFrameImpl::deprecatedMainWorldScriptContext() const { - return toV8Context(frame(), DOMWrapperWorld::mainWorld()); + return static_cast<RemoteWindowProxy*>( + frame()->windowProxy(DOMWrapperWorld::mainWorld())) + ->contextIfInitialized(); } void WebRemoteFrameImpl::reload(WebFrameLoadType) {
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom b/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom index 43ac52f4..ddd5fd7 100644 --- a/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom +++ b/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom
@@ -70,6 +70,10 @@ DEVICE_NO_LONGER_IN_RANGE, GATT_NOT_PAIRED, GATT_OPERATION_IN_PROGRESS, + GATT_SERVER_DISCONNECTED, + GATT_SERVER_NOT_CONNECTED, + GATT_SERVER_DISCONNECTED_WHILE_RETRIEVING_CHARACTERISTICS, + GATT_SERVER_NOT_CONNECTED_CANNOT_RETRIEVE_CHARACTERISTICS, UNTRANSLATED_CONNECT_ERROR_CODE, // NotFoundError: NO_BLUETOOTH_ADAPTER, @@ -102,7 +106,6 @@ NOT_ALLOWED_TO_ACCESS_SERVICE, REQUEST_DEVICE_WITH_BLOCKLISTED_UUID, REQUEST_DEVICE_FROM_CROSS_ORIGIN_IFRAME, - REQUEST_DEVICE_WITHOUT_FRAME, DESCRIPTOR_NO_LONGER_EXISTS, };
diff --git a/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py b/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py index 5805345..c4bb1dc 100755 --- a/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py +++ b/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py
@@ -13,7 +13,6 @@ import os import random import re -import subprocess import sys import time @@ -30,6 +29,7 @@ import devil_chromium sys.path.append(os.path.join(_SRC_PATH, 'tools', 'android', 'loading')) +import chrome_setup import device_setup @@ -40,35 +40,6 @@ _INVALID_VALUE = -1 -# Command line arguments for Chrome. -CHROME_ARGS = [ - # Disable backgound network requests that may pollute WPR archive, pollute - # HTTP cache generation, and introduce noise in loading performance. - '--disable-background-networking', - '--disable-default-apps', - '--no-proxy-server', - # TODO(droger): Remove once crbug.com/354743 is fixed. - '--safebrowsing-disable-auto-update', - - # Disables actions that chrome performs only on first run or each launches, - # which can interfere with page load performance, or even block its - # execution by waiting for user input. - '--disable-fre', - '--no-default-browser-check', - '--no-first-run', -] - - -def ResetChromeLocalState(device): - """Remove the Chrome Profile and the various disk caches.""" - profile_dirs = ['app_chrome/Default', 'cache', 'app_chrome/ShaderCache', - 'app_tabs'] - cmd = ['rm', '-rf'] - cmd.extend( - '/data/data/{}/{}'.format(_CHROME_PACKAGE, d) for d in profile_dirs) - device.adb.Shell(subprocess.list2cmdline(cmd)) - - def RunOnce(device, url, warmup, speculation_mode, delay_to_may_launch_url, delay_to_launch_url, cold, chrome_args, reset_chrome_state): """Runs a test on a device once. @@ -116,7 +87,7 @@ device.ForceStop(_TEST_APP_PACKAGE_NAME) if reset_chrome_state: - ResetChromeLocalState(device) + chrome_setup.ResetChromeLocalState(device, _CHROME_PACKAGE) if cold: cache_control.CacheControl(device).DropRamCaches() @@ -180,7 +151,7 @@ try: while should_stop is None or not should_stop.is_set(): config = configs[random.randint(0, len(configs) - 1)] - chrome_args = CHROME_ARGS + wpr_attributes.chrome_args + chrome_args = chrome_setup.CHROME_ARGS + wpr_attributes.chrome_args if config['speculation_mode'] == 'no_state_prefetch': # NoStatePrefetch is enabled through an experiment. chrome_args.extend([
diff --git a/tools/android/loading/chrome_setup.py b/tools/android/loading/chrome_setup.py new file mode 100644 index 0000000..889f86d --- /dev/null +++ b/tools/android/loading/chrome_setup.py
@@ -0,0 +1,34 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import subprocess + + +# Command line arguments for Chrome for loading performance measurements. +CHROME_ARGS = [ + # Disable backgound network requests that may pollute WPR archive, pollute + # HTTP cache generation, and introduce noise in loading performance. + '--disable-background-networking', + '--disable-default-apps', + '--no-proxy-server', + # TODO(droger): Remove once crbug.com/354743 is fixed. + '--safebrowsing-disable-auto-update', + + # Disables actions that chrome performs only on first run or each launches, + # which can interfere with page load performance, or even block its + # execution by waiting for user input. + '--disable-fre', + '--no-default-browser-check', + '--no-first-run', +] + + +def ResetChromeLocalState(device, package): + """Remove the Chrome Profile and the various disk caches.""" + profile_dirs = ['app_chrome/Default', 'cache', 'app_chrome/ShaderCache', + 'app_tabs'] + cmd = ['rm', '-rf'] + cmd.extend( + '/data/data/{}/{}'.format(package, d) for d in profile_dirs) + device.adb.Shell(subprocess.list2cmdline(cmd))
diff --git a/tools/android/loading/controller.py b/tools/android/loading/controller.py index ace200b03..b15b62d 100644 --- a/tools/android/loading/controller.py +++ b/tools/android/loading/controller.py
@@ -27,6 +27,7 @@ import psutil import chrome_cache +import chrome_setup import common_util import device_setup import devtools_monitor @@ -146,23 +147,7 @@ DEVTOOLS_CONNECTION_ATTEMPT_INTERVAL_SECONDS = 1 def __init__(self): - self._chrome_args = [ - # Disable backgound network requests that may pollute WPR archive, - # pollute HTTP cache generation, and introduce noise in loading - # performance. - '--disable-background-networking', - '--disable-default-apps', - '--no-proxy-server', - # TODO(gabadie): Remove once crbug.com/354743 done. - '--safebrowsing-disable-auto-update', - - # Disables actions that chrome performs only on first run or each - # launches, which can interfere with page load performance, or even - # block its execution by waiting for user input. - '--disable-fre', - '--no-default-browser-check', - '--no-first-run', - + self._chrome_args = chrome_setup.CHROME_ARGS + [ # Tests & dev-tools related stuff. '--enable-test-events', '--remote-debugging-port=%d' % OPTIONS.devtools_port, @@ -402,14 +387,9 @@ def ResetBrowserState(self): """Override resetting Chrome local state.""" logging.info('Resetting Chrome local state') - package = OPTIONS.ChromePackage().package - # Remove the Chrome Profile and the various disk caches. Other parts - # theoretically should not affect loading performance. Also remove the tab - # state to prevent it from growing infinitely. [:D] - for directory in ['app_chrome/Default', 'cache', 'app_chrome/ShaderCache', - 'app_tabs']: - cmd = ['rm', '-rf', '/data/data/{}/{}'.format(package, directory)] - self._device.adb.Shell(subprocess.list2cmdline(cmd)) + chrome_setup.ResetChromeLocalState(self._device, + OPTIONS.ChromePackage().package) + def RebootDevice(self): """Reboot the remote device."""
diff --git a/tools/android/loading/wpr_helper.py b/tools/android/loading/wpr_helper.py new file mode 100755 index 0000000..ab655a59 --- /dev/null +++ b/tools/android/loading/wpr_helper.py
@@ -0,0 +1,125 @@ +#!/usr/bin/python +# +# 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. + +"""Helper script to launch Chrome on device and WebPageReplay on host.""" + +import logging +import optparse +import os +import sys +import time + +_SRC_PATH = os.path.abspath(os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)) + +sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil')) +from devil.android import device_utils +from devil.android.constants import chrome +from devil.android.perf import cache_control +from devil.android.sdk import intent + +sys.path.append(os.path.join(_SRC_PATH, 'build', 'android')) +import devil_chromium + +import chrome_setup +import device_setup + + +def RunChrome(device, cold, chrome_args, package_info): + """Runs Chrome on the device. + + Args: + device: (DeviceUtils) device to run the tests on. + cold: (bool) Whether caches should be dropped. + chrome_args: ([str]) List of arguments to pass to Chrome. + package_info: (PackageInfo) Chrome package info. + """ + if not device.HasRoot(): + device.EnableRoot() + + cmdline_file = package_info.cmdline_file + package = package_info.package + with device_setup.FlagReplacer(device, cmdline_file, chrome_args): + device.ForceStop(package) + + if cold: + chrome_setup.ResetChromeLocalState(device, package) + cache_control.CacheControl(device).DropRamCaches() + + start_intent = intent.Intent(package=package, data='about:blank', + activity=package_info.activity) + try: + device.StartActivity(start_intent, blocking=True) + print ( + '\n\n' + ' +---------------------------------------------+\n' + ' | Chrome launched, press Ctrl-C to interrupt. |\n' + ' +---------------------------------------------+') + while True: + time.sleep(1) + except KeyboardInterrupt: + pass + finally: + device.ForceStop(package) + + +def _CreateOptionParser(): + description = 'Launches Chrome on a device, connected to a WebPageReplay ' \ + 'instance running on the host. The WPR archive must be ' \ + 'passed as parameter.' + parser = optparse.OptionParser(description=description, + usage='Usage: %prog [options] wpr_archive') + + # Device-related options. + d = optparse.OptionGroup(parser, 'Device options') + d.add_option('--device', help='Device ID') + d.add_option('--cold', help='Purge all caches before running Chrome.', + default=False, action='store_true') + d.add_option('--chrome_package_name', + help='Chrome package name (e.g. "chrome" or "chromium") ' + '[default: %default].', default='chrome') + parser.add_option_group(d) + + # WebPageReplay-related options. + w = optparse.OptionGroup(parser, 'WebPageReplay options') + w.add_option('--record', + help='Enable this to record a new WPR archive.', + action='store_true', default=False) + w.add_option('--wpr_log', help='WPR log path.') + w.add_option('--network_condition', help='Network condition for emulation.') + parser.add_option_group(w) + + return parser + + +def main(): + parser = _CreateOptionParser() + options, args = parser.parse_args() + if len(args) != 1: + parser.error("Incorrect number of arguments.") + devil_chromium.Initialize() + devices = device_utils.DeviceUtils.HealthyDevices() + device = devices[0] + if len(devices) != 1 and options.device is None: + logging.error('Several devices attached, must specify one with --device.') + sys.exit(0) + if options.device is not None: + matching_devices = [d for d in devices if str(d) == options.device] + if not matching_devices: + logging.error('Device not found.') + sys.exit(0) + device = matching_devices[0] + + with device_setup.RemoteWprHost(device, args[0], options.record, + options.network_condition, + out_log_path=options.wpr_log) as wpr_attr: + RunChrome(device, options.cold, + chrome_setup.CHROME_ARGS + wpr_attr.chrome_args, + chrome.PACKAGE_INFO[options.chrome_package_name]) + + +if __name__ == '__main__': + main()
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 17197fe9..6c89c0a 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -98393,6 +98393,7 @@ <int value="1586022426" label="AutofillCreditCardAssist:enabled"/> <int value="1589341623" label="disable-easy-unlock"/> <int value="1612446645" label="enable-weak-memorycache"/> + <int value="1612871297" label="WebPayments:disabled"/> <int value="1612974229" label="allow-insecure-localhost"/> <int value="1617187093" label="enable-improved-a2hs"/> <int value="1622131033" label="ozone-test-single-overlay-support"/> @@ -98462,6 +98463,7 @@ <int value="1889076955" label="disable-app-link"/> <int value="1891210939" label="enable-blink-features"/> <int value="1892201400" label="enable-password-separated-signin-flow"/> + <int value="1893317228" label="WebPayments:enabled"/> <int value="1895587769" label="CredentialManagementAPI:disabled"/> <int value="1896456311" label="enable-password-save-in-page-navigation"/> <int value="1898231011" label="enable-native-notifications"/>
diff --git a/ui/app_list/app_list_item_list.cc b/ui/app_list/app_list_item_list.cc index 6e1e564b..2cb13fe7 100644 --- a/ui/app_list/app_list_item_list.cc +++ b/ui/app_list/app_list_item_list.cc
@@ -25,18 +25,16 @@ } AppListItem* AppListItemList::FindItem(const std::string& id) { - for (size_t i = 0; i < app_list_items_.size(); ++i) { - AppListItem* item = app_list_items_[i]; + for (const auto& item : app_list_items_) { if (item->id() == id) - return item; + return item.get(); } - return NULL; + return nullptr; } bool AppListItemList::FindItemIndex(const std::string& id, size_t* index) { for (size_t i = 0; i < app_list_items_.size(); ++i) { - AppListItem* item = app_list_items_[i]; - if (item->id() == id) { + if (app_list_items_[i]->id() == id) { *index = i; return true; } @@ -50,17 +48,15 @@ if (from_index == to_index) return; - AppListItem* target_item = app_list_items_[from_index]; + auto target_item = std::move(app_list_items_[from_index]); DVLOG(2) << "MoveItem: " << from_index << " -> " << to_index << " [" << target_item->position().ToDebugString() << "]"; - // Remove the target item - app_list_items_.weak_erase(app_list_items_.begin() + from_index); + app_list_items_.erase(app_list_items_.begin() + from_index); // Update the position - AppListItem* prev = to_index > 0 ? app_list_items_[to_index - 1] : NULL; - AppListItem* next = - to_index < item_count() ? app_list_items_[to_index] : NULL; + AppListItem* prev = to_index > 0 ? item_at(to_index - 1) : nullptr; + AppListItem* next = to_index < item_count() ? item_at(to_index) : nullptr; CHECK_NE(prev, next); syncer::StringOrdinal new_position; if (!prev) { @@ -83,9 +79,11 @@ << " -> " << new_position.ToDebugString(); // Insert the item and notify observers. - app_list_items_.insert(app_list_items_.begin() + to_index, target_item); + app_list_items_.insert(app_list_items_.begin() + to_index, + std::move(target_item)); + AppListItem* item = item_at(to_index); for (auto& observer : observers_) - observer.OnListItemMoved(from_index, to_index, target_item); + observer.OnListItemMoved(from_index, to_index, item); } void AppListItemList::SetItemPosition(AppListItem* item, @@ -96,12 +94,12 @@ LOG(ERROR) << "SetItemPosition: Not in list: " << item->id().substr(0, 8); return; } - DCHECK(app_list_items_[from_index] == item); + DCHECK(item_at(from_index) == item); if (!new_position.IsValid()) { size_t last_index = app_list_items_.size() - 1; if (from_index == last_index) return; // Already last item, do nothing. - new_position = app_list_items_[last_index]->position().CreateAfter(); + new_position = item_at(last_index)->position().CreateAfter(); } // First check if the order would remain the same, in which case just update // the position. @@ -112,13 +110,15 @@ return; } // Remove the item and get the updated to index. - app_list_items_.weak_erase(app_list_items_.begin() + from_index); - to_index = GetItemSortOrderIndex(new_position, item->id()); - DVLOG(2) << "SetItemPosition: " << item->id().substr(0, 8) << " -> " + auto target_item = std::move(app_list_items_[from_index]); + app_list_items_.erase(app_list_items_.begin() + from_index); + to_index = GetItemSortOrderIndex(new_position, target_item->id()); + DVLOG(2) << "SetItemPosition: " << target_item->id().substr(0, 8) << " -> " << new_position.ToDebugString() << " From: " << from_index << " To: " << to_index; - item->set_position(new_position); - app_list_items_.insert(app_list_items_.begin() + to_index, item); + target_item->set_position(new_position); + app_list_items_.insert(app_list_items_.begin() + to_index, + std::move(target_item)); for (auto& observer : observers_) observer.OnListItemMoved(from_index, to_index, item); } @@ -157,25 +157,27 @@ index = nitems; } else { for (index = 0; index < nitems; ++index) { - if (!app_list_items_[index]->position().LessThan(position)) + if (!item_at(index)->position().LessThan(position)) break; } } if (index == 0) - return app_list_items_[0]->position().CreateBefore(); + return item_at(0)->position().CreateBefore(); if (index == nitems) - return app_list_items_[nitems - 1]->position().CreateAfter(); - return app_list_items_[index - 1]->position().CreateBetween( - app_list_items_[index]->position()); + return item_at(nitems - 1)->position().CreateAfter(); + return item_at(index - 1)->position().CreateBetween( + item_at(index)->position()); } AppListItem* AppListItemList::AddItem(std::unique_ptr<AppListItem> item_ptr) { AppListItem* item = item_ptr.get(); - CHECK(std::find(app_list_items_.begin(), app_list_items_.end(), item) - == app_list_items_.end()); + CHECK(std::find_if(app_list_items_.cbegin(), app_list_items_.cend(), + [item](const std::unique_ptr<AppListItem>& item_p) { + return item_p.get() == item; + }) == app_list_items_.cend()); EnsureValidItemPosition(item); size_t index = GetItemSortOrderIndex(item->position(), item->id()); - app_list_items_.insert(app_list_items_.begin() + index, item_ptr.release()); + app_list_items_.insert(app_list_items_.begin() + index, std::move(item_ptr)); for (auto& observer : observers_) observer.OnListItemAdded(index, item); @@ -203,11 +205,11 @@ std::unique_ptr<AppListItem> AppListItemList::RemoveItemAt(size_t index) { CHECK_LT(index, item_count()); - AppListItem* item = app_list_items_[index]; - app_list_items_.weak_erase(app_list_items_.begin() + index); + auto item = std::move(app_list_items_[index]); + app_list_items_.erase(app_list_items_.begin() + index); for (auto& observer : observers_) - observer.OnListItemRemoved(index, item); - return base::WrapUnique<AppListItem>(item); + observer.OnListItemRemoved(index, item.get()); + return item; } void AppListItemList::DeleteItemAt(size_t index) { @@ -223,7 +225,7 @@ if (nitems == 0) { position = syncer::StringOrdinal::CreateInitialOrdinal(); } else { - position = app_list_items_[nitems - 1]->position().CreateAfter(); + position = item_at(nitems - 1)->position().CreateAfter(); } item->set_position(position); } @@ -233,9 +235,9 @@ const std::string& id) { DCHECK(position.IsValid()); for (size_t index = 0; index < app_list_items_.size(); ++index) { - if (position.LessThan(app_list_items_[index]->position()) || - (position.Equals(app_list_items_[index]->position()) && - (id < app_list_items_[index]->id()))) { + if (position.LessThan(item_at(index)->position()) || + (position.Equals(item_at(index)->position()) && + (id < item_at(index)->id()))) { return index; } } @@ -249,23 +251,24 @@ DCHECK_GT(index, 0u); // Update the position of |index| and any necessary subsequent items. // First, find the next item that has a different position. - AppListItem* prev = app_list_items_[index - 1]; + AppListItem* prev = item_at(index - 1); size_t last_index = index + 1; for (; last_index < nitems; ++last_index) { - if (!app_list_items_[last_index]->position().Equals(prev->position())) + if (!item_at(last_index)->position().Equals(prev->position())) break; } - AppListItem* last = last_index < nitems ? app_list_items_[last_index] : NULL; + AppListItem* last = last_index < nitems ? item_at(last_index) : nullptr; for (size_t i = index; i < last_index; ++i) { - AppListItem* cur = app_list_items_[i]; + AppListItem* cur = item_at(i); if (last) cur->set_position(prev->position().CreateBetween(last->position())); else cur->set_position(prev->position().CreateAfter()); prev = cur; } + AppListItem* item = item_at(index); for (auto& observer : observers_) - observer.OnListItemMoved(index, index, app_list_items_[index]); + observer.OnListItemMoved(index, index, item); } } // namespace app_list
diff --git a/ui/app_list/app_list_item_list.h b/ui/app_list/app_list_item_list.h index 99044e9b..72ae543 100644 --- a/ui/app_list/app_list_item_list.h +++ b/ui/app_list/app_list_item_list.h
@@ -9,9 +9,9 @@ #include <memory> #include <string> +#include <vector> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/observer_list.h" #include "components/sync/model/string_ordinal.h" #include "ui/app_list/app_list_export.h" @@ -57,11 +57,11 @@ AppListItem* item_at(size_t index) { DCHECK_LT(index, app_list_items_.size()); - return app_list_items_[index]; + return app_list_items_[index].get(); } const AppListItem* item_at(size_t index) const { DCHECK_LT(index, app_list_items_.size()); - return app_list_items_[index]; + return app_list_items_[index].get(); } size_t item_count() const { return app_list_items_.size(); } @@ -108,7 +108,7 @@ // previous item's position. |index| must be > 0. void FixItemPosition(size_t index); - ScopedVector<AppListItem> app_list_items_; + std::vector<std::unique_ptr<AppListItem>> app_list_items_; base::ObserverList<AppListItemListObserver, true> observers_; std::string highlighted_id_;
diff --git a/ui/app_list/search/mixer.cc b/ui/app_list/search/mixer.cc index 78db4de..537c834 100644 --- a/ui/app_list/search/mixer.cc +++ b/ui/app_list/search/mixer.cc
@@ -11,6 +11,7 @@ #include <vector> #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "ui/app_list/search_provider.h" #include "ui/app_list/search_result.h" @@ -126,7 +127,7 @@ } size_t Mixer::AddGroup(size_t max_results, double multiplier) { - groups_.push_back(new Group(max_results, multiplier)); + groups_.push_back(base::MakeUnique<Group>(max_results, multiplier)); return groups_.size() - 1; } @@ -144,7 +145,7 @@ // Add results from each group. Limit to the maximum number of results in each // group. - for (const Group* group : groups_) { + for (const auto& group : groups_) { const size_t num_results = std::min(group->results().size(), group->max_results()); results.insert(results.end(), group->results().begin(), @@ -162,7 +163,7 @@ // We didn't get enough results. Insert all the results again, and this // time, do not limit the maximum number of results from each group. (This // will result in duplicates, which will be removed by RemoveDuplicates.) - for (const Group* group : groups_) { + for (const auto& group : groups_) { results.insert(results.end(), group->results().begin(), group->results().end()); } @@ -238,7 +239,7 @@ void Mixer::FetchResults(bool is_voice_query, const KnownResults& known_results) { - for (auto* group : groups_) + for (const auto& group : groups_) group->FetchResults(is_voice_query, known_results); }
diff --git a/ui/app_list/search/mixer.h b/ui/app_list/search/mixer.h index aa77f6dd..253de6fd3 100644 --- a/ui/app_list/search/mixer.h +++ b/ui/app_list/search/mixer.h
@@ -7,11 +7,11 @@ #include <stddef.h> +#include <memory> #include <vector> #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/app_list/app_list_export.h" #include "ui/app_list/app_list_model.h" #include "ui/app_list/search/history_types.h" @@ -65,7 +65,7 @@ typedef std::vector<Mixer::SortData> SortedResults; class Group; - typedef ScopedVector<Group> Groups; + typedef std::vector<std::unique_ptr<Group>> Groups; // Publishes the given |new_results| to |ui_results|, deleting any existing // results that are not in |new_results|. Results that already exist in
diff --git a/ui/app_list/search/mixer_unittest.cc b/ui/app_list/search/mixer_unittest.cc index 084c579..fb4f91d 100644 --- a/ui/app_list/search/mixer_unittest.cc +++ b/ui/app_list/search/mixer_unittest.cc
@@ -6,12 +6,13 @@ #include <stddef.h> +#include <memory> #include <set> #include <string> +#include <vector> #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/memory/scoped_vector.h" #include "base/strings/string16.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -122,9 +123,9 @@ void SetUp() override { results_.reset(new AppListModel::SearchResults); - providers_.push_back(new TestSearchProvider("app")); - providers_.push_back(new TestSearchProvider("omnibox")); - providers_.push_back(new TestSearchProvider("webstore")); + providers_.push_back(base::MakeUnique<TestSearchProvider>("app")); + providers_.push_back(base::MakeUnique<TestSearchProvider>("omnibox")); + providers_.push_back(base::MakeUnique<TestSearchProvider>("webstore")); is_voice_query_ = false; @@ -134,9 +135,9 @@ size_t omnibox_group_id = mixer_->AddGroup(kMaxOmniboxResults, 1.0); size_t webstore_group_id = mixer_->AddGroup(kMaxWebstoreResults, 0.5); - mixer_->AddProviderToGroup(apps_group_id, providers_[0]); - mixer_->AddProviderToGroup(omnibox_group_id, providers_[1]); - mixer_->AddProviderToGroup(webstore_group_id, providers_[2]); + mixer_->AddProviderToGroup(apps_group_id, providers_[0].get()); + mixer_->AddProviderToGroup(omnibox_group_id, providers_[1].get()); + mixer_->AddProviderToGroup(webstore_group_id, providers_[2].get()); } void RunQuery() { @@ -163,9 +164,9 @@ } Mixer* mixer() { return mixer_.get(); } - TestSearchProvider* app_provider() { return providers_[0]; } - TestSearchProvider* omnibox_provider() { return providers_[1]; } - TestSearchProvider* webstore_provider() { return providers_[2]; } + TestSearchProvider* app_provider() { return providers_[0].get(); } + TestSearchProvider* omnibox_provider() { return providers_[1].get(); } + TestSearchProvider* webstore_provider() { return providers_[2].get(); } // Sets whether test runs should be treated as a voice query. void set_is_voice_query(bool is_voice_query) { @@ -183,7 +184,7 @@ bool is_voice_query_; - ScopedVector<TestSearchProvider> providers_; + std::vector<std::unique_ptr<TestSearchProvider>> providers_; DISALLOW_COPY_AND_ASSIGN(MixerTest); };
diff --git a/ui/app_list/views/app_list_main_view.h b/ui/app_list/views/app_list_main_view.h index bee65ddb..790bc44 100644 --- a/ui/app_list/views/app_list_main_view.h +++ b/ui/app_list/views/app_list_main_view.h
@@ -8,7 +8,6 @@ #include <string> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "base/timer/timer.h" #include "ui/app_list/app_list_export.h"
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc b/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc index 720dfd5..519ffe4 100644 --- a/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc +++ b/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc
@@ -11,7 +11,6 @@ #include "base/bind.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/event.h"
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h index 9ae1956f..c453b67d 100644 --- a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h +++ b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h
@@ -18,7 +18,6 @@ #include <vector> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/events/ozone/evdev/event_device_info.h" #include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
diff --git a/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc index 30bd240..ecbd840 100644 --- a/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc +++ b/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc
@@ -17,7 +17,6 @@ #include "base/files/file_util.h" #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/memory/scoped_vector.h" #include "base/posix/eintr_wrapper.h" #include "base/run_loop.h" #include "base/time/time.h"
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc index ebe3f2f..cbc9c27 100644 --- a/ui/gfx/render_text_harfbuzz.cc +++ b/ui/gfx/render_text_harfbuzz.cc
@@ -491,7 +491,8 @@ // no larger than |available_width_|. size_t GetCutoffPos(const internal::LineSegment& segment) const { DCHECK(!segment.char_range.is_empty()); - const internal::TextRunHarfBuzz& run = *(run_list_.runs()[segment.run]); + const internal::TextRunHarfBuzz& run = + *(run_list_.runs()[segment.run]).get(); size_t end_pos = segment.char_range.start(); SkScalar width = 0; while (end_pos < segment.char_range.end()) { @@ -804,7 +805,7 @@ // Precalculate run width information. width_ = 0.0f; for (size_t i = 0; i < runs_.size(); ++i) { - TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; + const auto& run = runs_[visual_to_logical_[i]]; run->preceding_run_widths = width_; width_ += run->width; } @@ -943,7 +944,7 @@ internal::TextRunList* run_list = GetRunList(); std::vector<RenderText::FontSpan> spans; - for (auto* run : run_list->runs()) { + for (const auto& run : run_list->runs()) { spans.push_back(RenderText::FontSpan( run->font, Range(DisplayIndexToTextIndex(run->range.start()), DisplayIndexToTextIndex(run->range.end())))); @@ -961,7 +962,7 @@ if (run_index >= run_list->size()) return Range(GetStringSize().width()); const size_t layout_index = TextIndexToDisplayIndex(index); - internal::TextRunHarfBuzz* run = run_list->runs()[run_index]; + internal::TextRunHarfBuzz* run = run_list->runs()[run_index].get(); RangeF bounds = run->GetGraphemeBounds(this, layout_index); // If cursor is enabled, extend the last glyph up to the rightmost cursor // position since clients expect them to be contiguous. @@ -1003,11 +1004,11 @@ if (edge.caret_pos() == selection.caret_pos()) return edge; int visual_index = (direction == CURSOR_RIGHT) ? 0 : run_list->size() - 1; - run = run_list->runs()[run_list->visual_to_logical(visual_index)]; + run = run_list->runs()[run_list->visual_to_logical(visual_index)].get(); } else { // If the cursor is moving within the current run, just move it by one // grapheme in the appropriate direction. - run = run_list->runs()[run_index]; + run = run_list->runs()[run_index].get(); size_t caret = selection.caret_pos(); bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); if (forward_motion) { @@ -1026,7 +1027,7 @@ visual_index += (direction == CURSOR_LEFT) ? -1 : 1; if (visual_index < 0 || visual_index >= static_cast<int>(run_list->size())) return EdgeSelectionModel(direction); - run = run_list->runs()[run_list->visual_to_logical(visual_index)]; + run = run_list->runs()[run_list->visual_to_logical(visual_index)].get(); } bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); return forward_motion ? FirstSelectionModelInsideRun(run) : @@ -1317,7 +1318,7 @@ LogicalCursorDirection affinity = caret.caret_affinity(); internal::TextRunList* run_list = GetRunList(); for (size_t i = 0; i < run_list->size(); ++i) { - internal::TextRunHarfBuzz* run = run_list->runs()[i]; + internal::TextRunHarfBuzz* run = run_list->runs()[i].get(); if (RangeContainsCaret(run->range, layout_position, affinity)) return i; } @@ -1348,10 +1349,10 @@ // to misbehave since they expect non-zero text metrics from a non-empty text. base::i18n::BiDiLineIterator bidi_iterator; if (!bidi_iterator.Open(text, GetTextDirection(text))) { - internal::TextRunHarfBuzz* run = - new internal::TextRunHarfBuzz(font_list().GetPrimaryFont()); + auto run = base::MakeUnique<internal::TextRunHarfBuzz>( + font_list().GetPrimaryFont()); run->range = Range(0, text.length()); - run_list_out->add(run); + run_list_out->Add(std::move(run)); run_list_out->InitIndexMap(); return; } @@ -1369,8 +1370,8 @@ internal::StyleIterator style(empty_colors, baselines(), weights(), styles()); for (size_t run_break = 0; run_break < text.length();) { - internal::TextRunHarfBuzz* run = - new internal::TextRunHarfBuzz(font_list().GetPrimaryFont()); + auto run = base::MakeUnique<internal::TextRunHarfBuzz>( + font_list().GetPrimaryFont()); run->range.set_start(run_break); run->italic = style.style(ITALIC); run->baseline_type = style.baseline(); @@ -1406,7 +1407,7 @@ style.UpdatePosition(DisplayIndexToTextIndex(run_break)); run->range.set_end(run_break); - run_list_out->add(run); + run_list_out->Add(std::move(run)); } // Undo the temporarily applied composition underlines and selection colors. @@ -1437,8 +1438,8 @@ void RenderTextHarfBuzz::ShapeRunList(const base::string16& text, internal::TextRunList* run_list) { - for (auto* run : run_list->runs()) - ShapeRun(text, run); + for (const auto& run : run_list->runs()) + ShapeRun(text, run.get()); run_list->ComputePrecedingRunWidths(); }
diff --git a/ui/gfx/render_text_harfbuzz.h b/ui/gfx/render_text_harfbuzz.h index 4f52cdee..3c31f51 100644 --- a/ui/gfx/render_text_harfbuzz.h +++ b/ui/gfx/render_text_harfbuzz.h
@@ -9,9 +9,9 @@ #include <stdint.h> #include <memory> +#include <vector> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "third_party/harfbuzz-ng/src/hb.h" #include "third_party/icu/source/common/unicode/ubidi.h" #include "third_party/icu/source/common/unicode/uscript.h" @@ -109,10 +109,14 @@ return logical_to_visual_[index]; } - const ScopedVector<TextRunHarfBuzz>& runs() const { return runs_; } + const std::vector<std::unique_ptr<TextRunHarfBuzz>>& runs() const { + return runs_; + } // Adds the new |run| to the run list. - void add(TextRunHarfBuzz* run) { runs_.push_back(run); } + void Add(std::unique_ptr<TextRunHarfBuzz> run) { + runs_.push_back(std::move(run)); + } // Reset the run list. void Reset(); @@ -132,7 +136,7 @@ private: // Text runs in logical order. - ScopedVector<TextRunHarfBuzz> runs_; + std::vector<std::unique_ptr<TextRunHarfBuzz>> runs_; // Maps visual run indices to logical run indices and vice versa. std::vector<int32_t> visual_to_logical_;
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index 0f3e5e9..a565606 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc
@@ -3434,7 +3434,7 @@ test_api()->EnsureLayout(); internal::TextRunList* run_list = GetHarfBuzzRunList(); ASSERT_EQ(1U, run_list->size()); - internal::TextRunHarfBuzz* run = run_list->runs()[0]; + internal::TextRunHarfBuzz* run = run_list->runs()[0].get(); auto first_grapheme_bounds = run->GetGraphemeBounds(render_text, 0); EXPECT_EQ(first_grapheme_bounds, run->GetGraphemeBounds(render_text, 1)); @@ -3613,7 +3613,7 @@ test_api()->EnsureLayout(); internal::TextRunList* run_list = GetHarfBuzzRunList(); ASSERT_EQ(1U, run_list->size()); - internal::TextRunHarfBuzz* run = run_list->runs()[0]; + internal::TextRunHarfBuzz* run = run_list->runs()[0].get(); ShapeRunWithFont(render_text->text(), Font("TheFontThatDoesntExist", 13), FontRenderParams(), run); }
diff --git a/ui/keyboard/keyboard_util.cc b/ui/keyboard/keyboard_util.cc index b6bd071..b9bb9e00 100644 --- a/ui/keyboard/keyboard_util.cc +++ b/ui/keyboard/keyboard_util.cc
@@ -54,6 +54,8 @@ bool g_touch_keyboard_enabled = false; +bool g_overscroll_enabled_with_accessibility_keyboard = false; + keyboard::KeyboardState g_requested_keyboard_state = keyboard::KEYBOARD_STATE_AUTO; @@ -145,8 +147,10 @@ // Users of the accessibility on-screen keyboard are likely to be using mouse // input, which may interfere with overscrolling. - if (g_accessibility_keyboard_enabled) + if (g_accessibility_keyboard_enabled && + !g_overscroll_enabled_with_accessibility_keyboard) { return false; + } // If overscroll enabled override is set, use it instead. Currently // login / out-of-box disable keyboard overscroll. http://crbug.com/363635 @@ -393,4 +397,8 @@ keyboard::KEYBOARD_CONTROL_MAX); } +void SetOverscrollEnabledWithAccessibilityKeyboard(bool enabled) { + g_overscroll_enabled_with_accessibility_keyboard = enabled; +} + } // namespace keyboard
diff --git a/ui/keyboard/keyboard_util.h b/ui/keyboard/keyboard_util.h index d32b098..ce4df68 100644 --- a/ui/keyboard/keyboard_util.h +++ b/ui/keyboard/keyboard_util.h
@@ -178,6 +178,10 @@ // Logs the keyboard control event as a UMA stat. void LogKeyboardControlEvent(KeyboardControlEvent event); +// Sets true if keyboard overscrolling is enabled with accessibility keyboard. +KEYBOARD_EXPORT void SetOverscrollEnabledWithAccessibilityKeyboard( + bool enabled); + } // namespace keyboard #endif // UI_KEYBOARD_KEYBOARD_UTIL_H_
diff --git a/ui/message_center/message_center_impl.cc b/ui/message_center/message_center_impl.cc index aa27168..0db1a54 100644 --- a/ui/message_center/message_center_impl.cc +++ b/ui/message_center/message_center_impl.cc
@@ -6,11 +6,13 @@ #include <algorithm> #include <deque> +#include <memory> #include <utility> +#include <vector> #include "base/command_line.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" +#include "base/memory/ptr_util.h" #include "base/observer_list.h" #include "base/stl_util.h" #include "build/build_config.h" @@ -117,7 +119,7 @@ void ApplyChangeInternal(MessageCenterImpl* message_center, std::unique_ptr<Change> change); - ScopedVector<Change> changes_; + std::vector<std::unique_ptr<Change>> changes_; DISALLOW_COPY_AND_ASSIGN(ChangeQueue); }; @@ -127,7 +129,9 @@ struct ChangeFinder { explicit ChangeFinder(const std::string& id) : id(id) {} - bool operator()(ChangeQueue::Change* change) { return change->id() == id; } + bool operator()(const std::unique_ptr<ChangeQueue::Change>& change) { + return change->id() == id; + } std::string id; }; @@ -170,10 +174,10 @@ void ChangeQueue::ApplyChanges(MessageCenterImpl* message_center) { // This method is re-entrant. while (!changes_.empty()) { - ScopedVector<Change>::iterator iter = changes_.begin(); - std::unique_ptr<Change> change(*iter); + auto iter = changes_.begin(); + std::unique_ptr<Change> change(std::move(*iter)); // TODO(dewittj): Replace changes_ with a deque. - changes_.weak_erase(iter); + changes_.erase(iter); ApplyChangeInternal(message_center, std::move(change)); } } @@ -185,16 +189,16 @@ // Traverses the queue in reverse so shat we can track changes which change // the notification's ID. - ScopedVector<Change>::iterator iter = changes_.end(); + auto iter = changes_.end(); while (iter != changes_.begin()) { --iter; if (interesting_id != (*iter)->id()) continue; - std::unique_ptr<Change> change(*iter); + std::unique_ptr<Change> change(std::move(*iter)); interesting_id = change->notification_list_id(); - iter = changes_.weak_erase(iter); + iter = changes_.erase(iter); changes_for_id.push_back(change.release()); } @@ -207,21 +211,22 @@ void ChangeQueue::AddNotification(std::unique_ptr<Notification> notification) { std::string id = notification->id(); - changes_.push_back(new Change(CHANGE_TYPE_ADD, id, std::move(notification))); + changes_.push_back( + base::MakeUnique<Change>(CHANGE_TYPE_ADD, id, std::move(notification))); } void ChangeQueue::UpdateNotification( const std::string& old_id, std::unique_ptr<Notification> notification) { - ScopedVector<Change>::reverse_iterator iter = - std::find_if(changes_.rbegin(), changes_.rend(), ChangeFinder(old_id)); + auto iter = + std::find_if(changes_.rbegin(), changes_.rend(), ChangeFinder(old_id)); if (iter == changes_.rend()) { - changes_.push_back( - new Change(CHANGE_TYPE_UPDATE, old_id, std::move(notification))); + changes_.push_back(base::MakeUnique<Change>(CHANGE_TYPE_UPDATE, old_id, + std::move(notification))); return; } - Change* change = *iter; + Change* change = iter->get(); switch (change->type()) { case CHANGE_TYPE_ADD: { std::string id = notification->id(); @@ -229,8 +234,8 @@ // its ID, some previous changes may affect new ID. // (eg. Add A, Update B->C, and This update A->B). changes_.erase(--(iter.base())); - changes_.push_back( - new Change(CHANGE_TYPE_ADD, id, std::move(notification))); + changes_.push_back(base::MakeUnique<Change>(CHANGE_TYPE_ADD, id, + std::move(notification))); break; } case CHANGE_TYPE_UPDATE: @@ -241,18 +246,18 @@ std::string id = notification->id(); // Safe to place the change at the last. changes_.erase(--(iter.base())); - changes_.push_back( - new Change(CHANGE_TYPE_ADD, id, std::move(notification))); + changes_.push_back(base::MakeUnique<Change>(CHANGE_TYPE_ADD, id, + std::move(notification))); } else { // Complex case: gives up to optimize. - changes_.push_back( - new Change(CHANGE_TYPE_UPDATE, old_id, std::move(notification))); + changes_.push_back(base::MakeUnique<Change>(CHANGE_TYPE_UPDATE, old_id, + std::move(notification))); } break; case CHANGE_TYPE_DELETE: // DELETE -> UPDATE. Something is wrong. Treats the UPDATE as ADD. - changes_.push_back( - new Change(CHANGE_TYPE_ADD, old_id, std::move(notification))); + changes_.push_back(base::MakeUnique<Change>(CHANGE_TYPE_ADD, old_id, + std::move(notification))); break; default: NOTREACHED(); @@ -260,16 +265,16 @@ } void ChangeQueue::EraseNotification(const std::string& id, bool by_user) { - ScopedVector<Change>::reverse_iterator iter = - std::find_if(changes_.rbegin(), changes_.rend(), ChangeFinder(id)); + auto iter = + std::find_if(changes_.rbegin(), changes_.rend(), ChangeFinder(id)); if (iter == changes_.rend()) { - std::unique_ptr<Change> change(new Change(CHANGE_TYPE_DELETE, id, nullptr)); + auto change = base::MakeUnique<Change>(CHANGE_TYPE_DELETE, id, nullptr); change->set_by_user(by_user); changes_.push_back(std::move(change)); return; } - Change* change = *iter; + Change* change = iter->get(); switch (change->type()) { case CHANGE_TYPE_ADD: // ADD -> DELETE. Just removes both. @@ -292,14 +297,12 @@ } bool ChangeQueue::Has(const std::string& id) const { - ScopedVector<Change>::const_iterator iter = - std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id)); + auto iter = std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id)); return iter != changes_.end(); } Notification* ChangeQueue::GetLatestNotification(const std::string& id) const { - ScopedVector<Change>::const_iterator iter = - std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id)); + auto iter = std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id)); if (iter == changes_.end()) return NULL;
diff --git a/ui/ozone/demo/ozone_demo.cc b/ui/ozone/demo/ozone_demo.cc index a501fe79..42c08c3 100644 --- a/ui/ozone/demo/ozone_demo.cc +++ b/ui/ozone/demo/ozone_demo.cc
@@ -8,7 +8,6 @@ #include "base/command_line.h" #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/task_scheduler/task_scheduler.h"
diff --git a/ui/ozone/platform/drm/common/drm_util.cc b/ui/ozone/platform/drm/common/drm_util.cc index eb0501c..9d41e98ad 100644 --- a/ui/ozone/platform/drm/common/drm_util.cc +++ b/ui/ozone/platform/drm/common/drm_util.cc
@@ -14,6 +14,7 @@ #include <utility> #include "base/containers/small_map.h" +#include "base/memory/ptr_util.h" #include "ui/display/util/edid_parser.h" #if !defined(DRM_FORMAT_YV12) @@ -28,8 +29,10 @@ static const size_t kDefaultCursorWidth = 64; static const size_t kDefaultCursorHeight = 64; -bool IsCrtcInUse(uint32_t crtc, - const ScopedVector<HardwareDisplayControllerInfo>& displays) { +bool IsCrtcInUse( + uint32_t crtc, + const std::vector<std::unique_ptr<HardwareDisplayControllerInfo>>& + displays) { for (size_t i = 0; i < displays.size(); ++i) { if (crtc == displays[i]->crtc()->crtc_id) return true; @@ -41,10 +44,12 @@ // Return a CRTC compatible with |connector| and not already used in |displays|. // If there are multiple compatible CRTCs, the one that supports the majority of // planes will be returned. -uint32_t GetCrtc(int fd, - drmModeConnector* connector, - drmModeRes* resources, - const ScopedVector<HardwareDisplayControllerInfo>& displays) { +uint32_t GetCrtc( + int fd, + drmModeConnector* connector, + drmModeRes* resources, + const std::vector<std::unique_ptr<HardwareDisplayControllerInfo>>& + displays) { ScopedDrmPlaneResPtr plane_resources(drmModeGetPlaneResources(fd)); std::vector<ScopedDrmPlanePtr> planes; for (uint32_t i = 0; i < plane_resources->count_planes; i++) @@ -218,11 +223,11 @@ HardwareDisplayControllerInfo::~HardwareDisplayControllerInfo() { } -ScopedVector<HardwareDisplayControllerInfo> GetAvailableDisplayControllerInfos( - int fd) { +std::vector<std::unique_ptr<HardwareDisplayControllerInfo>> +GetAvailableDisplayControllerInfos(int fd) { ScopedDrmResourcesPtr resources(drmModeGetResources(fd)); DCHECK(resources) << "Failed to get DRM resources"; - ScopedVector<HardwareDisplayControllerInfo> displays; + std::vector<std::unique_ptr<HardwareDisplayControllerInfo>> displays; std::vector<ScopedDrmConnectorPtr> available_connectors; std::vector<ScopedDrmConnectorPtr::element_type*> connectors; @@ -270,7 +275,7 @@ size_t index = std::find(connectors.begin(), connectors.end(), c.get()) - connectors.begin(); DCHECK_LT(index, connectors.size()); - displays.push_back(new HardwareDisplayControllerInfo( + displays.push_back(base::MakeUnique<HardwareDisplayControllerInfo>( std::move(c), std::move(crtc), index)); }
diff --git a/ui/ozone/platform/drm/common/drm_util.h b/ui/ozone/platform/drm/common/drm_util.h index 17a62bb..52e90fe 100644 --- a/ui/ozone/platform/drm/common/drm_util.h +++ b/ui/ozone/platform/drm/common/drm_util.h
@@ -7,9 +7,11 @@ #include <stddef.h> +#include <memory> +#include <vector> + #include "base/files/file_path.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/ozone/common/gpu/ozone_gpu_message_params.h" #include "ui/ozone/platform/drm/common/scoped_drm_types.h" @@ -45,8 +47,8 @@ // Looks-up and parses the native display configurations returning all available // displays. -ScopedVector<HardwareDisplayControllerInfo> GetAvailableDisplayControllerInfos( - int fd); +std::vector<std::unique_ptr<HardwareDisplayControllerInfo>> +GetAvailableDisplayControllerInfos(int fd); bool SameMode(const drmModeModeInfo& lhs, const drmModeModeInfo& rhs);
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc index 0d406a96..100c7a4 100644 --- a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc +++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -75,9 +75,8 @@ const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices(); size_t device_index = 0; for (const auto& drm : devices) { - ScopedVector<HardwareDisplayControllerInfo> display_infos = - GetAvailableDisplayControllerInfos(drm->get_fd()); - for (auto* display_info : display_infos) { + auto display_infos = GetAvailableDisplayControllerInfos(drm->get_fd()); + for (const auto& display_info : display_infos) { auto it = std::find_if( old_displays.begin(), old_displays.end(), DisplayComparator(drm, display_info->crtc()->crtc_id, @@ -89,7 +88,7 @@ displays_.push_back(base::MakeUnique<DrmDisplay>(screen_manager_, drm)); } params_list.push_back( - displays_.back()->Update(display_info, device_index)); + displays_.back()->Update(display_info.get(), device_index)); } device_index++; }
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h index 068a62a1..389dfc5 100644 --- a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h +++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
@@ -7,8 +7,10 @@ #include <stdint.h> +#include <memory> +#include <vector> + #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc index 989eec4..24e17c7 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc +++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -41,7 +41,7 @@ HasEGLExtension("EGL_EXT_image_flush_external")), weak_factory_(this) { surface_factory_->RegisterSurface(window_->widget(), this); - unsubmitted_frames_.push_back(new PendingFrame()); + unsubmitted_frames_.push_back(base::MakeUnique<PendingFrame>()); } void GbmSurfaceless::QueueOverlayPlane(const OverlayPlane& plane) { @@ -111,9 +111,9 @@ SwapCompletionCallback surface_swap_callback = base::Bind( &GbmSurfaceless::SwapCompleted, weak_factory_.GetWeakPtr(), callback); - PendingFrame* frame = unsubmitted_frames_.back(); + PendingFrame* frame = unsubmitted_frames_.back().get(); frame->callback = surface_swap_callback; - unsubmitted_frames_.push_back(new PendingFrame()); + unsubmitted_frames_.push_back(base::MakeUnique<PendingFrame>()); // TODO: the following should be replaced by a per surface flush as it gets // implemented in GL drivers. @@ -198,8 +198,8 @@ DCHECK(!unsubmitted_frames_.empty()); if (unsubmitted_frames_.front()->ready && !swap_buffers_pending_) { - std::unique_ptr<PendingFrame> frame(unsubmitted_frames_.front()); - unsubmitted_frames_.weak_erase(unsubmitted_frames_.begin()); + std::unique_ptr<PendingFrame> frame(std::move(unsubmitted_frames_.front())); + unsubmitted_frames_.erase(unsubmitted_frames_.begin()); swap_buffers_pending_ = true; if (!frame->ScheduleOverlayPlanes(widget_)) {
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h index c800f1a..91b944c 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h +++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -9,7 +9,6 @@ #include <vector> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "ui/gfx/native_widget_types.h" #include "ui/gl/gl_image.h" @@ -92,7 +91,7 @@ // The native surface. Deleting this is allowed to free the EGLNativeWindow. gfx::AcceleratedWidget widget_; std::unique_ptr<gfx::VSyncProvider> vsync_provider_; - ScopedVector<PendingFrame> unsubmitted_frames_; + std::vector<std::unique_ptr<PendingFrame>> unsubmitted_frames_; bool has_implicit_external_sync_; bool has_image_flush_external_; bool last_swap_buffers_result_ = true;
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/ui/ozone/platform/drm/gpu/hardware_display_controller.h index eda2ce3..1851ee4f 100644 --- a/ui/ozone/platform/drm/gpu/hardware_display_controller.h +++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.h
@@ -17,7 +17,6 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/gfx/swap_result.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h" #include "ui/ozone/platform/drm/gpu/overlay_plane.h"
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h index 800aa5a..15538c5 100644 --- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h +++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -11,7 +11,6 @@ #include <vector> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/ozone/platform/drm/common/scoped_drm_types.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane.h" #include "ui/ozone/platform/drm/gpu/overlay_plane.h"
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.h b/ui/ozone/platform/drm/gpu/screen_manager.h index 7785b94..3854422 100644 --- a/ui/ozone/platform/drm/gpu/screen_manager.h +++ b/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -10,7 +10,6 @@ #include <unordered_map> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/observer_list.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc index ae8b0516..c603352 100644 --- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc +++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -139,14 +139,15 @@ proxy_->RegisterHandlerForDrmDisplayHostManager(this); proxy_->AddGpuThreadObserver(this); - ScopedVector<HardwareDisplayControllerInfo> display_infos = + auto display_infos = GetAvailableDisplayControllerInfos(primary_drm_device_handle_->fd()); has_dummy_display_ = !display_infos.empty(); - for (size_t i = 0; i < display_infos.size(); ++i) { + for (const auto& display_info : display_infos) { displays_.push_back(base::MakeUnique<DrmDisplayHost>( - proxy_, CreateDisplaySnapshotParams( - display_infos[i], primary_drm_device_handle_->fd(), - primary_drm_device_handle_->sys_path(), 0, gfx::Point()), + proxy_, + CreateDisplaySnapshotParams( + display_info.get(), primary_drm_device_handle_->fd(), + primary_drm_device_handle_->sys_path(), 0, gfx::Point()), true /* is_dummy */)); } }
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.h b/ui/ozone/platform/drm/host/drm_display_host_manager.h index c2b68e6f..48097c7 100644 --- a/ui/ozone/platform/drm/host/drm_display_host_manager.h +++ b/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -14,7 +14,6 @@ #include "base/file_descriptor_posix.h" #include "base/files/scoped_file.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "ui/display/types/native_display_delegate.h" #include "ui/events/ozone/device/device_event.h"
diff --git a/ui/ozone/platform/drm/host/drm_overlay_manager.h b/ui/ozone/platform/drm/host/drm_overlay_manager.h index 7731eec..8afad3bb 100644 --- a/ui/ozone/platform/drm/host/drm_overlay_manager.h +++ b/ui/ozone/platform/drm/host/drm_overlay_manager.h
@@ -11,7 +11,6 @@ #include "base/containers/mru_cache.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/ozone/platform/drm/host/gpu_thread_adapter.h" #include "ui/ozone/public/overlay_candidates_ozone.h" #include "ui/ozone/public/overlay_manager_ozone.h"
diff --git a/ui/views/examples/text_example.cc b/ui/views/examples/text_example.cc index 0e65163..58e9994 100644 --- a/ui/views/examples/text_example.cc +++ b/ui/views/examples/text_example.cc
@@ -5,6 +5,7 @@ #include "ui/views/examples/text_example.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font_list.h" @@ -137,9 +138,9 @@ int count) { layout->StartRow(0, 0); layout->AddView(new Label(base::ASCIIToUTF16(name))); - ExampleComboboxModel* model = new ExampleComboboxModel(strings, count); - example_combobox_model_.push_back(model); - Combobox* combobox = new Combobox(model); + example_combobox_model_.push_back( + base::MakeUnique<ExampleComboboxModel>(strings, count)); + Combobox* combobox = new Combobox(example_combobox_model_.back().get()); combobox->SetSelectedIndex(0); combobox->set_listener(this); layout->AddView(combobox, kNumColumns - 1, 1);
diff --git a/ui/views/examples/text_example.h b/ui/views/examples/text_example.h index ad3090f..9f13a95 100644 --- a/ui/views/examples/text_example.h +++ b/ui/views/examples/text_example.h
@@ -5,8 +5,10 @@ #ifndef UI_VIEWS_EXAMPLES_TEXT_EXAMPLE_H_ #define UI_VIEWS_EXAMPLES_TEXT_EXAMPLE_H_ +#include <memory> +#include <vector> + #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/combobox/combobox_listener.h" #include "ui/views/examples/example_base.h" @@ -81,7 +83,7 @@ // We create a model for each of the combobox, so we need to keep them // around until destruction time. - ScopedVector<ExampleComboboxModel> example_combobox_model_; + std::vector<std::unique_ptr<ExampleComboboxModel>> example_combobox_model_; DISALLOW_COPY_AND_ASSIGN(TextExample); };