diff --git a/BUILD.gn b/BUILD.gn index d27481923..a5dfc16 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -739,7 +739,7 @@ if (target_cpu == "x86") { if (is_clang) { - deps += [ "//courgette(//build/toolchain/win:clang_x64)" ] + deps += [ "//courgette(//build/toolchain/win:win_clang_x64)" ] } else { deps += [ "//courgette(//build/toolchain/win:x64)" ] }
diff --git a/DEPS b/DEPS index e8a3175e..56dad3e2 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': 'd3e247ff439da39d17bf646ce2bfe591abf90b56', + 'skia_revision': '92376017d9ee317ebc1393cc38937f9a86289c71', # 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': '317f204b01f95cc6d6ed6290827cabb5d01e929c', + 'v8_revision': '84c765c274c689b2c51ecb7a52c256629c464565', # 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. @@ -244,7 +244,7 @@ Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248 'src/third_party/libyuv': - Var('chromium_git') + '/libyuv/libyuv.git' + '@' + 'd8136924bd0bef0cf39ef379d03196950ce58418', # from r1662 + Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '56022ef77fab3ce5a7c8ee44bd095c22a94bff5b', 'src/third_party/smhasher/src': Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f',
diff --git a/WATCHLISTS b/WATCHLISTS index 9fa14fa..47c22268 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -266,7 +266,8 @@ }, 'cast_channel': { 'filepath': 'chrome/test/data/extensions/api_test/cast_channel/' \ - '|extensions/(browser|common)/api/cast_channel' + '|components/cast_channel/' \ + '|extensions/browser/api/cast_channel' }, 'certificate_transparency': { 'filepath': 'components/certificate_transparency/'\ @@ -564,6 +565,9 @@ 'importer': { 'filepath': 'import', }, + 'incident_reporting': { + 'filepath': 'chrome/browser/safe_browsing/incident_reporting', + }, 'indexed_db': { 'filepath': 'content/browser/indexed_db|'\ 'content/child/indexed_db|'\ @@ -583,12 +587,13 @@ 'installable': { 'filepath': 'chrome/browser/installable/', }, - 'installer': { - 'filepath': 'chrome/install(_static|er)/', - }, 'installer_linux': { 'filepath': 'chrome/installer/linux/', }, + 'installer_win': { + 'filepath': 'chrome/install_static/'\ + '|chrome/installer/(?!gcapi_mac/|linux/|mac/)', + }, 'instant': { 'filepath': 'instant|searchbox|'\ 'chrome/browser/search/|'\ @@ -1941,7 +1946,8 @@ 'cast_certificate': ['dougsteed+watch@chromium.org', 'mfoltz+watch@chromium.org', 'ryanchung+watch@chromium.org'], - 'cast_channel': ['mfoltz+watch@chromium.org'], + 'cast_channel': ['mfoltz+watch@chromium.org', + 'ryanchung+watch@chromium.org'], 'cc': ['cc-bugs@chromium.org'], 'certificate_transparency': ['certificate-transparency-chrome@googlegroups.com', 'eranm@chromium.org', @@ -2063,15 +2069,16 @@ 'hotword': ['rlp+watch@chromium.org'], 'i18n': ['jshin+watch@chromium.org'], 'importer': ['tfarina@chromium.org'], + 'incident_reporting': ['grt+watch@chromium.org'], 'indexed_db': ['cmumford@chromium.org', 'jsbell+idb@chromium.org'], 'ink_drop': ['bruthig+ink_drop@chromium.org'], 'input': ['dtapuska+chromiumwatch@chromium.org'], 'installable': ['dominickn+watch@chromium.org'], - 'installer': ['grt+watch@chromium.org', - 'pennymac+watch@chromium.org', - 'wfh+watch@chromium.org'], 'installer_linux': [ 'mmoss@chromium.org'], + 'installer_win': ['grt+watch@chromium.org', + 'pennymac+watch@chromium.org', + 'wfh+watch@chromium.org'], 'instant': ['dcblack@chromium.org', 'donnd+watch@chromium.org', 'jered+watch@chromium.org', @@ -2217,8 +2224,7 @@ 'rlz_id': ['alito+watch@chromium.org', 'gab+watch@chromium.org', 'robertshield+watch@chromium.org'], - 'safe_browsing': ['grt+watch@chromium.org', - 'timvolodine@chromium.org', + 'safe_browsing': ['timvolodine@chromium.org', 'vakh+watch@chromium.org'], 'safe_browsing_db': ['timvolodine@chromium.org', 'vakh+watch@chromium.org'],
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 5e49c36..6aecbb0 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -125,6 +125,8 @@ "drag_drop/drag_drop_tracker.h", "drag_drop/drag_image_view.cc", "drag_drop/drag_image_view.h", + "fast_ink/fast_ink_points.cc", + "fast_ink/fast_ink_points.h", "fast_ink/fast_ink_view.cc", "fast_ink/fast_ink_view.h", "first_run/desktop_cleaner.cc", @@ -190,8 +192,6 @@ "keyboard/keyboard_ui_observer.h", "laser/laser_pointer_controller.cc", "laser/laser_pointer_controller.h", - "laser/laser_pointer_points.cc", - "laser/laser_pointer_points.h", "laser/laser_pointer_view.cc", "laser/laser_pointer_view.h", "laser/laser_segment_utils.cc", @@ -1169,6 +1169,7 @@ "autoclick/autoclick_unittest.cc", "display/display_configuration_controller_unittest.cc", "drag_drop/drag_image_view_unittest.cc", + "fast_ink/fast_ink_points_unittest.cc", "first_run/first_run_helper_unittest.cc", "focus_cycler_unittest.cc", "frame/caption_buttons/frame_caption_button_container_view_unittest.cc", @@ -1178,7 +1179,6 @@ "highlighter/highlighter_gesture_util_unittest.cc", "ime/ime_controller_unittest.cc", "laser/laser_pointer_controller_unittest.cc", - "laser/laser_pointer_points_unittest.cc", "laser/laser_segment_utils_unittest.cc", "login/lock_screen_controller_unittest.cc", "login/mock_lock_screen_client.cc", @@ -1650,8 +1650,6 @@ "keyboard/test_keyboard_ui.h", "laser/laser_pointer_controller_test_api.cc", "laser/laser_pointer_controller_test_api.h", - "laser/laser_pointer_points_test_api.cc", - "laser/laser_pointer_points_test_api.h", "metrics/task_switch_time_tracker_test_api.cc", "metrics/task_switch_time_tracker_test_api.h", "metrics/user_metrics_recorder_test_api.cc",
diff --git a/ash/fast_ink/fast_ink_points.cc b/ash/fast_ink/fast_ink_points.cc new file mode 100644 index 0000000..90e15e8 --- /dev/null +++ b/ash/fast_ink/fast_ink_points.cc
@@ -0,0 +1,184 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/fast_ink/fast_ink_points.h" + +#include <algorithm> +#include <array> +#include <limits> + +#include "base/containers/adapters.h" +#include "ui/gfx/geometry/point_f.h" +#include "ui/gfx/geometry/rect_conversions.h" + +namespace ash { + +FastInkPoints::FastInkPoints(base::TimeDelta life_duration) + : life_duration_(life_duration) {} + +FastInkPoints::~FastInkPoints() {} + +void FastInkPoints::AddPoint(const gfx::PointF& point, + const base::TimeTicks& time) { + FastInkPoint new_point; + new_point.location = point; + new_point.time = time; + points_.push_back(new_point); +} + +void FastInkPoints::MoveForwardToTime(const base::TimeTicks& latest_time) { + DCHECK_GE(latest_time, collection_latest_time_); + collection_latest_time_ = latest_time; + + if (!points_.empty() && !life_duration_.is_zero()) { + // Remove obsolete points. + const base::TimeTicks expiration = latest_time - life_duration_; + auto first_alive_point = std::find_if( + points_.begin(), points_.end(), + [expiration](const FastInkPoint& p) { return p.time > expiration; }); + points_.erase(points_.begin(), first_alive_point); + } +} + +void FastInkPoints::Clear() { + points_.clear(); +} + +gfx::Rect FastInkPoints::GetBoundingBox() const { + if (IsEmpty()) + return gfx::Rect(); + + gfx::PointF min_point = GetOldest().location; + gfx::PointF max_point = GetOldest().location; + for (const FastInkPoint& point : points_) { + min_point.SetToMin(point.location); + max_point.SetToMax(point.location); + } + return gfx::ToEnclosingRect(gfx::BoundingRect(min_point, max_point)); +} + +FastInkPoints::FastInkPoint FastInkPoints::GetOldest() const { + DCHECK(!IsEmpty()); + return points_.front(); +} + +FastInkPoints::FastInkPoint FastInkPoints::GetNewest() const { + DCHECK(!IsEmpty()); + return points_.back(); +} + +bool FastInkPoints::IsEmpty() const { + return points_.empty(); +} + +int FastInkPoints::GetNumberOfPoints() const { + return points_.size(); +} + +const std::deque<FastInkPoints::FastInkPoint>& FastInkPoints::points() const { + return points_; +} + +float FastInkPoints::GetFadeoutFactor(int index) const { + DCHECK(!life_duration_.is_zero()); + DCHECK(0 <= index && index < GetNumberOfPoints()); + base::TimeDelta age = collection_latest_time_ - points_[index].time; + return std::min(age.InMillisecondsF() / life_duration_.InMillisecondsF(), + 1.0); +} + +void FastInkPoints::Predict(const FastInkPoints& real_points, + const base::TimeTicks& current_time, + base::TimeDelta prediction_duration, + const gfx::Size& screen_size) { + Clear(); + + if (real_points.IsEmpty() || prediction_duration.is_zero()) + return; + + gfx::Vector2dF scale(1.0f / screen_size.width(), 1.0f / screen_size.height()); + + // Create a new set of predicted points based on the last four points added. + // We add enough predicted points to fill the time between the new point and + // the expected presentation time. Note that estimated presentation time is + // based on current time and inefficient rendering of points can result in an + // actual presentation time that is later. + + // TODO(reveman): Determine interval based on history when event time stamps + // are accurate. b/36137953 + const float kPredictionIntervalMs = 5.0f; + const float kMaxPointIntervalMs = 10.0f; + base::TimeDelta prediction_interval = + base::TimeDelta::FromMilliseconds(kPredictionIntervalMs); + base::TimeDelta max_point_interval = + base::TimeDelta::FromMilliseconds(kMaxPointIntervalMs); + const FastInkPoint newest_real_point = real_points.GetNewest(); + base::TimeTicks last_point_time = newest_real_point.time; + gfx::PointF last_point_location = + gfx::ScalePoint(newest_real_point.location, scale.x(), scale.y()); + + // Use the last four points for prediction. + using PositionArray = std::array<gfx::PointF, 4>; + PositionArray position; + PositionArray::iterator it = position.begin(); + for (const auto& point : base::Reversed(real_points.points())) { + // Stop adding positions if interval between points is too large to provide + // an accurate history for prediction. + if ((last_point_time - point.time) > max_point_interval) + break; + + last_point_time = point.time; + last_point_location = gfx::ScalePoint(point.location, scale.x(), scale.y()); + *it++ = last_point_location; + + // Stop when no more positions are needed. + if (it == position.end()) + break; + } + // Pad with last point if needed. + std::fill(it, position.end(), last_point_location); + + // Note: Currently there's no need to divide by the time delta between + // points as we assume a constant delta between points that matches the + // prediction point interval. + gfx::Vector2dF velocity[3]; + for (size_t i = 0; i < arraysize(velocity); ++i) + velocity[i] = position[i] - position[i + 1]; + + gfx::Vector2dF acceleration[2]; + for (size_t i = 0; i < arraysize(acceleration); ++i) + acceleration[i] = velocity[i] - velocity[i + 1]; + + gfx::Vector2dF jerk = acceleration[0] - acceleration[1]; + + // Adjust max prediction time based on speed as prediction data is not great + // at lower speeds. + const float kMaxPredictionScaleSpeed = 1e-5; + double speed = velocity[0].LengthSquared(); + base::TimeTicks max_prediction_time = + current_time + + std::min(prediction_duration * (speed / kMaxPredictionScaleSpeed), + prediction_duration); + + // Add predicted points until we reach the max prediction time. + gfx::PointF location = position[0]; + for (base::TimeTicks time = newest_real_point.time + prediction_interval; + time < max_prediction_time; time += prediction_interval) { + // Note: Currently there's no need to multiply by the prediction interval + // as the velocity is calculated based on a time delta between points that + // is the same as the prediction interval. + velocity[0] += acceleration[0]; + acceleration[0] += jerk; + location += velocity[0]; + + AddPoint(gfx::ScalePoint(location, 1 / scale.x(), 1 / scale.y()), time); + + // Always stop at three predicted points as a four point history doesn't + // provide accurate prediction of more points. + if (GetNumberOfPoints() == 3) + break; + } +} + +} // namespace ash
diff --git a/ash/fast_ink/fast_ink_points.h b/ash/fast_ink/fast_ink_points.h new file mode 100644 index 0000000..8c16482 --- /dev/null +++ b/ash/fast_ink/fast_ink_points.h
@@ -0,0 +1,75 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_FAST_INK_FAST_INK_POINTS_H_ +#define ASH_FAST_INK_FAST_INK_POINTS_H_ + +#include <deque> +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "base/time/time.h" +#include "ui/gfx/geometry/point_f.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { + +// FastInkPoints is a helper class used for displaying low-latency palette tools +// It keeps track of the points needed to render the image. +class ASH_EXPORT FastInkPoints { + public: + // Struct to describe each point. + struct FastInkPoint { + gfx::PointF location; + base::TimeTicks time; + }; + + // Constructor with a parameter to choose the fade out time of the points in + // the collection. Zero means no fadeout. + explicit FastInkPoints(base::TimeDelta life_duration); + ~FastInkPoints(); + + // Adds a point. + void AddPoint(const gfx::PointF& point, const base::TimeTicks& time); + // Updates the collection latest time. Automatically clears points that are + // too old. + void MoveForwardToTime(const base::TimeTicks& latest_time); + // Removes all points. + void Clear(); + // Gets the bounding box of the points. + gfx::Rect GetBoundingBox() const; + // Returns the oldest point in the collection. + FastInkPoint GetOldest() const; + // Returns the newest point in the collection. + FastInkPoint GetNewest() const; + // Returns the number of points in the collection. + int GetNumberOfPoints() const; + // Whether there are any points or not. + bool IsEmpty() const; + // Expose the collection so callers can work with the points. + const std::deque<FastInkPoint>& points() const; + // Returns the fadeout factor for a point. This is a value between 0.0 and + // 1.0, where 0.0 corresponds to a recently added point, and 1.0 to a point + // that is about to expire. Do not call this method if |life_duration_| is 0. + float GetFadeoutFactor(int index) const; + // Fills the container with predicted points based on |real_points|. + void Predict(const FastInkPoints& real_points, + const base::TimeTicks& current_time, + base::TimeDelta prediction_duration, + const gfx::Size& screen_size); + + private: + const base::TimeDelta life_duration_; + std::deque<FastInkPoint> points_; + // The latest time of the collection of points. This gets updated when new + // points are added or when MoveForwardToTime is called. + base::TimeTicks collection_latest_time_; + + DISALLOW_COPY_AND_ASSIGN(FastInkPoints); +}; + +} // namespace ash + +#endif // ASH_FAST_INK_FAST_INK_POINTS_H_
diff --git a/ash/fast_ink/fast_ink_points_unittest.cc b/ash/fast_ink/fast_ink_points_unittest.cc new file mode 100644 index 0000000..eb670e58 --- /dev/null +++ b/ash/fast_ink/fast_ink_points_unittest.cc
@@ -0,0 +1,218 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/fast_ink/fast_ink_points.h" +#include "ash/test/ash_test_base.h" +#include "ui/events/test/event_generator.h" + +namespace ash { +namespace { + +const int kTestPointsLifetimeSeconds = 5; + +class FastInkPointsTest : public AshTestBase { + public: + FastInkPointsTest() + : points_(base::TimeDelta::FromSeconds(kTestPointsLifetimeSeconds)), + predicted_(base::TimeDelta::FromSeconds(kTestPointsLifetimeSeconds)), + event_time_(base::TimeTicks()), + screen_size_(1000, 1000) {} + + ~FastInkPointsTest() override {} + + protected: + FastInkPoints points_; + FastInkPoints predicted_; + base::TimeTicks event_time_; + const gfx::Size screen_size_; + + base::TimeDelta prediction_duration_; + + void AddPoint(const gfx::PointF& point, base::TimeDelta interval) { + event_time_ += interval; + points_.AddPoint(point, event_time_); + predicted_.Predict(points_, event_time_, prediction_duration_, + screen_size_); + const base::TimeTicks presentation_time = + event_time_ + prediction_duration_; + points_.MoveForwardToTime(presentation_time); + predicted_.MoveForwardToTime(presentation_time); + } + + void AddStroke(int points, + base::TimeDelta interval, + const gfx::PointF& position, + const gfx::Vector2dF& velocity, + const gfx::Vector2dF& acceleration) { + points_.Clear(); + gfx::PointF p = position; + gfx::Vector2dF v = velocity; + for (int i = 0; i < points; ++i) { + AddPoint(p, interval); + p += v; + v += acceleration; + } + } + + void Diff(std::vector<gfx::Vector2dF>& dst, + const std::vector<gfx::Vector2dF>& src) { + dst.clear(); + if (src.size() < 2) + return; + for (size_t i = 1; i < src.size(); ++i) + dst.push_back(src[i] - src[i - 1]); + } + + void ComputeDeltas(std::vector<gfx::Vector2dF>& velocity, + std::vector<gfx::Vector2dF>& acceleration) { + std::vector<gfx::Vector2dF> position; + for (auto p : points_.points()) + position.push_back(p.location.OffsetFromOrigin()); + for (auto p : predicted_.points()) + position.push_back(p.location.OffsetFromOrigin()); + + Diff(velocity, position); + Diff(acceleration, velocity); + } + + private: + DISALLOW_COPY_AND_ASSIGN(FastInkPointsTest); +}; + +} // namespace + +// Tests that the fast ink points internal collection handles receiving points +// and that the functions are returning the expected output. +TEST_F(FastInkPointsTest, FastInkPointsInternalCollection) { + EXPECT_TRUE(points_.IsEmpty()); + EXPECT_EQ(gfx::Rect(), points_.GetBoundingBox()); + const gfx::PointF left(1, 1); + const gfx::PointF bottom(1, 9); + const gfx::PointF top_right(30, 0); + const gfx::PointF last(2, 2); + points_.AddPoint(left, base::TimeTicks()); + EXPECT_EQ(gfx::Rect(1, 1, 0, 0), points_.GetBoundingBox()); + + // Should be the new bottom of the bounding box. + points_.AddPoint(bottom, base::TimeTicks()); + EXPECT_EQ(gfx::Rect(1, 1, 0, bottom.y() - 1), points_.GetBoundingBox()); + + // Should be the new top and right of the bounding box. + points_.AddPoint(top_right, base::TimeTicks()); + EXPECT_EQ(3, points_.GetNumberOfPoints()); + EXPECT_FALSE(points_.IsEmpty()); + EXPECT_EQ(gfx::Rect(left.x(), top_right.y(), top_right.x() - left.x(), + bottom.y() - top_right.y()), + points_.GetBoundingBox()); + + // Should not expand bounding box. + points_.AddPoint(last, base::TimeTicks()); + EXPECT_EQ(gfx::Rect(left.x(), top_right.y(), top_right.x() - left.x(), + bottom.y() - top_right.y()), + points_.GetBoundingBox()); + + // Points should be sorted in the order they are added. + EXPECT_EQ(left, points_.GetOldest().location); + EXPECT_EQ(last, points_.GetNewest().location); + + // Add a new point which will expand the bounding box. + gfx::PointF new_left_bottom(0, 40); + points_.AddPoint(new_left_bottom, base::TimeTicks()); + EXPECT_EQ(5, points_.GetNumberOfPoints()); + EXPECT_EQ(gfx::Rect(new_left_bottom.x(), top_right.y(), + top_right.x() - new_left_bottom.x(), + new_left_bottom.y() - top_right.y()), + points_.GetBoundingBox()); + + // Verify clearing works. + points_.Clear(); + EXPECT_TRUE(points_.IsEmpty()); +} + +// Test the fast ink points collection to verify that old points are +// removed. +TEST_F(FastInkPointsTest, FastInkPointsInternalCollectionDeletion) { + EXPECT_EQ(1, prediction_duration_.is_zero()); + // When a point older than kTestPointsLifetimeSeconds (5 sec) is added, it + // should get removed. The age of the point is a number between 0.0 and 1.0, + // with 0.0 specifying a newly added point and 1.0 specifying the age of a + // point added |kTestPointsLifetimeSeconds| ago. + AddPoint(gfx::PointF(), base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(1, points_.GetNumberOfPoints()); + EXPECT_FLOAT_EQ(0.0, points_.GetFadeoutFactor(0)); + + // Verify when we move forward in time by one second, the age of the last + // point, added one second ago is 1 / |kTestPointsLifetimeSeconds|. + AddPoint(gfx::PointF(), base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(2, points_.GetNumberOfPoints()); + EXPECT_FLOAT_EQ(0.2, points_.GetFadeoutFactor(0)); + EXPECT_FLOAT_EQ(0.0, points_.GetFadeoutFactor(1)); + // Verify adding a point 10 seconds later will clear all other points, since + // they are older than 5 seconds. + AddPoint(gfx::PointF(), base::TimeDelta::FromSeconds(10)); + EXPECT_EQ(1, points_.GetNumberOfPoints()); + + // Verify adding 3 points one second apart each will add 3 points to the + // collection, since all 4 points are younger than 5 seconds. All 4 points are + // added 1 second apart so their age should be 0.2 apart. + AddPoint(gfx::PointF(), base::TimeDelta::FromSeconds(1)); + AddPoint(gfx::PointF(), base::TimeDelta::FromSeconds(1)); + AddPoint(gfx::PointF(), base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(4, points_.GetNumberOfPoints()); + EXPECT_FLOAT_EQ(0.6, points_.GetFadeoutFactor(0)); + EXPECT_FLOAT_EQ(0.4, points_.GetFadeoutFactor(1)); + EXPECT_FLOAT_EQ(0.2, points_.GetFadeoutFactor(2)); + EXPECT_FLOAT_EQ(0.0, points_.GetFadeoutFactor(3)); + + // Verify adding 1 point three seconds later will remove 2 points which are + // older than 5 seconds. + AddPoint(gfx::PointF(), base::TimeDelta::FromSeconds(3)); + EXPECT_EQ(3, points_.GetNumberOfPoints()); +} + +// Test the fast ink prediction. +TEST_F(FastInkPointsTest, FastInkPointsPrediction) { + prediction_duration_ = base::TimeDelta::FromMilliseconds(18); + + const int kTraceLength = 4; + const base::TimeDelta kTraceInterval = base::TimeDelta::FromMilliseconds(5); + + const int kExpectedPredictionDepth = 3; + + // Using fairly generous error margin to allow for the accumulation + // of rounding errors. + const float kMaxPredictionError = 1e-4; + + std::vector<gfx::Vector2dF> computed_velocity; + std::vector<gfx::Vector2dF> computed_acceleration; + + const gfx::Vector2dF zero; + + // Fixed position, no prediction should be available. + const gfx::PointF position(0, 0); + AddStroke(kTraceLength, kTraceInterval, position, zero, zero); + EXPECT_EQ(0, predicted_.GetNumberOfPoints()); + + // Constant velocity, the predicted trajectory should maintain it. + const gfx::Vector2dF velocity(10, 5); + AddStroke(kTraceLength, kTraceInterval, position, velocity, zero); + EXPECT_EQ(kExpectedPredictionDepth, predicted_.GetNumberOfPoints()); + ComputeDeltas(computed_velocity, computed_acceleration); + for (auto v : computed_velocity) { + EXPECT_GT(kMaxPredictionError, (velocity - v).Length()); + } + + // Constant acceleration, the predicted trajectory should maintain it. + const gfx::Vector2dF acceleration(4, 2); + AddStroke(kTraceLength, kTraceInterval, position, velocity, acceleration); + EXPECT_EQ(kExpectedPredictionDepth, predicted_.GetNumberOfPoints()); + ComputeDeltas(computed_velocity, computed_acceleration); + for (auto a : computed_acceleration) { + EXPECT_GT(kMaxPredictionError, (acceleration - a).Length()); + } + + // Not testing with non-zero jerk, as the current prediction implementation + // is not maintaining constant jerk on purpose. +} +} // namespace ash
diff --git a/ash/laser/DEPS b/ash/laser/DEPS index 61499381..2067a546 100644 --- a/ash/laser/DEPS +++ b/ash/laser/DEPS
@@ -1,4 +1,3 @@ include_rules = [ - "+cc", "+ash/fast_ink", ]
diff --git a/ash/laser/laser_pointer_controller_test_api.cc b/ash/laser/laser_pointer_controller_test_api.cc index c3fb23a..4c483fd 100644 --- a/ash/laser/laser_pointer_controller_test_api.cc +++ b/ash/laser/laser_pointer_controller_test_api.cc
@@ -4,8 +4,8 @@ #include "ash/laser/laser_pointer_controller_test_api.h" +#include "ash/fast_ink/fast_ink_points.h" #include "ash/laser/laser_pointer_controller.h" -#include "ash/laser/laser_pointer_points.h" #include "ash/laser/laser_pointer_view.h" namespace ash { @@ -32,12 +32,12 @@ instance_->is_fading_away_ = fading_away; } -const LaserPointerPoints& LaserPointerControllerTestApi::laser_points() const { +const FastInkPoints& LaserPointerControllerTestApi::laser_points() const { return instance_->laser_pointer_view_->laser_points_; } -const LaserPointerPoints& -LaserPointerControllerTestApi::predicted_laser_points() const { +const FastInkPoints& LaserPointerControllerTestApi::predicted_laser_points() + const { return instance_->laser_pointer_view_->predicted_laser_points_; }
diff --git a/ash/laser/laser_pointer_controller_test_api.h b/ash/laser/laser_pointer_controller_test_api.h index 8653dbdb..bfb5463 100644 --- a/ash/laser/laser_pointer_controller_test_api.h +++ b/ash/laser/laser_pointer_controller_test_api.h
@@ -9,8 +9,8 @@ namespace ash { +class FastInkPoints; class LaserPointerController; -class LaserPointerPoints; class LaserPointerView; // An api for testing the LaserPointerController class. @@ -23,8 +23,8 @@ bool IsShowingLaserPointer() const; bool IsFadingAway() const; void SetIsFadingAway(bool fading_away); - const LaserPointerPoints& laser_points() const; - const LaserPointerPoints& predicted_laser_points() const; + const FastInkPoints& laser_points() const; + const FastInkPoints& predicted_laser_points() const; LaserPointerView* laser_pointer_view() const; private:
diff --git a/ash/laser/laser_pointer_controller_unittest.cc b/ash/laser/laser_pointer_controller_unittest.cc index d65a6b0..0658262 100644 --- a/ash/laser/laser_pointer_controller_unittest.cc +++ b/ash/laser/laser_pointer_controller_unittest.cc
@@ -145,7 +145,7 @@ controller_test_api_.predicted_laser_points().GetNumberOfPoints()); // Verify predicted points are in the right direction. for (const auto& point : - controller_test_api_.predicted_laser_points().laser_points()) { + controller_test_api_.predicted_laser_points().points()) { EXPECT_LT(30, point.location.x()); EXPECT_LT(30, point.location.y()); }
diff --git a/ash/laser/laser_pointer_points.cc b/ash/laser/laser_pointer_points.cc deleted file mode 100644 index 1e597636..0000000 --- a/ash/laser/laser_pointer_points.cc +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/laser/laser_pointer_points.h" - -#include <algorithm> -#include <limits> - -#include "ui/gfx/geometry/rect_conversions.h" - -namespace ash { - -LaserPointerPoints::LaserPointerPoints(base::TimeDelta life_duration) - : life_duration_(life_duration) {} - -LaserPointerPoints::~LaserPointerPoints() {} - -void LaserPointerPoints::AddPoint(const gfx::PointF& point, - const base::TimeTicks& time) { - // Move forward in time if needed. - if (time > collection_latest_time_) - MoveForwardToTime(time); - - LaserPoint new_point; - new_point.location = point; - new_point.time = time; - new_point.age = std::min((collection_latest_time_ - time).InMillisecondsF() / - life_duration_.InMillisecondsF(), - 1.0); - points_.push_back(new_point); -} - -void LaserPointerPoints::MoveForwardToTime(const base::TimeTicks& latest_time) { - DCHECK_GE(latest_time, collection_latest_time_); - - if (!points_.empty()) { - DCHECK(!collection_latest_time_.is_null()); - - // Increase the age of points based on how much time has elapsed. - base::TimeDelta delta = latest_time - collection_latest_time_; - double lifespan_change = - delta.InMillisecondsF() / life_duration_.InMillisecondsF(); - for (LaserPoint& point : points_) - point.age += lifespan_change; - - // Remove points that are too old (points age older than 1.0). - auto first_alive_point = - std::find_if(points_.begin(), points_.end(), - [](const LaserPoint& p) { return p.age < 1.0; }); - points_.erase(points_.begin(), first_alive_point); - } - collection_latest_time_ = latest_time; -} - -void LaserPointerPoints::Clear() { - points_.clear(); -} - -gfx::Rect LaserPointerPoints::GetBoundingBox() { - if (IsEmpty()) - return gfx::Rect(); - - gfx::PointF min_point = GetOldest().location; - gfx::PointF max_point = GetOldest().location; - for (const LaserPoint& point : points_) { - min_point.SetToMin(point.location); - max_point.SetToMax(point.location); - } - return gfx::ToEnclosingRect(gfx::BoundingRect(min_point, max_point)); -} - -LaserPointerPoints::LaserPoint LaserPointerPoints::GetOldest() const { - DCHECK(!IsEmpty()); - return points_.front(); -} - -LaserPointerPoints::LaserPoint LaserPointerPoints::GetNewest() const { - DCHECK(!IsEmpty()); - return points_.back(); -} - -bool LaserPointerPoints::IsEmpty() const { - return points_.empty(); -} - -int LaserPointerPoints::GetNumberOfPoints() const { - return points_.size(); -} - -const std::deque<LaserPointerPoints::LaserPoint>& -LaserPointerPoints::laser_points() const { - return points_; -} -} // namespace ash
diff --git a/ash/laser/laser_pointer_points.h b/ash/laser/laser_pointer_points.h deleted file mode 100644 index 9bf1d8d..0000000 --- a/ash/laser/laser_pointer_points.h +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_LASER_LASER_POINTER_POINTS_H_ -#define ASH_LASER_LASER_POINTER_POINTS_H_ - -#include <deque> -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "base/time/time.h" -#include "ui/gfx/geometry/point_f.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { - -// LaserPointerPoints is a helper class used for displaying the palette tool -// laser pointer. It keeps track of the points needed to render the laser -// pointer and its tail. -class ASH_EXPORT LaserPointerPoints { - public: - // Struct to describe each point. - struct LaserPoint { - gfx::PointF location; - base::TimeTicks time; - // age is a value between [0,1] where 0 means the point was just added and 1 - // means that the point is just about to be removed. - float age = 0.0f; - }; - - // Constructor with a parameter to choose the fade out time of the points in - // the collection. - explicit LaserPointerPoints(base::TimeDelta life_duration); - ~LaserPointerPoints(); - - // Adds a point. Automatically clears points that are too old. - void AddPoint(const gfx::PointF& point, const base::TimeTicks& time); - // Updates the collection latest time. Automatically clears points that are - // too old. - void MoveForwardToTime(const base::TimeTicks& latest_time); - // Removes all points. - void Clear(); - // Gets the bounding box of the points. - gfx::Rect GetBoundingBox(); - // Returns the oldest point in the collection. - LaserPoint GetOldest() const; - // Returns the newest point in the collection. - LaserPoint GetNewest() const; - // Returns the number of points in the collection. - int GetNumberOfPoints() const; - // Whether there are any points or not. - bool IsEmpty() const; - // Expose the collection so callers can work with the points. - const std::deque<LaserPoint>& laser_points() const; - - private: - friend class LaserPointerPointsTestApi; - - base::TimeDelta life_duration_; - std::deque<LaserPoint> points_; - // The latest time of the collection of points. This gets updated when new - // points are added or when MoveForwardInTime is called. - base::TimeTicks collection_latest_time_; - - DISALLOW_COPY_AND_ASSIGN(LaserPointerPoints); -}; - -} // namespace ash - -#endif // ASH_LASER_LASER_POINTER_POINTS_H_
diff --git a/ash/laser/laser_pointer_points_test_api.cc b/ash/laser/laser_pointer_points_test_api.cc deleted file mode 100644 index 9b55900..0000000 --- a/ash/laser/laser_pointer_points_test_api.cc +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/laser/laser_pointer_points_test_api.h" - -namespace ash { - -LaserPointerPointsTestApi::LaserPointerPointsTestApi( - LaserPointerPoints* instance) - : instance_(instance) {} - -LaserPointerPointsTestApi::~LaserPointerPointsTestApi() {} - -int LaserPointerPointsTestApi::GetNumberOfPoints() const { - return instance_->GetNumberOfPoints(); -} - -void LaserPointerPointsTestApi::MoveForwardInTime( - const base::TimeDelta& delta) { - base::TimeTicks new_time = instance_->collection_latest_time_ + delta; - instance_->MoveForwardToTime(new_time); - - LaserPointerPoints::LaserPoint new_point; - instance_->points_.push_back(new_point); -} - -LaserPointerPoints::LaserPoint LaserPointerPointsTestApi::GetPointAtIndex( - int index) { - DCHECK(index >= 0 && index < GetNumberOfPoints()); - return instance_->points_[index]; -} - -} // namespace ash
diff --git a/ash/laser/laser_pointer_points_test_api.h b/ash/laser/laser_pointer_points_test_api.h deleted file mode 100644 index a28889fd..0000000 --- a/ash/laser/laser_pointer_points_test_api.h +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_LASER_LASER_POINTER_POINTS_TEST_API_H_ -#define ASH_LASER_LASER_POINTER_POINTS_TEST_API_H_ - -#include "ash/laser/laser_pointer_points.h" -#include "base/time/time.h" - -namespace ash { - -// An api for testing the laser_pointer_points class. -class LaserPointerPointsTestApi { - public: - LaserPointerPointsTestApi(LaserPointerPoints* instance); - ~LaserPointerPointsTestApi(); - - int GetNumberOfPoints() const; - // Moves existing points back in time by |delta| and adds a new point at - // (0,0). - void MoveForwardInTime(const base::TimeDelta& delta); - LaserPointerPoints::LaserPoint GetPointAtIndex(int index); - - private: - LaserPointerPoints* instance_; - - DISALLOW_COPY_AND_ASSIGN(LaserPointerPointsTestApi); -}; -} // namespace ash - -#endif // ASH_LASER_LASER_POINTER_POINTS_TEST_API_H_
diff --git a/ash/laser/laser_pointer_points_unittest.cc b/ash/laser/laser_pointer_points_unittest.cc deleted file mode 100644 index 71897e2..0000000 --- a/ash/laser/laser_pointer_points_unittest.cc +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/laser/laser_pointer_points.h" -#include "ash/laser/laser_pointer_points_test_api.h" -#include "ash/test/ash_test_base.h" -#include "ui/events/test/event_generator.h" - -namespace ash { -namespace { - -const int kTestPointsLifetimeSeconds = 5; - -class LaserPointerPointsTest : public AshTestBase { - public: - LaserPointerPointsTest() - : points_(base::TimeDelta::FromSeconds(kTestPointsLifetimeSeconds)) {} - - ~LaserPointerPointsTest() override {} - - protected: - LaserPointerPoints points_; - - private: - DISALLOW_COPY_AND_ASSIGN(LaserPointerPointsTest); -}; - -} // namespace - -// Tests that the laser pointers internal collection handles receiving points -// and that the functions are returning the expected output. -TEST_F(LaserPointerPointsTest, LaserPointerInternalCollection) { - EXPECT_TRUE(points_.IsEmpty()); - EXPECT_EQ(gfx::Rect(), points_.GetBoundingBox()); - const gfx::PointF left(1, 1); - const gfx::PointF bottom(1, 9); - const gfx::PointF top_right(30, 0); - const gfx::PointF last(2, 2); - points_.AddPoint(left, base::TimeTicks()); - EXPECT_EQ(gfx::Rect(1, 1, 0, 0), points_.GetBoundingBox()); - - // Should be the new bottom of the bounding box. - points_.AddPoint(bottom, base::TimeTicks()); - EXPECT_EQ(gfx::Rect(1, 1, 0, bottom.y() - 1), points_.GetBoundingBox()); - - // Should be the new top and right of the bounding box. - points_.AddPoint(top_right, base::TimeTicks()); - EXPECT_EQ(3, points_.GetNumberOfPoints()); - EXPECT_FALSE(points_.IsEmpty()); - EXPECT_EQ(gfx::Rect(left.x(), top_right.y(), top_right.x() - left.x(), - bottom.y() - top_right.y()), - points_.GetBoundingBox()); - - // Should not expand bounding box. - points_.AddPoint(last, base::TimeTicks()); - EXPECT_EQ(gfx::Rect(left.x(), top_right.y(), top_right.x() - left.x(), - bottom.y() - top_right.y()), - points_.GetBoundingBox()); - - // Points should be sorted in the order they are added. - EXPECT_EQ(left, points_.GetOldest().location); - EXPECT_EQ(last, points_.GetNewest().location); - - // Add a new point which will expand the bounding box. - gfx::PointF new_left_bottom(0, 40); - points_.AddPoint(new_left_bottom, base::TimeTicks()); - EXPECT_EQ(5, points_.GetNumberOfPoints()); - EXPECT_EQ(gfx::Rect(new_left_bottom.x(), top_right.y(), - top_right.x() - new_left_bottom.x(), - new_left_bottom.y() - top_right.y()), - points_.GetBoundingBox()); - - // Verify clearing works. - points_.Clear(); - EXPECT_TRUE(points_.IsEmpty()); -} - -// Test the laser pointer points collection to verify that old points are -// removed. -TEST_F(LaserPointerPointsTest, LaserPointerInternalCollectionDeletion) { - LaserPointerPointsTestApi points_test_api_(&points_); - - // When a point older than kTestPointsLifetime (5 seconds) is added, it - // should get removed. The age of the point is a number between 0.0 and 1.0, - // with 0.0 specifying a newly added point and 1.0 specifying the age of a - // point added |kTestPointsLifetime| ago. - points_test_api_.MoveForwardInTime(base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(1, points_test_api_.GetNumberOfPoints()); - EXPECT_FLOAT_EQ(0.0, points_test_api_.GetPointAtIndex(0).age); - - // Verify when we move forward in time by one second, the age of the last - // point, added one second ago is 1 / |kTestPointsLifetime|. - points_test_api_.MoveForwardInTime(base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(2, points_test_api_.GetNumberOfPoints()); - EXPECT_FLOAT_EQ(0.2, points_test_api_.GetPointAtIndex(0).age); - EXPECT_FLOAT_EQ(0.0, points_test_api_.GetPointAtIndex(1).age); - // Verify adding a point 10 seconds later will clear all other points, since - // they are older than 5 seconds. - points_test_api_.MoveForwardInTime(base::TimeDelta::FromSeconds(10)); - EXPECT_EQ(1, points_test_api_.GetNumberOfPoints()); - - // Verify adding 3 points one second apart each will add 3 points to the - // collection, since all 4 points are younger than 5 seconds. All 4 points are - // added 1 second apart so their age should be 0.2 apart. - points_test_api_.MoveForwardInTime(base::TimeDelta::FromSeconds(1)); - points_test_api_.MoveForwardInTime(base::TimeDelta::FromSeconds(1)); - points_test_api_.MoveForwardInTime(base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(4, points_test_api_.GetNumberOfPoints()); - EXPECT_FLOAT_EQ(0.6, points_test_api_.GetPointAtIndex(0).age); - EXPECT_FLOAT_EQ(0.4, points_test_api_.GetPointAtIndex(1).age); - EXPECT_FLOAT_EQ(0.2, points_test_api_.GetPointAtIndex(2).age); - EXPECT_FLOAT_EQ(0.0, points_test_api_.GetPointAtIndex(3).age); - - // Verify adding 1 point three seconds later will remove 2 points which are - // older than 5 seconds. - points_test_api_.MoveForwardInTime(base::TimeDelta::FromSeconds(3)); - EXPECT_EQ(3, points_test_api_.GetNumberOfPoints()); -} -} // namespace ash
diff --git a/ash/laser/laser_pointer_view.cc b/ash/laser/laser_pointer_view.cc index e26d777..163a397 100644 --- a/ash/laser/laser_pointer_view.cc +++ b/ash/laser/laser_pointer_view.cc
@@ -4,9 +4,7 @@ #include "ash/laser/laser_pointer_view.h" -#include "ash/laser/laser_pointer_points.h" #include "ash/laser/laser_segment_utils.h" -#include "base/containers/adapters.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkTypes.h" #include "ui/aura/window.h" @@ -182,9 +180,9 @@ TRACE_COUNTER1( "ui", "LaserPointerPredictionError", predicted_laser_points_.GetNumberOfPoints() - ? std::round((new_point - - predicted_laser_points_.laser_points().front().location) - .Length()) + ? std::round( + (new_point - predicted_laser_points_.points().front().location) + .Length()) : 0); UpdateDamageRect(GetBoundingBox()); @@ -193,94 +191,9 @@ // Current time is needed to determine presentation time and the number of // predicted points to add. base::TimeTicks current_time = ui::EventTimeForNow(); - - // Create a new set of predicted points based on the last four points added. - // We add enough predicted points to fill the time between the new point and - // the expected presentation time. Note that estimated presentation time is - // based on current time and inefficient rendering of points can result in an - // actual presentation time that is later. - predicted_laser_points_.Clear(); - - // Normalize all coordinates to screen size. - gfx::Size screen_size = - GetWidget()->GetNativeView()->GetBoundsInScreen().size(); - gfx::Vector2dF scale(1.0f / screen_size.width(), 1.0f / screen_size.height()); - - // TODO(reveman): Determine interval based on history when event time stamps - // are accurate. b/36137953 - const float kPredictionIntervalMs = 5.0f; - const float kMaxPointIntervalMs = 10.0f; - base::TimeDelta prediction_interval = - base::TimeDelta::FromMilliseconds(kPredictionIntervalMs); - base::TimeDelta max_point_interval = - base::TimeDelta::FromMilliseconds(kMaxPointIntervalMs); - base::TimeTicks last_point_time = new_time; - gfx::PointF last_point_location = - gfx::ScalePoint(new_point, scale.x(), scale.y()); - - // Use the last four points for prediction. - using PositionArray = std::array<gfx::PointF, 4>; - PositionArray position; - PositionArray::iterator it = position.begin(); - for (const auto& point : base::Reversed(laser_points_.laser_points())) { - // Stop adding positions if interval between points is too large to provide - // an accurate history for prediction. - if ((last_point_time - point.time) > max_point_interval) - break; - - last_point_time = point.time; - last_point_location = gfx::ScalePoint(point.location, scale.x(), scale.y()); - *it++ = last_point_location; - - // Stop when no more positions are needed. - if (it == position.end()) - break; - } - // Pad with last point if needed. - std::fill(it, position.end(), last_point_location); - - // Note: Currently there's no need to divide by the time delta between - // points as we assume a constant delta between points that matches the - // prediction point interval. - gfx::Vector2dF velocity[3]; - for (size_t i = 0; i < arraysize(velocity); ++i) - velocity[i] = position[i] - position[i + 1]; - - gfx::Vector2dF acceleration[2]; - for (size_t i = 0; i < arraysize(acceleration); ++i) - acceleration[i] = velocity[i] - velocity[i + 1]; - - gfx::Vector2dF jerk = acceleration[0] - acceleration[1]; - - // Adjust max prediction time based on speed as prediction data is not great - // at lower speeds. - const float kMaxPredictionScaleSpeed = 1e-5; - double speed = velocity[0].LengthSquared(); - base::TimeTicks max_prediction_time = - current_time + - std::min(presentation_delay_ * (speed / kMaxPredictionScaleSpeed), - presentation_delay_); - - // Add predicted points until we reach the max prediction time. - gfx::PointF location = position[0]; - for (base::TimeTicks time = new_time + prediction_interval; - time < max_prediction_time; time += prediction_interval) { - // Note: Currently there's no need to multiply by the prediction interval - // as the velocity is calculated based on a time delta between points that - // is the same as the prediction interval. - velocity[0] += acceleration[0]; - acceleration[0] += jerk; - location += velocity[0]; - - predicted_laser_points_.AddPoint( - gfx::ScalePoint(location, screen_size.width(), screen_size.height()), - time); - - // Always stop at three predicted points as a four point history doesn't - // provide accurate prediction of more points. - if (predicted_laser_points_.GetNumberOfPoints() == 3) - break; - } + predicted_laser_points_.Predict( + laser_points_, current_time, presentation_delay_, + GetWidget()->GetNativeView()->GetBoundsInScreen().size()); // Move forward to next presentation time. base::TimeTicks next_presentation_time = current_time + presentation_delay_; @@ -325,59 +238,59 @@ if (!num_points) return; - LaserPointerPoints::LaserPoint previous_point = laser_points_.GetOldest(); - previous_point.location -= offset; - LaserPointerPoints::LaserPoint current_point; + gfx::PointF previous_point; std::vector<gfx::PointF> previous_segment_points; float previous_radius; - int current_opacity; for (int i = 0; i < num_points; ++i) { + gfx::PointF current_point; + float fadeout_factor; if (i < laser_points_.GetNumberOfPoints()) { - current_point = laser_points_.laser_points()[i]; + current_point = laser_points_.points()[i].location - offset; + fadeout_factor = laser_points_.GetFadeoutFactor(i); } else { - current_point = - predicted_laser_points_ - .laser_points()[i - laser_points_.GetNumberOfPoints()]; - } - current_point.location -= offset; - - // Set the radius and opacity based on the distance. - float current_radius = LinearInterpolate( - kPointInitialRadius, kPointFinalRadius, current_point.age); - current_opacity = static_cast<int>(LinearInterpolate( - kPointInitialOpacity, kPointFinalOpacity, current_point.age)); - - // If we draw laser_points_ that are within a stroke width of each other, - // the result will be very jagged, unless we are on the last point, then - // we draw regardless. - float distance_threshold = current_radius * 2.0f; - if (DistanceBetweenPoints(previous_point.location, - current_point.location) <= distance_threshold && - i != num_points - 1) { - continue; + int index = i - laser_points_.GetNumberOfPoints(); + current_point = predicted_laser_points_.points()[index].location - offset; + fadeout_factor = predicted_laser_points_.GetFadeoutFactor(index); } - LaserSegment current_segment( - previous_segment_points, gfx::PointF(previous_point.location), - gfx::PointF(current_point.location), previous_radius, current_radius, - i == num_points - 1); + // Set the radius and opacity based on the age of the point. + float current_radius = LinearInterpolate(kPointInitialRadius, + kPointFinalRadius, fadeout_factor); + int current_opacity = static_cast<int>(LinearInterpolate( + kPointInitialOpacity, kPointFinalOpacity, fadeout_factor)); - SkPath path = current_segment.path(); if (i < laser_points_.GetNumberOfPoints()) flags.setColor(SkColorSetA(kPointColor, current_opacity)); else flags.setColor(SkColorSetA(kPredictionPointColor, current_opacity)); - canvas.DrawPath(path, flags); - previous_segment_points = current_segment.path_points(); + if (i != 0) { + // If we draw laser_points_ that are within a stroke width of each other, + // the result will be very jagged, unless we are on the last point, then + // we draw regardless. + float distance_threshold = current_radius * 2.0f; + if (DistanceBetweenPoints(previous_point, current_point) <= + distance_threshold && + i != num_points - 1) { + continue; + } + + LaserSegment current_segment(previous_segment_points, + gfx::PointF(previous_point), + gfx::PointF(current_point), previous_radius, + current_radius, i == num_points - 1); + canvas.DrawPath(current_segment.path(), flags); + previous_segment_points = current_segment.path_points(); + } + previous_radius = current_radius; previous_point = current_point; } // Draw the last point as a circle. flags.setStyle(cc::PaintFlags::kFill_Style); - canvas.DrawCircle(current_point.location, kPointInitialRadius, flags); + canvas.DrawCircle(previous_point, kPointInitialRadius, flags); } } // namespace ash
diff --git a/ash/laser/laser_pointer_view.h b/ash/laser/laser_pointer_view.h index ed832d8..d952946 100644 --- a/ash/laser/laser_pointer_view.h +++ b/ash/laser/laser_pointer_view.h
@@ -5,8 +5,8 @@ #ifndef ASH_LASER_LASER_POINTER_VIEW_H_ #define ASH_LASER_LASER_POINTER_VIEW_H_ +#include "ash/fast_ink/fast_ink_points.h" #include "ash/fast_ink/fast_ink_view.h" -#include "ash/laser/laser_pointer_points.h" #include "base/time/time.h" namespace gfx { @@ -37,8 +37,8 @@ void OnRedraw(gfx::Canvas& canvas, const gfx::Vector2d& offset) override; - LaserPointerPoints laser_points_; - LaserPointerPoints predicted_laser_points_; + FastInkPoints laser_points_; + FastInkPoints predicted_laser_points_; const base::TimeDelta presentation_delay_; DISALLOW_COPY_AND_ASSIGN(LaserPointerView);
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index 73531d9..b7ecf69 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -88,6 +88,8 @@ "palette_tray_icon_magnify.icon", "palette_tray_icon_metalayer.1x.icon", "palette_tray_icon_metalayer.icon", + "shelf_back.1x.icon", + "shelf_back.icon", "shelf_keyboard.1x.icon", "shelf_keyboard.icon", "shelf_logout.1x.icon",
diff --git a/ash/resources/vector_icons/shelf_back.1x.icon b/ash/resources/vector_icons/shelf_back.1x.icon new file mode 100644 index 0000000..0eb4554 --- /dev/null +++ b/ash/resources/vector_icons/shelf_back.1x.icon
@@ -0,0 +1,24 @@ +// 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. + +CANVAS_DIMENSIONS, 16, +MOVE_TO, 0, 0, +R_H_LINE_TO, 16, +R_V_LINE_TO, 16, +H_LINE_TO, 0, +CLOSE, +NEW_PATH, +PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF, +MOVE_TO, 5.2f, 7, +H_LINE_TO, 15, +R_V_LINE_TO, 2, +H_LINE_TO, 5.2f, +R_LINE_TO, 4.8f, 4.8f, +LINE_TO, 8.9f, 15, +LINE_TO, 2, 8, +R_LINE_TO, 6.9f, -7, +LINE_TO, 10, 2.2f, +LINE_TO, 5.2f, 7, +CLOSE, +END
diff --git a/ash/resources/vector_icons/shelf_back.icon b/ash/resources/vector_icons/shelf_back.icon new file mode 100644 index 0000000..c8ca33f --- /dev/null +++ b/ash/resources/vector_icons/shelf_back.icon
@@ -0,0 +1,23 @@ +// 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. + +CANVAS_DIMENSIONS, 32, +MOVE_TO, 0, 0, +R_H_LINE_TO, 32, +R_V_LINE_TO, 32, +H_LINE_TO, 0, +CLOSE, +NEW_PATH, +PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF, +MOVE_TO, 8.56f, 17.99f, +R_LINE_TO, 9.65f, 9.98f, +LINE_TO, 16.18f, 30, +LINE_TO, 3, 16.49f, +LINE_TO, 16.18f, 3, +R_LINE_TO, 2.03f, 2, +R_LINE_TO, -9.86f, 9.99f, +H_LINE_TO, 29, +R_V_LINE_TO, 3, +CLOSE, +END
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc index 755edf17..b42ac3d 100644 --- a/ash/shelf/app_list_button.cc +++ b/ash/shelf/app_list_button.cc
@@ -17,20 +17,24 @@ #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/system/tray/tray_popup_utils.h" +#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/command_line.h" #include "base/memory/ptr_util.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "base/timer/timer.h" #include "chromeos/chromeos_switches.h" +#include "third_party/skia/include/core/SkPath.h" #include "ui/accessibility/ax_node_data.h" #include "ui/app_list/presenter/app_list.h" +#include "ui/aura/window_tree_host.h" #include "ui/base/l10n/l10n_util.h" #include "ui/compositor/layer_animation_element.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/compositor/layer_animation_sequence.h" #include "ui/compositor/paint_context.h" #include "ui/compositor/paint_recorder.h" +#include "ui/events/event_sink.h" #include "ui/gfx/canvas.h" #include "ui/gfx/image/canvas_image_source.h" #include "ui/gfx/image/image_skia.h" @@ -41,11 +45,14 @@ #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" #include "ui/views/painter.h" +#include "ui/views/widget/widget.h" namespace ash { namespace { + constexpr int kVoiceInteractionAnimationDelayMs = 200; constexpr int kVoiceInteractionAnimationHideDelayMs = 500; + } // namespace constexpr uint8_t kVoiceInteractionRunningAlpha = 255; // 100% alpha @@ -107,6 +114,27 @@ } void AppListButton::OnGestureEvent(ui::GestureEvent* event) { + last_event_is_back_event_ = IsBackEvent(event->location()); + // Handle gesture events that are on the back button. + if (last_event_is_back_event_) { + switch (event->type()) { + case ui::ET_GESTURE_TAP: + AnimateInkDrop(views::InkDropState::ACTION_TRIGGERED, event); + GenerateAndSendBackEvent(*event); + return; + case ui::ET_GESTURE_TAP_CANCEL: + AnimateInkDrop(views::InkDropState::HIDDEN, event); + return; + case ui::ET_GESTURE_TAP_DOWN: + AnimateInkDrop(views::InkDropState::ACTION_PENDING, event); + GenerateAndSendBackEvent(*event); + return; + default: + return; + } + } + + // Handle gesture events that are on the app list circle. switch (event->type()) { case ui::ET_GESTURE_SCROLL_BEGIN: AnimateInkDrop(views::InkDropState::HIDDEN, event); @@ -173,14 +201,26 @@ } bool AppListButton::OnMousePressed(const ui::MouseEvent& event) { - ImageButton::OnMousePressed(event); - shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event); + last_event_is_back_event_ = IsBackEvent(event.location()); + if (last_event_is_back_event_) { + AnimateInkDrop(views::InkDropState::ACTION_PENDING, &event); + GenerateAndSendBackEvent(*event.AsLocatedEvent()); + } else { + ImageButton::OnMousePressed(event); + shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event); + } return true; } void AppListButton::OnMouseReleased(const ui::MouseEvent& event) { - ImageButton::OnMouseReleased(event); - shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false); + last_event_is_back_event_ = IsBackEvent(event.location()); + if (last_event_is_back_event_) { + AnimateInkDrop(views::InkDropState::ACTION_TRIGGERED, &event); + GenerateAndSendBackEvent(*event.AsLocatedEvent()); + } else { + ImageButton::OnMouseReleased(event); + shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false); + } } void AppListButton::OnMouseCaptureLost() { @@ -201,7 +241,8 @@ std::unique_ptr<views::InkDropRipple> AppListButton::CreateInkDropRipple() const { - gfx::Point center = GetCenterPoint(); + gfx::Point center = last_event_is_back_event_ ? GetBackButtonCenterPoint() + : GetAppListButtonCenterPoint(); gfx::Rect bounds(center.x() - kAppListButtonRadius, center.y() - kAppListButtonRadius, 2 * kAppListButtonRadius, 2 * kAppListButtonRadius); @@ -233,22 +274,81 @@ } std::unique_ptr<views::InkDropMask> AppListButton::CreateInkDropMask() const { - return base::MakeUnique<views::CircleInkDropMask>(size(), GetCenterPoint(), - kAppListButtonRadius); + return base::MakeUnique<views::CircleInkDropMask>( + size(), + last_event_is_back_event_ ? GetBackButtonCenterPoint() + : GetAppListButtonCenterPoint(), + kAppListButtonRadius); } void AppListButton::PaintButtonContents(gfx::Canvas* canvas) { - gfx::PointF circle_center(GetCenterPoint()); + const bool is_tablet_mode = Shell::Get() + ->tablet_mode_controller() + ->IsTabletModeWindowManagerEnabled(); + gfx::PointF circle_center(GetAppListButtonCenterPoint()); // Paint the circular background. cc::PaintFlags bg_flags; bg_flags.setColor(background_color_); bg_flags.setAntiAlias(true); bg_flags.setStyle(cc::PaintFlags::kFill_Style); - canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_flags); - // Paint a white ring as the foreground. The ceil/dsf math assures that the - // ring draws sharply and is centered at all scale factors. + if (is_tablet_mode) { + // Draw the tablet mode app list background. It will look something like + // [1] when the shelf is horizontal and [2] when the shelf is vertical, + // where 1. is the back button and 2. is the app launcher circle. + // _____ + // [1] _______________ [2] / 1. \ + // / \ | | + // | 1. 2. | | 2. | + // \_______________/ \_____/ + + // Calculate the rectangular bounds of the path. The primary axis will be + // the distance between the back button and app circle centers and the + // secondary axis will be 2 * |kAppListButtonRadius|. The origin will be + // situated such that the back button center and app circle center are + // located equal distance from the sides parallel to the primary axis. See + // diagrams below; (1) is the back button and (2) is the app circle. + // + // ___________ ____(1)____ + // | | | | + // (1) (2) | | + // |_________| | | + // |___(2)___| + gfx::PointF back_center(GetBackButtonCenterPoint()); + gfx::RectF background_bounds( + shelf_->PrimaryAxisValue(back_center.x(), + back_center.x() - kAppListButtonRadius), + shelf_->PrimaryAxisValue(back_center.y() - kAppListButtonRadius, + back_center.y()), + shelf_->PrimaryAxisValue(circle_center.x() - back_center.x(), + 2 * kAppListButtonRadius), + shelf_->PrimaryAxisValue(2 * kAppListButtonRadius, + circle_center.y() - back_center.y())); + + // Create the path by drawing two circles, one around the back button and + // one around the app list circle. Join them with the rectangle calculated + // previously. + SkPath path; + path.addCircle(circle_center.x(), circle_center.y(), kAppListButtonRadius); + path.addCircle(back_center.x(), back_center.y(), kAppListButtonRadius); + path.addRect(background_bounds.x(), background_bounds.y(), + background_bounds.right(), background_bounds.bottom()); + canvas->DrawPath(path, bg_flags); + + // Draw the back button icon. + // TODO(sammiequon): Check if the back button should be flipped in RTL. + gfx::ImageSkia back_button = + CreateVectorIcon(kShelfBackIcon, SK_ColorTRANSPARENT); + canvas->DrawImageInt(back_button, back_center.x() - back_button.width() / 2, + back_center.y() - back_button.height() / 2); + } else { + canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_flags); + } + + // Paint a white ring as the foreground for the app list circle. The ceil/dsf + // math assures that the ring draws sharply and is centered at all scale + // factors. float ring_outer_radius_dp = 7.f; float ring_thickness_dp = 1.5f; if (chromeos::switches::IsVoiceInteractionEnabled()) { @@ -287,26 +387,55 @@ } } -gfx::Point AppListButton::GetCenterPoint() const { +gfx::Point AppListButton::GetAppListButtonCenterPoint() const { // For a bottom-aligned shelf, the button bounds could have a larger height - // than width (in the case of touch-dragging the shelf updwards) or a larger + // than width (in the case of touch-dragging the shelf upwards) or a larger // width than height (in the case of a shelf hide/show animation), so adjust // the y-position of the circle's center to ensure correct layout. Similarly - // adjust the x-position for a left- or right-aligned shelf. + // adjust the x-position for a left- or right-aligned shelf. In maximized + // mode, the button will increase it's primary axis size to accomodate the + // back button arrow in addition to the app list button circle. const int x_mid = width() / 2.f; const int y_mid = height() / 2.f; + const bool is_tablet_mode = Shell::Get() + ->tablet_mode_controller() + ->IsTabletModeWindowManagerEnabled(); + ShelfAlignment alignment = shelf_->alignment(); if (alignment == SHELF_ALIGNMENT_BOTTOM || alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) { + if (is_tablet_mode) { + return gfx::Point(width() - kShelfButtonSize / 2.f, + kShelfButtonSize / 2.f); + } return gfx::Point(x_mid, x_mid); } else if (alignment == SHELF_ALIGNMENT_RIGHT) { + if (is_tablet_mode) { + return gfx::Point(kShelfButtonSize / 2.f, + height() - kShelfButtonSize / 2.f); + } return gfx::Point(y_mid, y_mid); } else { DCHECK_EQ(alignment, SHELF_ALIGNMENT_LEFT); + if (is_tablet_mode) { + return gfx::Point(width() - kShelfButtonSize / 2.f, + height() - kShelfButtonSize / 2.f); + } return gfx::Point(width() - y_mid, y_mid); } } +gfx::Point AppListButton::GetBackButtonCenterPoint() const { + DCHECK(Shell::Get() + ->tablet_mode_controller() + ->IsTabletModeWindowManagerEnabled()); + + if (shelf_->alignment() == SHELF_ALIGNMENT_LEFT) + return gfx::Point(width() - kShelfButtonSize / 2.f, kShelfButtonSize / 2.f); + + return gfx::Point(kShelfButtonSize / 2.f, kShelfButtonSize / 2.f); +} + void AppListButton::OnAppListVisibilityChanged(bool shown, aura::Window* root_window) { if (shelf_ != Shelf::ForWindow(root_window)) @@ -344,4 +473,41 @@ voice_interaction_overlay_->StartAnimation(show_icon); } +bool AppListButton::IsBackEvent(const gfx::Point& location) { + if (!Shell::Get() + ->tablet_mode_controller() + ->IsTabletModeWindowManagerEnabled()) { + return false; + } + + return (location - GetBackButtonCenterPoint()).LengthSquared() < + (location - GetAppListButtonCenterPoint()).LengthSquared(); +} + +void AppListButton::GenerateAndSendBackEvent( + const ui::LocatedEvent& original_event) { + ui::EventType event_type; + switch (original_event.type()) { + case ui::ET_MOUSE_PRESSED: + case ui::ET_GESTURE_TAP_DOWN: + event_type = ui::ET_KEY_PRESSED; + break; + case ui::ET_MOUSE_RELEASED: + case ui::ET_GESTURE_TAP: + event_type = ui::ET_KEY_RELEASED; + break; + default: + return; + } + + // Send the back event to the root window of the app list button's widget. + const views::Widget* widget = GetWidget(); + if (widget && widget->GetNativeWindow()) { + aura::Window* root_window = widget->GetNativeWindow()->GetRootWindow(); + ui::KeyEvent key_event(event_type, ui::VKEY_BROWSER_BACK, ui::EF_NONE); + ignore_result( + root_window->GetHost()->event_sink()->OnEventFromSource(&key_event)); + } +} + } // namespace ash
diff --git a/ash/shelf/app_list_button.h b/ash/shelf/app_list_button.h index 732d3618..45a0f56 100644 --- a/ash/shelf/app_list_button.h +++ b/ash/shelf/app_list_button.h
@@ -40,15 +40,19 @@ // Updates background and schedules a paint. void UpdateShelfItemBackground(SkColor color); - // views::ImageButton overrides: + // views::ImageButton: void OnGestureEvent(ui::GestureEvent* event) override; - // Get the center point of the app list button used to draw its background and - // ink drops. - gfx::Point GetCenterPoint() const; + // Get the center point of the app list button circle used to draw its + // background and ink drops. + gfx::Point GetAppListButtonCenterPoint() const; + + // Get the center point of the app list button back arrow. Returns an empty + // gfx::Point if the back arrow is not shown. + gfx::Point GetBackButtonCenterPoint() const; protected: - // views::ImageButton overrides: + // views::ImageButton: bool OnMousePressed(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override; void OnMouseCaptureLost() override; @@ -62,13 +66,22 @@ void PaintButtonContents(gfx::Canvas* canvas) override; private: - // ShellObserver overrides: + // ShellObserver: void OnAppListVisibilityChanged(bool shown, aura::Window* root_window) override; void OnVoiceInteractionStatusChanged(bool running) override; void StartVoiceInteractionAnimation(); + // Helper function to determine whether and event at |location| should be + // handled by the back button or the app list circle. Returns false if we are + // not in maximized mode (there is no back button). + bool IsBackEvent(const gfx::Point& location); + + // Generate and send a VKEY_BROWSER_BACK key event when the back button + // portion is clicked or tapped. + void GenerateAndSendBackEvent(const ui::LocatedEvent& original_event); + // True if the app list is currently showing for this display. // This is useful because other IsApplistVisible functions aren't per-display. bool is_showing_app_list_; @@ -87,6 +100,10 @@ bool voice_interaction_running_ = false; + // Flag that gets set each time we receive a mouse or gesture event. It is + // then used to render the ink drop in the right location. + bool last_event_is_back_event_ = false; + DISALLOW_COPY_AND_ASSIGN(AppListButton); };
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index b0a2f4e..f6c6b3d 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -29,6 +29,7 @@ #include "ash/shell_port.h" #include "ash/strings/grit/ash_strings.h" #include "ash/wm/root_window_finder.h" +#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/auto_reset.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" @@ -763,15 +764,31 @@ int w = shelf_->PrimaryAxisValue(kShelfButtonSize, width()); int h = shelf_->PrimaryAxisValue(height(), kShelfButtonSize); + + const bool is_tablet_mode = Shell::Get()->tablet_mode_controller() + ? Shell::Get() + ->tablet_mode_controller() + ->IsTabletModeWindowManagerEnabled() + : false; + for (int i = 0; i < view_model_->view_size(); ++i) { if (i < first_visible_index_) { view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0)); continue; } - view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); - x = shelf_->PrimaryAxisValue(x + w + kShelfButtonSpacing, x); - y = shelf_->PrimaryAxisValue(y, y + h + kShelfButtonSpacing); + int width = w; + int height = h; + // If this is the app list button and we are in tablet mode, make space for + // the back button (which is part of the app list button). + if (i == 0 && is_tablet_mode) { + width = shelf_->PrimaryAxisValue(2 * w + kShelfButtonSpacing, w); + height = shelf_->PrimaryAxisValue(h, 2 * h + kShelfButtonSpacing); + } + + view_model_->set_ideal_bounds(i, gfx::Rect(x, y, width, height)); + x = shelf_->PrimaryAxisValue(x + width + kShelfButtonSpacing, x); + y = shelf_->PrimaryAxisValue(y, y + height + kShelfButtonSpacing); } if (is_overflow_mode()) {
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index cd114fd..a072e152 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -35,6 +35,7 @@ #include "ash/test_shell_delegate.h" #include "ash/wallpaper/wallpaper_controller.h" #include "ash/wallpaper/wallpaper_controller_test_api.h" +#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/i18n/rtl.h" #include "base/macros.h" #include "base/memory/ptr_util.h" @@ -2548,6 +2549,127 @@ namespace { +// Test fixture to run app list button ink drop tests for both mouse and touch +// events. +class AppListButtonInkDropTest + : public ShelfViewInkDropTest, + public testing::WithParamInterface<ui::EventPointerType> { + public: + AppListButtonInkDropTest() : pointer_type_(GetParam()) {} + + ~AppListButtonInkDropTest() override {} + + void MovePointerTo(const gfx::Point& point) { + if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_MOUSE) + GetEventGenerator().MoveMouseTo(point); + else if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH) + GetEventGenerator().MoveTouch(point); + } + + void PressPointer() { + if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_MOUSE) + GetEventGenerator().PressLeftButton(); + else if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH) + GetEventGenerator().PressTouch(); + } + + void ReleasePointer() { + if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_MOUSE) + GetEventGenerator().ReleaseLeftButton(); + else if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH) + GetEventGenerator().ReleaseTouch(); + } + + private: + ui::EventPointerType pointer_type_; + + DISALLOW_COPY_AND_ASSIGN(AppListButtonInkDropTest); +}; + +const ui::EventPointerType kPointerTypes[] = { + ui::EventPointerType::POINTER_TYPE_MOUSE, + ui::EventPointerType::POINTER_TYPE_TOUCH}; + +} // namespace + +// Tests that clicking/tapping on the app list button in tablet mode (when +// it has two functionalities), transitions the ink drop state correctly. +TEST_P(AppListButtonInkDropTest, AppListButtonInTabletMode) { + // TODO: investigate failure in mash, http://crbug.com/695751. + if (Shell::GetAshConfig() == Config::MASH) + return; + + InitAppListButtonInkDrop(); + + // Verify the app list button bounds change when we enter tablet mode. + const gfx::Rect old_bounds = app_list_button_->GetBoundsInScreen(); + Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true); + gfx::Rect new_bounds = app_list_button_->GetBoundsInScreen(); + EXPECT_EQ(new_bounds.height(), old_bounds.height()); + EXPECT_GT(new_bounds.width(), old_bounds.width()); + + gfx::Point point_on_circle = app_list_button_->GetAppListButtonCenterPoint(); + views::View::ConvertPointToScreen(app_list_button_, &point_on_circle); + gfx::Point point_on_back_button = + app_list_button_->GetBackButtonCenterPoint(); + views::View::ConvertPointToScreen(app_list_button_, &point_on_back_button); + + // Verify the ink drop state transitions as expected when we press and + // release on the app list circle part of the app list button. Taps on the + // app list circle, which shows the app list, should end up in the activated + // state. + MovePointerTo(point_on_circle); + PressPointer(); + EXPECT_EQ(views::InkDropState::ACTION_PENDING, + app_list_button_ink_drop_->GetTargetInkDropState()); + EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(), + ElementsAre(views::InkDropState::ACTION_PENDING)); + ReleasePointer(); + + // Trigger a mock button notification that the app list was shown. + app_list_button_->OnAppListShown(); + FinishAppListVisibilityChange(); + EXPECT_EQ(views::InkDropState::ACTIVATED, + app_list_button_ink_drop_->GetTargetInkDropState()); + EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(), + ElementsAre(views::InkDropState::ACTIVATED)); + + // Trigger a mock button notification that the app list was dismissed. + app_list_button_->OnAppListDismissed(); + FinishAppListVisibilityChange(); + EXPECT_EQ(views::InkDropState::HIDDEN, + app_list_button_ink_drop_->GetTargetInkDropState()); + EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(), + ElementsAre(views::InkDropState::DEACTIVATED)); + + // Verify the ink drop state transitions as expected when we tap on the back + // button part of the app list button. + MovePointerTo(point_on_back_button); + PressPointer(); + EXPECT_EQ(views::InkDropState::ACTION_PENDING, + app_list_button_ink_drop_->GetTargetInkDropState()); + EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(), + ElementsAre(views::InkDropState::ACTION_PENDING)); + ReleasePointer(); + EXPECT_EQ(views::InkDropState::HIDDEN, + app_list_button_ink_drop_->GetTargetInkDropState()); + EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(), + ElementsAre(views::InkDropState::ACTION_TRIGGERED)); + + // Verify when we leave tablet mode, the bounds should return to be the same + // as they were before we entered tablet mode. + Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false); + new_bounds = app_list_button_->GetBoundsInScreen(); + EXPECT_EQ(new_bounds, old_bounds); +} + +INSTANTIATE_TEST_CASE_P( + /* prefix intentionally left blank due to only one parameterization */, + AppListButtonInkDropTest, + ::testing::ValuesIn(kPointerTypes)); + +namespace { + // An empty menu model for shell context menu just to have a menu. class TestShellMenuModel : public ui::SimpleMenuModel, public ui::SimpleMenuModel::Delegate {
diff --git a/ash/shelf/voice_interaction_overlay.cc b/ash/shelf/voice_interaction_overlay.cc index 4b6edd5..139f2c4 100644 --- a/ash/shelf/voice_interaction_overlay.cc +++ b/ash/shelf/voice_interaction_overlay.cc
@@ -470,7 +470,7 @@ kRippleCircleStartRadiusDip / kRippleCircleInitRadiusDip; gfx::Transform transform; - const gfx::Point center = host_view_->GetCenterPoint(); + const gfx::Point center = host_view_->GetAppListButtonCenterPoint(); transform.Translate(center.x() - kRippleCircleStartRadiusDip, center.y() - kRippleCircleStartRadiusDip); transform.Scale(scale_factor, scale_factor); @@ -568,7 +568,7 @@ is_bursting_ = true; should_hide_animation_ = false; - gfx::Point center = host_view_->GetCenterPoint(); + gfx::Point center = host_view_->GetAppListButtonCenterPoint(); gfx::Transform transform; // Setup ripple animations. @@ -646,7 +646,7 @@ kRippleCircleStartRadiusDip / kRippleCircleInitRadiusDip; gfx::Transform transform; - const gfx::Point center = host_view_->GetCenterPoint(); + const gfx::Point center = host_view_->GetAppListButtonCenterPoint(); transform.Translate(center.x() - kRippleCircleStartRadiusDip, center.y() - kRippleCircleStartRadiusDip); transform.Scale(scale_factor, scale_factor);
diff --git a/base/BUILD.gn b/base/BUILD.gn index 334d6be..1e0ba61 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -2243,7 +2243,6 @@ "win/pe_image_unittest.cc", "win/registry_unittest.cc", "win/scoped_bstr_unittest.cc", - "win/scoped_comptr_unittest.cc", "win/scoped_handle_unittest.cc", "win/scoped_process_information_unittest.cc", "win/scoped_variant_unittest.cc",
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java b/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java index 08161f90..105a31c 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
@@ -198,16 +198,17 @@ } @Override - public void onChildStartFailed() { + public void onChildStartFailed(final ChildProcessConnection connection) { assert isRunningOnLauncherThread(); if (serviceCallback != null) { mLauncherHandler.post(new Runnable() { @Override public void run() { - serviceCallback.onChildStartFailed(); + serviceCallback.onChildStartFailed(connection); } }); } + freeConnectionWithDelay(connection); } @Override @@ -221,7 +222,10 @@ } }); } + freeConnectionWithDelay(connection); + } + private void freeConnectionWithDelay(final ChildProcessConnection connection) { // Freeing a service should be delayed. This is so that we avoid immediately // reusing the freed service (see http://crbug.com/164069): the framework // might keep a service process alive when it's been unbound for a short
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java index 5088020..9019b2a 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
@@ -45,11 +45,9 @@ /** * Called when the child process failed to start. This can happen if the process is already - * in use by another client. Note onChildProcessDied will be called after this callback, - * once the client unbinds and the service gets cleaned. - * TODO(jcivelli): crbug.com/736948 we should improve the behavior in such cases. + * in use by another client. The client will not receive any other callbacks after this one. */ - void onChildStartFailed(); + void onChildStartFailed(ChildProcessConnection connection); /** * Called when the service has been disconnected. whether it was stopped by the client or @@ -402,10 +400,7 @@ */ public void stop() { assert isRunningOnLauncherThread(); - cancelWatchDog(); unbind(); - mService = null; - mConnectionParams = null; notifyChildProcessDied(); } @@ -431,8 +426,9 @@ try { if (!mService.bindToCaller()) { if (mServiceCallback != null) { - mServiceCallback.onChildStartFailed(); + mServiceCallback.onChildStartFailed(this); } + unbind(); return; } } catch (RemoteException ex) { @@ -537,6 +533,9 @@ @VisibleForTesting protected void unbind() { assert isRunningOnLauncherThread(); + cancelWatchDog(); + mService = null; + mConnectionParams = null; mUnbound = true; unbindAll(); // Note that we don't update the waived bound only state here as to preserve the state when
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java index 9a52a7d..cd1ff1e 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java
@@ -145,8 +145,9 @@ public void onChildStarted() {} @Override - public void onChildStartFailed() { + public void onChildStartFailed(ChildProcessConnection connection) { assert isRunningOnLauncherThread(); + assert mConnection == connection; Log.e(TAG, "ChildProcessConnection.start failed, trying again"); mLauncherHandler.post(new Runnable() { @Override
diff --git a/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java b/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java index 50c3eb2..982daaa 100644 --- a/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java +++ b/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
@@ -10,14 +10,17 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -45,6 +48,9 @@ private static final int MAX_CONNECTION_NUMBER = 2; + private static final int FREE_CONNECTION_TEST_CALLBACK_START_FAILED = 1; + private static final int FREE_CONNECTION_TEST_CALLBACK_PROCESS_DIED = 2; + @Mock private ChildProcessConnection.ServiceCallback mServiceCallback; @@ -98,7 +104,7 @@ serviceCallback.onChildStarted(); } if (onStartFailed) { - serviceCallback.onChildStartFailed(); + serviceCallback.onChildStartFailed(connection); } if (onChildProcessDied) { serviceCallback.onChildProcessDied(connection); @@ -111,6 +117,10 @@ anyBoolean()); } + public void simulateServiceStartFailed() { + mConnectionServiceCallback.onChildStartFailed(mConnection); + } + public void simulateServiceProcessDying() { mConnectionServiceCallback.onChildProcessDied(mConnection); } @@ -183,7 +193,7 @@ allocator.setConnectionFactoryForTesting(mTestConnectionFactory); ChildProcessConnection connection = allocator.allocate( null /* context */, null /* serviceBundle */, mServiceCallback); - verify(connection, times(0)) + verify(connection, never()) .start(useStrongBinding, mServiceCallback, false /* retryOnTimeout */); } } @@ -203,13 +213,13 @@ assertNotNull(connection); // Callbacks are posted. - verify(mServiceCallback, times(0)).onChildStarted(); - verify(mServiceCallback, times(0)).onChildStartFailed(); - verify(mServiceCallback, times(0)).onChildProcessDied(any()); + verify(mServiceCallback, never()).onChildStarted(); + verify(mServiceCallback, never()).onChildStartFailed(any()); + verify(mServiceCallback, never()).onChildProcessDied(any()); ShadowLooper.unPauseMainLooper(); ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); verify(mServiceCallback, times(onChildStarted ? 1 : 0)).onChildStarted(); - verify(mServiceCallback, times(onChildStartFailed ? 1 : 0)).onChildStartFailed(); + verify(mServiceCallback, times(onChildStartFailed ? 1 : 0)).onChildStartFailed(any()); verify(mServiceCallback, times(onChildProcessDied ? 1 : 0)).onChildProcessDied(any()); } @@ -234,25 +244,62 @@ true /* onChildProcessDied */); } - /** Tests that the allocator clears the connection when it stops and that the listener gets - * invoked. */ - @Test - @Feature({"ProcessManagement"}) - public void testFreeConnectionOnChildProcessDied() { + /** + * Tests that the allocator clears the connection when it fails to bind/process dies and that + * the listener gets invoked. + */ + private void testFreeConnection(int callbackType) { ChildConnectionAllocator.Listener listener = mock(ChildConnectionAllocator.Listener.class); - mAllocator.addListener(listener); ChildProcessConnection connection = mAllocator.allocate(null /* context */, null /* serviceBundle */, mServiceCallback); + assertNotNull(connection); + ComponentName serviceName = mTestConnectionFactory.getAndResetLastServiceName(); verify(connection, times(1)) .start(eq(false) /* useStrongBinding */, any(ChildProcessConnection.ServiceCallback.class), anyBoolean()); assertTrue(mAllocator.anyConnectionAllocated()); - - mTestConnectionFactory.simulateServiceProcessDying(); + int onChildStartFailedExpectedCount = 0; + int onChildProcessDiedExpectedCount = 0; + switch (callbackType) { + case FREE_CONNECTION_TEST_CALLBACK_START_FAILED: + mTestConnectionFactory.simulateServiceStartFailed(); + onChildStartFailedExpectedCount = 1; + break; + case FREE_CONNECTION_TEST_CALLBACK_PROCESS_DIED: + mTestConnectionFactory.simulateServiceProcessDying(); + onChildProcessDiedExpectedCount = 1; + break; + default: + fail(); + break; + } ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); assertFalse(mAllocator.anyConnectionAllocated()); verify(listener, times(1)).onConnectionFreed(mAllocator, connection); + verify(mServiceCallback, never()).onChildStarted(); + verify(mServiceCallback, times(onChildStartFailedExpectedCount)) + .onChildStartFailed(connection); + verify(mServiceCallback, times(onChildProcessDiedExpectedCount)) + .onChildProcessDied(connection); + + // Allocate a new connection to make sure we are not getting the same connection. + connection = + mAllocator.allocate(null /* context */, null /* serviceBundle */, mServiceCallback); + assertNotNull(connection); + assertNotEquals(mTestConnectionFactory.getAndResetLastServiceName(), serviceName); + } + + @Test + @Feature({"ProcessManagement"}) + public void testFreeConnectionOnChildStartFailed() { + testFreeConnection(FREE_CONNECTION_TEST_CALLBACK_START_FAILED); + } + + @Test + @Feature({"ProcessManagement"}) + public void testFreeConnectionOnChildProcessDied() { + testFreeConnection(FREE_CONNECTION_TEST_CALLBACK_PROCESS_DIED); } }
diff --git a/base/android/junit/src/org/chromium/base/process_launcher/ChildProcessConnectionTest.java b/base/android/junit/src/org/chromium/base/process_launcher/ChildProcessConnectionTest.java index 17c39d1e4..8689e5e3 100644 --- a/base/android/junit/src/org/chromium/base/process_launcher/ChildProcessConnectionTest.java +++ b/base/android/junit/src/org/chromium/base/process_launcher/ChildProcessConnectionTest.java
@@ -198,14 +198,14 @@ Assert.assertTrue(connection.isInitialBindingBound()); Assert.assertFalse(connection.didOnServiceConnectedForTesting()); verify(mServiceCallback, never()).onChildStarted(); - verify(mServiceCallback, never()).onChildStartFailed(); + verify(mServiceCallback, never()).onChildStartFailed(any()); verify(mServiceCallback, never()).onChildProcessDied(any()); // The service connects. mFirstServiceConnection.notifyServiceConnected(null /* iBinder */); Assert.assertTrue(connection.didOnServiceConnectedForTesting()); verify(mServiceCallback, times(1)).onChildStarted(); - verify(mServiceCallback, never()).onChildStartFailed(); + verify(mServiceCallback, never()).onChildStartFailed(any()); verify(mServiceCallback, never()).onChildProcessDied(any()); } @@ -221,7 +221,7 @@ Assert.assertFalse(connection.isInitialBindingBound()); Assert.assertFalse(connection.didOnServiceConnectedForTesting()); verify(mServiceCallback, never()).onChildStarted(); - verify(mServiceCallback, never()).onChildStartFailed(); + verify(mServiceCallback, never()).onChildStartFailed(any()); verify(mServiceCallback, times(1)).onChildProcessDied(connection); } @@ -233,7 +233,7 @@ mFirstServiceConnection.notifyServiceConnected(null /* iBinder */); connection.stop(); verify(mServiceCallback, times(1)).onChildStarted(); - verify(mServiceCallback, never()).onChildStartFailed(); + verify(mServiceCallback, never()).onChildStartFailed(any()); verify(mServiceCallback, times(1)).onChildProcessDied(connection); } @@ -245,7 +245,7 @@ mFirstServiceConnection.notifyServiceConnected(null /* iBinder */); mFirstServiceConnection.notifyServiceDisconnected(); verify(mServiceCallback, times(1)).onChildStarted(); - verify(mServiceCallback, never()).onChildStartFailed(); + verify(mServiceCallback, never()).onChildStartFailed(any()); verify(mServiceCallback, times(1)).onChildProcessDied(connection); } @@ -258,7 +258,7 @@ mFirstServiceConnection.notifyServiceConnected(mChildProcessServiceBinder); // Service is started and bindToCallback is not called. verify(mServiceCallback, times(1)).onChildStarted(); - verify(mServiceCallback, never()).onChildStartFailed(); + verify(mServiceCallback, never()).onChildStartFailed(any()); verify(mServiceCallback, never()).onChildProcessDied(connection); verify(mIChildProcessService, never()).bindToCaller(); } @@ -273,7 +273,7 @@ mFirstServiceConnection.notifyServiceConnected(mChildProcessServiceBinder); // Service is started and bindToCallback is called. verify(mServiceCallback, times(1)).onChildStarted(); - verify(mServiceCallback, never()).onChildStartFailed(); + verify(mServiceCallback, never()).onChildStartFailed(any()); verify(mServiceCallback, never()).onChildProcessDied(connection); verify(mIChildProcessService, times(1)).bindToCaller(); } @@ -290,7 +290,7 @@ mFirstServiceConnection.notifyServiceConnected(mChildProcessServiceBinder); // Service fails to start. verify(mServiceCallback, never()).onChildStarted(); - verify(mServiceCallback, times(1)).onChildStartFailed(); + verify(mServiceCallback, times(1)).onChildStartFailed(any()); verify(mServiceCallback, never()).onChildProcessDied(connection); verify(mIChildProcessService, times(1)).bindToCaller(); }
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc index 435b39b..0f001f9 100644 --- a/base/metrics/histogram.cc +++ b/base/metrics/histogram.cc
@@ -354,12 +354,10 @@ if (delta != delta64) delta = INT_MAX; // Flag all giant errors as INT_MAX. if (delta > 0) { - UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta); if (delta > kCommonRaceBasedCountMismatch) inconsistencies |= COUNT_HIGH_ERROR; } else { DCHECK_GT(0, delta); - UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta); if (-delta > kCommonRaceBasedCountMismatch) inconsistencies |= COUNT_LOW_ERROR; }
diff --git a/base/timer/timer_unittest.cc b/base/timer/timer_unittest.cc index 3e486d01d..01ce876 100644 --- a/base/timer/timer_unittest.cc +++ b/base/timer/timer_unittest.cc
@@ -419,7 +419,7 @@ OneShotTimerTester f(&did_run); f.SetTaskRunner(other_thread.task_runner()); f.Start(); - EXPECT_TRUE(f.IsRunning()); + EXPECT_TRUE(f.IsRunning() || did_run.IsSignaled()); f.WaitAndConfirmTimerFiredAfterDelay(); EXPECT_TRUE(did_run.IsSignaled());
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h index a7b089e5f..6f40050 100644 --- a/base/win/scoped_comptr.h +++ b/base/win/scoped_comptr.h
@@ -5,256 +5,13 @@ #ifndef BASE_WIN_SCOPED_COMPTR_H_ #define BASE_WIN_SCOPED_COMPTR_H_ -#include <stddef.h> -#include <unknwn.h> - -#include "base/logging.h" +#include <wrl/client.h> namespace base { namespace win { -namespace details { - template <typename T> -class ScopedComPtrRef; - -} // details - -// DEPRECATED: Use Microsoft::WRL::ComPtr instead. -// A fairly minimalistic smart class for COM interface pointers. -template <class Interface> -class ScopedComPtr { - public: - using InterfaceType = Interface; - - // Utility template to prevent users of ScopedComPtr from calling AddRef - // and/or Release() without going through the ScopedComPtr class. - class BlockIUnknownMethods : public Interface { - private: - STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0; - STDMETHOD_(ULONG, AddRef)() = 0; - STDMETHOD_(ULONG, Release)() = 0; - }; - - ScopedComPtr() {} - - ScopedComPtr(std::nullptr_t) : ptr_(nullptr) {} - - explicit ScopedComPtr(Interface* p) : ptr_(p) { - if (ptr_) - ptr_->AddRef(); - } - - ScopedComPtr(const ScopedComPtr<Interface>& p) : ptr_(p.Get()) { - if (ptr_) - ptr_->AddRef(); - } - - ~ScopedComPtr() { - // We don't want the smart pointer class to be bigger than the pointer - // it wraps. - static_assert(sizeof(ScopedComPtr<Interface>) == sizeof(Interface*), - "ScopedComPtrSize"); - Reset(); - } - - Interface* Get() const { return ptr_; } - - explicit operator bool() const { return ptr_ != nullptr; } - - // Explicit Release() of the held object. Useful for reuse of the - // ScopedComPtr instance. - // Note that this function equates to IUnknown::Release and should not - // be confused with e.g. unique_ptr::release(). - unsigned long Reset() { - unsigned long ref = 0; - Interface* temp = ptr_; - if (temp) { - ptr_ = nullptr; - ref = temp->Release(); - } - return ref; - } - - // Sets the internal pointer to NULL and returns the held object without - // releasing the reference. - Interface* Detach() { - Interface* p = ptr_; - ptr_ = nullptr; - return p; - } - - // Accepts an interface pointer that has already been addref-ed. - void Attach(Interface* p) { - DCHECK(!ptr_); - ptr_ = p; - } - - // Retrieves the pointer address. - // Used to receive object pointers as out arguments (and take ownership). - // The function DCHECKs on the current value being NULL. - // Usage: Foo(p.GetAddressOf()); - Interface** GetAddressOf() { - DCHECK(!ptr_) << "Object leak. Pointer must be NULL"; - return &ptr_; - } - - template <class Query> - HRESULT CopyTo(Query** p) { - DCHECK(p); - DCHECK(ptr_); - // IUnknown already has a template version of QueryInterface - // so the iid parameter is implicit here. The only thing this - // function adds are the DCHECKs. - return ptr_->QueryInterface(IID_PPV_ARGS(p)); - } - - // QI for times when the IID is not associated with the type. - HRESULT CopyTo(const IID& iid, void** obj) { - DCHECK(obj); - DCHECK(ptr_); - return ptr_->QueryInterface(iid, obj); - } - - // Provides direct access to the interface. - // Here we use a well known trick to make sure we block access to - // IUnknown methods so that something bad like this doesn't happen: - // ScopedComPtr<IUnknown> p(Foo()); - // p->Release(); - // ... later the destructor runs, which will Release() again. - // and to get the benefit of the DCHECKs we add to QueryInterface. - // There's still a way to call these methods if you absolutely must - // by statically casting the ScopedComPtr instance to the wrapped interface - // and then making the call... but generally that shouldn't be necessary. - BlockIUnknownMethods* operator->() const { - DCHECK(ptr_); - return reinterpret_cast<BlockIUnknownMethods*>(ptr_); - } - - ScopedComPtr<Interface>& operator=(std::nullptr_t) { - Reset(); - return *this; - } - - ScopedComPtr<Interface>& operator=(Interface* rhs) { - // AddRef first so that self assignment should work - if (rhs) - rhs->AddRef(); - Interface* old_ptr = ptr_; - ptr_ = rhs; - if (old_ptr) - old_ptr->Release(); - return *this; - } - - ScopedComPtr<Interface>& operator=(const ScopedComPtr<Interface>& rhs) { - return *this = rhs.ptr_; - } - - Interface& operator*() const { - DCHECK(ptr_); - return *ptr_; - } - - bool operator==(const ScopedComPtr<Interface>& rhs) const { - return ptr_ == rhs.Get(); - } - - template <typename U> - bool operator==(const ScopedComPtr<U>& rhs) const { - return ptr_ == rhs.Get(); - } - - template <typename U> - bool operator==(const U* rhs) const { - return ptr_ == rhs; - } - - bool operator!=(const ScopedComPtr<Interface>& rhs) const { - return ptr_ != rhs.Get(); - } - - template <typename U> - bool operator!=(const ScopedComPtr<U>& rhs) const { - return ptr_ != rhs.Get(); - } - - template <typename U> - bool operator!=(const U* rhs) const { - return ptr_ != rhs; - } - - details::ScopedComPtrRef<ScopedComPtr<Interface>> operator&() { - return details::ScopedComPtrRef<ScopedComPtr<Interface>>(this); - } - - void Swap(ScopedComPtr<Interface>& r) { - Interface* tmp = ptr_; - ptr_ = r.ptr_; - r.ptr_ = tmp; - } - - private: - Interface* ptr_ = nullptr; -}; - -namespace details { - -// ComPtrRef equivalent transitional reference type to handle ComPtr equivalent -// void** implicit casting. T should be a ScopedComPtr. -template <typename T> -class ScopedComPtrRef { - public: - explicit ScopedComPtrRef(T* scoped_com_ptr) - : scoped_com_ptr_(scoped_com_ptr) {} - - // ComPtr equivalent conversion operators. - operator void**() const { - return reinterpret_cast<void**>(scoped_com_ptr_->GetAddressOf()); - } - - // Allows ScopedComPtr to be passed to functions as a pointer. - operator T*() { return scoped_com_ptr_; } - - // Equivalent to ComPtrRef's version of this operator. - operator typename T::InterfaceType**() { - return scoped_com_ptr_->GetAddressOf(); - } - - // Allows IID_PPV_ARGS to perform __uuidof(**(ppType)). - typename T::InterfaceType* operator*() { return scoped_com_ptr_->Get(); } - - private: - T* const scoped_com_ptr_; -}; - -} // details - -template <typename T> -bool operator==(const ScopedComPtr<T>& lhs, std::nullptr_t null) { - return !static_cast<bool>(lhs); -} - -template <typename T> -bool operator==(std::nullptr_t null, const ScopedComPtr<T>& rhs) { - return !static_cast<bool>(rhs); -} - -template <typename T> -bool operator!=(const ScopedComPtr<T>& lhs, std::nullptr_t null) { - return !operator==(lhs, null); -} - -template <typename T> -bool operator!=(std::nullptr_t null, const ScopedComPtr<T>& rhs) { - return !operator==(null, rhs); -} - -// Helper to make IID_PPV_ARGS work with ScopedComPtr. -template <typename T> -void** IID_PPV_ARGS_Helper(base::win::details::ScopedComPtrRef<T> pp) throw() { - return pp; -} +using ScopedComPtr = Microsoft::WRL::ComPtr<T>; } // namespace win } // namespace base
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc deleted file mode 100644 index 523e908..0000000 --- a/base/win/scoped_comptr_unittest.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/scoped_comptr.h" - -#include <objbase.h> -#include <shlobj.h> - -#include <memory> - -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -struct Dummy { - Dummy() : adds(0), releases(0) { } - unsigned long AddRef() { return ++adds; } - unsigned long Release() { return ++releases; } - - int adds; - int releases; -}; - -} // namespace - -TEST(ScopedComPtrTest, ScopedComPtr) { - base::win::ScopedCOMInitializer com_initializer; - EXPECT_TRUE(com_initializer.succeeded()); - - ScopedComPtr<IUnknown> unk; - EXPECT_TRUE(SUCCEEDED(::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, - IID_PPV_ARGS(&unk)))); - ScopedComPtr<IUnknown> unk2; - unk2.Attach(unk.Detach()); - EXPECT_TRUE(unk.Get() == NULL); - EXPECT_TRUE(unk2.Get() != NULL); - - ScopedComPtr<IMalloc> mem_alloc; - EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.GetAddressOf()))); - - ScopedComPtr<IUnknown> qi_test; - EXPECT_HRESULT_SUCCEEDED(mem_alloc.CopyTo(IID_PPV_ARGS(&qi_test))); - EXPECT_TRUE(qi_test.Get() != NULL); -} - -TEST(ScopedComPtrTest, ScopedComPtrVector) { - // Verify we don't get error C2558. - typedef ScopedComPtr<Dummy> Ptr; - std::vector<Ptr> bleh; - - std::unique_ptr<Dummy> p(new Dummy); - { - Ptr p2(p.get()); - EXPECT_EQ(p->adds, 1); - EXPECT_EQ(p->releases, 0); - Ptr p3 = p2; - EXPECT_EQ(p->adds, 2); - EXPECT_EQ(p->releases, 0); - p3 = p2; - EXPECT_EQ(p->adds, 3); - EXPECT_EQ(p->releases, 1); - // To avoid hitting a reallocation. - bleh.reserve(1); - bleh.push_back(p2); - EXPECT_EQ(p->adds, 4); - EXPECT_EQ(p->releases, 1); - EXPECT_EQ(bleh[0].Get(), p.get()); - bleh.pop_back(); - EXPECT_EQ(p->adds, 4); - EXPECT_EQ(p->releases, 2); - } - EXPECT_EQ(p->adds, 4); - EXPECT_EQ(p->releases, 4); -} - -} // namespace win -} // namespace base
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index de3f35f..d0795d7d 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -208,7 +208,7 @@ # On Windows always use the target CPU for host builds. On the # configurations we support this will always work and it saves build steps. if (is_clang) { - host_toolchain = "//build/toolchain/win:clang_$target_cpu" + host_toolchain = "//build/toolchain/win:win_clang_$target_cpu" } else { host_toolchain = "//build/toolchain/win:$target_cpu" } @@ -247,7 +247,7 @@ # On Windows we use the same toolchain for host and target by default. assert(target_os == host_os, "Win cross-compiles only work on win hosts.") if (is_clang) { - _default_toolchain = "//build/toolchain/win:clang_$target_cpu" + _default_toolchain = "//build/toolchain/win:win_clang_$target_cpu" } else { _default_toolchain = "//build/toolchain/win:$target_cpu" }
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn index 90777eb..bace798 100644 --- a/build/toolchain/win/BUILD.gn +++ b/build/toolchain/win/BUILD.gn
@@ -356,7 +356,7 @@ } } - msvc_toolchain("clang_x86") { + msvc_toolchain("win_clang_x86") { environment = "environment.x86" prefix = rebase_path("$clang_base_path/bin", root_build_dir) cl = "${goma_prefix}$prefix/${clang_cl}" @@ -393,7 +393,7 @@ } } - msvc_toolchain("clang_" + target_name) { + msvc_toolchain("win_clang_" + target_name) { environment = "environment.x64" prefix = rebase_path("$clang_base_path/bin", root_build_dir) cl = "${goma_prefix}$prefix/${clang_cl}"
diff --git a/build/toolchain/win/clang_name.gni b/build/toolchain/win/clang_name.gni deleted file mode 100644 index d72735c..0000000 --- a/build/toolchain/win/clang_name.gni +++ /dev/null
@@ -1,7 +0,0 @@ -# Copyright 2017 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# The name of the 64-bit win clang toolchain. -# TODO(thakis): Remove this again soon, https://crbug.com/748501 -win_clang_x64_toolchain = "//build/toolchain/win:clang_x64"
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc index 014e98ce..cff5f34 100644 --- a/cc/paint/paint_op_buffer.cc +++ b/cc/paint/paint_op_buffer.cc
@@ -595,10 +595,10 @@ } template <typename T> -PaintOp* SimpleDeserialize(const void* input, - size_t input_size, - void* output, - size_t output_size) { +T* SimpleDeserialize(const void* input, + size_t input_size, + void* output, + size_t output_size) { if (input_size < sizeof(T)) return nullptr; memcpy(output, input, sizeof(T)); @@ -641,7 +641,7 @@ helper.Read(&op->path); helper.Read(&op->op); helper.Read(&op->antialias); - if (!helper.valid()) { + if (!helper.valid() || !IsValidSkClipOp(op->op)) { op->~ClipPathOp(); return nullptr; } @@ -654,14 +654,18 @@ size_t input_size, void* output, size_t output_size) { - return SimpleDeserialize<ClipRectOp>(input, input_size, output, output_size); + ClipRectOp* op = + SimpleDeserialize<ClipRectOp>(input, input_size, output, output_size); + return op && IsValidSkClipOp(op->op) ? op : nullptr; } PaintOp* ClipRRectOp::Deserialize(const void* input, size_t input_size, void* output, size_t output_size) { - return SimpleDeserialize<ClipRRectOp>(input, input_size, output, output_size); + ClipRRectOp* op = + SimpleDeserialize<ClipRRectOp>(input, input_size, output, output_size); + return op && IsValidSkClipOp(op->op) ? op : nullptr; } PaintOp* ConcatOp::Deserialize(const void* input, @@ -716,7 +720,9 @@ size_t input_size, void* output, size_t output_size) { - return SimpleDeserialize<DrawColorOp>(input, input_size, output, output_size); + DrawColorOp* op = + SimpleDeserialize<DrawColorOp>(input, input_size, output, output_size); + return op && IsValidSkBlendMode(op->mode) ? op : nullptr; } PaintOp* DrawDRRectOp::Deserialize(const void* input,
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h index 813aef42..6ed9545 100644 --- a/cc/paint/paint_op_buffer.h +++ b/cc/paint/paint_op_buffer.h
@@ -147,6 +147,16 @@ // memory buffers and so don't have their destructors run automatically. void DestroyThis(); + static bool IsValidSkBlendMode(SkBlendMode mode) { + return static_cast<uint32_t>(mode) <= + static_cast<uint32_t>(SkBlendMode::kLastCoeffMode); + } + + static bool IsValidSkClipOp(SkClipOp op) { + return static_cast<uint32_t>(op) <= + static_cast<uint32_t>(SkClipOp::kMax_EnumValue); + } + static constexpr bool kIsDrawOp = false; static constexpr bool kHasPaintFlags = false; // Since skip and type fit in a uint32_t, this is the max size of skip.
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc index c0e2855..4c6bc27 100644 --- a/cc/paint/paint_op_buffer_unittest.cc +++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -24,6 +24,11 @@ namespace cc { namespace { +// An arbitrary size guaranteed to fit the size of any serialized op in this +// unit test. This can also be used for deserialized op size safely in this +// unit test suite as generally deserialized ops are smaller. +static constexpr size_t kBufferBytesPerOp = 1000 + sizeof(LargestPaintOp); + void ExpectFlattenableEqual(SkFlattenable* expected, SkFlattenable* actual) { sk_sp<SkData> expected_data(SkValidatingSerializeFlattenable(expected)); sk_sp<SkData> actual_data(SkValidatingSerializeFlattenable(actual)); @@ -1988,7 +1993,7 @@ void ResizeOutputBuffer() { // An arbitrary deserialization buffer size that should fit all the ops // in the buffer_. - output_size_ = (1000 + sizeof(LargestPaintOp)) * buffer_.size(); + output_size_ = kBufferBytesPerOp * buffer_.size(); output_.reset(static_cast<char*>( base::AlignedAlloc(output_size_, PaintOpBuffer::PaintOpAlign))); } @@ -2097,7 +2102,7 @@ char* current = static_cast<char*>(output_.get()); static constexpr size_t kAlign = PaintOpBuffer::PaintOpAlign; - static constexpr size_t kOutputOpSize = sizeof(LargestPaintOp) + 1000; + static constexpr size_t kOutputOpSize = kBufferBytesPerOp; std::unique_ptr<char, base::AlignedFreeDeleter> deserialize_buffer_( static_cast<char*>(base::AlignedAlloc(kOutputOpSize, kAlign))); @@ -2184,4 +2189,123 @@ PaintOp::Deserialize(input_.get(), bytes_written, output_.get(), kSize)); } +// Test that deserializing invalid SkClipOp enums fails silently. +// Skia release asserts on this in several places so these are not safe +// to pass through to the SkCanvas API. +TEST(PaintOpBufferTest, ValidateSkClip) { + size_t buffer_size = kBufferBytesPerOp; + std::unique_ptr<char, base::AlignedFreeDeleter> serialized(static_cast<char*>( + base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign))); + std::unique_ptr<char, base::AlignedFreeDeleter> deserialized( + static_cast<char*>( + base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign))); + + PaintOpBuffer buffer; + + // Successful first op. + SkPath path; + buffer.push<ClipPathOp>(path, SkClipOp::kMax_EnumValue, true); + + // Bad other ops. + SkClipOp bad_clip = static_cast<SkClipOp>( + static_cast<uint32_t>(SkClipOp::kMax_EnumValue) + 1); + + buffer.push<ClipPathOp>(path, bad_clip, true); + buffer.push<ClipRectOp>(test_rects[0], bad_clip, true); + buffer.push<ClipRRectOp>(test_rrects[0], bad_clip, false); + + SkClipOp bad_clip_max = static_cast<SkClipOp>(~static_cast<uint32_t>(0)); + buffer.push<ClipRectOp>(test_rects[1], bad_clip_max, false); + + PaintOp::SerializeOptions options; + + int op_idx = 0; + for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) { + const PaintOp* op = *iter; + size_t bytes_written = + op->Serialize(serialized.get(), buffer_size, options); + ASSERT_GT(bytes_written, 0u); + PaintOp* written = PaintOp::Deserialize(serialized.get(), bytes_written, + deserialized.get(), buffer_size); + // First op should succeed. Other ops with bad enums should + // serialize correctly but fail to deserialize due to the bad + // SkClipOp enum. + if (!op_idx) { + EXPECT_TRUE(written) << "op: " << op_idx; + written->DestroyThis(); + } else { + EXPECT_FALSE(written) << "op: " << op_idx; + } + + ++op_idx; + } +} + +TEST(PaintOpBufferTest, ValidateSkBlendMode) { + size_t buffer_size = kBufferBytesPerOp; + std::unique_ptr<char, base::AlignedFreeDeleter> serialized(static_cast<char*>( + base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign))); + std::unique_ptr<char, base::AlignedFreeDeleter> deserialized( + static_cast<char*>( + base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign))); + + PaintOpBuffer buffer; + + // Successful first two ops. + buffer.push<DrawColorOp>(SK_ColorMAGENTA, SkBlendMode::kDstIn); + buffer.push<DrawRectOp>(test_rects[0], test_flags[0]); + + // Modes that are not supported by drawColor or SkPaint. + SkBlendMode bad_modes[] = { + SkBlendMode::kOverlay, + SkBlendMode::kDarken, + SkBlendMode::kLighten, + SkBlendMode::kColorDodge, + SkBlendMode::kColorBurn, + SkBlendMode::kHardLight, + SkBlendMode::kSoftLight, + SkBlendMode::kDifference, + SkBlendMode::kExclusion, + SkBlendMode::kMultiply, + SkBlendMode::kHue, + SkBlendMode::kSaturation, + SkBlendMode::kColor, + SkBlendMode::kLuminosity, + static_cast<SkBlendMode>(static_cast<uint32_t>(SkBlendMode::kLastMode) + + 1), + static_cast<SkBlendMode>(static_cast<uint32_t>(~0)), + }; + + for (size_t i = 0; i < arraysize(bad_modes); ++i) { + buffer.push<DrawColorOp>(SK_ColorMAGENTA, bad_modes[i]); + + PaintFlags flags = test_flags[i % test_flags.size()]; + flags.setBlendMode(bad_modes[i]); + buffer.push<DrawRectOp>(test_rects[i % test_rects.size()], flags); + } + + PaintOp::SerializeOptions options; + + int op_idx = 0; + for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) { + const PaintOp* op = *iter; + size_t bytes_written = + op->Serialize(serialized.get(), buffer_size, options); + ASSERT_GT(bytes_written, 0u); + PaintOp* written = PaintOp::Deserialize(serialized.get(), bytes_written, + deserialized.get(), buffer_size); + // First two ops should succeed. Other ops with bad enums should + // serialize correctly but fail to deserialize due to the bad + // SkBlendMode enum. + if (op_idx < 2) { + EXPECT_TRUE(written) << "op: " << op_idx; + written->DestroyThis(); + } else { + EXPECT_FALSE(written) << "op: " << op_idx; + } + + ++op_idx; + } +} + } // namespace cc
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc index 5c4ec78..f95379d8 100644 --- a/cc/paint/paint_op_reader.cc +++ b/cc/paint/paint_op_reader.cc
@@ -7,6 +7,7 @@ #include <stddef.h> #include "cc/paint/paint_flags.h" +#include "cc/paint/paint_op_buffer.h" #include "third_party/skia/include/core/SkFlattenableSerialization.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkRRect.h" @@ -120,6 +121,8 @@ Read(&flags->width_); Read(&flags->miter_limit_); ReadSimple(&flags->blend_mode_); + if (!PaintOp::IsValidSkBlendMode(flags->getBlendMode())) + valid_ = false; ReadSimple(&flags->bitfields_uint_); // TODO(enne): ReadTypeface, http://crbug.com/737629
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index a9967811..88119b99 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -557,6 +557,7 @@ "javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java", "javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrCoreVersionCheckerImpl.java", "javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrDaydreamApi.java", + "javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrIntentHandler.java", "javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/SimNfcActivity.java", "javatests/src/org/chromium/chrome/browser/vr_shell/util/CardboardUtils.java", "javatests/src/org/chromium/chrome/browser/vr_shell/util/NfcSimUtils.java", @@ -591,6 +592,7 @@ "//third_party/android_support_test_runner:runner_java", "//third_party/android_tools:android_support_v7_appcompat_java", "//third_party/android_tools:android_support_v7_recyclerview_java", + "//third_party/custom_tabs_client:custom_tabs_support_java", "//third_party/gvr-android-sdk:controller_test_api_java", "//third_party/gvr-android-sdk:gvr_common_java", "//third_party/junit", @@ -734,29 +736,29 @@ "/libmonochrome$shlib_extension.whitelist" output = monochrome_resource_whitelist } - + # Use custom resource ID list instead of android_webview's compiler # resource whitelist because //android_webview: generate_webui_resources # and //android_webview: generate_components_resources use hand-written # resource whitelists. action("system_webview_locale_resource_id_list") { script = "//tools/grit/pak_util.py" - + _system_webview_en_US_locale_pak = "$root_out_dir/android_webview/locales/en-US.pak" - + inputs = [ _system_webview_en_US_locale_pak, ] - + outputs = [ system_webview_locale_resource_id_list, ] - + deps = [ "//android_webview:repack_locales", ] - + args = [ "list-id", "--output", @@ -764,25 +766,25 @@ rebase_path(_system_webview_en_US_locale_pak, root_build_dir), ] } - + action("monochrome_locale_whitelist") { script = "//tools/resources/filter_resource_whitelist.py" - + inputs = [ monochrome_resource_whitelist, system_webview_locale_resource_id_list, ] - + outputs = [ monochrome_locale_whitelist, ] - + deps = [ ":monochrome_resource_whitelist", ":system_webview_locale_resource_id_list", "//android_webview:system_webview_pak_whitelist", ] - + args = [ "--input", rebase_path(monochrome_resource_whitelist, root_build_dir), @@ -791,7 +793,7 @@ "--output", rebase_path(monochrome_locale_whitelist, root_build_dir), ] - } + } } chrome_paks("monochrome_paks") { @@ -809,7 +811,7 @@ deps += [ ":monochrome_locale_whitelist" ] } } - + # This target is separate from monochrome_pak_assets because it does not # disable compression. android_assets("monochrome_locale_pak_assets") { @@ -817,7 +819,7 @@ foreach(_locale, locales - android_chrome_omitted_locales) { sources += [ "$target_gen_dir/monochrome_paks/locales/$_locale.pak" ] } - + deps = [ ":monochrome_paks", ]
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java index b400600..8df96ef9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -292,6 +292,8 @@ Runnable onNativeFinished = new Runnable() { @Override public void run() { + if (isActivityDestroyed()) return; + onNativeDependenciesFullyInitialized(); } };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java index 68b57bc3..ec83bacc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -40,6 +40,7 @@ import org.chromium.chrome.browser.preferences.website.SingleCategoryPreferences; import org.chromium.chrome.browser.preferences.website.SingleWebsitePreferences; import org.chromium.chrome.browser.preferences.website.SiteSettingsCategory; +import org.chromium.chrome.browser.webapps.WebApkServiceClient; import org.chromium.components.url_formatter.UrlFormatter; import org.chromium.webapk.lib.client.WebApkValidator; @@ -584,7 +585,7 @@ String platformTag = makePlatformTag(notificationId, origin, tag); if (forWebApk) { - WebApkNotificationClient.notifyNotification( + WebApkServiceClient.getInstance().notifyNotification( webApkPackage, notificationBuilder, platformTag, PLATFORM_ID); } else { // Set up a pending intent for going to the settings screen for |origin|. @@ -719,7 +720,8 @@ if (webApkPackage.isEmpty()) { mNotificationManager.cancel(platformTag, PLATFORM_ID); } else { - WebApkNotificationClient.cancelNotification(webApkPackage, platformTag, PLATFORM_ID); + WebApkServiceClient.getInstance().cancelNotification( + webApkPackage, platformTag, PLATFORM_ID); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApi.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApi.java index 042f609..996c251 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApi.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApi.java
@@ -36,12 +36,18 @@ Intent createVrIntent(final ComponentName componentName); /** - * Launch the given Intent in VR mode. + * Launch the given PendingIntent in VR mode. * @return false if unable to acquire DaydreamApi instance. */ boolean launchInVr(final PendingIntent pendingIntent); /** + * Launch the given Intent in VR mode. + * @return false if unable to acquire DaydreamApi instance. + */ + boolean launchInVr(final Intent intent); + + /** * @param requestCode The requestCode used by startActivityForResult. * @param intent The data passed to VrCore as part of the exit request. * @return false if unable to acquire DaydreamApi instance.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApiImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApiImpl.java index e356018..4d1dcb1f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApiImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApiImpl.java
@@ -68,6 +68,15 @@ } @Override + public boolean launchInVr(final Intent intent) { + DaydreamApi daydreamApi = DaydreamApi.create(mContext); + if (daydreamApi == null) return false; + daydreamApi.launchInVr(intent); + daydreamApi.close(); + return true; + } + + @Override public boolean exitFromVr(int requestCode, final Intent intent) { Activity activity = WindowAndroid.activityFromContext(mContext); Assert.assertNotNull(activity);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrIntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrIntentHandler.java new file mode 100644 index 0000000..ee47736 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrIntentHandler.java
@@ -0,0 +1,46 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.vr_shell; + +import android.content.Intent; + +import org.chromium.base.VisibleForTesting; +import org.chromium.chrome.browser.IntentHandler; + +// TODO(bsheedy): Move more VR intent related code into here even if it doesn't need +// to be overridden for testing +/** + * Handles VR intent checking for VrShellDelegate. + */ +public class VrIntentHandler { + private static VrIntentHandler sInstance; + private static final String DAYDREAM_HOME_PACKAGE = "com.google.android.vr.home"; + + /** + * Determines whether the given intent is a VR intent from Daydream Home. + * @param intent The intent to check + * @return Whether the intent is a VR intent and originated from Daydream Home + */ + public boolean isTrustedDaydreamIntent(Intent intent) { + return VrShellDelegate.isVrIntent(intent) + && IntentHandler.isIntentFromTrustedApp(intent, DAYDREAM_HOME_PACKAGE); + } + + /** + * Gets the static VrIntentHandler instance. + * @return The VrIntentHandler instance + */ + public static VrIntentHandler getInstance() { + if (sInstance == null) { + sInstance = new VrIntentHandler(); + } + return sInstance; + } + + @VisibleForTesting + public static void setInstanceForTesting(VrIntentHandler handler) { + sInstance = handler; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java index d5dc33f..6a355037 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -46,7 +46,6 @@ import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeTabbedActivity; -import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.help.HelpAndFeedback; import org.chromium.chrome.browser.infobar.InfoBarIdentifier; @@ -94,8 +93,7 @@ @IntDef({VR_NOT_AVAILABLE, VR_CARDBOARD, VR_DAYDREAM}) private @interface VrSupportLevel {} - private static final String DAYDREAM_VR_EXTRA = "android.intent.extra.VR_LAUNCH"; - private static final String DAYDREAM_HOME_PACKAGE = "com.google.android.vr.home"; + public static final String DAYDREAM_VR_EXTRA = "android.intent.extra.VR_LAUNCH"; static final String VR_FRE_INTENT_EXTRA = "org.chromium.chrome.browser.vr_shell.VR_FRE"; // Linter and formatter disagree on how the line below should be formatted. @@ -852,11 +850,6 @@ sBlackOverlayView = null; } - private static boolean isTrustedDaydreamIntent(Intent intent) { - return isVrIntent(intent) - && IntentHandler.isIntentFromTrustedApp(intent, DAYDREAM_HOME_PACKAGE); - } - private void onAutopresentIntent() { // Autopresent intents are only expected from trusted first party apps while // we're not in vr. @@ -887,7 +880,7 @@ VrShellDelegate instance = getInstance(activity); if (instance == null) return; instance.onVrIntent(); - if (isTrustedDaydreamIntent(intent)) { + if (VrIntentHandler.getInstance().isTrustedDaydreamIntent(intent)) { if (!ChromeFeatureList.isEnabled(ChromeFeatureList.WEBVR_AUTOPRESENT) || !activitySupportsPresentation(activity) || !isVrShellEnabled(instance.mVrSupportLevel)) { @@ -902,7 +895,7 @@ * This is called when ChromeTabbedActivity gets a new intent before native is initialized. */ public static void maybeHandleVrIntentPreNative(ChromeActivity activity, Intent intent) { - if (isTrustedDaydreamIntent(intent)) { + if (VrIntentHandler.getInstance().isTrustedDaydreamIntent(intent)) { // We add a black overlay view so that we can show black while the VR UI is loading. // Note that this alone isn't sufficient to prevent 2D UI from showing when // auto-presenting WebVR. See comment about the custom animation in {@link
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java index 4c276d4..75f9431f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -13,7 +13,6 @@ import org.chromium.base.ActivityState; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApplicationStatus; -import org.chromium.base.ContextUtils; import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.externalnav.ExternalNavigationParams; @@ -29,7 +28,6 @@ import org.chromium.content.browser.ChildProcessCreationParams; import org.chromium.net.NetError; import org.chromium.net.NetworkChangeNotifier; -import org.chromium.webapk.lib.client.WebApkServiceConnectionManager; import org.chromium.webapk.lib.common.WebApkConstants; import java.util.concurrent.TimeUnit; @@ -213,8 +211,7 @@ @Override public void onStop() { super.onStop(); - WebApkServiceConnectionManager.getInstance().disconnect( - ContextUtils.getApplicationContext(), getWebApkPackageName()); + WebApkServiceClient.getInstance().disconnect(getWebApkPackageName()); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/WebApkNotificationClient.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkServiceClient.java similarity index 65% rename from chrome/android/java/src/org/chromium/chrome/browser/notifications/WebApkNotificationClient.java rename to chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkServiceClient.java index 7d34867..de43889 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/WebApkNotificationClient.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkServiceClient.java
@@ -1,49 +1,69 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. +// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser.notifications; +package org.chromium.chrome.browser.webapps; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Build; +import android.os.IBinder; import android.os.RemoteException; import org.chromium.base.ContextUtils; import org.chromium.base.Log; +import org.chromium.chrome.browser.notifications.NotificationBuilderBase; import org.chromium.webapk.lib.client.WebApkServiceConnectionManager; import org.chromium.webapk.lib.runtime_library.IWebApkApi; /** - * WebApkNotificationClient provides an API to display and close notifications remotely in - * context of a WebAPK, enriching the notification with the WebAPK's small icon when available. + * Provides APIs for browsers to communicate with WebAPK services. Each WebAPK has its own "WebAPK + * service". */ -public class WebApkNotificationClient { - private static final String TAG = "cr_WebApk"; - +public class WebApkServiceClient { // Callback which catches RemoteExceptions thrown due to IWebApkApi failure. private abstract static class ApiUseCallback implements WebApkServiceConnectionManager.ConnectionCallback { public abstract void useApi(IWebApkApi api) throws RemoteException; @Override - public void onConnected(IWebApkApi api) { + public void onConnected(IBinder api) { try { - useApi(api); + useApi(IWebApkApi.Stub.asInterface(api)); } catch (RemoteException e) { Log.w(TAG, "WebApkAPI use failed.", e); } } } + private static final String CATEGORY_WEBAPK_API = "android.intent.category.WEBAPK_API"; + private static final String TAG = "cr_WebApk"; + + private static WebApkServiceClient sInstance; + + /** Manages connections between the browser application and WebAPK services. */ + private WebApkServiceConnectionManager mConnectionManager; + + public static WebApkServiceClient getInstance() { + if (sInstance == null) { + sInstance = new WebApkServiceClient(); + } + return sInstance; + } + + private WebApkServiceClient() { + mConnectionManager = + new WebApkServiceConnectionManager(CATEGORY_WEBAPK_API, null /* action */); + } + /** - * Connect to a WebAPK's bound service, build a notification and hand it over to the WebAPK to - * display. Handing over the notification makes the notification look like it originated from + * Connects to a WebAPK's bound service, builds a notification and hands it over to the WebAPK + * to display. Handing over the notification makes the notification look like it originated from * the WebAPK - not Chrome - in the Android UI. */ - public static void notifyNotification(final String webApkPackage, + public void notifyNotification(final String webApkPackage, final NotificationBuilderBase notificationBuilder, final String platformTag, final int platformID) { final ApiUseCallback connectionCallback = new ApiUseCallback() { @@ -68,14 +88,12 @@ } }; - WebApkServiceConnectionManager.getInstance().connect( + mConnectionManager.connect( ContextUtils.getApplicationContext(), webApkPackage, connectionCallback); } - /** - * Cancel notification previously shown by WebAPK. - */ - public static void cancelNotification( + /** Cancels notification previously shown by WebAPK. */ + public void cancelNotification( String webApkPackage, final String platformTag, final int platformID) { final ApiUseCallback connectionCallback = new ApiUseCallback() { @Override @@ -83,10 +101,19 @@ api.cancelNotification(platformTag, platformID); } }; - WebApkServiceConnectionManager.getInstance().connect( + + mConnectionManager.connect( ContextUtils.getApplicationContext(), webApkPackage, connectionCallback); } + /** + * Disconnects Chrome application from the WebAPK service. + * @param webApkPackage WebAPK package for the service to disconnect from. + */ + public void disconnect(String webApkPackage) { + mConnectionManager.disconnect(ContextUtils.getApplicationContext(), webApkPackage); + } + /** Decodes bitmap from WebAPK's resources. */ private static Bitmap decodeImageResource(String webApkPackage, int resourceId) { PackageManager packageManager = ContextUtils.getApplicationContext().getPackageManager();
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index c86f240..016f2624 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -608,7 +608,6 @@ "java/src/org/chromium/chrome/browser/notifications/NotificationSystemStatusUtil.java", "java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java", "java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java", - "java/src/org/chromium/chrome/browser/notifications/WebApkNotificationClient.java", "java/src/org/chromium/chrome/browser/notifications/channels/Channel.java", "java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java", "java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java", @@ -1172,6 +1171,7 @@ "java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionChecker.java", "java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApi.java", "java/src/org/chromium/chrome/browser/vr_shell/VrFeedbackStatus.java", + "java/src/org/chromium/chrome/browser/vr_shell/VrIntentHandler.java", "java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java", "java/src/org/chromium/chrome/browser/vr_shell/OnExitVrRequestListener.java", "java/src/org/chromium/chrome/browser/vr_shell/VrFirstRunActivity.java", @@ -1200,6 +1200,7 @@ "java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java", "java/src/org/chromium/chrome/browser/webapps/WebApkManagedActivity.java", "java/src/org/chromium/chrome/browser/webapps/WebApkOfflineDialog.java", + "java/src/org/chromium/chrome/browser/webapps/WebApkServiceClient.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java", "java/src/org/chromium/chrome/browser/webapps/WebApkVersionManager.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java index d7281f9..8de38bd02 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
@@ -70,7 +70,7 @@ CriteriaHelper.pollInstrumentationThread(new Criteria() { @Override public boolean isSatisfied() { - return contentViewCore.getScale() - INITIAL_SCALE < FLOAT_DELTA; + return contentViewCore.getPageScaleFactor() - INITIAL_SCALE < FLOAT_DELTA; } }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL); } @@ -80,7 +80,7 @@ CriteriaHelper.pollInstrumentationThread(new Criteria() { @Override public boolean isSatisfied() { - return contentViewCore.getScale() > initialZoomLevel; + return contentViewCore.getPageScaleFactor() > initialZoomLevel; } }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL); } @@ -95,7 +95,7 @@ // This should focus the text field and initiate a zoom in. Tab tab = mActivityTestRule.getActivity().getActivityTab(); final ContentViewCore contentViewCore = tab.getContentViewCore(); - float initialZoomLevel = contentViewCore.getScale(); + float initialZoomLevel = contentViewCore.getPageScaleFactor(); DOMUtils.clickNode(contentViewCore, TEXTFIELD_DOM_ID); @@ -112,7 +112,7 @@ public void testZoomOutOfSelectedIfOnlyBackPressed() throws Throwable { final Tab tab = mActivityTestRule.getActivity().getActivityTab(); final ContentViewCore contentViewCore = tab.getContentViewCore(); - final float initialZoomLevel = contentViewCore.getScale(); + final float initialZoomLevel = contentViewCore.getPageScaleFactor(); // This should focus the text field and initiate a zoom in. DOMUtils.clickNode(contentViewCore, TEXTFIELD_DOM_ID); @@ -127,7 +127,7 @@ CriteriaHelper.pollInstrumentationThread(new Criteria() { @Override public boolean isSatisfied() { - return (contentViewCore.getScale() - initialZoomLevel) < FLOAT_DELTA; + return (contentViewCore.getPageScaleFactor() - initialZoomLevel) < FLOAT_DELTA; } }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java index 15eaea0..8d9ae2c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
@@ -5,6 +5,8 @@ package org.chromium.chrome.browser.vr_shell; import static org.chromium.chrome.browser.vr_shell.VrTestRule.PAGE_LOAD_TIMEOUT_S; +import static org.chromium.chrome.browser.vr_shell.VrTestRule.POLL_CHECK_INTERVAL_SHORT_MS; +import static org.chromium.chrome.browser.vr_shell.VrTestRule.POLL_TIMEOUT_LONG_MS; import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_DON_ENABLED; import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VIEWER_DAYDREAM; @@ -19,12 +21,16 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.base.test.util.Restriction; -import org.chromium.base.test.util.RetryOnFailure; +import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.vr_shell.mock.MockVrIntentHandler; import org.chromium.chrome.browser.vr_shell.util.NfcSimUtils; import org.chromium.chrome.browser.vr_shell.util.VrTransitionUtils; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.content.browser.test.util.Criteria; +import org.chromium.content.browser.test.util.CriteriaHelper; +import org.chromium.content_public.browser.WebContents; /** * End-to-end tests for transitioning between WebVR's magic window and @@ -59,11 +65,12 @@ @Test @MediumTest @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM) - @RetryOnFailure(message = "crbug.com/736527") public void testNfcFiresVrdisplayactivate() throws InterruptedException { mVrTestRule.loadUrlAndAwaitInitialization( VrTestRule.getHtmlTestFile("test_nfc_fires_vrdisplayactivate"), PAGE_LOAD_TIMEOUT_S); + mVrTestRule.runJavaScriptOrFail( + "addListener()", POLL_TIMEOUT_LONG_MS, mVrTestRule.getFirstTabWebContents()); NfcSimUtils.simNfcScan(mVrTestRule.getActivity()); mVrTestRule.waitOnJavaScriptStep(mVrTestRule.getFirstTabWebContents()); mVrTestRule.endTest(mVrTestRule.getFirstTabWebContents()); @@ -84,4 +91,31 @@ mVrTestRule.getFirstTabCvc(), mVrTestRule.getFirstTabWebContents()); mVrTestRule.endTest(mVrTestRule.getFirstTabWebContents()); } + + /** + * Tests that an intent from a trusted app such as Daydream Home allows WebVR content + * to auto present without the need for a user gesture. + */ + @Test + @MediumTest + @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM) + public void testTrustedIntentAllowsAutoPresent() throws InterruptedException { + VrIntentHandler.setInstanceForTesting(new MockVrIntentHandler( + true /* useMockImplementation */, true /* treatIntentsAsTrusted */)); + VrTransitionUtils.sendDaydreamAutopresentIntent( + mVrTestRule.getHtmlTestFile("test_webvr_autopresent"), mVrTestRule.getActivity()); + + // Wait until the link is opened in a new tab + final ChromeActivity act = mVrTestRule.getActivity(); + CriteriaHelper.pollUiThread(new Criteria() { + @Override + public boolean isSatisfied() { + return act.getTabModelSelector().getTotalTabCount() == 2; + } + }, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS); + + WebContents wc = mVrTestRule.getActivity().getActivityTab().getWebContents(); + mVrTestRule.waitOnJavaScriptStep(wc); + mVrTestRule.endTest(wc); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrDaydreamApi.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrDaydreamApi.java index ad0ddec..7701a0d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrDaydreamApi.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrDaydreamApi.java
@@ -43,6 +43,11 @@ } @Override + public boolean launchInVr(final Intent intent) { + return true; + } + + @Override public boolean exitFromVr(int requestCode, final Intent intent) { return true; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrIntentHandler.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrIntentHandler.java new file mode 100644 index 0000000..84b0c47 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrIntentHandler.java
@@ -0,0 +1,38 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.vr_shell.mock; + +import android.content.Intent; + +import org.chromium.chrome.browser.vr_shell.VrIntentHandler; + +/** + * Mock version of VrIntentHandler for testing. + */ +public class MockVrIntentHandler extends VrIntentHandler { + private boolean mUseMockImplementation; + private boolean mTreatIntentsAsTrusted; + + public MockVrIntentHandler(boolean useMockImplementation, boolean treatIntentsAsTrusted) { + mUseMockImplementation = useMockImplementation; + mTreatIntentsAsTrusted = treatIntentsAsTrusted; + } + + @Override + public boolean isTrustedDaydreamIntent(Intent intent) { + if (mUseMockImplementation) { + return mTreatIntentsAsTrusted; + } + return super.isTrustedDaydreamIntent(intent); + } + + public void setUseMockImplementation(boolean enabled) { + mUseMockImplementation = enabled; + } + + public void setTreatIntentsAsTrusted(boolean trusted) { + mTreatIntentsAsTrusted = trusted; + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTransitionUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTransitionUtils.java index 29beb393..53293fe 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTransitionUtils.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTransitionUtils.java
@@ -7,9 +7,17 @@ import static org.chromium.chrome.browser.vr_shell.VrTestRule.POLL_CHECK_INTERVAL_SHORT_MS; import static org.chromium.chrome.browser.vr_shell.VrTestRule.POLL_TIMEOUT_LONG_MS; +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.support.customtabs.CustomTabsIntent; + +import com.google.vr.ndk.base.DaydreamApi; + import org.junit.Assert; import org.chromium.base.ThreadUtils; +import org.chromium.chrome.browser.vr_shell.VrClassesWrapperImpl; import org.chromium.chrome.browser.vr_shell.VrShellDelegate; import org.chromium.chrome.browser.vr_shell.VrTestRule; import org.chromium.content.browser.ContentViewCore; @@ -130,4 +138,31 @@ }); return isBackButtonEnabled.get(); } + + /** + * Sends an intent to Chrome telling it to autopresent the given URL. This + * is expected to fail unless the trusted intent check is disabled in VrShellDelegate. + * + * @param url String containing the URL to open + * @param activity The activity to launch the intent from + */ + public static void sendDaydreamAutopresentIntent(String url, final Activity activity) { + // Create an intent that will launch Chrome at the specified URL with autopresent + final Intent intent = + activity.getPackageManager().getLaunchIntentForPackage(activity.getPackageName()); + intent.setAction(Intent.ACTION_VIEW); + intent.setData(Uri.parse(url)); + intent.putExtra(VrShellDelegate.DAYDREAM_VR_EXTRA, true); + DaydreamApi.setupVrIntent(intent); + intent.removeCategory("com.google.intent.category.DAYDREAM"); + CustomTabsIntent.setAlwaysUseBrowserUI(intent); + + final VrClassesWrapperImpl wrapper = new VrClassesWrapperImpl(); + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + wrapper.createVrDaydreamApi(activity).launchInVr(intent); + } + }); + } }
diff --git a/chrome/android/webapk/libs/client/BUILD.gn b/chrome/android/webapk/libs/client/BUILD.gn index 6ca8f1ee6..2b23e0f 100644 --- a/chrome/android/webapk/libs/client/BUILD.gn +++ b/chrome/android/webapk/libs/client/BUILD.gn
@@ -10,6 +10,7 @@ java_files = [ "src/org/chromium/webapk/lib/client/DexOptimizer.java", "src/org/chromium/webapk/lib/client/WebApkNavigationClient.java", + "src/org/chromium/webapk/lib/client/WebApkIdentityServiceClient.java", "src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java", "src/org/chromium/webapk/lib/client/WebApkValidator.java", "src/org/chromium/webapk/lib/client/WebApkVerifySignature.java", @@ -36,6 +37,7 @@ junit_binary("webapk_client_junit_tests") { java_files = [ + "junit/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClientTest.java", "junit/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManagerTest.java", "junit/src/org/chromium/webapk/lib/client/WebApkValidatorTest.java", "junit/src/org/chromium/webapk/lib/client/WebApkVerifySignatureTest.java", @@ -47,6 +49,7 @@ ":client_java", "//chrome/android/webapk/libs/common:common_java", "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java", + "//chrome/android/webapk/test:junit_test_support", "//testing/android/junit:junit_test_support", ] }
diff --git a/chrome/android/webapk/libs/client/junit/DEPS b/chrome/android/webapk/libs/client/junit/DEPS index 6e1c553a..5b1ffdb5 100644 --- a/chrome/android/webapk/libs/client/junit/DEPS +++ b/chrome/android/webapk/libs/client/junit/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "+chrome/android/webapk/libs/client", + "+chrome/android/webapk/test", "+testing", ] \ No newline at end of file
diff --git a/chrome/android/webapk/libs/client/junit/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClientTest.java b/chrome/android/webapk/libs/client/junit/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClientTest.java new file mode 100644 index 0000000..cd2aef1 --- /dev/null +++ b/chrome/android/webapk/libs/client/junit/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClientTest.java
@@ -0,0 +1,171 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.webapk.lib.client; + +import android.content.ComponentName; +import android.os.Bundle; +import android.os.RemoteException; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; +import org.robolectric.shadows.ShadowLooper; + +import org.chromium.testing.local.CustomShadowAsyncTask; +import org.chromium.testing.local.LocalRobolectricTestRunner; +import org.chromium.webapk.lib.common.WebApkMetaDataKeys; +import org.chromium.webapk.lib.common.identity_service.IIdentityService; +import org.chromium.webapk.test.WebApkTestHelper; + +/** + * Unit tests for {@link org.chromium.webapk.lib.client.WebApkIdentityServiceClient}. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE, packageName = WebApkIdentityServiceClientTest.BROWSER_PACKAGE_NAME, + shadows = {CustomShadowAsyncTask.class}) +public class WebApkIdentityServiceClientTest { + static final String BROWSER_PACKAGE_NAME = "browser"; + + private static final String WEBAPK_PACKAGE_NAME = "org.chromium.webapk.test_package"; + private static final String ANOTHER_BROWSER_PACKAGE_NAME = "another.browser"; + private ShadowApplication mShadowApplication; + + /** Mocks the {@link WebApkIdentityServiceClient.CheckBrowserBacksWebApkCallback}. */ + private static class TestCheckBacksWebApkCallback + implements WebApkIdentityServiceClient.CheckBrowserBacksWebApkCallback { + private boolean mResult; + private boolean mIsCalled; + + @Override + public void onChecked(boolean doesBrowserBackWebApk) { + mResult = doesBrowserBackWebApk; + mIsCalled = true; + } + } + + /** Mocks the Identity service of a WebAPK. */ + private static class TestIdentityService extends IIdentityService.Stub { + private String mRuntimeHost; + + public TestIdentityService(String runtimeHost) { + mRuntimeHost = runtimeHost; + } + + @Override + public String getRuntimeHostBrowserPackageName() throws RemoteException { + return mRuntimeHost; + } + } + + @Before + public void setUp() { + mShadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + } + + @After + public void tearDown() { + WebApkIdentityServiceClient.disconnectAll(RuntimeEnvironment.application); + } + + /** + * Tests that for WebAPKs with shell APK version lower than the + * {@link WebApkIdentityServiceClient#SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST}, + * the backs-WebAPK-check returns false if the browser does NOT match the WebAPK's runtime host + * specified in the metaData. + */ + @Test + public void testReturnsFalseWhenNotMatchRuntimeHostBeforeIntroduceHostBrowserSwitchLogic() { + registerWebApk(ANOTHER_BROWSER_PACKAGE_NAME /*webApkRuntimeHost*/, + WebApkIdentityServiceClient.SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST - 1 + /*shellApkVersion*/); + + Assert.assertFalse(doesBrowserBackWebApk()); + } + + /** + * Tests that for WebAPKs with shell APK version lower than the + * {@link WebApkIdentityServiceClient#SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST}, + * the backs-WebAPK-check returns true if the browser matches the WebAPK's runtime host + * specified in the metaData. + */ + @Test + public void testReturnsTrueWhenMatchesRuntimeHostBeforeIntroduceHostBrowserSwitchLogic() { + registerWebApk(BROWSER_PACKAGE_NAME /*webApkRuntimeHost*/, + WebApkIdentityServiceClient.SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST - 1 + /*shellApkVersion*/); + + Assert.assertTrue(doesBrowserBackWebApk()); + } + + /** + * Tests that for WebAPKs with shell APK version equal or higher than the + * {@link WebApkIdentityServiceClient#SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST} but + * doesn't have Identity Service, the backs-WebAPK-check returns false. + */ + @Test + public void testBacksWebApkCheckForWebApkWithHostBrowserSwitchLogicButWithoutIdentityService() { + registerWebApk(BROWSER_PACKAGE_NAME /*webApkRuntimeHost*/, + WebApkIdentityServiceClient.SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST + /*shellApkVersion*/); + + Assert.assertFalse(doesBrowserBackWebApk()); + } + + /** + * Tests that for WebAPKs with Identity service, the backs-WebAPK-check returns false if the + * package name of the browser does NOT match the one provided by the Identity service. + */ + @Test + public void testReturnsFalseWhenDoesNotMatchRuntimeHostProvidedByIdentityService() { + // The shell APK version doesn't matter as long as the WebAPK has an Identity service. + registerWebApk(BROWSER_PACKAGE_NAME /*webApkSpecifiedRuntimeHost*/, 0 /*shellApkVersion*/); + mShadowApplication.setComponentNameAndServiceForBindService( + new ComponentName(WEBAPK_PACKAGE_NAME, ""), + new TestIdentityService(ANOTHER_BROWSER_PACKAGE_NAME)); + + Assert.assertFalse(doesBrowserBackWebApk()); + } + + /** + * Tests that for WebAPKs with Identity service, the backs-WebAPK-check returns true if the + * package name of the browser matches the one provided by the Identity service. + */ + @Test + public void testReturnsTrueWhenMatchesRuntimeHostProvidedByIdentityService() { + // The shell APK version doesn't matter as long as the WebAPK has an Identity service. + registerWebApk( + ANOTHER_BROWSER_PACKAGE_NAME /*webApkSpecifiedRuntimeHost*/, 0 /*shellApkVersion*/); + mShadowApplication.setComponentNameAndServiceForBindService( + new ComponentName(WEBAPK_PACKAGE_NAME, ""), + new TestIdentityService(BROWSER_PACKAGE_NAME /*realRuntimeHost*/)); + + Assert.assertTrue(doesBrowserBackWebApk()); + } + + /** Registers a WebAPK with the runtime host and the shell APK version in its metadata. */ + private void registerWebApk(String runtimeHost, int shellApkVersion) { + Bundle bundle = new Bundle(); + bundle.putString(WebApkMetaDataKeys.RUNTIME_HOST, runtimeHost); + bundle.putInt(WebApkMetaDataKeys.SHELL_APK_VERSION, shellApkVersion); + WebApkTestHelper.registerWebApkWithMetaData(WEBAPK_PACKAGE_NAME, bundle); + } + + /** Checks whether the browser backs the WebAPK. */ + private boolean doesBrowserBackWebApk() { + TestCheckBacksWebApkCallback callback = new TestCheckBacksWebApkCallback(); + WebApkIdentityServiceClient.getInstance().checkBrowserBacksWebApkAsync( + RuntimeEnvironment.application, WEBAPK_PACKAGE_NAME, callback); + ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); + + Assert.assertTrue(callback.mIsCalled); + return callback.mResult; + } +}
diff --git a/chrome/android/webapk/libs/client/junit/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManagerTest.java b/chrome/android/webapk/libs/client/junit/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManagerTest.java index 6f486c9..fdb39337 100644 --- a/chrome/android/webapk/libs/client/junit/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManagerTest.java +++ b/chrome/android/webapk/libs/client/junit/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManagerTest.java
@@ -4,26 +4,28 @@ package org.chromium.webapk.lib.client; +import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.ServiceConnection; - -import org.chromium.testing.local.CustomShadowAsyncTask; -import org.chromium.testing.local.LocalRobolectricTestRunner; -import org.chromium.webapk.lib.runtime_library.IWebApkApi; +import android.os.IBinder; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplication; +import org.chromium.testing.local.CustomShadowAsyncTask; +import org.chromium.testing.local.LocalRobolectricTestRunner; + /** - * Unit tests for {@link org.chromium.libs.client.WebApkServiceConnectionManager}. + * Unit tests for {@link org.chromium.webapk.lib.client.WebApkServiceConnectionManager}. */ @RunWith(LocalRobolectricTestRunner.class) @Config(manifest = Config.NONE, shadows = {CustomShadowAsyncTask.class}) @@ -31,6 +33,8 @@ private static final String WEB_APK_PACKAGE = "com.webapk.package"; + private static final String CATEGORY_WEBAPK_SERVICE_API = "android.intent.category.WEBAPK_API"; + private ShadowApplication mShadowApplication; private WebApkServiceConnectionManager mConnectionManager; @@ -38,7 +42,7 @@ public boolean mGotResult = false; @Override - public void onConnected(IWebApkApi api) { + public void onConnected(IBinder service) { mGotResult = true; } } @@ -46,7 +50,10 @@ @Before public void setUp() { mShadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); - mConnectionManager = new WebApkServiceConnectionManager(); + mConnectionManager = + new WebApkServiceConnectionManager(CATEGORY_WEBAPK_SERVICE_API, null /* action*/); + mShadowApplication.setComponentNameAndServiceForBindService( + new ComponentName(WEB_APK_PACKAGE, ""), Mockito.mock(IBinder.class)); } /** @@ -134,7 +141,7 @@ Assert.assertEquals(WEB_APK_PACKAGE, getNextStartedServicePackage()); Assert.assertEquals(null, getNextStartedServicePackage()); - mConnectionManager.disconnect(RuntimeEnvironment.application, WEB_APK_PACKAGE); + mConnectionManager.disconnectAll(RuntimeEnvironment.application); mConnectionManager.connect( RuntimeEnvironment.application, WEB_APK_PACKAGE, new TestCallback()); Assert.assertEquals(WEB_APK_PACKAGE, getNextStartedServicePackage());
diff --git a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClient.java b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClient.java new file mode 100644 index 0000000..7b1d202 --- /dev/null +++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkIdentityServiceClient.java
@@ -0,0 +1,148 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.webapk.lib.client; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.text.TextUtils; +import android.util.Log; + +import org.chromium.webapk.lib.common.WebApkMetaDataKeys; +import org.chromium.webapk.lib.common.identity_service.IIdentityService; + +/** + * Provides APIs for browsers to communicate with WebAPK Identity services. Each WebAPK has its own + * "WebAPK Identity service". + */ +public class WebApkIdentityServiceClient { + /** Used to notify the consumer after checking whether the caller browser backs the WebAPK. */ + public interface CheckBrowserBacksWebApkCallback { + void onChecked(boolean doesBrowserBackWebApk); + } + + /** + * Before shell APK version 6, all WebAPKs are installed from browsers, and that browser is the + * runtime host and specified in the WebAPK's AndroidManifest.xml. In shell APK version 6, we + * introduced logic to allow user to choose runtime host browser for WebAPKs not bound to any + * browser, and for WebAPKs installed from browsers when the browser is subsequently + * uninstalled. However, the browser cannot track of WebAPKs which are backed by the browser + * because the browser is not notified if a user changes the runtime host of a WebAPK by + * clearing the WebAPK's data. Besides, the browser loses the knowledge of WebAPKs if a user + * clears the browser's data. Therefore, a browser doesn't know whether it is the runtime host + * of a WebAPK without asking the WebAPK. An Identity service is introduced in shell APK version + * 16 to allow browsers to query the runtime host of a WebAPK. + */ + public static final int SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST = 6; + + private static final String ACTION_WEBAPK_IDENTITY_SERVICE = "org.webapk.IDENTITY_SERVICE_API"; + private static final String TAG = "cr_WebApkIdentityService"; + + private static WebApkIdentityServiceClient sInstance; + + /** Manages connections between the browser application and WebAPK Identity services. */ + private WebApkServiceConnectionManager mConnectionManager; + + public static WebApkIdentityServiceClient getInstance() { + if (sInstance == null) { + sInstance = new WebApkIdentityServiceClient(); + } + return sInstance; + } + + private WebApkIdentityServiceClient() { + mConnectionManager = new WebApkServiceConnectionManager( + null /* category */, ACTION_WEBAPK_IDENTITY_SERVICE); + } + + /** + * Checks whether a WebAPK is backed by the browser with {@link browserContext}. + * @param browserContext The browser context. + * @param webApkPackageName The package name of the WebAPK. + * @param callback The callback to be called after querying the runtime host is done. + */ + public void checkBrowserBacksWebApkAsync(final Context browserContext, + final String webApkPackageName, final CheckBrowserBacksWebApkCallback callback) { + WebApkServiceConnectionManager.ConnectionCallback connectionCallback = + new WebApkServiceConnectionManager.ConnectionCallback() { + @Override + public void onConnected(IBinder service) { + String browserPackageName = browserContext.getPackageName(); + if (service == null) { + onGotWebApkRuntimeHost(browserPackageName, + maybeExtractRuntimeHostFromMetaData( + browserContext, webApkPackageName), + callback); + return; + } + + IIdentityService identityService = + IIdentityService.Stub.asInterface(service); + String runtimeHost = null; + try { + // The runtime host could be null if the WebAPK hasn't bound to any + // browser yet. + runtimeHost = identityService.getRuntimeHostBrowserPackageName(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to get runtime host from the Identity service."); + } + onGotWebApkRuntimeHost(browserPackageName, runtimeHost, callback); + } + }; + mConnectionManager.connect(browserContext, webApkPackageName, connectionCallback); + } + + /** + * Called after fetching the WebAPK's backing browser. + * @param browserPackageName The browser's package name. + * @param webApkBackingBrowserPackageName The package name of the WebAPK's backing browser. + * @param callback The callback to notify whether {@link browserPackageName} backs the WebAPK. + */ + private static void onGotWebApkRuntimeHost(String browserPackageName, + String webApkBackingBrowserPackageName, CheckBrowserBacksWebApkCallback callback) { + callback.onChecked(TextUtils.equals(webApkBackingBrowserPackageName, browserPackageName)); + } + + /** + * Extracts the backing browser from the WebAPK's meta data. + * See {@link WebApkIdentityServiceClient#SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST} for + * more details. + */ + private static String maybeExtractRuntimeHostFromMetaData( + Context context, String webApkPackageName) { + Bundle metadata = readMetaData(context, webApkPackageName); + if (metadata == null + || metadata.getInt(WebApkMetaDataKeys.SHELL_APK_VERSION) + >= SHELL_APK_VERSION_SUPPORTING_SWITCH_RUNTIME_HOST) { + // The backing browser in the WebAPK's meta data may not be the one which actually backs + // the WebAPK. The user may have switched the backing browser. + return null; + } + + return metadata.getString(WebApkMetaDataKeys.RUNTIME_HOST); + } + + /** Returns the <meta-data> in the Android Manifest of the given package name. */ + private static Bundle readMetaData(Context context, String packageName) { + ApplicationInfo ai = null; + try { + ai = context.getPackageManager().getApplicationInfo( + packageName, PackageManager.GET_META_DATA); + } catch (PackageManager.NameNotFoundException e) { + return null; + } + return ai.metaData; + } + + /** Disconnects all the connections to WebAPK Identity services. */ + public static void disconnectAll(Context appContext) { + if (sInstance == null) return; + + sInstance.mConnectionManager.disconnectAll(appContext); + } +}
diff --git a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java index 2ef8453..9467fbd 100644 --- a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java +++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java
@@ -12,90 +12,81 @@ import android.os.IBinder; import android.util.Log; -import org.chromium.webapk.lib.runtime_library.IWebApkApi; - import java.util.ArrayList; -import java.util.Hashtable; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; /** - * Manages static global connections between the Chrome application and "WebAPK services". Each - * WebAPK has its own "WebAPK service". + * Each WebAPK has several services. This class manages static global connections between the + * Chrome application and the "WebAPK services." */ public class WebApkServiceConnectionManager { /** - * Interface for getting notified once Chrome is connected to the WebAPK service. + * Interface for getting notified once Chrome is connected to a WebAPK service. */ public interface ConnectionCallback { /** * Called once Chrome is connected to the WebAPK service. - * @param api The WebAPK service API. + * @param service The WebAPK service. */ - public void onConnected(IWebApkApi api); + void onConnected(IBinder service); } - /** - * Managed connection to WebAPK service. - */ + /** Managed connection to WebAPK service. */ private static class Connection implements ServiceConnection { - /** - * Whether the connection to the service was established. - */ - private boolean mHasConnected; + /** The connection manager who owns this connection. */ + private WebApkServiceConnectionManager mConnectionManager; - /** - * Callbacks to call once the connection is established. - */ + /** Callbacks to call once the connection is established. */ private ArrayList<ConnectionCallback> mCallbacks = new ArrayList<ConnectionCallback>(); - /** - * WebAPK IBinder interface. - */ - private IWebApkApi mApi; + /** WebAPK IBinder interface.*/ + private IBinder mBinder; - public boolean hasConnected() { - return mHasConnected; - } - - public IWebApkApi getApi() { - return mApi; + public IBinder getService() { + return mBinder; } public void addCallback(ConnectionCallback callback) { mCallbacks.add(callback); } + public Connection(WebApkServiceConnectionManager manager) { + mConnectionManager = manager; + } + @Override - public void onServiceDisconnected(ComponentName name) {} + public void onServiceDisconnected(ComponentName name) { + mBinder = null; + mConnectionManager.onServiceDisconnected(name.getPackageName()); + } @Override public void onServiceConnected(ComponentName name, IBinder service) { - mHasConnected = true; - mApi = IWebApkApi.Stub.asInterface(service); - Log.d(TAG, String.format("Got IWebApkApi: %s", mApi)); - + mBinder = service; + Log.d(TAG, String.format("Got IBinder Service: %s", mBinder)); for (ConnectionCallback callback : mCallbacks) { - callback.onConnected(mApi); + callback.onConnected(mBinder); } mCallbacks.clear(); } } - private static final String CATEGORY_WEBAPK_API = "android.intent.category.WEBAPK_API"; + private static final String TAG = "cr_WebApkService"; - private static final String TAG = "cr_WebApk"; + /** The category of the service to connect to. */ + private String mCategory; - private static WebApkServiceConnectionManager sInstance; + /** The action of the service to connect to. */ + private String mAction; - /** - * Mapping of WebAPK package to WebAPK service connection. - */ - private Hashtable<String, Connection> mConnections = new Hashtable<String, Connection>(); + /** Mapping of WebAPK package to WebAPK service connection.*/ + private HashMap<String, Connection> mConnections = new HashMap<>(); - public static WebApkServiceConnectionManager getInstance() { - if (sInstance == null) { - sInstance = new WebApkServiceConnectionManager(); - } - return sInstance; + /** Called when a WebAPK service connection is disconnected. */ + private void onServiceDisconnected(String webApkName) { + mConnections.remove(webApkName); } /** @@ -103,47 +94,80 @@ * @param appContext Application context. * @param webApkPackage WebAPK package to create connection for. * @param callback Callback to call after connection has been established. Called synchronously - * if the connection is already established. */ public void connect(final Context appContext, final String webApkPackage, final ConnectionCallback callback) { Connection connection = mConnections.get(webApkPackage); if (connection != null) { - if (connection.hasConnected()) { - callback.onConnected(connection.getApi()); + IBinder service = connection.getService(); + if (service != null) { + callback.onConnected(service); } else { connection.addCallback(callback); } return; } - new AsyncTask<Void, Void, Void>() { + new AsyncTask<Void, Void, Connection>() { @Override - protected Void doInBackground(Void... params) { - Connection newConnection = new Connection(); + protected Connection doInBackground(Void... params) { + Connection newConnection = new Connection(WebApkServiceConnectionManager.this); newConnection.addCallback(callback); Intent intent = createConnectIntent(webApkPackage); - try { - appContext.bindService(intent, newConnection, Context.BIND_AUTO_CREATE); - + if (appContext.bindService(intent, newConnection, Context.BIND_AUTO_CREATE)) { + return newConnection; + } else { + appContext.unbindService(newConnection); + return null; + } } catch (SecurityException e) { Log.w(TAG, "Security failed binding.", e); return null; } + } - mConnections.put(webApkPackage, newConnection); - return null; + @Override + protected void onPostExecute(Connection connection) { + if (connection == null) { + callback.onConnected(null); + } else { + mConnections.put(webApkPackage, connection); + } } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } /** - * Disconnects Chrome application from WebAPK service. Can be called from any thread. - * @param appContext Application context. - * @param webApkPackage WebAPK package for the service to disconnect from. + * Disconnect from all of the WebAPK services. Can be called from any thread. + * @param appContext The application context. */ - public void disconnect(final Context appContext, String webApkPackage) { + public void disconnectAll(final Context appContext) { + if (mConnections.isEmpty()) return; + + List<Connection> values = new ArrayList<>(); + values.addAll(mConnections.values()); + mConnections.clear(); + + new AsyncTask<Collection<Connection>, Void, Void>() { + @Override + protected Void doInBackground(Collection<Connection>... collections) { + Collection<Connection> values = collections[0]; + for (Connection connection : values) { + if (connection.getService() != null) { + appContext.unbindService(connection); + } + } + return null; + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, values); + } + + /** + * Disconnect from the given WebAPK. Can be called from any thread. + * @param browserContext The browser context. + */ + public void disconnect(final Context browserContext, String webApkPackage) { if (webApkPackage == null) { return; } @@ -156,22 +180,25 @@ new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { - appContext.unbindService(connection); + browserContext.unbindService(connection); return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - WebApkServiceConnectionManager() { + public WebApkServiceConnectionManager(String category, String action) { + mCategory = category; + mAction = action; } /** * Creates intent to connect to WebAPK service. * @param webApkPackage The package name of the WebAPK to connect to. */ - private static Intent createConnectIntent(String webApkPackage) { + private Intent createConnectIntent(String webApkPackage) { Intent intent = new Intent(); - intent.addCategory(CATEGORY_WEBAPK_API); + if (mCategory != null) intent.addCategory(mCategory); + if (mAction != null) intent.setAction(mAction); intent.setPackage(webApkPackage); return intent; }
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 0a6c5e3f..b0232a97 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -1872,9 +1872,16 @@ </message> <!-- Search Page --> - <message name="IDS_SETTINGS_SEARCH" desc="Name of the settings page which displays search engine preferences."> - Search engine - </message> + <if expr="chromeos"> + <message name="IDS_SETTINGS_SEARCH" desc="Name of the settings page which displays search engine and assistant preferences on Chrome OS."> + Search engine and Google Assistant + </message> + </if> + <if expr="not chromeos"> + <message name="IDS_SETTINGS_SEARCH" desc="Name of the settings page which displays search engine preferences."> + Search engine + </message> + </if> <message name="IDS_SETTINGS_SEARCH_EXPLANATION" desc="Explanation for the search engine dropdown setting."> Search engine used in the <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>address bar<ph name="END_LINK"></a></ph> </message> @@ -1914,6 +1921,17 @@ <message name="IDS_SETTINGS_SEARCH_ENABLE_GOOGLE_NOW" desc="Label for the checkbox which enables the Google Now in the launcher."> Show Google Now cards in the launcher </message> +<if expr="chromeos"> + <message name="IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT" desc="Label for the Google Assistant button."> + Google Assistant + </message> + <message name="IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ENABLED" desc="Sub label for the Google Assistant button when Assistant is enabled."> + Enabled + </message> + <message name="IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_DISABLED" desc="Sub label for the Google Assistant button when Assistant is disabled."> + Disabled + </message> +</if> <!-- Search Engines Page --> <message name="IDS_SETTINGS_SEARCH_ENGINES" desc="Name of the settings page which manages search engines."> @@ -1959,6 +1977,22 @@ Manage </message> + <!-- Google Assistant Page --> +<if expr="chromeos"> + <message name="IDS_SETTINGS_GOOGLE_ASSISTANT" desc="Name of the settings page for Google Assistant."> + Google Assistant + </message> + <message name="IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_CONTEXT" desc="Title for a toggle that lets the assistant use whats on the screen."> + Let assistant use what's on your screen + </message> + <message name="IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_CONTEXT_DESCRIPTION" desc="Sub label for context-enable toggle."> + Enables the assistant to show you related info, apps, and actions. + </message> + <message name="IDS_SETTINGS_GOOGLE_ASSISTANT_SETTINGS" desc="Title for a button that opens the Google Assistant app settings."> + Google Assistant settings + </message> +</if> + <!-- Site Settings Page --> <message name="IDS_SETTINGS_EXCEPTIONS_EMBEDDED_ON_HOST" desc="Template text for a child row in the content Exceptions page view. Controls the permission setting for the parent page when embedded on the specified site."> embedded on <ph name="URL">$1<ex>www.google.com</ex></ph>
diff --git a/chrome/browser/android/download/ui/thumbnail_provider.cc b/chrome/browser/android/download/ui/thumbnail_provider.cc index 2d2b647..13c6cf1 100644 --- a/chrome/browser/android/download/ui/thumbnail_provider.cc +++ b/chrome/browser/android/download/ui/thumbnail_provider.cc
@@ -7,7 +7,10 @@ #include "base/android/jni_string.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/memory/ptr_util.h" #include "base/memory/weak_ptr.h" +#include "base/task_scheduler/post_task.h" +#include "base/threading/thread_restrictions.h" #include "chrome/browser/image_decoder.h" #include "content/public/browser/browser_thread.h" #include "jni/ThumbnailProviderImpl_jni.h" @@ -25,71 +28,92 @@ // Ignore image files that are too large to avoid long delays. const int64_t kMaxImageSize = 10 * 1024 * 1024; // 10 MB +std::string LoadImageData(const base::FilePath& path) { + base::ThreadRestrictions::AssertIOAllowed(); + + // Confirm that the file's size is within our threshold. + int64_t file_size; + if (!base::GetFileSize(path, &file_size) || file_size > kMaxImageSize) { + LOG(ERROR) << "Unexpected file size: " << path.MaybeAsASCII() << ", " + << file_size; + return std::string(); + } + + std::string data; + bool success = base::ReadFileToString(path, &data); + + // Make sure the file isn't empty. + if (!success || data.empty()) { + LOG(ERROR) << "Failed to read file: " << path.MaybeAsASCII(); + return std::string(); + } + + return data; +} + +SkBitmap ScaleDownBitmap(int icon_size, const SkBitmap& decoded_image) { + DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + if (decoded_image.drawsNothing()) + return decoded_image; + + // Shrink the image down so that its smallest dimension is equal to or + // smaller than the requested size. + int min_dimension = std::min(decoded_image.width(), decoded_image.height()); + + if (min_dimension <= icon_size) + return decoded_image; + + uint64_t width = static_cast<uint64_t>(decoded_image.width()); + uint64_t height = static_cast<uint64_t>(decoded_image.height()); + return skia::ImageOperations::Resize( + decoded_image, skia::ImageOperations::RESIZE_BEST, + width * icon_size / min_dimension, height * icon_size / min_dimension); +} + class ImageThumbnailRequest : public ImageDecoder::ImageRequest { public: - static void Create(int icon_size, - const std::string& file_path, - base::WeakPtr<ThumbnailProvider> weak_provider) { - DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); - ImageThumbnailRequest* request = - new ImageThumbnailRequest(icon_size, file_path, weak_provider); - request->Start(); + ImageThumbnailRequest(int icon_size, + base::OnceCallback<void(const SkBitmap&)> callback) + : icon_size_(icon_size), + callback_(std::move(callback)), + weak_ptr_factory_(this) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } - protected: - void OnImageDecoded(const SkBitmap& decoded_image) override { - DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); - - SkBitmap thumbnail = decoded_image; - if (!decoded_image.drawsNothing()) { - // Shrink the image down so that its smallest dimension is equal to or - // smaller than the requested size. - int min_dimension = - std::min(decoded_image.width(), decoded_image.height()); - - if (min_dimension > icon_size_) { - uint64_t width = static_cast<uint64_t>(decoded_image.width()); - uint64_t height = static_cast<uint64_t>(decoded_image.height()); - thumbnail = skia::ImageOperations::Resize( - decoded_image, skia::ImageOperations::RESIZE_BEST, - width * icon_size_ / min_dimension, - height * icon_size_ / min_dimension); - } - } - - FinishRequest(thumbnail); + ~ImageThumbnailRequest() override { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } - void OnDecodeImageFailed() override { - LOG(ERROR) << "Failed to decode image: " << file_path_; - FinishRequest(SkBitmap()); + void Start(const base::FilePath& path) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, + base::BindOnce(&LoadImageData, path), + base::BindOnce(&ImageThumbnailRequest::OnLoadComplete, + weak_ptr_factory_.GetWeakPtr())); } private: - ImageThumbnailRequest(int icon_size, - const std::string& file_path, - base::WeakPtr<ThumbnailProvider> weak_provider) - : icon_size_(icon_size), - file_path_(file_path), - weak_provider_(weak_provider) {} + // ImageDecoder::ImageRequest implementation. + void OnImageDecoded(const SkBitmap& decoded_image) override { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, + base::BindOnce(&ScaleDownBitmap, icon_size_, decoded_image), + base::BindOnce(&ImageThumbnailRequest::FinishRequest, + weak_ptr_factory_.GetWeakPtr())); + } - void Start() { - DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); + void OnDecodeImageFailed() override { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + LOG(ERROR) << "Failed to decode image."; + FinishRequest(SkBitmap()); + } - // Confirm that the file's size is within our threshold. - int64_t file_size; - base::FilePath path = base::FilePath::FromUTF8Unsafe(file_path_); - if (!base::GetFileSize(path, &file_size) || file_size > kMaxImageSize) { - LOG(ERROR) << "Unexpected file size: " << file_path_ << ", " << file_size; - FinishRequest(SkBitmap()); - return; - } - - // Make sure the file isn't empty. - std::string data; - bool success = base::ReadFileToString(path, &data); - if (!success || data.empty()) { - LOG(ERROR) << "Failed to read file: " << file_path_; + void OnLoadComplete(const std::string& data) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (data.empty()) { FinishRequest(SkBitmap()); return; } @@ -98,20 +122,18 @@ } void FinishRequest(const SkBitmap& thumbnail) { - DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); - + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, - base::Bind(&ThumbnailProvider::OnThumbnailRetrieved, - weak_provider_, file_path_, thumbnail)); - task_runner()->DeleteSoon(FROM_HERE, this); + base::BindOnce(std::move(callback_), thumbnail)); + delete this; } const int icon_size_; - std::string file_path_; - base::WeakPtr<ThumbnailProvider> weak_provider_; + base::OnceCallback<void(const SkBitmap&)> callback_; + base::WeakPtrFactory<ImageThumbnailRequest> weak_ptr_factory_; - DISALLOW_IMPLICIT_CONSTRUCTORS(ImageThumbnailRequest); + DISALLOW_COPY_AND_ASSIGN(ImageThumbnailRequest); }; } // namespace @@ -151,13 +173,17 @@ jint icon_size) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - // The ImageThumbnailRequest deletes itself on completion. Don't track it - // because we don't (currently) cancel it. - std::string path = base::android::ConvertJavaStringToUTF8(env, jfile_path); - content::BrowserThread::PostTask( - content::BrowserThread::FILE, FROM_HERE, - base::Bind(&ImageThumbnailRequest::Create, icon_size, path, - weak_factory_.GetWeakPtr())); + std::string file_path = + base::android::ConvertJavaStringToUTF8(env, jfile_path); + + auto request = base::MakeUnique<ImageThumbnailRequest>( + icon_size, base::BindOnce(&ThumbnailProvider::OnThumbnailRetrieved, + weak_factory_.GetWeakPtr(), file_path)); + request->Start(base::FilePath::FromUTF8Unsafe(file_path)); + + // Dropping ownership of |request| here because it will clean itself up once + // the started request finishes. + request.release(); } // static
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc index 77e007ff..4d2446d7 100644 --- a/chrome/browser/chromeos/login/kiosk_browsertest.cc +++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -45,7 +45,6 @@ #include "chrome/browser/profiles/profile_impl.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profiles_state.h" -#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h" #include "chrome/common/chrome_constants.h" @@ -56,7 +55,6 @@ #include "chromeos/disks/disk_mount_manager.h" #include "chromeos/settings/cros_settings_provider.h" #include "components/prefs/pref_service.h" -#include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_manager.h" #include "components/signin/core/common/signin_pref_names.h" #include "content/public/browser/notification_observer.h" @@ -2222,14 +2220,6 @@ ASSERT_TRUE(window); content::WaitForLoadStop(window->web_contents()); - Profile* app_profile = ProfileManager::GetPrimaryUserProfile(); - ASSERT_TRUE(app_profile); - - // Ensure that the token service is initialized, as the below call to the - // Identity extension API will otherwise hang forever. - ProfileOAuth2TokenServiceFactory::GetForProfile(app_profile) - ->LoadCredentials("dummy_primary_account_id"); - // Check whether the app can retrieve an OAuth2 access token. std::string result; EXPECT_TRUE(content::ExecuteScriptAndExtractString( @@ -2242,6 +2232,8 @@ // Verify that the session is not considered to be logged in with a GAIA // account. + Profile* app_profile = ProfileManager::GetPrimaryUserProfile(); + ASSERT_TRUE(app_profile); EXPECT_FALSE( SigninManagerFactory::GetForProfile(app_profile)->IsAuthenticated());
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc index 3805952..3ca4324 100644 --- a/chrome/browser/extensions/api/identity/identity_apitest.cc +++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -430,10 +430,6 @@ GaiaCookieManagerServiceFactory::GetInstance() ->GetForProfile(profile()) ->Init(); - - // Ensure that the token service is initialized, as the Identity Service - // delays responding to requests until this initialization is complete. - token_service_->LoadCredentials("dummy_primary_account_id"); } protected:
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_api.cc b/chrome/browser/extensions/api/page_capture/page_capture_api.cc index 7ec0dc27..262f0e7 100644 --- a/chrome/browser/extensions/api/page_capture/page_capture_api.cc +++ b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
@@ -11,6 +11,8 @@ #include "base/bind_helpers.h" #include "base/files/file_util.h" #include "base/memory/ptr_util.h" +#include "base/task_scheduler/post_task.h" +#include "base/threading/thread_restrictions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/profiles/profile.h" @@ -47,6 +49,17 @@ const char kUserDenied[] = "User denied request."; #endif +constexpr base::TaskTraits kCreateTemporaryFileTaskTraits = { + // Requires IO. + base::MayBlock(), + + // TaskPriority: Inherit. + + // TaskShutdownBehavior: TemporaryFileCreated() called from + // CreateTemporaryFile() might access global variable, so use + // SKIP_ON_SHUTDOWN. See ShareableFileReference::GetOrCreate(). + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}; + void ClearFileReferenceOnIOThread( scoped_refptr<storage::ShareableFileReference>) {} @@ -100,8 +113,8 @@ } #endif - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, + base::PostTaskWithTraits( + FROM_HERE, kCreateTemporaryFileTaskTraits, base::BindOnce(&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile, this)); return true; @@ -133,8 +146,8 @@ void PageCaptureSaveAsMHTMLFunction::ResolvePermissionRequest( const PermissionIDSet& allowed_permissions) { if (allowed_permissions.ContainsID(APIPermission::kPageCapture)) { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, + base::PostTaskWithTraits( + FROM_HERE, kCreateTemporaryFileTaskTraits, base::BindOnce(&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile, this)); } else { @@ -144,7 +157,7 @@ #endif void PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile() { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); + base::ThreadRestrictions::AssertIOAllowed(); bool success = base::CreateTemporaryFile(&mhtml_path_); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE,
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc index c393e2e4..10671beb 100644 --- a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc +++ b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
@@ -58,7 +58,7 @@ // Make sure the MHTML data gets written to the temporary file. ASSERT_FALSE(delegate.temp_file_.empty()); // Flush the message loops to make sure the delete happens. - content::RunAllPendingInMessageLoop(content::BrowserThread::FILE); + content::RunAllBlockingPoolTasksUntilIdle(); content::RunAllPendingInMessageLoop(content::BrowserThread::IO); // Make sure the temporary file is destroyed once the javascript side reads // the contents. @@ -76,7 +76,7 @@ ScopedTestDialogAutoConfirm auto_confirm(ScopedTestDialogAutoConfirm::ACCEPT); ASSERT_TRUE(RunExtensionTest("page_capture")) << message_; ASSERT_FALSE(delegate.temp_file_.empty()); - content::RunAllPendingInMessageLoop(content::BrowserThread::FILE); + content::RunAllBlockingPoolTasksUntilIdle(); content::RunAllPendingInMessageLoop(content::BrowserThread::IO); base::ThreadRestrictions::ScopedAllowIO allow_io; ASSERT_FALSE(base::PathExists(delegate.temp_file_));
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 6cc7e6e..546d2d4d 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -268,6 +268,12 @@ (*s_whitelist)[::prefs::kArcEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; + // Google Assistant. + (*s_whitelist)[::prefs::kVoiceInteractionEnabled] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kVoiceInteractionContextEnabled] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + // Misc. (*s_whitelist)[::prefs::kUse24HourClock] = settings_private::PrefType::PREF_TYPE_BOOLEAN;
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.cc b/chrome/browser/extensions/api/terminal/terminal_private_api.cc index c2207fe..582571ef 100644 --- a/chrome/browser/extensions/api/terminal/terminal_private_api.cc +++ b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -11,6 +11,7 @@ #include "base/json/json_writer.h" #include "base/memory/ptr_util.h" #include "base/sys_info.h" +#include "base/task_scheduler/post_task.h" #include "base/values.h" #include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h" #include "chrome/browser/extensions/extension_service.h" @@ -140,11 +141,12 @@ if (tab_id < 0) return RespondNow(Error("Not called from a tab or app window")); - // Registry lives on FILE thread. - content::BrowserThread::PostTask( - content::BrowserThread::FILE, FROM_HERE, + // Registry lives on its own task runner. + chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask( + FROM_HERE, base::BindOnce( - &TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread, this, + &TerminalPrivateOpenTerminalProcessFunction::OpenOnRegistryTaskRunner, + this, base::Bind(&NotifyProcessOutput, browser_context(), extension_id(), tab_id), base::Bind( @@ -153,7 +155,7 @@ return RespondLater(); } -void TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread( +void TerminalPrivateOpenTerminalProcessFunction::OpenOnRegistryTaskRunner( const ProcessOutputCallback& output_callback, const OpenProcessCallback& callback) { DCHECK(!command_.empty()); @@ -182,15 +184,16 @@ std::unique_ptr<SendInput::Params> params(SendInput::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - // Registry lives on the FILE thread. - content::BrowserThread::PostTask( - content::BrowserThread::FILE, FROM_HERE, - base::BindOnce(&TerminalPrivateSendInputFunction::SendInputOnFileThread, - this, params->pid, params->input)); + // Registry lives on its own task runner. + chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce( + &TerminalPrivateSendInputFunction::SendInputOnRegistryTaskRunner, + this, params->pid, params->input)); return RespondLater(); } -void TerminalPrivateSendInputFunction::SendInputOnFileThread( +void TerminalPrivateSendInputFunction::SendInputOnRegistryTaskRunner( int terminal_id, const std::string& text) { bool success = @@ -215,17 +218,16 @@ CloseTerminalProcess::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - // Registry lives on the FILE thread. - content::BrowserThread::PostTask( - content::BrowserThread::FILE, FROM_HERE, - base::BindOnce( - &TerminalPrivateCloseTerminalProcessFunction::CloseOnFileThread, this, - params->pid)); + // Registry lives on its own task runner. + chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&TerminalPrivateCloseTerminalProcessFunction:: + CloseOnRegistryTaskRunner, + this, params->pid)); return RespondLater(); } -void TerminalPrivateCloseTerminalProcessFunction::CloseOnFileThread( +void TerminalPrivateCloseTerminalProcessFunction::CloseOnRegistryTaskRunner( int terminal_id) { bool success = chromeos::ProcessProxyRegistry::Get()->CloseProcess(terminal_id); @@ -251,17 +253,17 @@ OnTerminalResize::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - // Registry lives on the FILE thread. - content::BrowserThread::PostTask( - content::BrowserThread::FILE, FROM_HERE, - base::BindOnce( - &TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread, this, - params->pid, params->width, params->height)); + // Registry lives on its own task runner. + chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&TerminalPrivateOnTerminalResizeFunction:: + OnResizeOnRegistryTaskRunner, + this, params->pid, params->width, params->height)); return RespondLater(); } -void TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread( +void TerminalPrivateOnTerminalResizeFunction::OnResizeOnRegistryTaskRunner( int terminal_id, int width, int height) { @@ -296,16 +298,18 @@ if (tab_id != params->tab_id) return RespondNow(NoArguments()); - // Registry lives on the FILE thread. - content::BrowserThread::PostTask( - content::BrowserThread::FILE, FROM_HERE, - base::BindOnce(&TerminalPrivateAckOutputFunction::AckOutputOnFileThread, - this, params->pid)); + // Registry lives on its own task runner. + chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce( + &TerminalPrivateAckOutputFunction::AckOutputOnRegistryTaskRunner, + this, params->pid)); return RespondNow(NoArguments()); } -void TerminalPrivateAckOutputFunction::AckOutputOnFileThread(int terminal_id) { +void TerminalPrivateAckOutputFunction::AckOutputOnRegistryTaskRunner( + int terminal_id) { chromeos::ProcessProxyRegistry::Get()->AckOutput(terminal_id); }
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.h b/chrome/browser/extensions/api/terminal/terminal_private_api.h index 09982a74..c6455784 100644 --- a/chrome/browser/extensions/api/terminal/terminal_private_api.h +++ b/chrome/browser/extensions/api/terminal/terminal_private_api.h
@@ -32,8 +32,8 @@ const std::string& output)>; using OpenProcessCallback = base::Callback<void(int terminal_id)>; - void OpenOnFileThread(const ProcessOutputCallback& output_callback, - const OpenProcessCallback& callback); + void OpenOnRegistryTaskRunner(const ProcessOutputCallback& output_callback, + const OpenProcessCallback& callback); void RespondOnUIThread(int terminal_id); std::string command_; @@ -52,7 +52,7 @@ ExtensionFunction::ResponseAction Run() override; private: - void SendInputOnFileThread(int terminal_id, const std::string& input); + void SendInputOnRegistryTaskRunner(int terminal_id, const std::string& input); void RespondOnUIThread(bool success); }; @@ -69,7 +69,7 @@ ExtensionFunction::ResponseAction Run() override; private: - void CloseOnFileThread(int terminal_id); + void CloseOnRegistryTaskRunner(int terminal_id); void RespondOnUIThread(bool success); }; @@ -86,7 +86,7 @@ ExtensionFunction::ResponseAction Run() override; private: - void OnResizeOnFileThread(int terminal_id, int width, int height); + void OnResizeOnRegistryTaskRunner(int terminal_id, int width, int height); void RespondOnUIThread(bool success); }; @@ -101,7 +101,7 @@ ExtensionFunction::ResponseAction Run() override; private: - void AckOutputOnFileThread(int terminal_id); + void AckOutputOnRegistryTaskRunner(int terminal_id); }; } // namespace extensions
diff --git a/chrome/browser/media/router/discovery/discovery_network_list_win.cc b/chrome/browser/media/router/discovery/discovery_network_list_win.cc index a18dd90..5cdc430 100644 --- a/chrome/browser/media/router/discovery/discovery_network_list_win.cc +++ b/chrome/browser/media/router/discovery/discovery_network_list_win.cc
@@ -4,7 +4,313 @@ #include "chrome/browser/media/router/discovery/discovery_network_list.h" -// TODO(btolsch): Implement this for Windows. +#include <winsock2.h> +#include <ws2tcpip.h> + +#include <iphlpapi.h> // NOLINT + +#include <windot11.h> // NOLINT +#include <wlanapi.h> // NOLINT + +#include <algorithm> +#include <cstring> +#include <map> +#include <utility> +#include <vector> + +#include "base/containers/small_map.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string_number_conversions.h" + +namespace { + +struct GuidOperatorLess { + bool operator()(const GUID& guid1, const GUID& guid2) const { + return memcmp(&guid1, &guid2, sizeof(GUID)) < 0; + } +}; + +void IfTable2Deleter(PMIB_IF_TABLE2 interface_table) { + if (interface_table) { + FreeMibTable(interface_table); + } +} + +typedef DWORD(WINAPI* WlanOpenHandleFunction)(DWORD dwClientVersion, + PVOID pReserved, + PDWORD pdwNegotiatedVersion, + PHANDLE phClientHandle); +typedef DWORD(WINAPI* WlanCloseHandleFunction)(HANDLE hClientHandle, + PVOID pReserved); +typedef DWORD(WINAPI* WlanEnumInterfacesFunction)( + HANDLE hClientHandle, + PVOID pReserved, + PWLAN_INTERFACE_INFO_LIST* ppInterfaceList); +typedef DWORD(WINAPI* WlanQueryInterfaceFunction)( + HANDLE hClientHandle, + const GUID* pInterfaceGuid, + WLAN_INTF_OPCODE OpCode, + PVOID pReserved, + PDWORD pdwDataSize, + PVOID* ppData, + PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType); +typedef VOID(WINAPI* WlanFreeMemoryFunction)(PVOID pMemory); + +class WlanApi { + public: + const WlanOpenHandleFunction wlan_open_handle; + const WlanCloseHandleFunction wlan_close_handle; + const WlanEnumInterfacesFunction wlan_enum_interfaces; + const WlanQueryInterfaceFunction wlan_query_interface; + const WlanFreeMemoryFunction wlan_free_memory; + + static std::unique_ptr<WlanApi> Create() { + static const wchar_t* kWlanDllPath = L"%WINDIR%\\system32\\wlanapi.dll"; + wchar_t path[MAX_PATH] = {0}; + ExpandEnvironmentStrings(kWlanDllPath, path, arraysize(path)); + HINSTANCE library = + LoadLibraryEx(path, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!library) { + return nullptr; + } + return base::WrapUnique(new WlanApi(library)); + } + + ~WlanApi() { FreeLibrary(library_); } + + private: + explicit WlanApi(HINSTANCE library) + : wlan_open_handle(reinterpret_cast<WlanOpenHandleFunction>( + GetProcAddress(library, "WlanOpenHandle"))), + wlan_close_handle(reinterpret_cast<WlanCloseHandleFunction>( + GetProcAddress(library, "WlanCloseHandle"))), + wlan_enum_interfaces(reinterpret_cast<WlanEnumInterfacesFunction>( + GetProcAddress(library, "WlanEnumInterfaces"))), + wlan_query_interface(reinterpret_cast<WlanQueryInterfaceFunction>( + GetProcAddress(library, "WlanQueryInterface"))), + wlan_free_memory(reinterpret_cast<WlanFreeMemoryFunction>( + GetProcAddress(library, "WlanFreeMemory"))), + library_(library) { + DCHECK(library); + DCHECK(wlan_open_handle); + DCHECK(wlan_close_handle); + DCHECK(wlan_enum_interfaces); + DCHECK(wlan_query_interface); + DCHECK(wlan_free_memory); + } + + HINSTANCE library_; + + DISALLOW_COPY_AND_ASSIGN(WlanApi); +}; + +class ScopedWlanClientHandle { + public: + explicit ScopedWlanClientHandle( + const WlanCloseHandleFunction wlan_close_handle) + : wlan_close_handle_(wlan_close_handle) {} + ~ScopedWlanClientHandle() { + if (handle != nullptr) { + wlan_close_handle_(handle, nullptr); + } + } + + HANDLE handle = nullptr; + + private: + const WlanCloseHandleFunction wlan_close_handle_; + + DISALLOW_COPY_AND_ASSIGN(ScopedWlanClientHandle); +}; + +// Returns a map from a network interface's GUID to its MAC address. This +// enumerates all network interfaces, not just wireless interfaces. +base::small_map<std::map<GUID, std::string, GuidOperatorLess>> +GetInterfaceGuidMacMap() { + PMIB_IF_TABLE2 interface_table_raw = nullptr; + auto result = GetIfTable2(&interface_table_raw); + if (result != ERROR_SUCCESS) { + LOG(WARNING) << "GetIfTable2() failed: " << result; + return {}; + } + std::unique_ptr<MIB_IF_TABLE2, decltype(&IfTable2Deleter)> interface_table( + interface_table_raw, IfTable2Deleter); + + base::small_map<std::map<GUID, std::string, GuidOperatorLess>> guid_mac_map; + for (ULONG i = 0; i < interface_table->NumEntries; ++i) { + const auto* interface_row = &interface_table->Table[i]; + guid_mac_map.emplace(interface_row->InterfaceGuid, + std::string{reinterpret_cast<const char*>( + interface_row->PhysicalAddress), + interface_row->PhysicalAddressLength}); + } + + return guid_mac_map; +} + +// Returns the associated SSID of an interface identified by its interface GUID. +// If it is not a wireless interface or if it's not currently associated with a +// network, it returns an empty string. +std::string GetSsidForInterfaceGuid(const HANDLE wlan_client_handle, + const WlanApi& wlan_api, + const GUID& interface_guid) { + WLAN_CONNECTION_ATTRIBUTES* connection_info_raw = nullptr; + DWORD connection_info_size = 0; + auto result = wlan_api.wlan_query_interface( + wlan_client_handle, &interface_guid, wlan_intf_opcode_current_connection, + nullptr, &connection_info_size, + reinterpret_cast<void**>(&connection_info_raw), nullptr); + if (result != ERROR_SUCCESS) { + // We can't get the SSID for this interface so its network ID will + // fall back to its MAC address below. + DVLOG(2) << "Failed to get wireless connection info: " << result; + return {}; + } + std::unique_ptr<WLAN_CONNECTION_ATTRIBUTES, WlanFreeMemoryFunction> + connection_info(connection_info_raw, wlan_api.wlan_free_memory); + if (connection_info->isState != wlan_interface_state_connected) { + return {}; + } + const auto* ssid = &connection_info->wlanAssociationAttributes.dot11Ssid; + return std::string(reinterpret_cast<const char*>(ssid->ucSSID), + ssid->uSSIDLength); +} + +// Returns a map from a network adapter's MAC address to its currently +// associated WiFi SSID. +base::small_map<std::map<std::string, std::string>> GetMacSsidMap() { + auto wlan_api = WlanApi::Create(); + if (!wlan_api) { + return {}; + } + ScopedWlanClientHandle wlan_client_handle(wlan_api->wlan_close_handle); + constexpr DWORD kWlanClientVersion = 2; + DWORD wlan_current_version = 0; + + auto result = wlan_api->wlan_open_handle(kWlanClientVersion, nullptr, + &wlan_current_version, + &wlan_client_handle.handle); + if (result != ERROR_SUCCESS) { + LOG(WARNING) << "Failed to open Wlan client handle: " << result; + return {}; + } + + PWLAN_INTERFACE_INFO_LIST wlan_interface_list_raw = nullptr; + result = wlan_api->wlan_enum_interfaces(wlan_client_handle.handle, nullptr, + &wlan_interface_list_raw); + if (result != ERROR_SUCCESS) { + LOG(WARNING) << "Failed to enumerate wireless interfaces: " << result; + return {}; + } + + std::unique_ptr<WLAN_INTERFACE_INFO_LIST, WlanFreeMemoryFunction> + wlan_interface_list(wlan_interface_list_raw, wlan_api->wlan_free_memory); + auto guid_mac_map = GetInterfaceGuidMacMap(); + base::small_map<std::map<std::string, std::string>> mac_ssid_map; + + // This loop takes each wireless interface and maps its MAC address to its + // associated SSID, if it has one. Each wireless interface has an interface + // GUID which we can use to get its MAC address via |guid_mac_map| and its + // associated SSID via WlanQueryInterface. + for (DWORD i = 0; i < wlan_interface_list->dwNumberOfItems; ++i) { + const auto* interface_info = &wlan_interface_list->InterfaceInfo[i]; + const auto mac_entry = guid_mac_map.find(interface_info->InterfaceGuid); + if (mac_entry == guid_mac_map.end()) { + continue; + } + auto ssid = GetSsidForInterfaceGuid(wlan_client_handle.handle, *wlan_api, + interface_info->InterfaceGuid); + if (ssid.empty()) { + continue; + } + mac_ssid_map.emplace(mac_entry->second, std::move(ssid)); + } + return mac_ssid_map; +} + +} // namespace + std::vector<DiscoveryNetworkInfo> GetDiscoveryNetworkInfoList() { - return std::vector<DiscoveryNetworkInfo>(); + // Max number of times to retry GetAdaptersAddresses due to + // ERROR_BUFFER_OVERFLOW. If GetAdaptersAddresses returns this indefinitely + // due to an unforeseen reason, we don't want to be stuck in an endless loop. + constexpr int kMaxGetAdaptersAddressTries = 10; + + // Use an initial buffer size of 15KB, as recommended by MSDN. See: + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx + constexpr int kInitialAddressBufferSize = 15000; + + constexpr ULONG kAddressFlags = + GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER; + + // Although we need to provide GetAdaptersAddresses with a buffer, there's no + // way to know what size to use. We use a best-guess here but when + // GetAdaptersAddresses returns ERROR_BUFFER_OVERFLOW, it means our guess was + // too small. When this happens it will also reset |addresses_buffer_size| to + // the required size. Although it's very unlikely that two successive calls + // will both require increasing the buffer size, there's no guarantee that + // this won't happen; this is what the maximum retry count guards against. + ULONG addresses_buffer_size = kInitialAddressBufferSize; + std::unique_ptr<char[]> addresses_buffer; + PIP_ADAPTER_ADDRESSES adapter_addresses = nullptr; + ULONG result = ERROR_BUFFER_OVERFLOW; + for (int i = 0; + result == ERROR_BUFFER_OVERFLOW && i < kMaxGetAdaptersAddressTries; + ++i) { + addresses_buffer.reset(new char[addresses_buffer_size]); + adapter_addresses = + reinterpret_cast<PIP_ADAPTER_ADDRESSES>(addresses_buffer.get()); + result = GetAdaptersAddresses(AF_UNSPEC, kAddressFlags, nullptr, + adapter_addresses, &addresses_buffer_size); + } + + if (result != NO_ERROR) { + return {}; + } + + std::vector<DiscoveryNetworkInfo> network_ids; + auto mac_ssid_map = GetMacSsidMap(); + for (const IP_ADAPTER_ADDRESSES* current_adapter = adapter_addresses; + current_adapter != nullptr; current_adapter = current_adapter->Next) { + // We only want adapters which are up and either Ethernet or wireless, so we + // skip everything else here. + if (current_adapter->OperStatus != IfOperStatusUp || + (current_adapter->IfType != IF_TYPE_ETHERNET_CSMACD && + current_adapter->IfType != IF_TYPE_IEEE80211)) { + continue; + } + + // We have to use a slightly roundabout way to get the SSID for each + // adapter: + // - Enumerate wifi devices to get list of interface GUIDs. + // - Enumerate interfaces to get interface GUID -> physical address map. + // - Map interface GUIDs to SSID. + // - Use GUID -> MAC map to do MAC -> interface GUID -> SSID. + // Although it's theoretically possible to have multiple interfaces per + // adapter, most wireless cards don't actually allow multiple + // managed-mode interfaces. However, in the event that there really + // are multiple interfaces per adapter (i.e. physical address), we will + // simply use the SSID of the first match. It's unclear how Windows would + // handle this case since it's somewhat loose with its use of the words + // "adapter" and "interface". + std::string name(current_adapter->AdapterName); + if (current_adapter->IfType == IF_TYPE_IEEE80211) { + std::string adapter_mac( + reinterpret_cast<const char*>(current_adapter->PhysicalAddress), + current_adapter->PhysicalAddressLength); + const auto ssid_entry = mac_ssid_map.find(adapter_mac); + if (ssid_entry != mac_ssid_map.end()) { + network_ids.emplace_back(name, ssid_entry->second); + continue; + } + } + network_ids.emplace_back( + name, base::HexEncode(current_adapter->PhysicalAddress, + current_adapter->PhysicalAddressLength)); + } + + StableSortDiscoveryNetworkInfo(network_ids.begin(), network_ids.end()); + + return network_ids; }
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc index 561601347..a884d98 100644 --- a/chrome/browser/printing/print_job_worker.cc +++ b/chrome/browser/printing/print_job_worker.cc
@@ -240,7 +240,7 @@ // Running a dialog causes an exit to webpage-initiated fullscreen. // http://crbug.com/728276 - if (web_contents->IsFullscreenForCurrentTab()) + if (web_contents && web_contents->IsFullscreenForCurrentTab()) web_contents->ExitFullscreen(true); // weak_factory_ creates pointers valid only on owner_ thread.
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html index bcff338..347d949 100644 --- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html +++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
@@ -87,10 +87,10 @@ #clearFrom { -webkit-margin-start: 0.5em; - /* Adjust for 1px md-select-underline and 1px additional bottom padding + /* Adjust for md-select-underline and 1px additional bottom padding * to keep md-select's text (without the underline) aligned with * neighboring text that does not have an underline. */ - margin-top: 2px; + margin-top: 3px; } .title .secondary {
diff --git a/chrome/browser/resources/settings/google_assistant_page/compiled_resources2.gyp b/chrome/browser/resources/settings/google_assistant_page/compiled_resources2.gyp new file mode 100644 index 0000000..2ce6c64 --- /dev/null +++ b/chrome/browser/resources/settings/google_assistant_page/compiled_resources2.gyp
@@ -0,0 +1,25 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +{ + 'targets': [ + { + 'target_name': 'google_assistant_browser_proxy', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(EXTERNS_GYP):chrome_send', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { + 'target_name': 'google_assistant_page', + 'dependencies': [ + '../prefs/compiled_resources2.gyp:prefs_behavior', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', + 'google_assistant_browser_proxy', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + ], +}
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.html b/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.html new file mode 100644 index 0000000..81603a75 --- /dev/null +++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.html
@@ -0,0 +1,2 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="google_assistant_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.js b/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.js new file mode 100644 index 0000000..27aa284 --- /dev/null +++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.js
@@ -0,0 +1,55 @@ +// 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. + +/** + * @fileoverview A helper object used from the google assistant section + * to interact with the browser. + */ + +cr.define('settings', function() { + /** @interface */ + class GoogleAssistantBrowserProxy { + /** + * Enables or disables the Google Assistant. + * @param {boolean} enabled + */ + setGoogleAssistantEnabled(enabled) {} + + /** + * Enables or disables screen context for the Google Assistant. + * @param {boolean} enabled + */ + setGoogleAssistantContextEnabled(enabled) {} + + /** Launches into the Google Assistant app settings. */ + launchGoogleAssistantSettings() {} + } + + /** @implements {settings.GoogleAssistantBrowserProxy} */ + class GoogleAssistantBrowserProxyImpl { + /** @override */ + setGoogleAssistantEnabled(enabled) { + chrome.send('setGoogleAssistantEnabled', [enabled]); + } + + /** @override */ + setGoogleAssistantContextEnabled(enabled) { + chrome.send('setGoogleAssistantContextEnabled', [enabled]); + } + + /** @override */ + showGoogleAssistantSettings() { + chrome.send('showGoogleAssistantSettings'); + } + } + + // The singleton instance_ is replaced with a test version of this wrapper + // during testing. + cr.addSingletonGetter(GoogleAssistantBrowserProxyImpl); + + return { + GoogleAssistantBrowserProxy: GoogleAssistantBrowserProxy, + GoogleAssistantBrowserProxyImpl: GoogleAssistantBrowserProxyImpl, + }; +});
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html new file mode 100644 index 0000000..fec7261 --- /dev/null +++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
@@ -0,0 +1,42 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> +<link rel="import" href="google_assistant_browser_proxy.html"> +<link rel="import" href="../prefs/prefs_behavior.html"> +<link rel="import" href="../settings_shared_css.html"> + +<dom-module id="settings-google-assistant-page"> + <template> + <style include="settings-shared"></style> + <div class="settings-box first"> + <settings-toggle-button id="googleAssistantEnable" + class="start primary-toggle" + pref="{{prefs.settings.voice_interaction.enabled}}" + label="[[getAssistantOnOffLabel_( + prefs.settings.voice_interaction.enabled.value)]]" + on-change="onGoogleAssistantEnableChange_"> + </settings-toggle-button> + </div> + <template is="dom-if" + if="{{prefs.settings.voice_interaction.enabled.value}}"> + <div class="settings-box continuation indented"> + <settings-toggle-button id="googleAssistantContextEnable" class="start" + pref="{{prefs.settings.voice_interaction.context.enabled}}" + label="$i18n{googleAssistantEnableContext}" + sub-label="$i18n{googleAssistantEnableContextDescription}" + on-change="onGoogleAssistantContextEnableChange_"> + </settings-toggle-button> + </div> + <div class="settings-box" + on-tap="onGoogleAssistantSettingsTapped_" actionable> + <div class="start"> + $i18n{googleAssistantSettings} + </div> + <button class="icon-external" is="paper-icon-button-light"> + </button> + </div> + </template> + </template> + <script src="google_assistant_page.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js new file mode 100644 index 0000000..8db740b --- /dev/null +++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js
@@ -0,0 +1,47 @@ +// 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. + +/** + * @fileoverview 'settings-google-assistant-page' is the settings page + * containing Google Assistant settings. + */ +Polymer({ + is: 'settings-google-assistant-page', + + behaviors: [I18nBehavior, PrefsBehavior], + + /** @private {?settings.GoogleAssistantBrowserProxy} */ + browserProxy_: null, + + /** @override */ + created: function() { + this.browserProxy_ = settings.GoogleAssistantBrowserProxyImpl.getInstance(); + }, + + /** + * @param {boolean} toggleValue + * @return {string} + * @private + */ + getAssistantOnOffLabel_: function(toggleValue) { + return this.i18n(toggleValue ? 'toggleOn' : 'toggleOff'); + }, + + /** @private */ + onGoogleAssistantEnableChange_: function() { + this.browserProxy_.setGoogleAssistantEnabled( + !!this.getPref('settings.voice_interaction.enabled.value')); + }, + + /** @private */ + onGoogleAssistantContextEnableChange_: function() { + this.browserProxy_.setGoogleAssistantContextEnabled( + !!this.getPref('settings.voice_interaction.context.enabled.value')); + }, + + /** @private */ + onGoogleAssistantSettingsTapped_: function() { + this.browserProxy_.showGoogleAssistantSettings(); + }, +});
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js index d20604ccc..e90fb16 100644 --- a/chrome/browser/resources/settings/route.js +++ b/chrome/browser/resources/settings/route.js
@@ -33,6 +33,7 @@ * EDIT_DICTIONARY: (undefined|!settings.Route), * FINGERPRINT: (undefined|!settings.Route), * FONTS: (undefined|!settings.Route), + * GOOGLE_ASSISTANT: (undefined|!settings.Route), * IMPORT_DATA: (undefined|!settings.Route), * INPUT_METHODS: (undefined|!settings.Route), * INTERNET: (undefined|!settings.Route), @@ -224,6 +225,9 @@ r.SEARCH = r.BASIC.createSection('/search', 'search'); r.SEARCH_ENGINES = r.SEARCH.createChild('/searchEngines'); + // <if expr="chromeos"> + r.GOOGLE_ASSISTANT = r.SEARCH.createChild('/googleAssistant'); + // </if> // <if expr="chromeos"> r.ANDROID_APPS = r.BASIC.createSection('/androidApps', 'androidApps');
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html index 0aed8e79..62ab45f0 100644 --- a/chrome/browser/resources/settings/search_page/search_page.html +++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -1,6 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html"> +<link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> @@ -18,6 +19,11 @@ <link rel="import" href="../settings_shared_css.html"> <link rel="import" href="../settings_vars_css.html"> +<if expr="chromeos"> + <link rel="import" href="../google_assistant_page/google_assistant_page.html"> + <link rel="import" href="../google_assistant_page/google_assistant_browser_proxy.html"> +</if> + <dom-module id="settings-search-page"> <template> <style include="settings-shared md-select"> @@ -135,7 +141,7 @@ </template> <!-- Manage search engines --> - <div id="subpage-trigger" class="settings-box" + <div id="engines-subpage-trigger" class="settings-box" on-tap="onManageSearchEnginesTap_" actionable> <div class="start"> $i18n{searchEnginesManage} @@ -143,14 +149,44 @@ <button class="subpage-arrow" is="paper-icon-button-light" aria-label="$i18n{searchEnginesManage}"></button> </div> + +<if expr="chromeos"> + <!-- Google Assistant --> + <template is="dom-if" if="[[voiceInteractionFeatureEnabled_]]"> + <div id="assistant-subpage-trigger" class="settings-box two-line" + on-tap="onGoogleAssistantTap_" actionable> + <div class="start"> + $i18n{searchGoogleAssistant} + <div class="secondary"> + [[getAssistantEnabledDisabledLabel_( + prefs.settings.voice_interaction.enabled.value)]] + </div> + </div> + <button class="subpage-arrow" is="paper-icon-button-light" + aria-label="$i18n{searchGoogleAssistant}"></button> + </div> + </template> +</if> </neon-animatable> <template is="dom-if" route-path="/searchEngines"> <settings-subpage - associated-control="[[$$('#subpage-trigger')]]" + associated-control="[[$$('#engines-subpage-trigger')]]" page-title="$i18n{searchEnginesManage}"> <settings-search-engines-page></settings-search-engines-page> </settings-subpage> </template> +<if expr="chromeos"> + <template is="dom-if" if="[[voiceInteractionFeatureEnabled_]]"> + <template is="dom-if" route-path="/googleAssistant"> + <settings-subpage + associated-control="[[$$('#assistant-subpage-trigger')]]" + page-title="$i18n{googleAssistantPageTitle}"> + <settings-google-assistant-page prefs="{{prefs}}"> + </settings-google-assistant-page> + </settings-subpage> + </template> + </template> +</if> </settings-animated-pages> </template> <script src="search_page.js"></script>
diff --git a/chrome/browser/resources/settings/search_page/search_page.js b/chrome/browser/resources/settings/search_page/search_page.js index 06439bd1..6732b03f 100644 --- a/chrome/browser/resources/settings/search_page/search_page.js +++ b/chrome/browser/resources/settings/search_page/search_page.js
@@ -42,6 +42,16 @@ /** @type {?Map<string, string>} */ focusConfig_: Object, + + // <if expr="chromeos"> + /** @private */ + voiceInteractionFeatureEnabled_: { + type: Boolean, + value: function() { + return loadTimeData.getBoolean('enableVoiceInteraction'); + }, + } + // </if> }, /** @private {?settings.SearchEnginesBrowserProxy} */ @@ -78,8 +88,15 @@ if (settings.routes.SEARCH_ENGINES) { this.focusConfig_.set( settings.routes.SEARCH_ENGINES.path, - '#subpage-trigger .subpage-arrow'); + '#engines-subpage-trigger .subpage-arrow'); } + // <if expr="chromeos"> + if (settings.routes.GOOGLE_ASSISTANT) { + this.focusConfig_.set( + settings.routes.GOOGLE_ASSISTANT.path, + '#assistant-subpage-trigger .subpage-arrow'); + } + // </if> }, /** @private */ @@ -99,6 +116,14 @@ settings.navigateTo(settings.routes.SEARCH_ENGINES); }, + // <if expr="chromeos"> + /** @private */ + onGoogleAssistantTap_: function() { + assert(this.voiceInteractionFeatureEnabled_); + settings.navigateTo(settings.routes.GOOGLE_ASSISTANT); + }, + // </if> + /** * @param {!Event} event * @private @@ -169,6 +194,19 @@ this.browserProxy_.setHotwordSearchEnabled(this.hotwordInfo_.enabled); }, + // <if expr="chromeos"> + /** + * @param {boolean} toggleValue + * @return {string} + * @private + */ + getAssistantEnabledDisabledLabel_: function(toggleValue) { + return this.i18n( + toggleValue ? 'searchGoogleAssistantEnabled' : + 'searchGoogleAssistantDisabled'); + }, + // </if> + /** * @param {!Event} event * @private
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index 5a8c40e2..eb33929 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -1017,9 +1017,28 @@ type="chrome_html" preprocess="true" allowexternalscript="true" /> + <if expr="chromeos"> + <structure name="IDR_SETTINGS_GOOGLE_ASSISTANT_PAGE_GOOGLE_ASSISTANT_PAGE_JS" + file="google_assistant_page/google_assistant_page.js" + type="chrome_html" + allowexternalscript="true"/> + <structure name="IDR_SETTINGS_GOOGLE_ASSISTANT_PAGE_GOOGLE_ASSISTANT_PAGE_HTML" + file="google_assistant_page/google_assistant_page.html" + type="chrome_html" + allowexternalscript="true" /> + <structure name="IDR_SETTINGS_GOOGLE_ASSISTANT_PAGE_GOOGLE_ASSISTANT_BROWSER_PROXY_JS" + file="google_assistant_page/google_assistant_browser_proxy.js" + type="chrome_html" + allowexternalscript="true" /> + <structure name="IDR_SETTINGS_GOOGLE_ASSISTANT_PAGE_GOOGLE_ASSISTANT_BROWSER_PROXY_HTML" + file="google_assistant_page/google_assistant_browser_proxy.html" + type="chrome_html" + allowexternalscript="true" /> + </if> <structure name="IDR_SETTINGS_SEARCH_PAGE_JS" file="search_page/search_page.js" - type="chrome_html" /> + type="chrome_html" + preprocess="true" /> <structure name="IDR_SETTINGS_SEARCH_PAGE_HTML" file="search_page/search_page.html" type="chrome_html"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 46e5b39..445df80 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1023,6 +1023,8 @@ "webui/settings/chromeos/easy_unlock_settings_handler.h", "webui/settings/chromeos/fingerprint_handler.cc", "webui/settings/chromeos/fingerprint_handler.h", + "webui/settings/chromeos/google_assistant_handler.cc", + "webui/settings/chromeos/google_assistant_handler.h", "webui/settings/chromeos/internet_handler.cc", "webui/settings/chromeos/internet_handler.h", "webui/settings/downloads_handler.cc",
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.cc b/chrome/browser/ui/views/payments/payment_method_view_controller.cc index fedfc5b..17707a4 100644 --- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -91,6 +91,9 @@ static_cast<AutofillPaymentInstrument*>(instrument_) ->credit_card()); return; + case PaymentInstrument::Type::NATIVE_MOBILE_APP: + // We cannot edit a native mobile app instrument. + return; } NOTREACHED(); }
diff --git a/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc new file mode 100644 index 0000000..7d4e338 --- /dev/null +++ b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc
@@ -0,0 +1,72 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h" + +#include <utility> + +#include "base/bind.h" +#include "base/values.h" +#include "chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h" +#include "chrome/browser/profiles/profile.h" +#include "components/arc/arc_service_manager.h" + +namespace chromeos { +namespace settings { + +GoogleAssistantHandler::GoogleAssistantHandler(Profile* profile) + : profile_(profile) {} + +GoogleAssistantHandler::~GoogleAssistantHandler() {} + +void GoogleAssistantHandler::OnJavascriptAllowed() {} +void GoogleAssistantHandler::OnJavascriptDisallowed() {} + +void GoogleAssistantHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "setGoogleAssistantEnabled", + base::Bind(&GoogleAssistantHandler::HandleSetGoogleAssistantEnabled, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "setGoogleAssistantContextEnabled", + base::Bind( + &GoogleAssistantHandler::HandleSetGoogleAssistantContextEnabled, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "showGoogleAssistantSettings", + base::Bind(&GoogleAssistantHandler::HandleShowGoogleAssistantSettings, + base::Unretained(this))); +} + +void GoogleAssistantHandler::HandleSetGoogleAssistantEnabled( + const base::ListValue* args) { + CHECK_EQ(1U, args->GetSize()); + bool enabled; + CHECK(args->GetBoolean(0, &enabled)); + + auto* service = + arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(profile_); + if (service) + service->SetVoiceInteractionEnabled(enabled); +} + +void GoogleAssistantHandler::HandleSetGoogleAssistantContextEnabled( + const base::ListValue* args) { + CHECK_EQ(1U, args->GetSize()); + bool enabled; + CHECK(args->GetBoolean(0, &enabled)); + + auto* service = + arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(profile_); + if (service) + service->SetVoiceInteractionContextEnabled(enabled); +} + +void GoogleAssistantHandler::HandleShowGoogleAssistantSettings( + const base::ListValue* args) { + // TODO(rcui): Implement. +} + +} // namespace settings +} // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h new file mode 100644 index 0000000..01c4116 --- /dev/null +++ b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h
@@ -0,0 +1,41 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_GOOGLE_ASSISTANT_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_GOOGLE_ASSISTANT_HANDLER_H_ + +#include "base/macros.h" +#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" + +class Profile; + +namespace chromeos { +namespace settings { + +class GoogleAssistantHandler : public ::settings::SettingsPageUIHandler { + public: + explicit GoogleAssistantHandler(Profile* profile); + ~GoogleAssistantHandler() override; + + void RegisterMessages() override; + void OnJavascriptAllowed() override; + void OnJavascriptDisallowed() override; + + private: + // WebUI call to enable the Google Assistant. + void HandleSetGoogleAssistantEnabled(const base::ListValue* args); + // WebUI call to enable context for the Google Assistant. + void HandleSetGoogleAssistantContextEnabled(const base::ListValue* args); + // WebUI call to launch into the Google Assistant app settings. + void HandleShowGoogleAssistantSettings(const base::ListValue* args); + + Profile* const profile_; + + DISALLOW_COPY_AND_ASSIGN(GoogleAssistantHandler); +}; + +} // namespace settings +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_GOOGLE_ASSISTANT_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 1e298d73..f33186d5 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -1677,19 +1677,26 @@ void AddSearchStrings(content::WebUIDataSource* html_source) { LocalizedString localized_strings[] = { - {"searchPageTitle", IDS_SETTINGS_SEARCH}, - {"searchEnginesManage", IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES}, - {"searchOkGoogleLabel", IDS_SETTINGS_SEARCH_OK_GOOGLE_LABEL}, - {"searchOkGoogleSubtextAlwaysOn", - IDS_SETTINGS_SEARCH_OK_GOOGLE_SUBTEXT_ALWAYS_ON}, - {"searchOkGoogleSubtextNoHardware", - IDS_SETTINGS_SEARCH_OK_GOOGLE_SUBTEXT_NO_HARDWARE}, - {"searchOkGoogleAudioHistoryLabel", - IDS_SETTINGS_SEARCH_OK_GOOGLE_AUDIO_HISTORY_LABEL}, - {"searchOkGoogleAudioHistorySubtext", - IDS_SETTINGS_SEARCH_OK_GOOGLE_AUDIO_HISTORY_SUBTEXT}, - {"searchOkGoogleRetrain", IDS_SETTINGS_SEARCH_OK_GOOGLE_RETRAIN}, - {"searchEnableGoogleNowLabel", IDS_SETTINGS_SEARCH_ENABLE_GOOGLE_NOW}, + {"searchPageTitle", IDS_SETTINGS_SEARCH}, + {"searchEnginesManage", IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES}, + {"searchOkGoogleLabel", IDS_SETTINGS_SEARCH_OK_GOOGLE_LABEL}, +#if defined(OS_CHROMEOS) + {"searchGoogleAssistant", IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT}, + {"searchGoogleAssistantEnabled", + IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ENABLED}, + {"searchGoogleAssistantDisabled", + IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_DISABLED}, +#endif + {"searchOkGoogleSubtextAlwaysOn", + IDS_SETTINGS_SEARCH_OK_GOOGLE_SUBTEXT_ALWAYS_ON}, + {"searchOkGoogleSubtextNoHardware", + IDS_SETTINGS_SEARCH_OK_GOOGLE_SUBTEXT_NO_HARDWARE}, + {"searchOkGoogleAudioHistoryLabel", + IDS_SETTINGS_SEARCH_OK_GOOGLE_AUDIO_HISTORY_LABEL}, + {"searchOkGoogleAudioHistorySubtext", + IDS_SETTINGS_SEARCH_OK_GOOGLE_AUDIO_HISTORY_SUBTEXT}, + {"searchOkGoogleRetrain", IDS_SETTINGS_SEARCH_OK_GOOGLE_RETRAIN}, + {"searchEnableGoogleNowLabel", IDS_SETTINGS_SEARCH_ENABLE_GOOGLE_NOW}, }; AddLocalizedStringsBulk(html_source, localized_strings, arraysize(localized_strings)); @@ -1701,6 +1708,10 @@ IDS_SETTINGS_SEARCH_EXPLANATION, base::ASCIIToUTF16(chrome::kOmniboxLearnMoreURL)); html_source->AddString("searchExplanation", search_explanation_text); +#if defined(OS_CHROMEOS) + html_source->AddBoolean("enableVoiceInteraction", + chromeos::switches::IsVoiceInteractionEnabled()); +#endif } void AddSearchEnginesStrings(content::WebUIDataSource* html_source) { @@ -1731,6 +1742,21 @@ arraysize(localized_strings)); } +#if defined(OS_CHROMEOS) +void AddGoogleAssistantStrings(content::WebUIDataSource* html_source) { + LocalizedString localized_strings[] = { + {"googleAssistantPageTitle", IDS_SETTINGS_GOOGLE_ASSISTANT}, + {"googleAssistantEnableContext", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_CONTEXT}, + {"googleAssistantEnableContextDescription", + IDS_SETTINGS_GOOGLE_ASSISTANT_ENABLE_CONTEXT_DESCRIPTION}, + {"googleAssistantSettings", IDS_SETTINGS_GOOGLE_ASSISTANT_SETTINGS}, + }; + AddLocalizedStringsBulk(html_source, localized_strings, + arraysize(localized_strings)); +} +#endif + void AddSiteSettingsStrings(content::WebUIDataSource* html_source, Profile* profile) { LocalizedString localized_strings[] = { @@ -2205,6 +2231,9 @@ AddPrivacyStrings(html_source, profile); AddResetStrings(html_source); AddSearchEnginesStrings(html_source); +#if defined(OS_CHROMEOS) + AddGoogleAssistantStrings(html_source); +#endif AddSearchInSettingsStrings(html_source); AddSearchStrings(html_source); AddSiteSettingsStrings(html_source, profile);
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc index 7ee8b992..e3b3377 100644 --- a/chrome/browser/ui/webui/settings/md_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -77,8 +77,10 @@ #include "chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h" #include "chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h" #include "chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.h" +#include "chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h" #include "chrome/browser/ui/webui/settings/chromeos/internet_handler.h" #include "chrome/common/chrome_switches.h" +#include "chromeos/chromeos_switches.h" #include "components/arc/arc_util.h" #else // !defined(OS_CHROMEOS) #include "chrome/browser/ui/webui/settings/settings_default_browser_handler.h" @@ -164,6 +166,10 @@ base::MakeUnique<chromeos::settings::CupsPrintersHandler>(web_ui)); AddSettingsPageUIHandler( base::MakeUnique<chromeos::settings::FingerprintHandler>(profile)); + if (chromeos::switches::IsVoiceInteractionEnabled()) { + AddSettingsPageUIHandler( + base::MakeUnique<chromeos::settings::GoogleAssistantHandler>(profile)); + } AddSettingsPageUIHandler( base::MakeUnique<chromeos::settings::KeyboardHandler>()); AddSettingsPageUIHandler(
diff --git a/chrome/browser/vr/elements/url_bar_texture.cc b/chrome/browser/vr/elements/url_bar_texture.cc index 27750e8e..bbe11d6 100644 --- a/chrome/browser/vr/elements/url_bar_texture.cc +++ b/chrome/browser/vr/elements/url_bar_texture.cc
@@ -97,6 +97,7 @@ if (state_ == state) return; state_ = state; + url_dirty_ = true; set_dirty(); } @@ -166,6 +167,7 @@ } void UrlBarTexture::OnSetMode() { + url_dirty_ = true; set_dirty(); } @@ -311,16 +313,12 @@ if (state_.should_display_url) { float url_x = left_edge; - if (!url_render_text_ || last_drawn_gurl_ != state_.gurl || - last_drawn_security_level_ != state_.security_level || - last_drawn_url_x_position_ != url_x) { + if (!url_render_text_ || url_dirty_) { float url_width = kWidth - url_x - kUrlRightMargin; gfx::Rect text_bounds(ToPixels(url_x), 0, ToPixels(url_width), ToPixels(kHeight)); RenderUrl(texture_size, text_bounds); - last_drawn_gurl_ = state_.gurl; - last_drawn_security_level_ = state_.security_level; - last_drawn_url_x_position_ = url_x; + url_dirty_ = false; } url_render_text_->Draw(&gfx_canvas); rendered_url_text_ = url_render_text_->text(); @@ -332,9 +330,12 @@ const gfx::Rect& bounds) { url::Parsed parsed; + url_formatter::FormatUrlTypes format_types = url_formatter::kFormatUrlOmitAll; + if (state_.offline_page) + format_types |= url_formatter::kFormatUrlExperimentalOmitHTTPS; const base::string16 text = url_formatter::FormatUrl( - state_.gurl, url_formatter::kFormatUrlOmitAll, net::UnescapeRule::NORMAL, - &parsed, nullptr, nullptr); + state_.gurl, format_types, net::UnescapeRule::NORMAL, &parsed, nullptr, + nullptr); int pixel_font_height = texture_size.height() * kFontHeight / kHeight;
diff --git a/chrome/browser/vr/elements/url_bar_texture.h b/chrome/browser/vr/elements/url_bar_texture.h index 379461d3..751b10f 100644 --- a/chrome/browser/vr/elements/url_bar_texture.h +++ b/chrome/browser/vr/elements/url_bar_texture.h
@@ -84,9 +84,7 @@ ToolbarState state_; - GURL last_drawn_gurl_; - security_state::SecurityLevel last_drawn_security_level_; - float last_drawn_url_x_position_ = -1.0f; + bool url_dirty_ = true; bool has_back_button_ = true; bool opaque_background_ = false;
diff --git a/chrome/browser/vr/elements/url_bar_texture_unittest.cc b/chrome/browser/vr/elements/url_bar_texture_unittest.cc index e6d54e9..d41b4ce 100644 --- a/chrome/browser/vr/elements/url_bar_texture_unittest.cc +++ b/chrome/browser/vr/elements/url_bar_texture_unittest.cc
@@ -315,6 +315,7 @@ EXPECT_GT(texture.url_rect().width(), 0); EXPECT_GT(texture.url_rect().height(), 0); EXPECT_TRUE(texture.security_text().empty()); + EXPECT_EQ(texture.url_text(), base::UTF8ToUTF16("https://host.com/page")); gfx::Rect online_url_rect = texture.url_rect(); // Go offline. Security text should be visible and displace the URL. @@ -326,6 +327,7 @@ EXPECT_GT(texture.url_rect().height(), 0); EXPECT_GT(texture.url_rect().x(), online_url_rect.x()); EXPECT_EQ(texture.security_text(), base::UTF8ToUTF16("Offline")); + EXPECT_EQ(texture.url_text(), base::UTF8ToUTF16("host.com/page")); // Go back online. state.offline_page = false; @@ -334,6 +336,7 @@ EXPECT_EQ(texture.security_rect().height(), 0); EXPECT_EQ(texture.url_rect(), online_url_rect); EXPECT_TRUE(texture.security_text().empty()); + EXPECT_EQ(texture.url_text(), base::UTF8ToUTF16("https://host.com/page")); } } // namespace vr
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java index 3422eaa..de3b67e0 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
@@ -205,10 +205,10 @@ public boolean isSatisfied() { if (activity.getCurrentContentViewCore() == null) return false; - updateFailureReason("Expecting scale factor of: " + expectedScale + ", got: " - + activity.getCurrentContentViewCore().getScale()); - return Math.abs(activity.getCurrentContentViewCore().getScale() - expectedScale) - < FLOAT_EPSILON; + float scale = activity.getCurrentContentViewCore().getPageScaleFactor(); + updateFailureReason( + "Expecting scale factor of: " + expectedScale + ", got: " + scale); + return Math.abs(scale - expectedScale) < FLOAT_EPSILON; } }, CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL, CriteriaHelper.DEFAULT_POLLING_INTERVAL); }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java index a7c486b2..b141b29 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java
@@ -113,7 +113,7 @@ return false; } - float scale = mTab.getContentViewCore().getScale(); + float scale = mTab.getContentViewCore().getPageScaleFactor(); if (Math.abs(mExpectedScale - scale) >= FLOAT_EPSILON) { updateFailureReason(String.format( Locale.ENGLISH,
diff --git a/chrome/test/data/android/webvr_instrumentation/html/test_nfc_fires_vrdisplayactivate.html b/chrome/test/data/android/webvr_instrumentation/html/test_nfc_fires_vrdisplayactivate.html index 9a9f21a..d871c22e 100644 --- a/chrome/test/data/android/webvr_instrumentation/html/test_nfc_fires_vrdisplayactivate.html +++ b/chrome/test/data/android/webvr_instrumentation/html/test_nfc_fires_vrdisplayactivate.html
@@ -13,8 +13,10 @@ <script src="../resources/webvr_e2e.js"></script> <script> var t = async_test("NFC scan fires the vrdisplayactivate event"); - window.addEventListener("vrdisplayactivate", () => {t.done();}, false); - // NFC scan triggered after page load + function addListener() { + window.addEventListener("vrdisplayactivate", () => {t.done();}, false); + } + // NFC scan triggered after page loaded and listener added </script> </body> </html>
diff --git a/chrome/test/data/android/webvr_instrumentation/html/test_webvr_autopresent.html b/chrome/test/data/android/webvr_instrumentation/html/test_webvr_autopresent.html new file mode 100644 index 0000000..959c12c --- /dev/null +++ b/chrome/test/data/android/webvr_instrumentation/html/test_webvr_autopresent.html
@@ -0,0 +1,40 @@ +<!doctype html> +<!-- +Tests that an intent from a trusted app allows a page to auto present without +the need for a user gesture. +--> +<html> + <head> + <link rel="stylesheet" type="text/css" href="../resources/webvr_e2e.css"> + </head> + <body> + <canvas id="webgl-canvas"></canvas> + <script src="../../../../../../third_party/WebKit/LayoutTests/resources/testharness.js"></script> + <script src="../resources/webvr_e2e.js"></script> + <script src="../resources/webvr_boilerplate.js"></script> + <script> + var t = async_test("Trusted intents allow auto present"); + + // We need to wait for vrDisplay to be non-null before adding the + // listener, so poll it + function pollVrDisplay() { + if (vrDisplay == null) { + window.setTimeout(pollVrDisplay, 100); + return + } + window.addEventListener("vrdisplayactivate", () => { + vrDisplay.requestPresent([{source: webglCanvas}]).then( () => { + // Do nothing + }, () => { + t.step( () => { + assert_unreached("requestPresent promise rejected"); + }); + }).then( () => { + t.done(); + }); + }, false); + } + window.setTimeout(pollVrDisplay, 100); + </script> + </body> +</html>
diff --git a/chrome/test/data/android/webvr_instrumentation/resources/webvr_boilerplate.js b/chrome/test/data/android/webvr_instrumentation/resources/webvr_boilerplate.js index 87d6f83..f4f4e84d 100644 --- a/chrome/test/data/android/webvr_instrumentation/resources/webvr_boilerplate.js +++ b/chrome/test/data/android/webvr_instrumentation/resources/webvr_boilerplate.js
@@ -87,7 +87,6 @@ gl.enable(gl.CULL_FACE); window.addEventListener("resize", onResize, false); window.addEventListener("vrdisplaypresentchange", onVrPresentChange, false); -window.addEventListener('vrdisplayactivate', onVrRequestPresent, false); window.requestAnimationFrame(onAnimationFrame); webglCanvas.onclick = onVrRequestPresent; onResize();
diff --git a/chrome/utility/media_galleries/media_metadata_parser.cc b/chrome/utility/media_galleries/media_metadata_parser.cc index 00576061..6f5cf0ee 100644 --- a/chrome/utility/media_galleries/media_metadata_parser.cc +++ b/chrome/utility/media_galleries/media_metadata_parser.cc
@@ -52,7 +52,7 @@ if (!extractor.Extract(source, get_attached_images)) return; - if (extractor.duration() >= 0) + if (extractor.has_duration() && extractor.duration() >= 0) metadata->duration.reset(new double(extractor.duration())); if (extractor.height() >= 0 && extractor.width() >= 0) {
diff --git a/chromecast/chromecast.gni b/chromecast/chromecast.gni index 4310f91..0dcf52e 100644 --- a/chromecast/chromecast.gni +++ b/chromecast/chromecast.gni
@@ -77,22 +77,37 @@ # These templates are a temporary fix fo link libc++ into shared libraries and # executables. These should be removed as soon as crbug.com/746091 is resolved. -template("cast_shared_library") { - shared_library(target_name) { - forward_variables_from(invoker, "*") - if (!defined(deps)) { - deps = [] +foreach(target_type, + [ + "executable", + "shared_library", + "loadable_module", + ]) { + template("cast_${target_type}") { + target(target_type, target_name) { + forward_variables_from(invoker, "*") + if (!defined(deps)) { + deps = [] + } + deps += [ "//build/config:exe_and_shlib_deps" ] } - deps += [ "//build/config:exe_and_shlib_deps" ] } } -template("cast_executable") { - executable(target_name) { - forward_variables_from(invoker, "*") - if (!defined(deps)) { - deps = [] - } - deps += [ "//build/config:exe_and_shlib_deps" ] +# Set the defaults for each target. The defaults for these target wrappers +# should match their unwrapped counterparts in BUILDCONFIG.gn. The variables +# referenced below are declared in BUILDCONFIG.gn. +set_defaults("cast_executable") { + configs = default_executable_configs +} + +set_defaults("cast_shared_library") { + configs = default_shared_library_configs +} + +set_defaults("cast_loadable_module") { + configs = default_shared_library_configs + if (is_android) { + configs -= [ "//build/config/android:hide_all_but_jni_onload" ] } }
diff --git a/chromeos/process_proxy/process_proxy.cc b/chromeos/process_proxy/process_proxy.cc index 331ba5f..03b7390e7 100644 --- a/chromeos/process_proxy/process_proxy.cc +++ b/chromeos/process_proxy/process_proxy.cc
@@ -65,6 +65,7 @@ bool ProcessProxy::StartWatchingOutput( const scoped_refptr<base::SingleThreadTaskRunner>& watcher_runner, + const scoped_refptr<base::SequencedTaskRunner>& callback_runner, const OutputCallback& callback) { DCHECK(process_launched_); CHECK(!output_watcher_.get()); @@ -78,7 +79,7 @@ callback_set_ = true; callback_ = callback; - callback_runner_ = base::ThreadTaskRunnerHandle::Get(); + callback_runner_ = callback_runner; watcher_runner_ = watcher_runner; // This object will delete itself once watching is stopped.
diff --git a/chromeos/process_proxy/process_proxy.h b/chromeos/process_proxy/process_proxy.h index 19335be..8e843171 100644 --- a/chromeos/process_proxy/process_proxy.h +++ b/chromeos/process_proxy/process_proxy.h
@@ -45,6 +45,7 @@ bool StartWatchingOutput( const scoped_refptr<base::SingleThreadTaskRunner>& watcher_runner, + const scoped_refptr<base::SequencedTaskRunner>& callback_runner, const OutputCallback& callback); // Sends some data to the process.
diff --git a/chromeos/process_proxy/process_proxy_registry.cc b/chromeos/process_proxy/process_proxy_registry.cc index 7ba2e45..5b9a5b3 100644 --- a/chromeos/process_proxy/process_proxy_registry.cc +++ b/chromeos/process_proxy/process_proxy_registry.cc
@@ -6,6 +6,8 @@ #include "base/bind.h" #include "base/message_loop/message_loop.h" +#include "base/sequenced_task_runner.h" +#include "base/task_scheduler/lazy_task_runner.h" namespace chromeos { @@ -68,9 +70,18 @@ // static ProcessProxyRegistry* ProcessProxyRegistry::Get() { + DCHECK(ProcessProxyRegistry::GetTaskRunner()->RunsTasksInCurrentSequence()); return g_process_proxy_registry.Pointer(); } +// static +scoped_refptr<base::SequencedTaskRunner> ProcessProxyRegistry::GetTaskRunner() { + static base::LazySequencedTaskRunner task_runner = + LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER( + base::TaskTraits({base::MayBlock(), base::TaskPriority::BACKGROUND})); + return task_runner.Get(); +} + int ProcessProxyRegistry::OpenProcess(const std::string& command, const OutputCallback& output_callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -89,7 +100,7 @@ // We can use Unretained because proxy will stop calling callback after it is // closed, which is done before this object goes away. if (!proxy->StartWatchingOutput( - watcher_thread_->task_runner(), + watcher_thread_->task_runner(), GetTaskRunner(), base::Bind(&ProcessProxyRegistry::OnProcessOutput, base::Unretained(this), terminal_id))) { proxy->Close();
diff --git a/chromeos/process_proxy/process_proxy_registry.h b/chromeos/process_proxy/process_proxy_registry.h index 16ca7b5..5bb34dbf 100644 --- a/chromeos/process_proxy/process_proxy_registry.h +++ b/chromeos/process_proxy/process_proxy_registry.h
@@ -41,6 +41,10 @@ static ProcessProxyRegistry* Get(); + // Returns a SequencedTaskRunner where the singleton instance of + // ProcessProxyRegistry lives. + static scoped_refptr<base::SequencedTaskRunner> GetTaskRunner(); + // Starts new ProcessProxy (which starts new process). // Returns ID used for the created process. Returns -1 on failure. int OpenProcess(const std::string& command, const OutputCallback& callback);
diff --git a/chromeos/process_proxy/process_proxy_unittest.cc b/chromeos/process_proxy/process_proxy_unittest.cc index 45cae00..194d810 100644 --- a/chromeos/process_proxy/process_proxy_unittest.cc +++ b/chromeos/process_proxy/process_proxy_unittest.cc
@@ -8,13 +8,17 @@ #include <memory> #include <string> +#include "base/at_exit.h" #include "base/bind.h" +#include "base/callback_forward.h" #include "base/location.h" #include "base/message_loop/message_loop.h" #include "base/process/kill.h" #include "base/process/process.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/test/scoped_task_environment.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "chromeos/process_proxy/process_proxy_registry.h" @@ -31,8 +35,15 @@ const char kStdoutType[] = "stdout"; const int kTestLineNum = 100; +void RunOnTaskRunner( + base::OnceClosure closure, + const scoped_refptr<base::SequencedTaskRunner>& task_runner) { + task_runner->PostTask(FROM_HERE, std::move(closure)); +} + class TestRunner { public: + TestRunner() {} virtual ~TestRunner() {} virtual void SetupExpectations(int terminal_id) = 0; virtual void OnSomeRead(int terminal_id, @@ -40,8 +51,14 @@ const std::string& output) = 0; virtual void StartRegistryTest(ProcessProxyRegistry* registry) = 0; + void set_done_read_closure(base::OnceClosure done_closure) { + done_read_closure_ = std::move(done_closure); + } + protected: int terminal_id_; + + base::OnceClosure done_read_closure_; }; class RegistryTestRunner : public TestRunner { @@ -82,8 +99,8 @@ } if (!valid || TestSucceeded()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); + ASSERT_FALSE(done_read_closure_.is_null()); + std::move(done_read_closure_).Run(); } } @@ -145,8 +162,8 @@ return; } EXPECT_EQ("exit", type); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); + ASSERT_FALSE(done_read_closure_.is_null()); + std::move(done_read_closure_).Run(); } void StartRegistryTest(ProcessProxyRegistry* registry) override { @@ -165,7 +182,7 @@ ~ProcessProxyTest() override {} protected: - void InitRegistryTest() { + void InitRegistryTest(base::OnceClosure done_closure) { registry_ = ProcessProxyRegistry::Get(); terminal_id_ = registry_->OpenProcess( @@ -173,6 +190,7 @@ base::Bind(&ProcessProxyTest::HandleRead, base::Unretained(this))); EXPECT_GE(terminal_id_, 0); + test_runner_->set_done_read_closure(std::move(done_closure)); test_runner_->SetupExpectations(terminal_id_); test_runner_->StartRegistryTest(registry_); } @@ -184,7 +202,7 @@ registry_->AckOutput(terminal_id); } - void EndRegistryTest() { + void EndRegistryTest(base::OnceClosure done_closure) { registry_->CloseProcess(terminal_id_); base::TerminationStatus status = @@ -198,34 +216,42 @@ registry_->ShutDown(); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); + std::move(done_closure).Run(); } void RunTest() { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&ProcessProxyTest::InitRegistryTest, - base::Unretained(this))); - + base::RunLoop init_registry_waiter; + ProcessProxyRegistry::GetTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce( + &ProcessProxyTest::InitRegistryTest, base::Unretained(this), + base::BindOnce(&RunOnTaskRunner, init_registry_waiter.QuitClosure(), + base::SequencedTaskRunnerHandle::Get()))); // Wait until all data from output watcher is received (QuitTask will be // fired on watcher thread). - base::RunLoop().Run(); + init_registry_waiter.Run(); - base::ThreadTaskRunnerHandle::Get()->PostTask( + base::RunLoop end_registry_waiter; + ProcessProxyRegistry::GetTaskRunner()->PostTask( FROM_HERE, - base::Bind(&ProcessProxyTest::EndRegistryTest, base::Unretained(this))); - + base::BindOnce( + &ProcessProxyTest::EndRegistryTest, base::Unretained(this), + base::BindOnce(&RunOnTaskRunner, end_registry_waiter.QuitClosure(), + base::SequencedTaskRunnerHandle::Get()))); // Wait until we clean up the process proxy. - base::RunLoop().Run(); + end_registry_waiter.Run(); } std::unique_ptr<TestRunner> test_runner_; private: + // Destroys ProcessProxyRegistry LazyInstance after each test. + base::ShadowingAtExitManager shadowing_at_exit_manager_; + ProcessProxyRegistry* registry_; int terminal_id_; - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment scoped_task_environment_; }; // Test will open new process that will run cat command, and verify data we
diff --git a/cloud_print/BUILD.gn b/cloud_print/BUILD.gn index 0ec5a6b..0c554c8 100644 --- a/cloud_print/BUILD.gn +++ b/cloud_print/BUILD.gn
@@ -15,7 +15,7 @@ # 64-bit systems. if (target_cpu == "x86" && current_cpu == "x86") { if (is_clang) { - win64 = "//build/toolchain/win:clang_x64" + win64 = "//build/toolchain/win:win_clang_x64" } else { win64 = "//build/toolchain/win:x64" }
diff --git a/cloud_print/virtual_driver/win/port_monitor/BUILD.gn b/cloud_print/virtual_driver/win/port_monitor/BUILD.gn index 27bf50d6..f63c3f8 100644 --- a/cloud_print/virtual_driver/win/port_monitor/BUILD.gn +++ b/cloud_print/virtual_driver/win/port_monitor/BUILD.gn
@@ -62,7 +62,7 @@ # directory. copy("copy_gcp_portmon_dll") { if (is_clang) { - gcp_portmon64_toolchain = "//build/toolchain/win:clang_x64" + gcp_portmon64_toolchain = "//build/toolchain/win:win_clang_x64" } else { gcp_portmon64_toolchain = "//build/toolchain/win:x64" }
diff --git a/components/nacl/broker/BUILD.gn b/components/nacl/broker/BUILD.gn index bf0bf3a4..44db949 100644 --- a/components/nacl/broker/BUILD.gn +++ b/components/nacl/broker/BUILD.gn
@@ -62,7 +62,7 @@ # NOTE: This must match what //build/config/BUILDCONFIG.gn uses # as default toolchain for the corresponding x64 build. if (is_clang) { - x64_toolchain = "//build/toolchain/win:clang_nacl_win64" + x64_toolchain = "//build/toolchain/win:win_clang_nacl_win64" } else { x64_toolchain = "//build/toolchain/win:nacl_win64" }
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc index 2c34461e..ccf09e2e 100644 --- a/components/network_session_configurator/browser/network_session_configurator.cc +++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -180,18 +180,6 @@ return 0; } -int GetQuicPacketReaderYieldAfterDurationMilliseconds( - const VariationParameters& quic_trial_params) { - int value; - if (base::StringToInt( - GetVariationParam(quic_trial_params, - "packet_reader_yield_after_duration_milliseconds"), - &value)) { - return value; - } - return 0; -} - bool ShouldQuicRaceCertVerification( const VariationParameters& quic_trial_params) { return base::LowerCaseEqualsASCII( @@ -282,12 +270,6 @@ reduced_ping_timeout_seconds < net::kPingTimeoutSecs) { params->quic_reduced_ping_timeout_seconds = reduced_ping_timeout_seconds; } - int packet_reader_yield_after_duration_milliseconds = - GetQuicPacketReaderYieldAfterDurationMilliseconds(quic_trial_params); - if (packet_reader_yield_after_duration_milliseconds != 0) { - params->quic_packet_reader_yield_after_duration_milliseconds = - packet_reader_yield_after_duration_milliseconds; - } params->quic_race_cert_verification = ShouldQuicRaceCertVerification(quic_trial_params); params->quic_estimate_initial_rtt =
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc index b04421d..8fbc23e 100644 --- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc +++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -87,8 +87,6 @@ EXPECT_EQ(net::kIdleConnectionTimeoutSeconds, params_.quic_idle_connection_timeout_seconds); EXPECT_EQ(net::kPingTimeoutSecs, params_.quic_reduced_ping_timeout_seconds); - EXPECT_EQ(net::kQuicYieldAfterDurationMilliseconds, - params_.quic_packet_reader_yield_after_duration_milliseconds); EXPECT_FALSE(params_.quic_race_cert_verification); EXPECT_FALSE(params_.quic_estimate_initial_rtt); EXPECT_FALSE(params_.quic_migrate_sessions_on_network_change); @@ -199,18 +197,6 @@ EXPECT_EQ(10, params_.quic_reduced_ping_timeout_seconds); } -TEST_F(NetworkSessionConfiguratorTest, - QuicPacketReaderYieldAfterDurationMillisecondsFieldTrialParams) { - std::map<std::string, std::string> field_trial_params; - field_trial_params["packet_reader_yield_after_duration_milliseconds"] = "10"; - variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params); - base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled"); - - ParseFieldTrials(); - - EXPECT_EQ(10, params_.quic_packet_reader_yield_after_duration_milliseconds); -} - TEST_F(NetworkSessionConfiguratorTest, QuicRaceCertVerification) { std::map<std::string, std::string> field_trial_params; field_trial_params["race_cert_verification"] = "true";
diff --git a/components/payments/core/payment_instrument.h b/components/payments/core/payment_instrument.h index 24b1d14..82d5af72 100644 --- a/components/payments/core/payment_instrument.h +++ b/components/payments/core/payment_instrument.h
@@ -19,7 +19,7 @@ class PaymentInstrument { public: // The type of this instrument instance. - enum class Type { AUTOFILL }; + enum class Type { AUTOFILL, NATIVE_MOBILE_APP }; class Delegate { public:
diff --git a/components/pdf/browser/pdf_web_contents_helper.cc b/components/pdf/browser/pdf_web_contents_helper.cc index 25066d2..761d8d21 100644 --- a/components/pdf/browser/pdf_web_contents_helper.cc +++ b/components/pdf/browser/pdf_web_contents_helper.cc
@@ -36,7 +36,8 @@ pdf_service_bindings_(web_contents, this), client_(std::move(client)), touch_selection_controller_client_manager_(nullptr), - has_selection_(false) {} + has_selection_(false), + remote_pdf_client_(nullptr) {} PDFWebContentsHelper::~PDFWebContentsHelper() { if (!touch_selection_controller_client_manager_) @@ -46,9 +47,13 @@ touch_selection_controller_client_manager_->RemoveObserver(this); } -void PDFWebContentsHelper::SelectionChanged(const gfx::Point& left, +void PDFWebContentsHelper::SetListener(mojom::PdfListenerPtr listener) { + remote_pdf_client_ = std::move(listener); +} + +void PDFWebContentsHelper::SelectionChanged(const gfx::PointF& left, int32_t left_height, - const gfx::Point& right, + const gfx::PointF& right, int32_t right_height) { if (!touch_selection_controller_client_manager_) InitTouchSelectionClientManager(); @@ -56,11 +61,11 @@ if (touch_selection_controller_client_manager_) { gfx::SelectionBound start; gfx::SelectionBound end; - start.SetEdgeTop(gfx::PointF(left.x(), left.y())); + start.SetEdgeTop(left); start.SetEdgeBottom(gfx::PointF(left.x(), left.y() + left_height)); start.set_type(gfx::SelectionBound::LEFT); start.set_visible(true); - end.SetEdgeTop(gfx::PointF(right.x(), right.y())); + end.SetEdgeTop(right); end.SetEdgeBottom(gfx::PointF(right.x(), right.y() + right_height)); end.set_type(gfx::SelectionBound::RIGHT); end.set_visible(true); @@ -77,16 +82,22 @@ } void PDFWebContentsHelper::MoveCaret(const gfx::PointF& position) { - // TODO(wjmaclean, dsinclair): Implement connection to PDFium to implement. + if (!remote_pdf_client_) + return; + remote_pdf_client_->SetCaretPosition(position); } void PDFWebContentsHelper::MoveRangeSelectionExtent(const gfx::PointF& extent) { - // TODO(wjmaclean, dsinclair): Implement connection to PDFium to implement. + if (!remote_pdf_client_) + return; + remote_pdf_client_->MoveRangeSelectionExtent(extent); } void PDFWebContentsHelper::SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) { - // TODO(wjmaclean, dsinclair): Implement connection to PDFium to implement. + if (!remote_pdf_client_) + return; + remote_pdf_client_->SetSelectionBounds(base, extent); } void PDFWebContentsHelper::OnSelectionEvent(ui::SelectionEventType event) {} @@ -112,16 +123,20 @@ switch (command_id) { case IDS_APP_COPY: return readable && has_selection_; - // TODO(wjmaclean): add logic for copy/paste as the information required + // TODO(wjmaclean): add logic for cut/paste as the information required // from PDFium becomes available. } return false; } void PDFWebContentsHelper::ExecuteCommand(int command_id, int event_flags) { - // TODO(wjmaclean, dsinclair): Need to communicate to PDFium to get it to copy - // the selection onto the clipboard (and eventually accept cut/paste commands - // too). + // TODO(wjmaclean, dsinclair): Need to communicate to PDFium to accept + // cut/paste commands. + switch (command_id) { + case IDS_APP_COPY: + web_contents()->Copy(); + break; + } } void PDFWebContentsHelper::RunContextMenu() {
diff --git a/components/pdf/browser/pdf_web_contents_helper.h b/components/pdf/browser/pdf_web_contents_helper.h index e91790f3..2937f0ca 100644 --- a/components/pdf/browser/pdf_web_contents_helper.h +++ b/components/pdf/browser/pdf_web_contents_helper.h
@@ -42,11 +42,6 @@ content::WebContents* contents, std::unique_ptr<PDFWebContentsHelperClient> client); - void SelectionChanged(const gfx::Point& left, - int32_t left_height, - const gfx::Point& right, - int32_t right_height); - // ui::TouchSelectionControllerClient : bool SupportsAnimation() const override; void SetNeedsAnimate() override {} @@ -73,15 +68,21 @@ void InitTouchSelectionClientManager(); // mojom::PdfService: + void SetListener(mojom::PdfListenerPtr listener) override; void HasUnsupportedFeature() override; void SaveUrlAs(const GURL& url, const content::Referrer& referrer) override; void UpdateContentRestrictions(int32_t content_restrictions) override; + void SelectionChanged(const gfx::PointF& left, + int32_t left_height, + const gfx::PointF& right, + int32_t right_height) override; content::WebContentsFrameBindingSet<mojom::PdfService> pdf_service_bindings_; std::unique_ptr<PDFWebContentsHelperClient> client_; content::TouchSelectionControllerClientManager* touch_selection_controller_client_manager_; bool has_selection_; + mojom::PdfListenerPtr remote_pdf_client_; DISALLOW_COPY_AND_ASSIGN(PDFWebContentsHelper); };
diff --git a/components/pdf/common/BUILD.gn b/components/pdf/common/BUILD.gn index c0aa0b3..370b7a9 100644 --- a/components/pdf/common/BUILD.gn +++ b/components/pdf/common/BUILD.gn
@@ -20,4 +20,6 @@ overridden_deps_blink = [ "//third_party/WebKit/public:mojo_bindings" ] component_deps_blink = [ "//third_party/WebKit/Source/platform" ] + + cpp_only = true }
diff --git a/components/pdf/common/pdf.mojom b/components/pdf/common/pdf.mojom index 0aaed7ba..f6e44274 100644 --- a/components/pdf/common/pdf.mojom +++ b/components/pdf/common/pdf.mojom
@@ -5,9 +5,24 @@ module pdf.mojom; import "third_party/WebKit/public/platform/referrer.mojom"; +import "ui/gfx/geometry/mojo/geometry.mojom"; import "url/mojo/url.mojom"; +interface PdfListener { + // Sets the current caret position. + SetCaretPosition(gfx.mojom.PointF position); + + // Move the end of the range selection to |extent|. + MoveRangeSelectionExtent(gfx.mojom.PointF extent); + + // Sets the selection to be between |base| and |extent|. The |extent| will + // be moved if the selection is modified. + SetSelectionBounds(gfx.mojom.PointF base, gfx.mojom.PointF extent); +}; + interface PdfService { + SetListener(PdfListener client); + // Updates the content restrictions, i.e. to disable print/copy. UpdateContentRestrictions(int32 restrictions); @@ -16,4 +31,9 @@ // Brings up SaveAs... dialog to save specified URL. SaveUrlAs(url.mojom.Url url, blink.mojom.Referrer referrer); + + // Notifies the embedder of the top-left and bottom-right coordinates of the + // current selection. + SelectionChanged(gfx.mojom.PointF left, int32 left_height, + gfx.mojom.PointF right, int32 right_height); };
diff --git a/components/pdf/renderer/DEPS b/components/pdf/renderer/DEPS index 7113287..9401253 100644 --- a/components/pdf/renderer/DEPS +++ b/components/pdf/renderer/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+components/strings/grit/components_strings.h", "+gin", + "+mojo/public/cpp/bindings", "+skia/ext", "+ui/accessibility", "+ui/gfx",
diff --git a/components/pdf/renderer/pepper_pdf_host.cc b/components/pdf/renderer/pepper_pdf_host.cc index 158c3b6..ee9b3f5 100644 --- a/components/pdf/renderer/pepper_pdf_host.cc +++ b/components/pdf/renderer/pepper_pdf_host.cc
@@ -43,7 +43,16 @@ PP_Instance instance, PP_Resource resource) : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource), - host_(host) {} + host_(host), + binding_(this) { + mojom::PdfService* service = GetRemotePdfService(); + if (!service) + return; + + mojom::PdfListenerPtr listener; + binding_.Bind(mojo::MakeRequest(&listener)); + service->SetListener(std::move(listener)); +} PepperPDFHost::~PepperPDFHost() {} @@ -91,6 +100,8 @@ PPAPI_DISPATCH_HOST_RESOURCE_CALL( PpapiHostMsg_PDF_SetAccessibilityPageInfo, OnHostMsgSetAccessibilityPageInfo) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SelectionChanged, + OnHostMsgSelectionChanged) PPAPI_END_MESSAGE_MAP() return PP_ERROR_FAILED; } @@ -226,6 +237,21 @@ return PP_OK; } +int32_t PepperPDFHost::OnHostMsgSelectionChanged( + ppapi::host::HostMessageContext* context, + const PP_FloatPoint& left, + int32_t left_height, + const PP_FloatPoint& right, + int32_t right_height) { + mojom::PdfService* service = GetRemotePdfService(); + if (!service) + return PP_ERROR_FAILED; + + service->SelectionChanged(gfx::PointF(left.x, left.y), left_height, + gfx::PointF(right.x, right.y), right_height); + return PP_OK; +} + void PepperPDFHost::CreatePdfAccessibilityTreeIfNeeded() { if (!pdf_accessibility_tree_) { pdf_accessibility_tree_ = @@ -251,4 +277,26 @@ return remote_pdf_service_.get(); } +void PepperPDFHost::SetCaretPosition(const gfx::PointF& position) { + content::PepperPluginInstance* instance = + host_->GetPluginInstance(pp_instance()); + if (instance) + instance->SetCaretPosition(position); +} + +void PepperPDFHost::MoveRangeSelectionExtent(const gfx::PointF& extent) { + content::PepperPluginInstance* instance = + host_->GetPluginInstance(pp_instance()); + if (instance) + instance->MoveRangeSelectionExtent(extent); +} + +void PepperPDFHost::SetSelectionBounds(const gfx::PointF& base, + const gfx::PointF& extent) { + content::PepperPluginInstance* instance = + host_->GetPluginInstance(pp_instance()); + if (instance) + instance->SetSelectionBounds(base, extent); +} + } // namespace pdf
diff --git a/components/pdf/renderer/pepper_pdf_host.h b/components/pdf/renderer/pepper_pdf_host.h index b5de8c27..7943b60 100644 --- a/components/pdf/renderer/pepper_pdf_host.h +++ b/components/pdf/renderer/pepper_pdf_host.h
@@ -16,6 +16,7 @@ #include "base/strings/string16.h" #include "components/pdf/common/pdf.mojom.h" #include "ipc/ipc_platform_file.h" +#include "mojo/public/cpp/bindings/binding.h" #include "ppapi/c/ppb_image_data.h" #include "ppapi/c/private/ppb_pdf.h" #include "ppapi/host/resource_host.h" @@ -36,7 +37,8 @@ class PdfAccessibilityTree; -class PepperPDFHost : public ppapi::host::ResourceHost { +class PepperPDFHost : public ppapi::host::ResourceHost, + public mojom::PdfListener { public: class PrintClient { public: @@ -71,6 +73,12 @@ const IPC::Message& msg, ppapi::host::HostMessageContext* context) override; + // mojom::PdfListener + void SetCaretPosition(const gfx::PointF& position) override; + void MoveRangeSelectionExtent(const gfx::PointF& extent) override; + void SetSelectionBounds(const gfx::PointF& base, + const gfx::PointF& extent) override; + private: int32_t OnHostMsgDidStartLoading(ppapi::host::HostMessageContext* context); int32_t OnHostMsgDidStopLoading(ppapi::host::HostMessageContext* context); @@ -99,6 +107,11 @@ const PP_PrivateAccessibilityPageInfo& page_info, const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs, const std::vector<PP_PrivateAccessibilityCharInfo>& chars); + int32_t OnHostMsgSelectionChanged(ppapi::host::HostMessageContext* context, + const PP_FloatPoint& left, + int32_t left_height, + const PP_FloatPoint& right, + int32_t right_height); void CreatePdfAccessibilityTreeIfNeeded(); @@ -109,6 +122,7 @@ std::unique_ptr<PdfAccessibilityTree> pdf_accessibility_tree_; content::RendererPpapiHost* const host_; mojom::PdfServiceAssociatedPtr remote_pdf_service_; + mojo::Binding<mojom::PdfListener> binding_; DISALLOW_COPY_AND_ASSIGN(PepperPDFHost); };
diff --git a/components/prefs/in_memory_pref_store_unittest.cc b/components/prefs/in_memory_pref_store_unittest.cc index 14da3ef..46f98625 100644 --- a/components/prefs/in_memory_pref_store_unittest.cc +++ b/components/prefs/in_memory_pref_store_unittest.cc
@@ -106,7 +106,7 @@ } TEST_F(InMemoryPrefStoreTest, CommitPendingWriteWithCallback) { - TestCommitPendingWriteWithCallback(store_.get()); + TestCommitPendingWriteWithCallback(store_.get(), &scoped_task_environment_); } } // namespace
diff --git a/components/prefs/json_pref_store_unittest.cc b/components/prefs/json_pref_store_unittest.cc index 54f87844..e9f2c9f 100644 --- a/components/prefs/json_pref_store_unittest.cc +++ b/components/prefs/json_pref_store_unittest.cc
@@ -143,14 +143,17 @@ pref_store->CommitPendingWrite(OnceClosure()); scoped_task_environment->RunUntilIdle(); } else { - TestCommitPendingWriteWithCallback(pref_store); + TestCommitPendingWriteWithCallback(pref_store, scoped_task_environment); } } class JsonPrefStoreTest : public testing::TestWithParam<CommitPendingWriteMode> { public: - JsonPrefStoreTest() = default; + JsonPrefStoreTest() + : scoped_task_environment_( + base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT, + base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {} protected: void SetUp() override { @@ -947,13 +950,7 @@ DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreCallbackTest); }; -// Flaky on Linux TSAN. http://crbug.com/732445. -#if defined(OS_LINUX) && defined(THREAD_SANITIZER) -#define MAYBE_TestSerializeDataCallbacks DISABLED_TestSerializeDataCallbacks -#else -#define MAYBE_TestSerializeDataCallbacks TestSerializeDataCallbacks -#endif -TEST_F(JsonPrefStoreCallbackTest, MAYBE_TestSerializeDataCallbacks) { +TEST_F(JsonPrefStoreCallbackTest, TestSerializeDataCallbacks) { base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json"); ASSERT_LT(0, base::WriteFile(input_file, kReadJson, arraysize(kReadJson) - 1));
diff --git a/components/prefs/overlay_user_pref_store_unittest.cc b/components/prefs/overlay_user_pref_store_unittest.cc index 802dc76..7d754e5 100644 --- a/components/prefs/overlay_user_pref_store_unittest.cc +++ b/components/prefs/overlay_user_pref_store_unittest.cc
@@ -275,7 +275,7 @@ } TEST_F(OverlayUserPrefStoreTest, CommitPendingWriteWithCallback) { - TestCommitPendingWriteWithCallback(overlay_.get()); + TestCommitPendingWriteWithCallback(overlay_.get(), &scoped_task_environment_); } } // namespace base
diff --git a/components/prefs/persistent_pref_store_unittest.cc b/components/prefs/persistent_pref_store_unittest.cc index e2a65416..d297858 100644 --- a/components/prefs/persistent_pref_store_unittest.cc +++ b/components/prefs/persistent_pref_store_unittest.cc
@@ -7,9 +7,12 @@ #include "base/bind.h" #include "base/run_loop.h" #include "base/sequence_checker_impl.h" +#include "base/test/scoped_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" -void TestCommitPendingWriteWithCallback(PersistentPrefStore* store) { +void TestCommitPendingWriteWithCallback( + PersistentPrefStore* store, + base::test::ScopedTaskEnvironment* scoped_task_environment) { base::RunLoop run_loop; base::SequenceCheckerImpl sequence_checker; store->CommitPendingWrite(base::BindOnce( @@ -18,5 +21,6 @@ run_loop->Quit(); }, base::Unretained(&sequence_checker), base::Unretained(&run_loop))); + scoped_task_environment->RunUntilIdle(); run_loop.Run(); }
diff --git a/components/prefs/persistent_pref_store_unittest.h b/components/prefs/persistent_pref_store_unittest.h index 99442336..ea658e1c 100644 --- a/components/prefs/persistent_pref_store_unittest.h +++ b/components/prefs/persistent_pref_store_unittest.h
@@ -5,11 +5,20 @@ #ifndef COMPONENTS_PREFS_PERSISTENT_PREF_STORE_UNITTEST_H_ #define COMPONENTS_PREFS_PERSISTENT_PREF_STORE_UNITTEST_H_ +namespace base { +namespace test { +class ScopedTaskEnvironment; +} +} // namespace base + class PersistentPrefStore; // Calls CommitPendingWrite() on |store| with a callback. Verifies that the -// callback runs on the appropriate sequence. This function is meant to be -// reused in the tests of various PersistentPrefStore implementations. -void TestCommitPendingWriteWithCallback(PersistentPrefStore* store); +// callback runs on the appropriate sequence. |scoped_task_environment| is the +// test's ScopedTaskEnvironment. This function is meant to be reused in the +// tests of various PersistentPrefStore implementations. +void TestCommitPendingWriteWithCallback( + PersistentPrefStore* store, + base::test::ScopedTaskEnvironment* scoped_task_environment); #endif // COMPONENTS_PREFS_PERSISTENT_PREF_STORE_UNITTEST_H_
diff --git a/components/sync/user_events/user_event_sync_bridge.cc b/components/sync/user_events/user_event_sync_bridge.cc index 892bd20..373733c 100644 --- a/components/sync/user_events/user_event_sync_bridge.cc +++ b/components/sync/user_events/user_event_sync_bridge.cc
@@ -6,6 +6,7 @@ #include <set> #include <utility> +#include <vector> #include "base/big_endian.h" #include "base/bind.h" @@ -272,13 +273,21 @@ void UserEventSyncBridge::HandleGlobalIdChange(int64_t old_global_id, int64_t new_global_id) { DCHECK_NE(old_global_id, new_global_id); - auto iter = in_flight_nav_linked_events_.find(old_global_id); - while (iter != in_flight_nav_linked_events_.end()) { - auto specifics = base::MakeUnique<UserEventSpecifics>(iter->second); - DCHECK_EQ(old_global_id, specifics->navigation_id()); + // Store specifics in a temp vector while erasing, as |RecordUserEvent()| will + // insert new values into |in_flight_nav_linked_events_|. While insert should + // not invalidate a std::multimap's iterator, and the updated global_id should + // not be within our given range, this approach seems less error prone. + std::vector<std::unique_ptr<UserEventSpecifics>> affected; + + auto range = in_flight_nav_linked_events_.equal_range(old_global_id); + for (auto iter = range.first; iter != range.second;) { + DCHECK_EQ(old_global_id, iter->second.navigation_id()); + affected.emplace_back(base::MakeUnique<UserEventSpecifics>(iter->second)); iter = in_flight_nav_linked_events_.erase(iter); + } + for (std::unique_ptr<UserEventSpecifics>& specifics : affected) { specifics->set_navigation_id(new_global_id); RecordUserEvent(std::move(specifics)); }
diff --git a/components/sync/user_events/user_event_sync_bridge_unittest.cc b/components/sync/user_events/user_event_sync_bridge_unittest.cc index 97f316e5..56a33ee 100644 --- a/components/sync/user_events/user_event_sync_bridge_unittest.cc +++ b/components/sync/user_events/user_event_sync_bridge_unittest.cc
@@ -107,6 +107,12 @@ &test_global_id_mapper_); } + std::string GetStorageKey(const UserEventSpecifics& specifics) { + EntityData entity_data; + *entity_data.specifics.mutable_user_event() = specifics; + return bridge()->GetStorageKey(entity_data); + } + UserEventSyncBridge* bridge() { return bridge_.get(); } const RecordingModelTypeChangeProcessor& processor() { return *processor_; } TestGlobalIdMapper* mapper() { return &test_global_id_mapper_; } @@ -200,6 +206,38 @@ bridge()->GetAllData(base::Bind(&VerifyDataBatchCount, 0)); } +TEST_F(UserEventSyncBridgeTest, MulipleEventsChanging) { + int64_t first_id = 11; + int64_t second_id = 12; + int64_t third_id = 13; + int64_t fourth_id = 14; + const UserEventSpecifics specifics1 = CreateSpecifics(1u, first_id, 2u); + const UserEventSpecifics specifics2 = CreateSpecifics(1u, first_id, 2u); + const UserEventSpecifics specifics3 = CreateSpecifics(1u, first_id, 2u); + const std::string key1 = GetStorageKey(specifics1); + const std::string key2 = GetStorageKey(specifics2); + const std::string key3 = GetStorageKey(specifics3); + + bridge()->RecordUserEvent(base::MakeUnique<UserEventSpecifics>(specifics1)); + bridge()->RecordUserEvent(base::MakeUnique<UserEventSpecifics>(specifics2)); + bridge()->RecordUserEvent(base::MakeUnique<UserEventSpecifics>(specifics3)); + bridge()->GetAllData(VerifyCallback( + {{key1, specifics1}, {key2, specifics2}, {key3, specifics3}})); + + mapper()->ChangeId(second_id, fourth_id); + bridge()->GetAllData( + VerifyCallback({{key1, specifics1}, + {key2, CreateSpecifics(3u, fourth_id, 4u)}, + {key3, specifics3}})); + + mapper()->ChangeId(first_id, fourth_id); + mapper()->ChangeId(third_id, fourth_id); + bridge()->GetAllData( + VerifyCallback({{key1, CreateSpecifics(1u, fourth_id, 2u)}, + {key2, CreateSpecifics(3u, fourth_id, 4u)}, + {key3, CreateSpecifics(5u, fourth_id, 6u)}})); +} + } // namespace } // namespace syncer
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc index 09a14cc..1c2eb3a 100644 --- a/components/viz/service/display/surface_aggregator.cc +++ b/components/viz/service/display/surface_aggregator.cc
@@ -647,6 +647,7 @@ }; std::vector<SurfaceInfo> child_surfaces; + gfx::Rect pixel_moving_background_filters_rect; // This data is created once and typically small or empty. Collect all items // and pass to a flat_vector to sort once. std::vector<cc::RenderPassId> pixel_moving_background_filter_passes_data; @@ -654,6 +655,12 @@ if (render_pass->background_filters.HasFilterThatMovesPixels()) { pixel_moving_background_filter_passes_data.push_back( RemapPassId(render_pass->id, surface_id)); + // TODO(wutao): Partial swap does not work with pixel moving background + // filter. See https://crbug.com/737255. Current solution is to mark the + // whole output rect as damaged. + pixel_moving_background_filters_rect.Union( + cc::MathUtil::MapEnclosingClippedRect( + render_pass->transform_to_root_target, render_pass->output_rect)); } } base::flat_set<cc::RenderPassId> pixel_moving_background_filter_passes( @@ -776,6 +783,8 @@ referenced_surfaces_.erase(it); if (!damage_rect.IsEmpty() && frame.metadata.may_contain_video) result->may_contain_video = true; + + damage_rect.Union(pixel_moving_background_filters_rect); return damage_rect; }
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc index 81a9445..dcf955e 100644 --- a/components/viz/service/display/surface_aggregator_unittest.cc +++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -2026,9 +2026,59 @@ EXPECT_EQ(0u, aggregated_pass_list[3]->quad_list.size()); } - // Root surface has smaller damage rect. Background filter on render pass - // means Surface - // quad under it should be aggregated. + // Root surface has smaller damage rect. Opacity filter on render pass + // means Surface quad under it should be aggregated. + { + int root_pass_ids[] = {1, 2}; + Quad root_quads1[] = { + Quad::SolidColorQuad(1), + }; + Quad root_quads2[] = { + Quad::RenderPassQuad(root_pass_ids[0]), + Quad::SurfaceQuad(child_surface_id, InvalidSurfaceId(), 1.f)}; + Pass root_passes[] = { + Pass(root_quads1, arraysize(root_quads1), root_pass_ids[0]), + Pass(root_quads2, arraysize(root_quads2), root_pass_ids[1])}; + + cc::RenderPassList root_pass_list; + AddPasses(&root_pass_list, gfx::Rect(SurfaceSize()), root_passes, + arraysize(root_passes)); + + auto* pass = root_pass_list[0].get(); + auto* root_pass = root_pass_list[1].get(); + root_pass->shared_quad_state_list.ElementAt(1) + ->quad_to_target_transform.Translate(10, 10); + pass->background_filters.Append( + cc::FilterOperation::CreateOpacityFilter(0.5f)); + root_pass->damage_rect = gfx::Rect(10, 10, 2, 2); + SubmitPassListAsFrame(support_.get(), root_local_surface_id_, + &root_pass_list); + } + + { + cc::CompositorFrame aggregated_frame = + aggregator_.Aggregate(root_surface_id); + const auto& aggregated_pass_list = aggregated_frame.render_pass_list; + + ASSERT_EQ(3u, aggregated_pass_list.size()); + + // Pass 0 is solid color quad from root, but outside damage rect. + EXPECT_EQ(gfx::Rect(10, 10, 2, 2), aggregated_pass_list[0]->damage_rect); + EXPECT_EQ(0u, aggregated_pass_list[0]->quad_list.size()); + EXPECT_EQ(gfx::Rect(0, 0, 2, 2), aggregated_pass_list[1]->damage_rect); + EXPECT_EQ(0u, aggregated_pass_list[1]->quad_list.size()); + + // First render pass draw quad is outside damage rect, so shouldn't be + // drawn. SurfaceDrawQuad is after opacity filter, so corresponding + // cc::RenderPassDrawQuad should be drawn. + EXPECT_EQ(gfx::Rect(10, 10, 2, 2), aggregated_pass_list[2]->damage_rect); + EXPECT_EQ(1u, aggregated_pass_list[2]->quad_list.size()); + } + + // TODO(wutao): Partial swap does not work with pixel moving background + // filter. See https://crbug.com/737255. + // Has background filter on render pass will make the whole output rect as + // damaged. { int root_pass_ids[] = {1, 2}; Quad root_quads1[] = { @@ -2063,17 +2113,17 @@ ASSERT_EQ(3u, aggregated_pass_list.size()); - // Pass 0 is solid color quad from root, but outside damage rect. - EXPECT_EQ(gfx::Rect(10, 10, 2, 2), aggregated_pass_list[0]->damage_rect); - EXPECT_EQ(0u, aggregated_pass_list[0]->quad_list.size()); + // Pass 0 has background blur filter, so should be drawn. + EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list[0]->damage_rect); + EXPECT_EQ(1u, aggregated_pass_list[0]->quad_list.size()); EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list[1]->damage_rect); EXPECT_EQ(1u, aggregated_pass_list[1]->quad_list.size()); - // First render pass draw quad is outside damage rect, so shouldn't be - // drawn. SurfaceDrawQuad is after background filter, so corresponding - // cc::RenderPassDrawQuad should be drawn. - EXPECT_EQ(gfx::Rect(10, 10, 2, 2), aggregated_pass_list[2]->damage_rect); - EXPECT_EQ(1u, aggregated_pass_list[2]->quad_list.size()); + // First render pass draw quad is outside damage rect but has background + // filter, so should be drawn. SurfaceDrawQuad is after background filter, + // so corresponding cc::RenderPassDrawQuad should be drawn. + EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list[2]->damage_rect); + EXPECT_EQ(2u, aggregated_pass_list[2]->quad_list.size()); } }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 31c52ae..708110c1 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1674,7 +1674,6 @@ "//third_party/webrtc/media:rtc_media_base", "//third_party/webrtc/modules/desktop_capture:primitives", "//third_party/webrtc/rtc_base:rtc_base", - "//third_party/webrtc_overrides:init_webrtc", ] } @@ -1717,6 +1716,7 @@ "media/capture/desktop_capture_device.h", ] deps += [ "//third_party/webrtc/modules/desktop_capture" ] + public_deps += [ "//third_party/webrtc_overrides:init_webrtc" ] } }
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc index 7c835fda..07da417 100644 --- a/content/browser/devtools/protocol/page_handler.cc +++ b/content/browser/devtools/protocol/page_handler.cc
@@ -574,6 +574,15 @@ return Response::InvalidParams("Unrecognized response"); } +Response PageHandler::BringToFront() { + WebContentsImpl* wc = GetWebContents(); + if (wc) { + wc->Activate(); + return Response::OK(); + } + return Response::InternalError(); +} + std::unique_ptr<PageNavigationThrottle> PageHandler::CreateThrottleForNavigation(NavigationHandle* navigation_handle) { if (!navigation_throttle_enabled_)
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h index c03d5bc..ea995ef 100644 --- a/content/browser/devtools/protocol/page_handler.h +++ b/content/browser/devtools/protocol/page_handler.h
@@ -114,6 +114,7 @@ Response SetControlNavigations(bool enabled) override; Response ProcessNavigation(const std::string& response, int navigation_id) override; + Response BringToFront() override; std::unique_ptr<PageNavigationThrottle> CreateThrottleForNavigation( NavigationHandle* navigation_handle);
diff --git a/content/browser/devtools/protocol_config.json b/content/browser/devtools/protocol_config.json index 612f362..1125e1c5f 100644 --- a/content/browser/devtools/protocol_config.json +++ b/content/browser/devtools/protocol_config.json
@@ -48,7 +48,7 @@ "domain": "Page", "include": ["enable", "disable", "reload", "navigate", "stopLoading", "getNavigationHistory", "navigateToHistoryEntry", "captureScreenshot", "startScreencast", "stopScreencast", "screencastFrameAck", "handleJavaScriptDialog", "setColorPickerEnabled", "requestAppBanner", - "setControlNavigations", "processNavigation", "printToPDF"], + "setControlNavigations", "processNavigation", "printToPDF", "bringToFront"], "include_events": ["interstitialShown", "interstitialHidden", "navigationRequested", "screencastVisibilityChanged", "screencastFrame", "colorPicked"], "async": ["captureScreenshot", "printToPDF"] },
diff --git a/content/browser/renderer_host/database_message_filter.cc b/content/browser/renderer_host/database_message_filter.cc index 0418b948..f18981f3 100644 --- a/content/browser/renderer_host/database_message_filter.cc +++ b/content/browser/renderer_host/database_message_filter.cc
@@ -220,10 +220,11 @@ if ((error_code == SQLITE_IOERR_DELETE) && reschedule_count) { // If the file could not be deleted, try again. - BrowserThread::PostDelayedTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&DatabaseMessageFilter::DatabaseDeleteFile, this, - vfs_file_name, sync_dir, reply_msg, reschedule_count - 1), + db_tracker_->task_runner()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&DatabaseMessageFilter::DatabaseDeleteFile, this, + vfs_file_name, sync_dir, reply_msg, + reschedule_count - 1), base::TimeDelta::FromMilliseconds(kDelayDeleteRetryMs)); return; }
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc index bc8275d2..d47ea5d 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
@@ -74,10 +74,6 @@ bool handled = true; IPC_BEGIN_MESSAGE_MAP(MediaStreamDispatcherHost, message) IPC_MESSAGE_HANDLER(MediaStreamHostMsg_GenerateStream, OnGenerateStream) - IPC_MESSAGE_HANDLER(MediaStreamHostMsg_OpenDevice, - OnOpenDevice) - IPC_MESSAGE_HANDLER(MediaStreamHostMsg_SetCapturingLinkSecured, - OnSetCapturingLinkSecured) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -115,39 +111,8 @@ controls, security_origin, user_gesture); } -void MediaStreamDispatcherHost::OnOpenDevice( - int render_frame_id, - int page_request_id, - const std::string& device_id, - MediaStreamType type, - const url::Origin& security_origin) { - DVLOG(1) << __func__ << " render_frame_id=" << render_frame_id - << " page_request_id=" << page_request_id - << " device_id=" << device_id << " type=" << type - << " security_origin=" << security_origin; - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - if (!MediaStreamManager::IsOriginAllowed(render_process_id_, security_origin)) - return; - - media_stream_manager_->OpenDevice(this, render_process_id_, render_frame_id, - salt_, page_request_id, device_id, type, - security_origin); -} - -void MediaStreamDispatcherHost::OnSetCapturingLinkSecured(int session_id, - MediaStreamType type, - bool is_secure) { - DVLOG(1) << __func__ << " session_id=" << session_id << " type=" << type - << " is_secure=" << is_secure; - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - media_stream_manager_->SetCapturingLinkSecured(render_process_id_, session_id, - type, is_secure); -} - -void MediaStreamDispatcherHost::CancelGenerateStream(int32_t render_frame_id, - int32_t page_request_id) { +void MediaStreamDispatcherHost::CancelGenerateStream(int render_frame_id, + int page_request_id) { DVLOG(1) << __func__ << " render_frame_id=" << render_frame_id << " page_request_id=" << page_request_id; DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -166,6 +131,27 @@ device_id); } +void MediaStreamDispatcherHost::OpenDevice(int32_t render_frame_id, + int32_t page_request_id, + const std::string& device_id, + MediaStreamType type, + const url::Origin& security_origin) { + DVLOG(1) << __func__ << " render_frame_id=" << render_frame_id + << " page_request_id=" << page_request_id + << " device_id=" << device_id << " type=" << type + << " security_origin=" << security_origin; + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + // TODO(c.padhi): Report OpenDevice failure to renderer, see + // https://crbug.com/742682. + if (!MediaStreamManager::IsOriginAllowed(render_process_id_, security_origin)) + return; + + media_stream_manager_->OpenDevice(this, render_process_id_, render_frame_id, + salt_, page_request_id, device_id, type, + security_origin); +} + void MediaStreamDispatcherHost::CloseDevice(const std::string& label) { DVLOG(1) << __func__ << " label = " << label; DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -173,6 +159,17 @@ media_stream_manager_->CancelRequest(label); } +void MediaStreamDispatcherHost::SetCapturingLinkSecured(int32_t session_id, + MediaStreamType type, + bool is_secure) { + DVLOG(1) << __func__ << " session_id=" << session_id << " type=" << type + << " is_secure=" << is_secure; + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + media_stream_manager_->SetCapturingLinkSecured(render_process_id_, session_id, + type, is_secure); +} + void MediaStreamDispatcherHost::StreamStarted(const std::string& label) { DVLOG(1) << __func__ << " label = " << label; DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.h b/content/browser/renderer_host/media/media_stream_dispatcher_host.h index fb84896..ec9decc 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host.h +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.h
@@ -69,22 +69,21 @@ const StreamControls& controls, const url::Origin& security_origin, bool user_gesture); - void OnOpenDevice(int render_frame_id, - int page_request_id, - const std::string& device_id, - MediaStreamType type, - const url::Origin& security_origin); - // Set if the video capturing is secure. - void OnSetCapturingLinkSecured(int session_id, - MediaStreamType type, - bool is_secure); // mojom::MediaStreamDispatcherHost implementation void CancelGenerateStream(int32_t render_frame_id, int32_t request_id) override; void StopStreamDevice(int32_t render_frame_id, const std::string& device_id) override; + void OpenDevice(int32_t render_frame_id, + int32_t request_id, + const std::string& device_id, + MediaStreamType type, + const url::Origin& security_origin) override; void CloseDevice(const std::string& label) override; + void SetCapturingLinkSecured(int32_t session_id, + MediaStreamType type, + bool is_secure) override; void StreamStarted(const std::string& label) override; int render_process_id_;
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc index 1758c17..06d303a 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -130,8 +130,8 @@ const url::Origin& security_origin, const base::Closure& quit_closure) { quit_closures_.push(quit_closure); - MediaStreamDispatcherHost::OnOpenDevice( - render_frame_id, page_request_id, device_id, type, security_origin); + MediaStreamDispatcherHost::OpenDevice(render_frame_id, page_request_id, + device_id, type, security_origin); } void OnStreamStarted(const std::string label) {
diff --git a/content/browser/theme_helper_mac.mm b/content/browser/theme_helper_mac.mm index 39eec61..50a8828 100644 --- a/content/browser/theme_helper_mac.mm +++ b/content/browser/theme_helper_mac.mm
@@ -53,8 +53,10 @@ params->preferred_scroller_style = ThemeHelperMac::GetPreferredScrollerStyle(); params->button_placement = GetButtonPlacement(); + + id rubber_band_value = [defaults objectForKey:@"NSScrollViewRubberbanding"]; params->scroll_view_rubber_banding = - [defaults boolForKey:@"NSScrollViewRubberbanding"]; + rubber_band_value ? [rubber_band_value boolValue] : YES; } void SendSystemColorsChangedMessage(content::mojom::Renderer* renderer) {
diff --git a/content/common/media/OWNERS b/content/common/media/OWNERS index fb2521de..402962c 100644 --- a/content/common/media/OWNERS +++ b/content/common/media/OWNERS
@@ -13,4 +13,7 @@ per-file *_struct_traits*.*=set noparent per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS +per-file *.typemap=set noparent +per-file *.typemap=file://ipc/SECURITY_OWNERS + # COMPONENT: Internals>Media
diff --git a/content/common/media/media_stream.mojom b/content/common/media/media_stream.mojom index 6d446984..32898f7a 100644 --- a/content/common/media/media_stream.mojom +++ b/content/common/media/media_stream.mojom
@@ -4,6 +4,20 @@ module content.mojom; +import "url/mojo/origin.mojom"; + +// Types of media streams (see content/public/common/media_stream_request.h). +enum MediaStreamType { + MEDIA_NO_SERVICE, + MEDIA_DEVICE_AUDIO_CAPTURE, + MEDIA_DEVICE_VIDEO_CAPTURE, + MEDIA_TAB_AUDIO_CAPTURE, + MEDIA_TAB_VIDEO_CAPTURE, + MEDIA_DESKTOP_VIDEO_CAPTURE, + MEDIA_DESKTOP_AUDIO_CAPTURE, + NUM_MEDIA_TYPES +}; + interface MediaStreamDispatcherHost { // TODO(c.padhi): Migrate the rest of the messages, https://crbug.com/742682. @@ -13,9 +27,24 @@ // Closes a stream device that has been opened by GenerateStream. StopStreamDevice(int32 render_frame_id, string device_id); + // Opens a device identified by |device_id|. + OpenDevice(int32 render_frame_id, int32 request_id, string device_id, + MediaStreamType type, url.mojom.Origin security_origin); + // Cancels an open request identified by |label|. CloseDevice(string label); + // Tells the browser process if the video capture is secure (i.e., all + // connected video sinks meet the requirement of output protection.). + // Note: the browser process only trusts the |is_secure| value in this Mojo + // message if it's comimg from a trusted, whitelisted extension. Extensions + // run in separate render processes. So it shouldn't be possible, for example, + // for a user's visit to a malicious web page to compromise a render process + // running a trusted extension to make it report falsehood in this Mojo + // message. + SetCapturingLinkSecured(int32 session_id, MediaStreamType type, + bool is_secure); + // Tells the browser process that the stream has been started successfully. StreamStarted(string label); };
diff --git a/content/common/media/media_stream.typemap b/content/common/media/media_stream.typemap new file mode 100644 index 0000000..1c7b1a9 --- /dev/null +++ b/content/common/media/media_stream.typemap
@@ -0,0 +1,19 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +mojom = "//content/common/media/media_stream.mojom" + +public_headers = [ "//content/public/common/media_stream_request.h" ] + +traits_headers = [ "//content/common/media/media_stream_typemap_traits.h" ] + +sources = [ + "//content/common/media/media_stream_typemap_traits.cc", +] + +deps = [ + "//base", +] + +type_mappings = [ "content.mojom.MediaStreamType=content::MediaStreamType" ]
diff --git a/content/common/media/media_stream_messages.h b/content/common/media/media_stream_messages.h index f6c4f40..5c49bbc 100644 --- a/content/common/media/media_stream_messages.h +++ b/content/common/media/media_stream_messages.h
@@ -98,23 +98,3 @@ content::StreamControls /* controls */, url::Origin /* security origin */, bool /* user_gesture */) - -// Request to open the device. -IPC_MESSAGE_CONTROL5(MediaStreamHostMsg_OpenDevice, - int /* render frame id */, - int /* request id */, - std::string /* device_id */, - content::MediaStreamType /* type */, - url::Origin /* security origin */) - -// Tell the browser process if the video capture is secure (i.e., all -// connected video sinks meet the requirement of output protection.). -// Note: the browser process only trusts the |is_sucure| value in this IPC -// message if it's comimg from a trusted, whitelisted extension. Extensions run -// in separate render processes. So it shouldn't be possible, for example, for -// a user's visit to a malicious web page to compromise a render process running -// a trusted extension to make it report falsehood in this IPC message. -IPC_MESSAGE_CONTROL3(MediaStreamHostMsg_SetCapturingLinkSecured, - int, /* session_id */ - content::MediaStreamType, /* type */ - bool /* is_secure */)
diff --git a/content/common/media/media_stream_typemap_traits.cc b/content/common/media/media_stream_typemap_traits.cc new file mode 100644 index 0000000..71f8401 --- /dev/null +++ b/content/common/media/media_stream_typemap_traits.cc
@@ -0,0 +1,71 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/media/media_stream_typemap_traits.h" + +#include "base/logging.h" + +namespace mojo { + +// static +content::mojom::MediaStreamType +EnumTraits<content::mojom::MediaStreamType, content::MediaStreamType>::ToMojom( + content::MediaStreamType type) { + switch (type) { + case content::MediaStreamType::MEDIA_NO_SERVICE: + return content::mojom::MediaStreamType::MEDIA_NO_SERVICE; + case content::MediaStreamType::MEDIA_DEVICE_AUDIO_CAPTURE: + return content::mojom::MediaStreamType::MEDIA_DEVICE_AUDIO_CAPTURE; + case content::MediaStreamType::MEDIA_DEVICE_VIDEO_CAPTURE: + return content::mojom::MediaStreamType::MEDIA_DEVICE_VIDEO_CAPTURE; + case content::MediaStreamType::MEDIA_TAB_AUDIO_CAPTURE: + return content::mojom::MediaStreamType::MEDIA_TAB_AUDIO_CAPTURE; + case content::MediaStreamType::MEDIA_TAB_VIDEO_CAPTURE: + return content::mojom::MediaStreamType::MEDIA_TAB_VIDEO_CAPTURE; + case content::MediaStreamType::MEDIA_DESKTOP_VIDEO_CAPTURE: + return content::mojom::MediaStreamType::MEDIA_DESKTOP_VIDEO_CAPTURE; + case content::MediaStreamType::MEDIA_DESKTOP_AUDIO_CAPTURE: + return content::mojom::MediaStreamType::MEDIA_DESKTOP_AUDIO_CAPTURE; + case content::MediaStreamType::NUM_MEDIA_TYPES: + return content::mojom::MediaStreamType::NUM_MEDIA_TYPES; + } + NOTREACHED(); + return content::mojom::MediaStreamType::MEDIA_NO_SERVICE; +} + +// static +bool EnumTraits<content::mojom::MediaStreamType, content::MediaStreamType>:: + FromMojom(content::mojom::MediaStreamType input, + content::MediaStreamType* out) { + switch (input) { + case content::mojom::MediaStreamType::MEDIA_NO_SERVICE: + *out = content::MediaStreamType::MEDIA_NO_SERVICE; + return true; + case content::mojom::MediaStreamType::MEDIA_DEVICE_AUDIO_CAPTURE: + *out = content::MediaStreamType::MEDIA_DEVICE_AUDIO_CAPTURE; + return true; + case content::mojom::MediaStreamType::MEDIA_DEVICE_VIDEO_CAPTURE: + *out = content::MediaStreamType::MEDIA_DEVICE_VIDEO_CAPTURE; + return true; + case content::mojom::MediaStreamType::MEDIA_TAB_AUDIO_CAPTURE: + *out = content::MediaStreamType::MEDIA_TAB_AUDIO_CAPTURE; + return true; + case content::mojom::MediaStreamType::MEDIA_TAB_VIDEO_CAPTURE: + *out = content::MediaStreamType::MEDIA_TAB_VIDEO_CAPTURE; + return true; + case content::mojom::MediaStreamType::MEDIA_DESKTOP_VIDEO_CAPTURE: + *out = content::MediaStreamType::MEDIA_DESKTOP_VIDEO_CAPTURE; + return true; + case content::mojom::MediaStreamType::MEDIA_DESKTOP_AUDIO_CAPTURE: + *out = content::MediaStreamType::MEDIA_DESKTOP_AUDIO_CAPTURE; + return true; + case content::mojom::MediaStreamType::NUM_MEDIA_TYPES: + *out = content::MediaStreamType::NUM_MEDIA_TYPES; + return true; + } + NOTREACHED(); + return false; +} + +} // namespace mojo
diff --git a/content/common/media/media_stream_typemap_traits.h b/content/common/media/media_stream_typemap_traits.h new file mode 100644 index 0000000..b581d67 --- /dev/null +++ b/content/common/media/media_stream_typemap_traits.h
@@ -0,0 +1,23 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_MEDIA_MEDIA_STREAM_TYPEMAP_TRAITS_H_ +#define CONTENT_COMMON_MEDIA_MEDIA_STREAM_TYPEMAP_TRAITS_H_ + +#include "content/common/media/media_stream.mojom.h" +#include "content/public/common/media_stream_request.h" + +namespace mojo { + +template <> +struct EnumTraits<content::mojom::MediaStreamType, content::MediaStreamType> { + static content::mojom::MediaStreamType ToMojom(content::MediaStreamType type); + + static bool FromMojom(content::mojom::MediaStreamType input, + content::MediaStreamType* out); +}; + +} // namespace mojo + +#endif // CONTENT_COMMON_MEDIA_MEDIA_STREAM_TYPEMAP_TRAITS_H_ \ No newline at end of file
diff --git a/content/common/typemaps.gni b/content/common/typemaps.gni index b65fe78..c5664d19a 100644 --- a/content/common/typemaps.gni +++ b/content/common/typemaps.gni
@@ -6,6 +6,7 @@ "//content/common/background_fetch/background_fetch_types.typemap", "//content/common/native_types.typemap", "//content/common/media/media_devices.typemap", + "//content/common/media/media_stream.typemap", "//content/common/push_messaging.typemap", "//content/common/service_worker/embedded_worker.typemap", "//content/common/service_worker/service_worker_event_dispatcher.typemap",
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java index 237f043..c672be1 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
@@ -372,17 +372,30 @@ } @Override - public void onConnectionFreed( - ChildConnectionAllocator allocator, ChildProcessConnection connection) { + public void onConnectionFreed(final ChildConnectionAllocator allocator, + ChildProcessConnection connection) { assert allocator == finalConnectionAllocator; - if (!allocator.anyConnectionAllocated()) { - // Last connection was freed, the allocator is going aways, remove the - // listener. - allocator.removeListener(this); - ChildConnectionAllocator removedAllocator = - sSandboxedChildConnectionAllocatorMap.remove(packageName); - assert removedAllocator == allocator; - } + final ChildConnectionAllocator.Listener listener = this; + // The ChildProcessLauncher may have posted a restart that will create a new + // connection with |allocator|. Delay clearing the allocator until that + // potential restart task has been run. + LauncherThread.post(new Runnable() { + @Override + public void run() { + if (!allocator.anyConnectionAllocated()) { + // Last connection was freed, the allocator is going aways, remove + // the listener. + allocator.removeListener(listener); + Log.w(TAG, + "Removing empty ChildConnectionAllocator for package " + + "name = %s,", + packageName); + ChildConnectionAllocator removedAllocator = + sSandboxedChildConnectionAllocatorMap.remove(packageName); + assert removedAllocator == allocator; + } + } + }); } }); }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 2b5d847..5651b61d 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -1854,15 +1854,6 @@ } } - /** - * Return the current scale of the ContentView. - * @return The current page scale factor. - */ - @VisibleForTesting - public float getScale() { - return mRenderCoordinates.getPageScaleFactor(); - } - @Override public void onAccessibilityStateChanged(boolean enabled) { setAccessibilityState(enabled);
diff --git a/content/public/android/java/src/org/chromium/content/browser/SpareChildConnection.java b/content/public/android/java/src/org/chromium/content/browser/SpareChildConnection.java index b973a81..eecba4ff 100644 --- a/content/public/android/java/src/org/chromium/content/browser/SpareChildConnection.java +++ b/content/public/android/java/src/org/chromium/content/browser/SpareChildConnection.java
@@ -55,11 +55,11 @@ } @Override - public void onChildStartFailed() { + public void onChildStartFailed(ChildProcessConnection connection) { assert LauncherThread.runningOnLauncherThread(); Log.e(TAG, "Failed to warm up the spare sandbox service"); if (mConnectionServiceCallback != null) { - mConnectionServiceCallback.onChildStartFailed(); + mConnectionServiceCallback.onChildStartFailed(connection); } clearConnection(); }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java index 59ba40df..79753ed 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java
@@ -90,6 +90,8 @@ @Test @MediumTest @Feature({"ProcessManagement"}) + @ChildProcessAllocatorSettings( + sandboxedServiceCount = 2, sandboxedServiceName = DEFAULT_SANDBOXED_PROCESS_SERVICE) public void testBindServiceFromMultipleProcesses() throws RemoteException { final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); @@ -176,11 +178,11 @@ ChildConnectionAllocator connectionAllocator = launcher.getChildConnectionAllocatorForTesting(); - // Check that only two connections are created. + // Check that only one connection is created. for (int i = 0; i < connectionAllocator.getNumberOfServices(); ++i) { ChildProcessConnection sandboxedConn = connectionAllocator.getChildProcessConnectionAtSlotForTesting(i); - if (i <= 1) { + if (i == 1) { Assert.assertNotNull(sandboxedConn); Assert.assertNotNull( ChildProcessLauncherTestUtils.getConnectionService(sandboxedConn)); @@ -192,12 +194,6 @@ Assert.assertEquals( connectionAllocator.getChildProcessConnectionAtSlotForTesting(1), retryConnection); - ChildProcessConnection failedConnection = - connectionAllocator.getChildProcessConnectionAtSlotForTesting(0); - Assert.assertEquals(0, ChildProcessLauncherTestUtils.getConnectionPid(failedConnection)); - Assert.assertFalse(ChildProcessLauncherTestUtils.getConnectionService(failedConnection) - .bindToCaller()); - CriteriaHelper.pollInstrumentationThread( new Criteria("Failed waiting retry connection to get pid") { @Override @@ -209,6 +205,28 @@ != helperConnectionPid); Assert.assertTrue( ChildProcessLauncherTestUtils.getConnectionService(retryConnection).bindToCaller()); + + // Unbind the service. + replyHandler.mMessage = null; + msg = Message.obtain(null, ChildProcessLauncherTestHelperService.MSG_UNBIND_SERVICE); + msg.replyTo = new Messenger(new Handler(Looper.getMainLooper(), replyHandler)); + serviceConnection.mMessenger.send(msg); + CriteriaHelper.pollInstrumentationThread( + new Criteria("Failed waiting for helper service unbind reply") { + @Override + public boolean isSatisfied() { + return replyHandler.mMessage != null; + } + }); + Assert.assertEquals(ChildProcessLauncherTestHelperService.MSG_UNBIND_SERVICE_REPLY, + replyHandler.mMessage.what); + + // The 0th connection should now be usable. + launcher = startSandboxedChildProcessWithCreationParams( + creationParams, BLOCK_UNTIL_SETUP, true /* doSetupConnection */); + ChildProcessConnection connection = ChildProcessLauncherTestUtils.getConnection(launcher); + Assert.assertEquals( + 0, ChildProcessLauncherTestUtils.getConnectionServiceNumber(connection)); } private static void warmUpOnUiThreadBlocking(final Context context) {
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java index fede1e0..4cbeb86 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
@@ -348,9 +348,11 @@ } @Override - public void onChildStartFailed() { + public void onChildStartFailed( + ChildProcessConnection connection) { if (serviceCallbackWrapper.get() != null) { - serviceCallbackWrapper.get().onChildStartFailed(); + serviceCallbackWrapper.get().onChildStartFailed( + connection); } }
diff --git a/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java b/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java index 86cc35d5..8941042 100644 --- a/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java +++ b/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
@@ -66,7 +66,7 @@ } public void simulateConnectionFailingToBind() { - mConnection.getServiceCallback().onChildStartFailed(); + mConnection.getServiceCallback().onChildStartFailed(mConnection); } public void simulateConnectionDied() { @@ -129,7 +129,7 @@ assertNull(connection); ShadowLooper.runUiThreadTasks(); verify(mServiceCallback, times(0)).onChildStarted(); - verify(mServiceCallback, times(0)).onChildStartFailed(); + verify(mServiceCallback, times(0)).onChildStartFailed(any()); verify(mServiceCallback, times(0)).onChildProcessDied(any()); } @@ -150,7 +150,7 @@ ShadowLooper.runUiThreadTasks(); verify(mServiceCallback, times(1)).onChildStarted(); - verify(mServiceCallback, times(0)).onChildStartFailed(); + verify(mServiceCallback, times(0)).onChildStartFailed(any()); } @Test @@ -165,7 +165,7 @@ ShadowLooper.runUiThreadTasks(); // No callbacks are called. verify(mServiceCallback, times(0)).onChildStarted(); - verify(mServiceCallback, times(0)).onChildStartFailed(); + verify(mServiceCallback, times(0)).onChildStartFailed(any()); // No more connections are available. assertTrue(mSpareConnection.isEmpty()); @@ -173,7 +173,7 @@ // Simulate the connection getting bound, it should trigger the callback. mTestConnectionFactory.simulateConnectionBindingSuccessfully(); verify(mServiceCallback, times(1)).onChildStarted(); - verify(mServiceCallback, times(0)).onChildStartFailed(); + verify(mServiceCallback, times(0)).onChildStartFailed(any()); } @Test @@ -199,7 +199,7 @@ // We should get a failure callback. verify(mServiceCallback, times(0)).onChildStarted(); - verify(mServiceCallback, times(1)).onChildStartFailed(); + verify(mServiceCallback, times(1)).onChildStartFailed(connection); } @Test @@ -214,7 +214,7 @@ // We should get a failure callback. verify(mServiceCallback, times(0)).onChildStarted(); - verify(mServiceCallback, times(0)).onChildStartFailed(); + verify(mServiceCallback, times(0)).onChildStartFailed(any()); verify(mServiceCallback, times(1)).onChildProcessDied(connection); }
diff --git a/content/public/renderer/pepper_plugin_instance.h b/content/public/renderer/pepper_plugin_instance.h index 3b1844c..27465c86 100644 --- a/content/public/renderer/pepper_plugin_instance.h +++ b/content/public/renderer/pepper_plugin_instance.h
@@ -15,6 +15,7 @@ #include "ppapi/c/private/ppb_instance_private.h" #include "ppapi/c/private/ppb_pdf.h" #include "ui/base/ime/text_input_type.h" +#include "ui/gfx/geometry/point_f.h" class GURL; @@ -121,6 +122,18 @@ // Posts a message to the JavaScript object for this instance. virtual void PostMessageToJavaScript(PP_Var message) = 0; + + // Sets the current mouse caret position. + virtual void SetCaretPosition(const gfx::PointF& position) = 0; + + // Sends notification that the selection extent has been modified. + virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) = 0; + + // Sends notification of the base and extent of the current selection. + // The extent provided maybe modified by subsequent calls to + // MoveRangeSelectionExtent. + virtual void SetSelectionBounds(const gfx::PointF& base, + const gfx::PointF& extent) = 0; }; } // namespace content
diff --git a/content/renderer/media/media_stream_dispatcher.cc b/content/renderer/media/media_stream_dispatcher.cc index 851275d..10a3a49 100644 --- a/content/renderer/media/media_stream_dispatcher.cc +++ b/content/renderer/media/media_stream_dispatcher.cc
@@ -142,11 +142,8 @@ DVLOG(1) << "MediaStreamDispatcher::OpenDevice(" << request_id << ")"; requests_.push_back(Request(event_handler, request_id, next_ipc_id_)); - Send(new MediaStreamHostMsg_OpenDevice(routing_id(), - next_ipc_id_++, - device_id, - type, - security_origin)); + GetMediaStreamDispatcherHost()->OpenDevice(routing_id(), next_ipc_id_++, + device_id, type, security_origin); } void MediaStreamDispatcher::CancelOpenDevice(
diff --git a/content/renderer/media/media_stream_dispatcher_unittest.cc b/content/renderer/media/media_stream_dispatcher_unittest.cc index a19c541..7b5e442 100644 --- a/content/renderer/media/media_stream_dispatcher_unittest.cc +++ b/content/renderer/media/media_stream_dispatcher_unittest.cc
@@ -38,7 +38,14 @@ MOCK_METHOD2(CancelGenerateStream, void(int32_t, int32_t)); MOCK_METHOD2(StopStreamDevice, void(int32_t, const std::string&)); + MOCK_METHOD5(OpenDevice, + void(int32_t, + int32_t, + const std::string&, + MediaStreamType, + const url::Origin&)); MOCK_METHOD1(CloseDevice, void(const std::string&)); + MOCK_METHOD3(SetCapturingLinkSecured, void(int32_t, MediaStreamType, bool)); MOCK_METHOD1(StreamStarted, void(const std::string&)); };
diff --git a/content/renderer/media/media_stream_video_capturer_source.cc b/content/renderer/media/media_stream_video_capturer_source.cc index 583eba3..386df2e 100644 --- a/content/renderer/media/media_stream_video_capturer_source.cc +++ b/content/renderer/media/media_stream_video_capturer_source.cc
@@ -13,7 +13,7 @@ #include "base/location.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h" -#include "content/common/media/media_stream_messages.h" +#include "content/child/child_thread_impl.h" #include "content/public/common/media_stream_request.h" #include "content/renderer/media/media_stream_constraints_util.h" #include "content/renderer/media/video_capture_impl_manager.h" @@ -159,7 +159,9 @@ MediaStreamVideoCapturerSource::MediaStreamVideoCapturerSource( const SourceStoppedCallback& stop_callback, std::unique_ptr<media::VideoCapturerSource> source) - : RenderFrameObserver(nullptr), source_(std::move(source)) { + : RenderFrameObserver(nullptr), + dispatcher_host_(nullptr), + source_(std::move(source)) { media::VideoCaptureFormats preferred_formats = source_->GetPreferredFormats(); if (!preferred_formats.empty()) capture_params_.requested_format = preferred_formats.front(); @@ -172,6 +174,7 @@ const media::VideoCaptureParams& capture_params, RenderFrame* render_frame) : RenderFrameObserver(render_frame), + dispatcher_host_(nullptr), source_(new LocalVideoCapturerSource(device_info)), capture_params_(capture_params) { SetStopCallback(stop_callback); @@ -193,8 +196,8 @@ } void MediaStreamVideoCapturerSource::OnCapturingLinkSecured(bool is_secure) { - Send(new MediaStreamHostMsg_SetCapturingLinkSecured( - device_info().session_id, device_info().device.type, is_secure)); + GetMediaStreamDispatcherHost()->SetCapturingLinkSecured( + device_info().session_id, device_info().device.type, is_secure); } void MediaStreamVideoCapturerSource::StartSourceImpl( @@ -226,4 +229,14 @@ } } +mojom::MediaStreamDispatcherHost* +MediaStreamVideoCapturerSource::GetMediaStreamDispatcherHost() { + if (!dispatcher_host_) { + ChildThreadImpl::current()->channel()->GetRemoteAssociatedInterface( + &dispatcher_host_ptr_); + dispatcher_host_ = dispatcher_host_ptr_.get(); + } + return dispatcher_host_; +}; + } // namespace content
diff --git a/content/renderer/media/media_stream_video_capturer_source.h b/content/renderer/media/media_stream_video_capturer_source.h index f4fa6067..cf3263d 100644 --- a/content/renderer/media/media_stream_video_capturer_source.h +++ b/content/renderer/media/media_stream_video_capturer_source.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" +#include "content/common/media/media_stream.mojom.h" #include "content/common/media/video_capture.h" #include "content/public/renderer/render_frame_observer.h" #include "content/renderer/media/media_stream_video_source.h" @@ -43,6 +44,9 @@ friend class CanvasCaptureHandlerTest; friend class MediaStreamVideoCapturerSourceTest; friend class MediaStreamVideoCapturerSourceOldConstraintsTest; + FRIEND_TEST_ALL_PREFIXES(MediaStreamVideoCapturerSourceTest, StartAndStop); + FRIEND_TEST_ALL_PREFIXES(MediaStreamVideoCapturerSourceTest, + CaptureTimeAndMetadataPlumbing); // MediaStreamVideoSource overrides. void RequestRefreshFrame() override; @@ -59,6 +63,11 @@ // Method to bind as RunningCallback in VideoCapturerSource::StartCapture(). void OnRunStateChanged(bool is_running); + mojom::MediaStreamDispatcherHost* GetMediaStreamDispatcherHost(); + + mojom::MediaStreamDispatcherHostAssociatedPtr dispatcher_host_ptr_; + mojom::MediaStreamDispatcherHost* dispatcher_host_; + // The source that provides video frames. const std::unique_ptr<media::VideoCapturerSource> source_;
diff --git a/content/renderer/media/media_stream_video_capturer_source_unittest.cc b/content/renderer/media/media_stream_video_capturer_source_unittest.cc index 0735060..9e6b811 100644 --- a/content/renderer/media/media_stream_video_capturer_source_unittest.cc +++ b/content/renderer/media/media_stream_video_capturer_source_unittest.cc
@@ -14,6 +14,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_task_environment.h" #include "content/child/child_process.h" +#include "content/common/media/media_stream.mojom.h" #include "content/public/renderer/media_stream_video_sink.h" #include "content/renderer/media/media_stream_video_track.h" #include "content/renderer/media/video_track_adapter.h" @@ -31,6 +32,24 @@ namespace { +class MockMojoMediaStreamDispatcherHost + : public mojom::MediaStreamDispatcherHost { + public: + MockMojoMediaStreamDispatcherHost() {} + + MOCK_METHOD2(CancelGenerateStream, void(int32_t, int32_t)); + MOCK_METHOD2(StopStreamDevice, void(int32_t, const std::string&)); + MOCK_METHOD5(OpenDevice, + void(int32_t, + int32_t, + const std::string&, + MediaStreamType, + const url::Origin&)); + MOCK_METHOD1(CloseDevice, void(const std::string&)); + MOCK_METHOD3(SetCapturingLinkSecured, void(int32_t, MediaStreamType, bool)); + MOCK_METHOD1(StreamStarted, void(const std::string&)); +}; + class MockVideoCapturerSource : public media::VideoCapturerSource { public: MockVideoCapturerSource() {} @@ -102,6 +121,7 @@ base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped, base::Unretained(this)), std::move(delegate)); + source_->dispatcher_host_ = &mock_dispatcher_host_; source_->SetDeviceInfo(device_info); webkit_source_.Initialize(blink::WebString::FromASCII("dummy_source_id"), @@ -146,6 +166,7 @@ std::unique_ptr<ChildProcess> child_process_; blink::WebMediaStreamSource webkit_source_; + MockMojoMediaStreamDispatcherHost mock_dispatcher_host_; MediaStreamVideoCapturerSource* source_; // owned by |webkit_source_|. MockVideoCapturerSource* delegate_; // owned by |source|. blink::WebString webkit_source_id_; @@ -161,6 +182,7 @@ base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped, base::Unretained(this)), std::move(delegate)); + source_->dispatcher_host_ = &mock_dispatcher_host_; webkit_source_.Initialize(blink::WebString::FromASCII("dummy_source_id"), blink::WebMediaStreamSource::kTypeVideo, blink::WebString::FromASCII("dummy_source_name"), @@ -199,6 +221,7 @@ base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped, base::Unretained(this)), std::move(delegate)); + source_->dispatcher_host_ = &mock_dispatcher_host_; webkit_source_.Initialize(blink::WebString::FromASCII("dummy_source_id"), blink::WebMediaStreamSource::kTypeVideo, blink::WebString::FromASCII("dummy_source_name"),
diff --git a/content/renderer/media/user_media_client_impl_unittest.cc b/content/renderer/media/user_media_client_impl_unittest.cc index 1629fde..8e1f424 100644 --- a/content/renderer/media/user_media_client_impl_unittest.cc +++ b/content/renderer/media/user_media_client_impl_unittest.cc
@@ -122,7 +122,14 @@ MOCK_METHOD2(CancelGenerateStream, void(int32_t, int32_t)); MOCK_METHOD2(StopStreamDevice, void(int32_t, const std::string&)); + MOCK_METHOD5(OpenDevice, + void(int32_t, + int32_t, + const std::string&, + MediaStreamType, + const url::Origin&)); MOCK_METHOD1(CloseDevice, void(const std::string&)); + MOCK_METHOD3(SetCapturingLinkSecured, void(int32_t, MediaStreamType, bool)); MOCK_METHOD1(StreamStarted, void(const std::string&)); };
diff --git a/content/renderer/pepper/fake_pepper_plugin_instance.cc b/content/renderer/pepper/fake_pepper_plugin_instance.cc index 19a9ad0..c260bb7 100644 --- a/content/renderer/pepper/fake_pepper_plugin_instance.cc +++ b/content/renderer/pepper/fake_pepper_plugin_instance.cc
@@ -77,5 +77,12 @@ void FakePepperPluginInstance::SetTextInputType(ui::TextInputType type) {} void FakePepperPluginInstance::PostMessageToJavaScript(PP_Var message) {} +void FakePepperPluginInstance::SetCaretPosition(const gfx::PointF& position) {} + +void FakePepperPluginInstance::MoveRangeSelectionExtent( + const gfx::PointF& extent) {} + +void FakePepperPluginInstance::SetSelectionBounds(const gfx::PointF& base, + const gfx::PointF& extent) {} } // namespace content
diff --git a/content/renderer/pepper/fake_pepper_plugin_instance.h b/content/renderer/pepper/fake_pepper_plugin_instance.h index 0fb43755..ddac1d5d 100644 --- a/content/renderer/pepper/fake_pepper_plugin_instance.h +++ b/content/renderer/pepper/fake_pepper_plugin_instance.h
@@ -43,6 +43,10 @@ void SetLinkUnderCursor(const std::string& url) override; void SetTextInputType(ui::TextInputType type) override; void PostMessageToJavaScript(PP_Var message) override; + void SetCaretPosition(const gfx::PointF& position) override; + void MoveRangeSelectionExtent(const gfx::PointF& extent) override; + void SetSelectionBounds(const gfx::PointF& base, + const gfx::PointF& extent) override; private: GURL gurl_;
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 6f1bf08..9443b3e 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -1465,6 +1465,42 @@ return link; } +void PepperPluginInstanceImpl::SetCaretPosition(const gfx::PointF& position) { + if (!LoadPdfInterface()) + return; + + PP_FloatPoint p; + p.x = position.x(); + p.y = position.y(); + plugin_pdf_interface_->SetCaretPosition(pp_instance(), &p); +} + +void PepperPluginInstanceImpl::MoveRangeSelectionExtent( + const gfx::PointF& extent) { + if (!LoadPdfInterface()) + return; + + PP_FloatPoint p; + p.x = extent.x(); + p.y = extent.y(); + plugin_pdf_interface_->MoveRangeSelectionExtent(pp_instance(), &p); +} + +void PepperPluginInstanceImpl::SetSelectionBounds(const gfx::PointF& base, + const gfx::PointF& extent) { + if (!LoadPdfInterface()) + return; + + PP_FloatPoint p_base; + p_base.x = base.x(); + p_base.y = base.y(); + + PP_FloatPoint p_extent; + p_extent.x = extent.x(); + p_extent.y = extent.y(); + plugin_pdf_interface_->SetSelectionBounds(pp_instance(), &p_base, &p_extent); +} + void PepperPluginInstanceImpl::RequestSurroundingText( size_t desired_number_of_characters) { // Keep a reference on the stack. See NOTE above.
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h index ed1ad74..1f91fda3 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.h +++ b/content/renderer/pepper/pepper_plugin_instance_impl.h
@@ -416,6 +416,10 @@ void SetLinkUnderCursor(const std::string& url) override; void SetTextInputType(ui::TextInputType type) override; void PostMessageToJavaScript(PP_Var message) override; + void SetCaretPosition(const gfx::PointF& position) override; + void MoveRangeSelectionExtent(const gfx::PointF& extent) override; + void SetSelectionBounds(const gfx::PointF& base, + const gfx::PointF& extent) override; // PPB_Instance_API implementation. PP_Bool BindGraphics(PP_Instance instance, PP_Resource device) override;
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestCommon.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestCommon.java index ac347249..cac7590b 100644 --- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestCommon.java +++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestCommon.java
@@ -166,7 +166,7 @@ Criteria.equals(expectedScale, new Callable<Float>() { @Override public Float call() { - return getContentViewCore().getScale(); + return getContentViewCore().getPageScaleFactor(); } })); }
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java index 117a31b..94ec16ae 100644 --- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java +++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java
@@ -32,6 +32,8 @@ public class ChildProcessLauncherTestHelperService extends Service { public static final int MSG_BIND_SERVICE = IBinder.FIRST_CALL_TRANSACTION + 1; public static final int MSG_BIND_SERVICE_REPLY = MSG_BIND_SERVICE + 1; + public static final int MSG_UNBIND_SERVICE = MSG_BIND_SERVICE_REPLY + 1; + public static final int MSG_UNBIND_SERVICE_REPLY = MSG_UNBIND_SERVICE + 1; private final Handler.Callback mHandlerCallback = new Handler.Callback() { @Override @@ -40,6 +42,9 @@ case MSG_BIND_SERVICE: doBindService(msg); return true; + case MSG_UNBIND_SERVICE: + unbindService(msg); + return true; } return false; } @@ -47,6 +52,8 @@ private final HandlerThread mHandlerThread = new HandlerThread("Helper Service Handler"); + private ChildProcessLauncherHelper mProcessLauncher; + @Override public void onCreate() { CommandLine.init(null); @@ -71,9 +78,8 @@ final boolean bindToCaller = true; ChildProcessCreationParams params = new ChildProcessCreationParams( getPackageName(), false, LibraryProcessType.PROCESS_CHILD, bindToCaller); - final ChildProcessLauncherHelper processLauncher = - ChildProcessLauncherTestUtils.startForTesting(true /* sandboxed */, commandLine, - new FileDescriptorInfo[0], params, true /* doSetupConnection */); + mProcessLauncher = ChildProcessLauncherTestUtils.startForTesting(true /* sandboxed */, + commandLine, new FileDescriptorInfo[0], params, true /* doSetupConnection */); // Poll the launcher until the connection is set up. The main test in // ChildProcessLauncherTest, which has bound the connection to this service, manages the @@ -85,7 +91,7 @@ @Override public void run() { int pid = 0; - ChildProcessConnection conn = processLauncher.getChildProcessConnection(); + ChildProcessConnection conn = mProcessLauncher.getChildProcessConnection(); if (conn != null) { pid = ChildProcessLauncherTestUtils.getConnectionPid(conn); } @@ -104,4 +110,15 @@ }; handler.postDelayed(task, 10); } + + private void unbindService(Message msg) { + // Crash the service instead of unbinding so we are guaranteed the service process dies + // (if we were to unbind, the service process would stay around and may be reused). + try { + mProcessLauncher.getChildProcessConnection().crashServiceForTesting(); + msg.replyTo.send(Message.obtain(null, MSG_UNBIND_SERVICE_REPLY)); + } catch (RemoteException ex) { + throw new RuntimeException(ex); + } + } }
diff --git a/courgette/BUILD.gn b/courgette/BUILD.gn index b2d13e9..3084b06 100644 --- a/courgette/BUILD.gn +++ b/courgette/BUILD.gn
@@ -137,7 +137,7 @@ # directory. copy("copy_courgette_binaries") { if (is_clang) { - courgette64_toolchain = "//build/toolchain/win:clang_x64" + courgette64_toolchain = "//build/toolchain/win:win_clang_x64" } else { courgette64_toolchain = "//build/toolchain/win:x64" }
diff --git a/extensions/common/api/declarative_net_request.idl b/extensions/common/api/declarative_net_request.idl new file mode 100644 index 0000000..56c684f --- /dev/null +++ b/extensions/common/api/declarative_net_request.idl
@@ -0,0 +1,112 @@ +// 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. + +// The <code>chrome.declarativeNetRequest</code> API is used to intercept and +// perform actions on a network request by specifying declarative rules. +namespace declarativeNetRequest { + // This describes the resource type of the network request. + enum ResourceType { + // TODO(crbug.com/696822): add main_frame, csp. + sub_frame, + stylesheet, + script, + image, + font, + object, + xmlhttprequest, + ping, + media, + websocket, + other + }; + + // This describes whether the request is first or third party to the frame in + // which it originated. A request is said to be first party if it has the same + // domain (eTLD+1) as the frame in which the request originated. + enum DomainType { + // The network request is first party to the frame in which it originated. + firstParty, + // The network request is third party to the frame in which it originated. + thirdParty + }; + + // Describes the kind of action to take if a given RuleCondition matches. + enum RuleActionType { + // Block the network request. + block, + // Redirect the network request. + redirect, + // Whitelist the network request. The request won't be blocked even if there + // is a blocking rule which matches it. + whitelist + }; + + dictionary RuleCondition { + + // The pattern which is matched against the network request url. + // Supported constructs: + // '*' : Wildcard: Matches any number of characters. + // '|' : Left/right anchor: If used at either end of the pattern, specifies + // the beginning/end of the url respectively. + // '||' : Domain name anchor: If used at the beginning of the pattern, + // specifies the start of a (sub-)domain of the URL. + // '^' : Separator character: This matches anything except a letter, a + // digit or one of the following: _ - . %. The end of the address is + // also accepted as a separator. + // Therefore urlFilter is composed of the following parts: + // (optional Left/Domain name anchor) + pattern + (optional Right anchor) + // If omitted, all urls are matched. An empty string is not allowed. + DOMString? urlFilter; + + // Whether the |urlFilter| is case sensitive. Default is false. + boolean? IsUrlFilterCaseSensitive; + + // The rule will only match network requests originating from the list of + // |domains|. If the list is omitted, the rule is applied to requests from + // all domains. An empty list is not allowed. + // Note: sub-domains like "a.example.com" are also allowed. + DOMString[]? domains; + + // The rule will not match network requests originating from the list of + // |excludedDomains|. If the list is empty or omitted, no domains are + // excluded. This takes precedence over |domains|. + // Note: sub-domains like "a.example.com" are also allowed. + DOMString[]? excludedDomains; + + // List of resource types which the rule can match. If the list is omitted, + // the rule is applied to all resource types. An empty list is not allowed. + ResourceType[]? resourceTypes; + + // List of resource types which the rule won't match. If the list is empty + // or omitted, no resource types are excluded. This takes precedence over + // |resourceTypes|. + ResourceType[]? excludedResourceTypes; + + // Specifies whether the network request is firstParty or thirdParty to the + // domain from which it originated. If omitted, all requests are accepted. + DomainType? domainType; + }; + + dictionary RuleAction { + // The type of action to perform. + RuleActionType type; + + // The redirect url. Only valid if |type| == 'redirect'. + DOMString? redirectUrl; + }; + + dictionary Rule { + // An id which uniquely identifies a rule. Mandatory and should be >= 1. + long id; + + // Rule priority. Mandatory for redirect rules and should be >= 1. + long? priority; + + // The condition which if satisfied causes the |action| to trigger. + RuleCondition condition; + + // The action to take if this rule is matched. + RuleAction action; + }; +};
diff --git a/extensions/common/api/schema.gni b/extensions/common/api/schema.gni index 0296e5fb..71d9679 100644 --- a/extensions/common/api/schema.gni +++ b/extensions/common/api/schema.gni
@@ -15,9 +15,10 @@ "bluetooth_socket.idl", "cast_channel.idl", "clipboard.idl", - "document_scan.idl", + "declarative_net_request.idl", "display_source.idl", "dns.idl", + "document_scan.idl", "events.json", "extensions_manifest_types.json", "extension_options_internal.idl",
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg index baa54579..e914c07 100644 --- a/infra/config/cq.cfg +++ b/infra/config/cq.cfg
@@ -73,16 +73,9 @@ experiment_percentage: 100 } # https://crbug.com/739556 - builders { - name: "ios-device-xcode-clang" - experiment_percentage: 100 - } + # builders { name: "ios-device-xcode-clang" } builders { name: "ios-simulator" } - # https://crbug.com/739556 - builders { - name: "ios-simulator-xcode-clang" - experiment_percentage: 100 - } + # builders { name: "ios-simulator-xcode-clang" } builders { name: "mac_chromium_compile_dbg_ng" } builders { name: "mac_chromium_rel_ng" } }
diff --git a/ios/chrome/browser/payments/BUILD.gn b/ios/chrome/browser/payments/BUILD.gn index 3c3ebc8..c4ce1d4 100644 --- a/ios/chrome/browser/payments/BUILD.gn +++ b/ios/chrome/browser/payments/BUILD.gn
@@ -9,6 +9,8 @@ sources = [ "ios_can_make_payment_query_factory.cc", "ios_can_make_payment_query_factory.h", + "ios_payment_instrument.h", + "ios_payment_instrument.mm", "ios_payment_request_cache_factory.h", "ios_payment_request_cache_factory.mm", "itunes_json_request.cc",
diff --git a/ios/chrome/browser/payments/ios_payment_instrument.h b/ios/chrome/browser/payments/ios_payment_instrument.h new file mode 100644 index 0000000..b683085 --- /dev/null +++ b/ios/chrome/browser/payments/ios_payment_instrument.h
@@ -0,0 +1,82 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_PAYMENTS_IOS_PAYMENT_INSTRUMENT_H_ +#define IOS_CHROME_BROWSER_PAYMENTS_IOS_PAYMENT_INSTRUMENT_H_ + +#import <UIKit/UIKit.h> + +#include <map> +#include <string> + +#import "base/mac/scoped_nsobject.h" +#include "base/macros.h" +#include "base/strings/string16.h" +#include "components/payments/core/payment_instrument.h" +#include "ios/chrome/browser/payments/payment_request.h" + +@class PaymentRequestUIDelegate; + +namespace payments { + +// A map is maintained to enumerate scheme names corresponding with iOS +// payment apps. These scheme names are needed as a form of installation +// check. If canOpenURL of UIApplication suceeds on the scheme name then +// that's a guarantee that the app is installed on the user's device. +// These scheme names MUST be enumerated in LSApplicationQueriesSchemes +// in the plist file. +const std::map<std::string, std::string>& GetMethodNameToSchemeName(); + +// Represents an iOS Native App as a form of payment in Payment Request. +class IOSPaymentInstrument : public PaymentInstrument { + public: + // Initializes an IOSPaymentInstrument. |method_name| is the url payment + // method identifier for this instrument. |universal_link| is the unique + // link that is used to open the app from Chrome. |app_name| is the name + // the iOS native payment app. The IOSPaymentInstrument takes ownership + // of |icon_image| which is an icon that represents the app. + // |payment_request_ui_delegate| is the UI class that manages opening + // the native payment app from Chrome. + IOSPaymentInstrument( + const std::string& method_name, + const std::string& universal_link, + const std::string& app_name, + UIImage* icon_image, + id<PaymentRequestUIDelegate> payment_request_ui_delegate); + + ~IOSPaymentInstrument() override; + + // PaymentInstrument: + void InvokePaymentApp(PaymentInstrument::Delegate* delegate) override; + bool IsCompleteForPayment() const override; + bool IsExactlyMatchingMerchantRequest() const override; + base::string16 GetMissingInfoLabel() const override; + bool IsValidForCanMakePayment() const override; + void RecordUse() override; + base::string16 GetLabel() const override; + base::string16 GetSublabel() const override; + bool IsValidForModifier( + const std::vector<std::string>& supported_methods, + const std::set<autofill::CreditCard::CardType>& supported_types, + const std::vector<std::string>& supported_networks) const override; + + // Given that the icon for the iOS payment instrument can only be determined + // at run-time, the icon is obtained using this UIImage object rather than + // using a resource ID and Chrome's resource bundle. + UIImage* icon_image() const { return icon_image_; } + + private: + std::string method_name_; + std::string universal_link_; + std::string app_name_; + base::scoped_nsobject<UIImage> icon_image_; + + id<PaymentRequestUIDelegate> payment_request_ui_delegate_; + + DISALLOW_COPY_AND_ASSIGN(IOSPaymentInstrument); +}; + +} // namespace payments + +#endif // IOS_CHROME_BROWSER_PAYMENTS_IOS_PAYMENT_INSTRUMENT_H_
diff --git a/ios/chrome/browser/payments/ios_payment_instrument.mm b/ios/chrome/browser/payments/ios_payment_instrument.mm new file mode 100644 index 0000000..a33911c3 --- /dev/null +++ b/ios/chrome/browser/payments/ios_payment_instrument.mm
@@ -0,0 +1,102 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/payments/ios_payment_instrument.h" + +#include "base/strings/utf_string_conversions.h" +#include "url/gurl.h" + +namespace payments { + +// URL payment method identifiers for iOS payment apps. +const char kBobpayPaymentMethodIdentifier[] = + "https://emerald-eon.appspot.com/bobpay"; + +// Scheme names for iOS payment apps. +const char kBobpaySchemeName[] = "bobpay://"; + +const std::map<std::string, std::string>& GetMethodNameToSchemeName() { + static const std::map<std::string, std::string> kMethodToScheme = + std::map<std::string, std::string>{ + {kBobpayPaymentMethodIdentifier, kBobpaySchemeName}, + }; + return kMethodToScheme; +} + +IOSPaymentInstrument::IOSPaymentInstrument( + const std::string& method_name, + const std::string& universal_link, + const std::string& app_name, + UIImage* icon_image, + id<PaymentRequestUIDelegate> payment_request_ui_delegate) + : PaymentInstrument(method_name, + -1 /* resource id not used */, + PaymentInstrument::Type::NATIVE_MOBILE_APP), + method_name_(method_name), + universal_link_(universal_link), + app_name_(app_name), + icon_image_(icon_image), + payment_request_ui_delegate_(payment_request_ui_delegate) {} +IOSPaymentInstrument::~IOSPaymentInstrument() {} + +void IOSPaymentInstrument::InvokePaymentApp( + PaymentInstrument::Delegate* delegate) { + DCHECK(delegate); + [payment_request_ui_delegate_ launchAppWithUniversalLink:universal_link_ + instrumentDelegate:delegate]; +} + +bool IOSPaymentInstrument::IsCompleteForPayment() const { + // As long as the native app is installed on the user's device it is + // always complete for payment. + return true; +} + +bool IOSPaymentInstrument::IsExactlyMatchingMerchantRequest() const { + // TODO(crbug.com/602666): Determine if the native payment app supports + // 'basic-card' if the merchant only accepts payment through credit cards. + return true; +} + +base::string16 IOSPaymentInstrument::GetMissingInfoLabel() const { + // This will always be an empty string because a native app cannot + // have incomplete information that can then be edited by the user. + return base::string16(); +} + +bool IOSPaymentInstrument::IsValidForCanMakePayment() const { + // Same as IsCompleteForPayment, as long as the native app is installed + // and found on the user's device then it is valid for payment. + return true; +} + +void IOSPaymentInstrument::RecordUse() { + // TODO(crbug.com/60266): Record the use of the native payment app. +} + +base::string16 IOSPaymentInstrument::GetLabel() const { + return base::ASCIIToUTF16(app_name_); +} + +base::string16 IOSPaymentInstrument::GetSublabel() const { + // Return host of |method_name_| e.g., paypal.com. + return base::ASCIIToUTF16(GURL(method_name_).host()); +} + +bool IOSPaymentInstrument::IsValidForModifier( + const std::vector<std::string>& supported_methods, + const std::set<autofill::CreditCard::CardType>& supported_types, + const std::vector<std::string>& supported_networks) const { + // This instrument only matches url-based payment method identifiers that + // are equal to the instrument's method name. + if (std::find(supported_methods.begin(), supported_methods.end(), + method_name_) == supported_methods.end()) + return false; + + // TODO(crbug.com/602666): Determine if the native payment app supports + // 'basic-card' if 'basic-card' is the specified modifier. + return true; +} + +} // namespace payments
diff --git a/ios/chrome/browser/payments/payment_request.h b/ios/chrome/browser/payments/payment_request.h index f149e1d..0fb989db 100644 --- a/ios/chrome/browser/payments/payment_request.h +++ b/ios/chrome/browser/payments/payment_request.h
@@ -17,6 +17,7 @@ #include "components/payments/core/address_normalization_manager.h" #include "components/payments/core/address_normalizer_impl.h" #include "components/payments/core/journey_logger.h" +#include "components/payments/core/payment_instrument.h" #include "components/payments/core/payment_options_provider.h" #include "components/payments/core/payment_request_base_delegate.h" #include "components/payments/core/payments_profile_comparator.h" @@ -31,7 +32,6 @@ namespace payments { class AddressNormalizer; class CurrencyFormatter; -class PaymentInstrument; class AutofillPaymentInstrument; } // namespace payments @@ -54,6 +54,10 @@ (base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>) resultDelegate; +- (void)launchAppWithUniversalLink:(std::string)universalLink + instrumentDelegate: + (payments::PaymentInstrument::Delegate*)instrumentDelegate; + @end namespace payments {
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm index 592c386..499e82c 100644 --- a/ios/chrome/browser/payments/payment_request.mm +++ b/ios/chrome/browser/payments/payment_request.mm
@@ -18,7 +18,6 @@ #include "components/autofill/core/browser/validation.h" #include "components/payments/core/autofill_payment_instrument.h" #include "components/payments/core/currency_formatter.h" -#include "components/payments/core/payment_instrument.h" #include "components/payments/core/payment_request_data_util.h" #include "components/prefs/pref_service.h" #include "components/signin/core/browser/signin_manager.h"
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm index 6f6d3522..37f01b4a 100644 --- a/ios/chrome/browser/ui/payments/payment_request_manager.mm +++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -27,6 +27,7 @@ #include "components/payments/core/can_make_payment_query.h" #include "components/payments/core/journey_logger.h" #include "components/payments/core/payment_address.h" +#include "components/payments/core/payment_instrument.h" #include "components/payments/core/payment_prefs.h" #include "components/payments/core/payment_request_base_delegate.h" #include "components/payments/core/payment_request_data_util.h" @@ -760,6 +761,14 @@ resultDelegate:resultDelegate]; } +- (void)launchAppWithUniversalLink:(std::string)universalLink + instrumentDelegate: + (payments::PaymentInstrument::Delegate*)instrumentDelegate { + // TODO(crbug.com/748556): Implement this function to use a native app's + // universal link to open it from Chrome with several arguments supplied + // from the Payment Request object. +} + #pragma mark - PaymentRequestCoordinatorDelegate methods - (void)paymentRequestCoordinatorDidCancel:
diff --git a/ipc/ipc_mojo_perftest.cc b/ipc/ipc_mojo_perftest.cc index 8513e08..6f11a772 100644 --- a/ipc/ipc_mojo_perftest.cc +++ b/ipc/ipc_mojo_perftest.cc
@@ -12,8 +12,7 @@ #include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/test/perf_time_logger.h" -#include "base/test/test_io_thread.h" -#include "base/threading/thread_task_runner_handle.h" +#include "base/threading/thread.h" #include "build/build_config.h" #include "ipc/ipc_channel_mojo.h" #include "ipc/ipc_sync_channel.h" @@ -39,6 +38,12 @@ namespace IPC { namespace { +scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() { + scoped_refptr<base::TaskRunner> runner = mojo::edk::GetIOTaskRunner(); + return scoped_refptr<base::SingleThreadTaskRunner>( + static_cast<base::SingleThreadTaskRunner*>(runner.get())); +} + class PerformanceChannelListener : public Listener { public: explicit PerformanceChannelListener(const std::string& label) @@ -266,15 +271,13 @@ ~MojoChannelPerfTest() override = default; void RunTestChannelProxyPingPong() { - io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart)); - Init("MojoPerfTestClient"); // Set up IPC channel and start client. PerformanceChannelListener listener("ChannelProxy"); auto channel_proxy = IPC::ChannelProxy::Create( TakeHandle().release(), IPC::Channel::MODE_SERVER, &listener, - io_thread_->task_runner()); + GetIOThreadTaskRunner()); listener.Init(channel_proxy.get()); LockThreadAffinity thread_locker(kSharedCore); @@ -295,13 +298,9 @@ EXPECT_TRUE(WaitForClientShutdown()); channel_proxy.reset(); - - io_thread_.reset(); } void RunTestChannelProxySyncPing() { - io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart)); - Init("MojoPerfTestClient"); // Set up IPC channel and start client. @@ -311,7 +310,7 @@ base::WaitableEvent::InitialState::NOT_SIGNALED); auto channel_proxy = IPC::SyncChannel::Create( TakeHandle().release(), IPC::Channel::MODE_SERVER, &listener, - io_thread_->task_runner(), false, &shutdown_event); + GetIOThreadTaskRunner(), false, &shutdown_event); listener.Init(channel_proxy.get()); LockThreadAffinity thread_locker(kSharedCore); @@ -332,18 +331,7 @@ EXPECT_TRUE(WaitForClientShutdown()); channel_proxy.reset(); - - io_thread_.reset(); } - - scoped_refptr<base::TaskRunner> io_task_runner() { - if (io_thread_) - return io_thread_->task_runner(); - return base::ThreadTaskRunnerHandle::Get(); - } - - private: - std::unique_ptr<base::TestIOThread> io_thread_; }; TEST_F(MojoChannelPerfTest, ChannelProxyPingPong) { @@ -371,11 +359,10 @@ int Run(MojoHandle handle) { handle_ = mojo::MakeScopedHandle(mojo::MessagePipeHandle(handle)); LockThreadAffinity thread_locker(kSharedCore); - base::TestIOThread io_thread(base::TestIOThread::kAutoStart); std::unique_ptr<ChannelProxy> channel = IPC::ChannelProxy::Create(handle_.release(), Channel::MODE_CLIENT, - listener_.get(), io_thread.task_runner()); + listener_.get(), GetIOThreadTaskRunner()); listener_->Init(channel.get()); base::RunLoop().Run();
diff --git a/media/base/media_observer.h b/media/base/media_observer.h index 3d293932..f82c387 100644 --- a/media/base/media_observer.h +++ b/media/base/media_observer.h
@@ -35,10 +35,6 @@ MediaObserver(); virtual ~MediaObserver(); - // Called when the media element entered/exited fullscreen. - virtual void OnEnteredFullscreen() = 0; - virtual void OnExitedFullscreen() = 0; - // Called when the media element starts/stops being the dominant visible // content. virtual void OnBecameDominantVisibleContent(bool is_dominant) {}
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index 9d2510f..52410d7 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -416,8 +416,6 @@ DoesOverlaySupportMetadata()) { EnableOverlay(); } - if (observer_) - observer_->OnEnteredFullscreen(); // We send this only if we can send multiple calls. Otherwise, either (a) // we already sent it and we don't have a callback anyway (we reset it when @@ -437,8 +435,6 @@ // overlay mode all the time. if (!force_video_overlays_ && overlay_enabled_) DisableOverlay(); - if (observer_) - observer_->OnExitedFullscreen(); // See EnteredFullscreen for why we do this. if (!decoder_requires_restart_for_overlay_)
diff --git a/media/filters/audio_video_metadata_extractor.cc b/media/filters/audio_video_metadata_extractor.cc index f97cfe9..bb67967 100644 --- a/media/filters/audio_video_metadata_extractor.cc +++ b/media/filters/audio_video_metadata_extractor.cc
@@ -63,6 +63,7 @@ AudioVideoMetadataExtractor::AudioVideoMetadataExtractor() : extracted_(false), + has_duration_(false), duration_(-1), width_(-1), height_(-1), @@ -93,8 +94,10 @@ if (avformat_find_stream_info(format_context, NULL) < 0) return false; - if (format_context->duration != AV_NOPTS_VALUE) + if (format_context->duration != AV_NOPTS_VALUE) { duration_ = static_cast<double>(format_context->duration) / AV_TIME_BASE; + has_duration_ = true; + } stream_infos_.push_back(StreamInfo()); StreamInfo& container_info = stream_infos_.back(); @@ -142,8 +145,14 @@ return true; } +bool AudioVideoMetadataExtractor::has_duration() const { + DCHECK(extracted_); + return has_duration_; +} + double AudioVideoMetadataExtractor::duration() const { DCHECK(extracted_); + DCHECK(has_duration_); return duration_; }
diff --git a/media/filters/audio_video_metadata_extractor.h b/media/filters/audio_video_metadata_extractor.h index 4e5906d..4257933 100644 --- a/media/filters/audio_video_metadata_extractor.h +++ b/media/filters/audio_video_metadata_extractor.h
@@ -41,7 +41,12 @@ // be called once. bool Extract(DataSource* source, bool extract_attached_pics); - // Returns -1 if we cannot extract the duration. In seconds. + // Returns whether or not duration information was extracted. Do not call + // duration() if this returns false. + bool has_duration() const; + + // Returns the duration in seconds. Value is undefined if has_duration() + // returns false. double duration() const; // Returns -1 for containers without video. @@ -77,7 +82,8 @@ bool extracted_; - int duration_; + bool has_duration_; + double duration_; // Valid only if |has_duration_| is true. int width_; int height_;
diff --git a/media/filters/audio_video_metadata_extractor_unittest.cc b/media/filters/audio_video_metadata_extractor_unittest.cc index b1f41654..9446ed3 100644 --- a/media/filters/audio_video_metadata_extractor_unittest.cc +++ b/media/filters/audio_video_metadata_extractor_unittest.cc
@@ -34,6 +34,7 @@ if (!extracted) return extractor; + EXPECT_TRUE(extractor->has_duration()); EXPECT_EQ(expected_duration, extractor->duration()); EXPECT_EQ(expected_width, extractor->width()); @@ -54,10 +55,8 @@ } TEST(AudioVideoMetadataExtractorTest, AudioOGG) { - // TODO(tommycli): Actual duration is 0.1, but |extractor| converts this - // internally to an integer. See https://crbug.com/747480. std::unique_ptr<AudioVideoMetadataExtractor> extractor = - GetExtractor("9ch.ogg", true, true, 0, -1, -1); + GetExtractor("9ch.ogg", true, true, 0.1, -1, -1); EXPECT_EQ("Processed by SoX", extractor->comment()); EXPECT_EQ("ogg", extractor->stream_infos()[0].type); @@ -74,10 +73,8 @@ } TEST(AudioVideoMetadataExtractorTest, AudioWAV) { - // TODO(tommycli): Actual duration is 0.288413, but |extractor| converts this - // internally to an integer. See https://crbug.com/747480. std::unique_ptr<AudioVideoMetadataExtractor> extractor = - GetExtractor("sfx_u8.wav", true, true, 0, -1, -1); + GetExtractor("sfx_u8.wav", true, true, 0.288413, -1, -1); EXPECT_EQ("Lavf54.37.100", extractor->encoder()); EXPECT_EQ("Amadeus Pro", extractor->encoded_by()); @@ -97,10 +94,8 @@ } TEST(AudioVideoMetadataExtractorTest, AudioFLAC) { - // TODO(tommycli): Actual duration is 0.288413, but |extractor| converts this - // internally to an integer. See https://crbug.com/747480. std::unique_ptr<AudioVideoMetadataExtractor> extractor = - GetExtractor("sfx.flac", true, true, 0, -1, -1); + GetExtractor("sfx.flac", true, true, 0.288413, -1, -1); EXPECT_EQ("Lavf55.43.100", extractor->encoder()); EXPECT_EQ("Amadeus Pro", extractor->encoded_by()); @@ -120,10 +115,8 @@ } TEST(AudioVideoMetadataExtractorTest, VideoWebM) { - // TODO(tommycli): Actual duration is 2.744, but |extractor| converts this - // internally to an integer. See https://crbug.com/747480. std::unique_ptr<AudioVideoMetadataExtractor> extractor = - GetExtractor("bear-320x240-multitrack.webm", true, true, 2, 320, 240); + GetExtractor("bear-320x240-multitrack.webm", true, true, 2.744, 320, 240); EXPECT_EQ("Lavf53.9.0", extractor->encoder()); EXPECT_EQ(6u, extractor->stream_infos().size()); @@ -155,10 +148,8 @@ #if BUILDFLAG(USE_PROPRIETARY_CODECS) TEST(AudioVideoMetadataExtractorTest, AndroidRotatedMP4Video) { - // TODO(tommycli): Actual duration is 0.196, but |extractor| converts this - // internally to an integer. See https://crbug.com/747480. std::unique_ptr<AudioVideoMetadataExtractor> extractor = - GetExtractor("90rotation.mp4", true, true, 0, 1920, 1080); + GetExtractor("90rotation.mp4", true, true, 0.196, 1920, 1080); EXPECT_EQ(90, extractor->rotation()); @@ -196,10 +187,8 @@ } TEST(AudioVideoMetadataExtractorTest, AudioMP3) { - // TODO(tommycli): Actual duration is 1.01878, but |extractor| converts this - // internally to an integer. See https://crbug.com/747480. std::unique_ptr<AudioVideoMetadataExtractor> extractor = - GetExtractor("id3_png_test.mp3", true, true, 1, -1, -1); + GetExtractor("id3_png_test.mp3", true, true, 1.018776, -1, -1); EXPECT_EQ("Airbag", extractor->title()); EXPECT_EQ("Radiohead", extractor->artist()); @@ -245,10 +234,8 @@ } TEST(AudioVideoMetadataExtractorTest, AudioFLACInMp4) { - // TODO(tommycli): Actual duration is 0.289, but |extractor| converts this - // internally to an integer. See https://crbug.com/747480. std::unique_ptr<AudioVideoMetadataExtractor> extractor = - GetExtractor("sfx-flac.mp4", true, true, 0, -1, -1); + GetExtractor("sfx-flac.mp4", true, true, 0.289, -1, -1); EXPECT_EQ("Lavf57.75.100", extractor->encoder()); EXPECT_EQ("mov,mp4,m4a,3gp,3g2,mj2", extractor->stream_infos()[0].type);
diff --git a/media/remoting/renderer_controller.cc b/media/remoting/renderer_controller.cc index e469530..2e26ecfeb 100644 --- a/media/remoting/renderer_controller.cc +++ b/media/remoting/renderer_controller.cc
@@ -19,6 +19,12 @@ namespace media { namespace remoting { +namespace { +// The duration to delay the start of media remoting to ensure all preconditions +// are held stable before switching to media remoting. +constexpr base::TimeDelta kDelayedStart = base::TimeDelta::FromSeconds(5); +} // namespace + RendererController::RendererController(scoped_refptr<SharedSession> session) : session_(std::move(session)), weak_factory_(this) { session_->AddClient(this); @@ -38,7 +44,6 @@ DCHECK(thread_checker_.CalledOnValidThread()); if (success) { - VLOG(1) << "Remoting started successively."; if (remote_rendering_started_) { metrics_recorder_.DidStartSession(); DCHECK(client_); @@ -61,13 +66,10 @@ void RendererController::UpdateFromSessionState(StartTrigger start_trigger, StopTrigger stop_trigger) { VLOG(1) << "UpdateFromSessionState: " << session_->state(); - if (client_) - client_->ActivateViewportIntersectionMonitoring(IsRemoteSinkAvailable()); - UpdateAndMaybeSwitch(start_trigger, stop_trigger); } -bool RendererController::IsRemoteSinkAvailable() { +bool RendererController::IsRemoteSinkAvailable() const { DCHECK(thread_checker_.CalledOnValidThread()); switch (session_->state()) { @@ -85,43 +87,11 @@ return false; // To suppress compiler warning on Windows. } -void RendererController::OnEnteredFullscreen() { - DCHECK(thread_checker_.CalledOnValidThread()); - - is_fullscreen_ = true; - // See notes in OnBecameDominantVisibleContent() for why this is forced: - is_dominant_content_ = true; - UpdateAndMaybeSwitch(ENTERED_FULLSCREEN, UNKNOWN_STOP_TRIGGER); -} - -void RendererController::OnExitedFullscreen() { - DCHECK(thread_checker_.CalledOnValidThread()); - - is_fullscreen_ = false; - // See notes in OnBecameDominantVisibleContent() for why this is forced: - is_dominant_content_ = false; - UpdateAndMaybeSwitch(UNKNOWN_START_TRIGGER, EXITED_FULLSCREEN); -} - void RendererController::OnBecameDominantVisibleContent(bool is_dominant) { DCHECK(thread_checker_.CalledOnValidThread()); - // Two scenarios where "dominance" status mixes with fullscreen transitions: - // - // 1. Just before/after entering fullscreen, the element will, of course, - // become the dominant on-screen content via automatic page layout. - // 2. Just before/after exiting fullscreen, the element may or may not - // shrink in size enough to become non-dominant. However, exiting - // fullscreen was caused by a user action that explicitly indicates a - // desire to exit remoting, so even if the element is still dominant, - // remoting should be shut down. - // - // Thus, to achieve the desired behaviors, |is_dominant_content_| is force-set - // in OnEnteredFullscreen() and OnExitedFullscreen(), and changes to it here - // are ignored while in fullscreen. - if (is_fullscreen_) + if (is_dominant_content_ == is_dominant) return; - is_dominant_content_ = is_dominant; UpdateAndMaybeSwitch(BECAME_DOMINANT_CONTENT, BECAME_AUXILIARY_CONTENT); } @@ -240,7 +210,7 @@ client_->UpdateRemotePlaybackCompatibility(is_source_supported); } -bool RendererController::IsVideoCodecSupported() { +bool RendererController::IsVideoCodecSupported() const { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(has_video()); @@ -264,7 +234,7 @@ } } -bool RendererController::IsAudioCodecSupported() { +bool RendererController::IsAudioCodecSupported() const { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(has_audio()); @@ -309,9 +279,11 @@ DCHECK(thread_checker_.CalledOnValidThread()); is_paused_ = true; + // Cancel the start if in the middle of delayed start. + CancelDelayedStart(); } -bool RendererController::ShouldBeRemoting() { +bool RendererController::CanBeRemoting() const { DCHECK(thread_checker_.CalledOnValidThread()); if (!client_) { @@ -355,13 +327,10 @@ if (is_remote_playback_disabled_) return false; - // Normally, entering fullscreen or being the dominant visible content is the - // signal that starts remote rendering. However, current technical limitations - // require encrypted content be remoted without waiting for a user signal. - return is_fullscreen_ || is_dominant_content_; + return true; } -bool RendererController::IsAudioOrVideoSupported() { +bool RendererController::IsAudioOrVideoSupported() const { if ((!has_audio() && !has_video()) || (has_video() && !IsVideoCodecSupported()) || (has_audio() && !IsAudioCodecSupported())) { @@ -375,11 +344,28 @@ StopTrigger stop_trigger) { DCHECK(thread_checker_.CalledOnValidThread()); - bool should_be_remoting = ShouldBeRemoting(); + bool should_be_remoting = CanBeRemoting(); + if (!is_encrypted_ && client_) + client_->ActivateViewportIntersectionMonitoring(should_be_remoting); - if (remote_rendering_started_ == should_be_remoting) + // Normally, being the dominant visible content is the signal that starts + // remote rendering. However, current technical limitations require encrypted + // content be remoted without waiting for a user signal. + if (!is_encrypted_) + should_be_remoting &= is_dominant_content_; + + if ((remote_rendering_started_ || + delayed_start_stability_timer_.IsRunning()) == should_be_remoting) return; + DCHECK(client_); + + if (is_encrypted_) { + DCHECK(should_be_remoting); + StartRemoting(start_trigger); + return; + } + // Only switch to remoting when media is playing. Since the renderer is // created when video starts loading/playing, receiver will display a black // screen before video starts playing if switching to remoting when paused. @@ -388,22 +374,13 @@ if (should_be_remoting && is_paused_) return; - // Switch between local renderer and remoting renderer. - remote_rendering_started_ = should_be_remoting; - - DCHECK(client_); - if (remote_rendering_started_) { - if (session_->state() == SharedSession::SESSION_PERMANENTLY_STOPPED) { - client_->SwitchRenderer(true); - return; - } - DCHECK_NE(start_trigger, UNKNOWN_START_TRIGGER); - metrics_recorder_.WillStartSession(start_trigger); - VLOG(2) << "Request to start remoting: start_trigger=" << start_trigger; - // |MediaObserverClient::SwitchRenderer()| will be called after remoting is - // started successfully. - session_->StartRemoting(this); + if (should_be_remoting) { + WaitForStabilityBeforeStart(start_trigger); + } else if (delayed_start_stability_timer_.IsRunning()) { + DCHECK(!remote_rendering_started_); + CancelDelayedStart(); } else { + remote_rendering_started_ = false; // For encrypted content, it's only valid to switch to remoting renderer, // and never back to the local renderer. The RemotingCdmController will // force-stop the session when remoting has ended; so no need to call @@ -417,6 +394,50 @@ } } +void RendererController::WaitForStabilityBeforeStart( + StartTrigger start_trigger) { + DCHECK(!delayed_start_stability_timer_.IsRunning()); + DCHECK(!remote_rendering_started_); + DCHECK(!is_encrypted_); + delayed_start_stability_timer_.Start( + FROM_HERE, kDelayedStart, + base::Bind(&RendererController::OnDelayedStartTimerFired, + base::Unretained(this), start_trigger)); + + // TODO(xjz): Start content bitrate estimation. +} + +void RendererController::CancelDelayedStart() { + delayed_start_stability_timer_.Stop(); + + // TODO(xjz): Stop content bitrate estimation. +} + +void RendererController::OnDelayedStartTimerFired(StartTrigger start_trigger) { + DCHECK(is_dominant_content_); + DCHECK(!remote_rendering_started_); + DCHECK(!is_encrypted_); + + // TODO(xjz): Stop content bitrate estimation and evaluate whether the + // estimated bitrate is supported by remoting. + + StartRemoting(start_trigger); +} + +void RendererController::StartRemoting(StartTrigger start_trigger) { + DCHECK(client_); + remote_rendering_started_ = true; + if (session_->state() == SharedSession::SESSION_PERMANENTLY_STOPPED) { + client_->SwitchRenderer(true); + return; + } + DCHECK_NE(start_trigger, UNKNOWN_START_TRIGGER); + metrics_recorder_.WillStartSession(start_trigger); + // |MediaObserverClient::SwitchRenderer()| will be called after remoting is + // started successfully. + session_->StartRemoting(this); +} + void RendererController::OnRendererFatalError(StopTrigger stop_trigger) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -435,7 +456,8 @@ DCHECK(!client_); client_ = client; - client_->ActivateViewportIntersectionMonitoring(IsRemoteSinkAvailable()); + if (!is_encrypted_) + client_->ActivateViewportIntersectionMonitoring(CanBeRemoting()); } } // namespace remoting
diff --git a/media/remoting/renderer_controller.h b/media/remoting/renderer_controller.h index c69ca4e..4b3cf03 100644 --- a/media/remoting/renderer_controller.h +++ b/media/remoting/renderer_controller.h
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" +#include "base/timer/timer.h" #include "media/base/media_observer.h" #include "media/remoting/metrics.h" #include "media/remoting/shared_session.h" @@ -36,8 +37,6 @@ void OnSessionStateChanged() override; // MediaObserver implementation. - void OnEnteredFullscreen() override; - void OnExitedFullscreen() override; void OnBecameDominantVisibleContent(bool is_dominant) override; void OnSetCdm(CdmContext* cdm_context) override; void OnMetadataChanged(const PipelineMetadata& metadata) override; @@ -73,6 +72,8 @@ void OnRendererFatalError(StopTrigger stop_trigger); private: + friend class RendererControllerTest; + bool has_audio() const { return pipeline_metadata_.has_audio && pipeline_metadata_.audio_decoder_config.IsValidConfig(); @@ -89,13 +90,16 @@ void UpdateFromSessionState(StartTrigger start_trigger, StopTrigger stop_trigger); - bool IsVideoCodecSupported(); - bool IsAudioCodecSupported(); - bool IsRemoteSinkAvailable(); - bool IsAudioOrVideoSupported(); + bool IsVideoCodecSupported() const; + bool IsAudioCodecSupported() const; + bool IsRemoteSinkAvailable() const; + bool IsAudioOrVideoSupported() const; - // Helper to decide whether to enter or leave Remoting mode. - bool ShouldBeRemoting(); + // Returns true if all of the technical requirements for the media pipeline + // and remote rendering are being met. This does not include environmental + // conditions, such as the content being dominant in the viewport, available + // network bandwidth, etc. + bool CanBeRemoting() const; // Determines whether to enter or leave Remoting mode and switches if // necessary. Each call to this method could cause a remoting session to be @@ -108,8 +112,16 @@ // the element is compatible with Remote Playback API. void UpdateRemotePlaybackAvailabilityMonitoringState(); - // Indicates whether this media element is in full screen. - bool is_fullscreen_ = false; + // Start |delayed_start_stability_timer_| to ensure all preconditions are met + // and held stable for a short time before starting remoting. + void WaitForStabilityBeforeStart(StartTrigger start_trigger); + // Cancel the start of remoting. + void CancelDelayedStart(); + // Called when |delayed_start_stability_timer_| is fired. + void OnDelayedStartTimerFired(StartTrigger start_trigger); + + // Helper to request the media pipeline switch to the remoting renderer. + void StartRemoting(StartTrigger start_trigger); // Indicates whether remoting is started. bool remote_rendering_started_ = false; @@ -161,6 +173,13 @@ // Not owned by this class. Can only be set once by calling SetClient(). MediaObserverClient* client_ = nullptr; + // When this is running, it indicates that remoting will be started later + // when the timer gets fired. The start will be canceled if there is any + // precondition change that does not allow for remoting duting this period. + // TODO(xjz): Estimate whether the transmission bandwidth is sufficient to + // remote the content while this timer is running. + base::OneShotTimer delayed_start_stability_timer_; + base::WeakPtrFactory<RendererController> weak_factory_; DISALLOW_COPY_AND_ASSIGN(RendererController);
diff --git a/media/remoting/renderer_controller_unittest.cc b/media/remoting/renderer_controller_unittest.cc index 5f2deaac..39f44e0 100644 --- a/media/remoting/renderer_controller_unittest.cc +++ b/media/remoting/renderer_controller_unittest.cc
@@ -82,7 +82,7 @@ void CreateCdm(bool is_remoting) { is_remoting_cdm_ = is_remoting; } - void InitializeControllerAndEnterFullscreen( + void InitializeControllerAndBecomeDominant( const scoped_refptr<SharedSession> shared_session, const PipelineMetadata& pipeline_metadata, const mojom::RemotingSinkMetadata& sink_metadata) { @@ -105,7 +105,7 @@ RunUntilIdle(); EXPECT_FALSE(is_rendering_remotely_); EXPECT_FALSE(disable_pipeline_suspend_); - controller_->OnEnteredFullscreen(); + controller_->OnBecameDominantVisibleContent(true); RunUntilIdle(); EXPECT_FALSE(is_rendering_remotely_); EXPECT_FALSE(disable_pipeline_suspend_); @@ -113,6 +113,18 @@ RunUntilIdle(); } + bool IsInDelayedStart() { + return controller_->delayed_start_stability_timer_.IsRunning(); + } + + void DelayedStartEnds() { + EXPECT_TRUE(IsInDelayedStart()); + const base::Closure callback = + controller_->delayed_start_stability_timer_.user_task(); + callback.Run(); + controller_->delayed_start_stability_timer_.Stop(); + } + base::MessageLoop message_loop_; protected: @@ -126,35 +138,38 @@ DISALLOW_COPY_AND_ASSIGN(RendererControllerTest); }; -TEST_F(RendererControllerTest, ToggleRendererOnFullscreenChange) { +TEST_F(RendererControllerTest, ToggleRendererOnDominantChange) { const scoped_refptr<SharedSession> shared_session = FakeRemoterFactory::CreateSharedSession(false); - InitializeControllerAndEnterFullscreen(shared_session, - DefaultMetadata(VideoCodec::kCodecVP8), - GetDefaultSinkMetadata(true)); - EXPECT_TRUE(activate_viewport_intersection_monitoring_); + InitializeControllerAndBecomeDominant(shared_session, + DefaultMetadata(VideoCodec::kCodecVP8), + GetDefaultSinkMetadata(true)); + EXPECT_FALSE(is_rendering_remotely_); + EXPECT_TRUE(IsInDelayedStart()); + DelayedStartEnds(); + RunUntilIdle(); EXPECT_TRUE(is_rendering_remotely_); // All requirements now satisfied. EXPECT_TRUE(disable_pipeline_suspend_); // Leaving fullscreen should shut down remoting. - controller_->OnExitedFullscreen(); + controller_->OnBecameDominantVisibleContent(false); RunUntilIdle(); EXPECT_FALSE(is_rendering_remotely_); - EXPECT_FALSE(activate_viewport_intersection_monitoring_); EXPECT_FALSE(disable_pipeline_suspend_); + EXPECT_FALSE(activate_viewport_intersection_monitoring_); } TEST_F(RendererControllerTest, ToggleRendererOnSinkCapabilities) { EXPECT_FALSE(is_rendering_remotely_); const scoped_refptr<SharedSession> shared_session = FakeRemoterFactory::CreateSharedSession(false); - InitializeControllerAndEnterFullscreen(shared_session, - DefaultMetadata(VideoCodec::kCodecVP8), - GetDefaultSinkMetadata(false)); + InitializeControllerAndBecomeDominant(shared_session, + DefaultMetadata(VideoCodec::kCodecVP8), + GetDefaultSinkMetadata(false)); // An available sink that does not support remote rendering should not cause // the controller to toggle remote rendering on. - EXPECT_FALSE(activate_viewport_intersection_monitoring_); EXPECT_FALSE(is_rendering_remotely_); + EXPECT_FALSE(activate_viewport_intersection_monitoring_); shared_session->OnSinkGone(); // Bye-bye useless sink! RunUntilIdle(); EXPECT_FALSE(is_rendering_remotely_); @@ -164,8 +179,16 @@ // toggle remote rendering on. shared_session->OnSinkAvailable(GetDefaultSinkMetadata(true).Clone()); RunUntilIdle(); - EXPECT_TRUE(is_rendering_remotely_); EXPECT_TRUE(activate_viewport_intersection_monitoring_); + EXPECT_FALSE(is_rendering_remotely_); + controller_->OnBecameDominantVisibleContent(true); + RunUntilIdle(); + EXPECT_FALSE(is_rendering_remotely_); + EXPECT_FALSE(disable_pipeline_suspend_); + EXPECT_TRUE(IsInDelayedStart()); + DelayedStartEnds(); + RunUntilIdle(); + EXPECT_TRUE(is_rendering_remotely_); EXPECT_TRUE(disable_pipeline_suspend_); } @@ -173,11 +196,14 @@ EXPECT_FALSE(is_rendering_remotely_); const scoped_refptr<SharedSession> shared_session = FakeRemoterFactory::CreateSharedSession(false); - InitializeControllerAndEnterFullscreen(shared_session, - DefaultMetadata(VideoCodec::kCodecVP8), - GetDefaultSinkMetadata(true)); - EXPECT_TRUE(is_rendering_remotely_); // All requirements now satisfied. + InitializeControllerAndBecomeDominant(shared_session, + DefaultMetadata(VideoCodec::kCodecVP8), + GetDefaultSinkMetadata(true)); EXPECT_TRUE(activate_viewport_intersection_monitoring_); + EXPECT_TRUE(IsInDelayedStart()); + DelayedStartEnds(); + RunUntilIdle(); + EXPECT_TRUE(is_rendering_remotely_); // All requirements now satisfied. EXPECT_TRUE(disable_pipeline_suspend_); // If the page disables remote playback (e.g., by setting the @@ -192,20 +218,16 @@ TEST_F(RendererControllerTest, WithVP9VideoCodec) { const scoped_refptr<SharedSession> shared_session = FakeRemoterFactory::CreateSharedSession(false); - InitializeControllerAndEnterFullscreen(shared_session, - DefaultMetadata(VideoCodec::kCodecVP9), - GetDefaultSinkMetadata(true)); + InitializeControllerAndBecomeDominant(shared_session, + DefaultMetadata(VideoCodec::kCodecVP9), + GetDefaultSinkMetadata(true)); // An available sink that does not support VP9 video codec should not cause // the controller to toggle remote rendering on. EXPECT_FALSE(is_rendering_remotely_); - EXPECT_TRUE(activate_viewport_intersection_monitoring_); EXPECT_FALSE(disable_pipeline_suspend_); + EXPECT_FALSE(activate_viewport_intersection_monitoring_); shared_session->OnSinkGone(); // Bye-bye useless sink! - RunUntilIdle(); - EXPECT_FALSE(is_rendering_remotely_); - EXPECT_FALSE(activate_viewport_intersection_monitoring_); - EXPECT_FALSE(disable_pipeline_suspend_); mojom::RemotingSinkMetadata sink_metadata = GetDefaultSinkMetadata(true); sink_metadata.video_capabilities.push_back( mojom::RemotingSinkVideoCapability::CODEC_VP9); @@ -213,6 +235,9 @@ // toggle remote rendering on. shared_session->OnSinkAvailable(sink_metadata.Clone()); RunUntilIdle(); + EXPECT_TRUE(IsInDelayedStart()); + DelayedStartEnds(); + RunUntilIdle(); EXPECT_TRUE(is_rendering_remotely_); // All requirements now satisfied. EXPECT_TRUE(activate_viewport_intersection_monitoring_); EXPECT_TRUE(disable_pipeline_suspend_); @@ -221,13 +246,13 @@ TEST_F(RendererControllerTest, WithHEVCVideoCodec) { const scoped_refptr<SharedSession> shared_session = FakeRemoterFactory::CreateSharedSession(false); - InitializeControllerAndEnterFullscreen( - shared_session, DefaultMetadata(VideoCodec::kCodecHEVC), - GetDefaultSinkMetadata(true)); + InitializeControllerAndBecomeDominant(shared_session, + DefaultMetadata(VideoCodec::kCodecHEVC), + GetDefaultSinkMetadata(true)); // An available sink that does not support HEVC video codec should not cause // the controller to toggle remote rendering on. EXPECT_FALSE(is_rendering_remotely_); - EXPECT_TRUE(activate_viewport_intersection_monitoring_); + EXPECT_FALSE(activate_viewport_intersection_monitoring_); EXPECT_FALSE(disable_pipeline_suspend_); shared_session->OnSinkGone(); // Bye-bye useless sink! @@ -242,6 +267,9 @@ // toggle remote rendering on. shared_session->OnSinkAvailable(sink_metadata.Clone()); RunUntilIdle(); + EXPECT_TRUE(IsInDelayedStart()); + DelayedStartEnds(); + RunUntilIdle(); EXPECT_TRUE(is_rendering_remotely_); // All requirements now satisfied. EXPECT_TRUE(activate_viewport_intersection_monitoring_); EXPECT_TRUE(disable_pipeline_suspend_); @@ -255,18 +283,17 @@ 44100, EmptyExtraData(), Unencrypted()); PipelineMetadata pipeline_metadata = DefaultMetadata(VideoCodec::kCodecVP8); pipeline_metadata.audio_decoder_config = audio_config; - InitializeControllerAndEnterFullscreen(shared_session, pipeline_metadata, - GetDefaultSinkMetadata(true)); + InitializeControllerAndBecomeDominant(shared_session, pipeline_metadata, + GetDefaultSinkMetadata(true)); // An available sink that does not support AAC audio codec should not cause // the controller to toggle remote rendering on. EXPECT_FALSE(is_rendering_remotely_); - EXPECT_TRUE(activate_viewport_intersection_monitoring_); EXPECT_FALSE(disable_pipeline_suspend_); + EXPECT_FALSE(activate_viewport_intersection_monitoring_); shared_session->OnSinkGone(); // Bye-bye useless sink! RunUntilIdle(); EXPECT_FALSE(is_rendering_remotely_); - EXPECT_FALSE(activate_viewport_intersection_monitoring_); EXPECT_FALSE(disable_pipeline_suspend_); mojom::RemotingSinkMetadata sink_metadata = GetDefaultSinkMetadata(true); sink_metadata.audio_capabilities.push_back( @@ -275,6 +302,9 @@ // toggle remote rendering on. shared_session->OnSinkAvailable(sink_metadata.Clone()); RunUntilIdle(); + EXPECT_TRUE(IsInDelayedStart()); + DelayedStartEnds(); + RunUntilIdle(); EXPECT_TRUE(is_rendering_remotely_); // All requirements now satisfied. EXPECT_TRUE(activate_viewport_intersection_monitoring_); EXPECT_TRUE(disable_pipeline_suspend_); @@ -288,19 +318,16 @@ 44100, EmptyExtraData(), Unencrypted()); PipelineMetadata pipeline_metadata = DefaultMetadata(VideoCodec::kCodecVP8); pipeline_metadata.audio_decoder_config = audio_config; - InitializeControllerAndEnterFullscreen(shared_session, pipeline_metadata, - GetDefaultSinkMetadata(true)); + InitializeControllerAndBecomeDominant(shared_session, pipeline_metadata, + GetDefaultSinkMetadata(true)); // An available sink that does not support Opus audio codec should not cause // the controller to toggle remote rendering on. EXPECT_FALSE(is_rendering_remotely_); - EXPECT_TRUE(activate_viewport_intersection_monitoring_); + EXPECT_FALSE(activate_viewport_intersection_monitoring_); EXPECT_FALSE(disable_pipeline_suspend_); shared_session->OnSinkGone(); // Bye-bye useless sink! RunUntilIdle(); - EXPECT_FALSE(is_rendering_remotely_); - EXPECT_FALSE(activate_viewport_intersection_monitoring_); - EXPECT_FALSE(disable_pipeline_suspend_); mojom::RemotingSinkMetadata sink_metadata = GetDefaultSinkMetadata(true); sink_metadata.audio_capabilities.push_back( mojom::RemotingSinkAudioCapability::CODEC_OPUS); @@ -308,6 +335,9 @@ // toggle remote rendering on. shared_session->OnSinkAvailable(sink_metadata.Clone()); RunUntilIdle(); + EXPECT_TRUE(IsInDelayedStart()); + DelayedStartEnds(); + RunUntilIdle(); EXPECT_TRUE(is_rendering_remotely_); // All requirements now satisfied. EXPECT_TRUE(activate_viewport_intersection_monitoring_); EXPECT_TRUE(disable_pipeline_suspend_); @@ -316,9 +346,13 @@ TEST_F(RendererControllerTest, StartFailed) { const scoped_refptr<SharedSession> shared_session = FakeRemoterFactory::CreateSharedSession(true); - InitializeControllerAndEnterFullscreen( - shared_session, DefaultMetadata(VideoCodec::kCodecHEVC), - GetDefaultSinkMetadata(true)); + InitializeControllerAndBecomeDominant(shared_session, + DefaultMetadata(VideoCodec::kCodecVP8), + GetDefaultSinkMetadata(true)); + RunUntilIdle(); + EXPECT_TRUE(IsInDelayedStart()); + DelayedStartEnds(); + RunUntilIdle(); EXPECT_FALSE(is_rendering_remotely_); EXPECT_FALSE(disable_pipeline_suspend_); } @@ -326,8 +360,8 @@ TEST_F(RendererControllerTest, EncryptedWithRemotingCdm) { const scoped_refptr<SharedSession> shared_session = FakeRemoterFactory::CreateSharedSession(false); - InitializeControllerAndEnterFullscreen(shared_session, EncryptedMetadata(), - GetDefaultSinkMetadata(true)); + InitializeControllerAndBecomeDominant(shared_session, EncryptedMetadata(), + GetDefaultSinkMetadata(true)); EXPECT_FALSE(is_rendering_remotely_); const scoped_refptr<SharedSession> cdm_shared_session = @@ -352,10 +386,15 @@ RunUntilIdle(); EXPECT_TRUE(is_rendering_remotely_); - // For encrypted contents, entering/exiting full screen has no effect. - controller_->OnExitedFullscreen(); + // For encrypted contents, becoming/exiting dominant has no effect. + controller_->OnBecameDominantVisibleContent(true); RunUntilIdle(); EXPECT_TRUE(is_rendering_remotely_); + EXPECT_FALSE(IsInDelayedStart()); + controller_->OnBecameDominantVisibleContent(false); + RunUntilIdle(); + EXPECT_TRUE(is_rendering_remotely_); + EXPECT_FALSE(IsInDelayedStart()); EXPECT_NE(SharedSession::SESSION_PERMANENTLY_STOPPED, controller_->session()->state()); @@ -371,9 +410,10 @@ TEST_F(RendererControllerTest, EncryptedWithLocalCdm) { const scoped_refptr<SharedSession> shared_session = FakeRemoterFactory::CreateSharedSession(false); - InitializeControllerAndEnterFullscreen(shared_session, EncryptedMetadata(), - GetDefaultSinkMetadata(true)); + InitializeControllerAndBecomeDominant(shared_session, EncryptedMetadata(), + GetDefaultSinkMetadata(true)); EXPECT_FALSE(is_rendering_remotely_); + EXPECT_FALSE(IsInDelayedStart()); const scoped_refptr<SharedSession> cdm_shared_session = FakeRemoterFactory::CreateSharedSession(true); @@ -385,14 +425,16 @@ RunUntilIdle(); EXPECT_FALSE(is_rendering_remotely_); EXPECT_FALSE(is_remoting_cdm_); + EXPECT_FALSE(IsInDelayedStart()); } TEST_F(RendererControllerTest, EncryptedWithFailedRemotingCdm) { const scoped_refptr<SharedSession> shared_session = FakeRemoterFactory::CreateSharedSession(false); - InitializeControllerAndEnterFullscreen(shared_session, EncryptedMetadata(), - GetDefaultSinkMetadata(true)); + InitializeControllerAndBecomeDominant(shared_session, EncryptedMetadata(), + GetDefaultSinkMetadata(true)); EXPECT_FALSE(is_rendering_remotely_); + EXPECT_FALSE(IsInDelayedStart()); const scoped_refptr<SharedSession> cdm_shared_session = FakeRemoterFactory::CreateSharedSession(false); @@ -404,6 +446,7 @@ RunUntilIdle(); EXPECT_FALSE(is_rendering_remotely_); EXPECT_TRUE(is_remoting_cdm_); + EXPECT_FALSE(IsInDelayedStart()); cdm_shared_session->OnSinkGone(); RunUntilIdle(); @@ -422,6 +465,7 @@ // Switch to using the remoting renderer, even when the remoting CDM session // was already terminated, to show the failure interstitial. EXPECT_TRUE(is_rendering_remotely_); + EXPECT_FALSE(IsInDelayedStart()); EXPECT_EQ(SharedSession::SESSION_PERMANENTLY_STOPPED, controller_->session()->state()); }
diff --git a/net/cert/internal/cert_issuer_source_aia_unittest.cc b/net/cert/internal/cert_issuer_source_aia_unittest.cc index ba9ff0f..0561372 100644 --- a/net/cert/internal/cert_issuer_source_aia_unittest.cc +++ b/net/cert/internal/cert_issuer_source_aia_unittest.cc
@@ -243,8 +243,6 @@ EXPECT_EQ(1u, result_certs.size()); } -// TODO(eroman): Re-enable these tests! -#if 0 // AuthorityInfoAccess with two URIs, one is invalid, the other HTTP. TEST(CertIssuerSourceAiaTest, OneInvalidOneHttpAia) { scoped_refptr<ParsedCertificate> cert; @@ -252,39 +250,28 @@ scoped_refptr<ParsedCertificate> intermediate_cert; ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert)); - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); + scoped_refptr<StrictMock<MockCertNetFetcher>> mock_fetcher( + new StrictMock<MockCertNetFetcher>()); + + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia2/I2.foo"), _, _)) + .WillOnce(Return( + ByMove(CreateMockRequest(CertDataVector(intermediate_cert.get()))))); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); ASSERT_NE(nullptr, cert_source_request); - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(1u, result_certs.size()); + EXPECT_EQ(result_certs.front()->der_cert(), intermediate_cert->der_cert()); - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get())); - Mock::VerifyAndClearExpectations(&mock_callback); - - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert()); - - status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); - - EXPECT_TRUE(req_manager->is_request_alive()); - cert_source_request.reset(); - EXPECT_FALSE(req_manager->is_request_alive()); + // No more results. + result_certs.clear(); + cert_source_request->GetNext(&result_certs); + EXPECT_EQ(0u, result_certs.size()); } // AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert. @@ -298,499 +285,169 @@ scoped_refptr<ParsedCertificate> intermediate_cert2; ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2)); - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); + scoped_refptr<StrictMock<MockCertNetFetcher>> mock_fetcher( + new StrictMock<MockCertNetFetcher>()); + + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia/I.cer"), _, _)) + .WillOnce(Return( + ByMove(CreateMockRequest(CertDataVector(intermediate_cert.get()))))); + + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia2/I2.foo"), _, _)) + .WillOnce(Return( + ByMove(CreateMockRequest(CertDataVector(intermediate_cert2.get()))))); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); ASSERT_NE(nullptr, cert_source_request); - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); + // GetNext() should return intermediate_cert followed by intermediate_cert2. + // They are returned in two separate batches. + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(1u, result_certs.size()); + EXPECT_EQ(result_certs.front()->der_cert(), intermediate_cert->der_cert()); - RequestManager* req_manager2 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager2); - ASSERT_TRUE(req_manager2->is_request_alive()); - - // Request for I.cer completes first. - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get())); - Mock::VerifyAndClearExpectations(&mock_callback); - - // Results are retrieved before the other request completes. - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert()); - - status = cert_source_request->GetNext(&result_cert); - // The other http request is still pending, status should be ASYNC to signify - // the need to wait for another callback. - ASSERT_EQ(CompletionStatus::ASYNC, status); - EXPECT_FALSE(result_cert.get()); - - // Request for I2.foo completes. - ASSERT_TRUE(req_manager2->is_request_alive()); - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager2->get_callback().Run(OK, - CertDataVector(intermediate_cert2.get())); - Mock::VerifyAndClearExpectations(&mock_callback); - - // Results from the second http request are retrieved. - status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert2->der_cert()); + result_certs.clear(); + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(1u, result_certs.size()); + EXPECT_EQ(result_certs.front()->der_cert(), intermediate_cert2->der_cert()); // No more results. - status = cert_source_request->GetNext(&result_cert); - ASSERT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); - - EXPECT_TRUE(req_manager->is_request_alive()); - EXPECT_TRUE(req_manager2->is_request_alive()); - cert_source_request.reset(); - EXPECT_FALSE(req_manager->is_request_alive()); - EXPECT_FALSE(req_manager2->is_request_alive()); -} - -// AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert. -// Both HTTP requests complete before the results are retrieved from the -// CertIssuerSourceAia. There should only be a single callback since the 2nd -// HTTP request completed before GetNext was called, so both requests can be -// supplied to the caller in the same batch. -TEST(CertIssuerSourceAiaTest, TwoAiaCompletedBeforeGetNext) { - scoped_refptr<ParsedCertificate> cert; - ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert)); - scoped_refptr<ParsedCertificate> intermediate_cert; - ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert)); - scoped_refptr<ParsedCertificate> intermediate_cert2; - ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2)); - - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); - CertIssuerSourceAia aia_source(mock_fetcher); - std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); - ASSERT_NE(nullptr, cert_source_request); - - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); - - RequestManager* req_manager2 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager2); - ASSERT_TRUE(req_manager2->is_request_alive()); - - // First HTTP request completes. Callback is called as soon as the first - // request completes. - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get())); - Mock::VerifyAndClearExpectations(&mock_callback); - - // Second HTTP request completes before any results were retrieved from the - // CertIssuerSourceAia. The callback should not be called again. - ASSERT_TRUE(req_manager2->is_request_alive()); - req_manager2->get_callback().Run(OK, - CertDataVector(intermediate_cert2.get())); - - // Caller retrieves results. Both certs should be supplied. - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert()); - - // 2nd cert is retrieved. - status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert2->der_cert()); - - // All results are done, SYNC signals completion. - status = cert_source_request->GetNext(&result_cert); - ASSERT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); -} - -// AuthorityInfoAccess with three HTTP urls, each pointing to a single DER cert. -// -// 1) Two HTTP requests complete before the results are retrieved from the -// CertIssuerSourceAia. -// 2) A single cert result is retrieved via GetNext. -// 3) The third HTTP request completes. -// 4) The remaining two certs are retrieved. -// -// Only one callback should occur (after the first HTTP request completed), -// since the pending cert results weren't exhausted before the 3rd request -// completed. -TEST(CertIssuerSourceAiaTest, AiaRequestCompletesDuringGetNextSequence) { - scoped_refptr<ParsedCertificate> cert; - ASSERT_TRUE(ReadTestCert("target_three_aia.pem", &cert)); - scoped_refptr<ParsedCertificate> intermediate_cert; - ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert)); - scoped_refptr<ParsedCertificate> intermediate_cert2; - ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2)); - scoped_refptr<ParsedCertificate> intermediate_cert3; - ASSERT_TRUE(ReadTestCert("i3.pem", &intermediate_cert3)); - - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); - CertIssuerSourceAia aia_source(mock_fetcher); - std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); - ASSERT_NE(nullptr, cert_source_request); - - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); - - RequestManager* req_manager2 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager2); - ASSERT_TRUE(req_manager2->is_request_alive()); - - RequestManager* req_manager3 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia3/I3.foo")); - ASSERT_TRUE(req_manager3); - ASSERT_TRUE(req_manager3->is_request_alive()); - - // First HTTP request completes. Callback is called as soon as the first - // request completes. - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get())); - Mock::VerifyAndClearExpectations(&mock_callback); - - // Second HTTP request completes before any results were retrieved from the - // CertIssuerSourceAia. The callback should not be called again. - ASSERT_TRUE(req_manager2->is_request_alive()); - req_manager2->get_callback().Run(OK, - CertDataVector(intermediate_cert2.get())); - - // Caller retrieves a single result. - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert()); - - // Third HTTP request completes. - // The callback should not be called again, since the last GetNext call had - // indicated more results were pending still. - ASSERT_TRUE(req_manager3->is_request_alive()); - req_manager3->get_callback().Run(OK, - CertDataVector(intermediate_cert3.get())); - - // 2nd cert is retrieved. - status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert2->der_cert()); - - // 3rd cert is retrieved. - status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert3->der_cert()); - - // All results are done, SYNC signals completion. - status = cert_source_request->GetNext(&result_cert); - ASSERT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); + result_certs.clear(); + cert_source_request->GetNext(&result_certs); + EXPECT_EQ(0u, result_certs.size()); } // AuthorityInfoAccess with a single HTTP url pointing to a single DER cert, -// CertNetFetcher request fails. The callback should be called to indicate the -// request is complete, but no results should be provided. +// CertNetFetcher request fails. TEST(CertIssuerSourceAiaTest, OneAiaHttpError) { scoped_refptr<ParsedCertificate> cert; ASSERT_TRUE(ReadTestCert("target_one_aia.pem", &cert)); - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); + scoped_refptr<StrictMock<MockCertNetFetcher>> mock_fetcher( + new StrictMock<MockCertNetFetcher>()); + + // HTTP request returns with an error. + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia/I.cer"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(ERR_FAILED)))); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); ASSERT_NE(nullptr, cert_source_request); - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); - - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - // HTTP request returns with an error. - req_manager->get_callback().Run(ERR_FAILED, std::vector<uint8_t>()); - Mock::VerifyAndClearExpectations(&mock_callback); - - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); + // No results. + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(0u, result_certs.size()); } // AuthorityInfoAccess with a single HTTP url pointing to a single DER cert, -// CertNetFetcher request completes, but the DER cert fails to parse. The -// callback should be called to indicate the request is complete, but no results -// should be provided. +// CertNetFetcher request completes, but the DER cert fails to parse. TEST(CertIssuerSourceAiaTest, OneAiaParseError) { scoped_refptr<ParsedCertificate> cert; ASSERT_TRUE(ReadTestCert("target_one_aia.pem", &cert)); - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); + scoped_refptr<StrictMock<MockCertNetFetcher>> mock_fetcher( + new StrictMock<MockCertNetFetcher>()); + + // HTTP request returns invalid certificate data. + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia/I.cer"), _, _)) + .WillOnce(Return( + ByMove(CreateMockRequest(std::vector<uint8_t>({1, 2, 3, 4, 5}))))); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); ASSERT_NE(nullptr, cert_source_request); - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); - - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - // HTTP request returns with an error. - req_manager->get_callback().Run(OK, std::vector<uint8_t>({1, 2, 3, 4, 5})); - Mock::VerifyAndClearExpectations(&mock_callback); - - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); + // No results. + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(0u, result_certs.size()); } // AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert. -// One request fails. No callback should be generated yet. Once the second -// request completes, the callback should occur. +// One request fails. TEST(CertIssuerSourceAiaTest, TwoAiaCompletedInSeriesFirstFails) { scoped_refptr<ParsedCertificate> cert; ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert)); scoped_refptr<ParsedCertificate> intermediate_cert2; ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2)); - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); + scoped_refptr<StrictMock<MockCertNetFetcher>> mock_fetcher( + new StrictMock<MockCertNetFetcher>()); + + // Request for I.cer completes first, but fails. + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia/I.cer"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(ERR_INVALID_RESPONSE)))); + + // Request for I2.foo succeeds. + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia2/I2.foo"), _, _)) + .WillOnce(Return( + ByMove(CreateMockRequest(CertDataVector(intermediate_cert2.get()))))); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); ASSERT_NE(nullptr, cert_source_request); - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); - - RequestManager* req_manager2 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager2); - ASSERT_TRUE(req_manager2->is_request_alive()); - - // Request for I.cer completes first, but fails. Callback is NOT called. - req_manager->get_callback().Run(ERR_INVALID_RESPONSE, std::vector<uint8_t>()); - Mock::VerifyAndClearExpectations(&mock_callback); - - // Request for I2.foo completes. Callback should be called now. - ASSERT_TRUE(req_manager2->is_request_alive()); - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager2->get_callback().Run(OK, - CertDataVector(intermediate_cert2.get())); - Mock::VerifyAndClearExpectations(&mock_callback); - - // Results from the second http request are retrieved. - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert2->der_cert()); + // GetNext() should return intermediate_cert2. + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(1u, result_certs.size()); + EXPECT_EQ(result_certs.front()->der_cert(), intermediate_cert2->der_cert()); // No more results. - status = cert_source_request->GetNext(&result_cert); - ASSERT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); + result_certs.clear(); + cert_source_request->GetNext(&result_certs); + EXPECT_EQ(0u, result_certs.size()); } // AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert. // First request completes, result is retrieved, then the second request fails. -// The second callback should occur to indicate that the results are exhausted, -// even though no more results are available. TEST(CertIssuerSourceAiaTest, TwoAiaCompletedInSeriesSecondFails) { scoped_refptr<ParsedCertificate> cert; ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert)); scoped_refptr<ParsedCertificate> intermediate_cert; ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert)); - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); - CertIssuerSourceAia aia_source(mock_fetcher); - std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); - ASSERT_NE(nullptr, cert_source_request); - - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); - - RequestManager* req_manager2 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager2); - ASSERT_TRUE(req_manager2->is_request_alive()); + scoped_refptr<StrictMock<MockCertNetFetcher>> mock_fetcher( + new StrictMock<MockCertNetFetcher>()); // Request for I.cer completes first. - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get())); - Mock::VerifyAndClearExpectations(&mock_callback); + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia/I.cer"), _, _)) + .WillOnce(Return( + ByMove(CreateMockRequest(CertDataVector(intermediate_cert.get()))))); - // Results are retrieved before the other request completes. - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert()); + // Request for I2.foo fails. + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia2/I2.foo"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(ERR_INVALID_RESPONSE)))); - status = cert_source_request->GetNext(&result_cert); - // The other http request is still pending, status should be ASYNC to signify - // the need to wait for another callback. - ASSERT_EQ(CompletionStatus::ASYNC, status); - EXPECT_FALSE(result_cert.get()); - - // Request for I2.foo fails. Callback should be called to indicate that - // results are exhausted. - ASSERT_TRUE(req_manager2->is_request_alive()); - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager2->get_callback().Run(ERR_INVALID_RESPONSE, - std::vector<uint8_t>()); - Mock::VerifyAndClearExpectations(&mock_callback); - - // GetNext has no more results. - status = cert_source_request->GetNext(&result_cert); - ASSERT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); -} - -// AuthorityInfoAccess with two HTTP urls. Request is cancelled before any HTTP -// requests finish. -TEST(CertIssuerSourceAiaTest, CertSourceRequestCancelled) { - scoped_refptr<ParsedCertificate> cert; - ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert)); - - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); ASSERT_NE(nullptr, cert_source_request); - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); + // GetNext() should return intermediate_cert. + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(1u, result_certs.size()); + EXPECT_EQ(result_certs.front()->der_cert(), intermediate_cert->der_cert()); - RequestManager* req_manager2 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager2); - ASSERT_TRUE(req_manager2->is_request_alive()); - - // Delete The CertIssuerSource::Request, cancelling it. - cert_source_request.reset(); - // Both CertNetFetcher::Requests should be cancelled. - EXPECT_FALSE(req_manager->is_request_alive()); - EXPECT_FALSE(req_manager2->is_request_alive()); -} - -// AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert. -// One request completes, results are retrieved, then request is cancelled -// before the second HTTP request completes. -TEST(CertIssuerSourceAiaTest, TwoAiaOneCompletedThenRequestCancelled) { - scoped_refptr<ParsedCertificate> cert; - ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert)); - scoped_refptr<ParsedCertificate> intermediate_cert; - ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert)); - - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); - CertIssuerSourceAia aia_source(mock_fetcher); - std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); - ASSERT_NE(nullptr, cert_source_request); - - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); - - RequestManager* req_manager2 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager2); - ASSERT_TRUE(req_manager2->is_request_alive()); - - // Request for I.cer completes first. - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get())); - Mock::VerifyAndClearExpectations(&mock_callback); - - // Results are retrieved before the other request completes. - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert()); - - status = cert_source_request->GetNext(&result_cert); - // The other http request is still pending, status should be ASYNC to signify - // the need to wait for another callback. - ASSERT_EQ(CompletionStatus::ASYNC, status); - EXPECT_FALSE(result_cert.get()); - - // Delete The CertIssuerSource::Request, cancelling it. - cert_source_request.reset(); - // Both CertNetFetcher::Requests should be cancelled. - EXPECT_FALSE(req_manager->is_request_alive()); - EXPECT_FALSE(req_manager2->is_request_alive()); + // No more results. + result_certs.clear(); + cert_source_request->GetNext(&result_certs); + EXPECT_EQ(0u, result_certs.size()); } // AuthorityInfoAccess with six HTTP URLs. kMaxFetchesPerCert is 5, so the @@ -799,49 +456,45 @@ scoped_refptr<ParsedCertificate> cert; ASSERT_TRUE(ReadTestCert("target_six_aia.pem", &cert)); - StrictMock<MockIssuerCallback> mock_callback; - scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( - new StrictMock<MockCertNetFetcherImpl>()); + scoped_refptr<StrictMock<MockCertNetFetcher>> mock_fetcher( + new StrictMock<MockCertNetFetcher>()); + + std::vector<uint8_t> bad_der({1, 2, 3, 4, 5}); + + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia/I.cer"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(bad_der)))); + + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia2/I2.foo"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(bad_der)))); + + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia3/I3.foo"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(bad_der)))); + + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia4/I4.foo"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(bad_der)))); + + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia5/I5.foo"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(bad_der)))); + + // Note that the sixth URL (http://url-for-aia6/I6.foo) will not be requested. + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); ASSERT_NE(nullptr, cert_source_request); - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - EXPECT_TRUE(req_manager->is_request_alive()); - - RequestManager* req_manager2 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager2); - EXPECT_TRUE(req_manager2->is_request_alive()); - - RequestManager* req_manager3 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia3/I3.foo")); - ASSERT_TRUE(req_manager3); - EXPECT_TRUE(req_manager3->is_request_alive()); - - RequestManager* req_manager4 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia4/I4.foo")); - ASSERT_TRUE(req_manager4); - EXPECT_TRUE(req_manager4->is_request_alive()); - - RequestManager* req_manager5 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia5/I5.foo")); - ASSERT_TRUE(req_manager5); - EXPECT_TRUE(req_manager5->is_request_alive()); - - // Sixth URL should not have created a request. - EXPECT_FALSE( - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia6/I6.foo"))); + // GetNext() will not get any certificates (since the first 5 fail to be + // parsed, and the sixth URL is not attempted). + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(0u, result_certs.size()); } -#endif - } // namespace } // namespace net
diff --git a/net/disk_cache/simple/simple_index_file_posix.cc b/net/disk_cache/simple/simple_index_file_posix.cc index 9fa387e..a26267c9 100644 --- a/net/disk_cache/simple/simple_index_file_posix.cc +++ b/net/disk_cache/simple/simple_index_file_posix.cc
@@ -5,6 +5,7 @@ #include "net/disk_cache/simple/simple_index_file.h" #include <dirent.h> +#include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> @@ -35,11 +36,22 @@ PLOG(ERROR) << "opendir " << cache_path.value(); return false; } - dirent entry, *result; - while (readdir_r(dir.get(), &entry, &result) == 0) { - if (!result) - return true; // The traversal completed successfully. - const std::string file_name(result->d_name); + while (true) { + // errno must be set to 0 before every readdir() call to detect errors. + errno = 0; + dirent* entry = readdir(dir.get()); + if (!entry) { + // Some implementations of readdir() (particularly older versions of + // Android Bionic) may leave errno set to EINTR even after they handle + // this case internally. It's safe to ignore EINTR in that case. + if (errno && errno != EINTR) { + PLOG(ERROR) << "readdir " << cache_path.value(); + return false; + } + break; + } + + const std::string file_name(entry->d_name); if (file_name == "." || file_name == "..") continue; const base::FilePath file_path = cache_path.Append( @@ -53,8 +65,8 @@ entry_file_callback.Run(file_path, file_info.last_accessed, file_info.last_modified, file_info.size); } - PLOG(ERROR) << "readdir_r " << cache_path.value(); - return false; + + return true; } } // namespace disk_cache
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index fe43449..d18447d 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc
@@ -121,8 +121,6 @@ quic_close_sessions_on_ip_change(false), quic_idle_connection_timeout_seconds(kIdleConnectionTimeoutSeconds), quic_reduced_ping_timeout_seconds(kPingTimeoutSecs), - quic_packet_reader_yield_after_duration_milliseconds( - kQuicYieldAfterDurationMilliseconds), quic_migrate_sessions_on_network_change(false), quic_migrate_sessions_early(false), quic_allow_server_migration(false), @@ -198,7 +196,6 @@ params.mark_quic_broken_when_network_blackholes, params.quic_idle_connection_timeout_seconds, params.quic_reduced_ping_timeout_seconds, - params.quic_packet_reader_yield_after_duration_milliseconds, params.quic_migrate_sessions_on_network_change, params.quic_migrate_sessions_early, params.quic_allow_server_migration, @@ -335,10 +332,6 @@ params_.quic_idle_connection_timeout_seconds); dict->SetInteger("reduced_ping_timeout_seconds", params_.quic_reduced_ping_timeout_seconds); - dict->SetInteger( - "packet_reader_yield_after_duration_milliseconds", - params_.quic_packet_reader_yield_after_duration_milliseconds); - dict->SetBoolean("mark_quic_broken_when_network_blackholes", params_.mark_quic_broken_when_network_blackholes); dict->SetBoolean("retry_without_alt_svc_on_quic_errors",
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 013e0d1..5cd08da9 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h
@@ -141,9 +141,6 @@ // Specifies the reduced ping timeout subsequent connections should use when // a connection was timed out with open streams. int quic_reduced_ping_timeout_seconds; - // Specifies the maximum time duration that QUIC packet reader can perform - // consecutive packets reading. - int quic_packet_reader_yield_after_duration_milliseconds; // If true, active QUIC sessions may be migrated onto a new network when // the platform indicates that the default network is changing. bool quic_migrate_sessions_on_network_change;
diff --git a/net/quic/chromium/quic_chromium_packet_reader.h b/net/quic/chromium/quic_chromium_packet_reader.h index 3918fc0..113eeef 100644 --- a/net/quic/chromium/quic_chromium_packet_reader.h +++ b/net/quic/chromium/quic_chromium_packet_reader.h
@@ -23,7 +23,7 @@ // milliseconds have passed, QuicChromiumPacketReader::StartReading() yields by // doing a QuicChromiumPacketReader::PostTask(). const int kQuicYieldAfterPacketsRead = 32; -const int kQuicYieldAfterDurationMilliseconds = 20; +const int kQuicYieldAfterDurationMilliseconds = 2; class NET_EXPORT_PRIVATE QuicChromiumPacketReader { public:
diff --git a/net/quic/chromium/quic_connection_logger.cc b/net/quic/chromium/quic_connection_logger.cc index e50792c..f058720 100644 --- a/net/quic/chromium/quic_connection_logger.cc +++ b/net/quic/chromium/quic_connection_logger.cc
@@ -415,6 +415,8 @@ QuicPacketNumber original_packet_number, TransmissionType transmission_type, QuicTime sent_time) { + if (!net_log_.IsCapturing()) + return; if (original_packet_number == 0) { net_log_.AddEvent( NetLogEventType::QUIC_SESSION_PACKET_SENT,
diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc index e65830d..b36c6e8 100644 --- a/net/quic/chromium/quic_stream_factory.cc +++ b/net/quic/chromium/quic_stream_factory.cc
@@ -664,7 +664,6 @@ bool mark_quic_broken_when_network_blackholes, int idle_connection_timeout_seconds, int reduced_ping_timeout_seconds, - int packet_reader_yield_after_duration_milliseconds, bool migrate_sessions_on_network_change, bool migrate_sessions_early, bool allow_server_migration, @@ -702,7 +701,7 @@ QuicTime::Delta::FromSeconds(reduced_ping_timeout_seconds)), yield_after_packets_(kQuicYieldAfterPacketsRead), yield_after_duration_(QuicTime::Delta::FromMilliseconds( - packet_reader_yield_after_duration_milliseconds)), + kQuicYieldAfterDurationMilliseconds)), close_sessions_on_ip_change_(close_sessions_on_ip_change), migrate_sessions_on_network_change_( migrate_sessions_on_network_change &&
diff --git a/net/quic/chromium/quic_stream_factory.h b/net/quic/chromium/quic_stream_factory.h index cdd1f996f..0d91062 100644 --- a/net/quic/chromium/quic_stream_factory.h +++ b/net/quic/chromium/quic_stream_factory.h
@@ -208,7 +208,6 @@ bool mark_quic_broken_when_network_blackholes, int idle_connection_timeout_seconds, int reduced_ping_timeout_seconds, - int packet_reader_yield_after_duration_milliseconds, bool migrate_sessions_on_network_change, bool migrate_sessions_early, bool allow_server_migration,
diff --git a/net/quic/chromium/quic_stream_factory_test.cc b/net/quic/chromium/quic_stream_factory_test.cc index 8a9c8c9..459af54b 100644 --- a/net/quic/chromium/quic_stream_factory_test.cc +++ b/net/quic/chromium/quic_stream_factory_test.cc
@@ -196,8 +196,6 @@ close_sessions_on_ip_change_(false), idle_connection_timeout_seconds_(kIdleConnectionTimeoutSeconds), reduced_ping_timeout_seconds_(kPingTimeoutSecs), - packet_reader_yield_after_duration_milliseconds_( - kQuicYieldAfterDurationMilliseconds), migrate_sessions_on_network_change_(false), migrate_sessions_early_(false), allow_server_migration_(false), @@ -220,7 +218,6 @@ close_sessions_on_ip_change_, /*mark_quic_broken_when_network_blackholes*/ false, idle_connection_timeout_seconds_, reduced_ping_timeout_seconds_, - packet_reader_yield_after_duration_milliseconds_, migrate_sessions_on_network_change_, migrate_sessions_early_, allow_server_migration_, force_hol_blocking_, race_cert_verification_, estimate_initial_rtt_, QuicTagVector(), @@ -729,7 +726,6 @@ bool close_sessions_on_ip_change_; int idle_connection_timeout_seconds_; int reduced_ping_timeout_seconds_; - int packet_reader_yield_after_duration_milliseconds_; bool migrate_sessions_on_network_change_; bool migrate_sessions_early_; bool allow_server_migration_;
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc index d0fac11..54fa72b 100644 --- a/pdf/out_of_process_instance.cc +++ b/pdf/out_of_process_instance.cc
@@ -220,10 +220,41 @@ } } +void SetCaretPosition(PP_Instance instance, const PP_FloatPoint* position) { + void* object = pp::Instance::GetPerInstanceObject(instance, kPPPPdfInterface); + if (object) { + OutOfProcessInstance* obj_instance = + static_cast<OutOfProcessInstance*>(object); + return obj_instance->SetCaretPosition(pp::FloatPoint(*position)); + } +} + +void MoveRangeSelectionExtent(PP_Instance instance, + const PP_FloatPoint* extent) { + void* object = pp::Instance::GetPerInstanceObject(instance, kPPPPdfInterface); + if (object) { + OutOfProcessInstance* obj_instance = + static_cast<OutOfProcessInstance*>(object); + return obj_instance->MoveRangeSelectionExtent(pp::FloatPoint(*extent)); + } +} + +void SetSelectionBounds(PP_Instance instance, + const PP_FloatPoint* base, + const PP_FloatPoint* extent) { + void* object = pp::Instance::GetPerInstanceObject(instance, kPPPPdfInterface); + if (object) { + OutOfProcessInstance* obj_instance = + static_cast<OutOfProcessInstance*>(object); + return obj_instance->SetSelectionBounds(pp::FloatPoint(*base), + pp::FloatPoint(*extent)); + } +} + const PPP_Pdf ppp_private = { - &GetLinkAtPosition, &Transform, &GetPrintPresetOptionsFromDocument, - &EnableAccessibility, -}; + &GetLinkAtPosition, &Transform, &GetPrintPresetOptionsFromDocument, + &EnableAccessibility, &SetCaretPosition, &MoveRangeSelectionExtent, + &SetSelectionBounds}; int ExtractPrintPreviewPageIndex(base::StringPiece src_url) { // Sample |src_url| format: chrome://print/id/page_index/print.pdf @@ -651,13 +682,7 @@ touch_event.GetTouchByIndex(PP_TOUCHLIST_TYPE_TARGETTOUCHES, i); pp::FloatPoint point = touch_point.position(); - - // Account for the scroll position. Touch events are in DOM coordinates - // where mouse events appear to be in screen coordinates. - point.set_x(scroll_offset_.x() + point.x()); - point.set_y(scroll_offset_.y() + point.y()); ScaleFloatPoint(device_scale_, &point); - point.set_x(point.x() - available_area_.x()); new_touch_event.AddTouchPoint( @@ -851,6 +876,48 @@ pp::PDF::SetAccessibilityViewportInfo(GetPluginInstance(), &viewport_info); } +void OutOfProcessInstance::SelectionChanged(const pp::Rect& left, + const pp::Rect& right) { + pp::Point l(left.point().x() + available_area_.x(), left.point().y()); + pp::Point r(right.x() + available_area_.x(), right.point().y()); + + float inverse_scale = 1.0f / device_scale_; + ScalePoint(inverse_scale, &l); + ScalePoint(inverse_scale, &r); + + pp::PDF::SelectionChanged(GetPluginInstance(), + PP_MakeFloatPoint(l.x(), l.y()), left.height(), + PP_MakeFloatPoint(r.x(), r.y()), right.height()); +} + +void OutOfProcessInstance::SetCaretPosition(const pp::FloatPoint& position) { + pp::Point new_position(position.x(), position.y()); + ScalePoint(device_scale_, &new_position); + new_position.set_x(new_position.x() - available_area_.x()); + engine_->SetCaretPosition(new_position); +} + +void OutOfProcessInstance::MoveRangeSelectionExtent( + const pp::FloatPoint& extent) { + pp::Point new_extent(extent.x(), extent.y()); + ScalePoint(device_scale_, &new_extent); + new_extent.set_x(new_extent.x() - available_area_.x()); + engine_->MoveRangeSelectionExtent(new_extent); +} + +void OutOfProcessInstance::SetSelectionBounds(const pp::FloatPoint& base, + const pp::FloatPoint& extent) { + pp::Point new_base_point(base.x(), base.y()); + ScalePoint(device_scale_, &new_base_point); + new_base_point.set_x(new_base_point.x() - available_area_.x()); + + pp::Point new_extent_point(extent.x(), extent.y()); + ScalePoint(device_scale_, &new_extent_point); + new_extent_point.set_x(new_extent_point.x() - available_area_.x()); + + engine_->SetSelectionBounds(new_base_point, new_extent_point); +} + pp::Var OutOfProcessInstance::GetLinkAtPosition(const pp::Point& point) { pp::Point offset_point(point); ScalePoint(device_scale_, &offset_point);
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h index e88fdd0..fa809f0 100644 --- a/pdf/out_of_process_instance.h +++ b/pdf/out_of_process_instance.h
@@ -77,6 +77,10 @@ pp::Var GetLinkAtPosition(const pp::Point& point); void GetPrintPresetOptionsFromDocument(PP_PdfPrintPresetOptions_Dev* options); void EnableAccessibility(); + void SetCaretPosition(const pp::FloatPoint& position); + void MoveRangeSelectionExtent(const pp::FloatPoint& extent); + void SetSelectionBounds(const pp::FloatPoint& base, + const pp::FloatPoint& extent); void FlushCallback(int32_t result); void DidOpen(int32_t result); @@ -137,6 +141,7 @@ bool IsPrintPreview() override; uint32_t GetBackgroundColor() override; void IsSelectingChanged(bool is_selecting) override; + void SelectionChanged(const pp::Rect& left, const pp::Rect& right) override; // PreviewModeClient::Client implementation. void PreviewDocumentLoadComplete() override;
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h index 1556e51..5d3493c 100644 --- a/pdf/pdf_engine.h +++ b/pdf/pdf_engine.h
@@ -190,6 +190,9 @@ // Sets selection status. virtual void IsSelectingChanged(bool is_selecting) {} + + virtual void SelectionChanged(const pp::Rect& left, const pp::Rect& right) { + } }; // Factory method to create an instance of the PDF Engine. @@ -305,6 +308,11 @@ virtual bool IsProgressiveLoad() = 0; virtual std::string GetMetadata(const std::string& key) = 0; + + virtual void SetCaretPosition(const pp::Point& position) = 0; + virtual void MoveRangeSelectionExtent(const pp::Point& extent) = 0; + virtual void SetSelectionBounds(const pp::Point& base, + const pp::Point& extent) = 0; }; // Interface for exports that wrap the PDF engine.
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index 22cff050..2d45f09 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -1962,8 +1962,11 @@ } SelectionChangeInvalidator selection_invalidator(this); + return ExtendSelection(page_index, char_index); +} - // Check if the user has descreased their selection area and we need to remove +bool PDFiumEngine::ExtendSelection(int page_index, int char_index) { + // Check if the user has decreased their selection area and we need to remove // pages from selection_. for (size_t i = 0; i < selection_.size(); ++i) { if (selection_[i].page_index() == page_index) { @@ -1972,7 +1975,6 @@ break; } } - if (selection_.empty()) return false; @@ -3321,6 +3323,7 @@ selection_changed = true; } } + if (selection_changed) engine_->OnSelectionChanged(); } @@ -3596,6 +3599,32 @@ void PDFiumEngine::OnSelectionChanged() { DCHECK(!in_form_text_area_); pp::PDF::SetSelectedText(GetPluginInstance(), GetSelectedText().c_str()); + + // We need to determine the top-left and bottom-right points of the selection + // in order to report those to the embedder. This code assumes that the + // selection list is out of order. + pp::Rect left(std::numeric_limits<int32_t>::max(), + std::numeric_limits<int32_t>::max(), 0, 0); + pp::Rect right; + for (auto& sel : selection_) { + for (const auto& rect : sel.GetScreenRects( + GetVisibleRect().point(), current_zoom_, current_rotation_)) { + if (rect.y() < left.y() || + (rect.y() == left.y() && rect.x() < left.x())) { + left = rect; + } + if (rect.y() > right.y() || + (rect.y() == right.y() && rect.right() > right.right())) { + right = rect; + } + } + } + right.set_x(right.x() + right.width()); + if (left.IsEmpty()) { + left.set_x(0); + left.set_y(0); + } + client_->SelectionChanged(left, right); } void PDFiumEngine::RotateInternal() { @@ -3964,6 +3993,49 @@ .InMilliseconds() > engine->progressive_paint_timeout_; } +void PDFiumEngine::SetCaretPosition(const pp::Point& position) { + // TODO(dsinclair): Handle caret position ... +} + +void PDFiumEngine::MoveRangeSelectionExtent(const pp::Point& extent) { + int page_index = -1; + int char_index = -1; + int form_type = FPDF_FORMFIELD_UNKNOWN; + PDFiumPage::LinkTarget target; + GetCharIndex(extent, &page_index, &char_index, &form_type, &target); + if (page_index < 0 || char_index < 0) + return; + + SelectionChangeInvalidator selection_invalidator(this); + if (range_selection_direction_ == RangeSelectionDirection::Right) { + ExtendSelection(page_index, char_index); + return; + } + + // For a left selection we clear the current selection and set a new starting + // point based on the new left position. We then extend that selection out to + // the previously provided base location. + selection_.clear(); + selection_.push_back(PDFiumRange(pages_[page_index].get(), char_index, 0)); + + // This should always succeeed because the range selection base should have + // already been selected. + GetCharIndex(range_selection_base_, &page_index, &char_index, &form_type, + &target); + ExtendSelection(page_index, char_index); +} + +void PDFiumEngine::SetSelectionBounds(const pp::Point& base, + const pp::Point& extent) { + range_selection_base_ = base; + if (base.y() < extent.y() || + (base.y() == extent.y() && base.x() < extent.x())) { + range_selection_direction_ = RangeSelectionDirection::Left; + } else { + range_selection_direction_ = RangeSelectionDirection::Right; + } +} + ScopedUnsupportedFeature::ScopedUnsupportedFeature(PDFiumEngine* engine) : old_engine_(g_engine_for_unsupported) { g_engine_for_unsupported = engine;
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h index 3953c745..2845bb6 100644 --- a/pdf/pdfium/pdfium_engine.h +++ b/pdf/pdfium/pdfium_engine.h
@@ -106,6 +106,10 @@ #endif bool IsProgressiveLoad() override; std::string GetMetadata(const std::string& key) override; + void SetCaretPosition(const pp::Point& position) override; + void MoveRangeSelectionExtent(const pp::Point& extent) override; + void SetSelectionBounds(const pp::Point& base, + const pp::Point& extent) override; // DocumentLoader::Client implementation. pp::Instance* GetPluginInstance() override; @@ -301,6 +305,8 @@ bool OnKeyUp(const pp::KeyboardInputEvent& event); bool OnChar(const pp::KeyboardInputEvent& event); + bool ExtendSelection(int page_index, int char_index); + FPDF_DOCUMENT CreateSinglePageRasterPdf( double source_page_width, double source_page_height, @@ -764,6 +770,11 @@ // to false after the user finishes getting their password. bool getting_password_; + enum class RangeSelectionDirection { Left, Right }; + RangeSelectionDirection range_selection_direction_; + + pp::Point range_selection_base_; + DISALLOW_COPY_AND_ASSIGN(PDFiumEngine); };
diff --git a/ppapi/c/private/ppb_pdf.h b/ppapi/c/private/ppb_pdf.h index 06ddf7e..ebf6c14 100644 --- a/ppapi/c/private/ppb_pdf.h +++ b/ppapi/c/private/ppb_pdf.h
@@ -162,6 +162,13 @@ void (*SetCrashData)(PP_Instance instance, const char* pdf_url, const char* top_level_url); + + // Sets the current selection bounding edges. + void (*SelectionChanged)(PP_Instance instance, + const struct PP_FloatPoint* left, + int32_t left_height, + const struct PP_FloatPoint* right, + int32_t right_height); }; #endif // PPAPI_C_PRIVATE_PPB_PDF_H_
diff --git a/ppapi/c/private/ppp_pdf.h b/ppapi/c/private/ppp_pdf.h index 4dc3e7c..63118f8 100644 --- a/ppapi/c/private/ppp_pdf.h +++ b/ppapi/c/private/ppp_pdf.h
@@ -65,6 +65,14 @@ PP_PdfPrintPresetOptions_Dev* options); void (*EnableAccessibility)(PP_Instance instance); + + void (*SetCaretPosition)(PP_Instance instance, + const struct PP_FloatPoint* position); + void (*MoveRangeSelectionExtent)(PP_Instance instance, + const struct PP_FloatPoint* extent); + void (*SetSelectionBounds)(PP_Instance instance, + const struct PP_FloatPoint* base, + const struct PP_FloatPoint* extent); }; typedef PPP_Pdf_1_1 PPP_Pdf;
diff --git a/ppapi/cpp/private/pdf.cc b/ppapi/cpp/private/pdf.cc index dda3fa9f..7a28ebf8 100644 --- a/ppapi/cpp/private/pdf.cc +++ b/ppapi/cpp/private/pdf.cc
@@ -193,4 +193,16 @@ } } +// static +void PDF::SelectionChanged(const InstanceHandle& instance, + const PP_FloatPoint& left, + int32_t left_height, + const PP_FloatPoint& right, + int32_t right_height) { + if (has_interface<PPB_PDF>()) { + get_interface<PPB_PDF>()->SelectionChanged( + instance.pp_instance(), &left, left_height, &right, right_height); + } +} + } // namespace pp
diff --git a/ppapi/cpp/private/pdf.h b/ppapi/cpp/private/pdf.h index a4f309fc9..ce89dbd1 100644 --- a/ppapi/cpp/private/pdf.h +++ b/ppapi/cpp/private/pdf.h
@@ -71,6 +71,11 @@ static void SetCrashData(const InstanceHandle& instance, const char* pdf_url, const char* top_level_url); + static void SelectionChanged(const InstanceHandle& instance, + const PP_FloatPoint& left, + int32_t left_height, + const PP_FloatPoint& right, + int32_t right_height); }; } // namespace pp
diff --git a/ppapi/proxy/pdf_resource.cc b/ppapi/proxy/pdf_resource.cc index 565c23d..d9a9e5b 100644 --- a/ppapi/proxy/pdf_resource.cc +++ b/ppapi/proxy/pdf_resource.cc
@@ -199,5 +199,13 @@ PluginGlobals::Get()->SetActiveURL(top_level_url); } +void PDFResource::SelectionChanged(const PP_FloatPoint& left, + int32_t left_height, + const PP_FloatPoint& right, + int32_t right_height) { + Post(RENDERER, PpapiHostMsg_PDF_SelectionChanged(left, left_height, right, + right_height)); +} + } // namespace proxy } // namespace ppapi
diff --git a/ppapi/proxy/pdf_resource.h b/ppapi/proxy/pdf_resource.h index 2c314a6c..ada6bce 100644 --- a/ppapi/proxy/pdf_resource.h +++ b/ppapi/proxy/pdf_resource.h
@@ -61,6 +61,10 @@ PP_PrivateAccessibilityTextRunInfo text_runs[], PP_PrivateAccessibilityCharInfo chars[]) override; void SetCrashData(const char* pdf_url, const char* top_level_url) override; + void SelectionChanged(const PP_FloatPoint& left, + int32_t left_height, + const PP_FloatPoint& right, + int32_t right_height) override; private: std::string locale_;
diff --git a/ppapi/proxy/pdf_resource_unittest.cc b/ppapi/proxy/pdf_resource_unittest.cc index 7bea178e..a7592381 100644 --- a/ppapi/proxy/pdf_resource_unittest.cc +++ b/ppapi/proxy/pdf_resource_unittest.cc
@@ -125,5 +125,18 @@ PpapiHostMsg_PDF_SaveAs::ID, ¶ms, &msg)); } +TEST_F(PDFResourceTest, SelectionChanged) { + const PPB_PDF* pdf_iface = thunk::GetPPB_PDF_Thunk(); + + PP_FloatPoint left = PP_MakeFloatPoint(0.0f, 0.0f); + PP_FloatPoint right = PP_MakeFloatPoint(1.0f, 1.0f); + pdf_iface->SelectionChanged(pp_instance(), &left, 0, &right, 0); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_PDF_SelectionChanged::ID, ¶ms, &msg)); +} + } // namespace proxy } // namespace ppapi
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index 74707c4..114c150 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h
@@ -791,6 +791,16 @@ PP_Bool /* result */) IPC_MESSAGE_ROUTED1(PpapiMsg_PPPPdf_EnableAccessibility, PP_Instance /* instance */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPPdf_SetCaretPosition, + PP_Instance /* instance */, + PP_FloatPoint /* position */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPPdf_MoveRangeSelectionExtent, + PP_Instance /* instance */, + PP_FloatPoint /* extent */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPPPdf_SetSelectionBounds, + PP_Instance /* instance */, + PP_FloatPoint /* base */, + PP_FloatPoint /* extent */) // Find IPC_MESSAGE_ROUTED2(PpapiPluginMsg_PPPFind_StartFind, @@ -2530,6 +2540,13 @@ std::vector<PP_PrivateAccessibilityTextRunInfo> /* text_runs */, std::vector<PP_PrivateAccessibilityCharInfo> /* chars */) +// Send information about the selection coordinates. +IPC_MESSAGE_CONTROL4(PpapiHostMsg_PDF_SelectionChanged, + PP_FloatPoint /* left */, + int32_t /* left_height */, + PP_FloatPoint /* right */, + int32_t /* right_height */) + // VideoCapture ---------------------------------------------------------------- // VideoCapture_Dev, plugin -> host
diff --git a/ppapi/proxy/ppp_pdf_proxy.cc b/ppapi/proxy/ppp_pdf_proxy.cc index ef89438..37c057a 100644 --- a/ppapi/proxy/ppp_pdf_proxy.cc +++ b/ppapi/proxy/ppp_pdf_proxy.cc
@@ -41,11 +41,31 @@ new PpapiMsg_PPPPdf_EnableAccessibility(API_ID_PPP_PDF, instance)); } +void SetCaretPosition(PP_Instance instance, const PP_FloatPoint* position) { + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPPdf_SetCaretPosition(API_ID_PPP_PDF, instance, + *position)); +} + +void MoveRangeSelectionExtent(PP_Instance instance, + const PP_FloatPoint* extent) { + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPPdf_MoveRangeSelectionExtent(API_ID_PPP_PDF, instance, + *extent)); +} + +void SetSelectionBounds(PP_Instance instance, + const PP_FloatPoint* base, + const PP_FloatPoint* extent) { + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPPdf_SetSelectionBounds(API_ID_PPP_PDF, instance, *base, + *extent)); +} + const PPP_Pdf ppp_pdf_interface = { - &GetLinkAtPosition, - &Transform, - &GetPrintPresetOptionsFromDocument, - &EnableAccessibility, + &GetLinkAtPosition, &Transform, &GetPrintPresetOptionsFromDocument, + &EnableAccessibility, &SetCaretPosition, &MoveRangeSelectionExtent, + &SetSelectionBounds, }; #else // The NaCl plugin doesn't need the host side interface - stub it out. @@ -82,6 +102,12 @@ OnPluginMsgPrintPresetOptions) IPC_MESSAGE_HANDLER(PpapiMsg_PPPPdf_EnableAccessibility, OnPluginMsgEnableAccessibility) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPPdf_SetCaretPosition, + OnPluginMsgSetCaretPosition) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPPdf_MoveRangeSelectionExtent, + OnPluginMsgMoveRangeSelectionExtent) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPPdf_SetSelectionBounds, + OnPluginMsgSetSelectionBounds) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -110,5 +136,25 @@ CallWhileUnlocked(ppp_pdf_->EnableAccessibility, instance); } +void PPP_Pdf_Proxy::OnPluginMsgSetCaretPosition(PP_Instance instance, + const PP_FloatPoint& position) { + if (ppp_pdf_) + CallWhileUnlocked(ppp_pdf_->SetCaretPosition, instance, &position); +} + +void PPP_Pdf_Proxy::OnPluginMsgMoveRangeSelectionExtent( + PP_Instance instance, + const PP_FloatPoint& extent) { + if (ppp_pdf_) + CallWhileUnlocked(ppp_pdf_->MoveRangeSelectionExtent, instance, &extent); +} + +void PPP_Pdf_Proxy::OnPluginMsgSetSelectionBounds(PP_Instance instance, + const PP_FloatPoint& base, + const PP_FloatPoint& extent) { + if (ppp_pdf_) + CallWhileUnlocked(ppp_pdf_->SetSelectionBounds, instance, &base, &extent); +} + } // namespace proxy } // namespace ppapi
diff --git a/ppapi/proxy/ppp_pdf_proxy.h b/ppapi/proxy/ppp_pdf_proxy.h index 40ba50c..095ce14b 100644 --- a/ppapi/proxy/ppp_pdf_proxy.h +++ b/ppapi/proxy/ppp_pdf_proxy.h
@@ -30,6 +30,13 @@ PP_PdfPrintPresetOptions_Dev* options, PP_Bool* result); void OnPluginMsgEnableAccessibility(PP_Instance instance); + void OnPluginMsgSetCaretPosition(PP_Instance instance, + const PP_FloatPoint& position); + void OnPluginMsgMoveRangeSelectionExtent(PP_Instance instance, + const PP_FloatPoint& extent); + void OnPluginMsgSetSelectionBounds(PP_Instance instance, + const PP_FloatPoint& base, + const PP_FloatPoint& extent); // When this proxy is in the plugin side, this value caches the interface // pointer so we don't have to retrieve it from the dispatcher each time.
diff --git a/ppapi/thunk/ppb_pdf_api.h b/ppapi/thunk/ppb_pdf_api.h index f917f0e9..1e3972b 100644 --- a/ppapi/thunk/ppb_pdf_api.h +++ b/ppapi/thunk/ppb_pdf_api.h
@@ -41,6 +41,10 @@ PP_PrivateAccessibilityTextRunInfo text_runs[], PP_PrivateAccessibilityCharInfo chars[]) = 0; virtual void SetCrashData(const char* pdf_url, const char* top_level_url) = 0; + virtual void SelectionChanged(const PP_FloatPoint& left, + int32_t left_height, + const PP_FloatPoint& right, + int32_t right_height) = 0; static const SingletonResourceID kSingletonResourceID = PDF_SINGLETON_ID; };
diff --git a/ppapi/thunk/ppb_pdf_thunk.cc b/ppapi/thunk/ppb_pdf_thunk.cc index d291b02..44c8daa 100644 --- a/ppapi/thunk/ppb_pdf_thunk.cc +++ b/ppapi/thunk/ppb_pdf_thunk.cc
@@ -169,6 +169,17 @@ enter.functions()->SetCrashData(pdf_url, top_level_url); } +void SelectionChanged(PP_Instance instance, + const PP_FloatPoint* left, + int32_t left_height, + const PP_FloatPoint* right, + int32_t right_height) { + EnterInstanceAPI<PPB_PDF_API> enter(instance); + if (enter.failed()) + return; + enter.functions()->SelectionChanged(*left, left_height, *right, right_height); +} + const PPB_PDF g_ppb_pdf_thunk = { &GetFontFileWithFallback, &GetFontTableForPrivateFontFile, @@ -188,6 +199,7 @@ &SetAccessibilityDocInfo, &SetAccessibilityPageInfo, &SetCrashData, + &SelectionChanged, }; } // namespace
diff --git a/remoting/client/chromoting_session.cc b/remoting/client/chromoting_session.cc index 50e831e..4e37888 100644 --- a/remoting/client/chromoting_session.cc +++ b/remoting/client/chromoting_session.cc
@@ -42,6 +42,9 @@ // Interval at which to log performance statistics, if enabled. const int kPerfStatsIntervalMs = 60000; +// Default DPI to assume for old clients that use notifyClientResolution. +const int kDefaultDPI = 96; + } // namespace ChromotingSession::ChromotingSession( @@ -235,6 +238,30 @@ client_->input_stub()->InjectTouchEvent(touch_event); } +void ChromotingSession::SendClientResolution(int dips_width, + int dips_height, + int scale) { + if (!runtime_->network_task_runner()->BelongsToCurrentThread()) { + runtime_->network_task_runner()->PostTask( + FROM_HERE, base::Bind(&ChromotingSession::SendClientResolution, + GetWeakPtr(), dips_width, dips_height, scale)); + return; + } + + protocol::ClientResolution client_resolution; + client_resolution.set_dips_width(dips_width); + client_resolution.set_dips_height(dips_height); + client_resolution.set_x_dpi(scale * kDefaultDPI); + client_resolution.set_y_dpi(scale * kDefaultDPI); + + // Include the legacy width & height in physical pixels for use by older + // hosts. + client_resolution.set_width_deprecated(dips_width * scale); + client_resolution.set_height_deprecated(dips_height * scale); + + client_->host_stub()->NotifyClientResolution(client_resolution); +} + void ChromotingSession::EnableVideoChannel(bool enable) { if (!runtime_->network_task_runner()->BelongsToCurrentThread()) { runtime_->network_task_runner()->PostTask(
diff --git a/remoting/client/chromoting_session.h b/remoting/client/chromoting_session.h index 29c0f67..a498f7a9 100644 --- a/remoting/client/chromoting_session.h +++ b/remoting/client/chromoting_session.h
@@ -123,6 +123,8 @@ // Sends the provided touch event payload to the host. void SendTouchEvent(const protocol::TouchEvent& touch_event); + void SendClientResolution(int dips_width, int dips_height, int scale); + // Enables or disables the video channel. May be called from any thread. void EnableVideoChannel(bool enable);
diff --git a/remoting/host/installer/win/BUILD.gn b/remoting/host/installer/win/BUILD.gn index 08908831..37ec466 100644 --- a/remoting/host/installer/win/BUILD.gn +++ b/remoting/host/installer/win/BUILD.gn
@@ -5,7 +5,6 @@ import("//remoting/build/config/remoting_build.gni") import("//remoting/host/installer/win/generate_clsids.gni") import("//build/toolchain/win/midl.gni") -import("//build/win/message_compiler.gni") action("remoting_me2me_host_archive") { script = "//remoting/host/installer/build-installer-archive.py"
diff --git a/remoting/ios/app/client_connection_view_controller.mm b/remoting/ios/app/client_connection_view_controller.mm index 2e95f2af..d4f4de52 100644 --- a/remoting/ios/app/client_connection_view_controller.mm +++ b/remoting/ios/app/client_connection_view_controller.mm
@@ -35,7 +35,7 @@ static const CGFloat kPinEntryViewWidth = 240.f; static const CGFloat kPinEntryViewHeight = 90.f; -static const CGFloat kReconnectViewWidth = 120.f; +static const CGFloat kReconnectViewWidth = 240.f; static const CGFloat kReconnectViewHeight = 90.f; static const CGFloat kPadding = 20.f; @@ -144,7 +144,7 @@ _iconView = [[UIImageView alloc] initWithFrame:CGRectZero]; _iconView.contentMode = UIViewContentModeCenter; _iconView.alpha = 0.87f; - _iconView.backgroundColor = RemotingTheme.onlineHostColor; + _iconView.backgroundColor = RemotingTheme.hostOnlineColor; _iconView.layer.cornerRadius = kIconRadius; _iconView.layer.masksToBounds = YES; _iconView.image = RemotingTheme.desktopIcon; @@ -163,8 +163,6 @@ [self.view addSubview:_pinEntryView]; _pinEntryView.delegate = self; - _reconnectView.hidden = YES; - [self initializeLayoutConstraintsWithViews:NSDictionaryOfVariableBindings( _activityIndicator, _statusLabel, @@ -417,6 +415,8 @@ _reconnectView.hidden = YES; + _iconView.backgroundColor = RemotingTheme.hostOnlineColor; + [_activityIndicator stopAnimating]; _activityIndicator.cycleColors = @[ [UIColor whiteColor] ]; _activityIndicator.indicatorMode = MDCActivityIndicatorModeIndeterminate; @@ -426,10 +426,14 @@ - (void)showPinPromptState { _statusLabel.text = [NSString stringWithFormat:@"%@", _remoteHostName]; + + _iconView.backgroundColor = RemotingTheme.hostOnlineColor; + [_activityIndicator stopAnimating]; _activityIndicator.hidden = YES; _pinEntryView.hidden = NO; + _reconnectView.hidden = YES; _reconnectView.hidden = YES; @@ -447,12 +451,15 @@ _pinEntryView.hidden = YES; [_pinEntryView clearPinEntry]; + _iconView.backgroundColor = RemotingTheme.hostOnlineColor; + _activityIndicator.progress = 0.0; _activityIndicator.hidden = NO; _activityIndicator.indicatorMode = MDCActivityIndicatorModeDeterminate; _activityIndicator.cycleColors = @[ [UIColor greenColor] ]; [_activityIndicator startAnimating]; _activityIndicator.progress = 1.0; + _reconnectView.hidden = YES; _reconnectView.hidden = YES; @@ -467,18 +474,19 @@ - (void)showReconnect { _statusLabel.text = [self stringWithHostNameForId:IDS_CONNECTION_CLOSED_FOR_HOST_MESSAGE]; + + _iconView.backgroundColor = RemotingTheme.hostErrorColor; + [_activityIndicator stopAnimating]; _activityIndicator.hidden = YES; _pinEntryView.hidden = YES; _reconnectView.hidden = NO; + _reconnectView.errorText = + l10n_util::GetNSString(IDS_MESSAGE_SESSION_FINISHED); [self.navigationController popToViewController:self animated:YES]; - [MDCSnackbarManager - showMessage:[MDCSnackbarMessage - messageWithText:l10n_util::GetNSString( - IDS_MESSAGE_SESSION_FINISHED)]]; } - (void)showError { @@ -487,77 +495,60 @@ _pinEntryView.hidden = YES; - _activityIndicator.indicatorMode = MDCActivityIndicatorModeDeterminate; - _activityIndicator.cycleColors = @[ [UIColor redColor] ]; - _activityIndicator.progress = 1.0; - _activityIndicator.hidden = NO; - [_activityIndicator startAnimating]; + _iconView.backgroundColor = RemotingTheme.hostErrorColor; - _reconnectView.hidden = NO; + _activityIndicator.hidden = YES; - // TODO(yuweih): I18N - MDCSnackbarMessage* message = nil; + NSString* message = nil; switch (_lastError) { case SessionErrorOk: // Do nothing. break; case SessionErrorPeerIsOffline: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorPeerIsOffline."]; + message = l10n_util::GetNSString(IDS_ERROR_HOST_IS_OFFLINE); break; case SessionErrorSessionRejected: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorSessionRejected."]; + message = l10n_util::GetNSString(IDS_ERROR_INVALID_ACCOUNT); break; case SessionErrorIncompatibleProtocol: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorIncompatibleProtocol."]; + message = l10n_util::GetNSString(IDS_ERROR_INCOMPATIBLE_PROTOCOL); break; case SessionErrorAuthenticationFailed: - message = [MDCSnackbarMessage messageWithText:@"Error: Invalid Pin."]; + message = l10n_util::GetNSString(IDS_ERROR_INVALID_ACCESS_CODE); [_pinEntryView clearPinEntry]; break; case SessionErrorInvalidAccount: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorInvalidAccount."]; + message = l10n_util::GetNSString(IDS_ERROR_INVALID_ACCOUNT); break; case SessionErrorChannelConnectionError: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorChannelConnectionError."]; + message = l10n_util::GetNSString(IDS_ERROR_NETWORK_FAILURE); break; case SessionErrorSignalingError: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorSignalingError."]; + message = l10n_util::GetNSString(IDS_ERROR_P2P_FAILURE); break; case SessionErrorSignalingTimeout: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorSignalingTimeout."]; + message = l10n_util::GetNSString(IDS_ERROR_SERVICE_UNAVAILABLE); break; case SessionErrorHostOverload: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorHostOverload."]; + message = l10n_util::GetNSString(IDS_ERROR_HOST_OVERLOAD); break; case SessionErrorMaxSessionLength: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorMaxSessionLength."]; + message = l10n_util::GetNSString(IDS_ERROR_MAX_SESSION_LENGTH); break; case SessionErrorHostConfigurationError: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorHostConfigurationError."]; + message = l10n_util::GetNSString(IDS_ERROR_HOST_CONFIGURATION_ERROR); break; case SessionErrorUnknownError: - message = [MDCSnackbarMessage - messageWithText:@"Error: SessionErrorUnknownError."]; + message = l10n_util::GetNSString(IDS_ERROR_UNEXPECTED); break; case SessionErrorOAuthTokenInvalid: - message = [MDCSnackbarMessage - messageWithText: - @"Error: SessionErrorOAuthTokenInvalid. Please login again."]; + message = l10n_util::GetNSString(IDS_ERROR_OAUTH_TOKEN_INVALID); break; } - if (message.text) { - [MDCSnackbarManager showMessage:message]; + if (message) { + _reconnectView.errorText = message; } + _reconnectView.hidden = NO; } - (void)didProvidePin:(NSString*)pin createPairing:(BOOL)createPairing {
diff --git a/remoting/ios/app/first_launch_view_controller.mm b/remoting/ios/app/first_launch_view_controller.mm index eb42bc1..c407ba2 100644 --- a/remoting/ios/app/first_launch_view_controller.mm +++ b/remoting/ios/app/first_launch_view_controller.mm
@@ -19,8 +19,8 @@ static const float kButtonHeight = 80.f; @interface FirstLaunchViewController () { - NSArray* _compactWidthConstraints; - NSArray* _compactHeightConstraints; + NSArray<NSLayoutConstraint*>* _compactWidthConstraints; + NSArray<NSLayoutConstraint*>* _compactHeightConstraints; } @end @@ -69,12 +69,23 @@ forAxis:UILayoutConstraintAxisVertical]; [imageView setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; + [imageView + setContentCompressionResistancePriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisVertical]; + [imageView + setContentCompressionResistancePriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisHorizontal]; + _compactWidthConstraints = @[ [imageView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:kLogoSizeMultiplier] ]; + _compactWidthConstraints[0].priority = UILayoutPriorityDefaultHigh; + _compactHeightConstraints = @[ [imageView.heightAnchor constraintEqualToAnchor:self.view.heightAnchor multiplier:kLogoSizeMultiplier] ]; + _compactHeightConstraints[0].priority = UILayoutPriorityDefaultHigh; + [NSLayoutConstraint activateConstraints:@[ [imageView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], [imageView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor @@ -93,13 +104,19 @@ } - (void)refreshTraitCollection { - if (self.traitCollection.horizontalSizeClass == + if (self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) { + [NSLayoutConstraint deactivateConstraints:_compactWidthConstraints]; + [NSLayoutConstraint activateConstraints:_compactHeightConstraints]; + } else if (self.traitCollection.horizontalSizeClass == + UIUserInterfaceSizeClassCompact && + self.traitCollection.verticalSizeClass == + UIUserInterfaceSizeClassRegular) { [NSLayoutConstraint deactivateConstraints:_compactHeightConstraints]; [NSLayoutConstraint activateConstraints:_compactWidthConstraints]; } else { [NSLayoutConstraint deactivateConstraints:_compactWidthConstraints]; - [NSLayoutConstraint activateConstraints:_compactHeightConstraints]; + [NSLayoutConstraint deactivateConstraints:_compactHeightConstraints]; } }
diff --git a/remoting/ios/app/host_collection_view_cell.mm b/remoting/ios/app/host_collection_view_cell.mm index 2a3619cb..e106547 100644 --- a/remoting/ios/app/host_collection_view_cell.mm +++ b/remoting/ios/app/host_collection_view_cell.mm
@@ -53,7 +53,7 @@ _imageView = [[UIImageView alloc] init]; _imageView.translatesAutoresizingMaskIntoConstraints = NO; _imageView.contentMode = UIViewContentModeCenter; - _imageView.backgroundColor = RemotingTheme.offlineHostColor; + _imageView.backgroundColor = RemotingTheme.hostOfflineColor; _imageView.layer.cornerRadius = kHostCardIconSize / 2.f; _imageView.layer.masksToBounds = YES; [self.contentView addSubview:_imageView]; @@ -136,10 +136,10 @@ _imageView.image = RemotingTheme.desktopIcon; if ([_hostInfo.status isEqualToString:@"ONLINE"]) { - _imageView.backgroundColor = RemotingTheme.onlineHostColor; + _imageView.backgroundColor = RemotingTheme.hostOnlineColor; _statusLabel.text = l10n_util::GetNSString(IDS_HOST_ONLINE_SUBTITLE); } else { - _imageView.backgroundColor = RemotingTheme.offlineHostColor; + _imageView.backgroundColor = RemotingTheme.hostOfflineColor; _statusLabel.text = hostInfo.updatedTime ? l10n_util::GetNSStringF(
diff --git a/remoting/ios/app/host_setup_view_cell.mm b/remoting/ios/app/host_setup_view_cell.mm index b37c878..2c11936 100644 --- a/remoting/ios/app/host_setup_view_cell.mm +++ b/remoting/ios/app/host_setup_view_cell.mm
@@ -45,7 +45,7 @@ _contentLabel.lineBreakMode = NSLineBreakByWordWrapping; _contentLabel.numberOfLines = 0; - _numberContainerView.backgroundColor = RemotingTheme.onlineHostColor; + _numberContainerView.backgroundColor = RemotingTheme.hostOnlineColor; _numberLabel.textColor = RemotingTheme.setupListNumberColor; _contentLabel.textColor = RemotingTheme.setupListTextColor; _numberLabel.font = MDCTypography.titleFont;
diff --git a/remoting/ios/app/host_view_controller.mm b/remoting/ios/app/host_view_controller.mm index cc6ca3b..f180268 100644 --- a/remoting/ios/app/host_view_controller.mm +++ b/remoting/ios/app/host_view_controller.mm
@@ -84,7 +84,7 @@ _actionImageView = [[MDCActionImageView alloc] initWithFrame:_floatingButton.bounds - primaryImage:RemotingTheme.settingsIcon + primaryImage:RemotingTheme.menuIcon activeImage:RemotingTheme.closeIcon]; [_floatingButton addSubview:_actionImageView]; [self.view addSubview:_floatingButton]; @@ -115,6 +115,7 @@ // the surface is not ready to handle the transformation matrix. // Call onSurfaceChanged here to cover that case. [_client surfaceChanged:self.view.frame]; + [self resizeHostToFitIfNeeded]; } - (void)viewWillAppear:(BOOL)animated { @@ -154,6 +155,7 @@ // If the context is not set yet, the view size will be set in // viewDidAppear. [_client surfaceChanged:self.view.bounds]; + [self resizeHostToFitIfNeeded]; } CGSize btnSize = _floatingButton.frame.size; @@ -244,10 +246,10 @@ } - (void)setResizeToFit:(BOOL)resizeToFit { - // TODO(nicholss): I don't think this option makes sense for phones. Maybe - // for an iPad. Maybe we add a native screen size mimimum before enabling - // this option? Ask Jon. - NSLog(@"TODO: resizeToFit %d", resizeToFit); + // TODO(yuweih): Maybe we add a native screen size mimimum before enabling + // this option? This doesn't work well for smaller screens. Ask Jon. + _settings.shouldResizeHostToFit = resizeToFit; + [self resizeHostToFitIfNeeded]; } - (void)useDirectInputMode { @@ -270,6 +272,13 @@ #pragma mark - Private +- (void)resizeHostToFitIfNeeded { + if (_settings.shouldResizeHostToFit) { + [_client setHostResolution:self.view.frame.size + scale:self.view.contentScaleFactor]; + } +} + - (void)applyInputMode { switch (_settings.inputMode) { case ClientInputModeTrackpad: @@ -352,6 +361,8 @@ [[RemotingSettingsViewController alloc] init]; settingsViewController.delegate = weakSelf; settingsViewController.inputMode = currentInputMode; + settingsViewController.shouldResizeHostToFit = + _settings.shouldResizeHostToFit; UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:settingsViewController]; [weakSelf presentViewController:navController animated:YES completion:nil];
diff --git a/remoting/ios/app/pin_entry_view.mm b/remoting/ios/app/pin_entry_view.mm index f5debd25..032f0cc3 100644 --- a/remoting/ios/app/pin_entry_view.mm +++ b/remoting/ios/app/pin_entry_view.mm
@@ -60,6 +60,9 @@ setImage:[RemotingTheme .arrowIcon imageFlippedForRightToLeftLayoutDirection] forState:UIControlStateNormal]; + [_pinButton setBackgroundColor:RemotingTheme.buttonBackgroundColor + forState:UIControlStateNormal]; + [_pinButton setDisabledAlpha:0.7]; [_pinButton addTarget:self action:@selector(didTapPinEntry:) forControlEvents:UIControlEventTouchUpInside];
diff --git a/remoting/ios/app/remoting_theme.h b/remoting/ios/app/remoting_theme.h index 52f5c1a..b61ead2c 100644 --- a/remoting/ios/app/remoting_theme.h +++ b/remoting/ios/app/remoting_theme.h
@@ -12,19 +12,20 @@ // Colors -@property(class, nonatomic, readonly) UIColor* firstLaunchViewBackgroundColor; -@property(class, nonatomic, readonly) UIColor* connectionViewBackgroundColor; -@property(class, nonatomic, readonly) UIColor* hostListBackgroundColor; -@property(class, nonatomic, readonly) UIColor* hostListRefreshIndicatorColor; -@property(class, nonatomic, readonly) UIColor* menuBlueColor; -@property(class, nonatomic, readonly) UIColor* offlineHostColor; -@property(class, nonatomic, readonly) UIColor* onlineHostColor; @property(class, nonatomic, readonly) UIColor* buttonBackgroundColor; @property(class, nonatomic, readonly) UIColor* buttonTextColor; +@property(class, nonatomic, readonly) UIColor* connectionViewBackgroundColor; +@property(class, nonatomic, readonly) UIColor* firstLaunchViewBackgroundColor; @property(class, nonatomic, readonly) UIColor* flatButtonTextColor; +@property(class, nonatomic, readonly) UIColor* hostErrorColor; +@property(class, nonatomic, readonly) UIColor* hostListBackgroundColor; +@property(class, nonatomic, readonly) UIColor* hostListRefreshIndicatorColor; +@property(class, nonatomic, readonly) UIColor* hostOfflineColor; +@property(class, nonatomic, readonly) UIColor* hostOnlineColor; +@property(class, nonatomic, readonly) UIColor* menuBlueColor; @property(class, nonatomic, readonly) UIColor* setupListBackgroundColor; -@property(class, nonatomic, readonly) UIColor* setupListTextColor; @property(class, nonatomic, readonly) UIColor* setupListNumberColor; +@property(class, nonatomic, readonly) UIColor* setupListTextColor; @property(class, nonatomic, readonly) UIColor* sideMenuIconColor; // Icons @@ -35,13 +36,13 @@ @property(class, nonatomic, readonly) UIImage* checkboxOutlineIcon; @property(class, nonatomic, readonly) UIImage* closeIcon; @property(class, nonatomic, readonly) UIImage* desktopIcon; +@property(class, nonatomic, readonly) UIImage* feedbackIcon; +@property(class, nonatomic, readonly) UIImage* helpIcon; @property(class, nonatomic, readonly) UIImage* menuIcon; @property(class, nonatomic, readonly) UIImage* radioCheckedIcon; @property(class, nonatomic, readonly) UIImage* radioOutlineIcon; @property(class, nonatomic, readonly) UIImage* refreshIcon; @property(class, nonatomic, readonly) UIImage* settingsIcon; -@property(class, nonatomic, readonly) UIImage* helpIcon; -@property(class, nonatomic, readonly) UIImage* feedbackIcon; @end
diff --git a/remoting/ios/app/remoting_theme.mm b/remoting/ios/app/remoting_theme.mm index 046ae37..34da7a2 100644 --- a/remoting/ios/app/remoting_theme.mm +++ b/remoting/ios/app/remoting_theme.mm
@@ -55,7 +55,7 @@ return color; } -+ (UIColor*)offlineHostColor { ++ (UIColor*)hostOfflineColor { static UIColor* color; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -64,7 +64,7 @@ return color; } -+ (UIColor*)onlineHostColor { ++ (UIColor*)hostOnlineColor { static UIColor* color; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -73,6 +73,18 @@ return color; } ++ (UIColor*)hostErrorColor { + static UIColor* color; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + color = [UIColor colorWithRed:249.f / 255.f + green:146.f / 255.f + blue:34.f / 255.f + alpha:1.f]; + }); + return color; +} + + (UIColor*)buttonBackgroundColor { static UIColor* color; static dispatch_once_t onceToken;
diff --git a/remoting/ios/app/session_reconnect_view.h b/remoting/ios/app/session_reconnect_view.h index 2909cd53..79a2102 100644 --- a/remoting/ios/app/session_reconnect_view.h +++ b/remoting/ios/app/session_reconnect_view.h
@@ -22,6 +22,9 @@ // This delegate will handle interactions on the view. @property(weak, nonatomic) id<SessionReconnectViewDelegate> delegate; +// This is the optional error text to be displayed above the reconnect button. +@property(nonatomic, copy) NSString* errorText; + @end #endif // REMOTING_IOS_SESSON_RECONNECT_VIEW_H_
diff --git a/remoting/ios/app/session_reconnect_view.mm b/remoting/ios/app/session_reconnect_view.mm index 7f4bdd5..ba1e778 100644 --- a/remoting/ios/app/session_reconnect_view.mm +++ b/remoting/ios/app/session_reconnect_view.mm
@@ -14,11 +14,11 @@ #include "remoting/base/string_resources.h" #include "ui/base/l10n/l10n_util.h" -static const CGFloat kReconnectButtonWidth = 120.f; -static const CGFloat kReconnectButtonHeight = 30.f; +static const CGFloat kPadding = 20.f; @interface SessionReconnectView () { - MDCRaisedButton* _reconnectButton; + MDCFloatingButton* _reconnectButton; + UILabel* _errorLabel; } @end @@ -31,7 +31,15 @@ if (self) { self.backgroundColor = [UIColor clearColor]; - _reconnectButton = [[MDCRaisedButton alloc] init]; + _reconnectButton = + [MDCFloatingButton floatingButtonWithShape:MDCFloatingButtonShapeMini]; + [_reconnectButton + setImage:[RemotingTheme + .refreshIcon imageFlippedForRightToLeftLayoutDirection] + forState:UIControlStateNormal]; + [_reconnectButton setBackgroundColor:RemotingTheme.buttonBackgroundColor + forState:UIControlStateNormal]; + [_reconnectButton setElevation:4.0f forState:UIControlStateNormal]; [_reconnectButton setTitle:l10n_util::GetNSString(IDS_RECONNECT) forState:UIControlStateNormal]; @@ -41,33 +49,64 @@ _reconnectButton.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:_reconnectButton]; + _errorLabel = [[UILabel alloc] init]; + _errorLabel.textColor = RemotingTheme.hostErrorColor; + _errorLabel.font = [UIFont systemFontOfSize:13.f]; + _errorLabel.numberOfLines = 0; + _errorLabel.lineBreakMode = NSLineBreakByWordWrapping; + _errorLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_errorLabel]; + [self initializeLayoutConstraintsWithViews:NSDictionaryOfVariableBindings( - _reconnectButton)]; + _reconnectButton, + _errorLabel)]; } return self; } - (void)initializeLayoutConstraintsWithViews:(NSDictionary*)views { - NSMutableArray* layoutConstraints = [NSMutableArray array]; + // NSMutableArray* layoutConstraints = [NSMutableArray array]; + // Metrics to use in visual format strings. + NSDictionary* layoutMetrics = @{ + @"padding" : @(kPadding), + }; - [layoutConstraints addObject:[_reconnectButton.centerYAnchor - constraintEqualToAnchor:self.centerYAnchor]]; + [self + addConstraints:[NSLayoutConstraint + constraintsWithVisualFormat: + @"H:|-[_errorLabel]-(padding)-[_reconnectButton]-|" + options:0 + metrics:layoutMetrics + views:views]]; + [self addConstraints:[NSLayoutConstraint + constraintsWithVisualFormat:@"V:|-[_errorLabel]" + options:0 + metrics:layoutMetrics + views:views]]; + [self addConstraints:[NSLayoutConstraint + constraintsWithVisualFormat:@"V:|-[_reconnectButton]" + options:0 + metrics:layoutMetrics + views:views]]; - [layoutConstraints addObject:[_reconnectButton.centerXAnchor - constraintEqualToAnchor:self.centerXAnchor]]; - - [layoutConstraints - addObject:[_reconnectButton.widthAnchor - constraintEqualToConstant:kReconnectButtonWidth]]; - - [layoutConstraints - addObject:[_reconnectButton.heightAnchor - constraintEqualToConstant:kReconnectButtonHeight]]; - - [NSLayoutConstraint activateConstraints:layoutConstraints]; [self setNeedsUpdateConstraints]; } +#pragma mark - Properties + +- (void)setErrorText:(NSString*)errorText { + if (errorText) { + _errorLabel.text = errorText; + _errorLabel.hidden = NO; + } else { + _errorLabel.hidden = YES; + } +} + +- (NSString*)errorText { + return _errorLabel.text; +} + #pragma mark - Private - (void)didTapReconnect:(id)sender {
diff --git a/remoting/ios/app/settings/remoting_settings_view_controller.h b/remoting/ios/app/settings/remoting_settings_view_controller.h index c675336..187b789a 100644 --- a/remoting/ios/app/settings/remoting_settings_view_controller.h +++ b/remoting/ios/app/settings/remoting_settings_view_controller.h
@@ -36,6 +36,7 @@ @property(weak, nonatomic) id<RemotingSettingsViewControllerDelegate> delegate; @property(nonatomic) remoting::GestureInterpreter::InputMode inputMode; +@property(nonatomic) BOOL shouldResizeHostToFit; @end
diff --git a/remoting/ios/app/settings/remoting_settings_view_controller.mm b/remoting/ios/app/settings/remoting_settings_view_controller.mm index c32980b..b74cda9 100644 --- a/remoting/ios/app/settings/remoting_settings_view_controller.mm +++ b/remoting/ios/app/settings/remoting_settings_view_controller.mm
@@ -32,6 +32,7 @@ @synthesize delegate = _delegate; @synthesize inputMode = _inputMode; +@synthesize shouldResizeHostToFit = _shouldResizeHostToFit; - (id)init { self = [super init]; @@ -233,6 +234,8 @@ __weak RemotingSettingsViewController* weakSelf = self; +// We are not going to support the shrink option for now. +#if 0 SettingOption* shrinkOption = [[SettingOption alloc] init]; shrinkOption.title = l10n_util::GetNSString(IDS_SHRINK_TO_FIT); // TODO(nicholss): I think this text changes based on value. Confirm. @@ -245,13 +248,14 @@ [weakSelf.delegate setShrinkToFit:weakShrinkOption.checked]; } }; +#endif SettingOption* resizeOption = [[SettingOption alloc] init]; resizeOption.title = l10n_util::GetNSString(IDS_RESIZE_TO_CLIENT); // TODO(nicholss): I think this text changes based on value. Confirm. resizeOption.subtext = l10n_util::GetNSString(IDS_RESIZE_TO_CLIENT_SUBTITLE); resizeOption.style = OptionCheckbox; - resizeOption.checked = YES; + resizeOption.checked = self.shouldResizeHostToFit; __weak SettingOption* weakResizeOption = resizeOption; resizeOption.action = ^{ if ([weakSelf.delegate respondsToSelector:@selector(setResizeToFit:)]) { @@ -259,7 +263,7 @@ } }; - [_content addObject:@[ shrinkOption, resizeOption ]]; + [_content addObject:@[ resizeOption ]]; SettingOption* directMode = [[SettingOption alloc] init]; directMode.title = l10n_util::GetNSString(IDS_SELECT_TOUCH_MODE);
diff --git a/remoting/ios/domain/host_settings.h b/remoting/ios/domain/host_settings.h index 25e95b6..208cf136 100644 --- a/remoting/ios/domain/host_settings.h +++ b/remoting/ios/domain/host_settings.h
@@ -19,6 +19,7 @@ // Various properties of the Remoting Settings. @property(nonatomic, copy) NSString* hostId; @property(nonatomic) ClientInputMode inputMode; +@property(nonatomic) BOOL shouldResizeHostToFit; @end
diff --git a/remoting/ios/domain/host_settings.mm b/remoting/ios/domain/host_settings.mm index 4c8e9503..b256ff3 100644 --- a/remoting/ios/domain/host_settings.mm +++ b/remoting/ios/domain/host_settings.mm
@@ -12,6 +12,7 @@ @synthesize hostId = _hostId; @synthesize inputMode = _inputMode; +@synthesize shouldResizeHostToFit = _shouldResizeHostToFit; - (id)initWithCoder:(NSCoder*)coder { self = [super init]; @@ -19,6 +20,8 @@ self.hostId = [coder decodeObjectForKey:@"hostId"]; NSNumber* mode = [coder decodeObjectForKey:@"inputMode"]; self.inputMode = (ClientInputMode)[mode intValue]; + self.shouldResizeHostToFit = + [[coder decodeObjectForKey:@"shouldResizeHostToFit"] boolValue]; } return self; } @@ -27,6 +30,8 @@ [coder encodeObject:self.hostId forKey:@"hostId"]; NSNumber* mode = [NSNumber numberWithInt:self.inputMode]; [coder encodeObject:mode forKey:@"inputMode"]; + [coder encodeObject:@(self.shouldResizeHostToFit) + forKey:@"shouldResizeHostToFit"]; } - (NSString*)description {
diff --git a/remoting/ios/session/remoting_client.h b/remoting/ios/session/remoting_client.h index 817ce146..0591812 100644 --- a/remoting/ios/session/remoting_client.h +++ b/remoting/ios/session/remoting_client.h
@@ -75,6 +75,8 @@ // Notifies all components that the frame of the surface has changed. - (void)surfaceChanged:(const CGRect&)frame; +- (void)setHostResolution:(CGSize)dipsResolution scale:(int)scale; + // The display handler tied to the remoting client used to display the host. @property(nonatomic, strong) GlDisplayHandler* displayHandler; // The host info used to make the remoting client connection.
diff --git a/remoting/ios/session/remoting_client.mm b/remoting/ios/session/remoting_client.mm index 53946ea..2030bbaf 100644 --- a/remoting/ios/session/remoting_client.mm +++ b/remoting/ios/session/remoting_client.mm
@@ -335,6 +335,11 @@ frame.size.height); } +- (void)setHostResolution:(CGSize)dipsResolution scale:(int)scale { + _session->SendClientResolution(dipsResolution.width, dipsResolution.height, + scale); +} + #pragma mark - GlDisplayHandlerDelegate - (void)canvasSizeChanged:(CGSize)size {
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd index 1686ff67..c6c0d5e 100644 --- a/remoting/resources/remoting_strings.grd +++ b/remoting/resources/remoting_strings.grd
@@ -867,6 +867,9 @@ <message desc="Error displayed when the service returns a 503 error. Such errors are usually temporary, and resolve themselves in about 30 seconds." name="IDS_ERROR_SERVICE_UNAVAILABLE"> The service is temporarily unavailable. Please try again later. </message> + <message desc="Error displayed when the user's oauth token is invalid." name="IDS_ERROR_OAUTH_TOKEN_INVALID"> + There was an issue authenticating, please login again. + </message> <message desc="Error displayed in situations where things go wrong in ways not anticipated by the developers. There is typically no user-workaround to suggest, other than reporting the error so that we can investigate further." name="IDS_ERROR_UNEXPECTED" formatter_data="android_java"> An unexpected error occurred. Please report this problem to the developers. </message>
diff --git a/sandbox/mac/sandbox_mac_compiler_v2_unittest.mm b/sandbox/mac/sandbox_mac_compiler_v2_unittest.mm index 94745f99..1bdb178b 100644 --- a/sandbox/mac/sandbox_mac_compiler_v2_unittest.mm +++ b/sandbox/mac/sandbox_mac_compiler_v2_unittest.mm
@@ -16,6 +16,7 @@ #include "base/files/file.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/mac/mac_util.h" #include "base/process/kill.h" #include "base/test/multiprocess_test.h" @@ -40,11 +41,12 @@ "(define allowed-dir \"ALLOWED_READ_DIR\")\n" "(define temp-file \"ALLOWED_TEMP_FILE\")\n" "(define is-pre-10_10 \"IS_PRE_10_10\")\n" + "(define zone-tab \"ZONE_TAB\")\n" "; Make it easier to drop (literal) once we stop supporting 10.9\n" "(define (path x) (literal x))\n" - "(allow file-read-metadata (subpath \"/Applications\"))\n" + "(allow file-read-metadata (subpath \"/\"))\n" "(allow file-read* (subpath (param allowed-dir)))\n" - "(allow file-read-data (path \"/usr/share/zoneinfo/zone.tab\"))\n" + "(allow file-read-data (path (param zone-tab)))\n" "(allow file-write* (path (param temp-file)))\n" "(allow ipc-posix-shm-read-data (ipc-posix-name " "\"apple.shm.notification_center\"))\n" @@ -60,6 +62,11 @@ CHECK(compiler.InsertBooleanParam("IS_PRE_10_10", !base::mac::IsAtLeastOS10_10())); + // crbug.com/748517: The zoneinfo folder is a symlink on 10.13. + base::FilePath zone_tab_path("/usr/share/zoneinfo/zone.tab"); + zone_tab_path = base::MakeAbsoluteFilePath(zone_tab_path); + CHECK(compiler.InsertStringParam("ZONE_TAB", zone_tab_path.value())); + std::string error; bool result = compiler.CompileAndApplyProfile(&error); CHECK(result) << error;
diff --git a/services/identity/README.md b/services/identity/README.md index 4eb09e9..3058778 100644 --- a/services/identity/README.md +++ b/services/identity/README.md
@@ -93,17 +93,6 @@ If the above guidance does not suffice for your use case, please contact blundell@chromium.org. -## Listening for All Refresh Tokens Being Loaded - -The Identity Service does not expose the event of all refresh tokens having been -loaded (i.e., OAuth2TokenService::Observer::OnRefreshTokensLoaded()). Rather, -the Identity Service guarantees that it does not respond to consumer requests -until its internal state has stabilized after startup (and in particular, until -all refresh tokens have been loaded). Thus, if a client queries whether a given -account has a refresh token available and receives a response that it doesn't, -there is no need for the client to worry about the edge case where the refresh -token might be still in the process of being loaded from disk. - ## Observing Signin-Related Events There are plans to build a unified Observer interface that will supersede the
diff --git a/services/identity/identity_manager_unittest.cc b/services/identity/identity_manager_unittest.cc index a2e5ba8b..2d338fd 100644 --- a/services/identity/identity_manager_unittest.cc +++ b/services/identity/identity_manager_unittest.cc
@@ -24,17 +24,6 @@ namespace identity { namespace { -// Delay that is long enough that the Identity Manager will receive and respond -// to a sent request within this delay *if* the connection is allowed. Local -// experimentation indicates that 2500 microseconds is long enough to allow this -// round trip to occur; we double that to give padding. Note that this delay is -// only ever used in cases where we want to verify that a message wasn't -// responded to by the Identity Manager. Hence, if this time is ever too short -// it won't cause tests to hang; it will simply mean that in that case the tests -// might pass because the connection wasn't made *yet* as opposed to wasn't made -// *at all*. -const int kRoundTripMessageTimeInMicroseconds = 5000; - #if defined(OS_CHROMEOS) using SigninManagerForTest = FakeSigninManagerBase; #else @@ -205,73 +194,9 @@ DISALLOW_COPY_AND_ASSIGN(IdentityManagerTest); }; -// Tests that the Identity Service delays responding to consumers until its -// internal state is stable after startup. -TEST_F(IdentityManagerTest, StartupBeforeInternalStateStable) { - EXPECT_FALSE(token_service()->AreAllCredentialsLoaded()); - AccountInfo sentinel; - sentinel.account_id = "sentinel"; - primary_account_info_ = sentinel; - - // Make a call to the IdentityManager before the Identity Service has reached - // an internal stable state, and verify that the IdentityManager does not yet - // respond. - base::RunLoop run_loop; - GetIdentityManager()->GetPrimaryAccountInfo( - base::Bind(&IdentityManagerTest::OnReceivedPrimaryAccountInfo, - base::Unretained(this), run_loop.QuitClosure())); - - // Spin the run loop long enough for the above request to reach the Identity - // Service and for the Identity Manager to process it *if* it were started up - // in response. Note that it's not possible to wait on |run_loop| here since - // the behavior we're looking to verify is that the above callback is *not* - // invoked at this point. It's also not possible to use - // FlushIdentityManagerForTesting(), as the Identity Service might not even - // bind the IdentityManager request before initialization. - base::RunLoop run_loop2; - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, run_loop2.QuitClosure(), - base::TimeDelta::FromMicroseconds(kRoundTripMessageTimeInMicroseconds)); - run_loop2.Run(); - - // Verify that the callback to GetPrimaryAccountInfo() was not invoked. - EXPECT_TRUE(primary_account_info_); - EXPECT_EQ("sentinel", primary_account_info_->account_id); - - // Put the Identity Service in an internal stable state. - token_service()->LoadCredentials("sentinel"); - EXPECT_TRUE(token_service()->AreAllCredentialsLoaded()); - - // Verify that the IdentityManager now responds to our earlier call. - run_loop.Run(); - EXPECT_FALSE(primary_account_info_); -} - -// Tests that the Identity Service immediately responds to consumers if first -// connected to after its internal dependencies have reached a stable state. -TEST_F(IdentityManagerTest, StartupAfterInternalStateStable) { - EXPECT_FALSE(token_service()->AreAllCredentialsLoaded()); - token_service()->LoadCredentials("sentinel"); - EXPECT_TRUE(token_service()->AreAllCredentialsLoaded()); - AccountInfo sentinel; - sentinel.account_id = "sentinel"; - primary_account_info_ = sentinel; - - // Connect to the Identity Manager (causing the Identity Service to be started - // up), and verify that the Identity Manager responds immediately. - base::RunLoop run_loop; - GetIdentityManager()->GetPrimaryAccountInfo( - base::Bind(&IdentityManagerTest::OnReceivedPrimaryAccountInfo, - base::Unretained(this), run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_FALSE(primary_account_info_); -} - // Tests that it is not possible to connect to the Identity Manager if // initiated after SigninManager shutdown. TEST_F(IdentityManagerTest, SigninManagerShutdownBeforeConnection) { - token_service()->LoadCredentials("sentinel"); - AccountInfo sentinel; sentinel.account_id = "sentinel"; primary_account_info_ = sentinel; @@ -302,8 +227,6 @@ // Tests that the Identity Manager destroys itself on SigninManager shutdown. TEST_F(IdentityManagerTest, SigninManagerShutdownAfterConnection) { - token_service()->LoadCredentials("dummy"); - base::RunLoop run_loop; SetIdentityManagerConnectionErrorHandler(run_loop.QuitClosure()); @@ -317,8 +240,6 @@ // Check that the primary account info is null if not signed in. TEST_F(IdentityManagerTest, GetPrimaryAccountInfoNotSignedIn) { - token_service()->LoadCredentials("dummy"); - base::RunLoop run_loop; GetIdentityManager()->GetPrimaryAccountInfo( base::Bind(&IdentityManagerTest::OnReceivedPrimaryAccountInfo, @@ -330,8 +251,6 @@ // Check that the primary account info has expected values if signed in without // a refresh token available. TEST_F(IdentityManagerTest, GetPrimaryAccountInfoSignedInNoRefreshToken) { - token_service()->LoadCredentials("dummy"); - signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail); base::RunLoop run_loop; GetIdentityManager()->GetPrimaryAccountInfo( @@ -350,8 +269,6 @@ // Check that the primary account info has expected values if signed in with a // refresh token available. TEST_F(IdentityManagerTest, GetPrimaryAccountInfoSignedInRefreshToken) { - token_service()->LoadCredentials("dummy"); - signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail); token_service()->UpdateCredentials( signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken); @@ -372,8 +289,6 @@ // Check that GetPrimaryAccountWhenAvailable() returns immediately in the // case where the primary account is available when the call is received. TEST_F(IdentityManagerTest, GetPrimaryAccountWhenAvailableSignedIn) { - token_service()->LoadCredentials("dummy"); - signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail); token_service()->UpdateCredentials( signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken); @@ -399,8 +314,6 @@ // info in the case where the primary account is made available *after* the // call is received. TEST_F(IdentityManagerTest, GetPrimaryAccountWhenAvailableSignInLater) { - token_service()->LoadCredentials("dummy"); - AccountInfo account_info; AccountState account_state; @@ -439,8 +352,6 @@ // info in the case where signin is done before the call is received but the // refresh token is made available only *after* the call is received. TEST_F(IdentityManagerTest, GetPrimaryAccountWhenAvailableTokenAvailableLater) { - token_service()->LoadCredentials("dummy"); - AccountInfo account_info; AccountState account_state; @@ -489,8 +400,6 @@ #if !defined(OS_CHROMEOS) TEST_F(IdentityManagerTest, GetPrimaryAccountWhenAvailableAuthenticationAvailableLater) { - token_service()->LoadCredentials("dummy"); - AccountInfo account_info; AccountState account_state; @@ -546,8 +455,6 @@ // info to all callers in the case where the primary account is made available // after multiple overlapping calls have been received. TEST_F(IdentityManagerTest, GetPrimaryAccountWhenAvailableOverlappingCalls) { - token_service()->LoadCredentials("dummy"); - AccountInfo account_info1; AccountState account_state1; base::RunLoop run_loop; @@ -600,8 +507,6 @@ // Check that the account info for a given GAIA ID is null if that GAIA ID is // unknown. TEST_F(IdentityManagerTest, GetAccountInfoForUnknownGaiaID) { - token_service()->LoadCredentials("dummy"); - base::RunLoop run_loop; GetIdentityManager()->GetAccountInfoFromGaiaId( kTestGaiaId, @@ -614,8 +519,6 @@ // Check that the account info for a given GAIA ID has expected values if that // GAIA ID is known and there is no refresh token available for it. TEST_F(IdentityManagerTest, GetAccountInfoForKnownGaiaIdNoRefreshToken) { - token_service()->LoadCredentials("dummy"); - std::string account_id = account_tracker()->SeedAccountInfo(kTestGaiaId, kTestEmail); base::RunLoop run_loop; @@ -635,8 +538,6 @@ // Check that the account info for a given GAIA ID has expected values if that // GAIA ID is known and has a refresh token available. TEST_F(IdentityManagerTest, GetAccountInfoForKnownGaiaIdRefreshToken) { - token_service()->LoadCredentials("dummy"); - std::string account_id = account_tracker()->SeedAccountInfo(kTestGaiaId, kTestEmail); token_service()->UpdateCredentials(account_id, kTestRefreshToken); @@ -657,8 +558,6 @@ // Check that the expected error is received if requesting an access token when // not signed in. TEST_F(IdentityManagerTest, GetAccessTokenNotSignedIn) { - token_service()->LoadCredentials("dummy"); - base::RunLoop run_loop; GetIdentityManager()->GetAccessToken( kTestGaiaId, ScopeSet(), "dummy_consumer", @@ -673,8 +572,6 @@ // Check that the expected access token is received if requesting an access // token when signed in. TEST_F(IdentityManagerTest, GetAccessTokenSignedIn) { - token_service()->LoadCredentials("dummy"); - signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail); std::string account_id = signin_manager()->GetAuthenticatedAccountId(); token_service()->UpdateCredentials(account_id, kTestRefreshToken);
diff --git a/services/identity/identity_service.cc b/services/identity/identity_service.cc index eb1c96c0..1906752a 100644 --- a/services/identity/identity_service.cc +++ b/services/identity/identity_service.cc
@@ -17,7 +17,6 @@ token_service_(token_service) { registry_.AddInterface<mojom::IdentityManager>( base::Bind(&IdentityService::Create, base::Unretained(this))); - token_service_->AddObserver(this); signin_manager_shutdown_subscription_ = signin_manager_->RegisterOnShutdownCallback( base::Bind(&IdentityService::ShutDown, base::Unretained(this))); @@ -36,23 +35,12 @@ registry_.BindInterface(interface_name, std::move(interface_pipe)); } -void IdentityService::OnRefreshTokensLoaded() { - DCHECK(IsInitializationComplete()); - - for (auto&& request : pending_identity_manager_requests_) { - BindIdentityManagerRequest(std::move(request)); - } - pending_identity_manager_requests_.clear(); -} - void IdentityService::ShutDown() { if (IsShutDown()) return; - pending_identity_manager_requests_.clear(); signin_manager_ = nullptr; signin_manager_shutdown_subscription_.reset(); - token_service_->RemoveObserver(this); token_service_ = nullptr; account_tracker_ = nullptr; } @@ -61,27 +49,13 @@ return (signin_manager_ == nullptr); } -bool IdentityService::IsInitializationComplete() { - return token_service_->AreAllCredentialsLoaded(); -} - -void IdentityService::BindIdentityManagerRequest( - mojom::IdentityManagerRequest request) { - IdentityManager::Create(std::move(request), account_tracker_, signin_manager_, - token_service_); -} - void IdentityService::Create(mojom::IdentityManagerRequest request) { // This instance cannot service requests if it has already been shut down. if (IsShutDown()) return; - if (!IsInitializationComplete()) { - pending_identity_manager_requests_.push_back(std::move(request)); - return; - } - - BindIdentityManagerRequest(std::move(request)); + IdentityManager::Create(std::move(request), account_tracker_, signin_manager_, + token_service_); } } // namespace identity
diff --git a/services/identity/identity_service.h b/services/identity/identity_service.h index d10ae89..c0fe76b 100644 --- a/services/identity/identity_service.h +++ b/services/identity/identity_service.h
@@ -5,21 +5,17 @@ #ifndef SERVICES_IDENTITY_IDENTITY_SERVICE_H_ #define SERVICES_IDENTITY_IDENTITY_SERVICE_H_ -#include <vector> - -#include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_manager_base.h" #include "services/identity/public/interfaces/identity_manager.mojom.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/service.h" class AccountTrackerService; -class SigninManagerBase; +class ProfileOAuth2TokenService; namespace identity { -class IdentityService : public service_manager::Service, - public OAuth2TokenService::Observer { +class IdentityService : public service_manager::Service { public: IdentityService(AccountTrackerService* account_tracker, SigninManagerBase* signin_manager, @@ -33,9 +29,6 @@ const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) override; - // OAuth2TokenService::Observer: - void OnRefreshTokensLoaded() override; - void Create(mojom::IdentityManagerRequest request); // Shuts down this instance, blocking it from serving any pending or future @@ -44,21 +37,10 @@ void ShutDown(); bool IsShutDown(); - // Returns whether all internal dependencies have finished initialization. - bool IsInitializationComplete(); - - // Binds |request| to a new IdentityManager instance. - void BindIdentityManagerRequest(mojom::IdentityManagerRequest request); - AccountTrackerService* account_tracker_; SigninManagerBase* signin_manager_; ProfileOAuth2TokenService* token_service_; - // Requests that have come in to connect to the Identity Manager before - // initialization is complete. These requests will be serviced once - // initialization is complete. - std::vector<mojom::IdentityManagerRequest> pending_identity_manager_requests_; - std::unique_ptr<base::CallbackList<void()>::Subscription> signin_manager_shutdown_subscription_;
diff --git a/services/identity/public/interfaces/identity_manager.mojom b/services/identity/public/interfaces/identity_manager.mojom index c179982..219bff43 100644 --- a/services/identity/public/interfaces/identity_manager.mojom +++ b/services/identity/public/interfaces/identity_manager.mojom
@@ -10,11 +10,7 @@ import "services/identity/public/interfaces/google_service_auth_error.mojom"; import "services/identity/public/interfaces/scope_set.mojom"; -// Gives access to information about the user's Google accounts. NOTE: The -// IdentityManager guarantees that it will not respond to requests until its -// internal state stabilizes after startup (e.g., until all refresh tokens have -// been loaded). Consumers thus don't have to be concerned with edge cases -// around startup. +// Gives access to information about the user's Google accounts. interface IdentityManager { // Returns the AccountInfo for the Google account that serves as the user's // primary account, or null if the user has no primary account (e.g., if they
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json index 2eccc746..cda7a6e 100644 --- a/testing/buildbot/chromium.perf.fyi.json +++ b/testing/buildbot/chromium.perf.fyi.json
@@ -2991,65 +2991,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build149-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build149-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -7945,65 +7886,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build213-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build213-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results",
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index ed64208..75941d5 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -30877,65 +30877,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build151-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build151-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -35851,65 +35792,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build105-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build105-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -40805,65 +40687,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build161-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build161-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -45759,65 +45582,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build126-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build126-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -50693,65 +50457,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build27-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build27-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -55647,65 +55352,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build131-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build131-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -60601,65 +60247,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build7-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build7-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -65535,65 +65122,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build120-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build120-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -70489,65 +70017,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build135-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build135-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -75503,65 +74972,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build104-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build104-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -80497,65 +79907,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build167-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build167-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -85491,65 +84842,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build95-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build95-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -90465,65 +89757,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build188-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build188-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -95439,65 +94672,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build141-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build141-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results", @@ -100433,65 +99607,6 @@ }, { "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build146-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "smoothness.scrolling_tough_ad_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "smoothness.scrolling_tough_ad_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build146-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "smoothness.top_25_smooth", "-v", "--upload-results",
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 39960fb..4cb70a71 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -651,35 +651,10 @@ # ====== LayoutNG-only failures until here ====== # ====== DevTools test migration failures from here ====== -# Temporary failures (these tests are copies from html to js) +# Temporary failures (these tests are moves from html to js) # See crbug.com/667560 for details -crbug.com/667560 http/tests/devtools/console/console-assert.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-big-array.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-custom-formatters.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-dir-es6.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-dirxml.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-edit-expanded-tree.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-external-array.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-format-array-prototype.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-format-es6-2.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-format-es6-symbols-error.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-format-es6.js [ Skip ] -crbug.com/667560 http/tests/devtools/console/console-format-style.js [ Skip ] - ### virtual/mojo-loading/http/tests/devtools -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-assert.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-big-array.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-custom-formatters.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-dir-es6.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-dirxml.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-edit-expanded-tree.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-external-array.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-format-array-prototype.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-format-es6-2.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-format-es6-symbols-error.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-format-es6.js [ Skip ] -crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-format-style.js [ Skip ] # ====== DevTools test migration failures until here ====== @@ -2234,7 +2209,6 @@ crbug.com/626703 external/wpt/XMLHttpRequest/send-entity-body-document.htm [ Failure ] crbug.com/626703 external/wpt/XMLHttpRequest/setrequestheader-allow-empty-value.htm [ Failure ] crbug.com/626703 external/wpt/XMLHttpRequest/setrequestheader-allow-whitespace-in-value.htm [ Failure ] -crbug.com/626703 external/wpt/XMLHttpRequest/setrequestheader-content-type.htm [ Failure ] crbug.com/626703 external/wpt/XMLHttpRequest/setrequestheader-header-allowed.htm [ Failure ] crbug.com/626703 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ] crbug.com/626703 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ] @@ -3116,6 +3090,9 @@ crbug.com/736056 [ Mac ] external/wpt/encoding/legacy-mb-tchinese [ Timeout Pass ] crbug.com/736056 external/wpt/encoding/legacy-mb-korean/euc-kr/euckr-encode-form-errors-hangul.html [ Timeout Pass ] +# Needs a mac person to fix the bug +crbug.com/719737 [ Mac ] css3/flexbox/radiobutton-min-size.html [ Failure ] + # module script lacks XHTML support crbug.com/717643 external/wpt/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/radiobutton-min-size.html b/third_party/WebKit/LayoutTests/css3/flexbox/radiobutton-min-size.html new file mode 100644 index 0000000..9ae84893 --- /dev/null +++ b/third_party/WebKit/LayoutTests/css3/flexbox/radiobutton-min-size.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> + +<style> +.flex { + display: flex; + width: 500px; +} + +.wide { + width: 600px; + flex: none; +} +</style> + +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + +<p>You should see two identical-looking lines, both with a radio button at the +beginning.</p> + +<div class="flex"> + <input type="radio" id="check"> + <div class="wide">Text</div> +</div> + +<div> + <input type="radio" style="vertical-align: top;" id="ref"><span>Text</span> +</div> + +<script> +var ref = document.getElementById("ref"); +var check = document.getElementById("check"); + +test(function() { + assert_equals(ref.offsetWidth, check.offsetWidth, "width should be equal"); + assert_equals(ref.offsetHeight, check.offsetHeight, + "height should be equal"); +}, "two radio button sizes are identical"); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/inspect-headers.py b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/inspect-headers.py index c87828b..a8f1258 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/inspect-headers.py +++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/inspect-headers.py
@@ -5,10 +5,12 @@ return "Syntax error: missing CRLF: " + line line = line[:-2] - if ': ' not in line: - return "Syntax error: no colon and space: " + line + if ':' not in line: + return "Syntax error: no colon found: " + line + name, value = line.split(':', 1) + if len(value) > 1 and value[0] == ' ': + value = value[1:] - name, value = line.split(': ', 1) if filter_value: if value == filter_value: result += name + ","
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/setrequestheader-content-type-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/setrequestheader-content-type-expected.txt new file mode 100644 index 0000000..3da7ecfb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/setrequestheader-content-type-expected.txt
@@ -0,0 +1,36 @@ +This is a testharness.js-based test. +FAIL setRequestHeader("") sends a blank string assert_equals: expected "Content-Type: \n" but got "Content-Type: , text/plain;charset=UTF-8\n" +FAIL setRequestHeader(" ") sends the string " " assert_equals: expected "Content-Type: \n" but got "Content-Type: , text/plain;charset=UTF-8\n" +PASS setRequestHeader(null) sends the string "null" +PASS setRequestHeader(undefined) sends the string "undefined" +PASS String request has correct default Content-Type of "text/plain;charset=UTF-8" +PASS String request keeps setRequestHeader() Content-Type, with charset adjusted to UTF-8 +PASS XML Document request respects setRequestHeader("") +PASS XML Document request has correct default Content-Type of "application/xml;charset=UTF-8" +FAIL XML Document request keeps setRequestHeader() Content-Type, with charset adjusted to UTF-8 assert_equals: expected "Content-Type: application/xhtml+xml;charset=UTF-8\n" but got "Content-Type: application/xhtml+xml;charset=ASCII\n" +PASS HTML Document request respects setRequestHeader("") +FAIL HTML Document request has correct default Content-Type of "text/html;charset=UTF-8" assert_equals: expected "Content-Type: text/html;charset=UTF-8\n" but got "Content-Type: application/xml;charset=UTF-8\n" +FAIL HTML Document request keeps setRequestHeader() Content-Type, with charset adjusted to UTF-8 assert_equals: expected "Content-Type: text/html+junk;charset=UTF-8\n" but got "Content-Type: text/html+junk;charset=ASCII\n" +PASS Blob request respects setRequestHeader("") to be specified +PASS Blob request with unset type sends no Content-Type without setRequestHeader() call +PASS Blob request with unset type keeps setRequestHeader() Content-Type and charset +PASS Blob request with set type respects setRequestHeader("") to be specified +PASS Blob request with set type uses that it for Content-Type unless setRequestHeader() +PASS Blob request with set type keeps setRequestHeader() Content-Type and charset +PASS ArrayBuffer request respects setRequestHeader("") +PASS ArrayBuffer request sends no Content-Type without setRequestHeader() call +PASS ArrayBuffer request keeps setRequestHeader() Content-Type and charset +PASS ArrayBufferView request respects setRequestHeader("") +PASS ArrayBufferView request sends no Content-Type without setRequestHeader() call +PASS ArrayBufferView request keeps setRequestHeader() Content-Type and charset +PASS FormData request respects setRequestHeader("") +PASS FormData request has correct default Content-Type of "multipart/form-data; boundary=_" +PASS FormData request keeps setRequestHeader() Content-Type and charset +FAIL URLSearchParams respects setRequestHeader("") assert_equals: expected "Content-Type: \n" but got "Content-Type: , application/x-www-form-urlencoded;charset=UTF-8\n" +PASS URLSearchParams request has correct default Content-Type of "application/x-www-form-urlencoded;charset=UTF-8" +PASS URLSearchParams request keeps setRequestHeader() Content-Type, with charset adjusted to UTF-8 +FAIL ReadableStream request respects setRequestHeader("") assert_equals: expected "Content-Type: \n" but got "Content-Type: , text/plain;charset=UTF-8\n" +FAIL ReadableStream request with under type sends no Content-Type without setRequestHeader() call assert_equals: expected "" but got "Content-Type: text/plain;charset=UTF-8\n" +FAIL ReadableStream request keeps setRequestHeader() Content-Type and charset assert_equals: expected "Content-Type: application/xml;charset=ASCII\n" but got "Content-Type: application/xml;charset=UTF-8\n" +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/setrequestheader-content-type.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/setrequestheader-content-type.htm index 0d3ebc4e..55196d83 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/setrequestheader-content-type.htm +++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/setrequestheader-content-type.htm
@@ -21,13 +21,13 @@ } client.send(toSend) - const responseType = client.responseText + const actual = client.responseText if (expectedType === undefined || expectedType === null) { - assert_equals(responseType, ""); + assert_equals(actual, ""); } else if (expectedType instanceof RegExp) { - assert_regexp_match(responseType, expectedType); + assert_regexp_match(actual, expectedType); } else { - assert_equals(responseType, "Content-Type: " + expectedType + "\n"); + assert_equals(actual, "Content-Type: " + expectedType + "\n"); } }, title) } @@ -123,6 +123,12 @@ ) request( function _Blob() { return new Blob(["<xml/>"], {type : "application/xml;charset=ASCII"}); }, + {"Content-Type": ""}, + "", + 'Blob request with set type respects setRequestHeader("") to be specified' + ) + request( + function _Blob() { return new Blob(["<xml/>"], {type : "application/xml;charset=ASCII"}); }, {}, "application/xml;charset=ascii", // new Blob lowercases the type argument "Blob request with set type uses that it for Content-Type unless setRequestHeader()"
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/command-line-api.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/command-line-api.js index 6c42016..2993b98 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/command-line-api.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/command-line-api.js
@@ -41,13 +41,15 @@ ConsoleTestRunner.evaluateInConsole(expression, step1); } - function step2() { - function assertNoBoundCommandLineAPI() { - ['__commandLineAPI', '__scopeChainForEval'].forEach(function(name) { - console.assert(!(name in window), 'FAIL: Should be no ' + name); - }); - } - TestRunner.evaluateInPage(assertNoBoundCommandLineAPI, step3); + async function step2() { + await TestRunner.evaluateInPagePromise(` + (function assertNoBoundCommandLineAPI() { + ['__commandLineAPI', '__scopeChainForEval'].forEach(function(name) { + console.assert(!(name in window), 'FAIL: Should be no ' + name); + }); + })(); + `); + step3(); } function step3() {
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-assert-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-assert-expected.txt index 23872df6..8184931 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-assert-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-assert-expected.txt
@@ -1,15 +1,13 @@ -CONSOLE ERROR: line 9: 1 -CONSOLE ERROR: line 10: a Tests that console.assert() will dump a message and stack trace with source URLs and line numbers. -console-assert.html:4 Assertion failed: 1 -b @ console-assert.html:4 -a @ console-assert.html:10 +console-assert.js:14 Assertion failed: 1 +b @ console-assert.js:14 +a @ console-assert.js:20 setTimeout (async) -(anonymous) @ VM:1 -console-assert.html:5 Assertion failed: a b -b @ console-assert.html:5 -a @ console-assert.html:10 +(anonymous) @ console-assert.js:37 +console-assert.js:15 Assertion failed: a b +b @ console-assert.js:15 +a @ console-assert.js:20 setTimeout (async) -(anonymous) @ VM:1 +(anonymous) @ console-assert.js:37
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-assert.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-assert.js index 5f7dcc0..17bfc6da 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-assert.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-assert.js
@@ -1,49 +1,39 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> +// 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. -<script> -function b() -{ - console.assert(false, 1); - console.assert(false, "a", "b"); -} +(async function() { + TestRunner.addResult('Tests that console.assert() will dump a message and stack trace with source URLs and line numbers.\n'); -function a() -{ - b(); -} -//# sourceURL=console-assert.html -</script> + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); -<script> -function test() -{ - var callCount = 0; - function callback() + await TestRunner.evaluateInPagePromise(` + function b() { - if (++callCount === 2) - InspectorTest.expandConsoleMessages(onExpandedMessages); + console.assert(false, 1); + console.assert(false, "a", "b"); } - function onExpandedMessages() + function a() { - InspectorTest.dumpConsoleMessages(); - InspectorTest.completeTest(); + b(); } + //# sourceURL=console-assert.js + `); - InspectorTest.evaluateInPage("setTimeout(a, 0)"); - InspectorTest.addConsoleSniffer(callback, true); -} + var callCount = 0; -</script> -</head> + function callback() { + if (++callCount === 2) + ConsoleTestRunner.expandConsoleMessages(onExpandedMessages); + } -<body onload="runTest()"> -<p> -Tests that console.assert() will dump a message and stack trace with source URLs and line numbers. -</p> + function onExpandedMessages() { + ConsoleTestRunner.dumpConsoleMessages(); + TestRunner.completeTest(); + } -</body> -</html> + TestRunner.evaluateInPage('setTimeout(a, 0)'); + ConsoleTestRunner.addConsoleSniffer(callback, true); +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-big-array-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-big-array-expected.txt index 72600e68..5aebdf40 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-big-array-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-big-array-expected.txt
@@ -1,13 +1,6 @@ -CONSOLE MESSAGE: line 13: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100 -CONSOLE MESSAGE: line 18: ,,,,,,,,, -CONSOLE MESSAGE: line 24: 0,1,2,3,4,5,6,7,8,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100 -CONSOLE MESSAGE: line 29: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404 -CONSOLE MESSAGE: line 42: %O -CONSOLE MESSAGE: line 52: %O -CONSOLE MESSAGE: line 55: [object Uint8Array] Tests that console logging dumps large arrays properly. -console-big-array.html:13 Array(101) +console-big-array.js:18 Array(101) [0 … 19] 0: 0 1: 1 @@ -56,7 +49,7 @@ 100: 100 length: 101 __proto__: Array(0) -console-big-array.html:18 Array(10) +console-big-array.js:23 Array(10) 0: undefined 1: undefined 2: undefined @@ -69,7 +62,7 @@ 9: undefined length: 10 __proto__: Array(0) -console-big-array.html:24 Array(101) +console-big-array.js:29 Array(101) 0: 0 1: 1 2: 2 @@ -83,7 +76,7 @@ 100: 100 length: 101 __proto__: Array(0) -console-big-array.html:29 Array(405) +console-big-array.js:34 Array(405) [0 … 399] [0 … 19] [20 … 39] @@ -113,7 +106,7 @@ 404: 404 length: 405 __proto__: Array(0) -console-big-array.html:42 Array(124) +console-big-array.js:47 Array(124) 0: 0 1: 1 2: 2 @@ -134,7 +127,7 @@ NaN: NaN length: 124 __proto__: Array(0) -console-big-array.html:52 Array(4294967295) +console-big-array.js:57 Array(4294967295) [0 … 19] 0: 0 1: 1 @@ -191,7 +184,7 @@ 8589934592: 8589934592 length: 4294967295 __proto__: Array(0) -console-big-array.html:55 Uint8Array(64160003) +console-big-array.js:60 Uint8Array(64160003) [0 … 63999999] [0 … 3199999] [3200000 … 6399999]
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-big-array.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-big-array.js index 27c6510..a3404de 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-big-array.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-big-array.js
@@ -1,121 +1,115 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> +// 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. -function onload() -{ - var a = []; - for (var i = 0; i < 42; ++i) - a[i] = i; - a[100] = 100; - console.dir(a); +(async function() { + TestRunner.addResult('Tests that console logging dumps large arrays properly.\n'); - var b = []; - for (var i = 0; i < 10; ++i) - b[i] = undefined; - console.dir(b); + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); - var c = []; - for (var i = 0; i < 10; ++i) - c[i] = i; - c[100] = 100; - console.dir(c); + await TestRunner.evaluateInPagePromise(` + (function onload() + { + var a = []; + for (var i = 0; i < 42; ++i) + a[i] = i; + a[100] = 100; + console.dir(a); - var d = []; - for (var i = 0; i < 405; ++i) - d[i] = i; - console.dir(d); + var b = []; + for (var i = 0; i < 10; ++i) + b[i] = undefined; + console.dir(b); - var e = []; - for (var i = 0; i < 10; ++i) - e[i] = i; - e[123] = 123; - e[-123] = -123; - e[3.14] = 3.14; - e[4294967295] = 4294967295; - e[4294967296] = 4294967296; - e[Infinity] = Infinity; - e[-Infinity] = -Infinity; - e[NaN] = NaN; - console.log("%O", e); + var c = []; + for (var i = 0; i < 10; ++i) + c[i] = i; + c[100] = 100; + console.dir(c); - var f = []; - f[4294967294] = 4294967294; - for (var i = 20; i >= 0; i -= 2) - f[i] = i; - for (var i = 2, n = 33; n--; i *= 2) - f[i] = i; - for (var i = 1; i < 20; i += 2) - f[i] = i; - console.log("%O", f) + var d = []; + for (var i = 0; i < 405; ++i) + d[i] = i; + console.dir(d); - var g = new Uint8Array(new ArrayBuffer(Math.pow(20, 6) + Math.pow(20, 4) + 3)); - console.dir(g); + var e = []; + for (var i = 0; i < 10; ++i) + e[i] = i; + e[123] = 123; + e[-123] = -123; + e[3.14] = 3.14; + e[4294967295] = 4294967295; + e[4294967296] = 4294967296; + e[Infinity] = Infinity; + e[-Infinity] = -Infinity; + e[NaN] = NaN; + console.log("%O", e); - runTest(); -} + var f = []; + f[4294967294] = 4294967294; + for (var i = 20; i >= 0; i -= 2) + f[i] = i; + for (var i = 2, n = 33; n--; i *= 2) + f[i] = i; + for (var i = 1; i < 20; i += 2) + f[i] = i; + console.log("%O", f) -function test() -{ - ObjectUI.ArrayGroupingTreeElement._bucketThreshold = 20; + var g = new Uint8Array(new ArrayBuffer(Math.pow(20, 6) + Math.pow(20, 4) + 3)); + console.dir(g); - var messages = Console.ConsoleView.instance()._visibleViewMessages; - var sections = []; - for (var i = 0; i < messages.length; ++i) { - var consoleMessage = messages[i].consoleMessage(); - var element = messages[i].toMessageElement(); - var node = element.traverseNextNode(element); - while (node) { - if (node._section) { - sections.push(node._section); - node._section.expand(); - } - node = node.traverseNextNode(element); + })(); + `); + + ObjectUI.ArrayGroupingTreeElement._bucketThreshold = 20; + var messages = Console.ConsoleView.instance()._visibleViewMessages; + var sections = []; + + for (var i = 0; i < messages.length; ++i) { + var consoleMessage = messages[i].consoleMessage(); + var element = messages[i].toMessageElement(); + var node = element.traverseNextNode(element); + + while (node) { + if (node._section) { + sections.push(node._section); + node._section.expand(); + } + + node = node.traverseNextNode(element); + } + } + + TestRunner.addSniffer(ObjectUI.ArrayGroupingTreeElement.prototype, 'onpopulate', populateCalled, true); + var populated = false; + + function populateCalled() { + populated = true; + } + + TestRunner.deprecatedRunAfterPendingDispatches(expandRecursively); + + function expandRecursively() { + for (var i = 0; i < sections.length; ++i) { + var children = sections[i].rootElement().children(); + + for (var j = 0; j < children.length; ++j) { + for (var treeElement = children[j]; treeElement; treeElement = treeElement.traverseNextTreeElement(true, null, true)) { + if (treeElement.listItemElement.textContent.indexOf('__proto__') === -1) + treeElement.expand(); } + } } - InspectorTest.addSniffer(ObjectUI.ArrayGroupingTreeElement.prototype, "onpopulate", populateCalled, true); - var populated = false; - function populateCalled() - { - populated = true; - } + if (populated) + TestRunner.deprecatedRunAfterPendingDispatches(completeTest); + else + TestRunner.deprecatedRunAfterPendingDispatches(expandRecursively); + } - InspectorTest.deprecatedRunAfterPendingDispatches(expandRecursively); - - function expandRecursively() - { - for (var i = 0; i < sections.length; ++i) { - var children = sections[i].rootElement().children(); - for (var j = 0; j < children.length; ++j) { - for (var treeElement = children[j]; treeElement; treeElement = treeElement.traverseNextTreeElement(true, null, true)) { - if (treeElement.listItemElement.textContent.indexOf("__proto__") === -1) - treeElement.expand(); - } - } - } - if (populated) - InspectorTest.deprecatedRunAfterPendingDispatches(completeTest); - else - InspectorTest.deprecatedRunAfterPendingDispatches(expandRecursively); - } - - function completeTest() - { - InspectorTest.dumpConsoleMessages(false, false, InspectorTest.textContentWithLineBreaks); - InspectorTest.completeTest(); - } -} - -</script> -</head> - -<body onload="onload()"> -<p> -Tests that console logging dumps large arrays properly. -</p> - -</body> -</html> + function completeTest() { + ConsoleTestRunner.dumpConsoleMessages(false, false, TestRunner.textContentWithLineBreaks); + TestRunner.completeTest(); + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-clear-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-clear-expected.txt index 6431775..6aff65e 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-clear-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-clear-expected.txt
@@ -1,8 +1,8 @@ Tests that console is cleared upon requestClearMessages call. === Before clear === -VM:3 one -VM:4 two -VM:5 three +console-clear.js:12 one +console-clear.js:13 two +console-clear.js:14 three === After clear ===
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-clear.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-clear.js index d132176..7d0c5a8 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-clear.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-clear.js
@@ -8,14 +8,11 @@ await TestRunner.loadPanel("console"); await TestRunner.loadModule("console_test_runner"); - function log() { - // Fill console. + await TestRunner.evaluateInPagePromise(` console.log("one"); console.log("two"); console.log("three"); - } - - await TestRunner.evaluateInPagePromise(`(${log.toString()})()`); + `); TestRunner.addResult("=== Before clear ==="); ConsoleTestRunner.dumpConsoleMessages();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-custom-formatters-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-custom-formatters-expected.txt index 2e9e974..6523bf5 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-custom-formatters-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-custom-formatters-expected.txt
@@ -1,18 +1,12 @@ -CONSOLE MESSAGE: line 123: [object Object] -CONSOLE MESSAGE: line 124: [object Object] -CONSOLE MESSAGE: line 125: [object Object] -CONSOLE MESSAGE: line 126: [object Object] -CONSOLE MESSAGE: line 127: [object Object] -CONSOLE ERROR: Custom Formatter Failed: Too deep hierarchy of inlined custom previews Tests that console logging dumps properly when there are multiple custom formatters on the page -console-custom-formatters.html:123 Header formatted by 1 aBody formatted by 1 a -console-custom-formatters.html:124 Header formatted by 2 bBody formatted by 2 b -console-custom-formatters.html:125 Header formatted by 1 cBody formatted by 1 c -console-custom-formatters.html:126 Formatter with config Header info: additional infobodyinfo: additional info -console-custom-formatters.html:127 Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Object +console-custom-formatters.js:120 Header formatted by 1 aBody formatted by 1 a +console-custom-formatters.js:121 Header formatted by 2 bBody formatted by 2 b +console-custom-formatters.js:122 Header formatted by 1 cBody formatted by 1 c +console-custom-formatters.js:123 Formatter with config Header info: additional infobodyinfo: additional info +console-custom-formatters.js:124 Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Formatter with config Object Custom Formatter Failed: Too deep hierarchy of inlined custom previews undefined Promise resolved (async) -logVars @ console-custom-formatters.html:127 -(anonymous) @ VM:1 +logVars @ console-custom-formatters.js:124 +(anonymous) @ console-custom-formatters.js:131
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-custom-formatters.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-custom-formatters.js index 5dbce49..feeae3f 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-custom-formatters.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-custom-formatters.js
@@ -1,166 +1,157 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> +// 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. -var a = {name: "a"}; -var b = {name: "b"}; -var c = {name: "c"}; +(async function() { + TestRunner.addResult('Tests that console logging dumps properly when there are multiple custom formatters on the page\n'); -a.formattableBy1 = true; -b.formattableBy2 = true; -c.formattableBy1 = true; -c.formattableBy2 = true; + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); -var formatter1 = { - header: function(x) - { - if (!x.formattableBy1) - return null; + await TestRunner.evaluateInPagePromise(` + var a = {name: "a"}; + var b = {name: "b"}; + var c = {name: "c"}; + a.formattableBy1 = true; + b.formattableBy2 = true; + c.formattableBy1 = true; + c.formattableBy2 = true; + var formatter1 = { + header: function(x) + { + if (!x.formattableBy1) + return null; - return ["span", {}, "Header formatted by 1 ", x.name]; - }, + return ["span", {}, "Header formatted by 1 ", x.name]; + }, - hasBody: function(x) - { - return true; - }, + hasBody: function(x) + { + return true; + }, - body: function(x) - { - return ["span", {}, "Body formatted by 1 ", x.name] + body: function(x) + { + return ["span", {}, "Body formatted by 1 ", x.name] + } + }; + var formatter2 = { + header: function(x) + { + if (!x.formattableBy2) + return null; + + return ["span", {}, "Header formatted by 2 ", x.name]; + }, + + hasBody: function(x) + { + return true; + }, + + body: function(x) + { + return ["span", {}, "Body formatted by 2 ", x.name] + } + }; + var configTest = {}; + var formatterWithConfig1 = { + header: function(x, config) + { + if (x !== configTest || config) + return null; + + return ["span", {}, "Formatter with config ", ["object", {"object": x, "config": {"info": "additional info"}}]]; + }, + + hasBody: function(x) + { + return false; + }, + + body: function(x) + { + throw "Unreachable" + } } -}; + var formatterWithConfig2 = { + header: function(x, config) + { + if (x !== configTest || !config) + return null; -var formatter2 = { - header: function(x) - { - if (!x.formattableBy2) - return null; + return ["span", {}, "Header ", "info: ", config.info]; + }, - return ["span", {}, "Header formatted by 2 ", x.name]; - }, + hasBody: function(x, config) + { + return config && config.info; + }, - hasBody: function(x) - { - return true; - }, - - body: function(x) - { - return ["span", {}, "Body formatted by 2 ", x.name] + body: function(x, config) + { + return ["span", {}, "body", "info: ", config.info] + } } -}; + var selfReferenceTest = {}; + var selfReferencingFormatter = { + header: function(x) + { + if (x !== selfReferenceTest) + return null; -var configTest = {}; -var formatterWithConfig1 = { - header: function(x, config) - { - if (x !== configTest || config) - return null; + return ["span", {}, "Formatter with config ", ["object", {"object": x}]]; + }, - return ["span", {}, "Formatter with config ", ["object", {"object": x, "config": {"info": "additional info"}}]]; - }, + hasBody: function(x) + { + return false; + }, - hasBody: function(x) - { - return false; - }, - - body: function(x) - { - throw "Unreachable" - } -} - -var formatterWithConfig2 = { - header: function(x, config) - { - if (x !== configTest || !config) - return null; - - return ["span", {}, "Header ", "info: ", config.info]; - }, - - hasBody: function(x, config) - { - return config && config.info; - }, - - body: function(x, config) - { - return ["span", {}, "body", "info: ", config.info] - } -} - -var selfReferenceTest = {}; -var selfReferencingFormatter = { - header: function(x) - { - if (x !== selfReferenceTest) - return null; - - return ["span", {}, "Formatter with config ", ["object", {"object": x}]]; - }, - - hasBody: function(x) - { - return false; - }, - - body: function(x) - { - throw "Unreachable" - } - -} - -window.devtoolsFormatters = [formatter1, formatter2, formatterWithConfig1, formatterWithConfig2, selfReferencingFormatter]; - -function logVars() -{ - console.log(a); - console.log(b); - console.log(c); - console.log(configTest); - console.log(selfReferenceTest); - //swap first formatters: test that header+body should be generated by the same formatter - window.devtoolsFormatters = [formatter2, formatter1, formatterWithConfig1, formatterWithConfig2, selfReferencingFormatter]; -} - -function test() -{ - InspectorTest.mainTarget.runtimeAgent().setCustomObjectFormatterEnabled(true); - InspectorTest.evaluateInPage("logVars()", expandVariablesInConsole); - - function expandVariablesInConsole() - { - var consoleView = Console.ConsoleView.instance(); - if (consoleView._needsFullUpdate) - consoleView._updateMessageList(); - var viewMessages = consoleView._visibleViewMessages; - for (var i = 0; i < viewMessages.length; ++i) { - var uiMessage = viewMessages[i]; - var shadowRoot = uiMessage.contentElement().querySelector(".console-message-text *").shadowRoot; - var customElement = shadowRoot ? shadowRoot.querySelector(".custom-expandable-section-header") : null; - if (customElement) - customElement.click(); + body: function(x) + { + throw "Unreachable" } - InspectorTest.deprecatedRunAfterPendingDispatches(dumpExpanded); } - - function dumpExpanded() + window.devtoolsFormatters = [formatter1, formatter2, formatterWithConfig1, formatterWithConfig2, selfReferencingFormatter]; + function logVars() { - InspectorTest.dumpConsoleMessages(); - InspectorTest.completeTest(); + console.log(a); + console.log(b); + console.log(c); + console.log(configTest); + console.log(selfReferenceTest); + //swap first formatters: test that header+body should be generated by the same formatter + window.devtoolsFormatters = [formatter2, formatter1, formatterWithConfig1, formatterWithConfig2, selfReferencingFormatter]; } -} -</script> -</head> + `); -<body onload="runTest()"> -<p>Tests that console logging dumps properly when there are multiple custom formatters on the page</p> -</body> -</html> + TestRunner.mainTarget.runtimeAgent().setCustomObjectFormatterEnabled(true); + TestRunner.evaluateInPage('logVars()', expandVariablesInConsole); + + function expandVariablesInConsole() { + var consoleView = Console.ConsoleView.instance(); + + if (consoleView._needsFullUpdate) + consoleView._updateMessageList(); + + var viewMessages = consoleView._visibleViewMessages; + + for (var i = 0; i < viewMessages.length; ++i) { + var uiMessage = viewMessages[i]; + var shadowRoot = uiMessage.contentElement().querySelector('.console-message-text *').shadowRoot; + var customElement = (shadowRoot ? shadowRoot.querySelector('.custom-expandable-section-header') : null); + + if (customElement) + customElement.click(); + } + + TestRunner.deprecatedRunAfterPendingDispatches(dumpExpanded); + } + + function dumpExpanded() { + ConsoleTestRunner.dumpConsoleMessages(); + TestRunner.completeTest(); + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dir-es6-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dir-es6-expected.txt index db462126..3a2e3bf 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dir-es6-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dir-es6-expected.txt
@@ -1,65 +1,46 @@ -CONSOLE MESSAGE: line 15: [object Object] -CONSOLE MESSAGE: line 18: Symbol() -CONSOLE MESSAGE: line 22: [object Map] -CONSOLE MESSAGE: line 22: [object WeakMap] -CONSOLE MESSAGE: line 26: [object Set] -CONSOLE MESSAGE: line 26: [object WeakSet] -CONSOLE MESSAGE: line 34: [object Set] -CONSOLE MESSAGE: line 37: [object WeakMap] -CONSOLE MESSAGE: line 45: [object Map Iterator] -CONSOLE MESSAGE: line 46: [object Map Iterator] -CONSOLE MESSAGE: line 47: [object Map Iterator] -CONSOLE MESSAGE: line 45: [object Set Iterator] -CONSOLE MESSAGE: line 46: [object Set Iterator] -CONSOLE MESSAGE: line 47: [object Set Iterator] -CONSOLE MESSAGE: line 85: class{method(){ return 1 }},class classWithWhitespace { method(){ return 1 } },class FooClass { - jump(x) { return 1 } - badArrow(x = a => 2) { return "looooooooooooooooooooooooooooooooooooooooooooooooooooong" } - },jump(x) { return 1 },class BarClass extends FooClass{},class BarClass2 extends class base{} {},class BarClass3 extends function base2(a, b) {} {},_ => { return 1 },(x) => { return 1 },(x, y, z) => { return 1 },({}) => { return 1 },([]) => { return 1 },() => { return "short" },() => { return "looooooooooooooooooooooooooooooooooooooooooooooooooooong" },(...x) => { return 1 },(x, y, ...z) => { return 1 },function (...x) { return 1 },function (x, y, ...z) { return 1 },function ({a}){ return 1 },function ([a]){ return 1 },function ({a, b}){ return 1 },function (...{a}){ return 1 },function (a = (1), b){ return 1 },function (a = {x: (1)}, b){ return 1 },function (a = (x) => { return 1 }, b){ return 2 },function ({a: b}){ return 1 },function (c = ")", {a: b}){ return 1 } -CONSOLE MESSAGE: line 93: badArrow(x = a => 2) { return "looooooooooooooooooooooooooooooooooooooooooooooooooooong" },function (a = ") {", b){ return 1 },function (a = function(){ return 1 }, b){ return 2 },function (a = class{ constructor(){} }){ return 2 } Tests that console logging dumps proper messages. -console-dir-es6.html:15 Object +console-dir-es6.js:20 Object a: 1 Symbol(): 2 Symbol(Symbol.iterator): Symbol(foo) Symbol(a): 3 Symbol(a): Symbol(Symbol.iterator) __proto__: Object -console-dir-es6.html:18 Symbol() -console-dir-es6.html:22 Map(1) +console-dir-es6.js:23 Symbol() +console-dir-es6.js:27 Map(1) size: (...) __proto__: Map [[Entries]]: Array(1) 0: {Object => Object} length: 1 -console-dir-es6.html:22 WeakMap +console-dir-es6.js:27 WeakMap __proto__: WeakMap [[Entries]]: Array(1) 0: {Object => Object} length: 1 -console-dir-es6.html:26 Set(1) +console-dir-es6.js:31 Set(1) size: (...) __proto__: Set [[Entries]]: Array(1) 0: Object length: 1 -console-dir-es6.html:26 WeakSet +console-dir-es6.js:31 WeakSet __proto__: WeakSet [[Entries]]: Array(1) 0: Object length: 1 -console-dir-es6.html:34 Set(1) +console-dir-es6.js:39 Set(1) size: (...) __proto__: Set [[Entries]]: Array(1) 0: Set(1) length: 1 -console-dir-es6.html:37 WeakMap +console-dir-es6.js:42 WeakMap __proto__: WeakMap [[Entries]]: Array(0) length: 0 -console-dir-es6.html:45 MapIterator +console-dir-es6.js:50 MapIterator __proto__: Map Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -67,7 +48,7 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-dir-es6.html:46 MapIterator +console-dir-es6.js:51 MapIterator __proto__: Map Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -75,7 +56,7 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-dir-es6.html:47 MapIterator +console-dir-es6.js:52 MapIterator __proto__: Map Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -83,7 +64,7 @@ [[Entries]]: Array(1) 0: {Object => Object} length: 1 -console-dir-es6.html:45 SetIterator +console-dir-es6.js:50 SetIterator __proto__: Set Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -91,7 +72,7 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-dir-es6.html:46 SetIterator +console-dir-es6.js:51 SetIterator __proto__: Set Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -99,7 +80,7 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-dir-es6.html:47 SetIterator +console-dir-es6.js:52 SetIterator __proto__: Set Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -107,7 +88,7 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-dir-es6.html:85 Array(27) +console-dir-es6.js:90 Array(27) 0: class 1: class classWithWhitespace 2: class FooClass @@ -137,7 +118,7 @@ 26: ƒ (c = ")", {a: b}) length: 27 __proto__: Array(0) -console-dir-es6.html:93 Array(4) +console-dir-es6.js:98 Array(4) 0: badArrow(x = a => {…} 1: ƒ (a = ") 2: ƒ (a = function()
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dir-es6.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dir-es6.js index aeda7f4..8112e2f 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dir-es6.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dir-es6.js
@@ -1,118 +1,109 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> +// 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. -function onload() -{ - var obj = new Object(); - obj["a"] = 1; - obj[Symbol()] = 2; - obj[Symbol("a")] = 3; - obj[Symbol("a")] = Symbol.iterator; - obj[Symbol.iterator] = Symbol("foo"); - console.dir(obj); +(async function() { + TestRunner.addResult('Tests that console logging dumps proper messages.\n'); - // This used to crash in debug build. - console.dir(Symbol()); + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); - [new Map(), new WeakMap()].forEach(function(m) { - m.set(obj, {foo: 1}); - console.dir(m); - }); - [new Set(), new WeakSet()].forEach(function(s) { - s.add(obj); - console.dir(s); - }); - - // Test circular dependency by entries. - var s1 = new Set(); - var s2 = new Set(); - s1.add(s2); - s2.add(s1); - console.dir(s1); - - // Test "No Entries" placeholder. - console.dir(new WeakMap()); - - // Test Map/Set iterators. - var m = new Map(); - m.set(obj, {foo: 1}); - var s = new Set(); - s.add(obj); - [m, s].forEach(function(c) { - console.dir(c.keys()); - console.dir(c.values()); - console.dir(c.entries()); - }); - - class FooClass { - jump(x) { return 1 } - badArrow(x = a => 2) { return "looooooooooooooooooooooooooooooooooooooooooooooooooooong" } - } - var fooInstance = new FooClass(); - - var fns = [ - class{method(){ return 1 }}, - class classWithWhitespace { method(){ return 1 } }, - FooClass, - fooInstance.jump, - class BarClass extends FooClass{}, - class BarClass2 extends class base{} {}, - class BarClass3 extends function base2(a, b) {} {}, - _ => { return 1 }, - (x) => { return 1 }, - (x, y, z) => { return 1 }, - ({}) => { return 1 }, - ([]) => { return 1 }, - () => { return "short" }, - () => { return "looooooooooooooooooooooooooooooooooooooooooooooooooooong" }, - (...x) => { return 1 }, - (x, y, ...z) => { return 1 }, - function (...x) { return 1 }, - function (x, y, ...z) { return 1 }, - function({a}){ return 1 }, - function([a]){ return 1 }, - function({a, b}){ return 1 }, - function(...{a}){ return 1 }, - function(a = (1), b){ return 1 }, - function(a = {x: (1)}, b){ return 1 }, - function(a = (x) => { return 1 }, b){ return 2 }, - function({a: b}){ return 1 }, - function(c = ")", {a: b}){ return 1 } - ]; - console.dir(fns); - - var badFns = [ - fooInstance.badArrow, - function(a = ") {", b){ return 1 }, - function(a = function(){ return 1 }, b){ return 2 }, - function(a = class{ constructor(){} }){ return 2 } - ]; - console.dir(badFns); - - runTest(); -} - -function test() -{ - InspectorTest.expandConsoleMessages(dumpConsoleMessages); - - function dumpConsoleMessages() + await TestRunner.evaluateInPagePromise(` + (function onload() { - InspectorTest.dumpConsoleMessages(false, false, InspectorTest.textContentWithLineBreaks); - InspectorTest.completeTest(); - } -} + var obj = new Object(); + obj["a"] = 1; + obj[Symbol()] = 2; + obj[Symbol("a")] = 3; + obj[Symbol("a")] = Symbol.iterator; + obj[Symbol.iterator] = Symbol("foo"); + console.dir(obj); -</script> -</head> + // This used to crash in debug build. + console.dir(Symbol()); -<body onload="onload()"> -<p> -Tests that console logging dumps proper messages. -</p> + [new Map(), new WeakMap()].forEach(function(m) { + m.set(obj, {foo: 1}); + console.dir(m); + }); + [new Set(), new WeakSet()].forEach(function(s) { + s.add(obj); + console.dir(s); + }); -</body> -</html> + // Test circular dependency by entries. + var s1 = new Set(); + var s2 = new Set(); + s1.add(s2); + s2.add(s1); + console.dir(s1); + + // Test "No Entries" placeholder. + console.dir(new WeakMap()); + + // Test Map/Set iterators. + var m = new Map(); + m.set(obj, {foo: 1}); + var s = new Set(); + s.add(obj); + [m, s].forEach(function(c) { + console.dir(c.keys()); + console.dir(c.values()); + console.dir(c.entries()); + }); + + class FooClass { + jump(x) { return 1 } + badArrow(x = a => 2) { return "looooooooooooooooooooooooooooooooooooooooooooooooooooong" } + } + var fooInstance = new FooClass(); + + var fns = [ + class{method(){ return 1 }}, + class classWithWhitespace { method(){ return 1 } }, + FooClass, + fooInstance.jump, + class BarClass extends FooClass{}, + class BarClass2 extends class base{} {}, + class BarClass3 extends function base2(a, b) {} {}, + _ => { return 1 }, + (x) => { return 1 }, + (x, y, z) => { return 1 }, + ({}) => { return 1 }, + ([]) => { return 1 }, + () => { return "short" }, + () => { return "looooooooooooooooooooooooooooooooooooooooooooooooooooong" }, + (...x) => { return 1 }, + (x, y, ...z) => { return 1 }, + function (...x) { return 1 }, + function (x, y, ...z) { return 1 }, + function({a}){ return 1 }, + function([a]){ return 1 }, + function({a, b}){ return 1 }, + function(...{a}){ return 1 }, + function(a = (1), b){ return 1 }, + function(a = {x: (1)}, b){ return 1 }, + function(a = (x) => { return 1 }, b){ return 2 }, + function({a: b}){ return 1 }, + function(c = ")", {a: b}){ return 1 } + ]; + console.dir(fns); + + var badFns = [ + fooInstance.badArrow, + function(a = ") {", b){ return 1 }, + function(a = function(){ return 1 }, b){ return 2 }, + function(a = class{ constructor(){} }){ return 2 } + ]; + console.dir(badFns); + + })(); + `); + + ConsoleTestRunner.expandConsoleMessages(dumpConsoleMessages); + + function dumpConsoleMessages() { + ConsoleTestRunner.dumpConsoleMessages(false, false, TestRunner.textContentWithLineBreaks); + TestRunner.completeTest(); + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dirxml-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dirxml-expected.txt index e8304b3..c0b6d0a8 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dirxml-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dirxml-expected.txt
@@ -1,13 +1,8 @@ -CONSOLE MESSAGE: line 12: [object HTMLDocument] -CONSOLE MESSAGE: line 13: [object DocumentFragment] -CONSOLE MESSAGE: line 14: [object HTMLParagraphElement] -CONSOLE MESSAGE: line 15: [object HTMLParagraphElement] -CONSOLE MESSAGE: line 16: [object HTMLDocument],[object DocumentFragment],[object HTMLSpanElement] Tests that console logging dumps proper messages. -console-dirxml.html:12 #document -console-dirxml.html:13 #document-fragment -console-dirxml.html:14 <p></p> -console-dirxml.html:15 [p] -console-dirxml.html:16 (3) [document, document-fragment, span] +console-dirxml.js:17 #document +console-dirxml.js:18 #document-fragment +console-dirxml.js:19 <p></p> +console-dirxml.js:20 [p] +console-dirxml.js:21 (3) [document, document-fragment, span]
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dirxml.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dirxml.js index d1baeb5..11c4030 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dirxml.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-dirxml.js
@@ -1,45 +1,37 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> +// 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. -function logToConsole() -{ - var fragment = document.createDocumentFragment(); - fragment.appendChild(document.createElement("p")); +(async function() { + TestRunner.addResult('Tests that console logging dumps proper messages.\n'); - console.dirxml(document); - console.dirxml(fragment); - console.dirxml(fragment.firstChild); - console.log([fragment.firstChild]); - console.dirxml([document, fragment, document.createElement("span")]); -} + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); -function test() -{ - runtime.loadModulePromise("elements").then(function() { - InspectorTest.evaluateInPage("logToConsole()", onLoggedToConsole); - }); - - function onLoggedToConsole() + await TestRunner.evaluateInPagePromise(` + function logToConsole() { - InspectorTest.waitForRemoteObjectsConsoleMessages(onRemoteObjectsLoaded) + var fragment = document.createDocumentFragment(); + fragment.appendChild(document.createElement("p")); + + console.dirxml(document); + console.dirxml(fragment); + console.dirxml(fragment.firstChild); + console.log([fragment.firstChild]); + console.dirxml([document, fragment, document.createElement("span")]); } + `); - function onRemoteObjectsLoaded() - { - InspectorTest.dumpConsoleMessages(); - InspectorTest.completeTest(); - } -} -</script> -</head> + runtime.loadModulePromise('elements').then(function() { + TestRunner.evaluateInPage('logToConsole()', onLoggedToConsole); + }); -<body onload="runTest()"> -<p> -Tests that console logging dumps proper messages. -</p> + function onLoggedToConsole() { + ConsoleTestRunner.waitForRemoteObjectsConsoleMessages(onRemoteObjectsLoaded); + } -</body> -</html> + function onRemoteObjectsLoaded() { + ConsoleTestRunner.dumpConsoleMessages(); + TestRunner.completeTest(); + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-edit-expanded-tree-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-edit-expanded-tree-expected.txt index 1d72fe0..3b2e8d6 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-edit-expanded-tree-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-edit-expanded-tree-expected.txt
@@ -1,4 +1,3 @@ -CONSOLE MESSAGE: line 12: [object Object] Tests that expanded tree element is editable in console. After viewport refresh tree element remains in editing mode: true
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-edit-expanded-tree.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-edit-expanded-tree.js index 4e85c61..2a546f9 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-edit-expanded-tree.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-edit-expanded-tree.js
@@ -1,54 +1,46 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> +// 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. -function onload() -{ - var a = {}; - for (var i = 0; i < 100; ++i) - a[i] = i; - console.dir(a); +(async function() { + TestRunner.addResult('Tests that expanded tree element is editable in console.\n'); - runTest(); -} + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); -function test() -{ - InspectorTest.expandConsoleMessages(onConsoleMessageExpanded); - - function onConsoleMessageExpanded() + await TestRunner.evaluateInPagePromise(` + (function onload() { - var messages = Console.ConsoleView.instance()._visibleViewMessages; - for (var i = 0; i < messages.length; ++i) { - var message = messages[i]; - var node = message.contentElement(); - for (var node = message.contentElement(); node; node = node.traverseNextNode(message.contentElement())) { - if (node.treeElement) { - onTreeElement(node.treeElement.firstChild()); - return; - } - } + var a = {}; + for (var i = 0; i < 100; ++i) + a[i] = i; + console.dir(a); + + })(); + `); + + ConsoleTestRunner.expandConsoleMessages(onConsoleMessageExpanded); + + function onConsoleMessageExpanded() { + var messages = Console.ConsoleView.instance()._visibleViewMessages; + + for (var i = 0; i < messages.length; ++i) { + var message = messages[i]; + var node = message.contentElement(); + + for (var node = message.contentElement(); node; node = node.traverseNextNode(message.contentElement())) { + if (node.treeElement) { + onTreeElement(node.treeElement.firstChild()); + return; } + } } + } - function onTreeElement(treeElement) - { - treeElement._startEditing(); - Console.ConsoleView.instance()._viewport.refresh(); - InspectorTest.addResult("After viewport refresh tree element remains in editing mode: " + !!treeElement._prompt); - InspectorTest.completeTest(); - } -} - -</script> -</head> - -<body onload="onload()"> -<p> -Tests that expanded tree element is editable in console. -</p> - -</body> -</html> + function onTreeElement(treeElement) { + treeElement._startEditing(); + Console.ConsoleView.instance()._viewport.refresh(); + TestRunner.addResult('After viewport refresh tree element remains in editing mode: ' + !!treeElement._prompt); + TestRunner.completeTest(); + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-external-array-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-external-array-expected.txt index c02ce3d..d00c238 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-external-array-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-external-array-expected.txt
@@ -1,35 +1,19 @@ -CONSOLE MESSAGE: line 9: [object Int8Array] -CONSOLE MESSAGE: line 10: [object Int16Array] -CONSOLE MESSAGE: line 11: [object Int32Array] -CONSOLE MESSAGE: line 12: [object Uint8Array] -CONSOLE MESSAGE: line 13: [object Uint16Array] -CONSOLE MESSAGE: line 14: [object Uint32Array] -CONSOLE MESSAGE: line 15: [object Float32Array] -CONSOLE MESSAGE: line 16: [object Float64Array] -CONSOLE MESSAGE: line 18: [object Int8Array] -CONSOLE MESSAGE: line 19: [object Int16Array] -CONSOLE MESSAGE: line 20: [object Int32Array] -CONSOLE MESSAGE: line 21: [object Uint8Array] -CONSOLE MESSAGE: line 22: [object Uint16Array] -CONSOLE MESSAGE: line 23: [object Uint32Array] -CONSOLE MESSAGE: line 24: [object Float32Array] -CONSOLE MESSAGE: line 25: [object Float64Array] Tests that console logging detects external arrays as arrays. -console-external-array.html:9 Int8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] -console-external-array.html:10 Int16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] -console-external-array.html:11 Int32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] -console-external-array.html:12 Uint8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] -console-external-array.html:13 Uint16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] -console-external-array.html:14 Uint32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] -console-external-array.html:15 Float32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] -console-external-array.html:16 Float64Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] -console-external-array.html:18 Int8Array(10) -console-external-array.html:19 Int16Array(10) -console-external-array.html:20 Int32Array(10) -console-external-array.html:21 Uint8Array(10) -console-external-array.html:22 Uint16Array(10) -console-external-array.html:23 Uint32Array(10) -console-external-array.html:24 Float32Array(10) -console-external-array.html:25 Float64Array(10) +console-external-array.js:14 Int8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +console-external-array.js:15 Int16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +console-external-array.js:16 Int32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +console-external-array.js:17 Uint8Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +console-external-array.js:18 Uint16Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +console-external-array.js:19 Uint32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +console-external-array.js:20 Float32Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +console-external-array.js:21 Float64Array(10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +console-external-array.js:23 Int8Array(10) +console-external-array.js:24 Int16Array(10) +console-external-array.js:25 Int32Array(10) +console-external-array.js:26 Uint8Array(10) +console-external-array.js:27 Uint16Array(10) +console-external-array.js:28 Uint32Array(10) +console-external-array.js:29 Float32Array(10) +console-external-array.js:30 Float64Array(10)
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-external-array.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-external-array.js index 4c995173..44355e0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-external-array.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-external-array.js
@@ -1,54 +1,44 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> +// 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. -function logToConsole() -{ - console.log(new Int8Array(10)); - console.log(new Int16Array(10)); - console.log(new Int32Array(10)); - console.log(new Uint8Array(10)); - console.log(new Uint16Array(10)); - console.log(new Uint32Array(10)); - console.log(new Float32Array(10)); - console.log(new Float64Array(10)); +(async function() { + TestRunner.addResult('Tests that console logging detects external arrays as arrays.\n'); - console.dir(new Int8Array(10)); - console.dir(new Int16Array(10)); - console.dir(new Int32Array(10)); - console.dir(new Uint8Array(10)); - console.dir(new Uint16Array(10)); - console.dir(new Uint32Array(10)); - console.dir(new Float32Array(10)); - console.dir(new Float64Array(10)); -} + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); -function test() -{ - InspectorTest.evaluateInPage("logToConsole()", onLoggedToConsole); - - - function onLoggedToConsole() + await TestRunner.evaluateInPagePromise(` + function logToConsole() { - InspectorTest.waitForRemoteObjectsConsoleMessages(onRemoteObjectsLoaded) + console.log(new Int8Array(10)); + console.log(new Int16Array(10)); + console.log(new Int32Array(10)); + console.log(new Uint8Array(10)); + console.log(new Uint16Array(10)); + console.log(new Uint32Array(10)); + console.log(new Float32Array(10)); + console.log(new Float64Array(10)); + + console.dir(new Int8Array(10)); + console.dir(new Int16Array(10)); + console.dir(new Int32Array(10)); + console.dir(new Uint8Array(10)); + console.dir(new Uint16Array(10)); + console.dir(new Uint32Array(10)); + console.dir(new Float32Array(10)); + console.dir(new Float64Array(10)); } + `); - function onRemoteObjectsLoaded() - { - InspectorTest.dumpConsoleMessages(); - InspectorTest.completeTest(); - } -} + TestRunner.evaluateInPage('logToConsole()', onLoggedToConsole); -</script> -</head> + function onLoggedToConsole() { + ConsoleTestRunner.waitForRemoteObjectsConsoleMessages(onRemoteObjectsLoaded); + } -<body onload="runTest()"> -<p> -Tests that console logging detects external arrays as arrays. -</p> - -</body> -</html> + function onRemoteObjectsLoaded() { + ConsoleTestRunner.dumpConsoleMessages(); + TestRunner.completeTest(); + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-array-prototype-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-array-prototype-expected.txt index ba59c88..9d731a9 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-array-prototype-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-array-prototype-expected.txt
@@ -1,47 +1,36 @@ -CONSOLE MESSAGE: line 9: -CONSOLE MESSAGE: line 9: -CONSOLE MESSAGE: line 9: ,,,, -CONSOLE MESSAGE: line 9: ,2,3 -CONSOLE MESSAGE: line 9: ,,,,,,,,,,,,,, -CONSOLE MESSAGE: line 9: ,,,,,,,,8,,,,,, -CONSOLE MESSAGE: line 9: 0,,,,,,,,,,10,,,, -CONSOLE MESSAGE: line 9: ,,,4,,,,,,,,,,, -CONSOLE MESSAGE: line 9: 0,1,2,3,4,5,6,7,8,9 -CONSOLE MESSAGE: line 9: ,1,2,3,4,,6,7,8,9, -CONSOLE MESSAGE: line 9: [object Object] Tests that console logging dumps array values defined on Array.prototype[]. a0 [] -console-format-array-prototype.html:4 [] +console-format-array-prototype.js:14 [] a1 [empty × 1] -console-format-array-prototype.html:4 [empty × 1] +console-format-array-prototype.js:14 [empty × 1] a2 (5) [empty × 5] -console-format-array-prototype.html:4 (5) [empty × 5] +console-format-array-prototype.js:14 (5) [empty × 5] a3 (3) [empty × 1, 2, 3] -console-format-array-prototype.html:4 (3) [empty × 1, 2, 3] +console-format-array-prototype.js:14 (3) [empty × 1, 2, 3] a4 (15) [empty × 15] -console-format-array-prototype.html:4 (15) [empty × 15] +console-format-array-prototype.js:14 (15) [empty × 15] a5 (15) [empty × 8, 8, empty × 6] -console-format-array-prototype.html:4 (15) [empty × 8, 8, empty × 6] +console-format-array-prototype.js:14 (15) [empty × 8, 8, empty × 6] a6 (15) [0, empty × 9, 10, empty × 4] -console-format-array-prototype.html:4 (15) [0, empty × 9, 10, empty × 4] +console-format-array-prototype.js:14 (15) [0, empty × 9, 10, empty × 4] a7 (15) [3: 4, index0: 0, index1: 1, index2: 2, index3: 3, index4: 4, …] -console-format-array-prototype.html:4 (15) [3: 4, index0: 0, index1: 1, index2: 2, index3: 3, index4: 4, …] +console-format-array-prototype.js:14 (15) [3: 4, index0: 0, index1: 1, index2: 2, index3: 3, index4: 4, …] a8 (10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] -console-format-array-prototype.html:4 (10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +console-format-array-prototype.js:14 (10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a9 (11) [empty × 1, 1, 2, 3, 4, empty × 1, 6, 7, 8, 9, empty × 1, foo: "bar"] -console-format-array-prototype.html:4 (11) [empty × 1, 1, 2, 3, 4, empty × 1, 6, 7, 8, 9, empty × 1, foo: "bar"] +console-format-array-prototype.js:14 (11) [empty × 1, 1, 2, 3, 4, empty × 1, 6, 7, 8, 9, empty × 1, foo: "bar"] a10 Array {} -console-format-array-prototype.html:4 Array {} +console-format-array-prototype.js:14 Array {}
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-array-prototype.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-array-prototype.js index a04eee7ef..d4736f8 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-array-prototype.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-array-prototype.js
@@ -1,77 +1,68 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> +// 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. -<script> -function log(data) -{ - console.log(data); -} +(async function() { + TestRunner.addResult('Tests that console logging dumps array values defined on Array.prototype[].\n'); -var a0 = []; -var a1 = []; a1.length = 1; -var a2 = []; a2.length = 5; -var a3 = [,2,3]; -var a4 = []; a4.length = 15; -var a5 = []; a5.length = 15; a5[8] = 8; -var a6 = []; a6.length = 15; a6[0] = 0; a6[10] = 10; -var a7 = [,,,4]; a7.length = 15; -for (var i = 0; i < 6; ++i) - a7["index" + i] = i; -var a8 = []; -for (var i = 0; i < 10; ++i) - a8[i] = i; -var a9 = []; -for (var i = 1; i < 5; ++i) { - a9[i] = i; - a9[i + 5] = i + 5; -} -a9.length = 11; -a9.foo = "bar"; -a10 = Object.create([1,2]); -//# sourceURL=console-format-array-prototype.html -</script> + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); -<script> -function test() -{ - loopOverGlobals(0, 11); - - function loopOverGlobals(current, total) + await TestRunner.evaluateInPagePromise(` + function log(data) { - function advance() - { - var next = current + 1; - if (next === total) { - InspectorTest.evaluateInPage("tearDown()"); - InspectorTest.deprecatedRunAfterPendingDispatches(finish); - } else { - loopOverGlobals(next, total); - } - } - - function finish() - { - InspectorTest.dumpConsoleMessages(false, false, InspectorTest.textContentWithLineBreaks); - InspectorTest.completeTest(); - } - - InspectorTest.evaluateInConsole("a" + current); - InspectorTest.deprecatedRunAfterPendingDispatches(invokeConsoleLog); - function invokeConsoleLog() - { - InspectorTest.evaluateInPage("log(a" + current + ")"); - InspectorTest.deprecatedRunAfterPendingDispatches(advance); - } + console.log(data); } -} -</script> -</head> -<body onload="runTest()"> -<p> -Tests that console logging dumps array values defined on Array.prototype[]. -</p> -</body> -</html> + var a0 = []; + var a1 = []; a1.length = 1; + var a2 = []; a2.length = 5; + var a3 = [,2,3]; + var a4 = []; a4.length = 15; + var a5 = []; a5.length = 15; a5[8] = 8; + var a6 = []; a6.length = 15; a6[0] = 0; a6[10] = 10; + var a7 = [,,,4]; a7.length = 15; + for (var i = 0; i < 6; ++i) + a7["index" + i] = i; + var a8 = []; + for (var i = 0; i < 10; ++i) + a8[i] = i; + var a9 = []; + for (var i = 1; i < 5; ++i) { + a9[i] = i; + a9[i + 5] = i + 5; + } + a9.length = 11; + a9.foo = "bar"; + a10 = Object.create([1,2]); + //# sourceURL=console-format-array-prototype.js + `); + + loopOverGlobals(0, 11); + + function loopOverGlobals(current, total) { + function advance() { + var next = current + 1; + + if (next === total) { + TestRunner.evaluateInPage('tearDown()'); + TestRunner.deprecatedRunAfterPendingDispatches(finish); + } else { + loopOverGlobals(next, total); + } + } + + function finish() { + ConsoleTestRunner.dumpConsoleMessages(false, false, TestRunner.textContentWithLineBreaks); + TestRunner.completeTest(); + } + + ConsoleTestRunner.evaluateInConsole('a' + current); + TestRunner.deprecatedRunAfterPendingDispatches(invokeConsoleLog); + + function invokeConsoleLog() { + TestRunner.evaluateInPage('log(a' + current + ')'); + TestRunner.deprecatedRunAfterPendingDispatches(advance); + } + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-2-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-2-expected.txt index f1d7c89..d7b5c02 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-2-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-2-expected.txt
@@ -1,55 +1,39 @@ -CONSOLE MESSAGE: line 11: [object Map Iterator] -CONSOLE MESSAGE: line 12: [object Map Iterator] -CONSOLE MESSAGE: line 11: [object Map Iterator] -CONSOLE MESSAGE: line 12: [object Map Iterator] -CONSOLE MESSAGE: line 11: [object Map Iterator] -CONSOLE MESSAGE: line 12: [object Map Iterator] -CONSOLE MESSAGE: line 11: [object Set Iterator] -CONSOLE MESSAGE: line 12: [object Set Iterator] -CONSOLE MESSAGE: line 11: [object Set Iterator] -CONSOLE MESSAGE: line 12: [object Set Iterator] -CONSOLE MESSAGE: line 11: [object Set Iterator] -CONSOLE MESSAGE: line 12: [object Set Iterator] -CONSOLE MESSAGE: line 11: [object Map Iterator] -CONSOLE MESSAGE: line 12: [object Map Iterator] -CONSOLE MESSAGE: line 11: [object Set Iterator] -CONSOLE MESSAGE: line 12: [object Set Iterator] Tests that console properly displays information about ES6 features. -console-format-es6-2.html:11 MapIterator {41, {…}} -console-format-es6-2.html:12 [MapIterator] +console-format-es6-2.js:15 MapIterator {41, {…}} +console-format-es6-2.js:16 [MapIterator] globals[0] MapIterator {41, {…}} -console-format-es6-2.html:11 MapIterator {42, {…}} -console-format-es6-2.html:12 [MapIterator] +console-format-es6-2.js:15 MapIterator {42, {…}} +console-format-es6-2.js:16 [MapIterator] globals[1] MapIterator {42, {…}} -console-format-es6-2.html:11 MapIterator {41 => 42, {…} => {…}} -console-format-es6-2.html:12 [MapIterator] +console-format-es6-2.js:15 MapIterator {41 => 42, {…} => {…}} +console-format-es6-2.js:16 [MapIterator] globals[2] MapIterator {41 => 42, {…} => {…}} -console-format-es6-2.html:11 SetIterator {41, {…}} -console-format-es6-2.html:12 [SetIterator] +console-format-es6-2.js:15 SetIterator {41, {…}} +console-format-es6-2.js:16 [SetIterator] globals[3] SetIterator {41, {…}} -console-format-es6-2.html:11 SetIterator {41, {…}} -console-format-es6-2.html:12 [SetIterator] +console-format-es6-2.js:15 SetIterator {41, {…}} +console-format-es6-2.js:16 [SetIterator] globals[4] SetIterator {41, {…}} -console-format-es6-2.html:11 SetIterator {41, {…}} -console-format-es6-2.html:12 [SetIterator] +console-format-es6-2.js:15 SetIterator {41, {…}} +console-format-es6-2.js:16 [SetIterator] globals[5] SetIterator {41, {…}} -console-format-es6-2.html:11 MapIterator {{…}} -console-format-es6-2.html:12 [MapIterator] +console-format-es6-2.js:15 MapIterator {{…}} +console-format-es6-2.js:16 [MapIterator] globals[6] MapIterator {{…}} -console-format-es6-2.html:11 SetIterator {{…}} -console-format-es6-2.html:12 [SetIterator] +console-format-es6-2.js:15 SetIterator {{…}} +console-format-es6-2.js:16 [SetIterator] globals[7] SetIterator {{…}} Expanded all messages -console-format-es6-2.html:11 MapIterator {41, {…}} +console-format-es6-2.js:15 MapIterator {41, {…}} __proto__: Map Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -58,7 +42,7 @@ 0: 41 1: Object length: 2 -console-format-es6-2.html:12 [MapIterator] +console-format-es6-2.js:16 [MapIterator] 0: MapIterator {41, {…}} length: 1 __proto__: Array(0) @@ -72,7 +56,7 @@ 0: 41 1: Object length: 2 -console-format-es6-2.html:11 MapIterator {42, {…}} +console-format-es6-2.js:15 MapIterator {42, {…}} __proto__: Map Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -81,7 +65,7 @@ 0: 42 1: Object length: 2 -console-format-es6-2.html:12 [MapIterator] +console-format-es6-2.js:16 [MapIterator] 0: MapIterator {42, {…}} length: 1 __proto__: Array(0) @@ -95,7 +79,7 @@ 0: 42 1: Object length: 2 -console-format-es6-2.html:11 MapIterator {41 => 42, {…} => {…}} +console-format-es6-2.js:15 MapIterator {41 => 42, {…} => {…}} __proto__: Map Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -104,7 +88,7 @@ 0: {41 => 42} 1: {Object => Object} length: 2 -console-format-es6-2.html:12 [MapIterator] +console-format-es6-2.js:16 [MapIterator] 0: MapIterator {41 => 42, {…} => {…}} length: 1 __proto__: Array(0) @@ -118,7 +102,7 @@ 0: {41 => 42} 1: {Object => Object} length: 2 -console-format-es6-2.html:11 SetIterator {41, {…}} +console-format-es6-2.js:15 SetIterator {41, {…}} __proto__: Set Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -127,7 +111,7 @@ 0: 41 1: Object length: 2 -console-format-es6-2.html:12 [SetIterator] +console-format-es6-2.js:16 [SetIterator] 0: SetIterator {41, {…}} length: 1 __proto__: Array(0) @@ -141,7 +125,7 @@ 0: 41 1: Object length: 2 -console-format-es6-2.html:11 SetIterator {41, {…}} +console-format-es6-2.js:15 SetIterator {41, {…}} __proto__: Set Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -150,7 +134,7 @@ 0: 41 1: Object length: 2 -console-format-es6-2.html:12 [SetIterator] +console-format-es6-2.js:16 [SetIterator] 0: SetIterator {41, {…}} length: 1 __proto__: Array(0) @@ -164,7 +148,7 @@ 0: 41 1: Object length: 2 -console-format-es6-2.html:11 SetIterator {41, {…}} +console-format-es6-2.js:15 SetIterator {41, {…}} __proto__: Set Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 0 @@ -173,7 +157,7 @@ 0: 41 1: Object length: 2 -console-format-es6-2.html:12 [SetIterator] +console-format-es6-2.js:16 [SetIterator] 0: SetIterator {41, {…}} length: 1 __proto__: Array(0) @@ -187,7 +171,7 @@ 0: 41 1: Object length: 2 -console-format-es6-2.html:11 MapIterator {{…}} +console-format-es6-2.js:15 MapIterator {{…}} __proto__: Map Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 1 @@ -195,7 +179,7 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-format-es6-2.html:12 [MapIterator] +console-format-es6-2.js:16 [MapIterator] 0: MapIterator {{…}} length: 1 __proto__: Array(0) @@ -208,7 +192,7 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-format-es6-2.html:11 SetIterator {{…}} +console-format-es6-2.js:15 SetIterator {{…}} __proto__: Set Iterator [[IteratorHasMore]]: true [[IteratorIndex]]: 1 @@ -216,7 +200,7 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-format-es6-2.html:12 [SetIterator] +console-format-es6-2.js:16 [SetIterator] 0: SetIterator {{…}} length: 1 __proto__: Array(0)
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-2.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-2.js index 46809892..7659aded 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-2.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-2.js
@@ -1,85 +1,74 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> +// 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. -var globals = []; +(async function() { + TestRunner.addResult('Tests that console properly displays information about ES6 features.\n'); -function log(current) -{ - console.log(globals[current]); - console.log([globals[current]]); -} + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); -function onload() -{ - var map2 = new Map(); - map2.set(41, 42); - map2.set({foo: 1}, {foo: 2}); - - var iter1 = map2.values(); - iter1.next(); - - var set2 = new Set(); - set2.add(41); - set2.add({foo: 1}); - - var iter2 = set2.keys(); - iter2.next(); - - globals = [ - map2.keys(), map2.values(), map2.entries(), - set2.keys(), set2.values(), set2.entries(), - iter1, iter2, - ]; - - runTest(); -} - -function test() -{ - InspectorTest.evaluateInPage("globals.length", loopOverGlobals.bind(this, 0)); - - function loopOverGlobals(current, total) + await TestRunner.evaluateInPagePromise(` + var globals = []; + function log(current) { - function advance() - { - var next = current + 1; - if (next == total.description) - finish(); - else - loopOverGlobals(next, total); - } - - function finish() - { - InspectorTest.dumpConsoleMessages(false, false, InspectorTest.textContentWithLineBreaks); - InspectorTest.addResult("Expanded all messages"); - InspectorTest.expandConsoleMessages(dumpConsoleMessages); - } - - function dumpConsoleMessages() - { - InspectorTest.dumpConsoleMessages(false, false, InspectorTest.textContentWithLineBreaks); - InspectorTest.completeTest(); - } - - InspectorTest.evaluateInPage("log(" + current + ")"); - InspectorTest.deprecatedRunAfterPendingDispatches(evalInConsole); - function evalInConsole() - { - InspectorTest.evaluateInConsole("globals[" + current + "]"); - InspectorTest.deprecatedRunAfterPendingDispatches(advance); - } + console.log(globals[current]); + console.log([globals[current]]); } -} -</script> -</head> + (function onload() + { + var map2 = new Map(); + map2.set(41, 42); + map2.set({foo: 1}, {foo: 2}); -<body onload="onload()"> -<p> -Tests that console properly displays information about ES6 features. -</p> -</body> -</html> + var iter1 = map2.values(); + iter1.next(); + + var set2 = new Set(); + set2.add(41); + set2.add({foo: 1}); + + var iter2 = set2.keys(); + iter2.next(); + + globals = [ + map2.keys(), map2.values(), map2.entries(), + set2.keys(), set2.values(), set2.entries(), + iter1, iter2, + ]; + + })(); + `); + + TestRunner.evaluateInPage('globals.length', loopOverGlobals.bind(this, 0)); + + function loopOverGlobals(current, total) { + function advance() { + var next = current + 1; + + if (next == total.description) + finish(); + else + loopOverGlobals(next, total); + } + + function finish() { + ConsoleTestRunner.dumpConsoleMessages(false, false, TestRunner.textContentWithLineBreaks); + TestRunner.addResult('Expanded all messages'); + ConsoleTestRunner.expandConsoleMessages(dumpConsoleMessages); + } + + function dumpConsoleMessages() { + ConsoleTestRunner.dumpConsoleMessages(false, false, TestRunner.textContentWithLineBreaks); + TestRunner.completeTest(); + } + + TestRunner.evaluateInPage('log(' + current + ')'); + TestRunner.deprecatedRunAfterPendingDispatches(evalInConsole); + + function evalInConsole() { + ConsoleTestRunner.evaluateInConsole('globals[' + current + ']'); + TestRunner.deprecatedRunAfterPendingDispatches(advance); + } + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-expected.txt index 15d5a0c..a0ad82a7 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-expected.txt
@@ -1,95 +1,67 @@ -CONSOLE MESSAGE: line 11: [object Promise] -CONSOLE MESSAGE: line 12: [object Promise] -CONSOLE MESSAGE: line 11: Symbol() -CONSOLE MESSAGE: line 12: Symbol() -CONSOLE MESSAGE: line 11: Symbol(a) -CONSOLE MESSAGE: line 12: Symbol(a) -CONSOLE MESSAGE: line 11: [object Object] -CONSOLE MESSAGE: line 12: [object Object] -CONSOLE MESSAGE: line 11: [object Map] -CONSOLE MESSAGE: line 12: [object Map] -CONSOLE MESSAGE: line 11: [object WeakMap] -CONSOLE MESSAGE: line 12: [object WeakMap] -CONSOLE MESSAGE: line 11: [object Set] -CONSOLE MESSAGE: line 12: [object Set] -CONSOLE MESSAGE: line 11: [object WeakSet] -CONSOLE MESSAGE: line 12: [object WeakSet] -CONSOLE MESSAGE: line 11: [object Map] -CONSOLE MESSAGE: line 12: [object Map] -CONSOLE MESSAGE: line 11: [object Map] -CONSOLE MESSAGE: line 12: [object Map] -CONSOLE MESSAGE: line 11: [object Set] -CONSOLE MESSAGE: line 12: [object Set] -CONSOLE MESSAGE: line 11: [object Set] -CONSOLE MESSAGE: line 12: [object Set] -CONSOLE MESSAGE: line 11: [object Map] -CONSOLE MESSAGE: line 12: [object Map] -CONSOLE MESSAGE: line 11: [object Generator] -CONSOLE MESSAGE: line 12: [object Generator] Tests that console properly displays information about ES6 features. -console-format-es6.html:11 Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: -0} -console-format-es6.html:12 [Promise] +console-format-es6.js:15 Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: -0} +console-format-es6.js:16 [Promise] globals[0] Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: -0} -console-format-es6.html:11 Symbol() -console-format-es6.html:12 [Symbol()] +console-format-es6.js:15 Symbol() +console-format-es6.js:16 [Symbol()] globals[1] Symbol() -console-format-es6.html:11 Symbol(a) -console-format-es6.html:12 [Symbol(a)] +console-format-es6.js:15 Symbol(a) +console-format-es6.js:16 [Symbol(a)] globals[2] Symbol(a) -console-format-es6.html:11 {a: Symbol(), Symbol(a): 2} -console-format-es6.html:12 [{…}] +console-format-es6.js:15 {a: Symbol(), Symbol(a): 2} +console-format-es6.js:16 [{…}] globals[3] {a: Symbol(), Symbol(a): 2} -console-format-es6.html:11 Map(1) {{…} => {…}} -console-format-es6.html:12 [Map(1)] +console-format-es6.js:15 Map(1) {{…} => {…}} +console-format-es6.js:16 [Map(1)] globals[4] Map(1) {{…} => {…}} -console-format-es6.html:11 WeakMap {{…} => {…}} -console-format-es6.html:12 [WeakMap] +console-format-es6.js:15 WeakMap {{…} => {…}} +console-format-es6.js:16 [WeakMap] globals[5] WeakMap {{…} => {…}} -console-format-es6.html:11 Set(1) {{…}} -console-format-es6.html:12 [Set(1)] +console-format-es6.js:15 Set(1) {{…}} +console-format-es6.js:16 [Set(1)] globals[6] Set(1) {{…}} -console-format-es6.html:11 WeakSet {{…}} -console-format-es6.html:12 [WeakSet] +console-format-es6.js:15 WeakSet {{…}} +console-format-es6.js:16 [WeakSet] globals[7] WeakSet {{…}} -console-format-es6.html:11 Map(1) {Map(0) => WeakMap} -console-format-es6.html:12 [Map(1)] +console-format-es6.js:15 Map(1) {Map(0) => WeakMap} +console-format-es6.js:16 [Map(1)] globals[8] Map(1) {Map(0) => WeakMap} -console-format-es6.html:11 Map(1) {Map(1) => WeakMap} -console-format-es6.html:12 [Map(1)] +console-format-es6.js:15 Map(1) {Map(1) => WeakMap} +console-format-es6.js:16 [Map(1)] globals[9] Map(1) {Map(1) => WeakMap} -console-format-es6.html:11 Set(1) {WeakSet} -console-format-es6.html:12 [Set(1)] +console-format-es6.js:15 Set(1) {WeakSet} +console-format-es6.js:16 [Set(1)] globals[10] Set(1) {WeakSet} -console-format-es6.html:11 Set(1) {WeakSet} -console-format-es6.html:12 [Set(1)] +console-format-es6.js:15 Set(1) {WeakSet} +console-format-es6.js:16 [Set(1)] globals[11] Set(1) {WeakSet} -console-format-es6.html:11 Map(6) {" from str " => " to str ", undefined => undefined, null => null, 42 => 42, {…} => {…}, …} -console-format-es6.html:12 [Map(6)] +console-format-es6.js:15 Map(6) {" from str " => " to str ", undefined => undefined, null => null, 42 => 42, {…} => {…}, …} +console-format-es6.js:16 [Map(6)] globals[12] Map(6) {" from str " => " to str ", undefined => undefined, null => null, 42 => 42, {…} => {…}, …} -console-format-es6.html:11 genFunction {[[GeneratorStatus]]: "suspended"} -console-format-es6.html:12 [genFunction] +console-format-es6.js:15 genFunction {[[GeneratorStatus]]: "suspended"} +console-format-es6.js:16 [genFunction] globals[13] genFunction {[[GeneratorStatus]]: "suspended"} Expanded all messages -console-format-es6.html:11 Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: -0} +console-format-es6.js:15 Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: -0} __proto__: Promise [[PromiseStatus]]: "rejected" [[PromiseValue]]: -0 -console-format-es6.html:12 [Promise] +console-format-es6.js:16 [Promise] 0: Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: -0} length: 1 __proto__: Array(0) @@ -98,27 +70,27 @@ __proto__: Promise [[PromiseStatus]]: "rejected" [[PromiseValue]]: -0 -console-format-es6.html:11 Symbol() -console-format-es6.html:12 [Symbol()] +console-format-es6.js:15 Symbol() +console-format-es6.js:16 [Symbol()] 0: Symbol() length: 1 __proto__: Array(0) globals[1] Symbol() -console-format-es6.html:11 Symbol(a) -console-format-es6.html:12 [Symbol(a)] +console-format-es6.js:15 Symbol(a) +console-format-es6.js:16 [Symbol(a)] 0: Symbol(a) length: 1 __proto__: Array(0) globals[2] Symbol(a) -console-format-es6.html:11 {a: Symbol(), Symbol(a): 2} +console-format-es6.js:15 {a: Symbol(), Symbol(a): 2} a: Symbol() getter: (...) Symbol(a): 2 get getter: ƒ getter() __proto__: Object -console-format-es6.html:12 [{…}] +console-format-es6.js:16 [{…}] 0: {a: Symbol(), Symbol(a): 2} length: 1 __proto__: Array(0) @@ -129,13 +101,13 @@ Symbol(a): 2 get getter: ƒ getter() __proto__: Object -console-format-es6.html:11 Map(1) {{…} => {…}} +console-format-es6.js:15 Map(1) {{…} => {…}} size: (...) __proto__: Map [[Entries]]: Array(1) 0: {Object => Object} length: 1 -console-format-es6.html:12 [Map(1)] +console-format-es6.js:16 [Map(1)] 0: Map(1) {{…} => {…}} length: 1 __proto__: Array(0) @@ -146,12 +118,12 @@ [[Entries]]: Array(1) 0: {Object => Object} length: 1 -console-format-es6.html:11 WeakMap {{…} => {…}} +console-format-es6.js:15 WeakMap {{…} => {…}} __proto__: WeakMap [[Entries]]: Array(1) 0: {Object => Object} length: 1 -console-format-es6.html:12 [WeakMap] +console-format-es6.js:16 [WeakMap] 0: WeakMap {{…} => {…}} length: 1 __proto__: Array(0) @@ -161,13 +133,13 @@ [[Entries]]: Array(1) 0: {Object => Object} length: 1 -console-format-es6.html:11 Set(1) {{…}} +console-format-es6.js:15 Set(1) {{…}} size: (...) __proto__: Set [[Entries]]: Array(1) 0: Object length: 1 -console-format-es6.html:12 [Set(1)] +console-format-es6.js:16 [Set(1)] 0: Set(1) {{…}} length: 1 __proto__: Array(0) @@ -178,12 +150,12 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-format-es6.html:11 WeakSet {{…}} +console-format-es6.js:15 WeakSet {{…}} __proto__: WeakSet [[Entries]]: Array(1) 0: Object length: 1 -console-format-es6.html:12 [WeakSet] +console-format-es6.js:16 [WeakSet] 0: WeakSet {{…}} length: 1 __proto__: Array(0) @@ -193,13 +165,13 @@ [[Entries]]: Array(1) 0: Object length: 1 -console-format-es6.html:11 Map(1) {Map(0) => WeakMap} +console-format-es6.js:15 Map(1) {Map(0) => WeakMap} size: (...) __proto__: Map [[Entries]]: Array(1) 0: {Map(0) => WeakMap} length: 1 -console-format-es6.html:12 [Map(1)] +console-format-es6.js:16 [Map(1)] 0: Map(1) {Map(0) => WeakMap} length: 1 __proto__: Array(0) @@ -210,13 +182,13 @@ [[Entries]]: Array(1) 0: {Map(0) => WeakMap} length: 1 -console-format-es6.html:11 Map(1) {Map(1) => WeakMap} +console-format-es6.js:15 Map(1) {Map(1) => WeakMap} size: (...) __proto__: Map [[Entries]]: Array(1) 0: {Map(1) => WeakMap} length: 1 -console-format-es6.html:12 [Map(1)] +console-format-es6.js:16 [Map(1)] 0: Map(1) {Map(1) => WeakMap} length: 1 __proto__: Array(0) @@ -227,13 +199,13 @@ [[Entries]]: Array(1) 0: {Map(1) => WeakMap} length: 1 -console-format-es6.html:11 Set(1) {WeakSet} +console-format-es6.js:15 Set(1) {WeakSet} size: (...) __proto__: Set [[Entries]]: Array(1) 0: WeakSet length: 1 -console-format-es6.html:12 [Set(1)] +console-format-es6.js:16 [Set(1)] 0: Set(1) {WeakSet} length: 1 __proto__: Array(0) @@ -244,13 +216,13 @@ [[Entries]]: Array(1) 0: WeakSet length: 1 -console-format-es6.html:11 Set(1) {WeakSet} +console-format-es6.js:15 Set(1) {WeakSet} size: (...) __proto__: Set [[Entries]]: Array(1) 0: WeakSet length: 1 -console-format-es6.html:12 [Set(1)] +console-format-es6.js:16 [Set(1)] 0: Set(1) {WeakSet} length: 1 __proto__: Array(0) @@ -261,7 +233,7 @@ [[Entries]]: Array(1) 0: WeakSet length: 1 -console-format-es6.html:11 Map(6) {" from str " => " to str ", undefined => undefined, null => null, 42 => 42, {…} => {…}, …} +console-format-es6.js:15 Map(6) {" from str " => " to str ", undefined => undefined, null => null, 42 => 42, {…} => {…}, …} size: (...) __proto__: Map [[Entries]]: Array(6) @@ -272,7 +244,7 @@ 4: {Object => Object} 5: {Array(1) => Array(1)} length: 6 -console-format-es6.html:12 [Map(6)] +console-format-es6.js:16 [Map(6)] 0: Map(6) {" from str " => " to str ", undefined => undefined, null => null, 42 => 42, {…} => {…}, …} length: 1 __proto__: Array(0) @@ -288,14 +260,14 @@ 4: {Object => Object} 5: {Array(1) => Array(1)} length: 6 -console-format-es6.html:11 genFunction {[[GeneratorStatus]]: "suspended"} +console-format-es6.js:15 genFunction {[[GeneratorStatus]]: "suspended"} __proto__: Generator [[GeneratorStatus]]: "suspended" [[GeneratorFunction]]: ƒ* () [[GeneratorReceiver]]: Window - [[GeneratorLocation]]: console-format-es6.html:56 + [[GeneratorLocation]]: console-format-es6.js:59 [[Scopes]]: Scopes[2] -console-format-es6.html:12 [genFunction] +console-format-es6.js:16 [genFunction] 0: genFunction {[[GeneratorStatus]]: "suspended"} length: 1 __proto__: Array(0) @@ -305,6 +277,6 @@ [[GeneratorStatus]]: "suspended" [[GeneratorFunction]]: ƒ* () [[GeneratorReceiver]]: Window - [[GeneratorLocation]]: console-format-es6.html:56 + [[GeneratorLocation]]: console-format-es6.js:59 [[Scopes]]: Scopes[2]
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-symbols-error-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-symbols-error-expected.txt index 2488623..a2d8d5f2 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-symbols-error-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-symbols-error-expected.txt
@@ -1,5 +1,4 @@ -CONSOLE MESSAGE: line 11: Symbol() Tests that console properly displays information about ES6 Symbols. -console-format-es6-symbols-error.html:11 Symbol +console-format-es6-symbols-error.js:16 Symbol
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-symbols-error.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-symbols-error.js index bc59d01..da7189b0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-symbols-error.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6-symbols-error.js
@@ -1,32 +1,26 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> +// 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. -function logSymbolToConsoleWithError() -{ - Symbol.prototype.toString = function (arg) { throw new Error(); }; - var smb = Symbol(); - console.log(smb); -} +(async function() { + TestRunner.addResult('Tests that console properly displays information about ES6 Symbols.\n'); -function test() -{ - InspectorTest.evaluateInPage("logSymbolToConsoleWithError()", complete); + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); - function complete() + await TestRunner.evaluateInPagePromise(` + function logSymbolToConsoleWithError() { - InspectorTest.dumpConsoleMessages(); - InspectorTest.completeTest(); + Symbol.prototype.toString = function (arg) { throw new Error(); }; + var smb = Symbol(); + console.log(smb); } -} -</script> -</head> + `); -<body onload="runTest()"> -<p> -Tests that console properly displays information about ES6 Symbols. -</p> -</body> -</html> + TestRunner.evaluateInPage('logSymbolToConsoleWithError()', complete); + + function complete() { + ConsoleTestRunner.dumpConsoleMessages(); + TestRunner.completeTest(); + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6.js index 1a3ea11..d9583be 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-es6.js
@@ -1,115 +1,104 @@ -<html> -<head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> +// 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. -var globals = []; +(async function() { + TestRunner.addResult('Tests that console properly displays information about ES6 features.\n'); -function log(current) -{ - console.log(globals[current]); - console.log([globals[current]]); -} + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); -function onload() -{ - var p = Promise.reject(-0); - p.catch(function() {}); - - var smb1 = Symbol(); - var smb2 = Symbol("a"); - var obj = { - get getter() {} - }; - obj["a"] = smb1; - obj[smb2] = 2; - - var map = new Map(); - var weakMap = new WeakMap(); - map.set(obj, {foo: 1}); - weakMap.set(obj, {foo: 1}); - - var set = new Set(); - var weakSet = new WeakSet(); - set.add(obj); - weakSet.add(obj); - - var mapMap0 = new Map(); - mapMap0.set(new Map(), new WeakMap()); - var mapMap = new Map(); - mapMap.set(map, weakMap); - - var setSet0 = new Set(); - setSet0.add(new WeakSet()); - var setSet = new Set(); - setSet.add(weakSet); - - var bigmap = new Map(); - bigmap.set(" from str ", " to str "); - bigmap.set(undefined, undefined); - bigmap.set(null, null); - bigmap.set(42, 42); - bigmap.set({foo:"from"}, {foo:"to"}); - bigmap.set(["from"], ["to"]); - - var genFunction = function *() { - yield 1; - yield 2; - } - var generator = genFunction(); - - globals = [ - p, smb1, smb2, obj, map, weakMap, set, weakSet, - mapMap0, mapMap, setSet0, setSet, bigmap, generator - ]; - - runTest(); -} - -function test() -{ - InspectorTest.evaluateInPage("globals.length", loopOverGlobals.bind(this, 0)); - - function loopOverGlobals(current, total) + await TestRunner.evaluateInPagePromise(` + var globals = []; + function log(current) { - function advance() - { - var next = current + 1; - if (next == total.description) - finish(); - else - loopOverGlobals(next, total); - } - - function finish() - { - InspectorTest.dumpConsoleMessages(false, false, InspectorTest.textContentWithLineBreaks); - InspectorTest.addResult("Expanded all messages"); - InspectorTest.expandConsoleMessages(dumpConsoleMessages); - } - - function dumpConsoleMessages() - { - InspectorTest.dumpConsoleMessages(false, false, InspectorTest.textContentWithLineBreaks); - InspectorTest.completeTest(); - } - - InspectorTest.evaluateInPage("log(" + current + ")"); - InspectorTest.deprecatedRunAfterPendingDispatches(evalInConsole); - function evalInConsole() - { - InspectorTest.evaluateInConsole("globals[" + current + "]"); - InspectorTest.deprecatedRunAfterPendingDispatches(advance); - } + console.log(globals[current]); + console.log([globals[current]]); } -} -</script> -</head> + (function onload() + { + var p = Promise.reject(-0); + p.catch(function() {}); -<body onload="onload()"> -<p> -Tests that console properly displays information about ES6 features. -</p> -</body> -</html> + var smb1 = Symbol(); + var smb2 = Symbol("a"); + var obj = { + get getter() {} + }; + obj["a"] = smb1; + obj[smb2] = 2; + + var map = new Map(); + var weakMap = new WeakMap(); + map.set(obj, {foo: 1}); + weakMap.set(obj, {foo: 1}); + + var set = new Set(); + var weakSet = new WeakSet(); + set.add(obj); + weakSet.add(obj); + + var mapMap0 = new Map(); + mapMap0.set(new Map(), new WeakMap()); + var mapMap = new Map(); + mapMap.set(map, weakMap); + + var setSet0 = new Set(); + setSet0.add(new WeakSet()); + var setSet = new Set(); + setSet.add(weakSet); + + var bigmap = new Map(); + bigmap.set(" from str ", " to str "); + bigmap.set(undefined, undefined); + bigmap.set(null, null); + bigmap.set(42, 42); + bigmap.set({foo:"from"}, {foo:"to"}); + bigmap.set(["from"], ["to"]); + + var genFunction = function *() { + yield 1; + yield 2; + } + var generator = genFunction(); + + globals = [ + p, smb1, smb2, obj, map, weakMap, set, weakSet, + mapMap0, mapMap, setSet0, setSet, bigmap, generator + ]; + + })(); + `); + + TestRunner.evaluateInPage('globals.length', loopOverGlobals.bind(this, 0)); + + function loopOverGlobals(current, total) { + function advance() { + var next = current + 1; + + if (next == total.description) + finish(); + else + loopOverGlobals(next, total); + } + + function finish() { + ConsoleTestRunner.dumpConsoleMessages(false, false, TestRunner.textContentWithLineBreaks); + TestRunner.addResult('Expanded all messages'); + ConsoleTestRunner.expandConsoleMessages(dumpConsoleMessages); + } + + function dumpConsoleMessages() { + ConsoleTestRunner.dumpConsoleMessages(false, false, TestRunner.textContentWithLineBreaks); + TestRunner.completeTest(); + } + + TestRunner.evaluateInPage('log(' + current + ')'); + TestRunner.deprecatedRunAfterPendingDispatches(evalInConsole); + + function evalInConsole() { + ConsoleTestRunner.evaluateInConsole('globals[' + current + ']'); + TestRunner.deprecatedRunAfterPendingDispatches(advance); + } + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-style-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-style-expected.txt index 2f9ff56..7a8ae5b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-style-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-style-expected.txt
@@ -1,14 +1,11 @@ -CONSOLE MESSAGE: line 8: %cBlue!. -CONSOLE MESSAGE: line 9: %cBlue! %cRed! -CONSOLE MESSAGE: line 10: %cwww.google.com Tests that console logging dumps properly styled messages. -console-format-style.html:8 Blue!. +console-format-style.js:14 Blue!. Styled text #0: color: blue; -console-format-style.html:9 Blue! Red! +console-format-style.js:15 Blue! Red! Styled text #0: color: blue; Styled text #1: color: red; -console-format-style.html:10 www.google.com +console-format-style.js:16 www.google.com Styled text #0: color: blue; Styled text #1: color: blue;
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-style.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-style.js index 6a8abb5..ace2917 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-style.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-style.js
@@ -1,30 +1,26 @@ -<html> - <head> -<script src="../../http/tests/inspector/inspector-test.js"></script> -<script src="../../http/tests/inspector/console-test.js"></script> -<script> -function onload() -{ - console.log("%cBlue!.", "color: blue;"); - console.log("%cBlue! %cRed!", "color: blue;", "color: red;"); - console.log("%cwww.google.com", "color: blue"); - runTest(); -} +// 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. -function test() -{ - InspectorTest.expandConsoleMessages(onExpanded); +(async function() { + TestRunner.addResult('Tests that console logging dumps properly styled messages.\n'); - function onExpanded() + await TestRunner.loadModule('console_test_runner'); + await TestRunner.loadPanel('console'); + + await TestRunner.evaluateInPagePromise(` + (function onload() { - InspectorTest.dumpConsoleMessagesWithStyles(); - InspectorTest.completeTest(); - } -} -</script> - </head> + console.log("%cBlue!.", "color: blue;"); + console.log("%cBlue! %cRed!", "color: blue;", "color: red;"); + console.log("%cwww.google.com", "color: blue"); + })(); + `); - <body onload="onload()"> - <p>Tests that console logging dumps properly styled messages.</p> - </body> -</html> + ConsoleTestRunner.expandConsoleMessages(onExpanded); + + function onExpanded() { + ConsoleTestRunner.dumpConsoleMessagesWithStyles(); + TestRunner.completeTest(); + } +})();
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp index 661876e..21cc0ca0 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -872,57 +872,30 @@ } std::pair<String, String> SpellChecker::SelectMisspellingAsync() { - VisibleSelection selection = - GetFrame().Selection().ComputeVisibleSelectionInDOMTree(); - if (selection.IsNone()) + const std::pair<Node*, SpellCheckMarker*>& node_and_marker = + GetSpellCheckMarkerUnderSelection(); + if (!node_and_marker.first) return {}; - // Caret and range selections always return valid normalized ranges. + Node* const marker_node = node_and_marker.first; + const SpellCheckMarker* const marker = node_and_marker.second; + + const VisibleSelection& selection = + GetFrame().Selection().ComputeVisibleSelectionInDOMTree(); + // Caret and range selections (one of which we must have since we found a + // marker) always return valid normalized ranges. const EphemeralRange& selection_range = selection.ToNormalizedEphemeralRange(); - Node* const selection_start_container = - selection_range.StartPosition().ComputeContainerNode(); - Node* const selection_end_container = - selection_range.EndPosition().ComputeContainerNode(); - - // We don't currently support the case where a misspelling spans multiple - // nodes. See crbug.com/720065 - if (selection_start_container != selection_end_container) + const EphemeralRange marker_range( + Position(marker_node, marker->StartOffset()), + Position(marker_node, marker->EndOffset())); + const String& marked_text = PlainText(marker_range); + if (marked_text.StripWhiteSpace(&IsWhiteSpaceOrPunctuation) != + PlainText(selection_range).StripWhiteSpace(&IsWhiteSpaceOrPunctuation)) return {}; - const unsigned selection_start_offset = - selection_range.StartPosition().ComputeOffsetInContainerNode(); - const unsigned selection_end_offset = - selection_range.EndPosition().ComputeOffsetInContainerNode(); - - const DocumentMarkerVector& markers_in_node = - GetFrame().GetDocument()->Markers().MarkersFor( - selection_start_container, DocumentMarker::MisspellingMarkers()); - - const auto marker_it = - std::find_if(markers_in_node.begin(), markers_in_node.end(), - [=](const DocumentMarker* marker) { - return marker->StartOffset() < selection_end_offset && - marker->EndOffset() > selection_start_offset; - }); - if (marker_it == markers_in_node.end()) - return {}; - - const SpellCheckMarker* const found_marker = ToSpellCheckMarker(*marker_it); - - Range* const marker_range = - Range::Create(*GetFrame().GetDocument(), selection_start_container, - found_marker->StartOffset(), selection_start_container, - found_marker->EndOffset()); - - if (marker_range->GetText().StripWhiteSpace(&IsWhiteSpaceOrPunctuation) != - CreateRange(selection_range) - ->GetText() - .StripWhiteSpace(&IsWhiteSpaceOrPunctuation)) - return {}; - - return std::make_pair(marker_range->GetText(), found_marker->Description()); + return std::make_pair(marked_text, marker->Description()); } void SpellChecker::ReplaceMisspelledRange(const String& text) {
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp index 23f195c..f1a43450 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -126,7 +126,6 @@ namespace { constexpr float kMostlyFillViewportThreshold = 0.85f; -constexpr double kMostlyFillViewportBecomeStableSeconds = 5; constexpr double kCheckViewportIntersectionIntervalSeconds = 1; // This enum is used to record histograms. Do not reorder. @@ -451,10 +450,6 @@ TaskRunnerHelper::Get(TaskType::kUnthrottled, &document), this, &HTMLMediaElement::AudioTracksTimerFired), - viewport_fill_debouncer_timer_( - TaskRunnerHelper::Get(TaskType::kUnthrottled, &document), - this, - &HTMLMediaElement::ViewportFillDebouncerTimerFired), check_viewport_intersection_timer_( TaskRunnerHelper::Get(TaskType::kUnthrottled, &document), this, @@ -558,8 +553,6 @@ TaskRunnerHelper::Get(TaskType::kUnthrottled, &GetDocument())); audio_tracks_timer_.MoveToNewTaskRunner( TaskRunnerHelper::Get(TaskType::kUnthrottled, &GetDocument())); - viewport_fill_debouncer_timer_.MoveToNewTaskRunner( - TaskRunnerHelper::Get(TaskType::kUnthrottled, &GetDocument())); check_viewport_intersection_timer_.MoveToNewTaskRunner( TaskRunnerHelper::Get(TaskType::kUnthrottled, &GetDocument())); deferred_load_timer_.MoveToNewTaskRunner( @@ -4115,28 +4108,13 @@ return; current_intersect_rect_ = intersect_rect; - // Reset on any intersection change, since this indicates the user is - // scrolling around in the document, the document is changing layout, etc. - viewport_fill_debouncer_timer_.Stop(); bool is_mostly_filling_viewport = (current_intersect_rect_.Size().Area() > kMostlyFillViewportThreshold * geometry.RootIntRect().Size().Area()); if (mostly_filling_viewport_ == is_mostly_filling_viewport) return; - if (!is_mostly_filling_viewport) { - mostly_filling_viewport_ = is_mostly_filling_viewport; - if (web_media_player_) - web_media_player_->BecameDominantVisibleContent(mostly_filling_viewport_); - return; - } - - viewport_fill_debouncer_timer_.StartOneShot( - kMostlyFillViewportBecomeStableSeconds, BLINK_FROM_HERE); -} - -void HTMLMediaElement::ViewportFillDebouncerTimerFired(TimerBase*) { - mostly_filling_viewport_ = true; + mostly_filling_viewport_ = is_mostly_filling_viewport; if (web_media_player_) web_media_player_->BecameDominantVisibleContent(mostly_filling_viewport_); }
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h index 618683f..304c3ef6 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -538,13 +538,10 @@ EnumerationHistogram& ShowControlsHistogram() const; - void ViewportFillDebouncerTimerFired(TimerBase*); - TaskRunnerTimer<HTMLMediaElement> load_timer_; TaskRunnerTimer<HTMLMediaElement> progress_event_timer_; TaskRunnerTimer<HTMLMediaElement> playback_progress_timer_; TaskRunnerTimer<HTMLMediaElement> audio_tracks_timer_; - TaskRunnerTimer<HTMLMediaElement> viewport_fill_debouncer_timer_; TaskRunnerTimer<HTMLMediaElement> check_viewport_intersection_timer_; Member<TimeRanges> played_time_ranges_;
diff --git a/third_party/WebKit/Source/core/html/MediaElementFillingViewportTest.cpp b/third_party/WebKit/Source/core/html/MediaElementFillingViewportTest.cpp index df955e0..12cc7152 100644 --- a/third_party/WebKit/Source/core/html/MediaElementFillingViewportTest.cpp +++ b/third_party/WebKit/Source/core/html/MediaElementFillingViewportTest.cpp
@@ -26,10 +26,6 @@ return element->mostly_filling_viewport_; } - bool ViewportFillDebouncerTimerActive(HTMLMediaElement* element) { - return element->viewport_fill_debouncer_timer_.IsActive(); - } - void CheckViewportIntersectionChanged(HTMLMediaElement* element) { element->ActivateViewportIntersectionMonitoring(true); EXPECT_TRUE(element->check_viewport_intersection_timer_.IsActive()); @@ -60,9 +56,7 @@ HTMLMediaElement* element = ToElement<HTMLMediaElement>(GetDocument().getElementById("video")); CheckViewportIntersectionChanged(element); - EXPECT_FALSE(IsMostlyFillingViewport(element)); - EXPECT_TRUE(ViewportFillDebouncerTimerActive(element)); - // TODO(xjz): Mock the time and check isMostlyFillingViewport() after 5s. + EXPECT_TRUE(IsMostlyFillingViewport(element)); } TEST_F(MediaElementFillingViewportTest, NotMostlyFillingViewport) { @@ -81,7 +75,6 @@ ToElement<HTMLMediaElement>(GetDocument().getElementById("video")); CheckViewportIntersectionChanged(element); EXPECT_FALSE(IsMostlyFillingViewport(element)); - EXPECT_FALSE(ViewportFillDebouncerTimerActive(element)); } TEST_F(MediaElementFillingViewportTest, FillingViewportChanged) { @@ -99,8 +92,7 @@ HTMLMediaElement* element = ToElement<HTMLMediaElement>(GetDocument().getElementById("video")); CheckViewportIntersectionChanged(element); - EXPECT_FALSE(IsMostlyFillingViewport(element)); - EXPECT_TRUE(ViewportFillDebouncerTimerActive(element)); + EXPECT_TRUE(IsMostlyFillingViewport(element)); element->setAttribute("style", "position:fixed; left:0; top:0; width:80%; height:80%;", @@ -109,7 +101,6 @@ CheckViewportIntersectionChanged(element); EXPECT_FALSE(IsMostlyFillingViewport(element)); - EXPECT_FALSE(ViewportFillDebouncerTimerActive(element)); } TEST_F(MediaElementFillingViewportTest, LargeVideo) { @@ -127,8 +118,7 @@ HTMLMediaElement* element = ToElement<HTMLMediaElement>(GetDocument().getElementById("video")); CheckViewportIntersectionChanged(element); - EXPECT_FALSE(IsMostlyFillingViewport(element)); - EXPECT_TRUE(ViewportFillDebouncerTimerActive(element)); + EXPECT_TRUE(IsMostlyFillingViewport(element)); } TEST_F(MediaElementFillingViewportTest, VideoScrollOutHalf) { @@ -146,8 +136,7 @@ HTMLMediaElement* element = ToElement<HTMLMediaElement>(GetDocument().getElementById("video")); CheckViewportIntersectionChanged(element); - EXPECT_FALSE(IsMostlyFillingViewport(element)); - EXPECT_TRUE(ViewportFillDebouncerTimerActive(element)); + EXPECT_TRUE(IsMostlyFillingViewport(element)); element->setAttribute( "style", "position:fixed; left:0; top:240px; width:100%; height:100%;", @@ -155,7 +144,6 @@ Compositor().BeginFrame(); CheckViewportIntersectionChanged(element); EXPECT_FALSE(IsMostlyFillingViewport(element)); - EXPECT_FALSE(ViewportFillDebouncerTimerActive(element)); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json index e40997f..feaaf55 100644 --- a/third_party/WebKit/Source/core/inspector/browser_protocol.json +++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -580,6 +580,10 @@ "returns": [ { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Execution context of the isolated world." } ] + }, + { + "name": "bringToFront", + "description": "Brings page to front (activates tab)." } ], "events": [
diff --git a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json index 3b2bbb2..a4390268 100644 --- a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json +++ b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
@@ -80,7 +80,7 @@ { "domain": "Page", "exclude": ["getNavigationHistory", "navigateToHistoryEntry", "captureScreenshot", "screencastFrameAck", "handleJavaScriptDialog", "setColorPickerEnabled", - "getAppManifest", "requestAppBanner", "setControlNavigations", "processNavigation", "printToPDF"], + "getAppManifest", "requestAppBanner", "setControlNavigations", "processNavigation", "printToPDF", "bringToFront"], "async": ["getResourceContent", "searchInResource"], "exclude_events": ["screencastFrame", "screencastVisibilityChanged", "colorPicked", "interstitialShown", "interstitialHidden", "navigationRequested"] },
diff --git a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp index dc9ad40..e0d2856 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp
@@ -892,10 +892,22 @@ void LayoutTheme::SetSizeIfAuto(ComputedStyle& style, const IntSize& size) { if (style.Width().IsIntrinsicOrAuto()) style.SetWidth(Length(size.Width(), kFixed)); - if (style.Height().IsAuto()) + if (style.Height().IsIntrinsicOrAuto()) style.SetHeight(Length(size.Height(), kFixed)); } +// static +void LayoutTheme::SetMinimumSizeIfAuto(ComputedStyle& style, + const IntSize& size) { + // We only want to set a minimum size if no explicit size is specified, to + // avoid overriding author intentions. + if (style.MinWidth().IsIntrinsicOrAuto() && style.Width().IsIntrinsicOrAuto()) + style.SetMinWidth(Length(size.Width(), kFixed)); + if (style.MinHeight().IsIntrinsicOrAuto() && + style.Height().IsIntrinsicOrAuto()) + style.SetMinHeight(Length(size.Height(), kFixed)); +} + void LayoutTheme::AdjustCheckboxStyleUsingFallbackTheme( ComputedStyle& style) const { // If the width and height are both specified, then we have nothing to do. @@ -907,6 +919,7 @@ float zoom_level = style.EffectiveZoom(); size.SetWidth(size.Width() * zoom_level); size.SetHeight(size.Height() * zoom_level); + SetMinimumSizeIfAuto(style, size); SetSizeIfAuto(style, size); // padding - not honored by WinIE, needs to be removed. @@ -929,6 +942,7 @@ float zoom_level = style.EffectiveZoom(); size.SetWidth(size.Width() * zoom_level); size.SetHeight(size.Height() * zoom_level); + SetMinimumSizeIfAuto(style, size); SetSizeIfAuto(style, size); // padding - not honored by WinIE, needs to be removed.
diff --git a/third_party/WebKit/Source/core/layout/LayoutTheme.h b/third_party/WebKit/Source/core/layout/LayoutTheme.h index 4a8a538..be7f30d 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTheme.h +++ b/third_party/WebKit/Source/core/layout/LayoutTheme.h
@@ -62,6 +62,10 @@ virtual void DidChangeThemeEngine() {} static void SetSizeIfAuto(ComputedStyle&, const IntSize&); + // SetMinimumSizeIfAuto must be called before SetSizeIfAuto, because we + // will not set a minimum size if an explicit size is set, and SetSizeIfAuto + // sets an explicit size. + static void SetMinimumSizeIfAuto(ComputedStyle&, const IntSize&); // This method is called whenever style has been computed for an element and // the appearance property has been set to a value other than "none".
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp index c31cd6bb..d6df6f7 100644 --- a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp
@@ -200,6 +200,7 @@ float zoom_level = style.EffectiveZoom(); size.SetWidth(size.Width() * zoom_level); size.SetHeight(size.Height() * zoom_level); + SetMinimumSizeIfAuto(style, size); SetSizeIfAuto(style, size); } @@ -213,6 +214,7 @@ float zoom_level = style.EffectiveZoom(); size.SetWidth(size.Width() * zoom_level); size.SetHeight(size.Height() * zoom_level); + SetMinimumSizeIfAuto(style, size); SetSizeIfAuto(style, size); }
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp index 145d58e..335ae68 100644 --- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp +++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -829,7 +829,7 @@ // FIXME: Per https://xhr.spec.whatwg.org/#dom-xmlhttprequest-send the // Content-Type header and whether to serialize as HTML or XML should // depend on |document->isHTMLDocument()|. - if (GetRequestHeader(HTTPNames::Content_Type).IsEmpty()) + if (!HasContentTypeRequestHeader()) SetRequestHeaderInternal(HTTPNames::Content_Type, "application/xml;charset=UTF-8"); @@ -868,7 +868,7 @@ RefPtr<EncodedFormData> http_body; if (AreMethodAndURLValidForSend()) { - if (GetRequestHeader(HTTPNames::Content_Type).IsEmpty()) { + if (!HasContentTypeRequestHeader()) { const String& blob_type = FetchUtils::NormalizeHeaderValue(body->type()); if (!blob_type.IsEmpty() && ParsedContentType(blob_type).IsValid()) { SetRequestHeaderInternal(HTTPNames::Content_Type, @@ -907,7 +907,7 @@ // TODO (sof): override any author-provided charset= in the // content type value to UTF-8 ? - if (GetRequestHeader(HTTPNames::Content_Type).IsEmpty()) { + if (!HasContentTypeRequestHeader()) { AtomicString content_type = AtomicString("multipart/form-data; boundary=") + FetchUtils::NormalizeHeaderValue(http_body->Boundary().data()); @@ -1402,9 +1402,9 @@ } } -const AtomicString& XMLHttpRequest::GetRequestHeader( - const AtomicString& name) const { - return request_headers_.Get(name); +bool XMLHttpRequest::HasContentTypeRequestHeader() const { + return request_headers_.Find(HTTPNames::Content_Type) != + request_headers_.end(); } String XMLHttpRequest::getAllResponseHeaders() const { @@ -1508,7 +1508,7 @@ const String& charset) { // http://xhr.spec.whatwg.org/#the-send()-method step 4's concilliation of // "charset=" in any author-provided Content-Type: request header. - String content_type = GetRequestHeader(HTTPNames::Content_Type); + String content_type = request_headers_.Get(HTTPNames::Content_Type); if (content_type.IsEmpty()) { SetRequestHeaderInternal(HTTPNames::Content_Type, default_content_type); return;
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h index cf581ab..74322507 100644 --- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h +++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h
@@ -243,7 +243,7 @@ void send(DOMArrayBuffer*, ExceptionState&); void send(DOMArrayBufferView*, ExceptionState&); - const AtomicString& GetRequestHeader(const AtomicString& name) const; + bool HasContentTypeRequestHeader() const; void SetRequestHeaderInternal(const AtomicString& name, const AtomicString& value);
diff --git a/third_party/WebKit/Source/devtools/front_end/console_test_runner/ConsoleTestRunner.js b/third_party/WebKit/Source/devtools/front_end/console_test_runner/ConsoleTestRunner.js index 0f0527e1..3a9931914 100644 --- a/third_party/WebKit/Source/devtools/front_end/console_test_runner/ConsoleTestRunner.js +++ b/third_party/WebKit/Source/devtools/front_end/console_test_runner/ConsoleTestRunner.js
@@ -513,3 +513,11 @@ return null; } }; + +/** + * @param {!Function} override + * @param {boolean=} opt_sticky + */ +ConsoleTestRunner.addConsoleSniffer = function(override, opt_sticky) { + TestRunner.addSniffer(ConsoleModel.ConsoleModel.prototype, 'addMessage', override, opt_sticky); +};
diff --git a/third_party/WebKit/Source/devtools/front_end/integration_test_runner/IntegrationTestRunner.js b/third_party/WebKit/Source/devtools/front_end/integration_test_runner/IntegrationTestRunner.js index a2bc34cd..8727b809 100644 --- a/third_party/WebKit/Source/devtools/front_end/integration_test_runner/IntegrationTestRunner.js +++ b/third_party/WebKit/Source/devtools/front_end/integration_test_runner/IntegrationTestRunner.js
@@ -45,13 +45,14 @@ * @param {!Function} callback */ TestRunner.evaluateInPage = async function(code, callback) { - if (typeof code === 'function') { - if (code.length) { - TestRunner.addResult('ERROR: do not use evaluateInPage on a function with parameters: ' + code.toString()); - TestRunner.addResult('TestRunner.evaluateInPage invokes the function without arguments'); - } - code = `(${code.toString()})()`; - } + var lines = new Error().stack.split('at '); + var components = lines[lines.length - 2].trim().split('/'); + var source = components[components.length - 1].slice(0, -1).split(':'); + var fileName = source[0]; + var lineOffset = parseInt(source[1], 10); + code = '\n'.repeat(lineOffset - 1) + code; + if (code.indexOf('sourceURL=') === -1) + code += `//# sourceURL=${fileName}`; var response = await TestRunner.RuntimeAgent.invoke_evaluate({expression: code, objectGroup: 'console'}); if (!response[Protocol.Error]) { TestRunner.safeWrap(callback)(
diff --git a/third_party/WebKit/Source/devtools/package.json b/third_party/WebKit/Source/devtools/package.json index 8d04000..56d1c858 100644 --- a/third_party/WebKit/Source/devtools/package.json +++ b/third_party/WebKit/Source/devtools/package.json
@@ -15,7 +15,8 @@ "extract": "node scripts/extract_module/extract_module.js", "check-gn": "node scripts/check_gn.js", "check-json": "node scripts/json_validator/validate_module_json.js", - "check-descriptors": "node scripts/check_application_descriptors.js" + "check-descriptors": "node scripts/check_application_descriptors.js", + "migrate": "node scripts/migrate_test/migrate_test.js" }, "repository": { "type": "git",
diff --git a/third_party/WebKit/Source/devtools/scripts/migrate_test/migrate_test.js b/third_party/WebKit/Source/devtools/scripts/migrate_test/migrate_test.js new file mode 100644 index 0000000..a49a166 --- /dev/null +++ b/third_party/WebKit/Source/devtools/scripts/migrate_test/migrate_test.js
@@ -0,0 +1,355 @@ +// 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. + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const cheerio = require('cheerio'); +const mkdirp = require('mkdirp'); +const recast = require('recast'); +const types = recast.types; +const b = recast.types.builders; +const args = require('yargs') + .wrap(Math.min(process.stdout.columns, 120)) + .example('node $0 existing-test.html') + .boolean('dry-run') + .help('help') + .demand(1) + .argv; + +const utils = require('../utils'); + +const FRONT_END_PATH = path.resolve(__dirname, '..', '..', 'front_end'); +const LINE_BREAK = '$$SECRET_IDENTIFIER_FOR_LINE_BREAK$$();'; + +function main() { + const inputPaths = args._.map(p => path.isAbsolute(p) ? p : path.resolve(process.cwd(), p)); + const identifierMap = generateTestHelperMap(); + for (const inputPath of inputPaths) { + migrateTest(inputPath, identifierMap); + } + console.log(`Finished migrating ${inputPaths.length} tests`); +} + +main(); + +function migrateTest(inputPath, identifierMap) { + console.log('Starting to migrate: ', inputPath); + const htmlTestFile = fs.readFileSync(inputPath, 'utf-8'); + const $ = cheerio.load(htmlTestFile); + const additionalHelperBlocks = []; + const inputCode = $('script:not([src])') + .toArray() + .map(n => n.children[0].data) + .map(code => processScriptCode(code, additionalHelperBlocks)) + .filter(x => !!x) + .join('\n'); + const bodyText = $('body').text().trim(); + const helperScripts = $('script[src]').toArray().map((n) => n.attribs.src).map(src => { + const components = src.split('/'); + return components[components.length - 1].split('.')[0]; + }); + + let outputCode; + try { + const testHelpers = mapTestHelpers(helperScripts); + let domFixture = $('body') + .html() + .trim() + // Tries to remove it if it has it's own line + .replace(bodyText + '\n', '') + // Tries to remove it if it's inline + .replace(bodyText, ''); + if (/<p>\s*<\/p>/.test(domFixture)) { + domFixture = undefined; + } + const onloadFunctionName = $('body')[0].attribs.onload.slice(0, -2); + outputCode = transformTestScript( + inputCode, bodyText, identifierMap, testHelpers, additionalHelperBlocks, getPanel(inputPath), domFixture, + onloadFunctionName); + } catch (err) { + console.log('Unable to migrate: ', inputPath); + console.log('ERROR: ', err); + return; + } + if (args.dryRun) { + console.log(outputCode); + } else { + const outPath = getOutPath(inputPath); + mkdirp.sync(path.dirname(outPath)); + fs.writeFileSync(outPath, outputCode); + const expectationsPath = inputPath.replace('.html', '-expected.txt'); + copyExpectations(expectationsPath, outPath); + fs.unlinkSync(inputPath); + fs.unlinkSync(expectationsPath); + console.log(outputCode); + console.log('Migrated to: ', outPath); + } +} + +function transformTestScript( + inputCode, bodyText, identifierMap, testHelpers, additionalHelperBlocks, panel, domFixture, onloadFunctionName) { + const ast = recast.parse(inputCode); + + /** + * Wrap everything that's not the magical 'test' function + * with evaluateInPagePromise + */ + const nonTestNodes = []; + for (const [index, node] of ast.program.body.entries()) { + if (node.type === 'FunctionDeclaration' && node.id.name === 'test') { + continue; + } + if (node.type === 'VariableDeclaration' && node.declarations[0].id.name === 'test') { + continue; + } + nonTestNodes.push(node); + } + + unwrapTestFunctionExpressionIfNecessary(ast); + unwrapTestFunctionDeclarationIfNecessary(ast); + + /** + * Create test header based on extracted data + */ + const headerLines = []; + headerLines.push(createExpressionNode(`TestRunner.addResult('${bodyText}\\n');`)); + headerLines.push(createExpressionNode(LINE_BREAK)); + for (const helper of testHelpers) { + headerLines.push(createAwaitExpressionNode(`await TestRunner.loadModule('${helper}');`)); + } + headerLines.push(createAwaitExpressionNode(`await TestRunner.loadPanel('${panel}');`)); + for (const helper of additionalHelperBlocks) { + headerLines.push(helper); + } + + if (domFixture) { + headerLines.push(createAwaitExpressionNode(`await TestRunner.loadHTML(\` +${domFixture.split('\n').map(line => ' ' + line).join('\n')} + \`)`)); + } + + let nonTestCode = nonTestNodes.reduce((acc, node) => { + let code = recast.print(node).code.split('\n').map(line => ' ' + line).join('\n'); + if (node.id && node.id.name === onloadFunctionName) { + code = code.replace(' runTest();\n', ''); + code = ` (${code.trimLeft()})();`; + }; + return acc + '\n' + code; + }, ''); + + nonTestCode = nonTestCode.startsWith('\n') && nonTestCode.slice(2); + if (nonTestCode) { + headerLines.push((createAwaitExpressionNode(`await TestRunner.evaluateInPagePromise(\` + ${nonTestCode} + \`)`))); + } + ast.program.body = headerLines.concat(ast.program.body); + + /** + * Wrap entire body in an async IIFE + */ + const iife = b.functionExpression(null, [], b.blockStatement(ast.program.body)); + iife.async = true; + ast.program.body = [b.expressionStatement(b.callExpression(iife, []))]; + + /** + * Migrate all the call sites from InspectorTest to .*TestRunner + */ + recast.visit(ast, { + visitIdentifier: function(path) { + if (path.parentPath && path.parentPath.value && path.parentPath.value.object && + path.parentPath.value.object.name === 'InspectorTest' && path.value.name !== 'InspectorTest') { + const newParentIdentifier = identifierMap.get(path.value.name); + if (!newParentIdentifier) { + throw new Error('Could not find identifier for', path.value.name); + } + path.parentPath.value.object.name = newParentIdentifier; + } + return false; + } + }); + + return print(ast); +} + +function copyExpectations(expectationsPath, outTestPath) { + const outExpectationsPath = path.resolve(path.dirname(outTestPath), path.basename(expectationsPath)); + fs.writeFileSync(outExpectationsPath, fs.readFileSync(expectationsPath)); +} + +/** + * If the <script></script> block doesn't contain a test function + * assume that it needs to be serialized + */ +function processScriptCode(code, additionalHelperBlocks) { + const ast = recast.parse(code); + const testFunctionExpression = + ast.program.body.find(n => n.type === 'VariableDeclaration' && n.declarations[0].id.name === 'test'); + const testFunctionDeclaration = ast.program.body.find(n => n.type === 'FunctionDeclaration' && n.id.name === 'test'); + if (testFunctionExpression || testFunctionDeclaration) { + return code; + } + const formattedCode = code.trimRight().split('\n').map(line => ' ' + line).join('\n'); + additionalHelperBlocks.push(createAwaitExpressionNode(`await TestRunner.evaluateInPagePromise(\`${formattedCode} + \`)`)); + return; +} + +/** + * Unwrap test if it's a function expression + * var test = function () {...} + */ +function unwrapTestFunctionExpressionIfNecessary(ast) { + const index = + ast.program.body.findIndex(n => n.type === 'VariableDeclaration' && n.declarations[0].id.name === 'test'); + if (index > -1) { + const testFunctionNode = ast.program.body[index]; + ast.program.body = testFunctionNode.declarations[0].init.body.body; + } +} + + +/** + * Unwrap test if it's a function declaration + * function test () {...} + */ +function unwrapTestFunctionDeclarationIfNecessary(ast) { + const index = ast.program.body.findIndex(n => n.type === 'FunctionDeclaration' && n.id.name === 'test'); + if (index > -1) { + const testFunctionNode = ast.program.body[index]; + ast.program.body.splice(index, 1); + ast.program.body = testFunctionNode.body.body; + } +} + +function print(ast) { + const copyrightNotice = `// 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. + +`; + + /** + * Not using clang-format because certain tests look bad when formatted by it. + * Recast pretty print is smarter about preserving existing spacing. + */ + let code = recast.prettyPrint(ast, {tabWidth: 2, wrapColumn: 120, quote: 'single'}).code; + code = code.replace(/(\/\/\#\s*sourceURL=[\w-]+)\.html/, '$1.js'); + const copyrightedCode = copyrightNotice + code.split(LINE_BREAK).join('') + '\n'; + return copyrightedCode; +} + + +function getOutPath(inputPath) { + // TODO: Only works for non-http tests + const layoutTestPrefix = 'LayoutTests/inspector'; + const postfix = + inputPath.slice(inputPath.indexOf(layoutTestPrefix) + layoutTestPrefix.length + 1).replace('.html', '.js'); + const out = path.resolve( + __dirname, '..', '..', '..', '..', 'LayoutTests', 'http', 'tests', 'inspector', 'devtools-js', postfix); + return out; +} + +function getPanel(inputPath) { + const panelByFolder = { + 'animation': 'elements', + 'audits': 'audits', + 'console': 'console', + 'elements': 'elements', + 'editor': 'sources', + 'layers': 'layers', + 'network': 'network', + 'profiler': 'heap_profiler', + 'resource-tree': 'resources', + 'search': 'sources', + 'security': 'security', + 'service-workers': 'resources', + 'sources': 'sources', + 'timeline': 'timeline', + 'tracing': 'timeline', + }; + // Only works for non-http tests + const folder = inputPath.slice(inputPath.indexOf('LayoutTests/')).split('/')[2]; + const panel = panelByFolder[folder]; + if (!panel) { + throw new Error('Could not figure out which panel to map folder: ' + folder); + } + return panel; +} + +function mapTestHelpers(testHelpers) { + const SKIP = 'SKIP'; + const testHelperMap = { + 'inspector-test': SKIP, + 'console-test': 'console_test_runner', + 'elements-test': 'elements_test_runner', + }; + const mappedHelpers = []; + for (const helper of testHelpers) { + const mappedHelper = testHelperMap[helper]; + if (!mappedHelper) { + throw Error('Could not map helper ' + helper); + } + if (mappedHelper !== SKIP) { + mappedHelpers.push(mappedHelper); + } + } + return mappedHelpers; +} + +function generateTestHelperMap() { + const map = new Map(); + for (const folder of fs.readdirSync(FRONT_END_PATH)) { + if (folder.indexOf('test_runner') === -1) { + continue; + } + const testRunnerModulePath = path.resolve(FRONT_END_PATH, folder); + if (!utils.isDir(testRunnerModulePath)) { + continue; + } + for (const filename of fs.readdirSync(testRunnerModulePath)) { + if (filename === 'module.json') { + continue; + } + scrapeTestHelperIdentifiers(path.resolve(testRunnerModulePath, filename)); + } + } + return map; + + function scrapeTestHelperIdentifiers(filePath) { + var content = fs.readFileSync(filePath).toString(); + var lines = content.split('\n'); + for (var line of lines) { + var line = line.trim(); + if (line.indexOf('TestRunner.') === -1) + continue; + var match = line.match(/^(\b\w*TestRunner.[a-z_A-Z0-9]+)\s*(\=[^,}]|[;])/) || + line.match(/^(TestRunner.[a-z_A-Z0-9]+)\s*\=$/); + if (!match) + continue; + var name = match[1]; + var components = name.split('.'); + if (components.length !== 2) + continue; + map.set(components[1], components[0]); + } + } +} + +/** + * Hack to quickly create an AST node + */ +function createExpressionNode(code) { + return recast.parse(code).program.body[0]; +} + +/** + * Hack to quickly create an AST node + */ +function createAwaitExpressionNode(code) { + return recast.parse(`(async function(){${code}})`).program.body[0].expression.body.body[0]; +}
diff --git a/third_party/WebKit/Source/devtools/scripts/migrate_test/package.json b/third_party/WebKit/Source/devtools/scripts/migrate_test/package.json new file mode 100644 index 0000000..356adcb --- /dev/null +++ b/third_party/WebKit/Source/devtools/scripts/migrate_test/package.json
@@ -0,0 +1,12 @@ +{ + "name": "chrome-devtools-migrate-test", + "version": "0.1.0", + "author": "The Chromium Authors", + "license": "SEE LICENSE IN https://chromium.googlesource.com/chromium/src/+/master/LICENSE", + "dependencies": { + "cheerio": "^1.0.0-rc.2", + "mkdirp": "^0.5.1", + "recast": "^0.12.6", + "yargs": "^8.0.2" + } +}
diff --git a/third_party/WebKit/Source/modules/payments/AbortPaymentRespondWithObserver.cpp b/third_party/WebKit/Source/modules/payments/AbortPaymentRespondWithObserver.cpp new file mode 100644 index 0000000..900970f --- /dev/null +++ b/third_party/WebKit/Source/modules/payments/AbortPaymentRespondWithObserver.cpp
@@ -0,0 +1,60 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "modules/payments/AbortPaymentRespondWithObserver.h" + +#include <v8.h> +#include "bindings/core/v8/ScriptValue.h" +#include "bindings/core/v8/V8BindingForCore.h" +#include "core/dom/ExecutionContext.h" +#include "modules/payments/PaymentHandlerUtils.h" +#include "modules/serviceworkers/ServiceWorkerGlobalScopeClient.h" +#include "modules/serviceworkers/WaitUntilObserver.h" + +namespace blink { + +AbortPaymentRespondWithObserver::AbortPaymentRespondWithObserver( + ExecutionContext* context, + int event_id, + WaitUntilObserver* observer) + : RespondWithObserver(context, event_id, observer) {} + +void AbortPaymentRespondWithObserver::OnResponseRejected( + WebServiceWorkerResponseError error) { + PaymentHandlerUtils::ReportResponseError(GetExecutionContext(), + "AbortPaymentEvent", error); + + ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) + ->RespondToAbortPaymentEvent(event_id_, false, event_dispatch_time_); +} + +void AbortPaymentRespondWithObserver::OnResponseFulfilled( + const ScriptValue& value) { + DCHECK(GetExecutionContext()); + ExceptionState exception_state(value.GetIsolate(), + ExceptionState::kUnknownContext, + "AbortPaymentEvent", "respondWith"); + bool response = ToBoolean(ToIsolate(GetExecutionContext()), value.V8Value(), + exception_state); + if (exception_state.HadException()) { + exception_state.ClearException(); + OnResponseRejected(kWebServiceWorkerResponseErrorNoV8Instance); + return; + } + + ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) + ->RespondToAbortPaymentEvent(event_id_, response, event_dispatch_time_); +} + +void AbortPaymentRespondWithObserver::OnNoResponse() { + DCHECK(GetExecutionContext()); + ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) + ->RespondToAbortPaymentEvent(event_id_, false, event_dispatch_time_); +} + +DEFINE_TRACE(AbortPaymentRespondWithObserver) { + RespondWithObserver::Trace(visitor); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/modules/payments/AbortPaymentRespondWithObserver.h b/third_party/WebKit/Source/modules/payments/AbortPaymentRespondWithObserver.h new file mode 100644 index 0000000..17d29e06 --- /dev/null +++ b/third_party/WebKit/Source/modules/payments/AbortPaymentRespondWithObserver.h
@@ -0,0 +1,37 @@ +// 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 AbortPaymentRespondWithObserver_h +#define AbortPaymentRespondWithObserver_h + +#include "modules/ModulesExport.h" +#include "modules/serviceworkers/RespondWithObserver.h" +#include "public/platform/modules/serviceworker/WebServiceWorkerResponseError.h" + +namespace blink { + +class ExecutionContext; +class ScriptValue; +class WaitUntilObserver; + +// Implementation for AbortPaymentEvent.respondWith(), which is used by the +// payment handler to indicate whether it was able to abort the payment. +class MODULES_EXPORT AbortPaymentRespondWithObserver final + : public RespondWithObserver { + public: + AbortPaymentRespondWithObserver(ExecutionContext*, + int event_id, + WaitUntilObserver*); + ~AbortPaymentRespondWithObserver() override = default; + + void OnResponseRejected(WebServiceWorkerResponseError) override; + void OnResponseFulfilled(const ScriptValue&) override; + void OnNoResponse() override; + + DECLARE_VIRTUAL_TRACE(); +}; + +} // namespace blink + +#endif // AbortPaymentRespondWithObserver_h
diff --git a/third_party/WebKit/Source/modules/payments/BUILD.gn b/third_party/WebKit/Source/modules/payments/BUILD.gn index 1f08f59..3e5f975 100644 --- a/third_party/WebKit/Source/modules/payments/BUILD.gn +++ b/third_party/WebKit/Source/modules/payments/BUILD.gn
@@ -8,6 +8,8 @@ sources = [ "AbortPaymentEvent.cpp", "AbortPaymentEvent.h", + "AbortPaymentRespondWithObserver.cpp", + "AbortPaymentRespondWithObserver.h", "CanMakePaymentEvent.cpp", "CanMakePaymentEvent.h", "CanMakePaymentRespondWithObserver.cpp",
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeClient.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeClient.cpp index 8a99d14e..7f2823f 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeClient.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeClient.cpp
@@ -154,6 +154,14 @@ fetch_event_id, response, stream_handle, event_dispatch_time); } +void ServiceWorkerGlobalScopeClient::RespondToAbortPaymentEvent( + int event_id, + bool abort_payment, + double event_dispatch_time) { + client_.RespondToAbortPaymentEvent(event_id, abort_payment, + event_dispatch_time); +} + void ServiceWorkerGlobalScopeClient::RespondToCanMakePaymentEvent( int event_id, bool response, @@ -212,6 +220,14 @@ client_.DidHandleSyncEvent(sync_event_id, result, event_dispatch_time); } +void ServiceWorkerGlobalScopeClient::DidHandleAbortPaymentEvent( + int abort_payment_event_id, + WebServiceWorkerEventResult result, + double event_dispatch_time) { + client_.DidHandleAbortPaymentEvent(abort_payment_event_id, result, + event_dispatch_time); +} + void ServiceWorkerGlobalScopeClient::DidHandleCanMakePaymentEvent( int payment_request_event_id, WebServiceWorkerEventResult result,
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeClient.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeClient.h index ae76f58..f283682 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeClient.h +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeClient.h
@@ -107,6 +107,9 @@ const WebServiceWorkerResponse&, WebServiceWorkerStreamHandle*, double event_dispatch_time); + void RespondToAbortPaymentEvent(int event_id, + bool abort_payment, + double event_dispatch_time); void RespondToCanMakePaymentEvent(int event_id, bool can_make_payment, double event_dispatch_time); @@ -131,6 +134,9 @@ void DidHandleSyncEvent(int sync_event_id, WebServiceWorkerEventResult, double event_dispatch_time); + void DidHandleAbortPaymentEvent(int abort_payment_event_id, + WebServiceWorkerEventResult, + double event_dispatch_time); void DidHandleCanMakePaymentEvent(int payment_request_event_id, WebServiceWorkerEventResult, double event_dispatch_time);
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp index d8d5acc..4619605 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
@@ -55,6 +55,8 @@ #include "modules/notifications/Notification.h" #include "modules/notifications/NotificationEvent.h" #include "modules/notifications/NotificationEventInit.h" +#include "modules/payments/AbortPaymentEvent.h" +#include "modules/payments/AbortPaymentRespondWithObserver.h" #include "modules/payments/CanMakePaymentEvent.h" #include "modules/payments/CanMakePaymentRespondWithObserver.h" #include "modules/payments/PaymentEventDataConversion.h" @@ -443,6 +445,21 @@ WorkerGlobalScope()->DispatchExtendableEvent(event, observer); } +void ServiceWorkerGlobalScopeProxy::DispatchAbortPaymentEvent(int event_id) { + WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create( + WorkerGlobalScope(), WaitUntilObserver::kAbortPayment, event_id); + AbortPaymentRespondWithObserver* respond_with_observer = + new AbortPaymentRespondWithObserver(WorkerGlobalScope(), event_id, + wait_until_observer); + + Event* event = AbortPaymentEvent::Create( + EventTypeNames::abortpayment, ExtendableEventInit(), + respond_with_observer, wait_until_observer); + + WorkerGlobalScope()->DispatchExtendableEventWithRespondWith( + event, wait_until_observer, respond_with_observer); +} + void ServiceWorkerGlobalScopeProxy::DispatchCanMakePaymentEvent( int event_id, const WebCanMakePaymentEventData& web_event_data) {
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.h index bf244b7..aa23253 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.h +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.h
@@ -119,6 +119,7 @@ const WebNotificationData&) override; void DispatchPushEvent(int, const WebString& data) override; void DispatchSyncEvent(int, const WebString& tag, LastChanceOption) override; + void DispatchAbortPaymentEvent(int) override; void DispatchCanMakePaymentEvent(int, const WebCanMakePaymentEventData&) override; void DispatchPaymentRequestEvent(int,
diff --git a/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.cpp b/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.cpp index 8e9edb1..537e8f2 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.cpp
@@ -248,6 +248,10 @@ ? kWebServiceWorkerEventResultRejected : kWebServiceWorkerEventResultCompleted; switch (type_) { + case kAbortPayment: + client->DidHandleAbortPaymentEvent(event_id_, result, + event_dispatch_time_); + break; case kActivate: client->DidHandleActivateEvent(event_id_, result, event_dispatch_time_); break;
diff --git a/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.h b/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.h index ae93d89a..521599d9 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.h +++ b/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.h
@@ -25,6 +25,7 @@ using PromiseSettledCallback = Function<void(const ScriptValue&)>; enum EventType { + kAbortPayment, kActivate, kCanMakePayment, kFetch,
diff --git a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h index 7b74f72b..9b75b5c 100644 --- a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h +++ b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
@@ -226,9 +226,6 @@ const WebServiceWorkerResponse& response, WebServiceWorkerStreamHandle* body_as_stream, double event_dispatch_time) {} - virtual void RespondToCanMakePaymentEvent(int event_id, - bool can_make_payment, - double event_dispatch_time) {} virtual void DidHandleFetchEvent(int fetch_event_id, WebServiceWorkerEventResult result, double event_dispatch_time) {} @@ -265,17 +262,42 @@ WebServiceWorkerEventResult result, double event_dispatch_time) {} - virtual void RespondToPaymentRequestEvent( - int event_id, - const WebPaymentHandlerResponse& response, - double event_dispatch_time) {} + // RespondToAbortPaymentEvent will be called after the service worker + // returns a response to a AbortPaymentEvent, and DidHandleAbortPaymentEvent + // will be called after the end of AbortPaymentEvent's lifecycle. + // |event_id| is the id that was passed to DispatchAbortPaymentEvent. + virtual void RespondToAbortPaymentEvent(int event_id, + bool abort_payment, + double event_dispatch_time) {} + // Called after AbortPaymentEvent (dispatched + // via WebServiceWorkerContextProxy) is handled by the service worker. + virtual void DidHandleAbortPaymentEvent(int abort_payment_event_id, + WebServiceWorkerEventResult result, + double event_dispatch_time) {} - // Called after PaymentRequestEvent (dispatched + // RespondToCanMakePaymentEvent will be called after the service worker + // returns a response to a CanMakePaymentEvent, and + // DidHandleCanMakePaymentEvent will be called after the end of + // CanMakePaymentEvent's lifecycle. |event_id| is the id that was passed + // to DispatchCanMakePaymentEvent. + virtual void RespondToCanMakePaymentEvent(int event_id, + bool can_make_payment, + double event_dispatch_time) {} + // Called after CanMakePaymentEvent (dispatched // via WebServiceWorkerContextProxy) is handled by the service worker. virtual void DidHandleCanMakePaymentEvent(int payment_request_event_id, WebServiceWorkerEventResult result, double event_dispatch_time) {} + // RespondToPaymentRequestEvent will be called after the service worker + // returns a response to a PaymentRequestEvent, and + // DidHandlePaymentRequestEvent will be called after the end of + // PaymentRequestEvent's lifecycle. |event_id| is the id that was passed + // to DispatchPaymentRequestEvent. + virtual void RespondToPaymentRequestEvent( + int event_id, + const WebPaymentHandlerResponse& response, + double event_dispatch_time) {} // Called after PaymentRequestEvent (dispatched via // WebServiceWorkerContextProxy) is handled by the service worker. virtual void DidHandlePaymentRequestEvent(int payment_request_event_id,
diff --git a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h index 6e8df620..d46f042 100644 --- a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h +++ b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h
@@ -116,6 +116,8 @@ const WebString& tag, LastChanceOption) = 0; + virtual void DispatchAbortPaymentEvent(int event_id) = 0; + virtual void DispatchCanMakePaymentEvent( int event_id, const WebCanMakePaymentEventData&) = 0;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 65c7eaa..bc429e42 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -24828,6 +24828,9 @@ </histogram> <histogram name="Histogram.InconsistentCountHigh"> + <obsolete> + Deprecated 7/2017. + </obsolete> <owner>asvitkine@chromium.org</owner> <summary> The number of extra samples counted in the redundant_count in a histogram @@ -24836,6 +24839,9 @@ </histogram> <histogram name="Histogram.InconsistentCountLow"> + <obsolete> + Deprecated 7/2017. + </obsolete> <owner>asvitkine@chromium.org</owner> <summary> The number of missing samples in the redundant_count in a histogram that
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index 8577c31..17e6a00 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -75,7 +75,6 @@ smoothness.key_silk_cases,ajuma@chromium.org, smoothness.maps,"kbr@chromium.org, zmo@chromium.org", smoothness.pathological_mobile_sites,picksi@chromium.org, -smoothness.scrolling_tough_ad_cases,skyostil@chromium.org, smoothness.simple_mobile_sites,vmiura@chromium.org, smoothness.sync_scroll.key_mobile_sites_smooth,"tdresser@chromium.org, rbyers@chromium.org", smoothness.top_25_smooth,vmiura@chromium.org,
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py index 707a7e9..bdd144da 100644 --- a/tools/perf/benchmarks/smoothness.py +++ b/tools/perf/benchmarks/smoothness.py
@@ -689,34 +689,6 @@ return StoryExpectations() -# http://crbug.com/522619 (mac/win) -# http://crbug.com/683247 (android/linux) -@benchmark.Disabled('win', 'mac', 'android', 'linux') -@benchmark.Owner(emails=['skyostil@chromium.org']) -class SmoothnessScrollingToughAdCases(_Smoothness): - """Measures rendering statistics while scrolling advertisements.""" - page_set = page_sets.ScrollingToughAdCasesPageSet - - @classmethod - def ShouldDisable(cls, possible_browser): # http://crbug.com/597656 - return (possible_browser.browser_type == 'reference' and - possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X') - - @classmethod - def Name(cls): - return 'smoothness.scrolling_tough_ad_cases' - - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://time.com/3977891/donald-trump-debate-republican/', - [story_module.expectations.ALL], 'crbug.com/520509') - self.DisableStory( - 'http://m.tmz.com', [story_module.expectations.ALL], 'crbug.com/597656') - return StoryExpectations() - - @benchmark.Owner(emails=['skyostil@chromium.org']) class SmoothnessToughWebGLAdCases(_Smoothness): """Measures rendering statistics while scrolling advertisements."""
diff --git a/tools/perf/page_sets/tough_ad_cases.py b/tools/perf/page_sets/tough_ad_cases.py index 08821e7..0a4b1bb 100644 --- a/tools/perf/page_sets/tough_ad_cases.py +++ b/tools/perf/page_sets/tough_ad_cases.py
@@ -209,11 +209,3 @@ y_scroll_distance_multiplier=0.25)) self.AddStory(AdPage('http://androidpolice.com', self, scroll=scroll, wait_for_interactive_or_better=True)) - - -class ScrollingToughAdCasesPageSet(ToughAdCasesPageSet): - """Pages for measuring scrolling performance with advertising content.""" - - def __init__(self): - super(ScrollingToughAdCasesPageSet, self).__init__( - scroll=True)
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc index 273a68a..1b3b107 100644 --- a/ui/app_list/views/search_box_view.cc +++ b/ui/app_list/views/search_box_view.cc
@@ -100,7 +100,8 @@ } // namespace -// To paint grey background on mic and back buttons +// To paint grey background on mic and back buttons, and close buttons for +// fullscreen launcher. class SearchBoxImageButton : public views::ImageButton { public: explicit SearchBoxImageButton(views::ButtonListener* listener) @@ -132,8 +133,10 @@ private: // views::View overrides: void OnPaintBackground(gfx::Canvas* canvas) override { - if (state() == STATE_HOVERED || state() == STATE_PRESSED || selected_) + if ((state() == STATE_HOVERED && !features::IsFullscreenAppListEnabled()) || + state() == STATE_PRESSED || selected_) { canvas->FillRect(gfx::Rect(size()), kSelectedColor); + } } const char* GetClassName() const override { return "SearchBoxImageButton"; }
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index 559f968..2ed8b230 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc
@@ -2704,6 +2704,7 @@ SetMsgHandled(FALSE); return -1; } + unsigned int mapped_pointer_id = id_generator_.GetGeneratedID(pointer_id); POINTER_INFO pointer_info = pointer_touch_info.pointerInfo; @@ -2731,9 +2732,9 @@ ui::TouchEvent event( event_type, touch_point, event_time, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, pointer_id, - radius_x, radius_y, pressure, 0.0f, 0.0f, 0.0f, - pointer_touch_info.orientation), + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, + mapped_pointer_id, radius_x, radius_y, pressure, 0.0f, + 0.0f, 0.0f, pointer_touch_info.orientation), ui::GetModifiersFromKeyState(), rotation_angle); event.latency()->AddLatencyNumberWithTimestamp( @@ -2744,6 +2745,8 @@ base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr()); delegate_->HandleTouchEvent(event); + if (event_type == ui::ET_TOUCH_RELEASED) + id_generator_.ReleaseNumber(pointer_id); if (ref) SetMsgHandled(TRUE); return 0; @@ -2753,6 +2756,7 @@ WPARAM w_param, LPARAM l_param) { UINT32 pointer_id = GET_POINTERID_WPARAM(w_param); + unsigned int mapped_pointer_id = id_generator_.GetGeneratedID(pointer_id); using GetPointerPenInfoFn = BOOL(WINAPI*)(UINT32, POINTER_PEN_INFO*); POINTER_PEN_INFO pointer_pen_info; static GetPointerPenInfoFn get_pointer_pen_info = @@ -2803,6 +2807,7 @@ } else { flag = ui::EF_LEFT_MOUSE_BUTTON; } + id_generator_.ReleaseNumber(pointer_id); click_count = 1; break; case WM_POINTERUPDATE: @@ -2822,12 +2827,13 @@ break; case WM_POINTERLEAVE: event_type = ui::ET_MOUSE_EXITED; + id_generator_.ReleaseNumber(pointer_id); break; default: NOTREACHED(); } ui::PointerDetails pointer_details( - input_type, pointer_id, /* radius_x */ 0.0f, /* radius_y */ 0.0f, + input_type, mapped_pointer_id, /* radius_x */ 0.0f, /* radius_y */ 0.0f, pressure, tilt_x, tilt_y, /* tangential_pressure */ 0.0f, rotation); ui::MouseEvent event(event_type, point, point, base::TimeTicks::Now(), flag, flag, pointer_details);
diff --git a/ui/webui/resources/html/md_select_css.html b/ui/webui/resources/html/md_select_css.html index 2128ad5..22d029d 100644 --- a/ui/webui/resources/html/md_select_css.html +++ b/ui/webui/resources/html/md_select_css.html
@@ -58,7 +58,6 @@ -webkit-margin-start: var(--md-select-side-padding); border-top: 1px solid var(--paper-grey-300); display: block; - height: 0; margin-bottom: 0; margin-top: 0; }