diff --git a/.gitignore b/.gitignore index d9ea400..81c2a0c 100644 --- a/.gitignore +++ b/.gitignore
@@ -419,8 +419,6 @@ /third_party/pdfium /third_party/pefile /third_party/perl -/third_party/platformsdk_win7 -/third_party/platformsdk_win8 /third_party/ppapi /third_party/psyco_win32 /third_party/pthreads-win32
diff --git a/DEPS b/DEPS index eb98fa5..46fd1e15 100644 --- a/DEPS +++ b/DEPS
@@ -40,7 +40,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'ac1f09d53bfe8b99ae7ac82b54e3911258b07b6a', + 'skia_revision': '08d57e6ae6510a7724119ab548485b4fcbd0a48d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '0ef7ba086f9e48100f9caebd0a52de478f0ada0a', + 'pdfium_revision': '48f776f7e801d719683b251dc21ee8c0e3250d90', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -228,7 +228,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'af5a0a05e5bfc8bf22c0be334f4e8c0a9f600875', # commit position 15911 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '5445b0716f1a96eb11cc3745093c058dffd53227', # commit position 15919 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/ash/magnifier/partial_magnification_controller.cc b/ash/magnifier/partial_magnification_controller.cc index 260d7c3..a9184eb8 100644 --- a/ash/magnifier/partial_magnification_controller.cc +++ b/ash/magnifier/partial_magnification_controller.cc
@@ -13,6 +13,7 @@ #include "ui/compositor/paint_recorder.h" #include "ui/events/event.h" #include "ui/events/event_constants.h" +#include "ui/gfx/shadow_value.h" #include "ui/views/widget/widget.h" #include "ui/wm/core/coordinate_conversion.h"
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc index 750f048..671cad242 100644 --- a/base/metrics/histogram_base.cc +++ b/base/metrics/histogram_base.cc
@@ -125,7 +125,9 @@ // static void HistogramBase::EnableActivityReportHistogram( const std::string& process_type) { - DCHECK(!report_histogram_); + if (report_histogram_) + return; + size_t existing = StatisticsRecorder::GetHistogramCount(); if (existing != 0) { DVLOG(1) << existing
diff --git a/base/task_scheduler/post_task.cc b/base/task_scheduler/post_task.cc index 737a219c..8c3e941 100644 --- a/base/task_scheduler/post_task.cc +++ b/base/task_scheduler/post_task.cc
@@ -30,7 +30,13 @@ } // namespace void PostTask(const tracked_objects::Location& from_here, const Closure& task) { - PostTaskWithTraits(from_here, TaskTraits(), task); + PostDelayedTask(from_here, task, TimeDelta()); +} + +void PostDelayedTask(const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay) { + PostDelayedTaskWithTraits(from_here, TaskTraits(), task, delay); } void PostTaskAndReply(const tracked_objects::Location& from_here, @@ -42,7 +48,15 @@ void PostTaskWithTraits(const tracked_objects::Location& from_here, const TaskTraits& traits, const Closure& task) { - TaskScheduler::GetInstance()->PostTaskWithTraits(from_here, traits, task); + PostDelayedTaskWithTraits(from_here, traits, task, TimeDelta()); +} + +void PostDelayedTaskWithTraits(const tracked_objects::Location& from_here, + const TaskTraits& traits, + const Closure& task, + TimeDelta delay) { + TaskScheduler::GetInstance()->PostDelayedTaskWithTraits(from_here, traits, + task, delay); } void PostTaskWithTraitsAndReply(const tracked_objects::Location& from_here,
diff --git a/base/task_scheduler/post_task.h b/base/task_scheduler/post_task.h index 2087e06..ee1de7fb 100644 --- a/base/task_scheduler/post_task.h +++ b/base/task_scheduler/post_task.h
@@ -15,6 +15,7 @@ #include "base/single_thread_task_runner.h" #include "base/task_runner.h" #include "base/task_scheduler/task_traits.h" +#include "base/time/time.h" namespace base { @@ -58,12 +59,25 @@ // If those loose requirements are sufficient for your task, use // PostTask[AndReply], otherwise override these with explicit traits via // PostTaskWithTraits[AndReply]. +// +// Tasks posted to TaskScheduler with a delay may be coalesced (i.e. delays may +// be adjusted to reduce the number of wakeups and hence power consumption). // Posts |task| to the TaskScheduler. Calling this is equivalent to calling // PostTaskWithTraits with plain TaskTraits. BASE_EXPORT void PostTask(const tracked_objects::Location& from_here, const Closure& task); +// Posts |task| to the TaskScheduler. |task| will not run before |delay| +// expires. Calling this is equivalent to calling PostDelayedTaskWithTraits with +// plain TaskTraits. +// +// Use PostDelayedTaskWithTraits to specify a BACKGROUND priority if the task +// doesn't have to run as soon as |delay| expires. +BASE_EXPORT void PostDelayedTask(const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay); + // Posts |task| to the TaskScheduler and posts |reply| on the caller's execution // context (i.e. same sequence or thread and same TaskTraits if applicable) when // |task| completes. Calling this is equivalent to calling @@ -90,6 +104,17 @@ const TaskTraits& traits, const Closure& task); +// Posts |task| with specific |traits| to the TaskScheduler. |task| will not run +// before |delay| expires. +// +// Specify a BACKGROUND priority via |traits| if the task doesn't have to run as +// soon as |delay| expires. +BASE_EXPORT void PostDelayedTaskWithTraits( + const tracked_objects::Location& from_here, + const TaskTraits& traits, + const Closure& task, + TimeDelta delay); + // Posts |task| with specific |traits| to the TaskScheduler and posts |reply| on // the caller's execution context (i.e. same sequence or thread and same // TaskTraits if applicable) when |task| completes. Can only be called when @@ -118,10 +143,6 @@ Owned(result))); } -// Delayed tasks posted to TaskRunners returned by the functions below may be -// coalesced (i.e. delays may be adjusted to reduce the number of wakeups and -// hence power consumption). - // Returns a TaskRunner whose PostTask invocations result in scheduling tasks // using |traits|. Tasks may run in any order and in parallel. BASE_EXPORT scoped_refptr<TaskRunner> CreateTaskRunnerWithTraits(
diff --git a/base/task_scheduler/task_scheduler.h b/base/task_scheduler/task_scheduler.h index d4084c6f..5d9344b 100644 --- a/base/task_scheduler/task_scheduler.h +++ b/base/task_scheduler/task_scheduler.h
@@ -15,6 +15,7 @@ #include "base/single_thread_task_runner.h" #include "base/task_runner.h" #include "base/task_scheduler/task_traits.h" +#include "base/time/time.h" namespace tracked_objects { class Location; @@ -39,11 +40,13 @@ virtual ~TaskScheduler() = default; - // Posts |task| with specific |traits|. + // Posts |task| with a |delay| and specific |traits|. |delay| can be zero. // For one off tasks that don't require a TaskRunner. - virtual void PostTaskWithTraits(const tracked_objects::Location& from_here, - const TaskTraits& traits, - const Closure& task) = 0; + virtual void PostDelayedTaskWithTraits( + const tracked_objects::Location& from_here, + const TaskTraits& traits, + const Closure& task, + TimeDelta delay) = 0; // Returns a TaskRunner whose PostTask invocations result in scheduling tasks // using |traits|. Tasks may run in any order and in parallel.
diff --git a/base/task_scheduler/task_scheduler_impl.cc b/base/task_scheduler/task_scheduler_impl.cc index 701616e3..827caae 100644 --- a/base/task_scheduler/task_scheduler_impl.cc +++ b/base/task_scheduler/task_scheduler_impl.cc
@@ -14,7 +14,6 @@ #include "base/task_scheduler/sequence_sort_key.h" #include "base/task_scheduler/task.h" #include "base/task_scheduler/task_tracker.h" -#include "base/time/time.h" #include "build/build_config.h" #if defined(OS_POSIX) && !defined(OS_NACL_SFI) @@ -41,13 +40,14 @@ #endif } -void TaskSchedulerImpl::PostTaskWithTraits( +void TaskSchedulerImpl::PostDelayedTaskWithTraits( const tracked_objects::Location& from_here, const TaskTraits& traits, - const Closure& task) { + const Closure& task, + TimeDelta delay) { // Post |task| as part of a one-off single-task Sequence. GetWorkerPoolForTraits(traits)->PostTaskWithSequence( - MakeUnique<Task>(from_here, task, traits, TimeDelta()), + MakeUnique<Task>(from_here, task, traits, delay), make_scoped_refptr(new Sequence), nullptr); }
diff --git a/base/task_scheduler/task_scheduler_impl.h b/base/task_scheduler/task_scheduler_impl.h index 0e03d52..3e6cfdb 100644 --- a/base/task_scheduler/task_scheduler_impl.h +++ b/base/task_scheduler/task_scheduler_impl.h
@@ -50,9 +50,10 @@ ~TaskSchedulerImpl() override; // TaskScheduler: - void PostTaskWithTraits(const tracked_objects::Location& from_here, - const TaskTraits& traits, - const Closure& task) override; + void PostDelayedTaskWithTraits(const tracked_objects::Location& from_here, + const TaskTraits& traits, + const Closure& task, + TimeDelta delay) override; scoped_refptr<TaskRunner> CreateTaskRunnerWithTraits( const TaskTraits& traits) override; scoped_refptr<SequencedTaskRunner> CreateSequencedTaskRunnerWithTraits(
diff --git a/base/task_scheduler/task_scheduler_impl_unittest.cc b/base/task_scheduler/task_scheduler_impl_unittest.cc index 8e22b69..cda0606 100644 --- a/base/task_scheduler/task_scheduler_impl_unittest.cc +++ b/base/task_scheduler/task_scheduler_impl_unittest.cc
@@ -20,6 +20,7 @@ #include "base/task_scheduler/scheduler_worker_pool_params.h" #include "base/task_scheduler/task_traits.h" #include "base/task_scheduler/test_task_factory.h" +#include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" #include "base/threading/simple_thread.h" #include "base/threading/thread.h" @@ -53,7 +54,7 @@ // Verify that the current thread priority and I/O restrictions are appropriate // to run a Task with |traits|. // Note: ExecutionMode is verified inside TestTaskFactory. -void VerifyTaskEnvironement(const TaskTraits& traits) { +void VerifyTaskEnvironment(const TaskTraits& traits) { const bool supports_background_priority = Lock::HandlesMultipleThreadPriorities() && PlatformThread::CanIncreaseCurrentThreadPriority(); @@ -81,10 +82,19 @@ current_thread_name.find("Blocking") != std::string::npos); } -void VerifyTaskEnvironementAndSignalEvent(const TaskTraits& traits, - WaitableEvent* event) { +void VerifyTaskEnvironmentAndSignalEvent(const TaskTraits& traits, + WaitableEvent* event) { DCHECK(event); - VerifyTaskEnvironement(traits); + VerifyTaskEnvironment(traits); + event->Signal(); +} + +void VerifyTimeAndTaskEnvironmentAndSignalEvent(const TaskTraits& traits, + TimeTicks expected_time, + WaitableEvent* event) { + DCHECK(event); + EXPECT_LE(expected_time, TimeTicks::Now()); + VerifyTaskEnvironment(traits); event->Signal(); } @@ -127,7 +137,7 @@ const size_t kNumTasksPerThread = 150; for (size_t i = 0; i < kNumTasksPerThread; ++i) { factory_.PostTask(test::TestTaskFactory::PostNestedTask::NO, - Bind(&VerifyTaskEnvironement, traits_)); + Bind(&VerifyTaskEnvironment, traits_)); } } @@ -220,16 +230,33 @@ } // namespace -// Verifies that a Task posted via PostTaskWithTraits with parameterized -// TaskTraits runs on a thread with the expected priority and I/O restrictions. -// The ExecutionMode parameter is ignored by this test. -TEST_P(TaskSchedulerImplTest, PostTaskWithTraits) { +// Verifies that a Task posted via PostDelayedTaskWithTraits with parameterized +// TaskTraits and no delay runs on a thread with the expected priority and I/O +// restrictions. The ExecutionMode parameter is ignored by this test. +TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsNoDelay) { WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, WaitableEvent::InitialState::NOT_SIGNALED); - scheduler_->PostTaskWithTraits( + scheduler_->PostDelayedTaskWithTraits( FROM_HERE, GetParam().traits, - Bind(&VerifyTaskEnvironementAndSignalEvent, GetParam().traits, - Unretained(&task_ran))); + Bind(&VerifyTaskEnvironmentAndSignalEvent, GetParam().traits, + Unretained(&task_ran)), + TimeDelta()); + task_ran.Wait(); +} + +// Verifies that a Task posted via PostDelayedTaskWithTraits with parameterized +// TaskTraits and a non-zero delay runs on a thread with the expected priority +// and I/O restrictions after the delay expires. The ExecutionMode parameter is +// ignored by this test. +TEST_P(TaskSchedulerImplTest, PostDelayedTaskWithTraitsWithDelay) { + WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL, + WaitableEvent::InitialState::NOT_SIGNALED); + scheduler_->PostDelayedTaskWithTraits( + FROM_HERE, GetParam().traits, + Bind(&VerifyTimeAndTaskEnvironmentAndSignalEvent, GetParam().traits, + TimeTicks::Now() + TestTimeouts::tiny_timeout(), + Unretained(&task_ran)), + TestTimeouts::tiny_timeout()); task_ran.Wait(); } @@ -246,7 +273,7 @@ const size_t kNumTasksPerTest = 150; for (size_t i = 0; i < kNumTasksPerTest; ++i) { factory.PostTask(test::TestTaskFactory::PostNestedTask::NO, - Bind(&VerifyTaskEnvironement, GetParam().traits)); + Bind(&VerifyTaskEnvironment, GetParam().traits)); } factory.WaitForAllTasksToRun();
diff --git a/base/test/scoped_task_scheduler.cc b/base/test/scoped_task_scheduler.cc index 19ee891..7858fc4 100644 --- a/base/test/scoped_task_scheduler.cc +++ b/base/test/scoped_task_scheduler.cc
@@ -40,9 +40,10 @@ ~TestTaskScheduler() override; // TaskScheduler: - void PostTaskWithTraits(const tracked_objects::Location& from_here, - const TaskTraits& traits, - const Closure& task) override; + void PostDelayedTaskWithTraits(const tracked_objects::Location& from_here, + const TaskTraits& traits, + const Closure& task, + TimeDelta delay) override; scoped_refptr<TaskRunner> CreateTaskRunnerWithTraits( const TaskTraits& traits) override; scoped_refptr<SequencedTaskRunner> CreateSequencedTaskRunnerWithTraits( @@ -124,11 +125,12 @@ RunLoop().RunUntilIdle(); } -void TestTaskScheduler::PostTaskWithTraits( +void TestTaskScheduler::PostDelayedTaskWithTraits( const tracked_objects::Location& from_here, const TaskTraits& traits, - const Closure& task) { - CreateTaskRunnerWithTraits(traits)->PostTask(from_here, task); + const Closure& task, + TimeDelta delay) { + CreateTaskRunnerWithTraits(traits)->PostDelayedTask(from_here, task, delay); } scoped_refptr<TaskRunner> TestTaskScheduler::CreateTaskRunnerWithTraits(
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc index 9c980a2..a92e21b 100644 --- a/cc/layers/render_surface_impl.cc +++ b/cc/layers/render_surface_impl.cc
@@ -35,6 +35,7 @@ : owning_layer_(owning_layer), layer_tree_impl_(owning_layer->layer_tree_impl()), stable_effect_id_(owning_layer->id()), + effect_tree_index_(EffectTree::kInvalidNodeId), surface_property_changed_(false), ancestor_property_changed_(false), contributes_to_drawn_surface_(false), @@ -159,8 +160,10 @@ } int RenderSurfaceImpl::EffectTreeIndex() const { - return layer_tree_impl_->property_trees() - ->effect_id_to_index_map[stable_effect_id_]; + DCHECK_EQ(effect_tree_index_, + layer_tree_impl_->property_trees() + ->effect_id_to_index_map[stable_effect_id_]); + return effect_tree_index_; } const EffectNode* RenderSurfaceImpl::OwningEffectNode() const {
diff --git a/cc/layers/render_surface_impl.h b/cc/layers/render_surface_impl.h index 80c2c15..6f024da9 100644 --- a/cc/layers/render_surface_impl.h +++ b/cc/layers/render_surface_impl.h
@@ -151,6 +151,8 @@ int TransformTreeIndex() const; int ClipTreeIndex() const; + + void set_effect_tree_index(int index) { effect_tree_index_ = index; } int EffectTreeIndex() const; private: @@ -163,6 +165,7 @@ LayerTreeImpl* layer_tree_impl_; int stable_effect_id_; + int effect_tree_index_; // Container for properties that render surfaces need to compute before they // can be drawn.
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc index 44fc5bb..511108d 100644 --- a/cc/layers/render_surface_unittest.cc +++ b/cc/layers/render_surface_unittest.cc
@@ -39,16 +39,23 @@ FakeImplTaskRunnerProvider task_runner_provider; TestTaskGraphRunner task_graph_runner; + std::unique_ptr<CompositorFrameSink> compositor_frame_sink = + FakeCompositorFrameSink::Create3d(); FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner); std::unique_ptr<LayerImpl> owning_layer = LayerImpl::Create(host_impl.active_tree(), 1); - owning_layer->SetHasRenderSurface(true); - ASSERT_TRUE(owning_layer->render_surface()); - RenderSurfaceImpl* render_surface = owning_layer->render_surface(); + owning_layer->test_properties()->force_render_surface = true; gfx::Rect test_rect(3, 4, 5, 6); host_impl.active_tree()->ResetAllChangeTracking(); host_impl.active_tree()->SetRootLayerForTesting(std::move(owning_layer)); - host_impl.active_tree()->BuildPropertyTreesForTesting(); + host_impl.SetVisible(true); + host_impl.InitializeRenderer(compositor_frame_sink.get()); + host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + host_impl.active_tree()->UpdateDrawProperties(false /* update_lcd_text */); + + RenderSurfaceImpl* render_surface = + host_impl.active_tree()->root_layer_for_testing()->render_surface(); + ASSERT_TRUE(render_surface); // Currently, the content_rect, clip_rect, and // owning_layer->layerPropertyChanged() are the only sources of change. @@ -158,19 +165,28 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectRenderPass) { FakeImplTaskRunnerProvider task_runner_provider; TestTaskGraphRunner task_graph_runner; + std::unique_ptr<CompositorFrameSink> compositor_frame_sink = + FakeCompositorFrameSink::Create3d(); FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner); std::unique_ptr<LayerImpl> root_layer = LayerImpl::Create(host_impl.active_tree(), 1); + int owning_layer_id = 2; std::unique_ptr<LayerImpl> owning_layer = - LayerImpl::Create(host_impl.active_tree(), 2); - owning_layer->SetHasRenderSurface(true); - ASSERT_TRUE(owning_layer->render_surface()); - RenderSurfaceImpl* render_surface = owning_layer->render_surface(); + LayerImpl::Create(host_impl.active_tree(), owning_layer_id); + owning_layer->test_properties()->force_render_surface = true; root_layer->test_properties()->AddChild(std::move(owning_layer)); host_impl.active_tree()->SetRootLayerForTesting(std::move(root_layer)); + host_impl.SetVisible(true); + host_impl.InitializeRenderer(compositor_frame_sink.get()); host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + host_impl.active_tree()->UpdateDrawProperties(false /* update_lcd_text */); + + ASSERT_TRUE( + host_impl.active_tree()->LayerById(owning_layer_id)->render_surface()); + RenderSurfaceImpl* render_surface = + host_impl.active_tree()->LayerById(owning_layer_id)->render_surface(); gfx::Rect content_rect(0, 0, 50, 50); gfx::Transform origin;
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index 80f3b09..7a216f0 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc
@@ -1072,8 +1072,11 @@ can_render_to_separate_surface, layer); EffectNode* node = property_trees->effect_tree.Node(layer->effect_tree_index()); - if (node->owning_layer_id == layer->id()) + if (node->owning_layer_id == layer->id()) { node->render_surface = layer->render_surface(); + if (node->render_surface) + node->render_surface->set_effect_tree_index(node->id); + } #if DCHECK_IS_ON() if (can_render_to_separate_surface) ValidateRenderSurfaceForLayer(layer);
diff --git a/cc/trees/layer_tree_host_in_process.cc b/cc/trees/layer_tree_host_in_process.cc index aac493b0..1f0eab1 100644 --- a/cc/trees/layer_tree_host_in_process.cc +++ b/cc/trees/layer_tree_host_in_process.cc
@@ -600,8 +600,10 @@ } bool LayerTreeHostInProcess::UpdateLayers() { - if (!layer_tree_->root_layer()) + if (!layer_tree_->root_layer()) { + layer_tree_->property_trees()->clear(); return false; + } DCHECK(!layer_tree_->root_layer()->parent()); base::ElapsedTimer timer;
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 89a082df9..5e58148 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -5616,6 +5616,82 @@ // This test blocks activation which is not supported for single thread mode. MULTI_THREAD_BLOCKNOTIFY_TEST_F(LayerTreeHostTestActivateOnInvisible); +class LayerTreeHostTestRenderSurfaceEffectTreeIndex : public LayerTreeHostTest { + public: + LayerTreeHostTestRenderSurfaceEffectTreeIndex() = default; + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void SetupTree() override { + root_ = Layer::Create(); + child_ = Layer::Create(); + grand_child_ = Layer::Create(); + + layer_tree()->SetRootLayer(root_); + root_->AddChild(child_); + child_->AddChild(grand_child_); + + root_->SetBounds(gfx::Size(50, 50)); + child_->SetBounds(gfx::Size(50, 50)); + grand_child_->SetBounds(gfx::Size(50, 50)); + child_->SetForceRenderSurfaceForTesting(true); + grand_child_->SetForceRenderSurfaceForTesting(true); + + LayerTreeHostTest::SetupTree(); + } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + if (host_impl->sync_tree()->source_frame_number() >= 1) { + LayerImpl* grand_child_impl = + host_impl->sync_tree()->LayerById(grand_child_->id()); + EXPECT_EQ(grand_child_impl->effect_tree_index(), + grand_child_impl->render_surface()->EffectTreeIndex()); + } + } + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + LayerImpl* grand_child_impl = + host_impl->active_tree()->LayerById(grand_child_->id()); + switch (host_impl->active_tree()->source_frame_number()) { + case 0: + PostSetNeedsCommitToMainThread(); + break; + case 1: + case 2: + EXPECT_EQ(grand_child_impl->effect_tree_index(), + grand_child_impl->render_surface()->EffectTreeIndex()); + PostSetNeedsCommitToMainThread(); + break; + case 3: + EXPECT_EQ(grand_child_impl->effect_tree_index(), + grand_child_impl->render_surface()->EffectTreeIndex()); + EndTest(); + } + } + + void DidCommit() override { + switch (layer_tree_host()->SourceFrameNumber()) { + case 2: + // Setting an empty viewport causes draws to get skipped, so the active + // tree won't update draw properties. + layer_tree()->SetViewportSize(gfx::Size()); + child_->SetForceRenderSurfaceForTesting(false); + break; + case 3: + layer_tree()->SetViewportSize(root_->bounds()); + } + } + + void AfterTest() override {} + + private: + scoped_refptr<Layer> root_; + scoped_refptr<Layer> child_; + scoped_refptr<Layer> grand_child_; +}; + +SINGLE_MULTI_AND_REMOTE_TEST_F(LayerTreeHostTestRenderSurfaceEffectTreeIndex); + // Do a synchronous composite and assert that the swap promise succeeds. class LayerTreeHostTestSynchronousCompositeSwapPromise : public LayerTreeHostTest {
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 6045b46..9d4773d 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -379,7 +379,11 @@ } void LayerTreeImpl::SetPropertyTrees(PropertyTrees* property_trees) { + EffectTree::StableIdRenderSurfaceList stable_id_render_surface_list = + property_trees_.effect_tree.CreateStableIdRenderSurfaceList(); property_trees_ = *property_trees; + property_trees_.effect_tree.UpdateRenderSurfaceEffectIds( + stable_id_render_surface_list, this); property_trees->effect_tree.PushCopyRequestsTo(&property_trees_.effect_tree); property_trees_.is_main_thread = false; property_trees_.is_active = IsActiveTree();
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index dd449d0..1b0b595 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc
@@ -991,6 +991,79 @@ } } +EffectTree::StableIdRenderSurfaceList +EffectTree::CreateStableIdRenderSurfaceList() const { + StableIdRenderSurfaceList stable_id_render_surface_list; + for (int id = kContentsRootNodeId; id < static_cast<int>(size()); ++id) { + const EffectNode* node = Node(id); + if (node->render_surface) { + stable_id_render_surface_list.push_back( + std::make_pair(node->owning_layer_id, node->render_surface)); + } + } + std::sort(stable_id_render_surface_list.begin(), + stable_id_render_surface_list.end()); + return stable_id_render_surface_list; +} + +void EffectTree::UpdateRenderSurfaceEffectIds( + const EffectTree::StableIdRenderSurfaceList& stable_id_render_surface_list, + LayerTreeImpl* layer_tree_impl) { + // Make a list of {stable id, node id} pairs for nodes that are supposed to + // have surfaces. + std::vector<std::pair<int, int>> stable_id_node_id_list; + for (int id = kContentsRootNodeId; id < static_cast<int>(size()); ++id) { + const EffectNode* node = Node(id); + if (node->has_render_surface) { + stable_id_node_id_list.push_back( + std::make_pair(node->owning_layer_id, node->id)); + } + } + + // Sort by stable id so that we can process the two lists cosequentially. + std::sort(stable_id_node_id_list.begin(), stable_id_node_id_list.end()); + + auto surface_list_it = stable_id_render_surface_list.begin(); + auto node_id_list_it = stable_id_node_id_list.begin(); + while (surface_list_it != stable_id_render_surface_list.end() && + node_id_list_it != stable_id_node_id_list.end()) { + if (surface_list_it->first == node_id_list_it->first) { + RenderSurfaceImpl* surface = surface_list_it->second; + int node_id = node_id_list_it->second; + Node(node_id)->render_surface = surface; + surface->set_effect_tree_index(node_id); + surface_list_it++; + node_id_list_it++; + continue; + } + + if (surface_list_it->first > node_id_list_it->first) { + node_id_list_it++; + continue; + } + + // If we reach here, there's no longer an effect node with stable id + // |surface_list_it->first| that has a render surface. If there's no longer + // any corresponding layer either, there's nothing more to do since the + // surface owned by that layer would have been destroyed when the layer was + // destroyed. But if the layer still exists, we need to destroy the surface + // since it now has an invalid effect node id. + if (LayerImpl* layer_impl = + layer_tree_impl->LayerById(surface_list_it->first)) { + layer_impl->SetHasRenderSurface(false); + } + surface_list_it++; + } + + while (surface_list_it != stable_id_render_surface_list.end()) { + if (LayerImpl* layer_impl = + layer_tree_impl->LayerById(surface_list_it->first)) { + layer_impl->SetHasRenderSurface(false); + } + surface_list_it++; + } +} + void TransformTree::UpdateNodeAndAncestorsHaveIntegerTranslations( TransformNode* node, TransformNode* parent_node) { @@ -1520,6 +1593,7 @@ full_tree_damaged = false; changed = false; non_root_surfaces_enabled = true; + sequence_number++; #if DCHECK_IS_ON() PropertyTrees tree;
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h index 85a8d47..c56126a 100644 --- a/cc/trees/property_tree.h +++ b/cc/trees/property_tree.h
@@ -30,6 +30,7 @@ class CopyOutputRequest; class LayerTreeImpl; +class RenderSurfaceImpl; class ScrollState; struct ClipNode; struct EffectNode; @@ -331,6 +332,14 @@ void ResetChangeTracking(); + // A list of pairs of stable id and render surface, sorted by stable id. + using StableIdRenderSurfaceList = + std::vector<std::pair<int, RenderSurfaceImpl*>>; + StableIdRenderSurfaceList CreateStableIdRenderSurfaceList() const; + void UpdateRenderSurfaceEffectIds( + const StableIdRenderSurfaceList& stable_id_render_surface_list, + LayerTreeImpl* layer_tree_impl); + private: void UpdateOpacities(EffectNode* node, EffectNode* parent_node); void UpdateIsDrawn(EffectNode* node, EffectNode* parent_node);
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc index e4e6fc1..7017538 100644 --- a/cc/trees/property_tree_builder.cc +++ b/cc/trees/property_tree_builder.cc
@@ -1376,8 +1376,6 @@ return; } - property_trees->sequence_number++; - DataForRecursion<LayerType> data_for_recursion; data_for_recursion.property_trees = property_trees; data_for_recursion.transform_tree_parent = nullptr;
diff --git a/chrome/android/java/res/menu/custom_tabs_menu.xml b/chrome/android/java/res/menu/custom_tabs_menu.xml index bc7f5aef..2ae82d5 100644 --- a/chrome/android/java/res/menu/custom_tabs_menu.xml +++ b/chrome/android/java/res/menu/custom_tabs_menu.xml
@@ -11,6 +11,12 @@ <item android:id="@+id/forward_menu_id" android:title="@string/accessibility_menu_forward" android:icon="@drawable/btn_forward"/> + <item android:id="@+id/bookmark_this_page_id" + android:title="@string/accessibility_menu_bookmark" + android:icon="@drawable/btn_star"/> + <item android:id="@+id/offline_page_id" + android:title="@string/download_page" + android:icon="@drawable/ic_get_app_white_24dp"/> <item android:id="@+id/info_menu_id" android:title="@string/accessibility_menu_info" android:icon="@drawable/btn_info" /> @@ -30,6 +36,17 @@ </menu> </item> <!-- Title is intentionally left blank in xml and will be set in java. --> + <item android:id="@+id/find_in_page_id" + android:title="@string/menu_find_in_page" + android:orderInCategory="2" /> + <item android:id="@+id/add_to_homescreen_id" + android:title="@string/menu_add_to_homescreen" + android:orderInCategory="2" /> + <item android:id="@+id/request_desktop_site_id" + android:title="@string/menu_request_desktop_site" + android:checkable="true" + android:icon="?android:attr/listChoiceIndicatorMultiple" + android:orderInCategory="2" /> <item android:id="@+id/open_in_browser_id" android:title="" android:orderInCategory="2" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index cf426e8..bee5d351 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1302,9 +1302,9 @@ if (!tabToBookmark.isClosing() && tabToBookmark.isInitialized()) { // The BookmarkModel will be destroyed by BookmarkUtils#addOrEditBookmark() when // done. - BookmarkId newBookmarkId = - BookmarkUtils.addOrEditBookmark(bookmarkId, bookmarkModel, - tabToBookmark, getSnackbarManager(), ChromeActivity.this); + BookmarkId newBookmarkId = BookmarkUtils.addOrEditBookmark(bookmarkId, + bookmarkModel, tabToBookmark, getSnackbarManager(), ChromeActivity.this, + isCustomTab()); // If a new bookmark was created, try to save an offline page for it. if (newBookmarkId != null && newBookmarkId.getId() != bookmarkId) { OfflinePageUtils.saveBookmarkOffline(newBookmarkId, tabToBookmark);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java index 6d0529a..63345c8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
@@ -179,11 +179,7 @@ // Hide request desktop site on all chrome:// pages except for the NTP. Check request // desktop site if it's activated on this page. MenuItem requestItem = menu.findItem(R.id.request_desktop_site_id); - requestItem.setVisible(!isChromeScheme || currentTab.isNativePage()); - requestItem.setChecked(currentTab.getUseDesktopUserAgent()); - requestItem.setTitleCondensed(requestItem.isChecked() - ? mActivity.getString(R.string.menu_request_desktop_site_on) - : mActivity.getString(R.string.menu_request_desktop_site_off)); + updateRequestDesktopSiteMenuItem(requestItem, currentTab, isChromeScheme); // Only display reader mode settings menu option if the current page is in reader mode. menu.findItem(R.id.reader_mode_prefs_id) @@ -292,4 +288,21 @@ bookmarkMenuItem.setTitleCondensed(null); } } + + /** + * Updates the request desktop site item's visibility + * + * @param requstMenuItem {@link MenuItem} for request desktop site. + * @param currentTab Current tab being displayed. + * @param isChromeScheme whether the url being displayed starts with chrome:// or + * chrome-native://. + */ + protected void updateRequestDesktopSiteMenuItem( + MenuItem requstMenuItem, Tab currentTab, boolean isChromeScheme) { + requstMenuItem.setVisible(!isChromeScheme || currentTab.isNativePage()); + requstMenuItem.setChecked(currentTab.getUseDesktopUserAgent()); + requstMenuItem.setTitleCondensed(requstMenuItem.isChecked() + ? mActivity.getString(R.string.menu_request_desktop_site_on) + : mActivity.getString(R.string.menu_request_desktop_site_off)); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java index 9ab1e77..ddfdf26 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
@@ -13,6 +13,7 @@ import android.provider.Browser; import android.text.TextUtils; +import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; @@ -50,11 +51,12 @@ * @param tab The tab to add or edit a bookmark. * @param snackbarManager The SnackbarManager used to show the snackbar. * @param activity Current activity. + * @param fromCustomTab boolean indicates whether it is called by Custom Tab. * @return Bookmark ID of the bookmark. Could be <code>null</code> if bookmark didn't exist * and bookmark model failed to create it. */ public static BookmarkId addOrEditBookmark(long existingBookmarkId, BookmarkModel bookmarkModel, - Tab tab, SnackbarManager snackbarManager, Activity activity) { + Tab tab, SnackbarManager snackbarManager, Activity activity, boolean fromCustomTab) { if (existingBookmarkId != Tab.INVALID_BOOKMARK_ID) { BookmarkId bookmarkId = new BookmarkId(existingBookmarkId, BookmarkType.NORMAL); startEditActivity(activity, bookmarkId); @@ -89,8 +91,16 @@ SnackbarController snackbarController = createSnackbarControllerForEditButton(activity, bookmarkId); if (getLastUsedParent(activity) == null) { - snackbar = Snackbar.make(activity.getString(R.string.bookmark_page_saved), - snackbarController, Snackbar.TYPE_ACTION, Snackbar.UMA_BOOKMARK_ADDED); + if (fromCustomTab) { + String packageLabel = BuildInfo.getPackageLabel(activity); + snackbar = Snackbar.make( + activity.getString(R.string.menu_open_in_product, packageLabel), + snackbarController, Snackbar.TYPE_ACTION, Snackbar.UMA_BOOKMARK_ADDED); + } else { + snackbar = Snackbar.make( + activity.getString(R.string.bookmark_page_saved_default), + snackbarController, Snackbar.TYPE_ACTION, Snackbar.UMA_BOOKMARK_ADDED); + } } else { snackbar = Snackbar.make(folderName, snackbarController, Snackbar.TYPE_ACTION, Snackbar.UMA_BOOKMARK_ADDED)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 7c09524..a478767f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -47,6 +47,7 @@ import org.chromium.chrome.browser.WarmupManager; import org.chromium.chrome.browser.WebContentsFactory; import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason; import org.chromium.chrome.browser.compositor.layouts.LayoutManagerDocument; import org.chromium.chrome.browser.datausage.DataUseTabUIManager; import org.chromium.chrome.browser.document.ChromeLauncherActivity; @@ -841,6 +842,20 @@ || id == R.id.new_incognito_tab_menu_id || id == R.id.new_tab_menu_id || id == R.id.open_history_menu_id) { return true; + } else if (id == R.id.bookmark_this_page_id) { + addOrEditBookmark(getActivityTab()); + RecordUserAction.record("MobileMenuAddToBookmarks"); + return true; + } else if (id == R.id.find_in_page_id) { + mFindToolbarManager.showToolbar(); + if (getContextualSearchManager() != null) { + getContextualSearchManager().hideContextualSearch(StateChangeReason.UNKNOWN); + } + if (fromMenu) { + RecordUserAction.record("MobileMeanuFindInPage"); + } else { + RecordUserAction.record("MobileShortcutFindInPage"); + } } else if (id == R.id.open_in_browser_id) { openCurrentUrlInBrowser(false); RecordUserAction.record("CustomTabsMenuOpenInChrome");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java index a894354..e37baf34 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
@@ -16,6 +16,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate; import org.chromium.chrome.browser.firstrun.FirstRunStatus; import org.chromium.chrome.browser.share.ShareHelper; @@ -97,6 +98,9 @@ MenuItem iconRow = menu.findItem(R.id.icon_row_menu_id); MenuItem openInChromeItem = menu.findItem(R.id.open_in_browser_id); + MenuItem bookmarkItem = menu.findItem(R.id.bookmark_this_page_id); + MenuItem downloadItem = menu.findItem(R.id.offline_page_id); + MenuItem addToHomeScreenItem = menu.findItem(R.id.add_to_homescreen_id); if (mIsMediaViewer) { // Most of the menu items don't make sense when viewing media. iconRow.setVisible(false); @@ -108,10 +112,14 @@ openInChromeItem.setTitle( mActivity.getString(R.string.menu_open_in_product_default)); } + updateBookmarkMenuItem(bookmarkItem, currentTab); } if (!FirstRunStatus.getFirstRunFlowComplete()) { openInChromeItem.setVisible(false); + bookmarkItem.setVisible(false); + downloadItem.setVisible(false); + addToHomeScreenItem.setVisible(false); } // Add custom menu items. Make sure they are only added once. @@ -122,6 +130,14 @@ mItemToIndexMap.put(item, i); } } + + // Hide request desktop site on all chrome:// pages except for the NTP. Check request + // desktop site if it's activated on this page. + MenuItem requestItem = menu.findItem(R.id.request_desktop_site_id); + String url = currentTab.getUrl(); + boolean isChromeScheme = url.startsWith(UrlConstants.CHROME_SCHEME) + || url.startsWith(UrlConstants.CHROME_NATIVE_SCHEME); + updateRequestDesktopSiteMenuItem(requestItem, currentTab, isChromeScheme); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java index 206998b..401c1db 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java
@@ -9,7 +9,9 @@ import android.content.Context; import org.chromium.base.ApplicationStatus; +import org.chromium.base.BuildInfo; import org.chromium.chrome.R; +import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBridge; import org.chromium.chrome.browser.snackbar.Snackbar; import org.chromium.chrome.browser.snackbar.SnackbarManager; @@ -74,9 +76,17 @@ public void onDownloadSucceeded( DownloadInfo downloadInfo, int notificationId, long downloadId, boolean canBeResolved) { if (getSnackbarManager() == null) return; - Snackbar snackbar = Snackbar.make( - mContext.getString(R.string.download_succeeded_message, downloadInfo.getFileName()), - this, Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_DOWNLOAD_SUCCEEDED); + Snackbar snackbar; + if (getActivity() instanceof CustomTabActivity) { + String packageLabel = BuildInfo.getPackageLabel(getActivity()); + snackbar = Snackbar.make(mContext.getString(R.string.download_succeeded_message, + downloadInfo.getFileName(), packageLabel), + this, Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_DOWNLOAD_SUCCEEDED); + } else { + snackbar = Snackbar.make(mContext.getString(R.string.download_succeeded_message_default, + downloadInfo.getFileName()), + this, Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_DOWNLOAD_SUCCEEDED); + } // TODO(qinmin): Coalesce snackbars if multiple downloads finish at the same time. snackbar.setDuration(SNACKBAR_DURATION_IN_MILLISECONDS).setSingleLine(false); ActionDataInfo info = null; @@ -111,10 +121,17 @@ getSnackbarManager().showSnackbar(snackbar); } + private Activity getActivity() { + if (ApplicationStatus.hasVisibleActivities()) { + return ApplicationStatus.getLastTrackedFocusedActivity(); + } else { + return null; + } + } + public SnackbarManager getSnackbarManager() { - Activity activity = ApplicationStatus.getLastTrackedFocusedActivity(); - if (activity != null && ApplicationStatus.hasVisibleActivities() - && activity instanceof SnackbarManager.SnackbarManageable) { + Activity activity = getActivity(); + if (activity != null && activity instanceof SnackbarManager.SnackbarManageable) { return ((SnackbarManager.SnackbarManageable) activity).getSnackbarManager(); } return null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/NativeInitializationController.java b/chrome/android/java/src/org/chromium/chrome/browser/init/NativeInitializationController.java index fc021528..a4835818 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/NativeInitializationController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/NativeInitializationController.java
@@ -93,6 +93,8 @@ public void startBackgroundTasks(final boolean allocateChildConnection) { ThreadUtils.assertOnUiThread(); + // TODO(asvitkine): Consider moving this logic to a singleton, like + // ChromeBrowserInitializer. if (shouldFetchVariationsSeedBeforeFRE()) { Context context = ContextUtils.getApplicationContext(); Intent initialIntent = mActivityDelegate.getInitialIntent(); @@ -105,6 +107,10 @@ new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + // This check is needed because onReceive() can be called multiple + // times even after having unregistered below if two broadcasts + // arrive in rapid succession. + if (!mWaitingForVariationsFetch) return; mWaitingForVariationsFetch = false; manager.unregisterReceiver(this); signalNativeLibraryLoadedIfReady();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java index 667d258..8a91399 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java
@@ -19,6 +19,10 @@ public class AutofillContact extends PaymentOption { private final AutofillProfile mProfile; private final Context mContext; + private int mCompletionStatus; + private boolean mRequestName; + private boolean mRequestPhone; + private boolean mRequestEmail; @Nullable private String mPayerName; @Nullable private String mPayerPhone; @Nullable private String mPayerEmail; @@ -33,13 +37,20 @@ * @param email The email address. If name and phone are empty, this will be the * primary label. * @param completionStatus The completion status of this contact. + * @param requestName Whether the merchant requests a payer name. + * @param requestPhone Whether the merchant requests a payer phone number. + * @param requestEmail Whether the merchant requests a payer email address. */ public AutofillContact(Context context, AutofillProfile profile, @Nullable String name, @Nullable String phone, @Nullable String email, - @ContactEditor.CompletionStatus int completionStatus) { + @ContactEditor.CompletionStatus int completionStatus, boolean requestName, + boolean requestPhone, boolean requestEmail) { super(profile.getGUID(), null, null, null, null); mContext = context; mProfile = profile; + mRequestName = requestName; + mRequestPhone = requestPhone; + mRequestEmail = requestEmail; mIsEditable = true; setContactInfo(profile.getGUID(), name, phone, email); updateCompletionStatus(completionStatus); @@ -50,16 +61,17 @@ return mPayerName; } - /** @return Email address. Null if the merchant did not request it or data is incomplete. */ - @Nullable public String getPayerEmail() { - return mPayerEmail; - } - /** @return Phone number. Null if the merchant did not request it or data is incomplete. */ @Nullable public String getPayerPhone() { return mPayerPhone; } + /** @return Email address. Null if the merchant did not request it or data is incomplete. */ + @Nullable + public String getPayerEmail() { + return mPayerEmail; + } + /** @return The autofill profile where this contact data lives. */ public AutofillProfile getProfile() { return mProfile; @@ -87,6 +99,60 @@ updateCompletionStatus(ContactEditor.COMPLETE); } + /** + * Returns whether this contact is equal or a superset of the specified contact considering the + * information requested by the merchant. + * + * @param contact The contact to compare to. + * @return Whether this contact is equal to or a superset of the other. + */ + public boolean isEqualOrSupersetOf(AutofillContact contact) { + assert contact != null; + + // This contact is not equal to or a superset of the other if for a requested field: + // 1- This contact's field is null and the other's is not. + // 2- The field values are not equal. + if (mRequestName) { + if (mPayerName == null && contact.mPayerName != null) return false; + if (mPayerName != null && contact.mPayerName != null + && !mPayerName.equalsIgnoreCase(contact.mPayerName)) { + return false; + } + } + + if (mRequestPhone) { + if (mPayerPhone == null && contact.mPayerPhone != null) return false; + if (mPayerPhone != null && contact.mPayerPhone != null + && !TextUtils.equals(mPayerPhone, contact.mPayerPhone)) { + return false; + } + } + + if (mRequestEmail) { + if (mPayerEmail == null && contact.mPayerEmail != null) return false; + if (mPayerEmail != null && contact.mPayerEmail != null + && !mPayerEmail.equalsIgnoreCase(contact.mPayerEmail)) { + return false; + } + } + + return true; + } + + /** + * @return Returns the relevance score of this contact, based on the validity of the information + * requested by the merchant. + */ + public int getRelevanceScore() { + int score = 0; + + if (mRequestName && (mCompletionStatus & ContactEditor.INVALID_NAME) == 0) ++score; + if (mRequestPhone && (mCompletionStatus & ContactEditor.INVALID_PHONE_NUMBER) == 0) ++score; + if (mRequestEmail && (mCompletionStatus & ContactEditor.INVALID_EMAIL) == 0) ++score; + + return score; + } + private void setContactInfo(String guid, @Nullable String name, @Nullable String phone, @Nullable String email) { mPayerName = TextUtils.isEmpty(name) ? null : name; @@ -104,6 +170,7 @@ } private void updateCompletionStatus(int completionStatus) { + mCompletionStatus = completionStatus; mIsComplete = completionStatus == ContactEditor.COMPLETE; switch (completionStatus) { @@ -123,12 +190,11 @@ mEditMessage = mContext.getString(R.string.payments_phone_number_required); mEditTitle = mContext.getString(R.string.payments_add_phone_number); break; - case ContactEditor.INVALID_MULTIPLE_FIELDS: + default: + // Multiple invalid fields. mEditMessage = mContext.getString(R.string.payments_more_information_required); mEditTitle = mContext.getString(R.string.payments_add_more_information); break; - default: - assert false : "Invalid completion status code"; } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java index 8f9d16e..7950bf6f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.payments; -import android.support.annotation.IntDef; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import android.util.Patterns; @@ -17,8 +16,6 @@ import org.chromium.chrome.browser.payments.ui.EditorFieldModel.EditorFieldValidator; import org.chromium.chrome.browser.payments.ui.EditorModel; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.HashSet; import java.util.Set; @@ -28,19 +25,15 @@ * Contact information editor. */ public class ContactEditor extends EditorBase<AutofillContact> { - @IntDef({INVALID_NAME, INVALID_EMAIL, INVALID_PHONE_NUMBER, INVALID_MULTIPLE_FIELDS}) - @Retention(RetentionPolicy.SOURCE) public @interface CompletionStatus {} /** Can be sent to the merchant as-is without editing first. */ public static final int COMPLETE = 0; /** The contact name is missing. */ - public static final int INVALID_NAME = 1; + public static final int INVALID_NAME = 1 << 0; /** The contact email is invalid or missing. */ - public static final int INVALID_EMAIL = 2; + public static final int INVALID_EMAIL = 1 << 1; /** The contact phone number is invalid or missing. */ - public static final int INVALID_PHONE_NUMBER = 3; - /** Multiple fields are invalid or missing. */ - public static final int INVALID_MULTIPLE_FIELDS = 4; + public static final int INVALID_PHONE_NUMBER = 1 << 2; private final boolean mRequestPayerName; private final boolean mRequestPayerPhone; @@ -80,26 +73,18 @@ @CompletionStatus public int checkContactCompletionStatus( @Nullable String name, @Nullable String phone, @Nullable String email) { - int invalidFieldCount = 0; int completionStatus = COMPLETE; if (mRequestPayerName && TextUtils.isEmpty(name)) { - invalidFieldCount++; - completionStatus = INVALID_NAME; + completionStatus |= INVALID_NAME; } if (mRequestPayerPhone && !getPhoneValidator().isValid(phone)) { - invalidFieldCount++; - completionStatus = INVALID_PHONE_NUMBER; + completionStatus |= INVALID_PHONE_NUMBER; } if (mRequestPayerEmail && !getEmailValidator().isValid(email)) { - invalidFieldCount++; - completionStatus = INVALID_EMAIL; - } - - if (invalidFieldCount > 1) { - completionStatus = INVALID_MULTIPLE_FIELDS; + completionStatus |= INVALID_EMAIL; } return completionStatus; @@ -139,7 +124,8 @@ final AutofillContact contact = toEdit == null ? new AutofillContact(mContext, new AutofillProfile(), null, null, null, - INVALID_MULTIPLE_FIELDS) + INVALID_NAME | INVALID_PHONE_NUMBER | INVALID_EMAIL, mRequestPayerName, + mRequestPayerPhone, mRequestPayerEmail) : toEdit; final EditorFieldModel nameField = mRequestPayerName
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index 8f050bfe..f7c6cbcc4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -363,11 +363,12 @@ } if (requestShipping) { - createShippingSection(profiles); + createShippingSection(Collections.unmodifiableList(profiles)); } if (requestPayerName || requestPayerPhone || requestPayerEmail) { - createContactSection(profiles, requestPayerName, requestPayerPhone, requestPayerEmail); + createContactSection(Collections.unmodifiableList(profiles), requestPayerName, + requestPayerPhone, requestPayerEmail); } mUI = new PaymentRequestUI(mContext, this, requestShipping, @@ -391,11 +392,11 @@ requestPayerPhone, requestShipping, requestPayerName); } - private void createShippingSection(List<AutofillProfile> profiles) { + private void createShippingSection(List<AutofillProfile> unmodifiableProfiles) { List<AutofillAddress> addresses = new ArrayList<>(); - for (int i = 0; i < profiles.size(); i++) { - AutofillProfile profile = profiles.get(i); + for (int i = 0; i < unmodifiableProfiles.size(); i++) { + AutofillProfile profile = unmodifiableProfiles.get(i); mAddressEditor.addPhoneNumberIfValid(profile.getPhoneNumber()); // Only suggest addresses that have a street address. @@ -440,14 +441,16 @@ PaymentRequestUI.TYPE_SHIPPING_ADDRESSES, firstCompleteAddressIndex, addresses); } - private void createContactSection(List<AutofillProfile> profiles, boolean requestName, - boolean requestPhone, boolean requestEmail) { - Set<String> uniqueContactInfos = new HashSet<>(); - mContactEditor = new ContactEditor(requestName, requestPhone, requestEmail); + private void createContactSection(List<AutofillProfile> unmodifiableProfiles, + boolean requestName, boolean requestPhone, boolean requestEmail) { List<AutofillContact> contacts = new ArrayList<>(); + List<AutofillContact> uniqueContacts = new ArrayList<>(); + mContactEditor = new ContactEditor(requestName, requestPhone, requestEmail); - for (int i = 0; i < profiles.size(); i++) { - AutofillProfile profile = profiles.get(i); + // Add the profile's valid request values to the editor's autocomplete list and convert + // relevant profiles to AutofillContacts. + for (int i = 0; i < unmodifiableProfiles.size(); ++i) { + AutofillProfile profile = unmodifiableProfiles.get(i); String name = requestName && !TextUtils.isEmpty(profile.getFullName()) ? profile.getFullName() : null; @@ -457,44 +460,62 @@ String email = requestEmail && !TextUtils.isEmpty(profile.getEmailAddress()) ? profile.getEmailAddress() : null; + + // Add the values to the editor's autocomplete list. mContactEditor.addPayerNameIfValid(name); mContactEditor.addPhoneNumberIfValid(phone); mContactEditor.addEmailAddressIfValid(email); + // Only create a contact if the profile has relevant information for the merchant. if (name != null || phone != null || email != null) { - // Different profiles can have identical contact info. Do not add the same - // contact info to the list twice. - String uniqueContactInfo = name + phone + email; - if (!uniqueContactInfos.contains(uniqueContactInfo)) { - uniqueContactInfos.add(uniqueContactInfo); - - @ContactEditor.CompletionStatus - int completionStatus = - mContactEditor.checkContactCompletionStatus(name, phone, email); - contacts.add(new AutofillContact( - mContext, profile, name, phone, email, completionStatus)); - } + contacts.add(new AutofillContact(mContext, profile, name, phone, email, + mContactEditor.checkContactCompletionStatus(name, phone, email), + requestName, requestPhone, requestEmail)); } } - // Suggest complete contact infos first. - Collections.sort(contacts, COMPLETENESS_COMPARATOR); + // Order the contacts so the ones that have most of the required information are put first. + // The sort is stable, so contacts with the same relevance score are sorted by frecency. + Collections.sort(contacts, new Comparator<AutofillContact>() { + @Override + public int compare(AutofillContact a, AutofillContact b) { + return b.getRelevanceScore() - a.getRelevanceScore(); + } + }); - // Limit the number of suggestions. - contacts = contacts.subList(0, Math.min(contacts.size(), SUGGESTIONS_LIMIT)); + // This algorithm is quadratic, but since the number of contacts is generally very small + // ( < 10) a faster but more complicated algorithm would be overkill. + for (int i = 0; i < contacts.size(); i++) { + AutofillContact contact = contacts.get(i); + + // Different contacts can have identical info. Do not add the same contact info or a + // subset of it twice. It's important that the profiles be sorted by the quantity of + // required info they have. + boolean isNewSuggestion = true; + for (int j = 0; j < uniqueContacts.size(); ++j) { + if (uniqueContacts.get(j).isEqualOrSupersetOf(contact)) { + isNewSuggestion = false; + break; + } + } + if (isNewSuggestion) uniqueContacts.add(contact); + + // Limit the number of suggestions. + if (uniqueContacts.size() == SUGGESTIONS_LIMIT) break; + } // Log the number of suggested contact infos. mJourneyLogger.setNumberOfSuggestionsShown( - PaymentRequestJourneyLogger.SECTION_CONTACT_INFO, contacts.size()); + PaymentRequestJourneyLogger.SECTION_CONTACT_INFO, uniqueContacts.size()); // Automatically select the first address if it is complete. int firstCompleteContactIndex = SectionInformation.NO_SELECTION; - if (!contacts.isEmpty() && contacts.get(0).isComplete()) { + if (!uniqueContacts.isEmpty() && uniqueContacts.get(0).isComplete()) { firstCompleteContactIndex = 0; } mContactSection = new SectionInformation( - PaymentRequestUI.TYPE_CONTACT_DETAILS, firstCompleteContactIndex, contacts); + PaymentRequestUI.TYPE_CONTACT_DETAILS, firstCompleteContactIndex, uniqueContacts); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java index 95289b7..6309c07 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -1079,14 +1079,13 @@ view.setMovementMethod(LinkMovementMethod.getInstance()); ApiCompatibilityUtils.setTextAppearance(view, R.style.PaymentsUiSectionDescriptiveText); - LinearLayout.LayoutParams layoutParams = - new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - int marginSize = mContext.getResources().getDimensionPixelSize( + // Add paddings instead of margin to let getMeasuredHeight return correct value for section + // resize animation. + int paddingSize = mContext.getResources().getDimensionPixelSize( R.dimen.payments_section_large_spacing); - layoutParams.topMargin = marginSize; - ApiCompatibilityUtils.setMarginStart(layoutParams, marginSize); - ApiCompatibilityUtils.setMarginEnd(layoutParams, marginSize); - parent.addView(view, layoutParams); + ApiCompatibilityUtils.setPaddingRelative( + view, paddingSize, paddingSize, paddingSize, paddingSize); + parent.addView(view); } private Callback<SectionInformation> createUpdateSectionCallback(@DataType final int type) {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 42de120..6ddd444 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1675,7 +1675,10 @@ <message name="IDS_DOWNLOAD_STARTED" desc="Message to show when download has started [CHAR LIMIT=30]"> Downloading… </message> - <message name="IDS_DOWNLOAD_SUCCEEDED_MESSAGE" desc="Transient message shown when a file download has succeeded." meaning="Android"> + <message name="IDS_DOWNLOAD_SUCCEEDED_MESSAGE" desc="App-based transient message shown when a file download has succeeded." meaning="Android"> + <ph name="FILE_NAME">%1$s<ex>http://abc.com/test.pdf</ex></ph> downloaded in <ph name="PRODUCT_NAME">%2$s<ex>Chrome</ex></ph> + </message> + <message name="IDS_DOWNLOAD_SUCCEEDED_MESSAGE_DEFAULT" desc="Transient message shown when a file download has succeeded." meaning="Android"> <ph name="FILE_NAME">%1$s<ex>http://abc.com/test.pdf</ex></ph> downloaded </message> <message name="IDS_REMAINING_DURATION_DAYS" desc="Message to show remaining duration in multiple days"> @@ -2083,7 +2086,10 @@ <message name="IDS_BOOKMARKS_FOLDER_EMPTY" desc="Text explaining that the currently selected bookmarks folder is empty."> No bookmarks here </message> - <message name="IDS_BOOKMARK_PAGE_SAVED" desc="Message shown after user adds a new bookmark. [CHAR-LIMIT=32]"> + <message name="IDS_BOOKMARK_PAGE_SAVED" desc="App-based message shown after user adds a new bookmark. [CHAR-LIMIT=32]"> + Bookmarked in <ph name="PRODUCT_NAME">%1$s<ex>Chrome</ex></ph> + </message> + <message name="IDS_BOOKMARK_PAGE_SAVED_DEFAULT" desc="Default message shown after user adds a new bookmark. [CHAR-LIMIT=32]"> Bookmarked </message> <message name="IDS_BOOKMARK_PAGE_SAVED_FOLDER" desc="Message shown after user adds a new bookmark. Also specifies in which folder the bookmark was added. [CHAR-LIMIT=32]">
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index aeebea4..f26e4e7 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -1353,6 +1353,7 @@ "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java", + "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java", @@ -1531,6 +1532,7 @@ "junit/src/org/chromium/chrome/browser/omaha/ResponseParserTest.java", "junit/src/org/chromium/chrome/browser/omaha/VersionNumberTest.java", "junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java", + "junit/src/org/chromium/chrome/browser/payments/AutofillContactUnitTest.java", "junit/src/org/chromium/chrome/browser/payments/CurrencyStringFormatterUnitTest.java", "junit/src/org/chromium/chrome/browser/snackbar/SnackbarCollectionUnitTest.java", "junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 8916788..13020919 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -97,7 +97,7 @@ */ public class CustomTabActivityTest extends CustomTabActivityTestBase { private static final int MAX_MENU_CUSTOM_ITEMS = 5; - private static final int NUM_CHROME_MENU_ITEMS = 2; + private static final int NUM_CHROME_MENU_ITEMS = 5; private static final String TEST_PAGE = "/chrome/test/data/android/google.html"; private static final String TEST_PAGE_2 = "/chrome/test/data/android/test.html"; private static final String GEOLOCATION_PAGE = @@ -375,13 +375,16 @@ assertNotNull("App menu is not initialized: ", menu); assertEquals(expectedMenuSize, actualMenuSize); assertNotNull(menu.findItem(R.id.forward_menu_id)); + assertNotNull(menu.findItem(R.id.bookmark_this_page_id)); + assertNotNull(menu.findItem(R.id.offline_page_id)); assertNotNull(menu.findItem(R.id.info_menu_id)); assertNotNull(menu.findItem(R.id.reload_menu_id)); assertNotNull(menu.findItem(R.id.open_in_browser_id)); assertFalse(menu.findItem(R.id.share_row_menu_id).isVisible()); assertFalse(menu.findItem(R.id.share_row_menu_id).isEnabled()); - assertNull(menu.findItem(R.id.bookmark_this_page_id)); - assertNull(menu.findItem(R.id.find_in_page_id)); + assertNotNull(menu.findItem(R.id.find_in_page_id)); + assertNotNull(menu.findItem(R.id.add_to_homescreen_id)); + assertNotNull(menu.findItem(R.id.request_desktop_site_id)); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java index 40df7425..7dab341 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
@@ -34,6 +34,26 @@ "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", "jon.doe@google.com", "en-US")); + // Add the same profile but with a different address. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "", "Google", + "999 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + + // Add the same profile but without a phone number. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "" /* phone_number */, + "jon.doe@google.com", "en-US")); + + // Add the same profile but without an email. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "" /* emailAddress */, "en-US")); + + // Add the same profile but without a name. + helper.setProfile(new AutofillProfile("" /* name */, "https://example.com", true, "", + "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } @@ -208,6 +228,19 @@ } /** + * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown + * to the user. + */ + @MediumTest + @Feature({"Payments"}) + public void testSuggestionsDeduped() + throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(mReadyToPay); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + assertEquals(1, getNumberOfContactDetailSuggestions()); + } + + /** * Test that starting a payment request that requires the user's email address, phone number and * name results in the appropriate metric being logged in the * PaymentRequest.RequestedInformation histogram.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java new file mode 100644 index 0000000..13abdbf --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java
@@ -0,0 +1,132 @@ +// 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. + +package org.chromium.chrome.browser.payments; + +import android.support.test.filters.MediumTest; + +import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.autofill.AutofillTestHelper; +import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +/** + * A payment integration test for a merchant that requests email address and a phone number. + */ +public class PaymentRequestEmailAndPhoneTest extends PaymentRequestTestBase { + public PaymentRequestEmailAndPhoneTest() { + // This merchant request an email address and a phone number. + super("payment_request_email_and_phone_test.html"); + } + + @Override + public void onMainActivityStarted() + throws InterruptedException, ExecutionException, TimeoutException { + AutofillTestHelper helper = new AutofillTestHelper(); + // The user has a valid email address and phone number on disk. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + + // Add the same profile but with a different address. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "", "Google", + "999 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + + // Add the same profile but without a phone number. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "" /* phoneNumber */, + "jon.doe@google.com", "en-US")); + + // Add the same profile but without an email. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "" /* emailAddress */, "en-US")); + + // Add the same profile but without a name. + helper.setProfile(new AutofillProfile("" /* name */, "https://example.com", true, "", + "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + + installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + } + + /** Provide the existing valid email address and phone number to the merchant. */ + @MediumTest + @Feature({"Payments"}) + public void testPay() throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(mReadyToPay); + clickAndWait(R.id.button_primary, mDismissed); + expectResultContains(new String[] {"555-555-5555", "jon.doe@google.com"}); + } + + /** Attempt to add an invalid email address and phone number and cancel the transaction. */ + @MediumTest + @Feature({"Payments"}) + public void testAddInvalidEmailAndCancel() + throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(mReadyToPay); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + clickInContactInfoAndWait(R.id.payments_add_option_button, mReadyToEdit); + setTextInEditorAndWait(new String[] {"-1-", "jane.jones"}, mEditorTextUpdate); + clickInEditorAndWait(R.id.payments_edit_done_button, mEditorValidationError); + clickInEditorAndWait(R.id.payments_edit_cancel_button, mReadyToPay); + clickAndWait(R.id.close_button, mDismissed); + expectResultContains(new String[] {"Request cancelled"}); + } + + /** Add a new email address and phone number and provide that to the merchant. */ + @MediumTest + @Feature({"Payments"}) + public void testAddEmailAndPhoneAndPay() + throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(mReadyToPay); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + clickInContactInfoAndWait(R.id.payments_add_option_button, mReadyToEdit); + setTextInEditorAndWait( + new String[] {"555-555-5555", "jane.jones@google.com"}, mEditorTextUpdate); + clickInEditorAndWait(R.id.payments_edit_done_button, mReadyToPay); + clickAndWait(R.id.button_primary, mDismissed); + expectResultContains(new String[] {"555-555-5555", "jane.jones@google.com"}); + } + + /** + * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown + * to the user. + */ + @MediumTest + @Feature({"Payments"}) + public void testSuggestionsDeduped() + throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(mReadyToPay); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + assertEquals(1, getNumberOfContactDetailSuggestions()); + } + + /** + * Test that starting a payment request that requires only the user's email address results in + * the appropriate metric being logged in the PaymentRequest.RequestedInformation histogram. + */ + @MediumTest + @Feature({"Payments"}) + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { + // Start the Payment Request. + triggerUIAndWait(mReadyToPay); + + int appropriateEnumValue = PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL + | PaymentRequestMetrics.REQUESTED_INFORMATION_PHONE; + + // Make sure that only the appropriate enum value was logged. + for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { + assertEquals((i == (appropriateEnumValue) ? 1 : 0), + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.RequestedInformation", i)); + } + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java index 103feb371..282dcc8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java
@@ -33,6 +33,26 @@ "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", "jon.doe@google.com", "en-US")); + // Add the same profile but with a different address. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "", "Google", + "999 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + + // Add the same profile but without a phone number. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "" /* phone_number */, + "jon.doe@google.com", "en-US")); + + // Add the same profile but without an email. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "" /* emailAddress */, "en-US")); + + // Add the same profile but without a name. + helper.setProfile(new AutofillProfile("" /* name */, "https://example.com", true, "", + "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } @@ -76,6 +96,19 @@ } /** + * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown + * to the user. + */ + @MediumTest + @Feature({"Payments"}) + public void testSuggestionsDeduped() + throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(mReadyToPay); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + assertEquals(1, getNumberOfContactDetailSuggestions()); + } + + /** * Test that starting a payment request that requires only the user's email address results in * the appropriate metric being logged in the PaymentRequest.RequestedInformation histogram. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java index d6c235b0..ad53450 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java
@@ -21,36 +21,69 @@ */ public class PaymentRequestMultipleContactDetailsTest extends PaymentRequestTestBase { private static final AutofillProfile[] AUTOFILL_PROFILES = { - // Incomplete (no phone) profile. + // 0 - Incomplete (no phone) profile. new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, "Bart Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US", "", "bart@simpson.com", ""), - // Incomplete (no email) profile. + // 1 - Incomplete (no email) profile. new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, "Homer Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US", "555 123-4567", "", ""), - // Complete profile. + // 2 - Complete profile. new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, "Lisa Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US", "555 123-4567", "lisa@simpson.com", ""), - // Complete profile. + // 3 - Complete profile. new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, "Maggie Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US", "555 123-4567", "maggie@simpson.com", ""), - // Incomplete (no phone and email) profile. + // 4 - Incomplete (no phone and email) profile. new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, "Marge Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US", "", "", ""), - // Incomplete (no name) profile. + // 5 - Incomplete (no name) profile. new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, "", "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US", "555 123-4567", "marge@simpson.com", ""), + // These profiles are used to test the dedupe of subset suggestions. They are based on + // The Lisa Simpson profile. + + // 6 - Same as original, but with no name. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "" /* name */, "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "555 123-4567", "lisa@simpson.com", ""), + + // 7 - Same as original, but with no phone. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "Lisa Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "" /* phoneNumber */, "lisa@simpson.com", ""), + + // 8 - Same as original, but with no email. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "Lisa Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "555 123-4567", "" /* emailAddress */, ""), + + // 9 - Same as original, but with no phone and no email. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "Lisa Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "" /* phoneNumber */, "" /* emailAddress */, ""), + + // 10 - Has an email address that is a superset of the original profile's email. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "Lisa Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "555 123-4567", "fakelisa@simpson.com", ""), + + // 11 - Has the same name as the original but with no capitalization in the name. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "lisa simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "555 123-4567", "lisa@simpson.com", ""), + }; private AutofillProfile[] mProfilesToAdd; @@ -131,9 +164,80 @@ getContactDetailsSuggestionLabel(0)); assertEquals( "Homer Simpson\n555 123-4567\nEmail required", getContactDetailsSuggestionLabel(1)); - assertEquals( - "Marge Simpson\nMore information required", getContactDetailsSuggestionLabel(2)); assertEquals("555 123-4567\nmarge@simpson.com\nName required", - getContactDetailsSuggestionLabel(3)); + getContactDetailsSuggestionLabel(2)); + assertEquals( + "Marge Simpson\nMore information required", getContactDetailsSuggestionLabel(3)); + } + + /** + * Makes sure that suggestions that are subsets of other fields (empty values) are deduped. + */ + @MediumTest + @Feature({"Payments"}) + public void testContactDetailsDedupe_EmptyFields() + throws InterruptedException, ExecutionException, TimeoutException { + // Add the original profile and a bunch of similar profiles with missing fields. + // Make sure the original profile is suggested last, to test that the suggestions are + // sorted by completeness. + mProfilesToAdd = new AutofillProfile[] { + AUTOFILL_PROFILES[2], AUTOFILL_PROFILES[6], AUTOFILL_PROFILES[7], + AUTOFILL_PROFILES[8], AUTOFILL_PROFILES[9], + }; + mCountsToSet = new int[] {1, 20, 15, 10, 5}; + mDatesToSet = new int[] {1000, 4000, 3000, 2000, 1000}; + + triggerUIAndWait(mReadyForInput); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + + // Only the original profile with all the fields should be suggested. + assertEquals(1, getNumberOfContactDetailSuggestions()); + assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", + getContactDetailsSuggestionLabel(0)); + } + + /** + * Makes sure that suggestions where some fields values are equal but with different case are + * deduped. + */ + @MediumTest + @Feature({"Payments"}) + public void testContactDetailsDedupe_Capitalization() + throws InterruptedException, ExecutionException, TimeoutException { + // Add the original profile and the one where the the name is not capitalized. + // Make sure the original profile is suggested first (no particular reason). + mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[2], AUTOFILL_PROFILES[11]}; + mCountsToSet = new int[] {15, 5}; + mDatesToSet = new int[] {5000, 2000}; + + triggerUIAndWait(mReadyForInput); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + assertEquals(1, getNumberOfContactDetailSuggestions()); + assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", + getContactDetailsSuggestionLabel(0)); + } + + /** + * Makes sure that suggestions where some fields values are subsets of the other are not + * deduped. + */ + @MediumTest + @Feature({"Payments"}) + public void testContactDetailsDontDedupe_FieldSubset() + throws InterruptedException, ExecutionException, TimeoutException { + // Add the original profile and the one where the email is a superset of the original. + // Make sure the one with the superset is suggested first, because to test the subset one + // needs to be added after. + mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[2], AUTOFILL_PROFILES[10]}; + mCountsToSet = new int[] {15, 25}; + mDatesToSet = new int[] {5000, 7000}; + + triggerUIAndWait(mReadyForInput); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + assertEquals(2, getNumberOfContactDetailSuggestions()); + assertEquals("Lisa Simpson\n555 123-4567\nfakelisa@simpson.com", + getContactDetailsSuggestionLabel(0)); + assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", + getContactDetailsSuggestionLabel(1)); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java index 594ba10..cc92694 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
@@ -37,6 +37,26 @@ helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe", "4111111111111111", "1111", "12", "2050", "visa", R.drawable.pr_visa, billingAddressId, "" /* serverId */)); + + // Add the same profile but with a different address. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "", "Google", + "999 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + + // Add the same profile but without a phone number. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "" /* phone_number */, + "jon.doe@google.com", "en-US")); + + // Add the same profile but without an email. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "" /* emailAddress */, "en-US")); + + // Add the same profile but without a name. + helper.setProfile(new AutofillProfile("" /* name */, "https://example.com", true, "", + "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); } /** Provide the existing valid payer name to the merchant. */ @@ -82,6 +102,19 @@ } /** + * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown + * to the user. + */ + @MediumTest + @Feature({"Payments"}) + public void testSuggestionsDeduped() + throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(mReadyToPay); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + assertEquals(1, getNumberOfContactDetailSuggestions()); + } + + /** * Test that starting a payment request that requires only the user's payer name results in * the appropriate metric being logged in the PaymentRequest.RequestedInformation histogram. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java index 6d1c9e4..94a8650 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java
@@ -33,6 +33,26 @@ "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", "jon.doe@google.com", "en-US")); + // Add the same profile but with a different address. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "", "Google", + "999 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + + // Add the same profile but without a phone number. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "" /* phone_number */, + "jon.doe@google.com", "en-US")); + + // Add the same profile but without an email. + helper.setProfile(new AutofillProfile("", "https://example.com", true, "Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "" /* emailAddress */, "en-US")); + + // Add the same profile but without a name. + helper.setProfile(new AutofillProfile("" /* name */, "https://example.com", true, "", + "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", + "jon.doe@google.com", "en-US")); + installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } @@ -76,6 +96,19 @@ } /** + * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown + * to the user. + */ + @MediumTest + @Feature({"Payments"}) + public void testSuggestionsDeduped() + throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(mReadyToPay); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + assertEquals(1, getNumberOfContactDetailSuggestions()); + } + + /** * Test that starting a payment request that requires only the user's phone number results in * the appropriate metric being logged in the PaymentRequest.RequestedInformation histogram. */
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java index 55039d5c..4060b95 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java
@@ -24,7 +24,7 @@ import java.util.Collection; /** - * Unit tests for the AutofillContact class. + * Parametrized unit tests for the AutofillContact class. */ @RunWith(ParameterizedRobolectricTestRunner.class) @Config(sdk = 21, manifest = Config.NONE) @@ -107,8 +107,9 @@ public void test() { AutofillProfile profile = new AutofillProfile(); AutofillContact contact = new AutofillContact(mContext, profile, mPayerName, mPayerPhone, - mPayerEmail, - mIsComplete ? ContactEditor.COMPLETE : ContactEditor.INVALID_MULTIPLE_FIELDS); + mPayerEmail, mIsComplete ? ContactEditor.COMPLETE + : ContactEditor.INVALID_NAME | ContactEditor.INVALID_EMAIL, + true, true, true); Assert.assertEquals( mIsComplete ? "Contact should be complete" : "Contact should be incomplete",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactUnitTest.java new file mode 100644 index 0000000..4ba84d81 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactUnitTest.java
@@ -0,0 +1,194 @@ +// 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. + +package org.chromium.chrome.browser.payments; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.testing.local.LocalRobolectricTestRunner; + +/** + * Unit tests for the AutofillContact class. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class AutofillContactUnitTest { + private static final String MESSAGE = "message"; + private static final String NAME = "Jon Doe"; + private static final String PHONE = "555-555-555"; + private static final String EMAIL = "jon@doe.com"; + + @Test + public void testIsEqualOrSupersetOf_RequestAllFields() { + AutofillProfile dummyProfile = new AutofillProfile(); + Context mockContext = spy(RuntimeEnvironment.application); + doReturn(MESSAGE).when(mockContext).getString(anyInt()); + + AutofillContact contact1 = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, + EMAIL, ContactEditor.COMPLETE, true /* requestName */, true /* requestPhone */, + true /* requestEmail */); + AutofillContact contact2 = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, + EMAIL, ContactEditor.COMPLETE, true /* requestName */, true /* requestPhone */, + true /* requestEmail */); + + // The return value should be true for identical profiles. + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + + // The return value should be true if the second profile is missing fields. + contact2.completeContact("", "", PHONE, EMAIL); + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + contact2.completeContact("", NAME, "", EMAIL); + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + contact2.completeContact("", NAME, PHONE, ""); + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + contact2.completeContact("", NAME, "", ""); + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + contact2.completeContact("", "", PHONE, ""); + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + contact2.completeContact("", "", "", EMAIL); + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + contact2.completeContact("", "", "", ""); + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + + // The return value should be false if one field is different. + contact2.completeContact("", "diff", PHONE, EMAIL); + Assert.assertFalse(contact1.isEqualOrSupersetOf(contact2)); + contact2.completeContact("", NAME, "diff", EMAIL); + Assert.assertFalse(contact1.isEqualOrSupersetOf(contact2)); + contact2.completeContact("", NAME, PHONE, "diff"); + Assert.assertFalse(contact1.isEqualOrSupersetOf(contact2)); + } + + @Test + public void testIsEqualOrSupersetOf_RequestSomeFields() { + AutofillProfile dummyProfile = new AutofillProfile(); + Context mockContext = spy(RuntimeEnvironment.application); + doReturn(MESSAGE).when(mockContext).getString(anyInt()); + + // The merchant does not request a name. + AutofillContact contact1 = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, + EMAIL, ContactEditor.COMPLETE, false /* requestName */, true /* requestPhone */, + true /* requestEmail */); + AutofillContact contact2 = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, + EMAIL, ContactEditor.COMPLETE, false /* requestName */, true /* requestPhone */, + true /* requestEmail */); + + // The return value should be true for identical profiles. + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + + // The return value should be true even if the name is missing. + contact2.completeContact("", "", PHONE, EMAIL); + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + + // The return value should be true even if the name is different. + contact2.completeContact("", "diff", PHONE, EMAIL); + Assert.assertTrue(contact1.isEqualOrSupersetOf(contact2)); + } + + @Test + public void testGetRelevanceScore_RequestAllFields() { + AutofillProfile dummyProfile = new AutofillProfile(); + Context mockContext = spy(RuntimeEnvironment.application); + doReturn(MESSAGE).when(mockContext).getString(anyInt()); + + // The merchant requests all fields. + // Since all requested fields are present and valid, The score should be 3. + AutofillContact contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.COMPLETE, true /* requestName */, true /* requestPhone */, + true /* requestEmail */); + Assert.assertEquals(3, contact.getRelevanceScore()); + + // The name is not valid, the score should be 2. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_NAME, true /* requestName */, true /* requestPhone */, + true /* requestEmail */); + Assert.assertEquals(2, contact.getRelevanceScore()); + + // The phone is not valid, the score should be 2. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_PHONE_NUMBER, true /* requestName */, true /* requestPhone */, + true /* requestEmail */); + Assert.assertEquals(2, contact.getRelevanceScore()); + + // The email is not valid, the score should be 2. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_EMAIL, true /* requestName */, true /* requestPhone */, + true /* requestEmail */); + Assert.assertEquals(2, contact.getRelevanceScore()); + + // The name and phone are not valid, the score should be 1. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_NAME | ContactEditor.INVALID_PHONE_NUMBER, + true /* requestName */, true /* requestPhone */, true /* requestEmail */); + Assert.assertEquals(1, contact.getRelevanceScore()); + + // The name and email are not valid, the score should be 1. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_NAME | ContactEditor.INVALID_EMAIL, true /* requestName */, + true /* requestPhone */, true /* requestEmail */); + Assert.assertEquals(1, contact.getRelevanceScore()); + + // The phone and email are not valid, the score should be 1. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_PHONE_NUMBER | ContactEditor.INVALID_EMAIL, + true /* requestName */, true /* requestPhone */, true /* requestEmail */); + Assert.assertEquals(1, contact.getRelevanceScore()); + + // The name, phone and email are not valid, the score should be 0. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_NAME | ContactEditor.INVALID_PHONE_NUMBER + | ContactEditor.INVALID_EMAIL, + true /* requestName */, true /* requestPhone */, true /* requestEmail */); + Assert.assertEquals(0, contact.getRelevanceScore()); + } + + @Test + public void testGetRelevanceScore_RequestSomeFields() { + AutofillProfile dummyProfile = new AutofillProfile(); + Context mockContext = spy(RuntimeEnvironment.application); + doReturn(MESSAGE).when(mockContext).getString(anyInt()); + + // The merchant does not request a name. + // Since all requested fields are present and valid, The score should be 2. + AutofillContact contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.COMPLETE, false /* requestName */, true /* requestPhone */, + true /* requestEmail */); + Assert.assertEquals(2, contact.getRelevanceScore()); + + // The name is not valid, the score should still be 2. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_NAME, false /* requestName */, true /* requestPhone */, + true /* requestEmail */); + Assert.assertEquals(2, contact.getRelevanceScore()); + + // The phone is not valid, the score should be 1. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_PHONE_NUMBER, false /* requestName */, + true /* requestPhone */, true /* requestEmail */); + Assert.assertEquals(1, contact.getRelevanceScore()); + + // The email is not valid, the score should be 1. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_EMAIL, false /* requestName */, true /* requestPhone */, + true /* requestEmail */); + Assert.assertEquals(1, contact.getRelevanceScore()); + + // The phone and email are not valid, the score should be 0. + contact = new AutofillContact(mockContext, dummyProfile, NAME, PHONE, EMAIL, + ContactEditor.INVALID_PHONE_NUMBER | ContactEditor.INVALID_EMAIL, + false /* requestName */, true /* requestPhone */, true /* requestEmail */); + Assert.assertEquals(0, contact.getRelevanceScore()); + } +} \ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 18d26a1..71f3705 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -14132,6 +14132,32 @@ This tab is connected to a USB device. </message> + <!-- Tab accessibility labels --> + <message name="IDS_TAB_AX_LABEL_MEDIA_RECORDING_FORMAT" desc="Accessibility label text, when the tab is recording media. Example: 'Google Hangouts - Camera or microphone recording'"> + <ph name="WINDOW_TITLE">$1<ex>Google Hangouts</ex></ph> - Camera or microphone recording + </message> + <message name="IDS_TAB_AX_LABEL_TAB_CAPTURING_FORMAT" desc="Accessibility label text, when the tab content is being captured and shared using screen sharing. Example: 'Google Hangouts - Tab content shared'"> + <ph name="WINDOW_TITLE">$1<ex>Google Hangouts</ex></ph> - Tab content shared + </message> + <message name="IDS_TAB_AX_LABEL_AUDIO_PLAYING_FORMAT" desc="Accessibility label text, when the tab is playing audio. Example: 'Google Play Music - Audio playing'"> + <ph name="WINDOW_TITLE">$1<ex>Google Play Music</ex></ph> - Audio playing + </message> + <message name="IDS_TAB_AX_LABEL_AUDIO_MUTING_FORMAT" desc="Accessibility label text, when all tab audio output is muted. Example: 'Google Play Music - Audio muted'"> + <ph name="WINDOW_TITLE">$1<ex>Google Play Music</ex></ph> - Audio muted + </message> + <message name="IDS_TAB_AX_LABEL_BLUETOOTH_CONNECTED_FORMAT" desc="Accessibility label text, when a tab is connected to and has access to a Bluetooth device. Example: 'Google Photos - Bluetooth device connected'"> + <ph name="WINDOW_TITLE">$1<ex>Google Photos</ex></ph> - Bluetooth device connected + </message> + <message name="IDS_TAB_AX_LABEL_USB_CONNECTED_FORMAT" desc="Accessibility label text, when a tab is connected to a USB device. Example: 'Google Photos - USB device connected'"> + <ph name="WINDOW_TITLE">$1<ex>Google Photos</ex></ph> - USB device connected + </message> + <message name="IDS_TAB_AX_LABEL_NETWORK_ERROR_FORMAT" desc="Accessibility label text, when tab has encountered a network error such as being disconnected from the internet. Example: 'www.google.com - Network error'"> + <ph name="WINDOW_TITLE">$1<ex>www.google.com</ex></ph> - Network error + </message> + <message name="IDS_TAB_AX_LABEL_CRASHED_FORMAT" desc="Accessibility label text, when a tab has crashed. Example: 'Google Search - Crashed'"> + <ph name="WINDOW_TITLE">$1<ex>Google Search</ex></ph> - Crashed + </message> + <!-- ProcessSingleton --> <message name="IDS_PROFILE_IN_USE_LINUX_QUIT" desc="Text of button in profile in use dialog to quit without doing anything."> Quit
diff --git a/chrome/browser/chromeos/extensions/wallpaper_manager_util.cc b/chrome/browser/chromeos/extensions/wallpaper_manager_util.cc index d21ef00b..13729cf 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_manager_util.cc +++ b/chrome/browser/chromeos/extensions/wallpaper_manager_util.cc
@@ -28,10 +28,6 @@ namespace { -const char kAndroidWallpapersAppPackage[] = "com.google.android.apps.wallpaper"; -const char kAndroidWallpapersAppActivity[] = - "com.google.android.apps.wallpaper.picker.CategoryPickerActivity"; - const char kAndroidWallpapersAppTrialName[] = "AndroidWallpapersAppOnChromeOS"; const char kEnableAndroidWallpapersApp[] = "Enable-android-wallpapers-app_Dogfood"; @@ -54,7 +50,8 @@ // Check if Android Wallpapers App has been installed. const ArcAppListPrefs* const prefs = ArcAppListPrefs::Get(profile); - if (!prefs || prefs->GetAppsForPackage(kAndroidWallpapersAppPackage).empty()) + if (!prefs || + prefs->GetAppsForPackage(arc::kAndroidWallpapersAppPackage).empty()) return false; // Check if the finch experiment or the chrome flag is enabled. @@ -74,7 +71,7 @@ if (ShouldUseAndroidWallpapersApp(profile)) { const std::string app_id = ArcAppListPrefs::GetAppId( - kAndroidWallpapersAppPackage, kAndroidWallpapersAppActivity); + arc::kAndroidWallpapersAppPackage, arc::kAndroidWallpapersAppActivity); arc::LaunchApp(profile, app_id, ui::EF_NONE); } else { ExtensionService* service =
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc index 0b031e8..7aa154e2 100644 --- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
@@ -47,7 +47,8 @@ AutoEnrollmentCheckScreen::AutoEnrollmentCheckScreen( BaseScreenDelegate* base_screen_delegate, AutoEnrollmentCheckScreenActor* actor) - : BaseScreen(base_screen_delegate), + : BaseScreen(base_screen_delegate, + WizardController::kAutoEnrollmentCheckScreenName), actor_(actor), auto_enrollment_controller_(nullptr), captive_portal_status_( @@ -120,10 +121,6 @@ void AutoEnrollmentCheckScreen::Hide() { } -std::string AutoEnrollmentCheckScreen::GetName() const { - return WizardController::kAutoEnrollmentCheckScreenName; -} - void AutoEnrollmentCheckScreen::OnActorDestroyed( AutoEnrollmentCheckScreenActor* actor) { if (actor_ == actor)
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h index ce4241da..b9ac5f1 100644 --- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h
@@ -50,7 +50,6 @@ // BaseScreen implementation: void Show() override; void Hide() override; - std::string GetName() const override; // AutoEnrollmentCheckScreenActor::Delegate implementation: void OnActorDestroyed(AutoEnrollmentCheckScreenActor* actor) override;
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc index 9e6cee7..e582634 100644 --- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc +++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
@@ -64,7 +64,7 @@ EnrollmentScreen::EnrollmentScreen(BaseScreenDelegate* base_screen_delegate, EnrollmentScreenActor* actor) - : BaseScreen(base_screen_delegate), + : BaseScreen(base_screen_delegate, WizardController::kEnrollmentScreenName), actor_(actor), weak_ptr_factory_(this) {} @@ -166,10 +166,6 @@ weak_ptr_factory_.InvalidateWeakPtrs(); } -std::string EnrollmentScreen::GetName() const { - return WizardController::kEnrollmentScreenName; -} - void EnrollmentScreen::AuthenticateUsingAttestation() { VLOG(1) << "Authenticating using attestation."; elapsed_timer_.reset(new base::ElapsedTimer());
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h index d7b7bd6e..6ccefec9 100644 --- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h +++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
@@ -56,7 +56,6 @@ // BaseScreen implementation: void Show() override; void Hide() override; - std::string GetName() const override; // EnrollmentScreenActor::Controller implementation: void OnLoginDone(const std::string& user,
diff --git a/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.cc b/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.cc index 1da3072..6c6dc8ae 100644 --- a/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.cc +++ b/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.cc
@@ -17,7 +17,9 @@ ArcTermsOfServiceScreen::ArcTermsOfServiceScreen( BaseScreenDelegate* base_screen_delegate, ArcTermsOfServiceScreenActor* actor) - : BaseScreen(base_screen_delegate), actor_(actor) { + : BaseScreen(base_screen_delegate, + WizardController::kArcTermsOfServiceScreenName), + actor_(actor) { DCHECK(actor_); if (actor_) actor_->SetDelegate(this); @@ -41,10 +43,6 @@ actor_->Hide(); } -std::string ArcTermsOfServiceScreen::GetName() const { - return WizardController::kArcTermsOfServiceScreenName; -} - void ArcTermsOfServiceScreen::OnSkip() { ApplyTerms(false); }
diff --git a/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h b/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h index b046ea8..f2a9d92 100644 --- a/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h +++ b/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h
@@ -25,7 +25,6 @@ // BaseScreen: void Show() override; void Hide() override; - std::string GetName() const override; // ArcTermsOfServiceScreenActor::Delegate: void OnSkip() override;
diff --git a/chrome/browser/chromeos/login/screens/base_screen.cc b/chrome/browser/chromeos/login/screens/base_screen.cc index 55397f17..8df5379 100644 --- a/chrome/browser/chromeos/login/screens/base_screen.cc +++ b/chrome/browser/chromeos/login/screens/base_screen.cc
@@ -67,9 +67,9 @@ return *this; } -BaseScreen::BaseScreen(BaseScreenDelegate* base_screen_delegate) - : channel_(nullptr), base_screen_delegate_(base_screen_delegate) { -} +BaseScreen::BaseScreen(BaseScreenDelegate* base_screen_delegate, + const std::string& screen_id) + : base_screen_delegate_(base_screen_delegate), screen_id_(screen_id) {} BaseScreen::~BaseScreen() { } @@ -92,17 +92,11 @@ return true; } -std::string BaseScreen::GetID() const { - // TODO (ygorshenin, crbug.com/433797): elimitate intermediate - // GetName() ASAP. - return GetName(); -} - void BaseScreen::CommitContextChanges() { if (!context_.HasChanges()) return; if (!channel_) { - LOG(ERROR) << "Model-view channel for " << GetID() + LOG(ERROR) << "Model-view channel for " << screen_id() << " is not ready, context changes are not sent to the view."; return; }
diff --git a/chrome/browser/chromeos/login/screens/base_screen.h b/chrome/browser/chromeos/login/screens/base_screen.h index c5d0b95..ca76b0d 100644 --- a/chrome/browser/chromeos/login/screens/base_screen.h +++ b/chrome/browser/chromeos/login/screens/base_screen.h
@@ -28,7 +28,8 @@ // method called just once. class BaseScreen { public: - explicit BaseScreen(BaseScreenDelegate* base_screen_delegate); + explicit BaseScreen(BaseScreenDelegate* base_screen_delegate, + const std::string& screen_id); virtual ~BaseScreen(); // ---- Old implementation ---- @@ -39,9 +40,6 @@ // Makes wizard screen invisible. virtual void Hide() = 0; - // Returns the screen name. - virtual std::string GetName() const = 0; - // ---- New Implementation ---- // Called to perform initialization of the screen. UI is guaranteed to exist @@ -65,7 +63,7 @@ virtual bool IsStatusAreaDisplayed(); // Returns the identifier of the screen. - virtual std::string GetID() const; + const std::string& screen_id() const { return screen_id_; } // Called when user action event with |event_id| // happened. Notification about this event comes from the JS @@ -149,9 +147,11 @@ // counterpart. void OnContextChanged(const base::DictionaryValue& diff); - ModelViewChannel* channel_; + ModelViewChannel* channel_ = nullptr; - BaseScreenDelegate* base_screen_delegate_; + BaseScreenDelegate* base_screen_delegate_ = nullptr; + + const std::string screen_id_; DISALLOW_COPY_AND_ASSIGN(BaseScreen); };
diff --git a/chrome/browser/chromeos/login/screens/controller_pairing_screen.cc b/chrome/browser/chromeos/login/screens/controller_pairing_screen.cc index 51e7105..9bd70f03 100644 --- a/chrome/browser/chromeos/login/screens/controller_pairing_screen.cc +++ b/chrome/browser/chromeos/login/screens/controller_pairing_screen.cc
@@ -20,7 +20,8 @@ Delegate* delegate, ControllerPairingScreenActor* actor, ControllerPairingController* shark_controller) - : BaseScreen(base_screen_delegate), + : BaseScreen(base_screen_delegate, + WizardController::kControllerPairingScreenName), delegate_(delegate), actor_(actor), shark_controller_(shark_controller), @@ -64,10 +65,6 @@ actor_->Hide(); } -std::string ControllerPairingScreen::GetName() const { - return WizardController::kControllerPairingScreenName; -} - void ControllerPairingScreen::PairingStageChanged(Stage new_stage) { DCHECK(new_stage != current_stage_);
diff --git a/chrome/browser/chromeos/login/screens/controller_pairing_screen.h b/chrome/browser/chromeos/login/screens/controller_pairing_screen.h index 6dcfa18..9305e14 100644 --- a/chrome/browser/chromeos/login/screens/controller_pairing_screen.h +++ b/chrome/browser/chromeos/login/screens/controller_pairing_screen.h
@@ -46,7 +46,6 @@ // Overridden from BaseScreen: void Show() override; void Hide() override; - std::string GetName() const override; // Overridden from pairing_chromeos::ControllerPairingController::Observer: void PairingStageChanged(Stage new_stage) override;
diff --git a/chrome/browser/chromeos/login/screens/device_disabled_screen.cc b/chrome/browser/chromeos/login/screens/device_disabled_screen.cc index 5c51620f..d5ca43e 100644 --- a/chrome/browser/chromeos/login/screens/device_disabled_screen.cc +++ b/chrome/browser/chromeos/login/screens/device_disabled_screen.cc
@@ -16,10 +16,11 @@ DeviceDisabledScreen::DeviceDisabledScreen( BaseScreenDelegate* base_screen_delegate, DeviceDisabledScreenActor* actor) - : BaseScreen(base_screen_delegate), + : BaseScreen(base_screen_delegate, + WizardController::kDeviceDisabledScreenName), actor_(actor), - device_disabling_manager_(g_browser_process->platform_part()-> - device_disabling_manager()), + device_disabling_manager_( + g_browser_process->platform_part()->device_disabling_manager()), showing_(false) { DCHECK(actor_); if (actor_) @@ -50,10 +51,6 @@ actor_->Hide(); } -std::string DeviceDisabledScreen::GetName() const { - return WizardController::kDeviceDisabledScreenName; -} - void DeviceDisabledScreen::OnActorDestroyed(DeviceDisabledScreenActor* actor) { if (actor_ == actor) actor_ = nullptr;
diff --git a/chrome/browser/chromeos/login/screens/device_disabled_screen.h b/chrome/browser/chromeos/login/screens/device_disabled_screen.h index ad1004d..6aff9bb 100644 --- a/chrome/browser/chromeos/login/screens/device_disabled_screen.h +++ b/chrome/browser/chromeos/login/screens/device_disabled_screen.h
@@ -30,7 +30,6 @@ // BaseScreen: void Show() override; void Hide() override; - std::string GetName() const override; // DeviceDisabledScreenActor::Delegate: void OnActorDestroyed(DeviceDisabledScreenActor* actor) override;
diff --git a/chrome/browser/chromeos/login/screens/enable_debugging_screen.cc b/chrome/browser/chromeos/login/screens/enable_debugging_screen.cc index a4e605e..babfbdf4 100644 --- a/chrome/browser/chromeos/login/screens/enable_debugging_screen.cc +++ b/chrome/browser/chromeos/login/screens/enable_debugging_screen.cc
@@ -10,10 +10,10 @@ namespace chromeos { -EnableDebuggingScreen::EnableDebuggingScreen( - BaseScreenDelegate* delegate, - EnableDebuggingScreenActor* actor) - : BaseScreen(delegate), actor_(actor) { +EnableDebuggingScreen::EnableDebuggingScreen(BaseScreenDelegate* delegate, + EnableDebuggingScreenActor* actor) + : BaseScreen(delegate, WizardController::kEnableDebuggingScreenName), + actor_(actor) { DCHECK(actor_); if (actor_) actor_->SetDelegate(this); @@ -34,10 +34,6 @@ actor_->Hide(); } -std::string EnableDebuggingScreen::GetName() const { - return WizardController::kEnableDebuggingScreenName; -} - void EnableDebuggingScreen::OnExit(bool success) { Finish(success ? BaseScreenDelegate::ENABLE_DEBUGGING_FINISHED : BaseScreenDelegate::ENABLE_DEBUGGING_CANCELED);
diff --git a/chrome/browser/chromeos/login/screens/enable_debugging_screen.h b/chrome/browser/chromeos/login/screens/enable_debugging_screen.h index 49cad4b8..36db96b1 100644 --- a/chrome/browser/chromeos/login/screens/enable_debugging_screen.h +++ b/chrome/browser/chromeos/login/screens/enable_debugging_screen.h
@@ -25,7 +25,6 @@ // BaseScreen implementation: void Show() override; void Hide() override; - std::string GetName() const override; // EnableDebuggingScreenActor::Delegate implementation: void OnExit(bool success) override;
diff --git a/chrome/browser/chromeos/login/screens/eula_model.cc b/chrome/browser/chromeos/login/screens/eula_model.cc index 12dca310..e8f0119 100644 --- a/chrome/browser/chromeos/login/screens/eula_model.cc +++ b/chrome/browser/chromeos/login/screens/eula_model.cc
@@ -13,14 +13,9 @@ const char EulaModel::kContextKeyUsageStatsEnabled[] = "usageStatsEnabled"; EulaModel::EulaModel(BaseScreenDelegate* base_screen_delegate) - : BaseScreen(base_screen_delegate) { -} + : BaseScreen(base_screen_delegate, WizardController::kEulaScreenName) {} EulaModel::~EulaModel() { } -std::string EulaModel::GetName() const { - return WizardController::kEulaScreenName; -} - } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/eula_model.h b/chrome/browser/chromeos/login/screens/eula_model.h index 121d1b76..fb1a45a 100644 --- a/chrome/browser/chromeos/login/screens/eula_model.h +++ b/chrome/browser/chromeos/login/screens/eula_model.h
@@ -23,9 +23,6 @@ explicit EulaModel(BaseScreenDelegate* base_screen_delegate); ~EulaModel() override; - // BaseScreen implementation: - std::string GetName() const override; - // Returns URL of the OEM EULA page that should be displayed using current // locale and manifest. Returns empty URL otherwise. virtual GURL GetOemEulaUrl() const = 0;
diff --git a/chrome/browser/chromeos/login/screens/hid_detection_model.cc b/chrome/browser/chromeos/login/screens/hid_detection_model.cc index 5f30798..65caf93 100644 --- a/chrome/browser/chromeos/login/screens/hid_detection_model.cc +++ b/chrome/browser/chromeos/login/screens/hid_detection_model.cc
@@ -25,14 +25,10 @@ "continue-button-enabled"; HIDDetectionModel::HIDDetectionModel(BaseScreenDelegate* base_screen_delegate) - : BaseScreen(base_screen_delegate) { -} + : BaseScreen(base_screen_delegate, + WizardController::kHIDDetectionScreenName) {} HIDDetectionModel::~HIDDetectionModel() { } -std::string HIDDetectionModel::GetName() const { - return WizardController::kHIDDetectionScreenName; -} - } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/hid_detection_model.h b/chrome/browser/chromeos/login/screens/hid_detection_model.h index 598992a3..2e5fa30 100644 --- a/chrome/browser/chromeos/login/screens/hid_detection_model.h +++ b/chrome/browser/chromeos/login/screens/hid_detection_model.h
@@ -28,9 +28,6 @@ explicit HIDDetectionModel(BaseScreenDelegate* base_screen_delegate); ~HIDDetectionModel() override; - // BaseScreen implementation: - std::string GetName() const override; - // Called when continue button was clicked. virtual void OnContinueButtonClicked() = 0;
diff --git a/chrome/browser/chromeos/login/screens/host_pairing_screen.cc b/chrome/browser/chromeos/login/screens/host_pairing_screen.cc index 93136a8..ad95e39 100644 --- a/chrome/browser/chromeos/login/screens/host_pairing_screen.cc +++ b/chrome/browser/chromeos/login/screens/host_pairing_screen.cc
@@ -22,7 +22,8 @@ Delegate* delegate, HostPairingScreenActor* actor, pairing_chromeos::HostPairingController* remora_controller) - : BaseScreen(base_screen_delegate), + : BaseScreen(base_screen_delegate, + WizardController::kHostPairingScreenName), delegate_(delegate), actor_(actor), remora_controller_(remora_controller), @@ -58,10 +59,6 @@ actor_->Hide(); } -std::string HostPairingScreen::GetName() const { - return WizardController::kHostPairingScreenName; -} - void HostPairingScreen::PairingStageChanged(Stage new_stage) { std::string desired_page; switch (new_stage) {
diff --git a/chrome/browser/chromeos/login/screens/host_pairing_screen.h b/chrome/browser/chromeos/login/screens/host_pairing_screen.h index ed03abf..b209d5d 100644 --- a/chrome/browser/chromeos/login/screens/host_pairing_screen.h +++ b/chrome/browser/chromeos/login/screens/host_pairing_screen.h
@@ -51,7 +51,6 @@ // Overridden from BaseScreen: void Show() override; void Hide() override; - std::string GetName() const override; // pairing_chromeos::HostPairingController::Observer: void PairingStageChanged(Stage new_stage) override;
diff --git a/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.cc b/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.cc index 733dad7e..047bca2 100644 --- a/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.cc +++ b/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.cc
@@ -14,7 +14,9 @@ KioskAutolaunchScreen::KioskAutolaunchScreen( BaseScreenDelegate* base_screen_delegate, KioskAutolaunchScreenActor* actor) - : BaseScreen(base_screen_delegate), actor_(actor) { + : BaseScreen(base_screen_delegate, + WizardController::kKioskAutolaunchScreenName), + actor_(actor) { DCHECK(actor_); if (actor_) actor_->SetDelegate(this); @@ -30,10 +32,6 @@ actor_->Show(); } -std::string KioskAutolaunchScreen::GetName() const { - return WizardController::kKioskAutolaunchScreenName; -} - void KioskAutolaunchScreen::OnExit(bool confirmed) { Finish(confirmed ? BaseScreenDelegate::KIOSK_AUTOLAUNCH_CONFIRMED : BaseScreenDelegate::KIOSK_AUTOLAUNCH_CANCELED);
diff --git a/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.h b/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.h index e5e01b4..5a22e59 100644 --- a/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.h +++ b/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.h
@@ -26,7 +26,6 @@ // BaseScreen implementation: void Show() override; void Hide() override {} - std::string GetName() const override; // KioskAutolaunchScreenActor::Delegate implementation: void OnExit(bool confirmed) override;
diff --git a/chrome/browser/chromeos/login/screens/kiosk_enable_screen.cc b/chrome/browser/chromeos/login/screens/kiosk_enable_screen.cc index 1a285a9..3311bd9 100644 --- a/chrome/browser/chromeos/login/screens/kiosk_enable_screen.cc +++ b/chrome/browser/chromeos/login/screens/kiosk_enable_screen.cc
@@ -13,7 +13,9 @@ KioskEnableScreen::KioskEnableScreen(BaseScreenDelegate* base_screen_delegate, KioskEnableScreenActor* actor) - : BaseScreen(base_screen_delegate), actor_(actor) { + : BaseScreen(base_screen_delegate, + WizardController::kKioskEnableScreenName), + actor_(actor) { DCHECK(actor_); if (actor_) actor_->SetDelegate(this); @@ -29,10 +31,6 @@ actor_->Show(); } -std::string KioskEnableScreen::GetName() const { - return WizardController::kKioskEnableScreenName; -} - void KioskEnableScreen::OnExit() { Finish(BaseScreenDelegate::KIOSK_ENABLE_COMPLETED); }
diff --git a/chrome/browser/chromeos/login/screens/kiosk_enable_screen.h b/chrome/browser/chromeos/login/screens/kiosk_enable_screen.h index baad510b..e5edae3 100644 --- a/chrome/browser/chromeos/login/screens/kiosk_enable_screen.h +++ b/chrome/browser/chromeos/login/screens/kiosk_enable_screen.h
@@ -26,7 +26,6 @@ // BaseScreen implementation: void Show() override; void Hide() override {} - std::string GetName() const override; // KioskEnableScreenActor::Delegate implementation: void OnExit() override;
diff --git a/chrome/browser/chromeos/login/screens/mock_eula_screen.h b/chrome/browser/chromeos/login/screens/mock_eula_screen.h index 59743422..27c4ba4 100644 --- a/chrome/browser/chromeos/login/screens/mock_eula_screen.h +++ b/chrome/browser/chromeos/login/screens/mock_eula_screen.h
@@ -31,8 +31,6 @@ MOCK_METHOD0(Show, void()); MOCK_METHOD0(Hide, void()); - MOCK_CONST_METHOD0(GetName, std::string()); - MOCK_METHOD1(MockBind, void(EulaModel& model)); MOCK_METHOD0(MockUnbind, void()); MOCK_METHOD1(OnPasswordFetched, void(const std::string& tpm_password));
diff --git a/chrome/browser/chromeos/login/screens/network_error_model.cc b/chrome/browser/chromeos/login/screens/network_error_model.cc index be02d01..b1d3d7bc 100644 --- a/chrome/browser/chromeos/login/screens/network_error_model.cc +++ b/chrome/browser/chromeos/login/screens/network_error_model.cc
@@ -33,14 +33,8 @@ "connect-requested"; NetworkErrorModel::NetworkErrorModel(BaseScreenDelegate* base_screen_delegate) - : BaseScreen(base_screen_delegate) { -} + : BaseScreen(base_screen_delegate, WizardController::kErrorScreenName) {} -NetworkErrorModel::~NetworkErrorModel() { -} - -std::string NetworkErrorModel::GetName() const { - return WizardController::kErrorScreenName; -} +NetworkErrorModel::~NetworkErrorModel() {} } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/network_error_model.h b/chrome/browser/chromeos/login/screens/network_error_model.h index 81941f3..ba201b3 100644 --- a/chrome/browser/chromeos/login/screens/network_error_model.h +++ b/chrome/browser/chromeos/login/screens/network_error_model.h
@@ -35,9 +35,6 @@ explicit NetworkErrorModel(BaseScreenDelegate* base_screen_delegate); ~NetworkErrorModel() override; - // BaseScreen: - std::string GetName() const override; - // Toggles the guest sign-in prompt. virtual void AllowGuestSignin(bool allowed) = 0;
diff --git a/chrome/browser/chromeos/login/screens/network_model.cc b/chrome/browser/chromeos/login/screens/network_model.cc index fbff3b2..36c4b8cc 100644 --- a/chrome/browser/chromeos/login/screens/network_model.cc +++ b/chrome/browser/chromeos/login/screens/network_model.cc
@@ -18,14 +18,8 @@ "continue-button-enabled"; NetworkModel::NetworkModel(BaseScreenDelegate* base_screen_delegate) - : BaseScreen(base_screen_delegate) { -} + : BaseScreen(base_screen_delegate, WizardController::kNetworkScreenName) {} -NetworkModel::~NetworkModel() { -} - -std::string NetworkModel::GetName() const { - return WizardController::kNetworkScreenName; -} +NetworkModel::~NetworkModel() {} } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/network_model.h b/chrome/browser/chromeos/login/screens/network_model.h index 8e3035f..66cbfda 100644 --- a/chrome/browser/chromeos/login/screens/network_model.h +++ b/chrome/browser/chromeos/login/screens/network_model.h
@@ -28,9 +28,6 @@ explicit NetworkModel(BaseScreenDelegate* base_screen_delegate); ~NetworkModel() override; - // BaseScreen implementation: - std::string GetName() const override; - // This method is called, when view is being destroyed. Note, if model // is destroyed earlier then it has to call Unbind(). virtual void OnViewDestroyed(NetworkView* view) = 0;
diff --git a/chrome/browser/chromeos/login/screens/reset_model.cc b/chrome/browser/chromeos/login/screens/reset_model.cc index 48ae3a00..fcaf183e8 100644 --- a/chrome/browser/chromeos/login/screens/reset_model.cc +++ b/chrome/browser/chromeos/login/screens/reset_model.cc
@@ -26,14 +26,8 @@ const char ResetModel::kContextKeyScreenState[] = "screen-state"; ResetModel::ResetModel(BaseScreenDelegate* base_screen_delegate) - : BaseScreen(base_screen_delegate) { -} + : BaseScreen(base_screen_delegate, WizardController::kResetScreenName) {} -ResetModel::~ResetModel() { -} - -std::string ResetModel::GetName() const { - return WizardController::kResetScreenName; -} +ResetModel::~ResetModel() {} } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/reset_model.h b/chrome/browser/chromeos/login/screens/reset_model.h index 75d11c56..5e37046 100644 --- a/chrome/browser/chromeos/login/screens/reset_model.h +++ b/chrome/browser/chromeos/login/screens/reset_model.h
@@ -33,9 +33,6 @@ explicit ResetModel(BaseScreenDelegate* base_screen_delegate); ~ResetModel() override; - // BaseScreen implementation: - std::string GetName() const override; - // Called when actor is destroyed so there's no dead reference to it. virtual void OnViewDestroyed(ResetView* view) = 0; };
diff --git a/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc b/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc index 5595a5fe..b121070 100644 --- a/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc +++ b/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
@@ -29,7 +29,9 @@ TermsOfServiceScreen::TermsOfServiceScreen( BaseScreenDelegate* base_screen_delegate, TermsOfServiceScreenActor* actor) - : BaseScreen(base_screen_delegate), actor_(actor) { + : BaseScreen(base_screen_delegate, + WizardController::kTermsOfServiceScreenName), + actor_(actor) { DCHECK(actor_); if (actor_) actor_->SetDelegate(this); @@ -61,10 +63,6 @@ actor_->Hide(); } -std::string TermsOfServiceScreen::GetName() const { - return WizardController::kTermsOfServiceScreenName; -} - void TermsOfServiceScreen::OnDecline() { Finish(BaseScreenDelegate::TERMS_OF_SERVICE_DECLINED); }
diff --git a/chrome/browser/chromeos/login/screens/terms_of_service_screen.h b/chrome/browser/chromeos/login/screens/terms_of_service_screen.h index 26f26c6..d4fff4da 100644 --- a/chrome/browser/chromeos/login/screens/terms_of_service_screen.h +++ b/chrome/browser/chromeos/login/screens/terms_of_service_screen.h
@@ -37,7 +37,6 @@ // BaseScreen: void Show() override; void Hide() override; - std::string GetName() const override; // TermsOfServiceScreenActor::Delegate: void OnDecline() override;
diff --git a/chrome/browser/chromeos/login/screens/update_model.cc b/chrome/browser/chromeos/login/screens/update_model.cc index d8f2be49..61d21e2 100644 --- a/chrome/browser/chromeos/login/screens/update_model.cc +++ b/chrome/browser/chromeos/login/screens/update_model.cc
@@ -20,14 +20,8 @@ "cancel-update-enabled"; UpdateModel::UpdateModel(BaseScreenDelegate* base_screen_delegate) - : BaseScreen(base_screen_delegate) { -} + : BaseScreen(base_screen_delegate, WizardController::kUpdateScreenName) {} -UpdateModel::~UpdateModel() { -} - -std::string UpdateModel::GetName() const { - return WizardController::kUpdateScreenName; -} +UpdateModel::~UpdateModel() {} } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/update_model.h b/chrome/browser/chromeos/login/screens/update_model.h index af18b50..2a8a7ed2 100644 --- a/chrome/browser/chromeos/login/screens/update_model.h +++ b/chrome/browser/chromeos/login/screens/update_model.h
@@ -27,9 +27,6 @@ explicit UpdateModel(BaseScreenDelegate* base_screen_delegate); ~UpdateModel() override; - // BaseScreen implementation: - std::string GetName() const override; - // This method is called, when view is being destroyed. Note, if model // is destroyed earlier then it has to call Unbind(). virtual void OnViewDestroyed(UpdateView* view) = 0;
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc index d08ad8c..24f8643 100644 --- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -182,7 +182,8 @@ // Check that OOBE will resume back at this screen. base::RunLoop().RunUntilIdle(); EXPECT_FALSE(StartupUtils::IsOobeCompleted()); - EXPECT_EQ(update_screen_->GetName(), + EXPECT_EQ( + update_screen_->screen_id(), g_browser_process->local_state()->GetString(prefs::kOobeScreenPending)); }
diff --git a/chrome/browser/chromeos/login/screens/user_image_model.cc b/chrome/browser/chromeos/login/screens/user_image_model.cc index 6a90d4aa..475d87a9 100644 --- a/chrome/browser/chromeos/login/screens/user_image_model.cc +++ b/chrome/browser/chromeos/login/screens/user_image_model.cc
@@ -14,14 +14,9 @@ const char UserImageModel::kContextKeySelectedImageURL[] = "selectedImageURL"; UserImageModel::UserImageModel(BaseScreenDelegate* base_screen_delegate) - : BaseScreen(base_screen_delegate) { + : BaseScreen(base_screen_delegate, WizardController::kUserImageScreenName) { } -UserImageModel::~UserImageModel() { -} - -std::string UserImageModel::GetName() const { - return WizardController::kUserImageScreenName; -} +UserImageModel::~UserImageModel() {} } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/user_image_model.h b/chrome/browser/chromeos/login/screens/user_image_model.h index 6234475..9e9a0617 100644 --- a/chrome/browser/chromeos/login/screens/user_image_model.h +++ b/chrome/browser/chromeos/login/screens/user_image_model.h
@@ -23,9 +23,6 @@ explicit UserImageModel(BaseScreenDelegate* base_screen_delegate); ~UserImageModel() override; - // BaseScreen implementation: - std::string GetName() const override; - // Called when UI ready to be shown. virtual void OnScreenReady() = 0;
diff --git a/chrome/browser/chromeos/login/screens/wrong_hwid_screen.cc b/chrome/browser/chromeos/login/screens/wrong_hwid_screen.cc index 661b0d25..4cf6062b 100644 --- a/chrome/browser/chromeos/login/screens/wrong_hwid_screen.cc +++ b/chrome/browser/chromeos/login/screens/wrong_hwid_screen.cc
@@ -11,7 +11,8 @@ WrongHWIDScreen::WrongHWIDScreen(BaseScreenDelegate* base_screen_delegate, WrongHWIDScreenActor* actor) - : BaseScreen(base_screen_delegate), actor_(actor) { + : BaseScreen(base_screen_delegate, WizardController::kWrongHWIDScreenName), + actor_(actor) { DCHECK(actor_); if (actor_) actor_->SetDelegate(this); @@ -32,10 +33,6 @@ actor_->Hide(); } -std::string WrongHWIDScreen::GetName() const { - return WizardController::kWrongHWIDScreenName; -} - void WrongHWIDScreen::OnExit() { Finish(BaseScreenDelegate::WRONG_HWID_WARNING_SKIPPED); }
diff --git a/chrome/browser/chromeos/login/screens/wrong_hwid_screen.h b/chrome/browser/chromeos/login/screens/wrong_hwid_screen.h index 55e486ae..ae1fe959 100644 --- a/chrome/browser/chromeos/login/screens/wrong_hwid_screen.h +++ b/chrome/browser/chromeos/login/screens/wrong_hwid_screen.h
@@ -26,7 +26,6 @@ // BaseScreen implementation: void Show() override; void Hide() override; - std::string GetName() const override; // WrongHWIDScreenActor::Delegate implementation: void OnExit() override;
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc index 36d99c6..82b07b4 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc +++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
@@ -103,7 +103,8 @@ SupervisedUserCreationScreen::SupervisedUserCreationScreen( BaseScreenDelegate* base_screen_delegate, SupervisedUserCreationScreenHandler* actor) - : BaseScreen(base_screen_delegate), + : BaseScreen(base_screen_delegate, + WizardController::kSupervisedUserCreationScreenName), actor_(actor), on_error_screen_(false), manager_signin_in_progress_(false), @@ -192,10 +193,6 @@ network_portal_detector::GetInstance()->RemoveObserver(this); } -std::string SupervisedUserCreationScreen::GetName() const { - return WizardController::kSupervisedUserCreationScreenName; -} - void SupervisedUserCreationScreen::AbortFlow() { DBusThreadManager::Get() ->GetSessionManagerClient()
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h index e123bb0..cc79735 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h +++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h
@@ -77,7 +77,6 @@ // BaseScreen implementation: void Show() override; void Hide() override; - std::string GetName() const override; // SupervisedUserCreationScreenHandler::Delegate implementation: void OnActorDestroyed(SupervisedUserCreationScreenHandler* actor) override;
diff --git a/chrome/browser/chromeos/login/ui/models/user_board_model.cc b/chrome/browser/chromeos/login/ui/models/user_board_model.cc index fd90a9216..c693e0c 100644 --- a/chrome/browser/chromeos/login/ui/models/user_board_model.cc +++ b/chrome/browser/chromeos/login/ui/models/user_board_model.cc
@@ -10,12 +10,8 @@ namespace chromeos { -UserBoardModel::UserBoardModel() : BaseScreen(nullptr) {} +UserBoardModel::UserBoardModel() : BaseScreen(nullptr, kUserBoardScreenName) {} UserBoardModel::~UserBoardModel() {} -std::string UserBoardModel::GetName() const { - return kUserBoardScreenName; -} - } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/models/user_board_model.h b/chrome/browser/chromeos/login/ui/models/user_board_model.h index ebbebdd1..11916a7 100644 --- a/chrome/browser/chromeos/login/ui/models/user_board_model.h +++ b/chrome/browser/chromeos/login/ui/models/user_board_model.h
@@ -24,9 +24,6 @@ virtual void AttemptEasyUnlock(const AccountId& account_id) = 0; virtual void RecordClickOnLockIcon(const AccountId& account_id) = 0; - // BaseScreen implementation: - std::string GetName() const override; - // Temorary unused methods: void Show() override{}; void Hide() override{};
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 3e572c9..d5b71add 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -958,8 +958,8 @@ return; // First remember how far have we reached so that we can resume if needed. - if (is_out_of_box_ && IsResumableScreen(current_screen_->GetName())) - StartupUtils::SaveOobePendingScreen(current_screen_->GetName()); + if (is_out_of_box_ && IsResumableScreen(current_screen_->screen_id())) + StartupUtils::SaveOobePendingScreen(current_screen_->screen_id()); smooth_show_timer_.Stop(); @@ -981,7 +981,7 @@ if (current_screen_) current_screen_->Hide(); - std::string screen_id = new_current->GetName(); + const std::string screen_id = new_current->screen_id(); if (IsOOBEStepToTrack(screen_id)) screen_show_times_[screen_id] = base::Time::Now(); @@ -1085,7 +1085,7 @@ ExitCodes exit_code, const ::login::ScreenContext* /* context */) { VLOG(1) << "Wizard screen exit code: " << exit_code; - std::string previous_screen_id = current_screen_->GetName(); + const std::string previous_screen_id = current_screen_->screen_id(); if (IsOOBEStepToTrack(previous_screen_id)) { RecordUMAHistogramForOOBEStepCompletionTime( previous_screen_id,
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc index 565c71c..acdf59d 100644 --- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -2156,7 +2156,7 @@ ASSERT_TRUE(wizard_controller); ASSERT_TRUE(wizard_controller->current_screen()); EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName, - wizard_controller->current_screen()->GetName()); + wizard_controller->current_screen()->screen_id()); // Wait for the Terms of Service to finish downloading. bool done = false; @@ -2363,7 +2363,7 @@ ASSERT_TRUE(wizard_controller); ASSERT_TRUE(wizard_controller->current_screen()); EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName, - wizard_controller->current_screen()->GetName()); + wizard_controller->current_screen()->screen_id()); // Wait for the Terms of Service to finish downloading, then get the status of // the screen's UI elements.
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc index 98b9d286..2e0de2e4 100644 --- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc +++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -24,6 +24,7 @@ #if defined(OS_CHROMEOS) #include "chrome/browser/metrics/chromeos_metrics_provider.h" #include "chromeos/system/statistics_provider.h" +#include "chromeos/system/version_loader.h" #endif #if defined(OS_WIN) @@ -39,6 +40,7 @@ constexpr char kDataReductionProxyKey[] = "data_reduction_proxy"; constexpr char kChromeVersionTag[] = "CHROME VERSION"; #if defined(OS_CHROMEOS) +constexpr char kChromeOsFirmwareVersion[] = "CHROMEOS_FIRMWARE_VERSION"; constexpr char kChromeEnrollmentTag[] = "ENTERPRISE_ENROLLED"; constexpr char kHWIDKey[] = "HWID"; constexpr char kSettingsKey[] = "settings"; @@ -69,20 +71,23 @@ return std::string(); } -void GetHWID(SystemLogsResponse* response) { +void GetEntriesOnBlockingPool(SystemLogsResponse* response) { DCHECK(response); chromeos::system::StatisticsProvider* stats = chromeos::system::StatisticsProvider::GetInstance(); DCHECK(stats); + // Get the HWID. std::string hwid; - if (!stats->GetMachineStatistic(chromeos::system::kHardwareClassKey, &hwid)) { + if (!stats->GetMachineStatistic(chromeos::system::kHardwareClassKey, &hwid)) VLOG(1) << "Couldn't get machine statistic 'hardware_class'."; - return; - } + else + (*response)[kHWIDKey] = hwid; - (*response)[kHWIDKey] = hwid; + // Get the firmware version. + (*response)[kChromeOsFirmwareVersion] = + chromeos::version_loader::GetFirmware(); } #endif @@ -127,10 +132,11 @@ #if defined(OS_CHROMEOS) PopulateLocalStateSettings(response.get()); - // Get the HWID on the blocking pool and invoke the callback later when done. + // Get the entries that should be retrieved on the blocking pool and invoke + // the callback later when done. SystemLogsResponse* response_ptr = response.release(); content::BrowserThread::PostBlockingPoolTaskAndReply( - FROM_HERE, base::Bind(&GetHWID, response_ptr), + FROM_HERE, base::Bind(&GetEntriesOnBlockingPool, response_ptr), base::Bind(callback, base::Owned(response_ptr))); #else // On other platforms, we're done. Invoke the callback.
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/OWNERS b/chrome/browser/safe_browsing/settings_reset_prompt/OWNERS new file mode 100644 index 0000000..93d2314 --- /dev/null +++ b/chrome/browser/safe_browsing/settings_reset_prompt/OWNERS
@@ -0,0 +1,2 @@ +csharp@chromium.org +robertshield@chromium.org
diff --git a/chrome/browser/ui/android/page_info/connection_info_popup_android.cc b/chrome/browser/ui/android/page_info/connection_info_popup_android.cc index c7254a2..5bfa205 100644 --- a/chrome/browser/ui/android/page_info/connection_info_popup_android.cc +++ b/chrome/browser/ui/android/page_info/connection_info_popup_android.cc
@@ -156,12 +156,6 @@ NOTIMPLEMENTED(); } -void ConnectionInfoPopupAndroid::SetSelectedTab( - WebsiteSettingsUI::TabId tab_id) { - // There's no tab UI on Android - only connection info is shown. - NOTIMPLEMENTED(); -} - // static bool ConnectionInfoPopupAndroid::RegisterConnectionInfoPopupAndroid(
diff --git a/chrome/browser/ui/android/page_info/connection_info_popup_android.h b/chrome/browser/ui/android/page_info/connection_info_popup_android.h index 97bf78e..52f04f4 100644 --- a/chrome/browser/ui/android/page_info/connection_info_popup_android.h +++ b/chrome/browser/ui/android/page_info/connection_info_popup_android.h
@@ -39,7 +39,6 @@ void SetPermissionInfo(const PermissionInfoList& permission_info_list, ChosenObjectInfoList chosen_object_info_list) override; void SetIdentityInfo(const IdentityInfo& identity_info) override; - void SetSelectedTab(WebsiteSettingsUI::TabId tab_id) override; static bool RegisterConnectionInfoPopupAndroid(JNIEnv* env);
diff --git a/chrome/browser/ui/android/page_info/website_settings_popup_android.cc b/chrome/browser/ui/android/page_info/website_settings_popup_android.cc index 40528df..b63da42 100644 --- a/chrome/browser/ui/android/page_info/website_settings_popup_android.cc +++ b/chrome/browser/ui/android/page_info/website_settings_popup_android.cc
@@ -148,12 +148,6 @@ Java_WebsiteSettingsPopup_updatePermissionDisplay(env, popup_jobject_); } -void WebsiteSettingsPopupAndroid::SetSelectedTab( - WebsiteSettingsUI::TabId tab_id) { - // There's no tab UI on Android - only connection info is shown. - NOTIMPLEMENTED(); -} - // static bool WebsiteSettingsPopupAndroid::RegisterWebsiteSettingsPopupAndroid( JNIEnv* env) {
diff --git a/chrome/browser/ui/android/page_info/website_settings_popup_android.h b/chrome/browser/ui/android/page_info/website_settings_popup_android.h index 46a27b78b..066d87b 100644 --- a/chrome/browser/ui/android/page_info/website_settings_popup_android.h +++ b/chrome/browser/ui/android/page_info/website_settings_popup_android.h
@@ -46,7 +46,6 @@ void SetPermissionInfo(const PermissionInfoList& permission_info_list, ChosenObjectInfoList chosen_object_info_list) override; void SetIdentityInfo(const IdentityInfo& identity_info) override; - void SetSelectedTab(WebsiteSettingsUI::TabId tab_id) override; static bool RegisterWebsiteSettingsPopupAndroid(JNIEnv* env);
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc index 7b992ac..ce01953 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -210,9 +210,14 @@ const char kPlayStorePackage[] = "com.android.vending"; const char kPlayStoreActivity[] = "com.android.vending.AssetBrowserActivity"; const char kSettingsAppId[] = "mconboelelhjpkbdhhiijkgcimoangdj"; +const char kAndroidWallpapersAppPackage[] = "com.google.android.apps.wallpaper"; +const char kAndroidWallpapersAppActivity[] = + "com.google.android.apps.wallpaper.picker.CategoryPickerActivity"; bool ShouldShowInLauncher(const std::string& app_id) { - return (app_id != kSettingsAppId); + const std::string wallpapers_app_id = ArcAppListPrefs::GetAppId( + kAndroidWallpapersAppPackage, kAndroidWallpapersAppActivity); + return (app_id != kSettingsAppId) && (app_id != wallpapers_app_id); } bool LaunchAppWithRect(content::BrowserContext* context,
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.h b/chrome/browser/ui/app_list/arc/arc_app_utils.h index e60f40f5..f0caf8c 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_utils.h +++ b/chrome/browser/ui/app_list/arc/arc_app_utils.h
@@ -23,6 +23,8 @@ extern const char kPlayStorePackage[]; extern const char kPlayStoreActivity[]; extern const char kSettingsAppId[]; +extern const char kAndroidWallpapersAppPackage[]; +extern const char kAndroidWallpapersAppActivity[]; using CanHandleResolutionCallback = base::Callback<void(bool)>;
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 767d3607..b64ad91 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -574,7 +574,19 @@ base::string16 Browser::GetWindowTitleForCurrentTab( bool include_app_name) const { - WebContents* contents = tab_strip_model_->GetActiveWebContents(); + return GetWindowTitleFromWebContents( + include_app_name, tab_strip_model_->GetActiveWebContents()); +} + +base::string16 Browser::GetWindowTitleForTab(bool include_app_name, + int index) const { + return GetWindowTitleFromWebContents( + include_app_name, tab_strip_model_->GetWebContentsAt(index)); +} + +base::string16 Browser::GetWindowTitleFromWebContents( + bool include_app_name, + content::WebContents* contents) const { base::string16 title; // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index 1e6c596..0860714 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -42,6 +42,7 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/page_navigator.h" +#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/page_zoom.h" #include "extensions/features/features.h" @@ -299,6 +300,16 @@ // Disables additional formatting when |include_app_name| is false. base::string16 GetWindowTitleForCurrentTab(bool include_app_name) const; + // Gets the window title of the tab at |index|. + // Disables additional formatting when |include_app_name| is false. + base::string16 GetWindowTitleForTab(bool include_app_name, int index) const; + + // Gets the window title from the provided WebContents. + // Disables additional formatting when |include_app_name| is false. + base::string16 GetWindowTitleFromWebContents( + bool include_app_name, + content::WebContents* contents) const; + // Prepares a title string for display (removes embedded newlines, etc). static void FormatTitleForDisplay(base::string16* title);
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell.mm b/chrome/browser/ui/cocoa/download/download_item_cell.mm index 74b1962..9744ffc1 100644 --- a/chrome/browser/ui/cocoa/download/download_item_cell.mm +++ b/chrome/browser/ui/cocoa/download/download_item_cell.mm
@@ -20,6 +20,7 @@ #include "ui/gfx/canvas_skia_paint.h" #include "ui/gfx/font_list.h" #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" +#include "ui/gfx/shadow_value.h" #include "ui/gfx/text_elider.h" #include "ui/native_theme/native_theme.h"
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h index f59a72bf..721237d 100644 --- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h +++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h
@@ -141,7 +141,6 @@ void SetPermissionInfo(const PermissionInfoList& permission_info_list, ChosenObjectInfoList chosen_object_info_list) override; void SetIdentityInfo(const IdentityInfo& identity_info) override; - void SetSelectedTab(TabId tab_id) override; private: // The WebContents the bubble UI is attached to.
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm index c978786..31b9d3c 100644 --- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
@@ -1216,7 +1216,3 @@ [bubble_controller_ setPermissionInfo:permission_info_list andChosenObjects:std::move(chosen_object_info_list)]; } - -void WebsiteSettingsUIBridge::SetSelectedTab(TabId tab_id) { - // TODO(lgarron): Remove this from the interface. (crbug.com/571533) -}
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc index 9c52094..766da80 100644 --- a/chrome/browser/ui/libgtkui/gtk_ui.cc +++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -880,7 +880,7 @@ #if GTK_MAJOR_VERSION > 2 colors_[ThemeProperties::COLOR_TOOLBAR_BOTTOM_SEPARATOR] = colors_[ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR] = - GetBorderColor("GtkToolbar.primary-toolbar.toolbar"); + GetBorderColor("GtkToolbar#toolbar.primary-toolbar"); #endif } @@ -925,9 +925,9 @@ colors_[ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE] = temp_color; #else // TODO(thomasanderson): Render a GtkHeaderBar directly. - SkColor color_frame = GetBgColor(".headerbar.header-bar.titlebar"); + SkColor color_frame = GetBgColor("#headerbar.header-bar.titlebar"); SkColor color_frame_inactive = - GetBgColor(".headerbar.header-bar.titlebar:backdrop"); + GetBgColor("#headerbar.header-bar.titlebar:backdrop"); colors_[ThemeProperties::COLOR_FRAME] = color_frame; colors_[ThemeProperties::COLOR_FRAME_INACTIVE] = color_frame_inactive; colors_[ThemeProperties::COLOR_FRAME_INCOGNITO] =
diff --git a/chrome/browser/ui/libgtkui/gtk_util.cc b/chrome/browser/ui/libgtkui/gtk_util.cc index 53a370f..826af71 100644 --- a/chrome/browser/ui/libgtkui/gtk_util.cc +++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/libgtkui/gtk_util.h" +#include <dlfcn.h> #include <gdk/gdk.h> #include <gdk/gdkx.h> #include <gtk/gtk.h> @@ -52,6 +53,14 @@ } } +#if GTK_MAJOR_VERSION == 3 +void* GetGtk3SharedLibrary() { + static void* gtk3lib = dlopen("libgtk-3.so.0", RTLD_LAZY); + DCHECK(gtk3lib); + return gtk3lib; +} +#endif + } // namespace namespace libgtkui { @@ -199,8 +208,8 @@ : gtk_widget_path_new(); enum { - // TODO(thomasanderson): Add CSS_NAME here to handle the Gtk3.20 case. CSS_TYPE, + CSS_NAME, CSS_CLASS, CSS_PSEUDOCLASS, } part_type = CSS_TYPE; @@ -224,7 +233,7 @@ }; GtkStateFlags state = context ? gtk_style_context_get_state(context) : GTK_STATE_FLAG_NORMAL; - base::StringTokenizer t(css_node, ".:"); + base::StringTokenizer t(css_node, ".:#"); t.set_options(base::StringTokenizer::RETURN_DELIMS); while (t.GetNext()) { if (t.token_is_delim()) { @@ -233,6 +242,9 @@ gtk_widget_path_append_type(path, G_TYPE_NONE); } switch (*t.token_begin()) { + case '#': + part_type = CSS_NAME; + break; case '.': part_type = CSS_CLASS; break; @@ -244,6 +256,20 @@ } } else { switch (part_type) { + case CSS_NAME: { + if (gtk_get_major_version() > 3 || + (gtk_get_major_version() == 3 && gtk_get_minor_version() >= 20)) { + static auto* _gtk_widget_path_iter_set_object_name = + reinterpret_cast<void (*)(GtkWidgetPath*, gint, const char*)>( + dlsym(GetGtk3SharedLibrary(), + "gtk_widget_path_iter_set_object_name")); + DCHECK(_gtk_widget_path_iter_set_object_name); + _gtk_widget_path_iter_set_object_name(path, -1, t.token().c_str()); + } else { + gtk_widget_path_iter_add_class(path, -1, t.token().c_str()); + } + break; + } case CSS_TYPE: { GType type = g_type_from_name(t.token().c_str()); DCHECK(type);
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk3.cc b/chrome/browser/ui/libgtkui/native_theme_gtk3.cc index 852ed8a..84de8bd 100644 --- a/chrome/browser/ui/libgtkui/native_theme_gtk3.cc +++ b/chrome/browser/ui/libgtkui/native_theme_gtk3.cc
@@ -74,44 +74,44 @@ // FocusableBorder case ui::NativeTheme::kColorId_FocusedBorderColor: - return GetBorderColor("GtkEntry.entry:focus"); + return GetBorderColor("GtkEntry#entry:focus"); case ui::NativeTheme::kColorId_UnfocusedBorderColor: - return GetBorderColor("GtkEntry.entry"); + return GetBorderColor("GtkEntry#entry"); // Menu case ui::NativeTheme::kColorId_MenuBackgroundColor: - return GetBgColor("GtkMenu.menu"); + return GetBgColor("GtkMenu#menu"); case ui::NativeTheme::kColorId_MenuBorderColor: - return GetBorderColor("GtkMenu.menu"); + return GetBorderColor("GtkMenu#menu"); case ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor: - return GetBgColor("GtkMenu.menu GtkMenuItem.menuitem:focus"); + return GetBgColor("GtkMenu#menu GtkMenuItem#menuitem:focus"); case ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor: - return GetFgColor("GtkMenu.menu GtkMenuItem.menuitem GtkLabel.label"); + return GetFgColor("GtkMenu#menu GtkMenuItem#menuitem GtkLabel#label"); case ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor: return GetFgColor( - "GtkMenu.menu GtkMenuItem.menuitem:selected GtkLabel.label"); + "GtkMenu#menu GtkMenuItem#menuitem:selected GtkLabel#label"); case ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor: return GetFgColor( - "GtkMenu.menu GtkMenuItem.menuitem:disabled GtkLabel.label"); + "GtkMenu#menu GtkMenuItem#menuitem:disabled GtkLabel#label"); case ui::NativeTheme::kColorId_MenuItemSubtitleColor: return GetFgColor( - "GtkMenu.menu GtkMenuItem.menuitem GtkLabel.label.accelerator"); + "GtkMenu#menu GtkMenuItem#menuitem GtkLabel#label.accelerator"); case ui::NativeTheme::kColorId_MenuSeparatorColor: // MenuButton borders are used the same way as menu separators in Chrome. case ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor: case ui::NativeTheme::kColorId_FocusedMenuButtonBorderColor: case ui::NativeTheme::kColorId_HoverMenuButtonBorderColor: - return GetFgColor("GtkMenu.menu GtkMenuItem.menuitem.separator:disabled"); + return GetFgColor("GtkMenu#menu GtkMenuItem#menuitem.separator:disabled"); // Label case ui::NativeTheme::kColorId_LabelEnabledColor: - return GetFgColor("GtkLabel.label"); + return GetFgColor("GtkLabel#label"); case ui::NativeTheme::kColorId_LabelDisabledColor: - return GetFgColor("GtkLabel.label:disabled"); + return GetFgColor("GtkLabel#label:disabled"); case ui::NativeTheme::kColorId_LabelTextSelectionColor: - return GetFgColor("GtkLabel.label .selection:selected"); + return GetFgColor("GtkLabel#label #selection:selected"); case ui::NativeTheme::kColorId_LabelTextSelectionBackgroundFocused: - return GetBgColor("GtkLabel.label .selection:selected"); + return GetBgColor("GtkLabel#label #selection:selected"); // Link case ui::NativeTheme::kColorId_LinkDisabled: @@ -121,7 +121,7 @@ case ui::NativeTheme::kColorId_LinkEnabled: { // TODO(thomasanderson): Gtk changed the way links are colored in 3.12. // Add code for later versions. - auto link_context = GetStyleContextFromCss("GtkLabel.label.view"); + auto link_context = GetStyleContextFromCss("GtkLabel#label.view"); GdkColor* color; gtk_style_context_get_style(link_context, "link-color", &color, nullptr); if (color) { @@ -137,143 +137,143 @@ // Button case ui::NativeTheme::kColorId_ButtonEnabledColor: - return GetFgColor("GtkButton.button.text-button GtkLabel.label"); + return GetFgColor("GtkButton#button.text-button GtkLabel#label"); case ui::NativeTheme::kColorId_ButtonDisabledColor: - return GetFgColor("GtkButton.button.text-button:disabled GtkLabel.label"); + return GetFgColor("GtkButton#button.text-button:disabled GtkLabel#label"); case ui::NativeTheme::kColorId_ButtonHoverColor: - return GetFgColor("GtkButton.button.text-button:hover GtkLabel.label"); + return GetFgColor("GtkButton#button.text-button:hover GtkLabel#label"); case ui::NativeTheme::kColorId_ButtonPressedShade: return SK_ColorTRANSPARENT; case ui::NativeTheme::kColorId_BlueButtonEnabledColor: return GetFgColor( - "GtkButton.button.text-button.suggested-action GtkLabel.label"); + "GtkButton#button.text-button.suggested-action GtkLabel#label"); case ui::NativeTheme::kColorId_BlueButtonDisabledColor: return GetFgColor( - "GtkButton.button.text-button.suggested-action:disabled " - "GtkLabel.label"); + "GtkButton#button.text-button.suggested-action:disabled " + "GtkLabel#label"); case ui::NativeTheme::kColorId_BlueButtonHoverColor: return GetFgColor( - "GtkButton.button.text-button.suggested-action:hover GtkLabel.label"); + "GtkButton#button.text-button.suggested-action:hover GtkLabel#label"); case ui::NativeTheme::kColorId_BlueButtonPressedColor: return GetFgColor( - "GtkButton.button.text-button.suggested-action:hover:active " - "GtkLabel.label"); + "GtkButton#button.text-button.suggested-action:hover:active " + "GtkLabel#label"); case ui::NativeTheme::kColorId_BlueButtonShadowColor: return SK_ColorTRANSPARENT; case ui::NativeTheme::kColorId_ProminentButtonColor: - return GetBgColor("GtkButton.button.text-button.destructive-action"); + return GetBgColor("GtkButton#button.text-button.destructive-action"); case ui::NativeTheme::kColorId_TextOnProminentButtonColor: return GetFgColor( - "GtkButton.button.text-button.destructive-action GtkLabel.label"); + "GtkButton#button.text-button.destructive-action GtkLabel#label"); // Textfield case ui::NativeTheme::kColorId_TextfieldDefaultColor: - return GetFgColor("GtkEntry.entry"); + return GetFgColor("GtkEntry#entry"); case ui::NativeTheme::kColorId_TextfieldDefaultBackground: - return GetBgColor("GtkEntry.entry"); + return GetBgColor("GtkEntry#entry"); case ui::NativeTheme::kColorId_TextfieldReadOnlyColor: - return GetFgColor("GtkEntry.entry:disabled"); + return GetFgColor("GtkEntry#entry:disabled"); case ui::NativeTheme::kColorId_TextfieldReadOnlyBackground: - return GetBgColor("GtkEntry.entry:disabled"); + return GetBgColor("GtkEntry#entry:disabled"); case ui::NativeTheme::kColorId_TextfieldSelectionColor: - return GetFgColor("GtkEntry.entry .selection:selected"); + return GetFgColor("GtkEntry#entry #selection:selected"); case ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused: - return GetBgColor("GtkEntry.entry .selection:selected"); + return GetBgColor("GtkEntry#entry #selection:selected"); // Tooltips case ui::NativeTheme::kColorId_TooltipBackground: - return GetBgColor("GtkTooltip.tooltip"); + return GetBgColor("GtkTooltip#tooltip"); case ui::NativeTheme::kColorId_TooltipText: - return color_utils::GetReadableColor(GetFgColor("GtkTooltip.tooltip"), - GetBgColor("GtkTooltip.tooltip")); + return color_utils::GetReadableColor(GetFgColor("GtkTooltip#tooltip"), + GetBgColor("GtkTooltip#tooltip")); // Trees and Tables (implemented on GTK using the same class) case ui::NativeTheme::kColorId_TableBackground: case ui::NativeTheme::kColorId_TreeBackground: - return GetBgColor("GtkTreeView.view"); + return GetBgColor("GtkTreeView#treeview.view"); case ui::NativeTheme::kColorId_TableText: case ui::NativeTheme::kColorId_TreeText: case ui::NativeTheme::kColorId_TreeArrow: case ui::NativeTheme::kColorId_TableGroupingIndicatorColor: - return GetFgColor("GtkTreeView.view .cell"); + return GetFgColor("GtkTreeView#treeview.view .cell"); case ui::NativeTheme::kColorId_TableSelectedText: case ui::NativeTheme::kColorId_TableSelectedTextUnfocused: case ui::NativeTheme::kColorId_TreeSelectedText: case ui::NativeTheme::kColorId_TreeSelectedTextUnfocused: - return GetFgColor("GtkTreeView.view .cell:selected"); + return GetFgColor("GtkTreeView#treeview.view .cell:selected"); case ui::NativeTheme::kColorId_TableSelectionBackgroundFocused: case ui::NativeTheme::kColorId_TableSelectionBackgroundUnfocused: case ui::NativeTheme::kColorId_TreeSelectionBackgroundFocused: case ui::NativeTheme::kColorId_TreeSelectionBackgroundUnfocused: - return GetBgColor("GtkTreeView.view .cell:selected"); + return GetBgColor("GtkTreeView#treeview.view .cell:selected"); // Results Table // TODO(thomasanderson): The GtkEntry selectors was how the gtk2 theme got // these colors. Update this code to use a different widget. case ui::NativeTheme::kColorId_ResultsTableNormalBackground: - return GetBgColor("GtkEntry.entry"); + return GetBgColor("GtkEntry#entry"); case ui::NativeTheme::kColorId_ResultsTableHoveredBackground: return color_utils::AlphaBlend( - GetBgColor("GtkEntry.entry"), - GetBgColor("GtkEntry.entry .selection:selected"), 0x80); + GetBgColor("GtkEntry#entry"), + GetBgColor("GtkEntry#entry #selection:selected"), 0x80); case ui::NativeTheme::kColorId_ResultsTableSelectedBackground: - return GetBgColor("GtkEntry.entry .selection:selected"); + return GetBgColor("GtkEntry#entry #selection:selected"); case ui::NativeTheme::kColorId_ResultsTableNormalText: case ui::NativeTheme::kColorId_ResultsTableHoveredText: - return GetFgColor("GtkEntry.entry"); + return GetFgColor("GtkEntry#entry"); case ui::NativeTheme::kColorId_ResultsTableSelectedText: - return GetFgColor("GtkEntry.entry .selection:selected"); + return GetFgColor("GtkEntry#entry #selection:selected"); case ui::NativeTheme::kColorId_ResultsTableNormalDimmedText: case ui::NativeTheme::kColorId_ResultsTableHoveredDimmedText: - return color_utils::AlphaBlend(GetFgColor("GtkEntry.entry"), - GetBgColor("GtkEntry.entry"), 0x80); + return color_utils::AlphaBlend(GetFgColor("GtkEntry#entry"), + GetBgColor("GtkEntry#entry"), 0x80); case ui::NativeTheme::kColorId_ResultsTableSelectedDimmedText: return color_utils::AlphaBlend( - GetFgColor("GtkEntry.entry .selection:selected"), - GetBgColor("GtkEntry.entry"), 0x80); + GetFgColor("GtkEntry#entry #selection:selected"), + GetBgColor("GtkEntry#entry"), 0x80); case ui::NativeTheme::kColorId_ResultsTableNormalUrl: case ui::NativeTheme::kColorId_ResultsTableHoveredUrl: - return NormalURLColor(GetFgColor("GtkEntry.entry")); + return NormalURLColor(GetFgColor("GtkEntry#entry")); case ui::NativeTheme::kColorId_ResultsTableSelectedUrl: - return SelectedURLColor(GetFgColor("GtkEntry.entry .selection:selected"), - GetBgColor("GtkEntry.entry .selection:selected")); + return SelectedURLColor(GetFgColor("GtkEntry#entry #selection:selected"), + GetBgColor("GtkEntry#entry #selection:selected")); case ui::NativeTheme::kColorId_ResultsTablePositiveText: return color_utils::GetReadableColor(kPositiveTextColor, - GetBgColor("GtkEntry.entry")); + GetBgColor("GtkEntry#entry")); case ui::NativeTheme::kColorId_ResultsTablePositiveHoveredText: return color_utils::GetReadableColor(kPositiveTextColor, - GetBgColor("GtkEntry.entry:hover")); + GetBgColor("GtkEntry#entry:hover")); case ui::NativeTheme::kColorId_ResultsTablePositiveSelectedText: return color_utils::GetReadableColor( - kPositiveTextColor, GetBgColor("GtkEntry.entry:selected")); + kPositiveTextColor, GetBgColor("GtkEntry#entry:selected")); case ui::NativeTheme::kColorId_ResultsTableNegativeText: return color_utils::GetReadableColor(kNegativeTextColor, - GetBgColor("GtkEntry.entry")); + GetBgColor("GtkEntry#entry")); case ui::NativeTheme::kColorId_ResultsTableNegativeHoveredText: return color_utils::GetReadableColor(kNegativeTextColor, - GetBgColor("GtkEntry.entry:hover")); + GetBgColor("GtkEntry#entry:hover")); case ui::NativeTheme::kColorId_ResultsTableNegativeSelectedText: return color_utils::GetReadableColor( - kNegativeTextColor, GetBgColor("GtkEntry.entry:selected")); + kNegativeTextColor, GetBgColor("GtkEntry#entry:selected")); // Throbber // TODO(thomasanderson): Render GtkSpinner directly. case ui::NativeTheme::kColorId_ThrobberSpinningColor: case ui::NativeTheme::kColorId_ThrobberWaitingColor: - return GetFgColor("GtkMenu.menu GtkSpinner.spinner"); + return GetFgColor("GtkMenu#menu GtkSpinner#spinner"); case ui::NativeTheme::kColorId_ThrobberLightColor: - return GetFgColor("GtkMenu.menu GtkSpinner.spinner:disabled"); + return GetFgColor("GtkMenu#menu GtkSpinner#spinner:disabled"); // Alert icons case ui::NativeTheme::kColorId_AlertSeverityLow: - return GetBgColor("GtkInfoBar.infobar.info"); + return GetBgColor("GtkInfoBar#infobar.info"); case ui::NativeTheme::kColorId_AlertSeverityMedium: - return GetBgColor("GtkInfoBar.infobar.warning"); + return GetBgColor("GtkInfoBar#infobar.warning"); case ui::NativeTheme::kColorId_AlertSeverityHigh: - return GetBgColor("GtkInfoBar.infobar.error"); + return GetBgColor("GtkInfoBar#infobar.error"); case ui::NativeTheme::kColorId_NumColors: NOTREACHED(); @@ -338,7 +338,7 @@ SkCanvas* canvas, const gfx::Size& size, const MenuBackgroundExtraParams& menu_background) const { - PaintWidget(canvas, gfx::Rect(size), "GtkMenu.menu", GTK_STATE_FLAG_NORMAL); + PaintWidget(canvas, gfx::Rect(size), "GtkMenu#menu", GTK_STATE_FLAG_NORMAL); } void NativeThemeGtk3::PaintMenuItemBackground( @@ -346,7 +346,7 @@ State state, const gfx::Rect& rect, const MenuItemExtraParams& menu_item) const { - PaintWidget(canvas, rect, "GtkMenu.menu GtkMenuItem.menuitem", + PaintWidget(canvas, rect, "GtkMenu#menu GtkMenuItem#menuitem", StateToStateFlags(state)); }
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 5c599dd5..489d9b1 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1590,6 +1590,15 @@ base::string16 BrowserView::GetAccessibleWindowTitle() const { const bool include_app_name = false; + int active_index = browser_->tab_strip_model()->active_index(); + if (active_index > -1) { + if (IsIncognito()) { + return l10n_util::GetStringFUTF16( + IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT, + GetAccessibleTabLabel(include_app_name, active_index)); + } + return GetAccessibleTabLabel(include_app_name, active_index); + } if (IsIncognito()) { return l10n_util::GetStringFUTF16( IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT, @@ -1598,6 +1607,53 @@ return browser_->GetWindowTitleForCurrentTab(include_app_name); } +base::string16 BrowserView::GetAccessibleTabLabel(bool include_app_name, + int index) const { + // ChromeVox provides an invalid index on browser start up before + // any tabs are created. + if (index == -1) + return base::string16(); + + base::string16 window_title = + browser_->GetWindowTitleForTab(include_app_name, index); + const TabRendererData& data = tabstrip_->tab_at(index)->data(); + + // Tab has crashed. + if (data.IsCrashed()) { + return l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_CRASHED_FORMAT, + window_title); + } + // Network error interstitial. + if (data.network_state == TabRendererData::NETWORK_STATE_ERROR) { + return l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_NETWORK_ERROR_FORMAT, + window_title); + } + // Alert tab states. + switch (data.alert_state) { + case TabAlertState::AUDIO_PLAYING: + return l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_AUDIO_PLAYING_FORMAT, + window_title); + case TabAlertState::USB_CONNECTED: + return l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_USB_CONNECTED_FORMAT, + window_title); + case TabAlertState::BLUETOOTH_CONNECTED: + return l10n_util::GetStringFUTF16( + IDS_TAB_AX_LABEL_BLUETOOTH_CONNECTED_FORMAT, window_title); + case TabAlertState::MEDIA_RECORDING: + return l10n_util::GetStringFUTF16( + IDS_TAB_AX_LABEL_MEDIA_RECORDING_FORMAT, window_title); + case TabAlertState::AUDIO_MUTING: + return l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_AUDIO_MUTING_FORMAT, + window_title); + case TabAlertState::TAB_CAPTURING: + return l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_TAB_CAPTURING_FORMAT, + window_title); + case TabAlertState::NONE: + return window_title; + } + return base::string16(); +} + views::View* BrowserView::GetInitiallyFocusedView() { return nullptr; } @@ -2018,8 +2074,7 @@ // TabStrip takes ownership of the controller. BrowserTabStripController* tabstrip_controller = - new BrowserTabStripController(browser_.get(), - browser_->tab_strip_model()); + new BrowserTabStripController(browser_->tab_strip_model(), this); tabstrip_ = new TabStrip(tabstrip_controller); top_container_->AddChildView(tabstrip_); tabstrip_controller->InitFromModel(tabstrip_);
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index d9e2f429..bcfdd06 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -32,6 +32,8 @@ #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "chrome/browser/ui/views/frame/web_contents_close_handler.h" #include "chrome/browser/ui/views/load_complete_listener.h" +#include "chrome/browser/ui/views/tabs/tab.h" +#include "chrome/browser/ui/views/tabs/tab_renderer_data.h" #include "chrome/common/features.h" #include "components/omnibox/browser/omnibox_popup_model_observer.h" #include "ui/base/accelerators/accelerator.h" @@ -466,6 +468,11 @@ extensions::ActiveTabPermissionGranter* GetActiveTabPermissionGranter() override; + // Creates an accessible tab label for screen readers that includes the tab + // status for the given tab index. This takes the form of + // "Page title - Tab state". + base::string16 GetAccessibleTabLabel(bool include_app_name, int index) const; + // Testing interface: views::View* GetContentsContainerForTest() { return contents_container_; } views::WebView* GetContentsWebViewForTest() { return contents_web_view_; }
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc index 21c34beb..59d15a7 100644 --- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc +++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -22,7 +22,6 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" #include "chrome/browser/ui/tabs/tab_utils.h" -#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/tabs/tab.h" #include "chrome/browser/ui/views/tabs/tab_renderer_data.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" @@ -34,6 +33,9 @@ #include "components/omnibox/browser/autocomplete_match.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/plugin_service.h" #include "content/public/browser/user_metrics.h" @@ -54,8 +56,17 @@ TabRendererData::NetworkState TabContentsNetworkState( WebContents* contents) { - if (!contents || !contents->IsLoadingToDifferentDocument()) + if (!contents) return TabRendererData::NETWORK_STATE_NONE; + + if (!contents->IsLoadingToDifferentDocument()) { + content::NavigationEntry* entry = + contents->GetController().GetLastCommittedEntry(); + if (entry && (entry->GetPageType() == content::PAGE_TYPE_ERROR)) + return TabRendererData::NETWORK_STATE_ERROR; + return TabRendererData::NETWORK_STATE_NONE; + } + if (contents->IsWaitingForResponse()) return TabRendererData::NETWORK_STATE_WAITING; return TabRendererData::NETWORK_STATE_LOADING; @@ -179,11 +190,11 @@ //////////////////////////////////////////////////////////////////////////////// // BrowserTabStripController, public: -BrowserTabStripController::BrowserTabStripController(Browser* browser, - TabStripModel* model) +BrowserTabStripController::BrowserTabStripController(TabStripModel* model, + BrowserView* browser_view) : model_(model), tabstrip_(NULL), - browser_(browser), + browser_view_(browser_view), hover_tab_selector_(model), weak_ptr_factory_(this) { model_->AddObserver(this); @@ -337,7 +348,8 @@ void BrowserTabStripController::PerformDrop(bool drop_before, int index, const GURL& url) { - chrome::NavigateParams params(browser_, url, ui::PAGE_TRANSITION_LINK); + chrome::NavigateParams params(browser_view_->browser(), url, + ui::PAGE_TRANSITION_LINK); params.tabstrip_index = index; if (drop_before) { @@ -374,7 +386,8 @@ } bool BrowserTabStripController::IsIncognito() { - return browser_->profile()->GetProfileType() == Profile::INCOGNITO_PROFILE; + return browser_view_->browser()->profile()->GetProfileType() == + Profile::INCOGNITO_PROFILE; } void BrowserTabStripController::StackedLayoutMaybeChanged() { @@ -389,14 +402,13 @@ } void BrowserTabStripController::OnStartedDraggingTabs() { - BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_); - if (browser_view && !immersive_reveal_lock_.get()) { + if (!immersive_reveal_lock_.get()) { // The top-of-window views should be revealed while the user is dragging // tabs in immersive fullscreen. The top-of-window views may not be already // revealed if the user is attempting to attach a tab to a tabstrip // belonging to an immersive fullscreen window. immersive_reveal_lock_.reset( - browser_view->immersive_mode_controller()->GetRevealedLock( + browser_view_->immersive_mode_controller()->GetRevealedLock( ImmersiveModeController::ANIMATE_REVEAL_NO)); } } @@ -416,8 +428,13 @@ } SkColor BrowserTabStripController::GetToolbarTopSeparatorColor() const { - return BrowserView::GetBrowserViewForBrowser(browser_)->frame() - ->GetFrameView()->GetToolbarTopSeparatorColor(); + return browser_view_->frame()->GetFrameView()->GetToolbarTopSeparatorColor(); +} + +base::string16 BrowserTabStripController::GetAccessibleTabName( + const Tab* tab) const { + return browser_view_->GetAccessibleTabLabel( + false /* include_app_name */, tabstrip_->GetModelIndexOfTab(tab)); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h index 63f6bff..bde789a 100644 --- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h +++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "chrome/browser/ui/tabs/hover_tab_selector.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" #include "components/prefs/pref_change_registrar.h" @@ -33,7 +34,7 @@ class BrowserTabStripController : public TabStripController, public TabStripModelObserver { public: - BrowserTabStripController(Browser* browser, TabStripModel* model); + BrowserTabStripController(TabStripModel* model, BrowserView* browser_view); ~BrowserTabStripController() override; void InitFromModel(TabStrip* tabstrip); @@ -76,6 +77,7 @@ void OnStoppedDraggingTabs() override; void CheckFileSupported(const GURL& url) override; SkColor GetToolbarTopSeparatorColor() const override; + base::string16 GetAccessibleTabName(const Tab* tab) const override; // TabStripModelObserver implementation: void TabInsertedAt(TabStripModel* tab_strip_model, @@ -101,6 +103,8 @@ void TabBlockedStateChanged(content::WebContents* contents, int model_index) override; + const Browser* browser() const { return browser_view_->browser(); } + protected: // The context in which SetTabRendererDataFromModel is being called. enum TabStatus { @@ -118,8 +122,6 @@ const TabStrip* tabstrip() const { return tabstrip_; } - const Browser* browser() const { return browser_; } - private: class TabContextMenuContents; @@ -148,8 +150,7 @@ TabStrip* tabstrip_; - // Non-owning pointer to the browser which is using this controller. - Browser* browser_; + BrowserView* browser_view_; // If non-NULL it means we're showing a menu for the tab. std::unique_ptr<TabContextMenuContents> context_menu_contents_;
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc index 44a03a3..d4c0337 100644 --- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc +++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
@@ -148,3 +148,8 @@ SkColor FakeBaseTabStripController::GetToolbarTopSeparatorColor() const { return SK_ColorBLACK; } + +base::string16 FakeBaseTabStripController::GetAccessibleTabName( + const Tab* tab) const { + return base::string16(); +}
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h index e2ef1142..28318dfa 100644 --- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h +++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
@@ -55,6 +55,7 @@ void OnStoppedDraggingTabs() override; void CheckFileSupported(const GURL& url) override; SkColor GetToolbarTopSeparatorColor() const override; + base::string16 GetAccessibleTabName(const Tab* tab) const override; private: TabStrip* tab_strip_;
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc index 5a080a6..d88bfdfe 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -19,8 +19,11 @@ #include "chrome/browser/ui/tab_contents/core_tab_helper.h" #include "chrome/browser/ui/tabs/tab_utils.h" #include "chrome/browser/ui/view_ids.h" +#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/tabs/alert_indicator_button.h" +#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h" #include "chrome/browser/ui/views/tabs/tab_controller.h" +#include "chrome/browser/ui/views/tabs/tab_strip.h" #include "chrome/browser/ui/views/touch_uma/touch_uma.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" @@ -494,7 +497,8 @@ void Tab::ThrobberView::OnPaint(gfx::Canvas* canvas) { const TabRendererData::NetworkState state = owner_->data().network_state; - if (state == TabRendererData::NETWORK_STATE_NONE) + if (state == TabRendererData::NETWORK_STATE_NONE || + state == TabRendererData::NETWORK_STATE_ERROR) return; const ui::ThemeProvider* tp = GetThemeProvider(); @@ -674,9 +678,10 @@ void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { if (state == data_.network_state && - state == TabRendererData::NETWORK_STATE_NONE) { - // If the network state is none and hasn't changed, do nothing. Otherwise we - // need to advance the animation frame. + (state == TabRendererData::NETWORK_STATE_NONE || + state == TabRendererData::NETWORK_STATE_ERROR)) { + // If the network state is none or is a network error and hasn't changed, + // do nothing. Otherwise we need to advance the animation frame. return; } @@ -1099,7 +1104,7 @@ void Tab::GetAccessibleNodeData(ui::AXNodeData* node_data) { node_data->role = ui::AX_ROLE_TAB; - node_data->SetName(data_.title); + node_data->SetName(controller_->GetAccessibleTabName(this)); node_data->AddStateFlag(ui::AX_STATE_MULTISELECTABLE); node_data->AddStateFlag(ui::AX_STATE_SELECTABLE); controller_->UpdateTabAccessibilityState(this, node_data); @@ -1184,7 +1189,8 @@ // Paint network activity indicator. // TODO(jamescook): Replace this placeholder animation with a real one. // For now, let's go with a Cylon eye effect, but in blue. - if (data().network_state != TabRendererData::NETWORK_STATE_NONE) { + if (data().network_state != TabRendererData::NETWORK_STATE_NONE && + data().network_state != TabRendererData::NETWORK_STATE_ERROR) { const SkColor kEyeColor = SkColorSetARGB(alpha, 71, 138, 217); int eye_width = bar_rect.width() / 3; int eye_offset = bar_rect.width() * immersive_loading_step_ / @@ -1389,9 +1395,10 @@ return; // Throbber will do its own painting. - if (data().network_state != TabRendererData::NETWORK_STATE_NONE) + if (data().network_state != TabRendererData::NETWORK_STATE_NONE && + data().network_state != TabRendererData::NETWORK_STATE_ERROR) { return; - + } // Ensure that |favicon_| is created. if (favicon_.isNull()) { ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); @@ -1441,7 +1448,8 @@ return; } - if (state == TabRendererData::NETWORK_STATE_NONE) { + if (state == TabRendererData::NETWORK_STATE_NONE || + state == TabRendererData::NETWORK_STATE_ERROR) { throbber_->ResetStartTimes(); throbber_->SetVisible(false); ScheduleIconPaint();
diff --git a/chrome/browser/ui/views/tabs/tab_controller.h b/chrome/browser/ui/views/tabs/tab_controller.h index a28d5e5..872c169 100644 --- a/chrome/browser/ui/views/tabs/tab_controller.h +++ b/chrome/browser/ui/views/tabs/tab_controller.h
@@ -129,6 +129,9 @@ virtual void UpdateTabAccessibilityState(const Tab* tab, ui::AXNodeData* node_data) = 0; + // Returns the accessible tab name for this tab. + virtual base::string16 GetAccessibleTabName(const Tab* tab) const = 0; + protected: virtual ~TabController() {} };
diff --git a/chrome/browser/ui/views/tabs/tab_renderer_data.h b/chrome/browser/ui/views/tabs/tab_renderer_data.h index 829de7e..9b1d2ab 100644 --- a/chrome/browser/ui/views/tabs/tab_renderer_data.h +++ b/chrome/browser/ui/views/tabs/tab_renderer_data.h
@@ -20,6 +20,7 @@ NETWORK_STATE_NONE, // no network activity. NETWORK_STATE_WAITING, // waiting for a connection. NETWORK_STATE_LOADING, // connected, transferring data. + NETWORK_STATE_ERROR, // Encountered a network error. }; TabRendererData();
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 1e6c8ef..7f721df 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1324,6 +1324,14 @@ return controller_->GetToolbarTopSeparatorColor(); } +// Returns the accessible tab name for the tab. +base::string16 TabStrip::GetAccessibleTabName(const Tab* tab) const { + int model_index = GetModelIndexOfTab(tab); + if (IsValidModelIndex(model_index)) + return controller_->GetAccessibleTabName(tab); + return base::string16(); +} + int TabStrip::GetBackgroundResourceId(bool* custom_image) const { const ui::ThemeProvider* tp = GetThemeProvider();
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h index 6022c86..4512b4d 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.h +++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -239,6 +239,7 @@ bool CanPaintThrobberToLayer() const override; bool IsImmersiveStyle() const override; SkColor GetToolbarTopSeparatorColor() const override; + base::string16 GetAccessibleTabName(const Tab* tab) const override; int GetBackgroundResourceId(bool* custom_image) const override; void UpdateTabAccessibilityState(const Tab* tab, ui::AXNodeData* node_data) override;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_controller.h b/chrome/browser/ui/views/tabs/tab_strip_controller.h index 8e80d365..f06590b 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_controller.h +++ b/chrome/browser/ui/views/tabs/tab_strip_controller.h
@@ -123,6 +123,9 @@ // Returns COLOR_TOOLBAR_TOP_SEPARATOR[,_INACTIVE] depending on the activation // state of the window. virtual SkColor GetToolbarTopSeparatorColor() const = 0; + + // Returns the accessible tab name. + virtual base::string16 GetAccessibleTabName(const Tab* tab) const = 0; }; #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_CONTROLLER_H_
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc index e78ebde..528b802 100644 --- a/chrome/browser/ui/views/tabs/tab_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -81,6 +81,9 @@ } void UpdateTabAccessibilityState(const Tab* tab, ui::AXNodeData* node_data) override{}; + base::string16 GetAccessibleTabName(const Tab* tab) const override { + return base::string16(); + } private: ui::ListSelectionModel selection_model_;
diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc index a324f0a..0f41cca 100644 --- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc +++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc
@@ -717,10 +717,6 @@ SizeToContents(); } -void WebsiteSettingsPopupView::SetSelectedTab(TabId tab_id) { - // TODO(lgarron): Remove this method. (https://crbug.com/571533) -} - views::View* WebsiteSettingsPopupView::CreateSiteSettingsView() { views::View* site_settings_view = new views::View(); views::BoxLayout* box_layout =
diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.h b/chrome/browser/ui/views/website_settings/website_settings_popup_view.h index 7bd9379..ea6da6a 100644 --- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.h +++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.h
@@ -129,8 +129,6 @@ void SetPermissionInfo(const PermissionInfoList& permission_info_list, ChosenObjectInfoList chosen_object_info_list) override; void SetIdentityInfo(const IdentityInfo& identity_info) override; - // TODO(lgarron): Remove SetSelectedTab() with https://crbug.com/571533 - void SetSelectedTab(TabId tab_id) override; // Creates the contents of the |site_settings_view_|. The ownership of the // returned view is transferred to the caller.
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc index c9dae32d..9a7f925 100644 --- a/chrome/browser/ui/website_settings/website_settings.cc +++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -666,32 +666,6 @@ // Only show an SSL decision revoke button if the user has chosen to bypass // SSL host errors for this host in the past. show_ssl_decision_revoke_button_ = delegate->HasAllowException(url.host()); - - // By default select the Permissions Tab that displays all the site - // permissions. In case of a connection error or an issue with the certificate - // presented by the website, select the Connection Tab to draw the user's - // attention to the issue. If the site does not provide a certificate because - // it was loaded over an unencrypted connection, don't select the Connection - // Tab. - WebsiteSettingsUI::TabId tab_id = WebsiteSettingsUI::TAB_ID_PERMISSIONS; - if (site_connection_status_ == SITE_CONNECTION_STATUS_ENCRYPTED_ERROR || - site_connection_status_ == - SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE || - site_connection_status_ == - SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE || - site_identity_status_ == SITE_IDENTITY_STATUS_ERROR || - site_identity_status_ == SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN || - site_identity_status_ == SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT || - site_identity_status_ == - SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MINOR || - site_identity_status_ == - SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR) { - tab_id = WebsiteSettingsUI::TAB_ID_CONNECTION; - RecordWebsiteSettingsAction( - WEBSITE_SETTINGS_CONNECTION_TAB_SHOWN_IMMEDIATELY); - } - - ui_->SetSelectedTab(tab_id); } void WebsiteSettings::PresentSitePermissions() {
diff --git a/chrome/browser/ui/website_settings/website_settings.h b/chrome/browser/ui/website_settings/website_settings.h index 7b9b4aca..bac9695 100644 --- a/chrome/browser/ui/website_settings/website_settings.h +++ b/chrome/browser/ui/website_settings/website_settings.h
@@ -89,9 +89,11 @@ // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.pageinfo enum WebsiteSettingsAction { WEBSITE_SETTINGS_OPENED = 0, - WEBSITE_SETTINGS_PERMISSIONS_TAB_SELECTED = 1, - WEBSITE_SETTINGS_CONNECTION_TAB_SELECTED = 2, - WEBSITE_SETTINGS_CONNECTION_TAB_SHOWN_IMMEDIATELY = 3, + // No longer used; indicated actions for the old version of Page Info that + // had a "Permissions" tab and a "Connection" tab. + // WEBSITE_SETTINGS_PERMISSIONS_TAB_SELECTED = 1, + // WEBSITE_SETTINGS_CONNECTION_TAB_SELECTED = 2, + // WEBSITE_SETTINGS_CONNECTION_TAB_SHOWN_IMMEDIATELY = 3, WEBSITE_SETTINGS_COOKIES_DIALOG_OPENED = 4, WEBSITE_SETTINGS_CHANGED_PERMISSION = 5, WEBSITE_SETTINGS_CERTIFICATE_DIALOG_OPENED = 6,
diff --git a/chrome/browser/ui/website_settings/website_settings_ui.h b/chrome/browser/ui/website_settings/website_settings_ui.h index 23d11404..a656ae57 100644 --- a/chrome/browser/ui/website_settings/website_settings_ui.h +++ b/chrome/browser/ui/website_settings/website_settings_ui.h
@@ -196,9 +196,6 @@ // Sets site identity information. virtual void SetIdentityInfo(const IdentityInfo& identity_info) = 0; - - // Selects the tab with the given |tab_id|. - virtual void SetSelectedTab(TabId tab_id) = 0; }; typedef WebsiteSettingsUI::CookieInfoList CookieInfoList;
diff --git a/chrome/browser/ui/website_settings/website_settings_unittest.cc b/chrome/browser/ui/website_settings/website_settings_unittest.cc index 14631ee8..024e5ae6 100644 --- a/chrome/browser/ui/website_settings/website_settings_unittest.cc +++ b/chrome/browser/ui/website_settings/website_settings_unittest.cc
@@ -74,7 +74,6 @@ MOCK_METHOD1(SetCookieInfo, void(const CookieInfoList& cookie_info_list)); MOCK_METHOD0(SetPermissionInfoStub, void()); MOCK_METHOD1(SetIdentityInfo, void(const IdentityInfo& identity_info)); - MOCK_METHOD1(SetSelectedTab, void(TabId tab_id)); void SetPermissionInfo( const PermissionInfoList& permission_info_list, @@ -226,8 +225,6 @@ #else EXPECT_CALL(*mock_ui(), SetPermissionInfoStub()).Times(7); #endif - EXPECT_CALL(*mock_ui(), SetSelectedTab( - WebsiteSettingsUI::TAB_ID_PERMISSIONS)); // Execute code under tests. website_settings()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_POPUPS, @@ -272,8 +269,6 @@ EXPECT_CALL(*mock_ui(), SetPermissionInfoStub()); EXPECT_CALL(*mock_ui(), SetIdentityInfo(_)); EXPECT_CALL(*mock_ui(), SetCookieInfo(_)).Times(2); - EXPECT_CALL(*mock_ui(), SetSelectedTab( - WebsiteSettingsUI::TAB_ID_PERMISSIONS)); website_settings()->OnSiteDataAccessed(); } @@ -287,8 +282,6 @@ EXPECT_CALL(*mock_ui(), SetIdentityInfo(_)); EXPECT_CALL(*mock_ui(), SetCookieInfo(_)); - EXPECT_CALL(*mock_ui(), - SetSelectedTab(WebsiteSettingsUI::TAB_ID_PERMISSIONS)); // Access WebsiteSettings so that SetPermissionInfo is called once to populate // |last_chosen_object_info_|. It will be called again by @@ -310,8 +303,6 @@ security_info_.malicious_content_status = security_state::MALICIOUS_CONTENT_STATUS_MALWARE; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), - SetSelectedTab(WebsiteSettingsUI::TAB_ID_PERMISSIONS)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_UNENCRYPTED, website_settings()->site_connection_status()); @@ -324,8 +315,6 @@ security_info_.malicious_content_status = security_state::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), - SetSelectedTab(WebsiteSettingsUI::TAB_ID_PERMISSIONS)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_UNENCRYPTED, website_settings()->site_connection_status()); @@ -338,8 +327,6 @@ security_info_.malicious_content_status = security_state::MALICIOUS_CONTENT_STATUS_UNWANTED_SOFTWARE; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), - SetSelectedTab(WebsiteSettingsUI::TAB_ID_PERMISSIONS)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_UNENCRYPTED, website_settings()->site_connection_status()); @@ -349,8 +336,6 @@ TEST_F(WebsiteSettingsTest, HTTPConnection) { SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), SetSelectedTab( - WebsiteSettingsUI::TAB_ID_PERMISSIONS)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_UNENCRYPTED, website_settings()->site_connection_status()); EXPECT_EQ(WebsiteSettings::SITE_IDENTITY_STATUS_NO_CERT, @@ -370,8 +355,6 @@ security_info_.connection_status = status; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), SetSelectedTab( - WebsiteSettingsUI::TAB_ID_PERMISSIONS)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED, website_settings()->site_connection_status()); @@ -508,8 +491,6 @@ security_info_.connection_status = status; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), - SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); EXPECT_EQ(test.expected_site_connection_status, website_settings()->site_connection_status()); @@ -541,7 +522,6 @@ security_info_.connection_status = status; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); EXPECT_EQ( WebsiteSettings::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, @@ -564,7 +544,6 @@ security_info_.connection_status = status; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED, website_settings()->site_connection_status()); @@ -585,7 +564,6 @@ security_info_.connection_status = status; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED_ERROR, website_settings()->site_connection_status()); @@ -607,7 +585,6 @@ security_info_.connection_status = status; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED, website_settings()->site_connection_status()); @@ -630,7 +607,6 @@ security_state::DEPRECATED_SHA1_MINOR; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED, website_settings()->site_connection_status()); @@ -657,7 +633,6 @@ security_state::DEPRECATED_SHA1_MAJOR; SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), SetSelectedTab(WebsiteSettingsUI::TAB_ID_CONNECTION)); EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED, website_settings()->site_connection_status()); @@ -673,8 +648,6 @@ #if !defined(OS_ANDROID) TEST_F(WebsiteSettingsTest, NoInfoBar) { SetDefaultUIExpectations(mock_ui()); - EXPECT_CALL(*mock_ui(), SetSelectedTab( - WebsiteSettingsUI::TAB_ID_PERMISSIONS)); EXPECT_EQ(0u, infobar_service()->infobar_count()); website_settings()->OnUIClosing(); EXPECT_EQ(0u, infobar_service()->infobar_count()); @@ -686,8 +659,6 @@ EXPECT_CALL(*mock_ui(), SetPermissionInfoStub()).Times(2); - EXPECT_CALL(*mock_ui(), SetSelectedTab( - WebsiteSettingsUI::TAB_ID_PERMISSIONS)); EXPECT_EQ(0u, infobar_service()->infobar_count()); website_settings()->OnSitePermissionChanged( CONTENT_SETTINGS_TYPE_GEOLOCATION, CONTENT_SETTING_ALLOW); @@ -762,7 +733,7 @@ website_settings()->RecordWebsiteSettingsAction( WebsiteSettings::WebsiteSettingsAction:: - WEBSITE_SETTINGS_PERMISSIONS_TAB_SELECTED); + WEBSITE_SETTINGS_OPENED); // RecordWebsiteSettingsAction() is called during WebsiteSettings // creation in addition to the explicit RecordWebsiteSettingsAction() @@ -770,19 +741,11 @@ histograms.ExpectTotalCount(kGenericHistogram, 2); histograms.ExpectBucketCount( kGenericHistogram, - WebsiteSettings::WebsiteSettingsAction::WEBSITE_SETTINGS_OPENED, 1); - histograms.ExpectBucketCount(kGenericHistogram, - WebsiteSettings::WebsiteSettingsAction:: - WEBSITE_SETTINGS_PERMISSIONS_TAB_SELECTED, - 1); + WebsiteSettings::WebsiteSettingsAction::WEBSITE_SETTINGS_OPENED, 2); histograms.ExpectTotalCount(test.histogram_name, 2); histograms.ExpectBucketCount( test.histogram_name, - WebsiteSettings::WebsiteSettingsAction::WEBSITE_SETTINGS_OPENED, 1); - histograms.ExpectBucketCount(test.histogram_name, - WebsiteSettings::WebsiteSettingsAction:: - WEBSITE_SETTINGS_PERMISSIONS_TAB_SELECTED, - 1); + WebsiteSettings::WebsiteSettingsAction::WEBSITE_SETTINGS_OPENED, 2); } }
diff --git a/chrome/common/extensions/docs/templates/articles/desktop_notifications.html b/chrome/common/extensions/docs/templates/articles/desktop_notifications.html index ba325b0..31654ff 100644 --- a/chrome/common/extensions/docs/templates/articles/desktop_notifications.html +++ b/chrome/common/extensions/docs/templates/articles/desktop_notifications.html
@@ -48,7 +48,7 @@ "notifications" ]</b>, ... - // <strong>Note:</strong> Because of <a href="http://code.google.com/p/chromium/issues/detail?id=134315">bug 134315</a>, you must declare any images you + // <strong>Note:</strong> Because of <a href="http://bugs.chromium.org/p/chromium/issues/detail?id=134315">bug 134315</a>, you must declare any images you // want to use with createNotification() as a web accessible resource. <b> "web_accessible_resources": [ "48.png"
diff --git a/chrome/common/extensions/docs/templates/articles/faq.html b/chrome/common/extensions/docs/templates/articles/faq.html index 7ebda44a9..95ead99f 100644 --- a/chrome/common/extensions/docs/templates/articles/faq.html +++ b/chrome/common/extensions/docs/templates/articles/faq.html
@@ -6,8 +6,8 @@ <p> If you don't find an answer to your question here, try the -<a href="https://developer.chrome.com/webstore/faq">Chrome Web Store FAQ</a>, -the {{?is_apps}} +<a href="https://developer.chrome.com/webstore/faq">Chrome Web Store FAQ</a>, the +{{?is_apps}} <a href="http://stackoverflow.com/questions/tagged/google-chrome-app">[google-chrome-app] tag on Stack Overflow</a>, the <a href="http://groups.google.com/a/chromium.org/group/chromium-apps">chromium-apps group</a>, or the {{:is_apps}} @@ -404,12 +404,12 @@ Search the issue tracker at <a href="http://crbug.com">http://crbug.com</a> to see whether someone has reported a similar issue. Most issues related to - extensions are filed under <strong>Cr=Platform-Extensions</strong>, so to + extensions are filed under <strong>component=Platform>Extensions</strong>, so to look for an extension bug related to the chrome.tabs.executeScript function (for example), search for - "<code>Cr=Platform-Extensions Type=Bug chrome.tabs.executeScript</code>", + "<code>component=Platform>Extensions Type=Bug chrome.tabs.executeScript</code>", which will give you - <a href="https://code.google.com/p/chromium/issues/list?can=2&q=Cr%3DPlatform-Extensions+Type%3DBug+chrome.tabs.executeScript&colspec=ID+Pri+M+Iteration+ReleaseBlock+Cr+Status+Owner+Summary+Modified&x=m&y=releaseblock&cells=tiles"> + <a href="https://bugs.chromium.org/p/chromium/issues/list?can=2&q=component%3DPlatform>Extensions+Type%3DBug+chrome.tabs.executeScript"> this list of results</a>. </li> <li> @@ -459,12 +459,12 @@ Search the issue tracker at <a href="http://crbug.com">http://crbug.com</a> to see whether someone has requested a similar feature. Most requests related to - extensions are filed under <strong>Cr=Platform-Extensions</strong>, so to + extensions are filed under <strong>component=Platform>Extensions</strong>, so to look for an extension feature request related to keyboard shortcuts (for example), search - for "<code>Cr=Platform-Extensions Type=Feature shortcuts</code>", + for "<code>component=Platform>Extensions Type=Feature shortcuts</code>", which will give you - <a href="https://code.google.com/p/chromium/issues/list?can=2&q=Cr%3DPlatform-Extensions+Type%3DFeature+shortcuts&colspec=ID+Pri+M+Iteration+ReleaseBlock+Cr+Status+Owner+Summary+Modified&x=m&y=releaseblock&cells=tiles"> + <a href="https://bugs.chromium.org/p/chromium/issues/list?can=2&q=component%3DPlatform>Extensions+Type%3DFeature+shortcuts"> this list of results</a>. </li> <li>
diff --git a/chrome/test/data/android/payments/email_and_phone.js b/chrome/test/data/android/payments/email_and_phone.js new file mode 100644 index 0000000..bc76e72 --- /dev/null +++ b/chrome/test/data/android/payments/email_and_phone.js
@@ -0,0 +1,34 @@ +/* + * 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. + */ + +/* global PaymentRequest:false */ + +/* + * Launches the PaymentRequest UI that requests email address and phone number. + */ +function buy() { // eslint-disable-line no-unused-vars + try { + new PaymentRequest( + [{supportedMethods: ['https://bobpay.com']}], + {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}}, + {requestPayerEmail: true, requestPayerPhone: true}) + .show() + .then(function(resp) { + resp.complete('success') + .then(function() { + print(JSON.stringify(resp, undefined, 2)); + }) + .catch(function(error) { + print(error); + }); + }) + .catch(function(error) { + print(error); + }); + } catch (error) { + print(error.message); + } +}
diff --git a/chrome/test/data/android/payments/payment_request_email_and_phone_test.html b/chrome/test/data/android/payments/payment_request_email_and_phone_test.html new file mode 100644 index 0000000..2c65337 --- /dev/null +++ b/chrome/test/data/android/payments/payment_request_email_and_phone_test.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<head> +<title>Email and Phone Test</title> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> +<link rel="stylesheet" type="text/css" href="style.css"> +</head> +<body> +<button onclick="buy()" id="buy">Email and Phone Test</button> +<pre id="result"></pre> +<script src="util.js"></script> +<script src="email_and_phone.js"></script> +</body> +</html>
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn index b0b18ab..26bcf8f 100644 --- a/chromecast/media/cma/backend/BUILD.gn +++ b/chromecast/media/cma/backend/BUILD.gn
@@ -54,6 +54,8 @@ "cast_media_default.cc", "media_pipeline_backend_default.cc", "media_pipeline_backend_default.h", + "media_sink_default.cc", + "media_sink_default.h", "video_decoder_default.cc", "video_decoder_default.h", ] @@ -62,6 +64,7 @@ "//base", "//chromecast/base", "//chromecast/public/media", + "//media", ] }
diff --git a/chromecast/media/cma/backend/audio_decoder_default.cc b/chromecast/media/cma/backend/audio_decoder_default.cc index 58504df2..84388d7 100644 --- a/chromecast/media/cma/backend/audio_decoder_default.cc +++ b/chromecast/media/cma/backend/audio_decoder_default.cc
@@ -4,42 +4,45 @@ #include "chromecast/media/cma/backend/audio_decoder_default.h" -#include <limits> - -#include "base/bind.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/threading/thread_task_runner_handle.h" -#include "chromecast/public/media/cast_decoder_buffer.h" +#include "base/memory/ptr_util.h" +#include "chromecast/media/cma/backend/media_sink_default.h" namespace chromecast { namespace media { -AudioDecoderDefault::AudioDecoderDefault() - : delegate_(nullptr), - last_push_pts_(std::numeric_limits<int64_t>::min()), - weak_factory_(this) {} +AudioDecoderDefault::AudioDecoderDefault() : delegate_(nullptr) {} AudioDecoderDefault::~AudioDecoderDefault() {} +void AudioDecoderDefault::Start(base::TimeDelta start_pts) { + DCHECK(!sink_); + sink_ = base::MakeUnique<MediaSinkDefault>(delegate_, start_pts); +} + +void AudioDecoderDefault::Stop() { + DCHECK(sink_); + sink_.reset(); +} + +void AudioDecoderDefault::SetPlaybackRate(float rate) { + DCHECK(sink_); + sink_->SetPlaybackRate(rate); +} + +base::TimeDelta AudioDecoderDefault::GetCurrentPts() { + DCHECK(sink_); + return sink_->GetCurrentPts(); +} + void AudioDecoderDefault::SetDelegate(Delegate* delegate) { - DCHECK(delegate); + DCHECK(!sink_); delegate_ = delegate; } MediaPipelineBackend::BufferStatus AudioDecoderDefault::PushBuffer( CastDecoderBuffer* buffer) { - DCHECK(delegate_); - DCHECK(buffer); - - if (buffer->end_of_stream()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&AudioDecoderDefault::OnEndOfStream, - weak_factory_.GetWeakPtr())); - } else { - last_push_pts_ = buffer->timestamp(); - } - return MediaPipelineBackend::kBufferSuccess; + DCHECK(sink_); + return sink_->PushBuffer(buffer); } void AudioDecoderDefault::GetStatistics(Statistics* statistics) { @@ -57,9 +60,5 @@ return RenderingDelay(); } -void AudioDecoderDefault::OnEndOfStream() { - delegate_->OnEndOfStream(); -} - } // namespace media } // namespace chromecast
diff --git a/chromecast/media/cma/backend/audio_decoder_default.h b/chromecast/media/cma/backend/audio_decoder_default.h index ea712dad..142de3b9 100644 --- a/chromecast/media/cma/backend/audio_decoder_default.h +++ b/chromecast/media/cma/backend/audio_decoder_default.h
@@ -5,21 +5,26 @@ #ifndef CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_DECODER_DEFAULT_H_ #define CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_DECODER_DEFAULT_H_ -#include <stdint.h> +#include <memory> #include "base/macros.h" -#include "base/memory/weak_ptr.h" +#include "base/time/time.h" #include "chromecast/public/media/media_pipeline_backend.h" namespace chromecast { namespace media { +class MediaSinkDefault; + class AudioDecoderDefault : public MediaPipelineBackend::AudioDecoder { public: AudioDecoderDefault(); ~AudioDecoderDefault() override; - int64_t last_push_pts() const { return last_push_pts_; } + void Start(base::TimeDelta start_pts); + void Stop(); + void SetPlaybackRate(float rate); + base::TimeDelta GetCurrentPts(); // MediaPipelineBackend::AudioDecoder implementation: void SetDelegate(Delegate* delegate) override; @@ -31,12 +36,8 @@ RenderingDelay GetRenderingDelay() override; private: - void OnEndOfStream(); - Delegate* delegate_; - int64_t last_push_pts_; - base::WeakPtrFactory<AudioDecoderDefault> weak_factory_; - + std::unique_ptr<MediaSinkDefault> sink_; DISALLOW_COPY_AND_ASSIGN(AudioDecoderDefault); };
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_default.cc b/chromecast/media/cma/backend/media_pipeline_backend_default.cc index f47e2cd..b41cd4c8 100644 --- a/chromecast/media/cma/backend/media_pipeline_backend_default.cc +++ b/chromecast/media/cma/backend/media_pipeline_backend_default.cc
@@ -4,95 +4,115 @@ #include "chromecast/media/cma/backend/media_pipeline_backend_default.h" -#include <algorithm> -#include <limits> - +#include "base/logging.h" +#include "base/memory/ptr_util.h" #include "chromecast/media/cma/backend/audio_decoder_default.h" #include "chromecast/media/cma/backend/video_decoder_default.h" -#include "chromecast/public/media/cast_decoder_buffer.h" +#include "media/base/timestamp_constants.h" namespace chromecast { namespace media { MediaPipelineBackendDefault::MediaPipelineBackendDefault() - : start_pts_(std::numeric_limits<int64_t>::min()), - running_(false), - rate_(1.0f) {} + : state_(kStateUninitialized), rate_(1.0f) {} MediaPipelineBackendDefault::~MediaPipelineBackendDefault() { } MediaPipelineBackend::AudioDecoder* MediaPipelineBackendDefault::CreateAudioDecoder() { + DCHECK_EQ(kStateUninitialized, state_); DCHECK(!audio_decoder_); - audio_decoder_.reset(new AudioDecoderDefault()); + audio_decoder_ = base::MakeUnique<AudioDecoderDefault>(); return audio_decoder_.get(); } MediaPipelineBackend::VideoDecoder* MediaPipelineBackendDefault::CreateVideoDecoder() { + DCHECK_EQ(kStateUninitialized, state_); DCHECK(!video_decoder_); - video_decoder_.reset(new VideoDecoderDefault()); + video_decoder_ = base::MakeUnique<VideoDecoderDefault>(); return video_decoder_.get(); } bool MediaPipelineBackendDefault::Initialize() { + DCHECK_EQ(kStateUninitialized, state_); + state_ = kStateInitialized; return true; } bool MediaPipelineBackendDefault::Start(int64_t start_pts) { - DCHECK(!running_); - start_pts_ = start_pts; - start_clock_ = base::TimeTicks::Now(); - running_ = true; + DCHECK_EQ(kStateInitialized, state_); + if (!audio_decoder_ && !video_decoder_) + return false; + + if (audio_decoder_) { + audio_decoder_->Start(base::TimeDelta::FromMicroseconds(start_pts)); + audio_decoder_->SetPlaybackRate(rate_); + } + if (video_decoder_) { + video_decoder_->Start(base::TimeDelta::FromMicroseconds(start_pts)); + video_decoder_->SetPlaybackRate(rate_); + } + state_ = kStatePlaying; return true; } void MediaPipelineBackendDefault::Stop() { - start_pts_ = GetCurrentPts(); - running_ = false; + DCHECK(state_ == kStatePlaying || state_ == kStatePaused); + if (audio_decoder_) + audio_decoder_->Stop(); + if (video_decoder_) + video_decoder_->Stop(); + state_ = kStateInitialized; } bool MediaPipelineBackendDefault::Pause() { - DCHECK(running_); - start_pts_ = GetCurrentPts(); - running_ = false; + DCHECK_EQ(kStatePlaying, state_); + if (audio_decoder_) + audio_decoder_->SetPlaybackRate(0.0f); + if (video_decoder_) + video_decoder_->SetPlaybackRate(0.0f); + state_ = kStatePaused; return true; } bool MediaPipelineBackendDefault::Resume() { - DCHECK(!running_); - running_ = true; - start_clock_ = base::TimeTicks::Now(); + DCHECK_EQ(kStatePaused, state_); + if (audio_decoder_) + audio_decoder_->SetPlaybackRate(rate_); + if (video_decoder_) + video_decoder_->SetPlaybackRate(rate_); + state_ = kStatePlaying; return true; } int64_t MediaPipelineBackendDefault::GetCurrentPts() { - if (!running_) - return start_pts_; + base::TimeDelta current_pts = ::media::kNoTimestamp; - if (audio_decoder_ && - audio_decoder_->last_push_pts() != std::numeric_limits<int64_t>::min()) { - start_pts_ = std::min(start_pts_, audio_decoder_->last_push_pts()); - } - if (video_decoder_ && - video_decoder_->last_push_pts() != std::numeric_limits<int64_t>::min()) { - start_pts_ = std::min(start_pts_, video_decoder_->last_push_pts()); + if (audio_decoder_ && video_decoder_) { + current_pts = std::min(audio_decoder_->GetCurrentPts(), + video_decoder_->GetCurrentPts()); + } else if (audio_decoder_) { + current_pts = audio_decoder_->GetCurrentPts(); + } else if (video_decoder_) { + current_pts = video_decoder_->GetCurrentPts(); } - base::TimeTicks now = base::TimeTicks::Now(); - base::TimeDelta interpolated_media_time = - base::TimeDelta::FromMicroseconds(start_pts_) + - (now - start_clock_) * rate_; - - return interpolated_media_time.InMicroseconds(); + return current_pts.InMicroseconds(); } bool MediaPipelineBackendDefault::SetPlaybackRate(float rate) { DCHECK_GT(rate, 0.0f); - start_pts_ = GetCurrentPts(); - start_clock_ = base::TimeTicks::Now(); rate_ = rate; + + if (state_ == kStatePlaying) { + if (audio_decoder_) + audio_decoder_->SetPlaybackRate(rate_); + if (video_decoder_) + video_decoder_->SetPlaybackRate(rate_); + } + return true; }
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_default.h b/chromecast/media/cma/backend/media_pipeline_backend_default.h index c838797..b1a44287 100644 --- a/chromecast/media/cma/backend/media_pipeline_backend_default.h +++ b/chromecast/media/cma/backend/media_pipeline_backend_default.h
@@ -10,7 +10,6 @@ #include <memory> #include "base/macros.h" -#include "base/time/time.h" #include "chromecast/public/media/media_pipeline_backend.h" namespace chromecast { @@ -24,7 +23,6 @@ MediaPipelineBackendDefault(); ~MediaPipelineBackendDefault() override; - bool running() const { return running_; } const AudioDecoderDefault* audio_decoder() const { return audio_decoder_.get(); } @@ -44,11 +42,14 @@ bool SetPlaybackRate(float rate) override; private: - int64_t start_pts_; - base::TimeTicks start_clock_; - bool running_; + enum State { + kStateUninitialized, + kStateInitialized, + kStatePlaying, + kStatePaused, + }; + State state_; float rate_; - std::unique_ptr<AudioDecoderDefault> audio_decoder_; std::unique_ptr<VideoDecoderDefault> video_decoder_;
diff --git a/chromecast/media/cma/backend/media_sink_default.cc b/chromecast/media/cma/backend/media_sink_default.cc new file mode 100644 index 0000000..61d58c6 --- /dev/null +++ b/chromecast/media/cma/backend/media_sink_default.cc
@@ -0,0 +1,89 @@ +// 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 "chromecast/media/cma/backend/media_sink_default.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chromecast/public/media/cast_decoder_buffer.h" +#include "media/base/timestamp_constants.h" + +namespace chromecast { +namespace media { + +MediaSinkDefault::MediaSinkDefault( + MediaPipelineBackend::Decoder::Delegate* delegate, + base::TimeDelta start_pts) + : delegate_(delegate), + time_interpolator_(&tick_clock_), + playback_rate_(1.0f), + last_frame_pts_(start_pts), + received_eos_(false) { + DCHECK(delegate_); + time_interpolator_.SetPlaybackRate(playback_rate_); + time_interpolator_.SetBounds(start_pts, start_pts, tick_clock_.NowTicks()); + time_interpolator_.StartInterpolating(); +} + +MediaSinkDefault::~MediaSinkDefault() {} + +void MediaSinkDefault::SetPlaybackRate(float rate) { + DCHECK_GE(rate, 0.0f); + playback_rate_ = rate; + time_interpolator_.SetPlaybackRate(playback_rate_); + + // Changing the playback rate affects the delay after which EOS callback + // should run. Reschedule the task according to the new delay. + if (received_eos_) { + eos_task_.Cancel(); + ScheduleEndOfStreamTask(); + } +} + +base::TimeDelta MediaSinkDefault::GetCurrentPts() { + return time_interpolator_.GetInterpolatedTime(); +} + +MediaPipelineBackend::BufferStatus MediaSinkDefault::PushBuffer( + CastDecoderBuffer* buffer) { + if (buffer->end_of_stream()) { + received_eos_ = true; + ScheduleEndOfStreamTask(); + return MediaPipelineBackend::kBufferSuccess; + } + + // This is wrong on several levels. + // 1. The correct PTS should be buffer->timestamp() + buffer->duration(). + // But CastDecoderBuffer does not expose duration unlike + // ::media::DecoderBuffer. + // 2. The PTS reported by GetCurrentPts should not move backwards. + // It should be clamped in the range [start_pts, last_frame_pts_]. + // But doing so makes several AudioVideoPipelineDeviceTest cases fail. + // Those tests are wrong should be fixed. + // TODO(alokp): Fix these issues when the next version of CMA backend is + // scheduled to roll out. crbug.com/678394 + last_frame_pts_ = base::TimeDelta::FromMicroseconds(buffer->timestamp()); + time_interpolator_.SetUpperBound(last_frame_pts_); + return MediaPipelineBackend::kBufferSuccess; +} + +void MediaSinkDefault::ScheduleEndOfStreamTask() { + DCHECK(received_eos_); + DCHECK(eos_task_.IsCancelled()); + + // Do not schedule if playback is paused. + if (playback_rate_ == 0.0f) + return; + + eos_task_.Reset( + base::Bind(&MediaPipelineBackend::Decoder::Delegate::OnEndOfStream, + base::Unretained(delegate_))); + base::TimeDelta delay = (last_frame_pts_ - GetCurrentPts()) / playback_rate_; + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, eos_task_.callback(), delay); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/media_sink_default.h b/chromecast/media/cma/backend/media_sink_default.h new file mode 100644 index 0000000..89f7c7b --- /dev/null +++ b/chromecast/media/cma/backend/media_sink_default.h
@@ -0,0 +1,44 @@ +// 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 CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_SINK_DEFAULT_H_ +#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_SINK_DEFAULT_H_ + +#include "base/cancelable_callback.h" +#include "base/macros.h" +#include "base/time/default_tick_clock.h" +#include "chromecast/public/media/media_pipeline_backend.h" +#include "media/base/time_delta_interpolator.h" + +namespace chromecast { +namespace media { + +class MediaSinkDefault { + public: + MediaSinkDefault(MediaPipelineBackend::Decoder::Delegate* delegate, + base::TimeDelta start_pts); + ~MediaSinkDefault(); + + void SetPlaybackRate(float rate); + base::TimeDelta GetCurrentPts(); + MediaPipelineBackend::BufferStatus PushBuffer(CastDecoderBuffer* buffer); + + private: + void ScheduleEndOfStreamTask(); + + MediaPipelineBackend::Decoder::Delegate* delegate_; + base::DefaultTickClock tick_clock_; + ::media::TimeDeltaInterpolator time_interpolator_; + float playback_rate_; + base::TimeDelta last_frame_pts_; + bool received_eos_; + base::CancelableClosure eos_task_; + + DISALLOW_COPY_AND_ASSIGN(MediaSinkDefault); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_SINK_DEFAULT_H_
diff --git a/chromecast/media/cma/backend/video_decoder_default.cc b/chromecast/media/cma/backend/video_decoder_default.cc index 552c7b5..60ee8a5b 100644 --- a/chromecast/media/cma/backend/video_decoder_default.cc +++ b/chromecast/media/cma/backend/video_decoder_default.cc
@@ -4,41 +4,45 @@ #include "chromecast/media/cma/backend/video_decoder_default.h" -#include <limits> - -#include "base/bind.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/threading/thread_task_runner_handle.h" -#include "chromecast/public/media/cast_decoder_buffer.h" +#include "base/memory/ptr_util.h" +#include "chromecast/media/cma/backend/media_sink_default.h" namespace chromecast { namespace media { -VideoDecoderDefault::VideoDecoderDefault() - : delegate_(nullptr), - last_push_pts_(std::numeric_limits<int64_t>::min()), - weak_factory_(this) {} +VideoDecoderDefault::VideoDecoderDefault() {} VideoDecoderDefault::~VideoDecoderDefault() {} +void VideoDecoderDefault::Start(base::TimeDelta start_pts) { + DCHECK(!sink_); + sink_ = base::MakeUnique<MediaSinkDefault>(delegate_, start_pts); +} + +void VideoDecoderDefault::Stop() { + DCHECK(sink_); + sink_.reset(); +} + +void VideoDecoderDefault::SetPlaybackRate(float rate) { + DCHECK(sink_); + sink_->SetPlaybackRate(rate); +} + +base::TimeDelta VideoDecoderDefault::GetCurrentPts() { + DCHECK(sink_); + return sink_->GetCurrentPts(); +} + void VideoDecoderDefault::SetDelegate(Delegate* delegate) { - DCHECK(delegate); + DCHECK(!sink_); delegate_ = delegate; } MediaPipelineBackend::BufferStatus VideoDecoderDefault::PushBuffer( CastDecoderBuffer* buffer) { - DCHECK(delegate_); - DCHECK(buffer); - if (buffer->end_of_stream()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&VideoDecoderDefault::OnEndOfStream, - weak_factory_.GetWeakPtr())); - } else { - last_push_pts_ = buffer->timestamp(); - } - return MediaPipelineBackend::kBufferSuccess; + DCHECK(sink_); + return sink_->PushBuffer(buffer); } void VideoDecoderDefault::GetStatistics(Statistics* statistics) { @@ -48,9 +52,5 @@ return true; } -void VideoDecoderDefault::OnEndOfStream() { - delegate_->OnEndOfStream(); -} - } // namespace media } // namespace chromecast
diff --git a/chromecast/media/cma/backend/video_decoder_default.h b/chromecast/media/cma/backend/video_decoder_default.h index b56a485..d91b1a2 100644 --- a/chromecast/media/cma/backend/video_decoder_default.h +++ b/chromecast/media/cma/backend/video_decoder_default.h
@@ -5,21 +5,26 @@ #ifndef CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_DECODER_DEFAULT_H_ #define CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_DECODER_DEFAULT_H_ -#include <stdint.h> +#include <memory> #include "base/macros.h" -#include "base/memory/weak_ptr.h" +#include "base/time/time.h" #include "chromecast/public/media/media_pipeline_backend.h" namespace chromecast { namespace media { +class MediaSinkDefault; + class VideoDecoderDefault : public MediaPipelineBackend::VideoDecoder { public: VideoDecoderDefault(); ~VideoDecoderDefault() override; - int64_t last_push_pts() const { return last_push_pts_; } + void Start(base::TimeDelta start_pts); + void Stop(); + void SetPlaybackRate(float rate); + base::TimeDelta GetCurrentPts(); // MediaPipelineBackend::VideoDecoder implementation: void SetDelegate(Delegate* delegate) override; @@ -29,12 +34,8 @@ bool SetConfig(const VideoConfig& config) override; private: - void OnEndOfStream(); - Delegate* delegate_; - int64_t last_push_pts_; - base::WeakPtrFactory<VideoDecoderDefault> weak_factory_; - + std::unique_ptr<MediaSinkDefault> sink_; DISALLOW_COPY_AND_ASSIGN(VideoDecoderDefault); };
diff --git a/components/error_page/common/localized_error.cc b/components/error_page/common/localized_error.cc index a420821..5192a11 100644 --- a/components/error_page/common/localized_error.cc +++ b/components/error_page/common/localized_error.cc
@@ -1037,8 +1037,9 @@ } #if defined(OS_ANDROID) - if (!reload_visible && !show_saved_copy_visible && !is_incognito && - failed_url.is_valid() && failed_url.SchemeIsHTTPOrHTTPS() && + if (!is_post && !reload_visible && !show_saved_copy_visible && + !is_incognito && failed_url.is_valid() && + failed_url.SchemeIsHTTPOrHTTPS() && offline_pages::IsOfflinePagesAsyncDownloadEnabled()) { std::unique_ptr<base::DictionaryValue> download_button = base::MakeUnique<base::DictionaryValue>();
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc index 3b798c5c..5bd7702 100644 --- a/components/safe_browsing_db/v4_local_database_manager.cc +++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -535,6 +535,7 @@ } // Post on the IO thread to enforce async behavior. + pending_clients_.insert(check->client); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&V4LocalDatabaseManager::PerformFullHashCheck, this, @@ -603,8 +604,6 @@ DCHECK(enabled_); DCHECK(!full_hash_to_store_and_hash_prefixes.empty()); - pending_clients_.insert(check->client); - v4_get_hash_protocol_manager_->GetFullHashes( full_hash_to_store_and_hash_prefixes, base::Bind(&V4LocalDatabaseManager::OnFullHashResponse, @@ -613,23 +612,32 @@ void V4LocalDatabaseManager::ProcessQueuedChecks() { DCHECK_CURRENTLY_ON(BrowserThread::IO); - for (auto& it : queued_checks_) { + + // Steal the queue to protect against reentrant CancelCheck() calls. + QueuedChecks checks; + checks.swap(queued_checks_); + + for (auto& it : checks) { FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes; if (!GetPrefixMatches(it, &full_hash_to_store_and_hash_prefixes)) { RespondToClient(std::move(it)); } else { + pending_clients_.insert(it->client); PerformFullHashCheck(std::move(it), full_hash_to_store_and_hash_prefixes); } } - queued_checks_.clear(); } void V4LocalDatabaseManager::RespondSafeToQueuedChecks() { DCHECK_CURRENTLY_ON(BrowserThread::IO); - for (std::unique_ptr<PendingCheck>& it : queued_checks_) { + + // Steal the queue to protect against reentrant CancelCheck() calls. + QueuedChecks checks; + checks.swap(queued_checks_); + + for (std::unique_ptr<PendingCheck>& it : checks) { RespondToClient(std::move(it)); } - queued_checks_.clear(); } void V4LocalDatabaseManager::RespondToClient(
diff --git a/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/components/safe_browsing_db/v4_local_database_manager_unittest.cc index 3b03db0e..3b1a68619 100644 --- a/components/safe_browsing_db/v4_local_database_manager_unittest.cc +++ b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -6,6 +6,7 @@ #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/run_loop.h" +#include "base/strings/stringprintf.h" #include "base/test/test_simple_task_runner.h" #include "components/safe_browsing_db/v4_database.h" #include "components/safe_browsing_db/v4_local_database_manager.h" @@ -27,6 +28,16 @@ return full_hashes[0]; } +// A fullhash response containing no matches. +std::string GetEmptyV4HashResponse() { + FindFullHashesResponse res; + res.mutable_negative_cache_duration()->set_seconds(600); + + std::string res_data; + res.SerializeToString(&res_data); + return res_data; +} + } // namespace class FakeV4Database : public V4Database { @@ -96,18 +107,29 @@ class TestClient : public SafeBrowsingDatabaseManager::Client { public: - TestClient(SBThreatType sb_threat_type, const GURL& url) - : expected_sb_threat_type(sb_threat_type), expected_url(url) {} + TestClient(SBThreatType sb_threat_type, + const GURL& url, + V4LocalDatabaseManager* manager_to_cancel = nullptr) + : expected_sb_threat_type(sb_threat_type), + expected_url(url), + result_received_(false), + manager_to_cancel_(manager_to_cancel) {} void OnCheckBrowseUrlResult(const GURL& url, SBThreatType threat_type, const ThreatMetadata& metadata) override { DCHECK_EQ(expected_url, url); DCHECK_EQ(expected_sb_threat_type, threat_type); + result_received_ = true; + if (manager_to_cancel_) { + manager_to_cancel_->CancelCheck(this); + } } SBThreatType expected_sb_threat_type; GURL expected_url; + bool result_received_; + V4LocalDatabaseManager* manager_to_cancel_; }; class FakeV4LocalDatabaseManager : public V4LocalDatabaseManager { @@ -348,6 +370,80 @@ EXPECT_TRUE(GetQueuedChecks().empty()); } +// Verify that a window where checks cannot be cancelled is closed. +TEST_F(V4LocalDatabaseManagerTest, CancelPending) { + WaitForTasksOnTaskRunner(); + net::FakeURLFetcherFactory factory(NULL); + // TODO(shess): Modify this to use a mock protocol manager instead + // of faking the requests. + const char* kReqs[] = { + // OSX + "Cg8KCHVuaXR0ZXN0EgMxLjAaJwgBCAIIAwgGCAcICAgJCAoQBBAIGgcKBWVXGg-" + "pIAEgAyAEIAUgBg==", + + // Linux + "Cg8KCHVuaXR0ZXN0EgMxLjAaJwgBCAIIAwgGCAcICAgJCAoQAhAIGgcKBWVXGg-" + "pIAEgAyAEIAUgBg==", + + // Windows + "Cg8KCHVuaXR0ZXN0EgMxLjAaJwgBCAIIAwgGCAcICAgJCAoQARAIGgcKBWVXGg-" + "pIAEgAyAEIAUgBg==", + }; + for (const char* req : kReqs) { + const GURL url( + base::StringPrintf("https://safebrowsing.googleapis.com/v4/" + "fullHashes:find?$req=%s" + "&$ct=application/x-protobuf&key=test_key_param", + req)); + factory.SetFakeResponse(url, GetEmptyV4HashResponse(), net::HTTP_OK, + net::URLRequestStatus::SUCCESS); + } + + const GURL url("http://example.com/a/"); + const HashPrefix hash_prefix("eW\x1A\xF\xA9"); + + StoreAndHashPrefixes store_and_hash_prefixes; + store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), hash_prefix); + ReplaceV4Database(store_and_hash_prefixes); + + // Test that a request flows through to the callback. + { + TestClient client(SB_THREAT_TYPE_SAFE, url); + EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url, &client)); + EXPECT_FALSE(client.result_received_); + WaitForTasksOnTaskRunner(); + EXPECT_TRUE(client.result_received_); + } + + // Test that cancel prevents the callback from being called. + { + TestClient client(SB_THREAT_TYPE_SAFE, url); + EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url, &client)); + v4_local_database_manager_->CancelCheck(&client); + EXPECT_FALSE(client.result_received_); + WaitForTasksOnTaskRunner(); + EXPECT_FALSE(client.result_received_); + } +} + +// When the database load flushes the queued requests, make sure that +// CancelCheck() is not fatal in the client callback. +TEST_F(V4LocalDatabaseManagerTest, CancelQueued) { + const GURL url("http://example.com/a/"); + + TestClient client1(SB_THREAT_TYPE_SAFE, url, + v4_local_database_manager_.get()); + TestClient client2(SB_THREAT_TYPE_SAFE, url); + EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url, &client1)); + EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url, &client2)); + EXPECT_EQ(2ul, GetQueuedChecks().size()); + EXPECT_FALSE(client1.result_received_); + EXPECT_FALSE(client2.result_received_); + WaitForTasksOnTaskRunner(); + EXPECT_TRUE(client1.result_received_); + EXPECT_TRUE(client2.result_received_); +} + // This test is somewhat similar to TestCheckBrowseUrlWithFakeDbReturnsMatch but // it uses a fake V4LocalDatabaseManager to assert that PerformFullHashCheck is // called async.
diff --git a/content/renderer/presentation/presentation_dispatcher.h b/content/renderer/presentation/presentation_dispatcher.h index 91dba49..6b6e1b3 100644 --- a/content/renderer/presentation/presentation_dispatcher.h +++ b/content/renderer/presentation/presentation_dispatcher.h
@@ -36,6 +36,8 @@ namespace content { +class TestPresentationDispatcher; + // PresentationDispatcher is a delegate for Presentation API messages used by // Blink. It forwards the calls to the Mojo PresentationService. class CONTENT_EXPORT PresentationDispatcher @@ -47,6 +49,21 @@ ~PresentationDispatcher() override; private: + friend class TestPresentationDispatcher; + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, TestStartSession); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, TestStartSessionError); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, TestJoinSession); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, TestJoinSessionError); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, TestSendString); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, TestSendArrayBuffer); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, TestSendBlobData); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, TestCloseSession); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, TestTerminateSession); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, + TestListenForScreenAvailability); + FRIEND_TEST_ALL_PREFIXES(PresentationDispatcherTest, + TestSetDefaultPresentationUrls); + struct SendMessageRequest { SendMessageRequest(blink::mojom::PresentationSessionInfoPtr session_info, blink::mojom::ConnectionMessagePtr message); @@ -137,7 +154,7 @@ void DoSendMessage(SendMessageRequest* request); void HandleSendMessageRequests(bool success); - void ConnectToPresentationServiceIfNeeded(); + virtual void ConnectToPresentationServiceIfNeeded(); void UpdateListeningState();
diff --git a/content/renderer/presentation/presentation_dispatcher_unittest.cc b/content/renderer/presentation/presentation_dispatcher_unittest.cc new file mode 100644 index 0000000..9397f85 --- /dev/null +++ b/content/renderer/presentation/presentation_dispatcher_unittest.cc
@@ -0,0 +1,409 @@ +// 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 <memory> +#include <utility> + +#include "base/run_loop.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "content/renderer/presentation/presentation_dispatcher.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationAvailabilityObserver.h" +#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationError.h" +#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationSessionInfo.h" +#include "third_party/WebKit/public/web/WebArrayBuffer.h" + +using ::testing::_; +using ::testing::Invoke; +using blink::WebArrayBuffer; +using blink::WebPresentationAvailabilityCallbacks; +using blink::WebPresentationAvailabilityObserver; +using blink::WebPresentationConnectionCallback; +using blink::WebPresentationError; +using blink::WebPresentationSessionInfo; +using blink::WebString; +using blink::WebURL; +using blink::WebVector; +using blink::mojom::PresentationError; +using blink::mojom::PresentationErrorPtr; +using blink::mojom::PresentationErrorType; +using blink::mojom::PresentationService; +using blink::mojom::PresentationServiceClientPtr; +using blink::mojom::PresentationSessionInfo; +using blink::mojom::PresentationSessionInfoPtr; +using blink::mojom::ConnectionMessage; +using blink::mojom::ConnectionMessagePtr; + +// TODO(crbug.com/576808): Add test cases for the following: +// - State changes +// - Messages received +// - Discarding queued messages when the frame navigates +// - Screen availability not supported +// - Default presentation starting + +namespace content { + +class MockPresentationAvailabilityObserver + : public WebPresentationAvailabilityObserver { + public: + explicit MockPresentationAvailabilityObserver(WebURL url) : url_(url) {} + ~MockPresentationAvailabilityObserver() override {} + + MOCK_METHOD1(availabilityChanged, void(bool is_available)); + const WebURL url() const override { return url_; } + + private: + const WebURL url_; +}; + +class MockPresentationService : public PresentationService { + public: + void SetClient(PresentationServiceClientPtr client) override {} + MOCK_METHOD1(SetDefaultPresentationUrls, + void(const std::vector<GURL>& presentation_urls)); + MOCK_METHOD1(ListenForScreenAvailability, void(const GURL& availability_url)); + MOCK_METHOD1(StopListeningForScreenAvailability, + void(const GURL& availability_url)); + MOCK_METHOD2(StartSession, + void(const std::vector<GURL>& presentation_urls, + const StartSessionCallback& callback)); + MOCK_METHOD3(JoinSession, + void(const std::vector<GURL>& presentation_urls, + const base::Optional<std::string>& presentation_id, + const JoinSessionCallback& callback)); + + // *Internal method is to work around lack of support for move-only types in + // GMock. + void SendConnectionMessage( + PresentationSessionInfoPtr session_info, + ConnectionMessagePtr message_request, + const SendConnectionMessageCallback& callback) override { + SendConnectionMessageInternal(session_info.get(), message_request.get(), + callback); + } + MOCK_METHOD3(SendConnectionMessageInternal, + void(PresentationSessionInfo* session_info, + ConnectionMessage* message_request, + const SendConnectionMessageCallback& callback)); + + MOCK_METHOD2(CloseConnection, + void(const GURL& presentation_url, + const std::string& presentation_id)); + MOCK_METHOD2(Terminate, + void(const GURL& presentation_url, + const std::string& presentation_id)); + + // *Internal method is to work around lack of support for move-only types in + // GMock. + void ListenForConnectionMessages( + PresentationSessionInfoPtr session_info) override { + ListenForConnectionMessagesInternal(session_info.get()); + } + MOCK_METHOD1(ListenForConnectionMessagesInternal, + void(PresentationSessionInfo* session_info)); +}; + +class TestWebPresentationConnectionCallback + : public WebPresentationConnectionCallback { + public: + TestWebPresentationConnectionCallback(WebURL url, WebString id) + : url_(url), id_(id), callback_called_(false) {} + ~TestWebPresentationConnectionCallback() override { + EXPECT_TRUE(callback_called_); + } + + void onSuccess(const WebPresentationSessionInfo& info) override { + callback_called_ = true; + EXPECT_EQ(info.url, url_); + EXPECT_EQ(info.id, id_); + } + + private: + const WebURL url_; + const WebString id_; + bool callback_called_; +}; + +class TestWebPresentationConnectionErrorCallback + : public WebPresentationConnectionCallback { + public: + TestWebPresentationConnectionErrorCallback( + WebPresentationError::ErrorType error_type, + WebString message) + : error_type_(error_type), message_(message), callback_called_(false) {} + ~TestWebPresentationConnectionErrorCallback() override { + EXPECT_TRUE(callback_called_); + } + + void onError(const WebPresentationError& error) override { + callback_called_ = true; + EXPECT_EQ(error.errorType, error_type_); + EXPECT_EQ(error.message, message_); + } + + private: + const WebPresentationError::ErrorType error_type_; + const WebString message_; + bool callback_called_; +}; + +class TestPresentationDispatcher : public PresentationDispatcher { + public: + explicit TestPresentationDispatcher( + MockPresentationService* presentation_service) + : PresentationDispatcher(nullptr), + mock_presentation_service_(presentation_service) {} + ~TestPresentationDispatcher() override {} + + private: + void ConnectToPresentationServiceIfNeeded() override { + if (!mock_binding_) { + mock_binding_ = base::MakeUnique<mojo::Binding<PresentationService>>( + mock_presentation_service_, + mojo::MakeRequest(&presentation_service_)); + } + } + + MockPresentationService* mock_presentation_service_; + std::unique_ptr<mojo::Binding<PresentationService>> mock_binding_; +}; + +class PresentationDispatcherTest : public ::testing::Test { + public: + PresentationDispatcherTest() + : gurl1_(GURL("https://www.example.com/1.html")), + gurl2_(GURL("https://www.example.com/2.html")), + gurls_({gurl1_, gurl2_}), + url1_(WebURL(gurl1_)), + url2_(WebURL(gurl2_)), + urls_(WebVector<WebURL>(gurls_)), + presentation_id_(WebString::fromUTF8("test-id")), + array_buffer_(WebArrayBuffer::create(4, 1)), + observer_(url1_), + dispatcher_(&presentation_service_) {} + ~PresentationDispatcherTest() override {} + + void SetUp() override { + // Set some test data. + *array_buffer_data() = 42; + } + + uint8_t* array_buffer_data() { + return static_cast<uint8_t*>(array_buffer_.data()); + } + + protected: + const GURL gurl1_; + const GURL gurl2_; + const std::vector<GURL> gurls_; + const WebURL url1_; + const WebURL url2_; + const WebVector<WebURL> urls_; + const WebString presentation_id_; + const WebArrayBuffer array_buffer_; + MockPresentationAvailabilityObserver observer_; + MockPresentationService presentation_service_; + TestPresentationDispatcher dispatcher_; + + private: + content::TestBrowserThreadBundle thread_bundle_; +}; + +TEST_F(PresentationDispatcherTest, TestStartSession) { + base::RunLoop run_loop; + + EXPECT_CALL(presentation_service_, StartSession(gurls_, _)) + .WillOnce(Invoke([this]( + const std::vector<GURL>& presentation_urls, + const PresentationService::StartSessionCallback& callback) { + PresentationSessionInfoPtr session_info(PresentationSessionInfo::New()); + session_info->url = gurl1_; + session_info->id = presentation_id_.utf8(); + callback.Run(std::move(session_info), PresentationErrorPtr()); + })); + dispatcher_.startSession( + urls_, base::MakeUnique<TestWebPresentationConnectionCallback>( + url1_, presentation_id_)); + run_loop.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestStartSessionError) { + WebString error_message = WebString::fromUTF8("Test error message"); + base::RunLoop run_loop; + + EXPECT_CALL(presentation_service_, StartSession(gurls_, _)) + .WillOnce(Invoke([this, &error_message]( + const std::vector<GURL>& presentation_urls, + const PresentationService::StartSessionCallback& callback) { + PresentationErrorPtr error(PresentationError::New()); + error->error_type = PresentationErrorType::NO_AVAILABLE_SCREENS; + error->message = error_message.utf8(); + callback.Run(PresentationSessionInfoPtr(), std::move(error)); + })); + dispatcher_.startSession( + urls_, + base::MakeUnique<TestWebPresentationConnectionErrorCallback>( + WebPresentationError::ErrorTypeNoAvailableScreens, error_message)); + run_loop.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestJoinSessionError) { + WebString error_message = WebString::fromUTF8("Test error message"); + base::RunLoop run_loop; + + EXPECT_CALL(presentation_service_, JoinSession(gurls_, _, _)) + .WillOnce(Invoke([this, &error_message]( + const std::vector<GURL>& presentation_urls, + const base::Optional<std::string>& presentation_id, + const PresentationService::JoinSessionCallback& callback) { + EXPECT_TRUE(presentation_id.has_value()); + EXPECT_EQ(presentation_id_.utf8(), presentation_id.value()); + PresentationErrorPtr error(PresentationError::New()); + error->error_type = PresentationErrorType::NO_AVAILABLE_SCREENS; + error->message = error_message.utf8(); + callback.Run(PresentationSessionInfoPtr(), std::move(error)); + })); + dispatcher_.joinSession( + urls_, presentation_id_, + base::MakeUnique<TestWebPresentationConnectionErrorCallback>( + WebPresentationError::ErrorTypeNoAvailableScreens, error_message)); + run_loop.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestJoinSession) { + base::RunLoop run_loop; + + EXPECT_CALL(presentation_service_, JoinSession(gurls_, _, _)) + .WillOnce(Invoke([this]( + const std::vector<GURL>& presentation_urls, + const base::Optional<std::string>& presentation_id, + const PresentationService::JoinSessionCallback& callback) { + EXPECT_TRUE(presentation_id.has_value()); + EXPECT_EQ(presentation_id_.utf8(), presentation_id.value()); + PresentationSessionInfoPtr session_info(PresentationSessionInfo::New()); + session_info->url = gurl1_; + session_info->id = presentation_id_.utf8(); + callback.Run(std::move(session_info), PresentationErrorPtr()); + })); + dispatcher_.joinSession( + urls_, presentation_id_, + base::MakeUnique<TestWebPresentationConnectionCallback>( + url1_, presentation_id_)); + run_loop.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestSendString) { + WebString message = WebString::fromUTF8("test message"); + base::RunLoop run_loop; + EXPECT_CALL(presentation_service_, SendConnectionMessageInternal(_, _, _)) + .WillOnce(Invoke([this, &message]( + PresentationSessionInfo* session_info, + ConnectionMessage* message_request, + const PresentationService::SendConnectionMessageCallback& callback) { + EXPECT_EQ(gurl1_, session_info->url); + EXPECT_EQ(presentation_id_.utf8(), session_info->id); + EXPECT_TRUE(message_request->message.has_value()); + EXPECT_EQ(message.utf8(), message_request->message.value()); + callback.Run(true); + })); + dispatcher_.sendString(url1_, presentation_id_, message); + run_loop.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestSendArrayBuffer) { + base::RunLoop run_loop; + EXPECT_CALL(presentation_service_, SendConnectionMessageInternal(_, _, _)) + .WillOnce(Invoke([this]( + PresentationSessionInfo* session_info, + ConnectionMessage* message_request, + const PresentationService::SendConnectionMessageCallback& callback) { + EXPECT_EQ(gurl1_, session_info->url); + EXPECT_EQ(presentation_id_.utf8(), session_info->id); + std::vector<uint8_t> data( + array_buffer_data(), + array_buffer_data() + array_buffer_.byteLength()); + EXPECT_TRUE(message_request->data.has_value()); + EXPECT_EQ(data, message_request->data.value()); + callback.Run(true); + })); + dispatcher_.sendArrayBuffer(url1_, presentation_id_, array_buffer_data(), + array_buffer_.byteLength()); + run_loop.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestSendBlobData) { + base::RunLoop run_loop; + EXPECT_CALL(presentation_service_, SendConnectionMessageInternal(_, _, _)) + .WillOnce(Invoke([this]( + PresentationSessionInfo* session_info, + ConnectionMessage* message_request, + const PresentationService::SendConnectionMessageCallback& callback) { + EXPECT_EQ(gurl1_, session_info->url); + EXPECT_EQ(presentation_id_.utf8(), session_info->id); + std::vector<uint8_t> data( + array_buffer_data(), + array_buffer_data() + array_buffer_.byteLength()); + EXPECT_TRUE(message_request->data.has_value()); + EXPECT_EQ(data, message_request->data.value()); + callback.Run(true); + })); + dispatcher_.sendBlobData(url1_, presentation_id_, array_buffer_data(), + array_buffer_.byteLength()); + run_loop.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestCloseSession) { + base::RunLoop run_loop; + EXPECT_CALL(presentation_service_, + CloseConnection(gurl1_, presentation_id_.utf8())); + dispatcher_.closeSession(url1_, presentation_id_); + run_loop.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestTerminateSession) { + base::RunLoop run_loop; + EXPECT_CALL(presentation_service_, + Terminate(gurl1_, presentation_id_.utf8())); + dispatcher_.terminateSession(url1_, presentation_id_); + run_loop.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestListenForScreenAvailability) { + base::RunLoop run_loop1; + EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl1_)); + dispatcher_.getAvailability( + url1_, base::MakeUnique<WebPresentationAvailabilityCallbacks>()); + dispatcher_.OnScreenAvailabilityUpdated(url1_, true); + run_loop1.RunUntilIdle(); + + base::RunLoop run_loop2; + EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl1_)); + dispatcher_.startListening(&observer_); + run_loop2.RunUntilIdle(); + + base::RunLoop run_loop3; + EXPECT_CALL(observer_, availabilityChanged(false)); + dispatcher_.OnScreenAvailabilityUpdated(url1_, false); + EXPECT_CALL(observer_, availabilityChanged(true)); + dispatcher_.OnScreenAvailabilityUpdated(url1_, true); + EXPECT_CALL(presentation_service_, + StopListeningForScreenAvailability(gurl1_)); + dispatcher_.stopListening(&observer_); + run_loop3.RunUntilIdle(); + + // After stopListening(), |observer_| should no longer be notified. + base::RunLoop run_loop4; + EXPECT_CALL(observer_, availabilityChanged(false)).Times(0); + dispatcher_.OnScreenAvailabilityUpdated(url1_, false); + run_loop4.RunUntilIdle(); +} + +TEST_F(PresentationDispatcherTest, TestSetDefaultPresentationUrls) { + base::RunLoop run_loop; + EXPECT_CALL(presentation_service_, SetDefaultPresentationUrls(gurls_)); + dispatcher_.setDefaultPresentationUrls(urls_); + run_loop.RunUntilIdle(); +} + +} // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 8b795cf..e07a00d 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1357,6 +1357,7 @@ "../renderer/media/video_capture_impl_unittest.cc", "../renderer/media/webmediaplayer_ms_unittest.cc", "../renderer/peripheral_content_heuristic_unittest.cc", + "../renderer/presentation/presentation_dispatcher_unittest.cc", "../renderer/render_thread_impl_unittest.cc", "../renderer/render_widget_unittest.cc", "../renderer/scheduler/resource_dispatch_throttler_unittest.cc",
diff --git a/extensions/renderer/api_event_handler_unittest.cc b/extensions/renderer/api_event_handler_unittest.cc index ce19937..e43c860 100644 --- a/extensions/renderer/api_event_handler_unittest.cc +++ b/extensions/renderer/api_event_handler_unittest.cc
@@ -447,4 +447,63 @@ context->Global(), context, "eventArgs")); } +// Test listeners that remove themselves in their handling of the event. +TEST_F(APIEventHandlerTest, RemovingListenersWhileHandlingEvent) { + v8::HandleScope handle_scope(isolate()); + v8::Local<v8::Context> context = ContextLocal(); + + APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); + const char kEventName[] = "alpha"; + v8::Local<v8::Object> event = + handler.CreateEventInstance(kEventName, context); + ASSERT_FALSE(event.IsEmpty()); + + { + // Cache the event object on the global in order to allow for easy removal. + v8::Local<v8::Function> set_event_on_global = + FunctionFromString( + context, + "(function(event) { this.testEvent = event; })"); + v8::Local<v8::Value> args[] = {event}; + RunFunctionOnGlobal(set_event_on_global, context, arraysize(args), args); + EXPECT_EQ(event, + GetPropertyFromObject(context->Global(), context, "testEvent")); + } + + // A listener function that removes itself as a listener. + const char kListenerFunction[] = + "(function() {\n" + " return function listener() {\n" + " this.testEvent.removeListener(listener);\n" + " };\n" + "})();"; + + // Create and add a bunch of listeners. + std::vector<v8::Local<v8::Function>> listeners; + const size_t kNumListeners = 20u; + listeners.reserve(kNumListeners); + for (size_t i = 0; i < kNumListeners; ++i) + listeners.push_back(FunctionFromString(context, kListenerFunction)); + + const char kAddListenerFunction[] = + "(function(event, listener) { event.addListener(listener); })"; + v8::Local<v8::Function> add_listener_function = + FunctionFromString(context, kAddListenerFunction); + + for (const auto& listener : listeners) { + v8::Local<v8::Value> argv[] = {event, listener}; + RunFunctionOnGlobal(add_listener_function, context, arraysize(argv), argv); + } + + // Fire the event. All listeners should be removed (and we shouldn't crash). + EXPECT_EQ(kNumListeners, + handler.GetNumEventListenersForTesting(kEventName, context)); + handler.FireEventInContext(kEventName, context, base::ListValue()); + EXPECT_EQ(0u, handler.GetNumEventListenersForTesting(kEventName, context)); + + // TODO(devlin): Another possible test: register listener a and listener b, + // where a removes b and b removes a. Theoretically, only one should be + // notified. Investigate what we currently do in JS-style bindings. +} + } // namespace extensions
diff --git a/extensions/renderer/event_emitter.cc b/extensions/renderer/event_emitter.cc index 74245a5..afc358a 100644 --- a/extensions/renderer/event_emitter.cc +++ b/extensions/renderer/event_emitter.cc
@@ -34,10 +34,15 @@ void EventEmitter::Fire(v8::Local<v8::Context> context, std::vector<v8::Local<v8::Value>>* args) { - for (const auto& listener : listeners_) { - run_js_.Run(listener.Get(context->GetIsolate()), context, args->size(), - args->data()); - } + // We create a local copy of listeners_ since the array can be modified during + // handling. + std::vector<v8::Local<v8::Function>> listeners; + listeners.reserve(listeners_.size()); + for (const auto& listener : listeners_) + listeners.push_back(listener.Get(context->GetIsolate())); + + for (const auto& listener : listeners) + run_js_.Run(listener, context, args->size(), args->data()); } void EventEmitter::AddListener(gin::Arguments* arguments) {
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg index 5a494ce..549191b 100644 --- a/infra/config/cq.cfg +++ b/infra/config/cq.cfg
@@ -57,6 +57,10 @@ experiment_percentage: 100 } builders { name: "linux_chromium_rel_ng" } + builders { + name: "linux_chromium_tsan_rel_ng" + experiment_percentage: 10 + } } buckets { name: "master.tryserver.chromium.mac"
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn index 83ee9d9..58f64a1 100644 --- a/ios/chrome/browser/ui/BUILD.gn +++ b/ios/chrome/browser/ui/BUILD.gn
@@ -4,19 +4,7 @@ import("//build/config/ios/rules.gni") -source_set("ui_arc") { - sources = [ - "network_activity_indicator_manager.h", - "network_activity_indicator_manager.mm", - ] - deps = [ - "//base", - ] - configs += [ "//build/config/compiler:enable_arc" ] -} - source_set("ui") { - configs += [ "//build/config/compiler:enable_arc" ] sources = [ "UIView+SizeClassSupport.h", "UIView+SizeClassSupport.mm", @@ -32,6 +20,8 @@ "image_util.mm", "native_content_controller.h", "native_content_controller.mm", + "network_activity_indicator_manager.h", + "network_activity_indicator_manager.mm", "orientation_limiting_navigation_controller.h", "orientation_limiting_navigation_controller.mm", "prerender_final_status.h", @@ -61,18 +51,13 @@ "//ui/base", "//ui/gfx", ] - public_deps = [ - ":ui_arc", - ] - allow_circular_includes_from = [ - ":ui_arc", - "//ios/chrome/browser/ui/commands", - ] + allow_circular_includes_from = [ "//ios/chrome/browser/ui/commands" ] libs = [ "Accelerate.framework", "CoreGraphics.framework", "QuartzCore.framework", ] + configs += [ "//build/config/compiler:enable_arc" ] } source_set("unit_tests") {
diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn index b2e4514d..77afc2c 100644 --- a/media/audio/BUILD.gn +++ b/media/audio/BUILD.gn
@@ -302,6 +302,7 @@ testonly = true sources = [ "audio_input_controller_unittest.cc", + "audio_input_device_unittest.cc", "audio_input_unittest.cc", "audio_manager_unittest.cc", "audio_output_controller_unittest.cc",
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc index cee639bb..9ebe480 100644 --- a/media/audio/audio_input_device.cc +++ b/media/audio/audio_input_device.cc
@@ -178,18 +178,25 @@ break; case AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR: DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)"; - // Don't dereference the callback object if the audio thread - // is stopped or stopping. That could mean that the callback - // object has been deleted. - // TODO(tommi): Add an explicit contract for clearing the callback - // object. Possibly require calling Initialize again or provide - // a callback object via Start() and clear it in Stop(). - { + if (state_ == CREATING_STREAM) { + // At this point, we haven't attempted to start the audio thread. + // Accessing the hardware might have failed or we may have reached + // the limit of the number of allowed concurrent streams. + // We must report the error to the |callback_| so that a potential + // audio source object will enter the correct state (e.g. 'ended' for + // a local audio source). + callback_->OnCaptureError( + "Maximum allowed input device limit reached or OS failure."); + } else { + // Don't dereference the callback object if the audio thread + // is stopped or stopping. That could mean that the callback + // object has been deleted. + // TODO(tommi): Add an explicit contract for clearing the callback + // object. Possibly require calling Initialize again or provide + // a callback object via Start() and clear it in Stop(). base::AutoLock auto_lock_(audio_thread_lock_); - if (audio_thread_) { - callback_->OnCaptureError( - "AudioInputDevice::OnStateChanged - audio thread still running"); - } + if (audio_thread_) + callback_->OnCaptureError("AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR"); } break; default:
diff --git a/media/audio/audio_input_device_unittest.cc b/media/audio/audio_input_device_unittest.cc new file mode 100644 index 0000000..046d2eb8 --- /dev/null +++ b/media/audio/audio_input_device_unittest.cc
@@ -0,0 +1,91 @@ +// Copyright (c) 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 "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/single_thread_task_runner.h" +#include "media/audio/audio_input_device.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gmock_mutant.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::DoAll; + +namespace media { + +namespace { + +class MockAudioInputIPC : public AudioInputIPC { + public: + MockAudioInputIPC() {} + ~MockAudioInputIPC() override {} + + MOCK_METHOD5(CreateStream, + void(AudioInputIPCDelegate* delegate, + int session_id, + const AudioParameters& params, + bool automatic_gain_control, + uint32_t total_segments)); + MOCK_METHOD0(RecordStream, void()); + MOCK_METHOD1(SetVolume, void(double volume)); + MOCK_METHOD0(CloseStream, void()); +}; + +class MockCaptureCallback : public AudioCapturerSource::CaptureCallback { + public: + MockCaptureCallback() {} + ~MockCaptureCallback() override {} + + MOCK_METHOD4(Capture, + void(const AudioBus* audio_source, + int audio_delay_milliseconds, + double volume, + bool key_pressed)); + + MOCK_METHOD1(OnCaptureError, void(const std::string& message)); +}; + +// Used to terminate a loop from a different thread than the loop belongs to. +// |task_runner| should be a SingleThreadTaskRunner. +ACTION_P(QuitLoop, task_runner) { + task_runner->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); +} + +} // namespace. + +// Regular construction. +TEST(AudioInputDeviceTest, Noop) { + base::MessageLoopForIO io_loop; + MockAudioInputIPC* input_ipc = new MockAudioInputIPC(); + scoped_refptr<AudioInputDevice> device( + new AudioInputDevice(base::WrapUnique(input_ipc), io_loop.task_runner())); +} + +ACTION_P2(ReportStateChange, device, state) { + static_cast<AudioInputIPCDelegate*>(device)->OnStateChanged(state); +} + +// Verify that we get an OnCaptureError() callback if CreateStream fails. +TEST(AudioInputDeviceTest, FailToCreateStream) { + AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, + CHANNEL_LAYOUT_STEREO, 48000, 16, 480); + + base::MessageLoopForIO io_loop; + MockCaptureCallback callback; + MockAudioInputIPC* input_ipc = new MockAudioInputIPC(); + scoped_refptr<AudioInputDevice> device( + new AudioInputDevice(base::WrapUnique(input_ipc), io_loop.task_runner())); + device->Initialize(params, &callback, 1); + device->Start(); + EXPECT_CALL(*input_ipc, CreateStream(_, _, _, _, _)) + .WillOnce(ReportStateChange(device.get(), + AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR)); + EXPECT_CALL(callback, OnCaptureError(_)) + .WillOnce(QuitLoop(io_loop.task_runner())); + base::RunLoop().Run(); +} + +} // namespace media.
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java b/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java index c312140..32c8b2c 100644 --- a/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java +++ b/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java
@@ -13,6 +13,9 @@ import org.chromium.base.annotations.JNINamespace; import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; /** * Video Capture Device base class, defines a set of methods that native code @@ -21,6 +24,19 @@ **/ @JNINamespace("media") public abstract class VideoCapture { + /** + * Common class for storing a framerate range. Values should be multiplied by 1000. + */ + protected static class FramerateRange { + public int min; + public int max; + + public FramerateRange(int min, int max) { + this.min = min; + this.max = max; + } + } + // The angle (0, 90, 180, 270) that the image needs to be rotated to show in // the display's native orientation. protected int mCameraNativeOrientation; @@ -58,7 +74,7 @@ /** * @param zoom Zoom level, should be ignored if 0. * @param focusMode Focus mode following AndroidMeteringMode enum. - * @param exposureMode Focus mode following AndroidMeteringMode enum. + * @param exposureMode Exposure mode following AndroidMeteringMode enum. * @param pointsOfInterest2D 2D normalized points of interest, marshalled with * x coordinate first followed by the y coordinate. * @param hasExposureCompensation Indicates if |exposureCompensation| is set. @@ -147,6 +163,52 @@ return orientation; } + /** + * Finds the framerate range matching |targetFramerate|. Tries to find a range with as low of a + * minimum value as possible to allow the camera adjust based on the lighting conditions. + * Assumes that all framerate values are multiplied by 1000. + * + * This code is mostly copied from WebRTC: + * CameraEnumerationAndroid.getClosestSupportedFramerateRange + * in webrtc/api/android/java/src/org/webrtc/CameraEnumerationAndroid.java + */ + protected static FramerateRange getClosestFramerateRange( + final List<FramerateRange> framerateRanges, final int targetFramerate) { + return Collections.min(framerateRanges, new Comparator<FramerateRange>() { + // Threshold and penalty weights if the upper bound is further away than + // |MAX_FPS_DIFF_THRESHOLD| from requested. + private static final int MAX_FPS_DIFF_THRESHOLD = 5000; + private static final int MAX_FPS_LOW_DIFF_WEIGHT = 1; + private static final int MAX_FPS_HIGH_DIFF_WEIGHT = 3; + + // Threshold and penalty weights if the lower bound is bigger than |MIN_FPS_THRESHOLD|. + private static final int MIN_FPS_THRESHOLD = 8000; + private static final int MIN_FPS_LOW_VALUE_WEIGHT = 1; + private static final int MIN_FPS_HIGH_VALUE_WEIGHT = 4; + + // Use one weight for small |value| less than |threshold|, and another weight above. + private int progressivePenalty( + int value, int threshold, int lowWeight, int highWeight) { + return (value < threshold) + ? value * lowWeight + : threshold * lowWeight + (value - threshold) * highWeight; + } + + int diff(FramerateRange range) { + final int minFpsError = progressivePenalty(range.min, MIN_FPS_THRESHOLD, + MIN_FPS_LOW_VALUE_WEIGHT, MIN_FPS_HIGH_VALUE_WEIGHT); + final int maxFpsError = progressivePenalty(Math.abs(targetFramerate - range.max), + MAX_FPS_DIFF_THRESHOLD, MAX_FPS_LOW_DIFF_WEIGHT, MAX_FPS_HIGH_DIFF_WEIGHT); + return minFpsError + maxFpsError; + } + + @Override + public int compare(FramerateRange range1, FramerateRange range2) { + return diff(range1) - diff(range2); + } + }); + } + // Method for VideoCapture implementations to call back native code. public native void nativeOnFrameAvailable( long nativeVideoCaptureDeviceAndroid, byte[] data, int length, int rotation);
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java index bc2c324..929f04115 100644 --- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java +++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java
@@ -287,26 +287,17 @@ Log.e(TAG, "allocate: no fps range found"); return false; } + final ArrayList<FramerateRange> framerateRanges = + new ArrayList<FramerateRange>(listFpsRange.size()); + for (int[] range : listFpsRange) { + framerateRanges.add(new FramerateRange(range[0], range[1])); + } // API fps ranges are scaled up x1000 to avoid floating point. int frameRateScaled = frameRate * 1000; - // Use the first range as the default chosen range. - int[] chosenFpsRange = listFpsRange.get(0); - int frameRateNearest = Math.abs(frameRateScaled - chosenFpsRange[0]) - < Math.abs(frameRateScaled - chosenFpsRange[1]) - ? chosenFpsRange[0] - : chosenFpsRange[1]; - int chosenFrameRate = (frameRateNearest + 999) / 1000; - int fpsRangeSize = Integer.MAX_VALUE; - for (int[] fpsRange : listFpsRange) { - if (fpsRange[0] <= frameRateScaled && frameRateScaled <= fpsRange[1] - && (fpsRange[1] - fpsRange[0]) <= fpsRangeSize) { - chosenFpsRange = fpsRange; - chosenFrameRate = frameRate; - fpsRangeSize = fpsRange[1] - fpsRange[0]; - } - } - Log.d(TAG, "allocate: fps set to %d, [%d-%d]", chosenFrameRate, chosenFpsRange[0], - chosenFpsRange[1]); + final FramerateRange chosenFramerateRange = + getClosestFramerateRange(framerateRanges, frameRateScaled); + final int[] chosenFpsRange = new int[] {chosenFramerateRange.min, chosenFramerateRange.max}; + Log.d(TAG, "allocate: fps set to [%d-%d]", chosenFpsRange[0], chosenFpsRange[1]); // Calculate size. List<android.hardware.Camera.Size> listCameraSize = parameters.getSupportedPreviewSizes(); @@ -347,9 +338,8 @@ Log.d(TAG, "Continuous focus mode not supported."); } - // Fill the capture format. - mCaptureFormat = new VideoCaptureFormat( - matchedWidth, matchedHeight, chosenFrameRate, BuggyDeviceHack.getImageFormat()); + mCaptureFormat = new VideoCaptureFormat(matchedWidth, matchedHeight, + chosenFpsRange[1] / 1000, BuggyDeviceHack.getImageFormat()); parameters.setPictureSize(matchedWidth, matchedHeight); parameters.setPreviewSize(matchedWidth, matchedHeight); parameters.setPreviewFpsRange(chosenFpsRange[0], chosenFpsRange[1]);
diff --git a/net/http2/hpack/decoder/hpack_decoder_tables.cc b/net/http2/hpack/decoder/hpack_decoder_tables.cc new file mode 100644 index 0000000..424cfe4 --- /dev/null +++ b/net/http2/hpack/decoder/hpack_decoder_tables.cc
@@ -0,0 +1,117 @@ +// 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 "net/http2/hpack/decoder/hpack_decoder_tables.h" + +#include "base/logging.h" + +namespace net { +namespace { + +std::vector<HpackStringPair>* MakeStaticTable() { + auto ptr = new std::vector<HpackStringPair>(); + ptr->reserve(kFirstDynamicTableIndex); + ptr->emplace_back("", ""); + +#define STATIC_TABLE_ENTRY(name, value, index) \ + DCHECK_EQ(ptr->size(), index); \ + ptr->emplace_back(name, value) + +#include "net/http2/hpack/hpack_static_table_entries.inc" + +#undef STATIC_TABLE_ENTRY + + return ptr; +} + +const std::vector<HpackStringPair>* GetStaticTable() { + static const std::vector<HpackStringPair>* const g_static_table = + MakeStaticTable(); + return g_static_table; +} + +} // namespace + +HpackDecoderStaticTable::HpackDecoderStaticTable( + const std::vector<HpackStringPair>* table) + : table_(table) {} + +HpackDecoderStaticTable::HpackDecoderStaticTable() : table_(GetStaticTable()) {} + +const HpackStringPair* HpackDecoderStaticTable::Lookup(size_t index) const { + if (0 < index && index < kFirstDynamicTableIndex) { + return &((*table_)[index]); + } + return nullptr; +} + +HpackDecoderDynamicTable::HpackDecoderDynamicTable() {} +HpackDecoderDynamicTable::~HpackDecoderDynamicTable() {} + +void HpackDecoderDynamicTable::DynamicTableSizeUpdate(size_t size_limit) { + EnsureSizeNoMoreThan(size_limit); + DCHECK_LE(current_size_, size_limit); + size_limit_ = size_limit; +} + +// TODO(jamessynge): Check somewhere before here that names received from the +// peer are valid (e.g. are lower-case, no whitespace, etc.). +bool HpackDecoderDynamicTable::Insert(const HpackString& name, + const HpackString& value) { + HpackStringPair p(name, value); + size_t entry_size = p.size(); + DVLOG(2) << "InsertEntry of size=" << entry_size << "\n name: " << name + << "\n value: " << value; + if (entry_size > size_limit_) { + DVLOG(2) << "InsertEntry: entry larger than table, removing " + << table_.size() << " entries, of total size " << current_size_ + << " bytes."; + table_.clear(); + current_size_ = 0; + return false; // Not inserted because too large. + } + size_t insert_limit = size_limit_ - entry_size; + EnsureSizeNoMoreThan(insert_limit); + table_.push_front(p); + current_size_ += entry_size; + DVLOG(2) << "InsertEntry: current_size_=" << current_size_; + DCHECK_GE(current_size_, entry_size); + DCHECK_LE(current_size_, size_limit_); + return true; +} + +const HpackStringPair* HpackDecoderDynamicTable::Lookup(size_t index) const { + if (index < table_.size()) { + return &(table_[index]); + } + return nullptr; +} + +void HpackDecoderDynamicTable::EnsureSizeNoMoreThan(size_t limit) { + DVLOG(2) << "EnsureSizeNoMoreThan limit=" << limit + << ", current_size_=" << current_size_; + // Not the most efficient choice, but any easy way to start. + while (current_size_ > limit) { + RemoveLastEntry(); + } + DCHECK_LE(current_size_, limit); +} + +void HpackDecoderDynamicTable::RemoveLastEntry() { + DCHECK(!table_.empty()); + if (!table_.empty()) { + DVLOG(2) << "RemoveLastEntry current_size_=" << current_size_ + << ", last entry size=" << table_.back().size(); + DCHECK_GE(current_size_, table_.back().size()); + current_size_ -= table_.back().size(); + table_.pop_back(); + // Empty IFF current_size_ == 0. + DCHECK_EQ(table_.empty(), current_size_ == 0); + } +} + +HpackDecoderTables::HpackDecoderTables() {} +HpackDecoderTables::~HpackDecoderTables() {} + +} // namespace net
diff --git a/net/http2/hpack/decoder/hpack_decoder_tables.h b/net/http2/hpack/decoder/hpack_decoder_tables.h new file mode 100644 index 0000000..525a54e7 --- /dev/null +++ b/net/http2/hpack/decoder/hpack_decoder_tables.h
@@ -0,0 +1,152 @@ +// 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 NET_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_ +#define NET_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_ + +// Static and dynamic tables for the HPACK decoder. See: +// http://httpwg.org/specs/rfc7541.html#indexing.tables + +// Note that the Lookup methods return nullptr if the requested index was not +// found. This should be treated as a COMPRESSION error according to the HTTP/2 +// spec, which is a connection level protocol error (i.e. the connection must +// be terminated). See these sections in the two RFCs: +// http://httpwg.org/specs/rfc7541.html#indexed.header.representation +// http://httpwg.org/specs/rfc7541.html#index.address.space +// http://httpwg.org/specs/rfc7540.html#HeaderBlock + +#include <stddef.h> + +#include <deque> +#include <functional> +#include <vector> + +#include "base/macros.h" +#include "net/base/net_export.h" +#include "net/http2/hpack/hpack_string.h" +#include "net/http2/http2_constants.h" + +namespace net { +namespace test { +class HpackDecoderTablesPeer; +} // namespace test + +const size_t kFirstDynamicTableIndex = 62; + +// See http://httpwg.org/specs/rfc7541.html#static.table.definition for the +// contents, and http://httpwg.org/specs/rfc7541.html#index.address.space for +// info about accessing the static table. +class NET_EXPORT_PRIVATE HpackDecoderStaticTable { + public: + explicit HpackDecoderStaticTable(const std::vector<HpackStringPair>* table); + // Uses a global table shared by all threads. + HpackDecoderStaticTable(); + + // If index is valid, returns a pointer to the entry, otherwise returns + // nullptr. + const HpackStringPair* Lookup(size_t index) const; + + private: + friend class test::HpackDecoderTablesPeer; + const std::vector<HpackStringPair>* const table_; +}; + +// HpackDecoderDynamicTable implements HPACK compression feature "indexed +// headers"; previously sent headers may be referenced later by their index +// in the dynamic table. See these sections of the RFC: +// http://httpwg.org/specs/rfc7541.html#dynamic.table +// http://httpwg.org/specs/rfc7541.html#dynamic.table.management +class NET_EXPORT_PRIVATE HpackDecoderDynamicTable { + public: + HpackDecoderDynamicTable(); + ~HpackDecoderDynamicTable(); + + // Sets a new size limit, received from the peer; performs evictions if + // necessary to ensure that the current size does not exceed the new limit. + // The caller needs to have validated that size_limit does not + // exceed the acknowledged value of SETTINGS_HEADER_TABLE_SIZE. + void DynamicTableSizeUpdate(size_t size_limit); + + // Returns true if inserted, false if too large (at which point the + // dynamic table will be empty.) + bool Insert(const HpackString& name, const HpackString& value); + + // If index is valid, returns a pointer to the entry, otherwise returns + // nullptr. + const HpackStringPair* Lookup(size_t index) const; + + size_t size_limit() const { return size_limit_; } + size_t current_size() const { return current_size_; } + + private: + friend class test::HpackDecoderTablesPeer; + + // Drop older entries to ensure the size is not greater than limit. + void EnsureSizeNoMoreThan(size_t limit); + + // Removes the oldest dynamic table entry. + void RemoveLastEntry(); + + // The last received DynamicTableSizeUpdate value, initialized to + // SETTINGS_HEADER_TABLE_SIZE. + size_t size_limit_ = Http2SettingsInfo::DefaultHeaderTableSize(); + + size_t current_size_ = 0; + + std::deque<HpackStringPair> table_; + + DISALLOW_COPY_AND_ASSIGN(HpackDecoderDynamicTable); +}; + +class NET_EXPORT_PRIVATE HpackDecoderTables { + public: + HpackDecoderTables(); + ~HpackDecoderTables(); + + // Sets a new size limit, received from the peer; performs evictions if + // necessary to ensure that the current size does not exceed the new limit. + // The caller needs to have validated that size_limit does not + // exceed the acknowledged value of SETTINGS_HEADER_TABLE_SIZE. + void DynamicTableSizeUpdate(size_t size_limit) { + dynamic_table_.DynamicTableSizeUpdate(size_limit); + } + + // Returns true if inserted, false if too large (at which point the + // dynamic table will be empty.) + // TODO(jamessynge): Add methods for moving the string(s) into the table, + // or for otherwise avoiding unnecessary copies. + bool Insert(const HpackString& name, const HpackString& value) { + return dynamic_table_.Insert(name, value); + } + + // If index is valid, returns a pointer to the entry, otherwise returns + // nullptr. + const HpackStringPair* Lookup(size_t index) const { + if (index < kFirstDynamicTableIndex) { + return static_table_.Lookup(index); + } else { + return dynamic_table_.Lookup(index - kFirstDynamicTableIndex); + } + } + + // The size limit that the peer (the HPACK encoder) has told the decoder it is + // currently operating with. Defaults to SETTINGS_HEADER_TABLE_SIZE, 4096. + size_t header_table_size_limit() const { return dynamic_table_.size_limit(); } + + // Sum of the sizes of the dynamic table entries. + size_t current_header_table_size() const { + return dynamic_table_.current_size(); + } + + private: + friend class test::HpackDecoderTablesPeer; + HpackDecoderStaticTable static_table_; + HpackDecoderDynamicTable dynamic_table_; + + DISALLOW_COPY_AND_ASSIGN(HpackDecoderTables); +}; + +} // namespace net + +#endif // NET_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_
diff --git a/net/http2/hpack/decoder/hpack_decoder_tables_test.cc b/net/http2/hpack/decoder/hpack_decoder_tables_test.cc new file mode 100644 index 0000000..13bdb6f --- /dev/null +++ b/net/http2/hpack/decoder/hpack_decoder_tables_test.cc
@@ -0,0 +1,265 @@ +// 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 "net/http2/hpack/decoder/hpack_decoder_tables.h" + +#include <algorithm> +#include <string> +#include <tuple> +#include <vector> + +#include "base/logging.h" +#include "net/http2/tools/failure.h" +#include "net/http2/tools/http2_random.h" +#include "net/http2/tools/random_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::AssertionResult; +using ::testing::AssertionSuccess; +using std::string; + +namespace net { +namespace test { +class HpackDecoderTablesPeer { + public: + static size_t num_dynamic_entries(const HpackDecoderTables& tables) { + return tables.dynamic_table_.table_.size(); + } +}; + +namespace { +struct StaticEntry { + const char* name; + const char* value; + size_t index; +}; + +std::vector<StaticEntry> MakeSpecStaticEntries() { + std::vector<StaticEntry> static_entries; + +#define STATIC_TABLE_ENTRY(name, value, index) \ + DCHECK_EQ(static_entries.size() + 1, index); \ + static_entries.push_back({name, value, index}); + +#include "net/http2/hpack/hpack_static_table_entries.inc" + +#undef STATIC_TABLE_ENTRY + + return static_entries; +} + +template <class C> +void ShuffleCollection(C* collection, RandomBase* r) { + std::shuffle(collection->begin(), collection->end(), *r); +} + +class HpackDecoderStaticTableTest : public ::testing::Test { + protected: + HpackDecoderStaticTableTest() {} + + std::vector<StaticEntry> shuffled_static_entries() { + std::vector<StaticEntry> entries = MakeSpecStaticEntries(); + ShuffleCollection(&entries, &random_); + return entries; + } + + // This test is in a function so that it can be applied to both the static + // table and the combined static+dynamic tables. + AssertionResult VerifyStaticTableContents() { + for (const auto& expected : shuffled_static_entries()) { + const HpackStringPair* found = Lookup(expected.index); + VERIFY_NE(found, nullptr); + VERIFY_EQ(expected.name, found->name) << expected.index; + VERIFY_EQ(expected.value, found->value) << expected.index; + } + + // There should be no entry with index 0. + VERIFY_EQ(nullptr, Lookup(0)); + return AssertionSuccess(); + } + + virtual const HpackStringPair* Lookup(size_t index) { + return static_table_.Lookup(index); + } + + RandomBase* RandomPtr() { return &random_; } + + private: + Http2Random random_; + HpackDecoderStaticTable static_table_; +}; + +TEST_F(HpackDecoderStaticTableTest, StaticTableContents) { + EXPECT_TRUE(VerifyStaticTableContents()); +} + +size_t Size(const string& name, const string& value) { + return name.size() + value.size() + 32; +} + +// To support tests with more than a few of hand crafted changes to the dynamic +// table, we have another, exceedingly simple, implementation of the HPACK +// dynamic table containing FakeHpackEntry instances. We can thus compare the +// contents of the actual table with those in fake_dynamic_table_. + +typedef std::tuple<string, string, size_t> FakeHpackEntry; +const string& Name(const FakeHpackEntry& entry) { + return std::get<0>(entry); +} +const string& Value(const FakeHpackEntry& entry) { + return std::get<1>(entry); +} +size_t Size(const FakeHpackEntry& entry) { + return std::get<2>(entry); +} + +class HpackDecoderTablesTest : public HpackDecoderStaticTableTest { + protected: + const HpackStringPair* Lookup(size_t index) override { + return tables_.Lookup(index); + } + + size_t dynamic_size_limit() const { + return tables_.header_table_size_limit(); + } + size_t current_dynamic_size() const { + return tables_.current_header_table_size(); + } + size_t num_dynamic_entries() const { + return HpackDecoderTablesPeer::num_dynamic_entries(tables_); + } + + // Insert the name and value into fake_dynamic_table_. + void FakeInsert(const string& name, const string& value) { + FakeHpackEntry entry(name, value, Size(name, value)); + fake_dynamic_table_.insert(fake_dynamic_table_.begin(), entry); + } + + // Add up the size of all entries in fake_dynamic_table_. + size_t FakeSize() { + size_t sz = 0; + for (const auto& entry : fake_dynamic_table_) { + sz += Size(entry); + } + return sz; + } + + // If the total size of the fake_dynamic_table_ is greater than limit, + // keep the first N entries such that those N entries have a size not + // greater than limit, and such that keeping entry N+1 would have a size + // greater than limit. Returns the count of removed bytes. + size_t FakeTrim(size_t limit) { + size_t original_size = FakeSize(); + size_t total_size = 0; + for (size_t ndx = 0; ndx < fake_dynamic_table_.size(); ++ndx) { + total_size += Size(fake_dynamic_table_[ndx]); + if (total_size > limit) { + // Need to get rid of ndx and all following entries. + fake_dynamic_table_.erase(fake_dynamic_table_.begin() + ndx, + fake_dynamic_table_.end()); + return original_size - FakeSize(); + } + } + return 0; + } + + // Verify that the contents of the actual dynamic table match those in + // fake_dynamic_table_. + AssertionResult VerifyDynamicTableContents() { + VERIFY_EQ(current_dynamic_size(), FakeSize()); + VERIFY_EQ(num_dynamic_entries(), fake_dynamic_table_.size()); + + for (size_t ndx = 0; ndx < fake_dynamic_table_.size(); ++ndx) { + const HpackStringPair* found = Lookup(ndx + kFirstDynamicTableIndex); + VERIFY_NE(found, nullptr); + + const auto& expected = fake_dynamic_table_[ndx]; + VERIFY_EQ(Name(expected), found->name); + VERIFY_EQ(Value(expected), found->value); + } + + // Make sure there are no more entries. + VERIFY_EQ(nullptr, + Lookup(fake_dynamic_table_.size() + kFirstDynamicTableIndex)); + return AssertionSuccess(); + } + + // Apply an update to the limit on the maximum size of the dynamic table. + AssertionResult DynamicTableSizeUpdate(size_t size_limit) { + VERIFY_EQ(current_dynamic_size(), FakeSize()); + if (size_limit < current_dynamic_size()) { + // Will need to trim the dynamic table's oldest entries. + tables_.DynamicTableSizeUpdate(size_limit); + FakeTrim(size_limit); + return VerifyDynamicTableContents(); + } + // Shouldn't change the size. + tables_.DynamicTableSizeUpdate(size_limit); + return VerifyDynamicTableContents(); + } + + // Insert an entry into the dynamic table, confirming that trimming of entries + // occurs if the total size is greater than the limit, and that older entries + // move up by 1 index. + AssertionResult Insert(const string& name, const string& value) { + size_t old_count = num_dynamic_entries(); + if (tables_.Insert(HpackString(name), HpackString(value))) { + VERIFY_GT(current_dynamic_size(), 0u); + VERIFY_GT(num_dynamic_entries(), 0u); + } else { + VERIFY_EQ(current_dynamic_size(), 0u); + VERIFY_EQ(num_dynamic_entries(), 0u); + } + FakeInsert(name, value); + VERIFY_EQ(old_count + 1, fake_dynamic_table_.size()); + FakeTrim(dynamic_size_limit()); + VERIFY_EQ(current_dynamic_size(), FakeSize()); + VERIFY_EQ(num_dynamic_entries(), fake_dynamic_table_.size()); + return VerifyDynamicTableContents(); + } + + private: + HpackDecoderTables tables_; + + std::vector<FakeHpackEntry> fake_dynamic_table_; +}; + +TEST_F(HpackDecoderTablesTest, StaticTableContents) { + EXPECT_TRUE(VerifyStaticTableContents()); +} + +// Generate a bunch of random header entries, insert them, and confirm they +// present, as required by the RFC, using VerifyDynamicTableContents above on +// each Insert. Also apply various resizings of the dynamic table. +TEST_F(HpackDecoderTablesTest, RandomDynamicTable) { + EXPECT_EQ(0u, current_dynamic_size()); + EXPECT_TRUE(VerifyStaticTableContents()); + EXPECT_TRUE(VerifyDynamicTableContents()); + + std::vector<size_t> table_sizes; + table_sizes.push_back(dynamic_size_limit()); + table_sizes.push_back(0); + table_sizes.push_back(dynamic_size_limit() / 2); + table_sizes.push_back(dynamic_size_limit()); + table_sizes.push_back(dynamic_size_limit() / 2); + table_sizes.push_back(0); + table_sizes.push_back(dynamic_size_limit()); + + for (size_t limit : table_sizes) { + ASSERT_TRUE(DynamicTableSizeUpdate(limit)); + for (int insert_count = 0; insert_count < 100; ++insert_count) { + string name = GenerateHttp2HeaderName( + GenerateUniformInRange(2, 40, RandomPtr()), RandomPtr()); + string value = GenerateWebSafeString( + GenerateUniformInRange(2, 600, RandomPtr()), RandomPtr()); + ASSERT_TRUE(Insert(name, value)); + } + EXPECT_TRUE(VerifyStaticTableContents()); + } +} + +} // namespace +} // namespace test +} // namespace net
diff --git a/net/http2/hpack/hpack_static_table_entries.inc b/net/http2/hpack/hpack_static_table_entries.inc new file mode 100644 index 0000000..3d2f1087 --- /dev/null +++ b/net/http2/hpack/hpack_static_table_entries.inc
@@ -0,0 +1,69 @@ +// 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. + +// This file is designed to be included by C/C++ files which need the contents +// of the HPACK static table. It may be included more than once if necessary. +// See http://httpwg.org/specs/rfc7541.html#static.table.definition + +STATIC_TABLE_ENTRY(":authority", "", 1u); +STATIC_TABLE_ENTRY(":method", "GET", 2u); +STATIC_TABLE_ENTRY(":method", "POST", 3u); +STATIC_TABLE_ENTRY(":path", "/", 4u); +STATIC_TABLE_ENTRY(":path", "/index.html", 5u); +STATIC_TABLE_ENTRY(":scheme", "http", 6u); +STATIC_TABLE_ENTRY(":scheme", "https", 7u); +STATIC_TABLE_ENTRY(":status", "200", 8u); +STATIC_TABLE_ENTRY(":status", "204", 9u); +STATIC_TABLE_ENTRY(":status", "206", 10u); +STATIC_TABLE_ENTRY(":status", "304", 11u); +STATIC_TABLE_ENTRY(":status", "400", 12u); +STATIC_TABLE_ENTRY(":status", "404", 13u); +STATIC_TABLE_ENTRY(":status", "500", 14u); +STATIC_TABLE_ENTRY("accept-charset", "", 15u); +STATIC_TABLE_ENTRY("accept-encoding", "gzip, deflate", 16u); +STATIC_TABLE_ENTRY("accept-language", "", 17u); +STATIC_TABLE_ENTRY("accept-ranges", "", 18u); +STATIC_TABLE_ENTRY("accept", "", 19u); +STATIC_TABLE_ENTRY("access-control-allow-origin", "", 20u); +STATIC_TABLE_ENTRY("age", "", 21u); +STATIC_TABLE_ENTRY("allow", "", 22u); +STATIC_TABLE_ENTRY("authorization", "", 23u); +STATIC_TABLE_ENTRY("cache-control", "", 24u); +STATIC_TABLE_ENTRY("content-disposition", "", 25u); +STATIC_TABLE_ENTRY("content-encoding", "", 26u); +STATIC_TABLE_ENTRY("content-language", "", 27u); +STATIC_TABLE_ENTRY("content-length", "", 28u); +STATIC_TABLE_ENTRY("content-location", "", 29u); +STATIC_TABLE_ENTRY("content-range", "", 30u); +STATIC_TABLE_ENTRY("content-type", "", 31u); +STATIC_TABLE_ENTRY("cookie", "", 32u); +STATIC_TABLE_ENTRY("date", "", 33u); +STATIC_TABLE_ENTRY("etag", "", 34u); +STATIC_TABLE_ENTRY("expect", "", 35u); +STATIC_TABLE_ENTRY("expires", "", 36u); +STATIC_TABLE_ENTRY("from", "", 37u); +STATIC_TABLE_ENTRY("host", "", 38u); +STATIC_TABLE_ENTRY("if-match", "", 39u); +STATIC_TABLE_ENTRY("if-modified-since", "", 40u); +STATIC_TABLE_ENTRY("if-none-match", "", 41u); +STATIC_TABLE_ENTRY("if-range", "", 42u); +STATIC_TABLE_ENTRY("if-unmodified-since", "", 43u); +STATIC_TABLE_ENTRY("last-modified", "", 44u); +STATIC_TABLE_ENTRY("link", "", 45u); +STATIC_TABLE_ENTRY("location", "", 46u); +STATIC_TABLE_ENTRY("max-forwards", "", 47u); +STATIC_TABLE_ENTRY("proxy-authenticate", "", 48u); +STATIC_TABLE_ENTRY("proxy-authorization", "", 49u); +STATIC_TABLE_ENTRY("range", "", 50u); +STATIC_TABLE_ENTRY("referer", "", 51u); +STATIC_TABLE_ENTRY("refresh", "", 52u); +STATIC_TABLE_ENTRY("retry-after", "", 53u); +STATIC_TABLE_ENTRY("server", "", 54u); +STATIC_TABLE_ENTRY("set-cookie", "", 55u); +STATIC_TABLE_ENTRY("strict-transport-security", "", 56u); +STATIC_TABLE_ENTRY("transfer-encoding", "", 57u); +STATIC_TABLE_ENTRY("user-agent", "", 58u); +STATIC_TABLE_ENTRY("vary", "", 59u); +STATIC_TABLE_ENTRY("via", "", 60u); +STATIC_TABLE_ENTRY("www-authenticate", "", 61u);
diff --git a/net/http2/hpack/hpack_string.cc b/net/http2/hpack/hpack_string.cc index f84bedbf..b4b820b 100644 --- a/net/http2/hpack/hpack_string.cc +++ b/net/http2/hpack/hpack_string.cc
@@ -6,6 +6,8 @@ #include <utility> +#include "base/logging.h" + using base::StringPiece; using std::string; @@ -44,4 +46,33 @@ return out << v.ToString(); } +HpackStringPair::HpackStringPair(const HpackString& name, + const HpackString& value) + : name(name), value(value) { + DVLOG(3) << DebugString() << " ctor"; +} + +HpackStringPair::HpackStringPair(StringPiece name, StringPiece value) + : name(name), value(value) { + DVLOG(3) << DebugString() << " ctor"; +} + +HpackStringPair::~HpackStringPair() { + DVLOG(3) << DebugString() << " dtor"; +} + +string HpackStringPair::DebugString() const { + string debug_string("HpackStringPair(name="); + debug_string.append(name.ToString()); + debug_string.append(", value="); + debug_string.append(value.ToString()); + debug_string.append(")"); + return debug_string; +} + +std::ostream& operator<<(std::ostream& os, const HpackStringPair& p) { + os << p.DebugString(); + return os; +} + } // namespace net
diff --git a/net/http2/hpack/hpack_string.h b/net/http2/hpack/hpack_string.h index aeb0c96c..5a7b693 100644 --- a/net/http2/hpack/hpack_string.h +++ b/net/http2/hpack/hpack_string.h
@@ -30,6 +30,8 @@ // Not sure yet whether this move ctor is required/sensible. HpackString(HpackString&& other) = default; + HpackString& operator=(const HpackString& other) = default; + ~HpackString(); size_t size() const { return str_.size(); } @@ -51,6 +53,24 @@ NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, const HpackString& v); +struct NET_EXPORT_PRIVATE HpackStringPair { + HpackStringPair(const HpackString& name, const HpackString& value); + HpackStringPair(base::StringPiece name, base::StringPiece value); + ~HpackStringPair(); + + // Returns the size of a header entry with this name and value, per the RFC: + // http://httpwg.org/specs/rfc7541.html#calculating.table.size + size_t size() const { return 32 + name.size() + value.size(); } + + std::string DebugString() const; + + HpackString name; + HpackString value; +}; + +NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + const HpackStringPair& p); + } // namespace net #endif // NET_HTTP2_HPACK_HPACK_STRING_H_
diff --git a/net/http2/tools/http2_random.cc b/net/http2/tools/http2_random.cc index 8732d6a8..12dd7436 100644 --- a/net/http2/tools/http2_random.cc +++ b/net/http2/tools/http2_random.cc
@@ -4,7 +4,6 @@ #include "net/http2/tools/http2_random.h" -#include <limits> #include <memory> #include "base/rand_util.h"
diff --git a/net/http2/tools/http2_random.h b/net/http2/tools/http2_random.h index f7956cb8..eb3f6aa 100644 --- a/net/http2/tools/http2_random.h +++ b/net/http2/tools/http2_random.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <limits> #include <string> namespace net { @@ -24,8 +25,18 @@ virtual int32_t Next() = 0; virtual int32_t Skewed(int max_log) = 0; virtual std::string RandString(int length) = 0; + + // STL UniformRandomNumberGenerator implementation. + typedef uint32_t result_type; + static constexpr result_type min() { return 0; } + static constexpr result_type max() { + return std::numeric_limits<uint32_t>::max(); + } + result_type operator()() { return Rand32(); } }; +// Http2Random holds no state: instances use the same base::RandGenerator +// with a global state. class Http2Random : public RandomBase { public: ~Http2Random() override {}
diff --git a/net/http2/tools/random_util.cc b/net/http2/tools/random_util.cc new file mode 100644 index 0000000..b1abebb2 --- /dev/null +++ b/net/http2/tools/random_util.cc
@@ -0,0 +1,60 @@ +// 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 "net/http2/tools/random_util.h" + +#include <cmath> + +#include "net/http2/tools/http2_random.h" + +using std::string; +using base::StringPiece; + +namespace net { +namespace test { + +const char kWebsafe64[] = + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"; + +string RandomString(RandomBase* rng, int len, StringPiece alphabet) { + string random_string; + random_string.reserve(len); + for (int i = 0; i < len; ++i) + random_string.push_back(alphabet[rng->Uniform(alphabet.size())]); + return random_string; +} + +size_t GenerateUniformInRange(size_t lo, size_t hi, RandomBase* rng) { + if (lo + 1 >= hi) { + return lo; + } + return lo + rng->Rand64() % (hi - lo); +} + +// Here "word" means something that starts with a lower-case letter, and has +// zero or more additional characters that are numbers or lower-case letters. +string GenerateHttp2HeaderName(size_t len, RandomBase* rng) { + StringPiece alpha_lc = "abcdefghijklmnopqrstuvwxyz"; + // If the name is short, just make it one word. + if (len < 8) { + return RandomString(rng, len, alpha_lc); + } + // If the name is longer, ensure it starts with a word, and after that may + // have any character in alphanumdash_lc. 4 is arbitrary, could be as low + // as 1. + StringPiece alphanumdash_lc = "abcdefghijklmnopqrstuvwxyz0123456789-"; + return RandomString(rng, 4, alpha_lc) + + RandomString(rng, len - 4, alphanumdash_lc); +} + +string GenerateWebSafeString(size_t len, RandomBase* rng) { + return RandomString(rng, len, kWebsafe64); +} + +string GenerateWebSafeString(size_t lo, size_t hi, RandomBase* rng) { + return GenerateWebSafeString(GenerateUniformInRange(lo, hi, rng), rng); +} + +} // namespace test +} // namespace net
diff --git a/net/http2/tools/random_util.h b/net/http2/tools/random_util.h new file mode 100644 index 0000000..d29609a --- /dev/null +++ b/net/http2/tools/random_util.h
@@ -0,0 +1,39 @@ +// 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 NET_HTTP2_TOOLS_RANDOM_UTIL_H_ +#define NET_HTTP2_TOOLS_RANDOM_UTIL_H_ + +#include <stddef.h> + +#include <string> + +#include "base/strings/string_piece.h" + +namespace net { +namespace test { + +class RandomBase; + +// Returns a random string of length |len|, each character drawn uniformly and +// independently fom |alphabet|. +std::string RandomString(RandomBase* rng, int len, base::StringPiece alphabet); + +// Returns a random integer in the range [lo, hi). +size_t GenerateUniformInRange(size_t lo, size_t hi, RandomBase* rng); + +// Generate a string with the allowed character set for HTTP/2 / HPACK header +// names. +std::string GenerateHttp2HeaderName(size_t len, RandomBase* rng); + +// Generate a string with the web-safe string character set of specified len. +std::string GenerateWebSafeString(size_t len, RandomBase* rng); + +// Generate a string with the web-safe string character set of length [lo, hi). +std::string GenerateWebSafeString(size_t lo, size_t hi, RandomBase* rng); + +} // namespace test +} // namespace net + +#endif // NET_HTTP2_TOOLS_RANDOM_UTIL_H_
diff --git a/net/net.gypi b/net/net.gypi index ffe6103..61b4c175 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -817,6 +817,8 @@ 'http2/hpack/decoder/hpack_block_decoder.h', 'http2/hpack/decoder/hpack_decoder_string_buffer.cc', 'http2/hpack/decoder/hpack_decoder_string_buffer.h', + 'http2/hpack/decoder/hpack_decoder_tables.cc', + 'http2/hpack/decoder/hpack_decoder_tables.h', 'http2/hpack/decoder/hpack_entry_decoder.cc', 'http2/hpack/decoder/hpack_entry_decoder.h', 'http2/hpack/decoder/hpack_entry_decoder_listener.cc', @@ -833,6 +835,7 @@ 'http2/hpack/decoder/hpack_whole_entry_buffer.h', 'http2/hpack/decoder/hpack_whole_entry_listener.cc', 'http2/hpack/decoder/hpack_whole_entry_listener.h', + 'http2/hpack/hpack_static_table_entries.inc', 'http2/hpack/hpack_string.cc', 'http2/hpack/hpack_string.h', 'http2/hpack/http2_hpack_constants.cc', @@ -1791,6 +1794,7 @@ 'http2/hpack/decoder/hpack_block_collector.h', 'http2/hpack/decoder/hpack_block_decoder_test.cc', 'http2/hpack/decoder/hpack_decoder_string_buffer_test.cc', + 'http2/hpack/decoder/hpack_decoder_tables_test.cc', 'http2/hpack/decoder/hpack_entry_collector.cc', 'http2/hpack/decoder/hpack_entry_collector.h', 'http2/hpack/decoder/hpack_entry_decoder_test.cc', @@ -1822,6 +1826,8 @@ 'http2/tools/http2_random.h', 'http2/tools/random_decoder_test.cc', 'http2/tools/random_decoder_test.h', + 'http2/tools/random_util.cc', + 'http2/tools/random_util.h', 'log/file_net_log_observer_unittest.cc', 'log/net_log_capture_mode_unittest.cc', 'log/net_log_unittest.cc',
diff --git a/remoting/BUILD.gn b/remoting/BUILD.gn index 1ae1485b..ba7a7047 100644 --- a/remoting/BUILD.gn +++ b/remoting/BUILD.gn
@@ -145,6 +145,7 @@ "//google_apis", "//remoting/base:unit_tests", "//remoting/client:unit_tests", + "//remoting/client/display:unit_tests", "//remoting/protocol:unit_tests", "//remoting/signaling:unit_tests", "//remoting/test:unit_tests",
diff --git a/remoting/android/BUILD.gn b/remoting/android/BUILD.gn index 18f7213..bf0969d 100644 --- a/remoting/android/BUILD.gn +++ b/remoting/android/BUILD.gn
@@ -24,7 +24,7 @@ "//remoting/android:jni_headers", "//remoting/base", "//remoting/client", - "//remoting/client:opengl_renderer", + "//remoting/client/display", "//remoting/protocol", "//ui/events:dom_keycode_converter", "//ui/gfx",
diff --git a/remoting/client/BUILD.gn b/remoting/client/BUILD.gn index b5ff104..bb8345a 100644 --- a/remoting/client/BUILD.gn +++ b/remoting/client/BUILD.gn
@@ -73,56 +73,6 @@ } } -source_set("opengl_renderer") { - sources = [ - "gl_canvas.cc", - "gl_canvas.h", - "gl_cursor.cc", - "gl_cursor.h", - "gl_cursor_feedback.cc", - "gl_cursor_feedback.h", - "gl_cursor_feedback_texture.cc", - "gl_cursor_feedback_texture.h", - "gl_desktop.cc", - "gl_desktop.h", - "gl_helpers.cc", - "gl_helpers.h", - "gl_math.cc", - "gl_math.h", - "gl_render_layer.cc", - "gl_render_layer.h", - "gl_renderer.cc", - "gl_renderer.h", - ] - - deps = [ - "//remoting/proto", - "//third_party/libyuv", - "//third_party/webrtc/base:rtc_base", - ] - - configs += [ "//third_party/khronos:khronos_headers" ] - - if (is_linux) { - libs = [ "GL" ] - } - - if (is_mac) { - libs = [ "OpenGL.framework" ] - } - - if (is_ios) { - libs = [ - "GLKit.framework", - "OpenGLES.framework", - ] - } - - if (is_win) { - deps += [ "//third_party/angle:libGLESv2" ] - } -} - source_set("unit_tests") { testonly = true @@ -159,11 +109,4 @@ "//testing/gtest", "//third_party/webrtc/base:rtc_base", ] - - if (!is_win) { - # Windows clang builder fails to link the test binary with ANGLE GLESv2. - # crbug.com/642027 - sources += [ "gl_renderer_unittest.cc" ] - deps += [ ":opengl_renderer" ] - } }
diff --git a/remoting/client/display/BUILD.gn b/remoting/client/display/BUILD.gn new file mode 100644 index 0000000..102850b --- /dev/null +++ b/remoting/client/display/BUILD.gn
@@ -0,0 +1,81 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("display") { + sources = [ + "gl_canvas.cc", + "gl_canvas.h", + "gl_cursor.cc", + "gl_cursor.h", + "gl_cursor_feedback.cc", + "gl_cursor_feedback.h", + "gl_cursor_feedback_texture.cc", + "gl_cursor_feedback_texture.h", + "gl_desktop.cc", + "gl_desktop.h", + "gl_helpers.cc", + "gl_helpers.h", + "gl_math.cc", + "gl_math.h", + "gl_render_layer.cc", + "gl_render_layer.h", + "gl_renderer.cc", + "gl_renderer.h", + ] + + deps = [ + "//remoting/proto", + "//third_party/libyuv", + "//third_party/webrtc/base:rtc_base", + ] + + configs += [ "//third_party/khronos:khronos_headers" ] + + if (is_linux) { + libs = [ "GL" ] + } + + if (is_mac) { + libs = [ "OpenGL.framework" ] + } + + if (is_ios) { + libs = [ + "GLKit.framework", + "OpenGLES.framework", + ] + } + + if (is_win) { + deps += [ "//third_party/angle:libGLESv2" ] + } +} + +source_set("unit_tests") { + testonly = true + + sources = [ + "gl_renderer_unittest.cc", + ] + + configs += [ + "//remoting/build/config:version", + "//remoting/build/config:enable_webrtc_remoting_client", + ] + + deps = [ + ":display", + "//remoting/proto", + "//testing/gmock", + "//testing/gtest", + "//third_party/webrtc/base:rtc_base", + ] + + if (is_win) { + # Windows clang builder fails to link the test binary with ANGLE GLESv2. + # crbug.com/642027 + sources -= [ "gl_renderer_unittest.cc" ] + deps -= [ ":display" ] + } +}
diff --git a/remoting/client/display/DEPS b/remoting/client/display/DEPS new file mode 100644 index 0000000..71d244b --- /dev/null +++ b/remoting/client/display/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "-remoting/client", + "+remoting/client/display", +]
diff --git a/remoting/client/gl_canvas.cc b/remoting/client/display/gl_canvas.cc similarity index 91% rename from remoting/client/gl_canvas.cc rename to remoting/client/display/gl_canvas.cc index 0a49f13..31d6b95 100644 --- a/remoting/client/gl_canvas.cc +++ b/remoting/client/display/gl_canvas.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_canvas.h" +#include "remoting/client/display/gl_canvas.h" #include "base/logging.h" -#include "remoting/client/gl_helpers.h" -#include "remoting/client/gl_math.h" +#include "remoting/client/display/gl_helpers.h" +#include "remoting/client/display/gl_math.h" namespace { @@ -37,15 +37,15 @@ "void main() {\n" " v_texCoord = a_texCoord;\n" - // Transforms coordinates related to the canvas to coordinates - // related to the view. + // Transforms coordinates related to the canvas to coordinates + // related to the view. " vec3 trans_position = u_transform * vec3(a_position, 1.0);\n" - // Normalize the position by the size of the view. + // Normalize the position by the size of the view. " trans_position.xy /= u_viewSize;\n" - // Transforms texture coordinates to view coordinates and adds - // projection component 1. + // Transforms texture coordinates to view coordinates and adds + // projection component 1. " gl_Position = vec4(tex_to_view * trans_position, 1.0);\n" "}"; @@ -108,7 +108,7 @@ void GlCanvas::SetViewSize(int width, int height) { DCHECK(width > 0 && height > 0); glViewport(0, 0, width, height); - float view_size[2] {width, height}; + float view_size[2]{width, height}; glUniform2fv(view_size_location_, 1, view_size); view_size_set_ = true; }
diff --git a/remoting/client/gl_canvas.h b/remoting/client/display/gl_canvas.h similarity index 94% rename from remoting/client/gl_canvas.h rename to remoting/client/display/gl_canvas.h index 4df0a4b8..975d79bc 100644 --- a/remoting/client/gl_canvas.h +++ b/remoting/client/display/gl_canvas.h
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_OPENGL_GL_CANVAS_H_ -#define REMOTING_CLIENT_OPENGL_GL_CANVAS_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_CANVAS_H_ +#define REMOTING_CLIENT_DISPLAY_GL_CANVAS_H_ #include <array> #include "base/macros.h" #include "base/threading/thread_checker.h" -#include "remoting/client/sys_opengl.h" +#include "remoting/client/display/sys_opengl.h" namespace remoting { @@ -91,4 +91,4 @@ } // namespace remoting -#endif // REMOTING_CLIENT_OPENGL_GL_CANVAS_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_CANVAS_H_
diff --git a/remoting/client/gl_cursor.cc b/remoting/client/display/gl_cursor.cc similarity index 90% rename from remoting/client/gl_cursor.cc rename to remoting/client/display/gl_cursor.cc index 152923ad..4a4c55a 100644 --- a/remoting/client/gl_cursor.cc +++ b/remoting/client/display/gl_cursor.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_cursor.h" +#include "remoting/client/display/gl_cursor.h" #include "remoting/base/util.h" -#include "remoting/client/gl_canvas.h" -#include "remoting/client/gl_math.h" -#include "remoting/client/gl_render_layer.h" -#include "remoting/client/gl_texture_ids.h" +#include "remoting/client/display/gl_canvas.h" +#include "remoting/client/display/gl_math.h" +#include "remoting/client/display/gl_render_layer.h" +#include "remoting/client/display/gl_texture_ids.h" #include "remoting/proto/control.pb.h" #include "third_party/libyuv/include/libyuv/convert_argb.h" @@ -24,7 +24,7 @@ void GlCursor::SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) { int data_size = cursor_shape.width() * cursor_shape.height() * - GlRenderLayer::kBytesPerPixel; + GlRenderLayer::kBytesPerPixel; if (current_cursor_data_size_ < data_size) { current_cursor_data_size_ = kDefaultCursorDataSize > data_size ? kDefaultCursorDataSize : data_size;
diff --git a/remoting/client/gl_cursor.h b/remoting/client/display/gl_cursor.h similarity index 91% rename from remoting/client/gl_cursor.h rename to remoting/client/display/gl_cursor.h index 365b2c2..eec03e8 100644 --- a/remoting/client/gl_cursor.h +++ b/remoting/client/display/gl_cursor.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_OPENGL_GL_CURSOR_H_ -#define REMOTING_CLIENT_OPENGL_GL_CURSOR_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_CURSOR_H_ +#define REMOTING_CLIENT_DISPLAY_GL_CURSOR_H_ #include <array> #include <cstdint> @@ -63,4 +63,4 @@ }; } // namespace remoting -#endif // REMOTING_CLIENT_OPENGL_GL_CURSOR_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_CURSOR_H_
diff --git a/remoting/client/gl_cursor_feedback.cc b/remoting/client/display/gl_cursor_feedback.cc similarity index 85% rename from remoting/client/gl_cursor_feedback.cc rename to remoting/client/display/gl_cursor_feedback.cc index c3fcbb49..41736aed 100644 --- a/remoting/client/gl_cursor_feedback.cc +++ b/remoting/client/display/gl_cursor_feedback.cc
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_cursor_feedback.h" +#include "remoting/client/display/gl_cursor_feedback.h" #include <math.h> #include <array> #include "base/logging.h" -#include "remoting/client/gl_canvas.h" -#include "remoting/client/gl_cursor_feedback_texture.h" -#include "remoting/client/gl_math.h" -#include "remoting/client/gl_render_layer.h" -#include "remoting/client/gl_texture_ids.h" +#include "remoting/client/display/gl_canvas.h" +#include "remoting/client/display/gl_cursor_feedback_texture.h" +#include "remoting/client/display/gl_math.h" +#include "remoting/client/display/gl_render_layer.h" +#include "remoting/client/display/gl_texture_ids.h" namespace { @@ -80,8 +80,8 @@ float diameter = GetExpansionCoefficient(progress) * max_diameter_; std::array<float, 8> positions; FillRectangleVertexPositions(cursor_x_ - diameter / 2, - cursor_y_ - diameter / 2, - diameter, diameter, &positions); + cursor_y_ - diameter / 2, diameter, diameter, + &positions); layer_->SetVertexPositions(positions); // Linear fade-out.
diff --git a/remoting/client/gl_cursor_feedback.h b/remoting/client/display/gl_cursor_feedback.h similarity index 86% rename from remoting/client/gl_cursor_feedback.h rename to remoting/client/display/gl_cursor_feedback.h index 6405efc..230b523 100644 --- a/remoting/client/gl_cursor_feedback.h +++ b/remoting/client/display/gl_cursor_feedback.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_OPENGL_GL_CURSOR_FEEDBACK_H_ -#define REMOTING_CLIENT_OPENGL_GL_CURSOR_FEEDBACK_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_H_ +#define REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_H_ #include <stdint.h> @@ -45,4 +45,4 @@ }; } // namespace remoting -#endif // REMOTING_CLIENT_OPENGL_GL_CURSOR_FEEDBACK_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_H_
diff --git a/remoting/client/gl_cursor_feedback_texture.cc b/remoting/client/display/gl_cursor_feedback_texture.cc similarity index 89% rename from remoting/client/gl_cursor_feedback_texture.cc rename to remoting/client/display/gl_cursor_feedback_texture.cc index d41d222..33a839e 100644 --- a/remoting/client/gl_cursor_feedback_texture.cc +++ b/remoting/client/display/gl_cursor_feedback_texture.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_cursor_feedback_texture.h" +#include "remoting/client/display/gl_cursor_feedback_texture.h" -#include "remoting/client/gl_render_layer.h" +#include "remoting/client/display/gl_render_layer.h" namespace remoting { @@ -17,15 +17,15 @@ // RGBA8888 colors. From inside to outside. const uint8_t kFeedbackRingColors[kColorRingsCount] [GlRenderLayer::kBytesPerPixel] = { - {0x0, 0x0, 0x0, 0x7f}, // Black - {0x0, 0x0, 0x0, 0x7f}, // Black + {0x0, 0x0, 0x0, 0x7f}, // Black + {0x0, 0x0, 0x0, 0x7f}, // Black {0xff, 0xff, 0xff, 0x7f}, // White {0xff, 0xff, 0xff, 0x7f}, // White {0xff, 0xff, 0xff, 0} // Transparent White }; -const float kFeedbackRadiusStops[kColorRingsCount] = - {0.0f, 0.85f, 0.9f, 0.95f, 1.0f}; +const float kFeedbackRadiusStops[kColorRingsCount] = {0.0f, 0.85f, 0.9f, 0.95f, + 1.0f}; uint32_t GetColorByRadius(float radius) { int ring_index = kColorRingsCount - 1;
diff --git a/remoting/client/gl_cursor_feedback_texture.h b/remoting/client/display/gl_cursor_feedback_texture.h similarity index 80% rename from remoting/client/gl_cursor_feedback_texture.h rename to remoting/client/display/gl_cursor_feedback_texture.h index 1826d21..c73dc035 100644 --- a/remoting/client/gl_cursor_feedback_texture.h +++ b/remoting/client/display/gl_cursor_feedback_texture.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_GL_CURSOR_FEEDBACK_TEXTURE_H_ -#define REMOTING_CLIENT_GL_CURSOR_FEEDBACK_TEXTURE_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_TEXTURE_H_ +#define REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_TEXTURE_H_ #include <vector> @@ -34,4 +34,4 @@ }; } // namespace remoting -#endif // REMOTING_CLIENT_GL_CURSOR_FEEDBACK_TEXTURE_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_TEXTURE_H_
diff --git a/remoting/client/gl_desktop.cc b/remoting/client/display/gl_desktop.cc similarity index 94% rename from remoting/client/gl_desktop.cc rename to remoting/client/display/gl_desktop.cc index 72bd9ec..e033d54 100644 --- a/remoting/client/gl_desktop.cc +++ b/remoting/client/display/gl_desktop.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_desktop.h" +#include "remoting/client/display/gl_desktop.h" #include "base/logging.h" #include "base/memory/ptr_util.h" -#include "remoting/client/gl_canvas.h" -#include "remoting/client/gl_math.h" -#include "remoting/client/gl_render_layer.h" -#include "remoting/client/gl_texture_ids.h" +#include "remoting/client/display/gl_canvas.h" +#include "remoting/client/display/gl_math.h" +#include "remoting/client/display/gl_render_layer.h" +#include "remoting/client/display/gl_texture_ids.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
diff --git a/remoting/client/gl_desktop.h b/remoting/client/display/gl_desktop.h similarity index 89% rename from remoting/client/gl_desktop.h rename to remoting/client/display/gl_desktop.h index 143a063..d43247c5 100644 --- a/remoting/client/gl_desktop.h +++ b/remoting/client/display/gl_desktop.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_OPENGL_GL_DESKTOP_H_ -#define REMOTING_CLIENT_OPENGL_GL_DESKTOP_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_DESKTOP_H_ +#define REMOTING_CLIENT_DISPLAY_GL_DESKTOP_H_ #include <memory> #include <vector> @@ -52,4 +52,4 @@ } // namespace remoting -#endif // REMOTING_CLIENT_OPENGL_GL_DESKTOP_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_DESKTOP_H_
diff --git a/remoting/client/gl_helpers.cc b/remoting/client/display/gl_helpers.cc similarity index 97% rename from remoting/client/gl_helpers.cc rename to remoting/client/display/gl_helpers.cc index 5cd1863..bce438b 100644 --- a/remoting/client/gl_helpers.cc +++ b/remoting/client/display/gl_helpers.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_helpers.h" +#include "remoting/client/display/gl_helpers.h" #include "base/logging.h"
diff --git a/remoting/client/gl_helpers.h b/remoting/client/display/gl_helpers.h similarity index 81% rename from remoting/client/gl_helpers.h rename to remoting/client/display/gl_helpers.h index 8dba721..16218d9 100644 --- a/remoting/client/gl_helpers.h +++ b/remoting/client/display/gl_helpers.h
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_GL_HELPERS_H_ -#define REMOTING_CLIENT_GL_HELPERS_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_HELPERS_H_ +#define REMOTING_CLIENT_DISPLAY_GL_HELPERS_H_ #include "base/macros.h" -#include "remoting/client/sys_opengl.h" +#include "remoting/client/display/sys_opengl.h" namespace remoting { @@ -26,4 +26,4 @@ } // namespace remoting -#endif // REMOTING_CLIENT_GL_HELPERS_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_HELPERS_H_
diff --git a/remoting/client/gl_math.cc b/remoting/client/display/gl_math.cc similarity index 96% rename from remoting/client/gl_math.cc rename to remoting/client/display/gl_math.cc index 6102e3c..b91229b 100644 --- a/remoting/client/gl_math.cc +++ b/remoting/client/display/gl_math.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_math.h" +#include "remoting/client/display/gl_math.h" #include <sstream>
diff --git a/remoting/client/gl_math.h b/remoting/client/display/gl_math.h similarity index 90% rename from remoting/client/gl_math.h rename to remoting/client/display/gl_math.h index cc8fc1b..184d37c 100644 --- a/remoting/client/gl_math.h +++ b/remoting/client/display/gl_math.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_OPENGL_GL_MATH_H_ -#define REMOTING_CLIENT_OPENGL_GL_MATH_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_MATH_H_ +#define REMOTING_CLIENT_DISPLAY_GL_MATH_H_ #include <array> #include <string> @@ -43,4 +43,4 @@ } // namespace remoting -#endif // REMOTING_CLIENT_OPENGL_GL_MATH_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_MATH_H_
diff --git a/remoting/client/gl_render_layer.cc b/remoting/client/display/gl_render_layer.cc similarity index 97% rename from remoting/client/gl_render_layer.cc rename to remoting/client/display/gl_render_layer.cc index 7d3e06ce..6fcb08c 100644 --- a/remoting/client/gl_render_layer.cc +++ b/remoting/client/display/gl_render_layer.cc
@@ -2,12 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_render_layer.h" +#include "remoting/client/display/gl_render_layer.h" #include "base/logging.h" -#include "remoting/client/gl_canvas.h" -#include "remoting/client/gl_helpers.h" - +#include "remoting/client/display/gl_canvas.h" +#include "remoting/client/display/gl_helpers.h" namespace remoting {
diff --git a/remoting/client/gl_render_layer.h b/remoting/client/display/gl_render_layer.h similarity index 94% rename from remoting/client/gl_render_layer.h rename to remoting/client/display/gl_render_layer.h index 5306e84..153e2e3e 100644 --- a/remoting/client/gl_render_layer.h +++ b/remoting/client/display/gl_render_layer.h
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_OPENGL_GL_RENDER_LAYER_H_ -#define REMOTING_CLIENT_OPENGL_GL_RENDER_LAYER_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_RENDER_LAYER_H_ +#define REMOTING_CLIENT_DISPLAY_GL_RENDER_LAYER_H_ #include <array> #include <memory> #include "base/macros.h" #include "base/threading/thread_checker.h" -#include "remoting/client/sys_opengl.h" +#include "remoting/client/display/sys_opengl.h" namespace remoting { class GlCanvas; @@ -97,4 +97,4 @@ }; } // namespace remoting -#endif // REMOTING_CLIENT_OPENGL_GL_RENDER_LAYER_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_RENDER_LAYER_H_
diff --git a/remoting/client/gl_renderer.cc b/remoting/client/display/gl_renderer.cc similarity index 94% rename from remoting/client/gl_renderer.cc rename to remoting/client/display/gl_renderer.cc index 64ce7d3..c975e54 100644 --- a/remoting/client/gl_renderer.cc +++ b/remoting/client/display/gl_renderer.cc
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_renderer.h" +#include "remoting/client/display/gl_renderer.h" #include "base/bind.h" #include "base/logging.h" #include "base/threading/thread_task_runner_handle.h" -#include "remoting/client/gl_canvas.h" -#include "remoting/client/gl_math.h" -#include "remoting/client/gl_renderer_delegate.h" -#include "remoting/client/sys_opengl.h" +#include "remoting/client/display/gl_canvas.h" +#include "remoting/client/display/gl_math.h" +#include "remoting/client/display/gl_renderer_delegate.h" +#include "remoting/client/display/sys_opengl.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" namespace remoting {
diff --git a/remoting/client/gl_renderer.h b/remoting/client/display/gl_renderer.h similarity index 93% rename from remoting/client/gl_renderer.h rename to remoting/client/display/gl_renderer.h index 832bd63..3cecb13 100644 --- a/remoting/client/gl_renderer.h +++ b/remoting/client/display/gl_renderer.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_GL_RENDERER_H_ -#define REMOTING_CLIENT_GL_RENDERER_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_RENDERER_H_ +#define REMOTING_CLIENT_DISPLAY_GL_RENDERER_H_ #include <queue> @@ -11,9 +11,9 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" -#include "remoting/client/gl_cursor.h" -#include "remoting/client/gl_cursor_feedback.h" -#include "remoting/client/gl_desktop.h" +#include "remoting/client/display/gl_cursor.h" +#include "remoting/client/display/gl_cursor_feedback.h" +#include "remoting/client/display/gl_desktop.h" #include "remoting/proto/control.pb.h" namespace webrtc { @@ -134,4 +134,4 @@ } // namespace remoting -#endif // REMOTING_CLIENT_GL_RENDERER_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_RENDERER_H_
diff --git a/remoting/client/gl_renderer_delegate.h b/remoting/client/display/gl_renderer_delegate.h similarity index 83% rename from remoting/client/gl_renderer_delegate.h rename to remoting/client/display/gl_renderer_delegate.h index 5d15a1e7..af97759 100644 --- a/remoting/client/gl_renderer_delegate.h +++ b/remoting/client/display/gl_renderer_delegate.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_GL_RENDERER_DELEGATE_H_ -#define REMOTING_CLIENT_GL_RENDERER_DELEGATE_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_RENDERER_DELEGATE_H_ +#define REMOTING_CLIENT_DISPLAY_GL_RENDERER_DELEGATE_H_ #include "base/macros.h" @@ -29,4 +29,4 @@ }; } // namespace remoting -#endif // REMOTING_CLIENT_GL_RENDERER_DELEGATE_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_RENDERER_DELEGATE_H_
diff --git a/remoting/client/gl_renderer_unittest.cc b/remoting/client/display/gl_renderer_unittest.cc similarity index 90% rename from remoting/client/gl_renderer_unittest.cc rename to remoting/client/display/gl_renderer_unittest.cc index 1a17e42..7edb9bd0 100644 --- a/remoting/client/gl_renderer_unittest.cc +++ b/remoting/client/display/gl_renderer_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/gl_renderer.h" +#include "remoting/client/display/gl_renderer.h" #include "base/bind.h" #include "base/bind_helpers.h" @@ -10,7 +10,7 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" -#include "remoting/client/gl_renderer_delegate.h" +#include "remoting/client/display/gl_renderer_delegate.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" @@ -42,29 +42,19 @@ on_frame_rendered_callback_ = callback; } - int canvas_width() { - return canvas_width_; - } + int canvas_width() { return canvas_width_; } - int canvas_height() { - return canvas_height_; - } + int canvas_height() { return canvas_height_; } base::WeakPtr<FakeGlRendererDelegate> GetWeakPtr() { return weak_factory_.GetWeakPtr(); } - int can_render_frame_call_count() { - return can_render_frame_call_count_; - } + int can_render_frame_call_count() { return can_render_frame_call_count_; } - int on_frame_rendered_call_count() { - return on_frame_rendered_call_count_; - } + int on_frame_rendered_call_count() { return on_frame_rendered_call_count_; } - int on_size_changed_call_count() { - return on_size_changed_call_count_; - } + int on_size_changed_call_count() { return on_size_changed_call_count_; } bool can_render_frame_ = false; @@ -120,8 +110,8 @@ base::Unretained(this))); } -void GlRendererTest::PostSetDesktopFrameTasks( - const webrtc::DesktopSize& size, int count) { +void GlRendererTest::PostSetDesktopFrameTasks(const webrtc::DesktopSize& size, + int count) { for (int i = 0; i < count; i++) { message_loop_.task_runner()->PostTask( FROM_HERE, base::Bind(&GlRendererTest::SetDesktopFrameWithSize, @@ -145,7 +135,6 @@ run_loop.Run(); } - TEST_F(GlRendererTest, TestDelegateCanRenderFrame) { delegate_.can_render_frame_ = true; RequestRender();
diff --git a/remoting/client/gl_texture_ids.h b/remoting/client/display/gl_texture_ids.h similarity index 77% rename from remoting/client/gl_texture_ids.h rename to remoting/client/display/gl_texture_ids.h index a4fb91e..3680973 100644 --- a/remoting/client/gl_texture_ids.h +++ b/remoting/client/display/gl_texture_ids.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_GL_TEXTURE_IDS_H_ -#define REMOTING_CLIENT_GL_TEXTURE_IDS_H_ +#ifndef REMOTING_CLIENT_DISPLAY_GL_TEXTURE_IDS_H_ +#define REMOTING_CLIENT_DISPLAY_GL_TEXTURE_IDS_H_ #include "base/macros.h" @@ -19,4 +19,4 @@ } // namespace remoting -#endif // REMOTING_CLIENT_GL_TEXTURE_IDS_H_ +#endif // REMOTING_CLIENT_DISPLAY_GL_TEXTURE_IDS_H_
diff --git a/remoting/client/sys_opengl.h b/remoting/client/display/sys_opengl.h similarity index 77% rename from remoting/client/sys_opengl.h rename to remoting/client/display/sys_opengl.h index 8a1c907d..90abd6be 100644 --- a/remoting/client/sys_opengl.h +++ b/remoting/client/display/sys_opengl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_SYS_OPENGL_H_ -#define REMOTING_CLIENT_SYS_OPENGL_H_ +#ifndef REMOTING_CLIENT_DISPLAY_SYS_OPENGL_H_ +#define REMOTING_CLIENT_DISPLAY_SYS_OPENGL_H_ #include "build/build_config.h" @@ -21,4 +21,4 @@ #include <GLES3/gl3.h> #endif // defined(OS_IOS) -#endif // REMOTING_CLIENT_SYS_OPENGL_H_ +#endif // REMOTING_CLIENT_DISPLAY_SYS_OPENGL_H_
diff --git a/remoting/client/ios/example_view_controller.mm b/remoting/client/ios/example_view_controller.mm index dbac4297..64fd9ac 100644 --- a/remoting/client/ios/example_view_controller.mm +++ b/remoting/client/ios/example_view_controller.mm
@@ -8,7 +8,7 @@ #import "remoting/client/ios/example_view_controller.h" -#import "remoting/client/sys_opengl.h" +#import "remoting/client/display/sys_opengl.h" @interface ExampleViewController()
diff --git a/remoting/client/jni/jni_gl_display_handler.h b/remoting/client/jni/jni_gl_display_handler.h index df79553..12a5d78 100644 --- a/remoting/client/jni/jni_gl_display_handler.h +++ b/remoting/client/jni/jni_gl_display_handler.h
@@ -11,8 +11,8 @@ #include "base/android/scoped_java_ref.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "remoting/client/gl_renderer.h" -#include "remoting/client/gl_renderer_delegate.h" +#include "remoting/client/display/gl_renderer.h" +#include "remoting/client/display/gl_renderer_delegate.h" #include "remoting/client/queued_task_poster.h" #include "remoting/protocol/cursor_shape_stub.h"
diff --git a/services/ui/surfaces/display_compositor.cc b/services/ui/surfaces/display_compositor.cc index 80faca0..35c92cd 100644 --- a/services/ui/surfaces/display_compositor.cc +++ b/services/ui/surfaces/display_compositor.cc
@@ -169,13 +169,13 @@ } // Remove markers for temporary references up to |child_id|, as the temporary - // references they correspond to were removed above. If |ref_iter| is the last - // element in |refs| then we are removing all temporary references for the - // FrameSinkId and can remove the map entry entirely. + // references they correspond to were removed above. If |temp_ref_iter| points + // at the last element in |refs| then we are removing all temporary references + // for the FrameSinkId and can remove the map entry entirely. if (++temp_ref_iter == refs.end()) temp_references_.erase(child_id.frame_sink_id()); else - refs.erase(refs.begin(), ++temp_ref_iter); + refs.erase(refs.begin(), temp_ref_iter); } void DisplayCompositor::RemoveSurfaceReference(
diff --git a/services/ui/surfaces/display_compositor_unittest.cc b/services/ui/surfaces/display_compositor_unittest.cc index 23d32a5..6d2cf5a1 100644 --- a/services/ui/surfaces/display_compositor_unittest.cc +++ b/services/ui/surfaces/display_compositor_unittest.cc
@@ -285,5 +285,36 @@ EXPECT_EQ(0u, CountTempReferences()); } +TEST_F(DisplayCompositorTest, RemoveFirstTempRefOnly) { + const cc::SurfaceId parent_id = MakeSurfaceId(1, 1, 1); + const cc::SurfaceId surface_id1 = MakeSurfaceId(2, 1, 1); + const cc::SurfaceId surface_id2 = MakeSurfaceId(2, 1, 2); + + // Add two surfaces that have the same FrameSinkId. This would happen when a + // client submits two CFs before parent submits a new CF. + surface_observer()->OnSurfaceCreated( + cc::SurfaceInfo(surface_id1, 1.0f, gfx::Size(1, 1))); + surface_observer()->OnSurfaceCreated( + cc::SurfaceInfo(surface_id2, 1.0f, gfx::Size(1, 1))); + RunUntilIdle(); + + // Client should get OnSurfaceCreated call and temporary reference added for + // both surfaces. + EXPECT_EQ("OnSurfaceCreated(2:1:1);OnSurfaceCreated(2:1:2)", + client_.events()); + EXPECT_EQ("Add(0:0:0-2:1:1);Add(0:0:0-2:1:2)", reference_manager_.events()); + EXPECT_EQ(2u, CountTempReferences()); + + // Add a reference to the surface with the earlier LocalFrameId. + AddSurfaceReference(parent_id, surface_id1); + RunUntilIdle(); + + // The real reference should be added for 2:1:1 and temporary reference + // should be removed. The temporary reference for 2:1:2 should remain. + EXPECT_EQ("Add(1:1:1-2:1:1);Remove(0:0:0-2:1:1)", + reference_manager_.events()); + EXPECT_EQ(1u, CountTempReferences()); +} + } // namespace test } // namespace ui
diff --git a/services/ui/ws/display.cc b/services/ui/ws/display.cc index 6314eb3..8a9cf98 100644 --- a/services/ui/ws/display.cc +++ b/services/ui/ws/display.cc
@@ -271,6 +271,13 @@ return root_.get(); } +ServerWindow* Display::GetActiveRootWindow() { + WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot(); + if (display_root) + return display_root->root(); + return nullptr; +} + void Display::OnAcceleratedWidgetAvailable() { display_manager()->OnDisplayAcceleratedWidgetAvailable(this); InitWindowManagerDisplayRoots();
diff --git a/services/ui/ws/display.h b/services/ui/ws/display.h index 839f5e94..28bf83b 100644 --- a/services/ui/ws/display.h +++ b/services/ui/ws/display.h
@@ -166,6 +166,7 @@ // PlatformDisplayDelegate: display::Display GetDisplay() override; ServerWindow* GetRootWindow() override; + ServerWindow* GetActiveRootWindow() override; void OnAcceleratedWidgetAvailable() override; bool IsInHighContrastMode() override; void OnEvent(const ui::Event& event) override;
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc index 7229a29..c4c309b 100644 --- a/services/ui/ws/frame_generator.cc +++ b/services/ui/ws/frame_generator.cc
@@ -130,7 +130,7 @@ render_pass->SetNew(render_pass_id, output_rect, output_rect, gfx::Transform()); - DrawWindowTree(render_pass.get(), root_window_, gfx::Vector2d(), 1.0f); + DrawWindow(render_pass.get(), delegate_->GetActiveRootWindow()); cc::CompositorFrame frame; frame.render_pass_list.push_back(std::move(render_pass)); @@ -155,80 +155,40 @@ return frame; } -void FrameGenerator::DrawWindowTree( - cc::RenderPass* pass, - ServerWindow* window, - const gfx::Vector2d& parent_to_root_origin_offset, - float opacity) { - if (!window->visible()) +void FrameGenerator::DrawWindow(cc::RenderPass* pass, ServerWindow* window) { + if (!window || !window->visible()) return; - const gfx::Rect absolute_bounds = - window->bounds() + parent_to_root_origin_offset; - const ServerWindow::Windows& children = window->children(); - const float combined_opacity = opacity * window->opacity(); - for (ServerWindow* child : base::Reversed(children)) { - DrawWindowTree(pass, child, absolute_bounds.OffsetFromOrigin(), - combined_opacity); - } - if (!window->compositor_frame_sink_manager() || !window->compositor_frame_sink_manager()->ShouldDraw()) return; - cc::SurfaceId underlay_surface_id = - window->compositor_frame_sink_manager()->GetLatestSurfaceId( - mojom::CompositorFrameSinkType::UNDERLAY); cc::SurfaceId default_surface_id = window->compositor_frame_sink_manager()->GetLatestSurfaceId( mojom::CompositorFrameSinkType::DEFAULT); - if (!underlay_surface_id.is_valid() && !default_surface_id.is_valid()) + if (!default_surface_id.is_valid()) return; - if (default_surface_id.is_valid()) { - gfx::Transform quad_to_target_transform; - quad_to_target_transform.Translate(absolute_bounds.x(), - absolute_bounds.y()); + gfx::Transform quad_to_target_transform; + quad_to_target_transform.Translate(window->bounds().x(), + window->bounds().y()); - cc::SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState(); + cc::SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState(); - const gfx::Rect bounds_at_origin(window->bounds().size()); - // TODO(fsamuel): These clipping and visible rects are incorrect. They need - // to be populated from CompositorFrame structs. - sqs->SetAll( - quad_to_target_transform, bounds_at_origin.size() /* layer_bounds */, - bounds_at_origin /* visible_layer_bounds */, - bounds_at_origin /* clip_rect */, false /* is_clipped */, - combined_opacity, SkBlendMode::kSrcOver, 0 /* sorting-context_id */); - auto* quad = pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>(); - quad->SetAll(sqs, bounds_at_origin /* rect */, - gfx::Rect() /* opaque_rect */, - bounds_at_origin /* visible_rect */, true /* needs_blending*/, - default_surface_id); - } - if (underlay_surface_id.is_valid()) { - const gfx::Rect underlay_absolute_bounds = - absolute_bounds - window->underlay_offset(); - gfx::Transform quad_to_target_transform; - quad_to_target_transform.Translate(underlay_absolute_bounds.x(), - underlay_absolute_bounds.y()); - cc::SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState(); - const gfx::Rect bounds_at_origin( - window->compositor_frame_sink_manager()->GetLatestFrameSize( - mojom::CompositorFrameSinkType::UNDERLAY)); - sqs->SetAll( - quad_to_target_transform, bounds_at_origin.size() /* layer_bounds */, - bounds_at_origin /* visible_layer_bounds */, - bounds_at_origin /* clip_rect */, false /* is_clipped */, - combined_opacity, SkBlendMode::kSrcOver, 0 /* sorting-context_id */); - - auto* quad = pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>(); - quad->SetAll(sqs, bounds_at_origin /* rect */, - gfx::Rect() /* opaque_rect */, - bounds_at_origin /* visible_rect */, true /* needs_blending*/, - underlay_surface_id); - } + const gfx::Rect bounds_at_origin(window->bounds().size()); + // TODO(fsamuel): These clipping and visible rects are incorrect. They need + // to be populated from CompositorFrame structs. + sqs->SetAll( + quad_to_target_transform, bounds_at_origin.size() /* layer_bounds */, + bounds_at_origin /* visible_layer_bounds */, + bounds_at_origin /* clip_rect */, false /* is_clipped */, + 1.0f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting-context_id */); + auto* quad = pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>(); + quad->SetAll(sqs, bounds_at_origin /* rect */, + gfx::Rect() /* opaque_rect */, + bounds_at_origin /* visible_rect */, true /* needs_blending*/, + default_surface_id); } cc::SurfaceId FrameGenerator::FindParentSurfaceId(ServerWindow* window) {
diff --git a/services/ui/ws/frame_generator.h b/services/ui/ws/frame_generator.h index 706f851..d60b8b2 100644 --- a/services/ui/ws/frame_generator.h +++ b/services/ui/ws/frame_generator.h
@@ -80,12 +80,9 @@ // Generates the CompositorFrame. cc::CompositorFrame GenerateCompositorFrame(const gfx::Rect& output_rect); - // DrawWindowTree recursively visits ServerWindows, creating a SurfaceDrawQuad - // for each that lacks one. - void DrawWindowTree(cc::RenderPass* pass, - ServerWindow* window, - const gfx::Vector2d& parent_to_root_origin_offset, - float opacity); + // DrawWindow creates SurfaceDrawQuad for the provided ServerWindow and + // appends it to the provided cc::RenderPass. + void DrawWindow(cc::RenderPass* pass, ServerWindow* window); // Finds the parent surface id for |window|. cc::SurfaceId FindParentSurfaceId(ServerWindow* window);
diff --git a/services/ui/ws/frame_generator_delegate.h b/services/ui/ws/frame_generator_delegate.h index 03fbcd04..88b2085 100644 --- a/services/ui/ws/frame_generator_delegate.h +++ b/services/ui/ws/frame_generator_delegate.h
@@ -10,6 +10,8 @@ class FrameGeneratorDelegate { public: + // Returns the root window of the active user. + virtual ServerWindow* GetActiveRootWindow() = 0; virtual bool IsInHighContrastMode() = 0; protected:
diff --git a/services/ui/ws/frame_generator_unittest.cc b/services/ui/ws/frame_generator_unittest.cc index 49c4a98..ea6017e 100644 --- a/services/ui/ws/frame_generator_unittest.cc +++ b/services/ui/ws/frame_generator_unittest.cc
@@ -52,8 +52,8 @@ kRootDisplayId)) {} ~FrameGeneratorTest() override {} - // Calls DrawWindowTree() on |frame_generator_| - void DrawWindowTree(cc::RenderPass* pass); + // Calls DrawWindow() on |frame_generator_| + void DrawWindow(cc::RenderPass* pass); ServerWindow* root_window() { return root_window_.get(); } @@ -75,14 +75,14 @@ DISALLOW_COPY_AND_ASSIGN(FrameGeneratorTest); }; -void FrameGeneratorTest::DrawWindowTree(cc::RenderPass* pass) { - frame_generator_->DrawWindowTree(pass, root_window_.get(), gfx::Vector2d(), - 1.0f); +void FrameGeneratorTest::DrawWindow(cc::RenderPass* pass) { + frame_generator_->DrawWindow(pass, root_window_.get()); } void FrameGeneratorTest::SetUp() { testing::Test::SetUp(); - frame_generator_delegate_ = base::MakeUnique<TestFrameGeneratorDelegate>(); + frame_generator_delegate_ = + base::MakeUnique<TestFrameGeneratorDelegate>(root_window_.get()); PlatformDisplayInitParams init_params; frame_generator_ = base::MakeUnique<FrameGenerator>( frame_generator_delegate_.get(), root_window_.get()); @@ -97,51 +97,23 @@ } // Tests correctness of the SharedQuadStateList generated by -// FrameGenerator::DrawWindowTree(). -TEST_F(FrameGeneratorTest, DrawWindowTree) { +// FrameGenerator::DrawWindow(). +TEST_F(FrameGeneratorTest, DrawWindow) { ServerWindow child_window(test_window_delegate(), WindowId(1, 1)); root_window()->Add(&child_window); InitWindow(&child_window); - const float root_opacity = .5f; const float child_opacity = .4f; - root_window()->SetOpacity(root_opacity); child_window.SetOpacity(child_opacity); std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create(); - DrawWindowTree(render_pass.get()); + DrawWindow(render_pass.get()); cc::SharedQuadStateList* quad_state_list = &render_pass->shared_quad_state_list; - // Both child and root have a DEFAULT Surface and no underlay Surfaces, so - // there should be two SharedQuadStates in the list. - EXPECT_EQ(2u, quad_state_list->size()); + EXPECT_EQ(1u, quad_state_list->size()); cc::SharedQuadState* root_sqs = quad_state_list->back(); - cc::SharedQuadState* child_sqs = quad_state_list->front(); - EXPECT_EQ(root_opacity, root_sqs->opacity); - // Child's SharedQuadState contains the effective opacity of the child layer, - // which should be a product of the child and the parent opacity. - EXPECT_EQ(child_opacity * root_opacity, child_sqs->opacity); - - // Pretend to create the UNDERLAY Surface for the child window, and confirm - // that this creates an extra SharedQuadState in the CompositorFrame. - child_window.GetOrCreateCompositorFrameSinkManager()->SetLatestSurfaceInfo( - mojom::CompositorFrameSinkType::UNDERLAY, - cc::SurfaceInfo( - cc::SurfaceId( - cc::FrameSinkId(WindowIdToTransportId(child_window.id()), - static_cast<uint32_t>( - mojom::CompositorFrameSinkType::UNDERLAY)), - cc::LocalFrameId(1u, kArbitraryToken)), - 1.0f, gfx::Size(100, 100))); - - render_pass = cc::RenderPass::Create(); - DrawWindowTree(render_pass.get()); - quad_state_list = &render_pass->shared_quad_state_list; - EXPECT_EQ(3u, quad_state_list->size()); - auto it = quad_state_list->begin(); - EXPECT_EQ(child_opacity * root_opacity, (*it)->opacity); - EXPECT_EQ(child_opacity * root_opacity, (*++it)->opacity); - EXPECT_EQ(root_opacity, (*++it)->opacity); + // Opacity should always be 1. + EXPECT_EQ(1.0f, root_sqs->opacity); } } // namespace test
diff --git a/services/ui/ws/platform_display_default.cc b/services/ui/ws/platform_display_default.cc index 6a3a6e9..e69588ed 100644 --- a/services/ui/ws/platform_display_default.cc +++ b/services/ui/ws/platform_display_default.cc
@@ -248,6 +248,10 @@ void PlatformDisplayDefault::OnActivationChanged(bool active) {} +ServerWindow* PlatformDisplayDefault::GetActiveRootWindow() { + return delegate_->GetActiveRootWindow(); +} + bool PlatformDisplayDefault::IsInHighContrastMode() { return delegate_ ? delegate_->IsInHighContrastMode() : false; }
diff --git a/services/ui/ws/platform_display_default.h b/services/ui/ws/platform_display_default.h index 12c07f2..8636c2b 100644 --- a/services/ui/ws/platform_display_default.h +++ b/services/ui/ws/platform_display_default.h
@@ -68,6 +68,7 @@ void OnActivationChanged(bool active) override; // FrameGeneratorDelegate: + ServerWindow* GetActiveRootWindow() override; bool IsInHighContrastMode() override; const int64_t display_id_;
diff --git a/services/ui/ws/platform_display_delegate.h b/services/ui/ws/platform_display_delegate.h index 0358573..808717bb 100644 --- a/services/ui/ws/platform_display_delegate.h +++ b/services/ui/ws/platform_display_delegate.h
@@ -28,6 +28,9 @@ // Returns the root window of this display. virtual ServerWindow* GetRootWindow() = 0; + // Returns the root window of the active user. + virtual ServerWindow* GetActiveRootWindow() = 0; + // Called once when the AcceleratedWidget is available for drawing. virtual void OnAcceleratedWidgetAvailable() = 0;
diff --git a/services/ui/ws/server_window_compositor_frame_sink_manager.cc b/services/ui/ws/server_window_compositor_frame_sink_manager.cc index 7480c7f..b55d0a89 100644 --- a/services/ui/ws/server_window_compositor_frame_sink_manager.cc +++ b/services/ui/ws/server_window_compositor_frame_sink_manager.cc
@@ -29,9 +29,7 @@ return true; waiting_for_initial_frames_ = !IsCompositorFrameSinkReadyAndNonEmpty( - mojom::CompositorFrameSinkType::DEFAULT) || - !IsCompositorFrameSinkReadyAndNonEmpty( - mojom::CompositorFrameSinkType::UNDERLAY); + mojom::CompositorFrameSinkType::DEFAULT); return !waiting_for_initial_frames_; }
diff --git a/services/ui/ws/server_window_compositor_frame_sink_manager.h b/services/ui/ws/server_window_compositor_frame_sink_manager.h index 8ca40a34..eb21737 100644 --- a/services/ui/ws/server_window_compositor_frame_sink_manager.h +++ b/services/ui/ws/server_window_compositor_frame_sink_manager.h
@@ -109,6 +109,8 @@ TypeToCompositorFrameSinkMap type_to_compositor_frame_sink_map_; + // TODO(mfomitchev): This is currently always false. Confirm if we still need + // this. // While true the window is not drawn. This is initially true if the window // has the property |kWaitForUnderlay_Property|. This is set to false once // the underlay and default surface have been set *and* their size is at
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc index 947f089..5c50fae 100644 --- a/services/ui/ws/test_utils.cc +++ b/services/ui/ws/test_utils.cc
@@ -151,10 +151,16 @@ // TestFrameGeneratorDelegate ------------------------------------------------- -TestFrameGeneratorDelegate::TestFrameGeneratorDelegate() {} +TestFrameGeneratorDelegate::TestFrameGeneratorDelegate( + ServerWindow* root_window) + : root_window_(root_window) {} TestFrameGeneratorDelegate::~TestFrameGeneratorDelegate() {} +ServerWindow* TestFrameGeneratorDelegate::GetActiveRootWindow() { + return root_window_; +} + bool TestFrameGeneratorDelegate::IsInHighContrastMode() { return false; }
diff --git a/services/ui/ws/test_utils.h b/services/ui/ws/test_utils.h index 5f5cb30..808f16f1 100644 --- a/services/ui/ws/test_utils.h +++ b/services/ui/ws/test_utils.h
@@ -285,13 +285,16 @@ // A stub implementation of FrameGeneratorDelegate. class TestFrameGeneratorDelegate : public FrameGeneratorDelegate { public: - TestFrameGeneratorDelegate(); + TestFrameGeneratorDelegate(ServerWindow* root_window); ~TestFrameGeneratorDelegate() override; // FrameGeneratorDelegate: + ServerWindow* GetActiveRootWindow() override; bool IsInHighContrastMode() override; private: + ServerWindow* root_window_; + DISALLOW_COPY_AND_ASSIGN(TestFrameGeneratorDelegate); };
diff --git a/skia/BUILD.gn b/skia/BUILD.gn index 64bc750..db9b5423 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn
@@ -367,10 +367,6 @@ # Select the right BitmapPlatformDevice. if (is_win) { sources += [ "ext/bitmap_platform_device_win.cc" ] - } else if (is_mac) { - sources += [ "ext/bitmap_platform_device_mac.cc" ] - } else if (use_cairo) { - sources += [ "ext/bitmap_platform_device_cairo.cc" ] } else if (!is_ios) { sources += [ "ext/bitmap_platform_device_skia.cc" ] }
diff --git a/skia/ext/bitmap_platform_device.h b/skia/ext/bitmap_platform_device.h deleted file mode 100644 index 1ca5f7e..0000000 --- a/skia/ext/bitmap_platform_device.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_BITMAP_PLATFORM_DEVICE_H_ -#define SKIA_EXT_BITMAP_PLATFORM_DEVICE_H_ - -// This file provides an easy way to include the appropriate -// BitmapPlatformDevice header file for your platform. - -#include <stdint.h> - -#if defined(WIN32) -#include "skia/ext/bitmap_platform_device_win.h" -#elif defined(__APPLE__) -#include "skia/ext/bitmap_platform_device_mac.h" -#elif defined(USE_CAIRO) -#include "skia/ext/bitmap_platform_device_cairo.h" -#else -#include "skia/ext/bitmap_platform_device_skia.h" -#endif - -#endif // SKIA_EXT_BITMAP_PLATFORM_DEVICE_H_
diff --git a/skia/ext/bitmap_platform_device_cairo.cc b/skia/ext/bitmap_platform_device_cairo.cc deleted file mode 100644 index 261228b..0000000 --- a/skia/ext/bitmap_platform_device_cairo.cc +++ /dev/null
@@ -1,180 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "build/build_config.h" -#include "skia/ext/bitmap_platform_device_cairo.h" -#include "skia/ext/platform_canvas.h" - -#if defined(OS_OPENBSD) -#include <cairo.h> -#else -#include <cairo/cairo.h> -#endif - -namespace skia { - -namespace { - -void CairoSurfaceReleaseProc(void*, void* context) { - SkASSERT(context); - cairo_surface_destroy(static_cast<cairo_surface_t*>(context)); -} - -// Back the destination bitmap by a Cairo surface. The bitmap's -// pixelRef takes ownership of the passed-in surface and will call -// cairo_surface_destroy() upon destruction. -// -// Note: it may immediately destroy the surface, if it fails to create a bitmap -// with pixels, thus the caller must either ref() the surface before hand, or -// it must not refer to the surface after this call. -bool InstallCairoSurfacePixels(SkBitmap* dst, - cairo_surface_t* surface, - bool is_opaque) { - SkASSERT(dst); - if (!surface) { - return false; - } - SkImageInfo info - = SkImageInfo::MakeN32(cairo_image_surface_get_width(surface), - cairo_image_surface_get_height(surface), - is_opaque ? kOpaque_SkAlphaType - : kPremul_SkAlphaType); - return dst->installPixels(info, - cairo_image_surface_get_data(surface), - cairo_image_surface_get_stride(surface), - NULL, - &CairoSurfaceReleaseProc, - static_cast<void*>(surface)); -} - -void LoadMatrixToContext(cairo_t* context, const SkMatrix& matrix) { - cairo_matrix_t cairo_matrix; - cairo_matrix_init(&cairo_matrix, - SkScalarToFloat(matrix.getScaleX()), - SkScalarToFloat(matrix.getSkewY()), - SkScalarToFloat(matrix.getSkewX()), - SkScalarToFloat(matrix.getScaleY()), - SkScalarToFloat(matrix.getTranslateX()), - SkScalarToFloat(matrix.getTranslateY())); - cairo_set_matrix(context, &cairo_matrix); -} - -void LoadClipToContext(cairo_t* context, const SkIRect& clip_bounds) { - cairo_reset_clip(context); - - cairo_rectangle(context, clip_bounds.fLeft, clip_bounds.fTop, - clip_bounds.width(), clip_bounds.height()); - cairo_clip(context); -} - -} // namespace - -void BitmapPlatformDevice::LoadConfig(const SkMatrix& transform, - const SkIRect& clip_bounds) { - if (!cairo_) - return; // Nothing to do. - - LoadClipToContext(cairo_, clip_bounds); - LoadMatrixToContext(cairo_, transform); -} - -// We use this static factory function instead of the regular constructor so -// that we can create the pixel data before calling the constructor. This is -// required so that we can call the base class' constructor with the pixel -// data. -BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, - bool is_opaque, - cairo_surface_t* surface) { - if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy(surface); - return NULL; - } - - // must call this before trying to install the surface, since that may result - // in the surface being destroyed. - cairo_t* cairo = cairo_create(surface); - - SkBitmap bitmap; - if (!InstallCairoSurfacePixels(&bitmap, surface, is_opaque)) { - cairo_destroy(cairo); - return NULL; - } - - // The device object will take ownership of the graphics context. - return new BitmapPlatformDevice(bitmap, cairo); -} - -BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, - bool is_opaque) { - // This initializes the bitmap to all zeros. - cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - width, height); - - BitmapPlatformDevice* device = Create(width, height, is_opaque, surface); - -#ifndef NDEBUG - if (device && is_opaque) // Fill with bright bluish green - SkCanvas(device).drawColor(0xFF00FF80); -#endif - - return device; -} - -BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, - bool is_opaque, - uint8_t* data) { - cairo_surface_t* surface = cairo_image_surface_create_for_data( - data, CAIRO_FORMAT_ARGB32, width, height, - cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); - - return Create(width, height, is_opaque, surface); -} - -// Ownership of the cairo object is transferred. -BitmapPlatformDevice::BitmapPlatformDevice( - const SkBitmap& bitmap, - cairo_t* cairo) - : SkBitmapDevice(bitmap), - cairo_(cairo) { - SetPlatformDevice(this, this); -} - -BitmapPlatformDevice::~BitmapPlatformDevice() { - cairo_destroy(cairo_); -} - -SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& info, - const SkPaint*) { - SkASSERT(info.fInfo.colorType() == kN32_SkColorType); - return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(), - info.fInfo.isOpaque()); -} - -cairo_t* BitmapPlatformDevice::BeginPlatformPaint( - const SkMatrix& transform, - const SkIRect& clip_bounds) { - LoadConfig(transform, clip_bounds); - cairo_surface_t* surface = cairo_get_target(cairo_); - // Tell cairo to flush anything it has pending. - cairo_surface_flush(surface); - // Tell Cairo that we (probably) modified (actually, will modify) its pixel - // buffer directly. - cairo_surface_mark_dirty(surface); - return cairo_; -} - -// PlatformCanvas impl - -std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels( - int width, - int height, - bool is_opaque, - uint8_t* data, - OnFailureType failureType) { - sk_sp<SkBaseDevice> dev( - BitmapPlatformDevice::Create(width, height, is_opaque, data)); - return CreateCanvas(dev, failureType); -} - -} // namespace skia
diff --git a/skia/ext/bitmap_platform_device_cairo.h b/skia/ext/bitmap_platform_device_cairo.h deleted file mode 100644 index 5e6a6f3..0000000 --- a/skia/ext/bitmap_platform_device_cairo.h +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_BITMAP_PLATFORM_DEVICE_CAIRO_H_ -#define SKIA_EXT_BITMAP_PLATFORM_DEVICE_CAIRO_H_ - -#include <stdint.h> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "skia/ext/platform_device.h" - -typedef struct _cairo_surface cairo_surface_t; - -// ----------------------------------------------------------------------------- -// Image byte ordering on Linux: -// -// Pixels are packed into 32-bit words these days. Even for 24-bit images, -// often 8-bits will be left unused for alignment reasons. Thus, when you see -// ARGB as the byte order you have to wonder if that's in memory order or -// little-endian order. Here I'll write A.R.G.B to specifiy the memory order. -// -// GdkPixbuf's provide a nice backing store and defaults to R.G.B.A order. -// They'll do the needed byte swapping to match the X server when drawn. -// -// Skia can be controled in skia/include/corecg/SkUserConfig.h (see bits about -// SK_R32_SHIFT). For Linux we define it to be ARGB in registers. For little -// endian machines that means B.G.R.A in memory. -// -// The image loaders are controlled in -// webkit/port/platform/image-decoders/ImageDecoder.h (see setRGBA). These are -// also configured for ARGB in registers. -// -// Cairo's only 32-bit mode is ARGB in registers. -// -// X servers commonly have a 32-bit visual with xRGB in registers (since they -// typically don't do alpha blending of drawables at the user level. Composite -// extensions aside.) -// -// We don't use GdkPixbuf because its byte order differs from the rest. Most -// importantly, it differs from Cairo which, being a system library, is -// something that we can't easily change. -// ----------------------------------------------------------------------------- - -namespace skia { - -// ----------------------------------------------------------------------------- -// This is the Linux bitmap backing for Skia. We create a Cairo image surface -// to store the backing buffer. This buffer is BGRA in memory (on little-endian -// machines). -// -// For now we are also using Cairo to paint to the Drawables so we provide an -// accessor for getting the surface. -// -// This is all quite ok for test_shell. In the future we will want to use -// shared memory between the renderer and the main process at least. In this -// case we'll probably create the buffer from a precreated region of memory. -// ----------------------------------------------------------------------------- -class BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { - public: - // Create a BitmapPlatformDeviceLinux from an already constructed bitmap; - // you should probably be using Create(). This may become private later if - // we ever have to share state between some native drawing UI and Skia, like - // the Windows and Mac versions of this class do. - // - // This object takes ownership of @cairo. - BitmapPlatformDevice(const SkBitmap& other, cairo_t* cairo); - ~BitmapPlatformDevice() override; - - // Constructs a device with size |width| * |height| with contents initialized - // to zero. |is_opaque| should be set if the caller knows the bitmap will be - // completely opaque and allows some optimizations. - static BitmapPlatformDevice* Create(int width, int height, bool is_opaque); - - // This doesn't take ownership of |data|. If |data| is NULL, the contents - // of the device are initialized to 0. - static BitmapPlatformDevice* Create(int width, int height, bool is_opaque, - uint8_t* data); - - protected: - SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; - - private: - // Overridden from PlatformDevice: - cairo_t* BeginPlatformPaint(const SkMatrix& transform, - const SkIRect& clip_bounds) override; - - static BitmapPlatformDevice* Create(int width, int height, bool is_opaque, - cairo_surface_t* surface); - - // Loads the current transform and clip into the context. - void LoadConfig(const SkMatrix& transform, const SkIRect& clip_bounds); - - // Graphics context used to draw into the surface. - cairo_t* cairo_; - - DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice); -}; - -} // namespace skia - -#endif // SKIA_EXT_BITMAP_PLATFORM_DEVICE_CAIRO_H_
diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc deleted file mode 100644 index 67ad2a9..0000000 --- a/skia/ext/bitmap_platform_device_mac.cc +++ /dev/null
@@ -1,275 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "skia/ext/bitmap_platform_device_mac.h" - -#import <ApplicationServices/ApplicationServices.h> -#include <stddef.h> -#include <time.h> - -#include "base/mac/mac_util.h" -#include "base/memory/ref_counted.h" -#include "skia/ext/bitmap_platform_device.h" -#include "skia/ext/platform_canvas.h" -#include "skia/ext/skia_utils_mac.h" -#include "third_party/skia/include/core/SkMatrix.h" -#include "third_party/skia/include/core/SkPath.h" -#include "third_party/skia/include/core/SkRect.h" -#include "third_party/skia/include/core/SkTypes.h" - -namespace skia { - -namespace { - -// Returns true if it is unsafe to attempt to allocate an offscreen buffer -// given these dimensions. -bool RasterDeviceTooBigToAllocate(int width, int height) { - -#ifndef SKIA_EXT_RASTER_DEVICE_ALLOCATION_MAX -#define SKIA_EXT_RASTER_DEVICE_ALLOCATION_MAX (2 * 256 * 1024 * 1024) -#endif - - int bytesPerPixel = 4; - int64_t bytes = (int64_t)width * height * bytesPerPixel; - return bytes > SKIA_EXT_RASTER_DEVICE_ALLOCATION_MAX; -} - -static CGContextRef CGContextForData(void* data, int width, int height) { -#define HAS_ARGB_SHIFTS(a, r, g, b) \ - (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \ - && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b)) -#if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) - // Allocate a bitmap context with 4 components per pixel (BGRA). Apple - // recommends these flags for improved CG performance. - - // CGBitmapContextCreate returns NULL if width/height are 0. However, our - // callers expect to get a canvas back (which they later resize/reallocate) - // so we pin the dimensions here. - width = SkMax32(1, width); - height = SkMax32(1, height); - CGContextRef context = - CGBitmapContextCreate(data, width, height, 8, width * 4, - base::mac::GetSystemColorSpace(), - kCGImageAlphaPremultipliedFirst | - kCGBitmapByteOrder32Host); -#else -#error We require that Skia's and CoreGraphics's recommended \ - image memory layout match. -#endif -#undef HAS_ARGB_SHIFTS - - if (!context) - return NULL; - - // Change the coordinate system to match WebCore's - CGContextTranslateCTM(context, 0, height); - CGContextScaleCTM(context, 1.0, -1.0); - - return context; -} - -} // namespace - -void BitmapPlatformDevice::ReleaseBitmapContext() { - SkASSERT(bitmap_context_); - CGContextRelease(bitmap_context_); - bitmap_context_ = NULL; -} - -// Loads the specified Skia transform into the device context -static void LoadTransformToCGContext(CGContextRef context, - const SkMatrix& matrix) { - // CoreGraphics can concatenate transforms, but not reset the current one. - // So in order to get the required behavior here, we need to first make - // the current transformation matrix identity and only then load the new one. - - // Reset matrix to identity. - CGAffineTransform orig_cg_matrix = CGContextGetCTM(context); - CGAffineTransform orig_cg_matrix_inv = - CGAffineTransformInvert(orig_cg_matrix); - CGContextConcatCTM(context, orig_cg_matrix_inv); - - // assert that we have indeed returned to the identity Matrix. - SkASSERT(CGAffineTransformIsIdentity(CGContextGetCTM(context))); - - // Convert xform to CG-land. - // Our coordinate system is flipped to match WebKit's so we need to modify - // the xform to match that. - SkMatrix transformed_matrix = matrix; - SkScalar sy = -matrix.getScaleY(); - transformed_matrix.setScaleY(sy); - size_t height = CGBitmapContextGetHeight(context); - SkScalar ty = -matrix.getTranslateY(); // y axis is flipped. - transformed_matrix.setTranslateY(ty + (SkScalar)height); - - CGAffineTransform cg_matrix = - skia::SkMatrixToCGAffineTransform(transformed_matrix); - - // Load final transform into context. - CGContextConcatCTM(context, cg_matrix); -} - -static void LoadClippingRegionToCGContext(CGContextRef context, - const SkIRect& clip_bounds, - const SkMatrix& transformation) { - // CoreGraphics applies the current transform to clip rects, which is - // unwanted. Inverse-transform the rect before sending it to CG. This only - // works for translations and scaling, but not for rotations (but the - // viewport is never rotated anyway). - SkMatrix t; - bool did_invert = transformation.invert(&t); - if (!did_invert) - t.reset(); - - SkRect rect = SkRect::Make(clip_bounds); - t.mapRect(&rect); - SkIRect irect; - rect.round(&irect); - CGContextClipToRect(context, skia::SkIRectToCGRect(irect)); -} - -void BitmapPlatformDevice::LoadConfig(const SkMatrix& transform, - const SkIRect& clip_bounds) { - if (!bitmap_context_) - return; // Nothing to do. - - // We must restore and then save the state of the graphics context since the - // calls to Load the clipping region to the context are strictly cummulative, - // i.e., you can't replace a clip rect, other than with a save/restore. - // But this implies that no other changes to the state are done elsewhere. - // If we ever get to need to change this, then we must replace the clip rect - // calls in LoadClippingRegionToCGContext() with an image mask instead. - CGContextRestoreGState(bitmap_context_); - CGContextSaveGState(bitmap_context_); - LoadTransformToCGContext(bitmap_context_, transform); - LoadClippingRegionToCGContext(bitmap_context_, clip_bounds, transform); -} - - -// We use this static factory function instead of the regular constructor so -// that we can create the pixel data before calling the constructor. This is -// required so that we can call the base class' constructor with the pixel -// data. -BitmapPlatformDevice* BitmapPlatformDevice::Create(CGContextRef context, - int width, - int height, - bool is_opaque, - bool do_clear) { - if (RasterDeviceTooBigToAllocate(width, height)) - return NULL; - - SkBitmap bitmap; - // TODO: verify that the CG Context's pixels will have tight rowbytes or pass in the correct - // rowbytes for the case when context != NULL. - bitmap.setInfo(SkImageInfo::MakeN32(width, height, is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType)); - - void* data; - if (context) { - data = CGBitmapContextGetData(context); - bitmap.setPixels(data); - } else { - if (!bitmap.tryAllocPixels()) - return NULL; - data = bitmap.getPixels(); - } - if (do_clear) - memset(data, 0, bitmap.getSafeSize()); - - // If we were given data, then don't clobber it! -#ifndef NDEBUG - if (!context && is_opaque) { - // To aid in finding bugs, we set the background color to something - // obviously wrong so it will be noticable when it is not cleared - bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green - } -#endif - - if (!context) { - context = CGContextForData(data, width, height); - if (!context) - return NULL; - } else - CGContextRetain(context); - - BitmapPlatformDevice* rv = new BitmapPlatformDevice(context, bitmap); - - // The device object took ownership of the graphics context with its own - // CGContextRetain call. - CGContextRelease(context); - - return rv; -} - -BitmapPlatformDevice* BitmapPlatformDevice::CreateWithData(uint8_t* data, - int width, - int height, - bool is_opaque) { - CGContextRef context = NULL; - if (data) - context = CGContextForData(data, width, height); - - BitmapPlatformDevice* rv = Create(context, width, height, is_opaque, false); - - // The device object took ownership of the graphics context with its own - // CGContextRetain call. - if (context) - CGContextRelease(context); - - return rv; -} - -// The device will own the bitmap, which corresponds to also owning the pixel -// data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap. -BitmapPlatformDevice::BitmapPlatformDevice( - CGContextRef context, const SkBitmap& bitmap) - : SkBitmapDevice(bitmap), - bitmap_context_(context) { - SetPlatformDevice(this, this); - SkASSERT(bitmap_context_); - // Initialize the clip region to the entire bitmap. - - SkIRect rect; - rect.set(0, 0, - CGBitmapContextGetWidth(bitmap_context_), - CGBitmapContextGetHeight(bitmap_context_)); - CGContextRetain(bitmap_context_); - // We must save the state once so that we can use the restore/save trick - // in LoadConfig(). - CGContextSaveGState(bitmap_context_); -} - -BitmapPlatformDevice::~BitmapPlatformDevice() { - if (bitmap_context_) - CGContextRelease(bitmap_context_); -} - -NativeDrawingContext BitmapPlatformDevice::BeginPlatformPaint( - const SkMatrix& transform, - const SkIRect& clip_bounds) { - LoadConfig(transform, clip_bounds); - return bitmap_context_; -} - -SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& cinfo, - const SkPaint*) { - const SkImageInfo& info = cinfo.fInfo; - const bool do_clear = !info.isOpaque(); - SkASSERT(info.colorType() == kN32_SkColorType); - return Create(NULL, info.width(), info.height(), info.isOpaque(), do_clear); -} - -// PlatformCanvas impl - -std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels( - int width, - int height, - bool is_opaque, - uint8_t* data, - OnFailureType failureType) { - sk_sp<SkBaseDevice> dev( - BitmapPlatformDevice::CreateWithData(data, width, height, is_opaque)); - return CreateCanvas(dev, failureType); -} - -} // namespace skia
diff --git a/skia/ext/bitmap_platform_device_mac.h b/skia/ext/bitmap_platform_device_mac.h deleted file mode 100644 index 10dce7fe..0000000 --- a/skia/ext/bitmap_platform_device_mac.h +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_BITMAP_PLATFORM_DEVICE_MAC_H_ -#define SKIA_EXT_BITMAP_PLATFORM_DEVICE_MAC_H_ - -#include <stdint.h> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "skia/ext/platform_device.h" - -namespace skia { - -// A device is basically a wrapper around SkBitmap that provides a surface for -// SkCanvas to draw into. Our device provides a surface CoreGraphics can also -// write to. BitmapPlatformDevice creates a bitmap using -// CGCreateBitmapContext() in a format that Skia supports and can then use this -// to draw text into, etc. This pixel data is provided to the bitmap that the -// device contains so that it can be shared. -// -// The device owns the pixel data, when the device goes away, the pixel data -// also becomes invalid. THIS IS DIFFERENT THAN NORMAL SKIA which uses -// reference counting for the pixel data. In normal Skia, you could assign -// another bitmap to this device's bitmap and everything will work properly. -// For us, that other bitmap will become invalid as soon as the device becomes -// invalid, which may lead to subtle bugs. Therefore, DO NOT ASSIGN THE -// DEVICE'S PIXEL DATA TO ANOTHER BITMAP, make sure you copy instead. -class SK_API BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { - public: - // Creates a BitmapPlatformDevice instance. |is_opaque| should be set if the - // caller knows the bitmap will be completely opaque and allows some - // optimizations. - // |context| may be NULL. If |context| is NULL, then the bitmap backing store - // is not initialized. - static BitmapPlatformDevice* Create(CGContextRef context, - int width, int height, - bool is_opaque, bool do_clear = false); - - // Creates a context for |data| and calls Create. - // If |data| is NULL, then the bitmap backing store is not initialized. - static BitmapPlatformDevice* CreateWithData(uint8_t* data, - int width, int height, - bool is_opaque); - - ~BitmapPlatformDevice() override; - - protected: - BitmapPlatformDevice(CGContextRef context, - const SkBitmap& bitmap); - - SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; - - private: - NativeDrawingContext BeginPlatformPaint(const SkMatrix& transform, - const SkIRect& clip_bounds) override; - - void ReleaseBitmapContext(); - - // Loads the current transform and clip into the context. Can be called even - // when |bitmap_context_| is NULL (will be a NOP). - void LoadConfig(const SkMatrix& transform, const SkIRect& clip_bounds); - - // Lazily-created graphics context used to draw into the bitmap. - CGContextRef bitmap_context_; - - DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice); -}; - -} // namespace skia - -#endif // SKIA_EXT_BITMAP_PLATFORM_DEVICE_MAC_H_
diff --git a/skia/ext/bitmap_platform_device_skia.cc b/skia/ext/bitmap_platform_device_skia.cc index a39e5d71..5904d6f2 100644 --- a/skia/ext/bitmap_platform_device_skia.cc +++ b/skia/ext/bitmap_platform_device_skia.cc
@@ -9,15 +9,7 @@ BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, bool is_opaque) { - SkBitmap bitmap; - if (bitmap.tryAllocN32Pixels(width, height, is_opaque)) { - // Follow the logic in SkCanvas::createDevice(), initialize the bitmap if it - // is not opaque. - if (!is_opaque) - bitmap.eraseARGB(0, 0, 0, 0); - return new BitmapPlatformDevice(bitmap); - } - return NULL; + return Create(width, height, is_opaque, nullptr); } BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, @@ -26,10 +18,17 @@ SkBitmap bitmap; bitmap.setInfo(SkImageInfo::MakeN32(width, height, is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType)); - if (data) + + if (data) { bitmap.setPixels(data); - else if (!bitmap.tryAllocPixels()) - return NULL; + } else { + if (!bitmap.tryAllocPixels()) + return nullptr; + // Follow the logic in SkCanvas::createDevice(), initialize the bitmap if + // it is not opaque. + if (!is_opaque) + bitmap.eraseARGB(0, 0, 0, 0); + } return new BitmapPlatformDevice(bitmap); } @@ -49,15 +48,6 @@ info.fInfo.isOpaque()); } -NativeDrawingContext BitmapPlatformDevice::BeginPlatformPaint( - const SkMatrix& transform, - const SkIRect& clip_bounds) { - // TODO(zhenghao): What should we return? The ptr to the address of the - // pixels? Maybe this won't be called at all. - SkPixmap pixmap; - return accessPixels(&pixmap) ? pixmap.writable_addr() : nullptr; -} - // PlatformCanvas impl std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels(
diff --git a/skia/ext/bitmap_platform_device_skia.h b/skia/ext/bitmap_platform_device_skia.h index 024064f..42a3be1 100644 --- a/skia/ext/bitmap_platform_device_skia.h +++ b/skia/ext/bitmap_platform_device_skia.h
@@ -21,15 +21,21 @@ // shared memory between the renderer and the main process at least. In this // case we'll probably create the buffer from a precreated region of memory. // ----------------------------------------------------------------------------- -class BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { +class BitmapPlatformDevice final : public SkBitmapDevice, + public PlatformDevice { public: // Construct a BitmapPlatformDevice. |is_opaque| should be set if the caller - // knows the bitmap will be completely opaque and allows some optimizations. - // The bitmap is not initialized. + // knows the bitmap will be completely opaque and allows some optimizations + // (the bitmap is not initialized to 0 when is_opaque == true). static BitmapPlatformDevice* Create(int width, int height, bool is_opaque); - // This doesn't take ownership of |data|. If |data| is null, the bitmap - // is not initialized to 0. + // This doesn't take ownership of |data|. If |data| is null and |is_opaque| + // is false, the bitmap is initialized to 0. + // + // Note: historicaly, BitmapPlatformDevice impls have had diverging + // initialization behavior for null |data| (Cairo used to initialize, while + // the others did not). For now we stick to the more conservative Cairo + // behavior. static BitmapPlatformDevice* Create(int width, int height, bool is_opaque, uint8_t* data); @@ -44,9 +50,6 @@ SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; private: - NativeDrawingContext BeginPlatformPaint(const SkMatrix& transform, - const SkIRect& clip_bounds) override; - DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice); };
diff --git a/skia/ext/bitmap_platform_device_win.h b/skia/ext/bitmap_platform_device_win.h index 82f17ff3..6f359e2 100644 --- a/skia/ext/bitmap_platform_device_win.h +++ b/skia/ext/bitmap_platform_device_win.h
@@ -17,8 +17,8 @@ // format that Skia supports and can then use this to draw ClearType into, etc. // This pixel data is provided to the bitmap that the device contains so that it // can be shared. -class SK_API BitmapPlatformDevice : public SkBitmapDevice, - public PlatformDevice { +class SK_API BitmapPlatformDevice final : public SkBitmapDevice, + public PlatformDevice { public: // Factory function. is_opaque should be set if the caller knows the bitmap // will be completely opaque and allows some optimizations.
diff --git a/skia/ext/platform_device.h b/skia/ext/platform_device.h index b756aa6..f349a49 100644 --- a/skia/ext/platform_device.h +++ b/skia/ext/platform_device.h
@@ -46,11 +46,14 @@ public: virtual ~PlatformDevice(); +// Only implemented in bitmap_platform_device_win. +#if defined(WIN32) // The DC that corresponds to the bitmap, used for GDI operations drawing // into the bitmap. This is possibly heavyweight, so it should be existant // only during one pass of rendering. virtual NativeDrawingContext BeginPlatformPaint(const SkMatrix& transform, const SkIRect& clip_bounds) = 0; +#endif }; } // namespace skia
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index a2d037a..569c9459 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -8,6 +8,9 @@ "test": "base_unittests" }, { + "test": "blimp_unittests" + }, + { "override_compile_targets": [ "breakpad_unittests_deps" ], @@ -88,6 +91,14 @@ ], "instrumentation_tests": [ { + "apk_under_test": "Blimp.apk", + "override_compile_targets": [ + "blimp_test_apk" + ], + "test": "blimp_test_apk", + "test_apk": "BlimpTest.apk" + }, + { "test": "chrome_public_test_apk" }, { @@ -107,6 +118,9 @@ "test": "base_unittests" }, { + "test": "blimp_unittests" + }, + { "override_compile_targets": [ "breakpad_unittests_deps" ], @@ -190,6 +204,14 @@ "test": "android_webview_test_apk" }, { + "apk_under_test": "Blimp.apk", + "override_compile_targets": [ + "blimp_test_apk" + ], + "test": "blimp_test_apk", + "test_apk": "BlimpTest.apk" + }, + { "test": "chrome_public_test_apk" }, { @@ -209,6 +231,9 @@ "test": "base_unittests" }, { + "test": "blimp_unittests" + }, + { "override_compile_targets": [ "breakpad_unittests_deps" ], @@ -301,6 +326,13 @@ "timeout_scale": 4 }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "test": "blimp_test_apk", + "timeout_scale": 4 + }, + { "test": "chrome_public_test_apk", "timeout_scale": 4 }, @@ -1374,6 +1406,12 @@ "test": "base_unittests" }, { + "swarming": { + "can_use_on_swarming_builders": false + }, + "test": "blimp_unittests" + }, + { "override_compile_targets": [ "breakpad_unittests_deps" ], @@ -1537,6 +1575,12 @@ "test": "android_webview_test_apk" }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "test": "blimp_test_apk" + }, + { "test": "chrome_public_test_apk" }, { @@ -1568,6 +1612,12 @@ "test": "base_unittests" }, { + "swarming": { + "can_use_on_swarming_builders": false + }, + "test": "blimp_unittests" + }, + { "override_compile_targets": [ "breakpad_unittests_deps" ], @@ -1731,6 +1781,12 @@ "test": "android_webview_test_apk" }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "test": "blimp_test_apk" + }, + { "test": "chrome_public_test_apk" }, {
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 73f97b4c..cfcafa1 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -104,6 +104,72 @@ "test": "base_unittests" }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "override_isolate_target": "blimp_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "MMB29Q", + "device_type": "bullhead" + } + ], + "hard_timeout": 960, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_test_apk" + }, + { + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "MMB29Q", + "device_type": "bullhead" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_unittests" + }, + { "override_isolate_target": "blink_heap_unittests", "swarming": { "can_use_on_swarming_builders": true, @@ -1150,6 +1216,9 @@ "test": "base_unittests" }, { + "test": "blimp_unittests" + }, + { "override_compile_targets": [ "breakpad_unittests_deps" ], @@ -1236,6 +1305,14 @@ "test": "android_webview_test_apk" }, { + "apk_under_test": "Blimp.apk", + "override_compile_targets": [ + "blimp_test_apk" + ], + "test": "blimp_test_apk", + "test_apk": "BlimpTest.apk" + }, + { "test": "chrome_public_test_apk" }, { @@ -1315,6 +1392,39 @@ "test": "base_unittests" }, { + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "LMY48I", + "device_type": "hammerhead" + } + ], + "expiration": 10800, + "hard_timeout": 960, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_unittests" + }, + { "override_compile_targets": [ "breakpad_unittests_deps" ], @@ -2183,6 +2293,42 @@ }, { "override_compile_targets": [ + "blimp_test_apk" + ], + "override_isolate_target": "blimp_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "LMY48I", + "device_type": "hammerhead" + } + ], + "expiration": 10800, + "hard_timeout": 960, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_test_apk" + }, + { + "override_compile_targets": [ "chrome_public_test_apk" ], "override_isolate_target": "chrome_public_test_apk", @@ -2300,6 +2446,9 @@ "test": "base_unittests" }, { + "test": "blimp_unittests" + }, + { "override_compile_targets": [ "breakpad_unittests_deps" ], @@ -2386,6 +2535,14 @@ "test": "android_webview_test_apk" }, { + "apk_under_test": "Blimp.apk", + "override_compile_targets": [ + "blimp_test_apk" + ], + "test": "blimp_test_apk", + "test_apk": "BlimpTest.apk" + }, + { "test": "chrome_public_test_apk" }, { @@ -2495,6 +2652,71 @@ "test": "base_unittests" }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "override_isolate_target": "blimp_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "device_os": "MMB29Q", + "device_type": "bullhead" + } + ], + "hard_timeout": 600, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_test_apk" + }, + { + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "device_os": "MMB29Q", + "device_type": "bullhead" + } + ], + "hard_timeout": 960, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_unittests" + }, + { "override_isolate_target": "blink_heap_unittests", "swarming": { "can_use_on_swarming_builders": true, @@ -3450,6 +3672,9 @@ "test": "base_unittests" }, { + "test": "blimp_unittests" + }, + { "override_compile_targets": [ "breakpad_unittests_deps" ], @@ -3536,6 +3761,14 @@ "test": "android_webview_test_apk" }, { + "apk_under_test": "Blimp.apk", + "override_compile_targets": [ + "blimp_test_apk" + ], + "test": "blimp_test_apk", + "test_apk": "BlimpTest.apk" + }, + { "test": "chrome_public_test_apk" }, {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index c3cde1d0..c4e9c24 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -265,6 +265,36 @@ "test": "base_unittests" }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "override_isolate_target": "blimp_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "4", + "device_type": "gce_x86" + } + ], + "hard_timeout": 600 + }, + "test": "blimp_test_apk" + }, + { + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "4", + "device_type": "gce_x86" + } + ] + }, + "test": "blimp_unittests" + }, + { "override_isolate_target": "blink_heap_unittests", "swarming": { "can_use_on_swarming_builders": true, @@ -906,6 +936,35 @@ "test": "base_unittests" }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "override_isolate_target": "blimp_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_type": "coho" + } + ] + }, + "test": "blimp_test_apk" + }, + { + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_type": "coho" + } + ] + }, + "test": "blimp_unittests" + }, + { "override_isolate_target": "blink_heap_unittests", "swarming": { "can_use_on_swarming_builders": true, @@ -1514,6 +1573,122 @@ } ] }, + "Blimp Android Client": { + "gtest_tests": [ + { + "override_compile_targets": [ + "blimp_test_apk" + ], + "override_isolate_target": "blimp_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "MMB29Q", + "device_type": "bullhead" + } + ], + "hard_timeout": 960, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_test_apk" + }, + { + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "MMB29Q", + "device_type": "bullhead" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_unittests" + } + ] + }, + "Blimp Linux Engine": { + "gtest_tests": [ + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "base_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blimp_browsertests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blimp_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "content_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "ipc_tests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "net_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "sandbox_linux_unittests" + } + ] + }, "Browser Side Navigation Linux": { "gtest_tests": [ { @@ -1603,6 +1778,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "blimp_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "blink_heap_unittests" }, { @@ -1980,6 +2161,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "blimp_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "blink_heap_unittests" }, { @@ -3587,6 +3774,35 @@ "test": "base_unittests" }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "override_isolate_target": "blimp_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_type": "coho" + } + ] + }, + "test": "blimp_test_apk" + }, + { + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "device_type": "coho" + } + ] + }, + "test": "blimp_unittests" + }, + { "override_isolate_target": "blink_heap_unittests", "swarming": { "can_use_on_swarming_builders": true, @@ -11136,6 +11352,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "blimp_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "blink_heap_unittests" }, { @@ -12764,6 +12986,23 @@ "args": [ "--test-arguments=--site-per-process" ], + "name": "site_per_process_blimp_unittests", + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "4", + "device_type": "bullhead" + } + ] + }, + "test": "blimp_unittests" + }, + { + "args": [ + "--test-arguments=--site-per-process" + ], "name": "site_per_process_components_browsertests", "override_isolate_target": "components_browsertests", "swarming": { @@ -12809,6 +13048,15 @@ }, { "args": [ + "--site-per-process" + ], + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blimp_unittests" + }, + { + "args": [ "--site-per-process", "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter" ], @@ -13070,6 +13318,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "blimp_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "blink_heap_unittests" }, { @@ -13426,6 +13680,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "blimp_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "blink_heap_unittests" }, {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index e71cdc8..84215c51 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -120,6 +120,72 @@ "test": "base_unittests" }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "override_isolate_target": "blimp_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "KTU84P", + "device_type": "hammerhead" + } + ], + "hard_timeout": 600, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_test_apk" + }, + { + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "KTU84P", + "device_type": "hammerhead" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_unittests" + }, + { "override_isolate_target": "blink_heap_unittests", "swarming": { "can_use_on_swarming_builders": true, @@ -1329,6 +1395,72 @@ "test": "base_unittests" }, { + "override_compile_targets": [ + "blimp_test_apk" + ], + "override_isolate_target": "blimp_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "KTU84P", + "device_type": "hammerhead" + } + ], + "hard_timeout": 600, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_test_apk" + }, + { + "override_isolate_target": "blimp_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "android_devices": "4", + "device_os": "KTU84P", + "device_type": "hammerhead" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "blimp_unittests" + }, + { "override_isolate_target": "blink_heap_unittests", "swarming": { "can_use_on_swarming_builders": true, @@ -2438,6 +2570,22 @@ } ] }, + "Blimp Linux (dbg)": { + "gtest_tests": [ + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blimp_browsertests" + }, + { + "swarming": { + "can_use_on_swarming_builders": false + }, + "test": "blimp_unittests" + } + ] + }, "Cast Linux": { "gtest_tests": [ { @@ -2651,6 +2799,12 @@ }, { "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blimp_unittests" + }, + { + "swarming": { "can_use_on_swarming_builders": true, "shards": 5 }, @@ -3302,6 +3456,12 @@ }, { "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blimp_unittests" + }, + { + "swarming": { "can_use_on_swarming_builders": true, "shards": 10 }, @@ -3849,6 +4009,12 @@ }, { "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blimp_unittests" + }, + { + "swarming": { "can_use_on_swarming_builders": true, "shards": 10 },
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index fe019ae9..67280c5 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -163,6 +163,18 @@ "label": "//tools/battor_agent:battor_agent_unittests", "type": "console_test_launcher", }, + "blimp_browsertests": { + "label": "//blimp:blimp_browsertests", + "type": "console_test_launcher", + }, + "blimp_test_apk": { + "label": "//blimp/client/app:blimp_test_apk", + "type": "console_test_launcher", + }, + "blimp_unittests": { + "label": "//blimp:blimp_unittests", + "type": "console_test_launcher", + }, "blink_heap_unittests": { "label": "//third_party/WebKit/Source/platform/heap:blink_heap_unittests", "type": "console_test_launcher",
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 74ad016..658384e 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1698,7 +1698,6 @@ crbug.com/600248 imported/wpt/web-animations/interfaces/Animation/onfinish.html [ Pass Failure ] crbug.com/600248 imported/wpt/web-animations/interfaces/Animation/playbackRate.html [ Pass Failure ] -crbug.com/600248 imported/wpt/web-animations/animation-model/animation-types/type-per-property.html [ Failure Timeout ] crbug.com/600248 imported/wpt/web-animations/timing-model/animations/updating-the-finished-state.html [ Pass Failure Timeout ] crbug.com/611658 [ Win7 ] fast/forms/text/text-font-height-mismatch.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/fast/harness/resources/results-test.js b/third_party/WebKit/LayoutTests/fast/harness/resources/results-test.js index 20e8541e..2d06f39 100644 --- a/third_party/WebKit/LayoutTests/fast/harness/resources/results-test.js +++ b/third_party/WebKit/LayoutTests/fast/harness/resources/results-test.js
@@ -27,7 +27,6 @@ "fixable": 0, "num_flaky": 0, "layout_tests_dir": "/WEBKITROOT", - "has_pretty_patch": false, "has_wdiff": false, "chromium_revision": 12345, "pixel_tests_enabled": true @@ -93,7 +92,7 @@ } catch (e) { logFail("FAIL: uncaught exception " + e.toString()); } - + try { assertions(); } catch (e) { @@ -126,7 +125,7 @@ assertTrue(document.querySelector('tbody td:nth-child(4)').textContent == actual); assertTrue(document.querySelector('tbody td:nth-child(5)').textContent == expected); }); - + } function runTests() @@ -176,14 +175,14 @@ assertTrue(testLinks[0].textContent == 'foo/bar.html'); assertTrue(testLinks[1].textContent == 'foo/bar1.html'); assertTrue(testLinks[2].textContent == 'foo/bar2.html'); - + assertTrue(!document.querySelector('#passes-table .expand-button')); var expectationTypes = document.querySelectorAll('#passes-table td:last-of-type'); assertTrue(expectationTypes[0].textContent == 'TEXT'); assertTrue(expectationTypes[1].textContent == 'CRASH'); assertTrue(expectationTypes[2].textContent == 'IMAGE'); - + assertTrue(document.getElementById('crash-tests-table')); assertTrue(document.getElementById('crash-tests-table').textContent.indexOf('crash log') != -1); assertTrue(document.getElementById('timeout-tests-table')); @@ -216,14 +215,14 @@ var expandLinks = document.querySelectorAll('.expand-button-text'); for (var i = 0; i < expandLinks.length; i++) assertTrue(isExpanded(expandLinks[i])); - + collapseAllExpectations(); // Collapsed expectations stay in the dom, but are display:none. assertTrue(document.querySelectorAll('tbody tr').length == 8); var expandLinks = document.querySelectorAll('.expand-button-text'); for (var i = 0; i < expandLinks.length; i++) assertTrue(isCollapsed(expandLinks[i])); - + expandExpectations(expandLinks[1]); assertTrue(isCollapsed(expandLinks[0])); assertTrue(isExpanded(expandLinks[1])); @@ -246,19 +245,19 @@ assertTrue(visibleExpandLinks().length == 1); assertTrue(document.querySelectorAll('.results-row').length == 1); assertTrue(window.getComputedStyle(document.querySelectorAll('tbody')[0], null)['display'] == 'none'); - + document.getElementById('show-expected-failures').checked = true; document.getElementById('show-expected-failures').onchange(); assertTrue(visibleExpandLinks().length == 2); assertTrue(document.querySelectorAll('.results-row').length == 1); assertTrue(window.getComputedStyle(document.querySelectorAll('tbody')[0], null)['display'] != 'none'); - + expandAllExpectations(); assertTrue(document.querySelectorAll('.results-row').length == 2); assertTrue(window.getComputedStyle(document.querySelectorAll('tbody')[0], null)['display'] != 'none'); }); - + results = mockResults(); results.tests['only-expected-fail.html'] = mockExpectation('TEXT', 'TEXT'); runTest(results, function() { @@ -266,16 +265,16 @@ }); runDefaultSingleRowTest('bar-skip.html', 'TEXT', 'SKIP', true, '', ''); - runDefaultSingleRowTest('bar-flaky-fail.html', 'PASS FAIL', 'TEXT', true, 'expected actual diff ', ''); + runDefaultSingleRowTest('bar-flaky-fail.html', 'PASS FAIL', 'TEXT', true, 'expected actual diff pretty diff ', ''); runDefaultSingleRowTest('bar-flaky-fail-unexpected.html', 'PASS TEXT', 'IMAGE', false, '', 'images diff '); runDefaultSingleRowTest('bar-audio.html', 'TEXT', 'AUDIO', false, 'expected audio actual audio ', ''); runDefaultSingleRowTest('bar-image.html', 'TEXT', 'IMAGE', false, '', 'images diff '); - runDefaultSingleRowTest('bar-image-plus-text.html', 'TEXT', 'IMAGE+TEXT', false, 'expected actual diff ', 'images diff '); + runDefaultSingleRowTest('bar-image-plus-text.html', 'TEXT', 'IMAGE+TEXT', false, 'expected actual diff pretty diff ', 'images diff '); - // test the mapping for FAIL onto only ['TEXT', 'IMAGE+TEXT', 'AUDIO'] - runDefaultSingleRowTest('bar-image.html', 'FAIL', 'IMAGE+TEXT', true, 'expected actual diff ', 'images diff '); + // Test the mapping for FAIL onto only ['IMAGE+TEXT', 'AUDIO', 'TEXT', 'IMAGE']. + runDefaultSingleRowTest('bar-image.html', 'FAIL', 'IMAGE+TEXT', true, 'expected actual diff pretty diff ', 'images diff '); runDefaultSingleRowTest('bar-image.html', 'FAIL', 'AUDIO', true, 'expected audio actual audio ', ''); - runDefaultSingleRowTest('bar-image.html', 'FAIL', 'TEXT', true, 'expected actual diff ', ''); + runDefaultSingleRowTest('bar-image.html', 'FAIL', 'TEXT', true, 'expected actual diff pretty diff ', ''); runDefaultSingleRowTest('bar-image.html', 'FAIL', 'IMAGE', false, '', 'images diff '); results = mockResults(); @@ -346,10 +345,8 @@ results = mockResults(); var subtree = results.tests['foo'] = {} subtree['bar.html'] = mockExpectation('TEXT', 'TEXT'); - results.has_pretty_patch = true; runTest(results, function() { assertTrue(document.querySelector('tbody td:nth-child(2)').textContent.indexOf('pretty diff') != -1); - assertTrue(document.querySelector('tbody td:nth-child(2)').textContent.indexOf('wdiff') == -1); }); results = mockResults(); @@ -358,9 +355,9 @@ results.has_wdiff = true; runTest(results, function() { assertTrue(document.querySelector('tbody td:nth-child(2)').textContent.indexOf('wdiff') != -1); - assertTrue(document.querySelector('tbody td:nth-child(2)').textContent.indexOf('pretty diff') == -1); + }); - + results = mockResults(); var subtree = results.tests['foo'] = {} subtree['bar.html'] = mockExpectation('TEXT', 'PASS'); @@ -404,7 +401,7 @@ assertTrue(!!document.querySelector('.pixel-zoom-container')); assertTrue(document.querySelectorAll('.zoom-image-container').length == 3); }); - + results = mockResults(); var subtree = results.tests['fullscreen'] = {} subtree['full-screen-api.html'] = mockExpectation('TEXT', 'IMAGE+TEXT'); @@ -416,7 +413,7 @@ var oldShouldUseTracLinks = shouldUseTracLinks; shouldUseTracLinks = function() { return true; }; - + results = mockResults(); var subtree = results.tests['fullscreen'] = {} subtree['full-screen-api.html'] = mockExpectation('TEXT', 'IMAGE+TEXT'); @@ -446,12 +443,12 @@ updateTogglingImages(); // FIXME: We get extra spaces in the DOM every time we enable/disable image toggling. assertTrue(document.querySelector('tbody td:nth-child(3)').textContent == 'expected actual diff '); - + document.getElementById('toggle-images').checked = true; updateTogglingImages(); assertTrue(document.querySelector('tbody td:nth-child(3)').textContent == ' images diff '); }); - + results = mockResults(); results.tests['reading-options-from-localstorage.html'] = mockExpectation('IMAGE+TEXT', 'IMAGE+TEXT'); runTest(results, function() { @@ -555,7 +552,7 @@ expandAllExpectations(); assertTrue(visibleExpandLinks().length == 2); }); - + results = mockResults(); var subtree = results.tests['foo'] = {} @@ -594,7 +591,7 @@ runTest(results, function() { assertTrue(document.getElementById('results-table')); assertTrue(visibleExpandLinks().length == 3); - + if (window.eventSender) { eventSender.keyDown('i', ["metaKey"]); eventSender.keyDown('i', ["shiftKey"]);
diff --git a/third_party/WebKit/LayoutTests/fast/harness/results-expected.txt b/third_party/WebKit/LayoutTests/fast/harness/results-expected.txt index ade95c5..02d8135 100644 --- a/third_party/WebKit/LayoutTests/fast/harness/results-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/harness/results-expected.txt
@@ -131,8 +131,6 @@ TEST-25: PASS TEST-25: PASS TEST-26: PASS -TEST-26: PASS -TEST-27: PASS TEST-27: PASS TEST-28: PASS TEST-29: PASS
diff --git a/third_party/WebKit/LayoutTests/fast/harness/results.html b/third_party/WebKit/LayoutTests/fast/harness/results.html index 7982f1b..0166837a 100644 --- a/third_party/WebKit/LayoutTests/fast/harness/results.html +++ b/third_party/WebKit/LayoutTests/fast/harness/results.html
@@ -539,10 +539,8 @@ { var html = resultLink(prefix, '-expected.txt', 'expected') + resultLink(prefix, '-actual.txt', 'actual') + - resultLink(prefix, '-diff.txt', 'diff'); - - if (globalState().results.has_pretty_patch) - html += resultLink(prefix, '-pretty-diff.html', 'pretty diff'); + resultLink(prefix, '-diff.txt', 'diff') + + resultLink(prefix, '-pretty-diff.html', 'pretty diff'); if (globalState().results.has_wdiff) html += resultLink(prefix, '-wdiff.html', 'wdiff');
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html b/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html index 86a29d1..b74b3f2 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html
@@ -62,8 +62,8 @@ var blob_2 = new Blob(['TEST000000002']) var reader = new FileReader(); reader.onloadend = this.step_func_done(function() { - assert_equals(reader.readyState, FileReader.LOADING, - "readyState must be LOADING") + assert_equals(reader.readyState, FileReader.DONE, + "readyState must be DONE") reader.readAsArrayBuffer(blob_2) assert_equals(reader.readyState, FileReader.LOADING, "readyState Must be LOADING") });
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/idbindex-rename.html b/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/idbindex-rename.html index 2ef26d29..370b83e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/idbindex-rename.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/idbindex-rename.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<meta name="timeout" content="long"> <title>IndexedDB: index renaming support</title> <link rel="help" href="https://w3c.github.io/IndexedDB/#dom-idbindex-name">
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/idbobjectstore-rename-store.html b/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/idbobjectstore-rename-store.html index 47860b59..d07a464 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/idbobjectstore-rename-store.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/idbobjectstore-rename-store.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<meta name="timeout" content="long"> <title>IndexedDB: object store renaming support</title> <link rel="help" href="https://w3c.github.io/IndexedDB/#dom-idbobjectstore-name">
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/WebIDL/current-realm.html b/third_party/WebKit/LayoutTests/imported/wpt/WebIDL/current-realm.html index fd24709b..c9450e2 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/WebIDL/current-realm.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/WebIDL/current-realm.html
@@ -134,6 +134,9 @@ test(function() { var c = new self[0].FontFace("test", "about:blank"), obj = c.load() + obj.catch(function(reason) { + // Ignore exception when it fails to load because the URL is invalid. + }); assert_global(obj) obj = FontFace.prototype.load.call(c)
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/check_stability.py b/third_party/WebKit/LayoutTests/imported/wpt/check_stability.py index 421f8cb..b8ede38 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/check_stability.py +++ b/third_party/WebKit/LayoutTests/imported/wpt/check_stability.py
@@ -536,14 +536,19 @@ except ValueError: pass if pr_number: - logger.info("### [%s](%s/%s%s) ###" % (test, baseurl, pr_number, test)) + logger.info("<details>\n") + logger.info('<summary><a href="%s/%s%s">%s</a></summary>\n\n' % + (baseurl, pr_number, test, test)) else: logger.info("### %s ###" % test) parent = test_results.pop(None) strings = [("", err_string(parent, iterations))] - strings.extend(((("`%s`" % markdown_adjust(subtest)) if subtest else "", err_string(results, iterations)) + strings.extend(((("`%s`" % markdown_adjust(subtest)) if subtest + else "", err_string(results, iterations)) for subtest, results in test_results.iteritems())) table(["Subtest", "Results"], strings, logger.info) + if pr_number: + logger.info("</details>\n") def get_parser():
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/historical.html b/third_party/WebKit/LayoutTests/imported/wpt/dom/historical.html index e0612be..d669ad4a 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/dom/historical.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/dom/historical.html
@@ -48,11 +48,22 @@ "renameNode", "defaultCharset", "height", - "width" + "width", + // https://github.com/whatwg/html/commit/a64aea7fdb221bba027d95dc3cabda09e0b3e5dc + "commands", + // https://github.com/whatwg/html/commit/797b4d273955a0fe3cc2e2d0ca5d578f37c0f126 + "cssElementMap", + // https://github.com/whatwg/html/commit/e236f46820b93d6fe2e2caae0363331075c6c4fb + "async", ] documentNuked.forEach(isNukedFromDocument) test(function() { + // https://github.com/whatwg/html/commit/e236f46820b93d6fe2e2caae0363331075c6c4fb + assert_false("load" in document); +}, "document.load"); + +test(function() { assert_equals(document.implementation["getFeature"], undefined) }, "DOMImplementation.getFeature() must be nuked.")
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-manual.html index 621b330..a3ac2ff 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-manual.html
@@ -7,7 +7,7 @@ <script> async_test(function(t) { - trusted_request(document.querySelector("div")); + trusted_request(t, document.querySelector("div")); document.addEventListener("fullscreenchange", t.step_func(function(event) {
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-timing-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-timing-manual.html index f91eb7e2..d52b64e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-timing-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-timing-manual.html
@@ -7,7 +7,7 @@ <script> async_test(t => { const div = document.querySelector('div'); - trusted_request(div); + trusted_request(t, div); document.onfullscreenchange = t.step_func(() => { // We are now in fullscreen. Exit again.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-twice-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-twice-manual.html index c80aeb41..49f3141 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-twice-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-twice-manual.html
@@ -27,6 +27,6 @@ }); document.onfullscreenerror = t.unreached_func("fullscreenerror event"); - trusted_request(div); + trusted_request(t, div); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-fullscreen-element-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-fullscreen-element-manual.html index 8f0af41..acd24e1 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-fullscreen-element-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-fullscreen-element-manual.html
@@ -22,11 +22,11 @@ }); }); - trusted_click(t.step_func(function() + trusted_click(t, function() { assert_equals(document.fullscreenElement, null, "fullscreenElement before requestFullscreen()"); div.requestFullscreen(); assert_equals(document.fullscreenElement, null, "fullscreenElement after requestFullscreen()"); - }), document.body); + }, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-onfullscreenchange-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-onfullscreenchange-manual.html index 1d05ce0..7415c111a 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-onfullscreenchange-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-onfullscreenchange-manual.html
@@ -10,6 +10,6 @@ var div = document.querySelector("div"); assert_equals(document.onfullscreenchange, null, "initial onfullscreenchange"); document.onfullscreenchange = t.step_func_done(); - trusted_request(div); + trusted_request(t, div); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-containing-iframe-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-containing-iframe-manual.html index a630fe2..66f9968 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-containing-iframe-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-containing-iframe-manual.html
@@ -10,10 +10,10 @@ async_test(function(t) { var iframes = document.getElementsByTagName("iframe"); - trusted_request(iframes[0].contentDocument.body, document.body); + trusted_request(t, iframes[0].contentDocument.body, document.body); iframes[0].contentDocument.onfullscreenchange = t.step_func(function() { - trusted_request(iframes[1].contentDocument.body, iframes[0].contentDocument.body); + trusted_request(t, iframes[1].contentDocument.body, iframes[0].contentDocument.body); iframes[1].contentDocument.onfullscreenchange = t.unreached_func("fullscreenchange event"); iframes[1].contentDocument.onfullscreenerror = t.step_func_done(); });
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-enabled-flag-not-set-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-enabled-flag-not-set-manual.html index 501767d..1e18be5e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-enabled-flag-not-set-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-enabled-flag-not-set-manual.html
@@ -14,6 +14,6 @@ iframe.contentDocument.onfullscreenchange = t.unreached_func("iframe fullscreenchange event"); iframe.contentDocument.onfullscreenerror = t.step_func_done(); assert_false(iframe.contentDocument.fullscreenEnabled, "fullscreen enabled flag"); - trusted_request(iframe.contentDocument.body, document.body); + trusted_request(t, iframe.contentDocument.body, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-fullscreen-element-sibling-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-fullscreen-element-sibling-manual.html index 0f79cb6..dc0c28c 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-fullscreen-element-sibling-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-fullscreen-element-sibling-manual.html
@@ -14,10 +14,10 @@ document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, a, "fullscreen element"); - trusted_request(b, a); + trusted_request(t, b, a); document.onfullscreenchange = t.unreached_func("second fullscreenchange event"); document.onfullscreenerror = t.step_func_done(); }); - trusted_request(a); + trusted_request(t, a); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-fullscreen-iframe-child-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-fullscreen-iframe-child-manual.html index 08febbd4..2563e70 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-fullscreen-iframe-child-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-fullscreen-iframe-child-manual.html
@@ -25,9 +25,9 @@ }); document.onfullscreenerror = t.unreached_func("fullscreenerror event"); - trusted_request(div, iframe.contentDocument.body); + trusted_request(t, div, iframe.contentDocument.body); }); - trusted_request(iframe); + trusted_request(t, iframe); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-iframe-child-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-iframe-child-manual.html index ab1c261..b8f4f2d 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-iframe-child-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-iframe-child-manual.html
@@ -15,6 +15,6 @@ }); document.onfullscreenerror = t.unreached_func("fullscreenerror event"); - trusted_request(div, document.body); + trusted_request(t, div, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-not-in-document-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-not-in-document-manual.html index 904d3199..498e71db 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-not-in-document-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-ready-check-not-in-document-manual.html
@@ -10,6 +10,6 @@ var div = document.createElement("div"); document.onfullscreenchange = t.unreached_func("fullscreenchange event"); document.onfullscreenerror = t.step_func_done(); - trusted_request(div, document.body); + trusted_request(t, div, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-exit-iframe-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-exit-iframe-manual.html index 4483cca..8305fc5e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-exit-iframe-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-exit-iframe-manual.html
@@ -33,6 +33,6 @@ document.onfullscreenerror = t.unreached_func('fullscreenerror event'); iframeDoc.onfullscreenerror = t.unreached_func('iframe fullscreenerror event'); - trusted_request(iframeBody, document.body); + trusted_request(t, iframeBody, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-manual.html index 697a27f3..c09cebb 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-manual.html
@@ -17,9 +17,9 @@ }); document.onfullscreenerror = t.unreached_func("fullscreenchange event"); - trusted_click(t.step_func(() => { + trusted_click(t, () => { target.requestFullscreen(); moveTo.appendChild(target); - }), document.body); + }, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html index 255623e..28832824 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html
@@ -19,9 +19,9 @@ assert_equals(iframeDoc.fullscreenElement, null); }); - trusted_click(t.step_func(() => { + trusted_click(t, () => { target.requestFullscreen(); iframeDoc.body.appendChild(target); - }), document.body); + }, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-iframe-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-iframe-manual.html index e2149fd..198ae73 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-iframe-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-iframe-manual.html
@@ -15,7 +15,7 @@ iframeDocument.onfullscreenchange = t.unreached_func("iframe fullscreenchange event"); iframeDocument.onfullscreenerror = t.unreached_func("iframe fullscreenerror event"); - trusted_click(t.step_func(() => { + trusted_click(t, () => { iframeDocument.body.requestFullscreen(); iframe.remove(); // No events will be fired, end test after 100ms. @@ -23,6 +23,6 @@ assert_equals(document.fullscreenElement, null); assert_equals(iframeDocument.fullscreenElement, null); }), 100); - }), document.body); + }, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual.html index c754bf00..03c38cc 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual.html
@@ -14,9 +14,9 @@ assert_equals(document.fullscreenElement, null); }); - trusted_click(t.step_func(() => { + trusted_click(t, () => { target.requestFullscreen(); target.remove(); - }), document.body); + }, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-manual.html index 43d1ea4..12f0a32 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-manual.html
@@ -17,6 +17,6 @@ t.done(); })); - trusted_request(div); + trusted_request(t, div); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-non-top-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-non-top-manual.html index ed5e1c8..06c4c1b 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-non-top-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-non-top-manual.html
@@ -11,16 +11,16 @@ async_test(function(t) { var first = document.getElementById("first"); - trusted_request(first); + trusted_request(t, first); document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, first); var last = document.getElementById("last"); - trusted_request(last); + trusted_request(t, last); document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, last); - trusted_request(first, last); + trusted_request(t, first, last); document.onfullscreenerror = t.step_func_done(); }); });
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-same-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-same-manual.html index a475c18..defe9ce5 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-same-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-same-manual.html
@@ -16,15 +16,15 @@ // doc's fullscreen element, terminate these subsubsteps." document.onfullscreenchange = t.unreached_func("fullscreenchange event"); - trusted_click(t.step_func(() => { + trusted_click(t, () => { target.requestFullscreen(); // Wait until after the next animation frame. requestAnimationFrame(t.step_func_done()); - }), target); + }, target); }); document.onfullscreenerror = t.unreached_func("fullscreenerror event"); - trusted_request(target); + trusted_request(t, target); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-svg-rect-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-svg-rect-manual.html index 9244d74e..77ea2b2 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-svg-rect-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-svg-rect-manual.html
@@ -10,7 +10,7 @@ { var rect = document.querySelector("rect"); assert_true(rect instanceof SVGRectElement); - trusted_request(rect, document.body); + trusted_request(t, rect, document.body); document.onfullscreenchange = t.unreached_func("fullscreenerror event"); document.onfullscreenerror = t.step_func_done(); });
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-svg-svg-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-svg-svg-manual.html index f971ee4d..c6e473c 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-svg-svg-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-svg-svg-manual.html
@@ -10,7 +10,7 @@ { var svg = document.querySelector("svg"); assert_true(svg instanceof SVGSVGElement); - trusted_request(svg, document.body); + trusted_request(t, svg, document.body); document.onfullscreenchange = t.step_func_done(); document.onfullscreenerror = t.unreached_func("fullscreenerror event"); });
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-timing-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-timing-manual.html index f92b4f6..14fe5f70 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-timing-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-timing-manual.html
@@ -6,7 +6,7 @@ <div id="log"></div> <script> async_test(t => { - trusted_request(document.querySelector('div')); + trusted_request(t, document.querySelector('div')); // If fullscreenchange is an animation frame event, then animation frame // callbacks should be run after it is fired, before the timer callback.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-top-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-top-manual.html index 4982916..eeeb783 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-top-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-top-manual.html
@@ -9,12 +9,12 @@ async_test(function(t) { var top = document.getElementById("top"); - trusted_request(top); + trusted_request(t, top); document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, top); document.onfullscreenchange = t.unreached_func("fullscreenchange event"); - trusted_click(t.step_func(function() + trusted_click(t, function() { top.requestFullscreen(); // A fullscreenerror event would be fired after an async section @@ -23,7 +23,7 @@ { requestAnimationFrame(t.step_func_done()); }, 0); - }), top); + }, top); }); document.onfullscreenerror = t.unreached_func("fullscreenerror event"); });
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-twice-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-twice-manual.html index 4e843c8e..2b28983b 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-twice-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-twice-manual.html
@@ -16,12 +16,12 @@ }); document.onfullscreenerror = t.unreached_func("fullscreenerror event"); - trusted_click(t.step_func(() => { + trusted_click(t, () => { // Request fullscreen twice. div.requestFullscreen(); assert_equals(document.fullscreenElement, null, "fullscreenElement after first requestFullscreen()"); div.requestFullscreen(); assert_equals(document.fullscreenElement, null, "fullscreenElement after second requestFullscreen()"); - }), document.body); + }, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-two-elements-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-two-elements-manual.html index 1ca4355..9611c816 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-two-elements-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-two-elements-manual.html
@@ -26,9 +26,9 @@ }); document.onfullscreenerror = t.unreached_func('fullscreenerror event'); - trusted_click(t.step_func(() => { + trusted_click(t, () => { b.requestFullscreen(); a.requestFullscreen(); - }), document.body); + }, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-two-iframes-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-two-iframes-manual.html index 60a880ef..99a7672e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-two-iframes-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-two-iframes-manual.html
@@ -28,9 +28,9 @@ }); document.onfullscreenerror = t.unreached_func('fullscreenerror event'); - trusted_click(t.step_func(() => { + trusted_click(t, () => { b.contentDocument.body.requestFullscreen(); a.contentDocument.body.requestFullscreen(); - }), document.body); + }, document.body); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-child-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-child-manual.html index 63cc727f..4c33733 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-child-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-child-manual.html
@@ -11,7 +11,7 @@ async_test(function(t) { var parent = document.getElementById("parent"); - trusted_request(parent); + trusted_request(t, parent); document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, parent);
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-first-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-first-manual.html index 5873a1cf..861dc69 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-first-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-first-manual.html
@@ -11,12 +11,12 @@ async_test(function(t) { var first = document.getElementById("first"); - trusted_request(first); + trusted_request(t, first); document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, first); var last = document.getElementById("last"); - trusted_request(last); + trusted_request(t, last); document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, last);
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-last-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-last-manual.html index 3e52049..3837439 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-last-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-last-manual.html
@@ -11,12 +11,12 @@ async_test(function(t) { var first = document.getElementById("first"); - trusted_request(first); + trusted_request(t, first); document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, first); var last = document.getElementById("last"); - trusted_request(last); + trusted_request(t, last); document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, last);
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-parent-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-parent-manual.html index 74327637..a284fc6 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-parent-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-parent-manual.html
@@ -11,7 +11,7 @@ async_test(function(t) { var child = document.getElementById("child"); - trusted_request(child); + trusted_request(t, child); document.onfullscreenchange = t.step_func(function() { assert_equals(document.fullscreenElement, child);
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-single-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-single-manual.html index 53abb5e8..9a57d93 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-single-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/model/remove-single-manual.html
@@ -19,6 +19,6 @@ t.done(); }); }); - trusted_request(single); + trusted_request(t, single); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/trusted-click.js b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/trusted-click.js index 6cd4020..cab23e3 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/trusted-click.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/trusted-click.js
@@ -1,6 +1,6 @@ // Invokes callback from a trusted click event, to satisfy // https://html.spec.whatwg.org/#triggered-by-user-activation -function trusted_click(callback, container) +function trusted_click(test, callback, container) { var document = container.ownerDocument; var button = document.createElement("button"); @@ -8,17 +8,16 @@ button.style.display = "block"; button.style.fontSize = "20px"; button.style.padding = "10px"; - button.onclick = function() + button.onclick = test.step_func(function() { callback(); container.removeChild(button); - }; + }); container.appendChild(button); } // Invokes element.requestFullscreen() from a trusted click. -function trusted_request(element, container) +function trusted_request(test, element, container) { - var request = element.requestFullscreen.bind(element); - trusted_click(request, container || element.parentNode); + trusted_click(test, () => element.requestFullscreen(), container || element.parentNode); }
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resources/post_name_on_load.html b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resources/post_name_on_load.html new file mode 100644 index 0000000..1e9b10d --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resources/post_name_on_load.html
@@ -0,0 +1,7 @@ +<!doctype html> +<script> +addEventListener('load', _ => { + let params = new URLSearchParams(window.location.search); + window.opener.postMessage(params.get('name'), '*'); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html new file mode 100644 index 0000000..fb7365b --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html
@@ -0,0 +1,145 @@ +<!doctype html> +<title>Verify history.back() on a persisted page resumes timers</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="text/javascript"> + +function make_post_back_url(name) { + return new URL('resources/post_name_on_load.html?name=' + name, + window.location).href; +} + +function wait_for_message(name) { + return new Promise(resolve => { + addEventListener('message', function onMsg(evt) { + if (evt.data !== name) { + return; + } + removeEventListener('message', onMsg); + resolve(); + }); + }); +} + +function with_window_by_name(name) { + let win = window.open(make_post_back_url(name)); + return wait_for_message(name).then(_ => { + return win; + }); +} + +function with_nested_frame(win, url) { + return new Promise(resolve => { + let frame = win.document.createElement('iframe'); + frame.addEventListener('load', function onLoad(evt) { + removeEventListener('load', onLoad); + resolve(frame); + }); + frame.src = url; + win.document.body.appendChild(frame); + }); +} + +function delay(win, delay) { + return new Promise(resolve => { + win.setTimeout(_ => { + resolve(win); + }, delay); + }); +} + +function navigate_by_name(win, name) { + win.location = make_post_back_url(name); + return wait_for_message(name).then(_ => { + return win; + }); +} + +function go_back(win) { + return new Promise(resolve => { + win.onpagehide = e => resolve(win); + win.history.back(); + }); +} + +let DELAY = 500; + +promise_test(t => { + // Create a new window so we can navigate it later. + return with_window_by_name('foo').then(win => { + // Schedule a timer within the new window. Our intent is + // to navigate the window before the timer fires. + let delayFired = false; + let innerDelay = delay(win, DELAY); + innerDelay.then(_ => { + delayFired = true; + }); + + return navigate_by_name(win, 'bar').then(_ => { + // Since the window has navigated the timer should not + // fire. We set a timer on our current test window + // to verify the other timer is not received. + assert_false(delayFired); + return delay(window, DELAY * 2); + }).then(_ => { + // The navigated window's timer should not have fired. + assert_false(delayFired); + // Now go back to the document that set the timer. + return go_back(win); + }).then(_ => { + // We wait for one of two conditions here. For browsers + // with a bfcache the original suspended timer will fire. + // Alternatively, if the browser reloads the page the original + // message will be sent again. Wait for either of these + // two events. + return Promise.race([wait_for_message('foo'), innerDelay]); + }).then(_ => { + win.close(); + }); + }); +}, 'history.back() handles top level page timer correctly'); + +promise_test(t => { + let win; + // Create a new window so we can navigate it later. + return with_window_by_name('foo').then(w => { + win = w; + + // Create a nested frame so we check if navigation and history.back() + // properly handle child window state. + return with_nested_frame(win, 'about:blank'); + + }).then(frame => { + // Schedule a timer within the nested frame contained by the new window. + // Our intent is to navigate the window before the timer fires. + let delayFired = false; + let innerDelay = delay(frame.contentWindow, DELAY); + innerDelay.then(_ => { + delayFired = true; + }); + + return navigate_by_name(win, 'bar').then(_ => { + // Since the window has navigated the timer should not + // fire. We set a timer on our current test window + // to verify the other timer is not received. + assert_false(delayFired); + return delay(window, DELAY * 2); + }).then(_ => { + // The navigated window's timer should not have fired. + assert_false(delayFired); + // Now go back to the document containing the frame that set the timer. + return go_back(win); + }).then(_ => { + // We wait for one of two conditions here. For browsers + // with a bfcache the original suspended timer will fire. + // Alternatively, if the browser reloads the page the original + // message will be sent again. Wait for either of these + // two events. + return Promise.race([wait_for_message('foo'), innerDelay]); + }).then(_ => { + win.close(); + }); + }); +}, 'history.back() handles nested iframe timer correctly'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/history/the-location-interface/location-pathname-setter-question-mark.html b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/history/the-location-interface/location-pathname-setter-question-mark.html new file mode 100644 index 0000000..0954602 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/history/the-location-interface/location-pathname-setter-question-mark.html
@@ -0,0 +1,16 @@ +<!doctype html> +<title>Set location.pathname to ?</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<iframe src=/common/blank.html></iframe> +<script> +async_test((t) => { + onload = t.step_func(() => { + self[0].frameElement.onload = t.step_func_done(() => { + assert_equals(self[0].location.pathname, "/%3F") + }) + self[0].location.pathname = "?" + }) +}) +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html index 79440e2..7560fcd 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
@@ -70,16 +70,25 @@ * Also tests for [[GetOwnProperty]] and [[HasOwnProperty]] behavior. */ -var whitelistedWindowProps = ['location', 'postMessage', 'window', 'frames', 'self', 'top', 'parent', - 'opener', 'closed', 'close', 'blur', 'focus', 'length']; +var whitelistedWindowIndices = ['0', '1']; +var whitelistedWindowPropNames = ['location', 'postMessage', 'window', 'frames', 'self', 'top', 'parent', + 'opener', 'closed', 'close', 'blur', 'focus', 'length']; +whitelistedWindowPropNames = whitelistedWindowPropNames.concat(whitelistedWindowIndices); +whitelistedWindowPropNames.sort(); +var whitelistedLocationPropNames = ['href', 'replace']; +whitelistedLocationPropNames.sort(); +var whitelistedSymbols = [Symbol.toStringTag, Symbol.hasInstance, + Symbol.isConcatSpreadable]; +var whitelistedWindowProps = whitelistedWindowPropNames.concat(whitelistedSymbols); + addTest(function() { for (var prop in window) { if (whitelistedWindowProps.indexOf(prop) != -1) { C[prop]; // Shouldn't throw. Object.getOwnPropertyDescriptor(C, prop); // Shouldn't throw. - assert_true(Object.prototype.hasOwnProperty.call(C, prop), "hasOwnProperty for " + prop); + assert_true(Object.prototype.hasOwnProperty.call(C, prop), "hasOwnProperty for " + String(prop)); } else { - assert_throws(null, function() { C[prop]; }, "Should throw when accessing " + prop + " on Window"); + assert_throws(null, function() { C[prop]; }, "Should throw when accessing " + String(prop) + " on Window"); assert_throws(null, function() { Object.getOwnPropertyDescriptor(C, prop); }, "Should throw when accessing property descriptor for " + prop + " on Window"); assert_throws(null, function() { Object.prototype.hasOwnProperty.call(C, prop); }, @@ -169,9 +178,18 @@ }, "[[GetOwnProperty]] - Properties on cross-origin objects should be reported |own|"); function checkPropertyDescriptor(desc, propName, expectWritable) { + var isSymbol = (typeof(propName) == "symbol"); + propName = String(propName); assert_true(isObject(desc), "property descriptor for " + propName + " should exist"); assert_equals(desc.enumerable, false, "property descriptor for " + propName + " should be non-enumerable"); assert_equals(desc.configurable, true, "property descriptor for " + propName + " should be configurable"); + if (isSymbol) { + assert_true("value" in desc, + "property descriptor for " + propName + " should be a value descriptor"); + assert_equals(desc.value, undefined, + "symbol-named cross-origin visible prop " + propName + + " should come back as undefined"); + } if ('value' in desc) assert_equals(desc.writable, expectWritable, "property descriptor for " + propName + " should have writable: " + expectWritable); else @@ -187,6 +205,10 @@ checkPropertyDescriptor(Object.getOwnPropertyDescriptor(C.location, 'replace'), 'replace', false); checkPropertyDescriptor(Object.getOwnPropertyDescriptor(C.location, 'href'), 'href', true); assert_equals(typeof Object.getOwnPropertyDescriptor(C.location, 'href').get, 'undefined', "Cross-origin location should have no href getter"); + whitelistedSymbols.forEach(function(prop) { + var desc = Object.getOwnPropertyDescriptor(C.location, prop); + checkPropertyDescriptor(desc, prop, false); + }); }, "[[GetOwnProperty]] - Property descriptors for cross-origin properties should be set up correctly"); /* @@ -243,13 +265,44 @@ */ addTest(function() { - assert_array_equals(whitelistedWindowProps.sort(), Object.getOwnPropertyNames(C).sort(), + assert_array_equals(Object.getOwnPropertyNames(C).sort(), + whitelistedWindowPropNames, "Object.getOwnPropertyNames() gives the right answer for cross-origin Window"); - assert_array_equals(Object.getOwnPropertyNames(C.location).sort(), ['href', 'replace'], + assert_array_equals(Object.getOwnPropertyNames(C.location).sort(), + whitelistedLocationPropNames, "Object.getOwnPropertyNames() gives the right answer for cross-origin Location"); }, "[[OwnPropertyKeys]] should return all properties from cross-origin objects"); addTest(function() { + assert_array_equals(Object.getOwnPropertySymbols(C), whitelistedSymbols, + "Object.getOwnPropertySymbols() should return the three symbol-named properties that are exposed on a cross-origin Window"); + assert_array_equals(Object.getOwnPropertySymbols(C.location), + whitelistedSymbols, + "Object.getOwnPropertySymbols() should return the three symbol-named properties that are exposed on a cross-origin Location"); +}, "[[OwnPropertyKeys]] should return the right symbol-named properties for cross-origin objects"); + +addTest(function() { + var allWindowProps = Reflect.ownKeys(C); + indexedWindowProps = allWindowProps.slice(0, whitelistedWindowIndices.length); + stringWindowProps = allWindowProps.slice(0, -1 * whitelistedSymbols.length); + symbolWindowProps = allWindowProps.slice(-1 * whitelistedSymbols.length); + assert_array_equals(indexedWindowProps, whitelistedWindowIndices, + "Reflect.ownKeys should start with the indices exposed on the cross-origin window."); + assert_array_equals(stringWindowProps.sort(), whitelistedWindowPropNames, + "Reflect.ownKeys should continue with the cross-origin window properties for a cross-origin Window."); + assert_array_equals(symbolWindowProps, whitelistedSymbols, + "Reflect.ownKeys should end with the cross-origin symbols for a cross-origin Window."); + + var allLocationProps = Reflect.ownKeys(C.location); + stringLocationProps = allLocationProps.slice(0, -1 * whitelistedSymbols.length); + symbolLocationProps = allLocationProps.slice(-1 * whitelistedSymbols.length); + assert_array_equals(stringLocationProps.sort(), whitelistedLocationPropNames, + "Reflect.ownKeys should start with the cross-origin window properties for a cross-origin Location.") + assert_array_equals(symbolLocationProps, whitelistedSymbols, + "Reflect.ownKeys should end with the cross-origin symbols for a cross-origin Location.") +}, "[[OwnPropertyKeys]] should place the symbols after the property names after the subframe indices"); + +addTest(function() { assert_true(B.eval('parent.C') === C, "A and B observe the same identity for C's Window"); assert_true(B.eval('parent.C.location') === C.location, "A and B observe the same identity for C's Location"); }, "A and B jointly observe the same identity for cross-origin Window and Location"); @@ -312,6 +365,11 @@ checkFunction(set_href_B, B.Function.prototype); }, "Same-origin observers get different accessors for cross-origin Location"); +addTest(function() { + assert_equals({}.toString.call(C), "[object Object]"); + assert_equals({}.toString.call(C.location), "[object Object]"); +}, "{}.toString.call() does the right thing on cross-origin objects"); + // We do a fresh load of the subframes for each test to minimize side-effects. // It would be nice to reload ourselves as well, but we can't do that without // disrupting the test harness.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/frame.html b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/frame.html index 046e49da..0a7769d 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/frame.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/frame.html
@@ -35,5 +35,8 @@ </script> </head> <body> + <!-- Two subframes to give us some indexed properties --> + <iframe></iframe> + <iframe></iframe> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/win-documentdomain.sub.html b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/win-documentdomain.sub.html index 3bfcd0c..a315e21 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/win-documentdomain.sub.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/win-documentdomain.sub.html
@@ -1,6 +1,7 @@ <!DOCTYPE html> <html> <head> + <script src="/common/get-host-info.sub.js"></script> <script> function loadFrames() { window.A = document.getElementById('A').contentWindow;
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/dom/elements/elements-in-the-dom/historical.html b/third_party/WebKit/LayoutTests/imported/wpt/html/dom/elements/elements-in-the-dom/historical.html new file mode 100644 index 0000000..c18ee31 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/dom/elements/elements-in-the-dom/historical.html
@@ -0,0 +1,24 @@ +<!doctype html> +<title>Historical HTMLElement features</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<body> +<script> +[ + // https://github.com/whatwg/html/commit/389ec2620d89e9480ef8847bf016abdfa92427bc + "commandType", + "commandLabel", + "commandIcon", + "commandHidden", + "commandDisabled", + "commandChecked", + "commandTriggers", + // https://github.com/whatwg/html/commit/5ddfc78b1f82e86cc202d72ccc752a0e15f1e4ad + "inert", +].forEach(function(member) { + test(function() { + assert_false(member in document.body); + assert_false(member in document.createElement('div')); + }, 'HTMLElement member must be nuked: ' + member); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/image.png b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/image.png new file mode 100644 index 0000000..d26878c9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/image.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-src-complete.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-src-complete.html new file mode 100644 index 0000000..267c0082 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-src-complete.html
@@ -0,0 +1,23 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Changing the img src should retain the 'complete' property</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<p id="display"><img src="image.png"></p> +<script> + function check() { + var img = document.querySelector("img"); + assert_true(img.complete, "By onload, image should have loaded"); + img.src = `image.png?${Math.random()}`; + assert_false(img.complete, "Now that we're loading we should no longer be complete"); + img.onload = function () { + assert_true(img.complete, "The new thing should have loaded."); + done(); + } + } + + onload = function () { + check(); + }; + +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-form-element/form-nameditem.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-form-element/form-nameditem.html index 3edf903b..0155d38b 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-form-element/form-nameditem.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-form-element/form-nameditem.html
@@ -327,4 +327,93 @@ assert_equals(form["new-name2"], 5); }, 'Trying to set a non-configurable expando that shadows a named property that gets added later'); +test(function() { + var form = document.getElementsByTagName("form")[1]; + + var i1 = document.createElement("input"); + i1.name = "past-name1"; + i1.id = "past-id1" + + assert_equals(form["past-name1"], undefined); + assert_equals(form["past-id1"], undefined); + form.appendChild(i1); + assert_equals(form["past-name1"], i1); + assert_equals(form["past-id1"], i1); + + i1.name = "twiddled-name1"; + i1.id = "twiddled-id1"; + assert_equals(form["past-name1"], i1); + assert_equals(form["twiddled-name1"], i1); + assert_equals(form["past-id1"], i1); + assert_equals(form["twiddled-id1"], i1); + + i1.name = "twiddled-name2"; + i1.id = "twiddled-id2"; + assert_equals(form["past-name1"], i1); + assert_equals(form["twiddled-name1"], i1); + assert_equals(form["twiddled-name2"], i1); + assert_equals(form["past-id1"], i1); + assert_equals(form["twiddled-id1"], i1); + assert_equals(form["twiddled-id2"], i1); + + i1.removeAttribute("id"); + i1.removeAttribute("name"); + assert_equals(form["past-name1"], i1); + assert_equals(form["twiddled-name1"], i1); + assert_equals(form["twiddled-name2"], i1); + assert_equals(form["past-id1"], i1); + assert_equals(form["twiddled-id1"], i1); + assert_equals(form["twiddled-id2"], i1); + + i1.remove(); + assert_equals(form["past-name1"], undefined); + assert_equals(form["twiddled-name1"], undefined); + assert_equals(form["twiddled-name2"], undefined); + assert_equals(form["past-id1"], undefined); + assert_equals(form["twiddled-id1"], undefined); + assert_equals(form["twiddled-id2"], undefined); + + var i2 = document.createElement("input"); + i2.name = "past-name2"; + i2.id = "past-id2"; + + assert_equals(form["past-name2"], undefined); + assert_equals(form["past-id2"], undefined); + form.appendChild(i2); + assert_equals(form["past-name2"], i2); + assert_equals(form["past-id2"], i2); + + i2.name = "twiddled-name3"; + i2.id = "twiddled-id3"; + assert_equals(form["past-name2"], i2); + assert_equals(form["twiddled-name3"], i2); + assert_equals(form["past-id2"], i2); + assert_equals(form["twiddled-id3"], i2); + + i2.name = "twiddled-name4"; + i2.id = "twiddled-id4"; + assert_equals(form["past-name2"], i2); + assert_equals(form["twiddled-name3"], i2); + assert_equals(form["twiddled-name4"], i2); + assert_equals(form["past-id2"], i2); + assert_equals(form["twiddled-id3"], i2); + assert_equals(form["twiddled-id4"], i2); + + i2.removeAttribute("id"); + i2.removeAttribute("name"); + assert_equals(form["past-name2"], i2); + assert_equals(form["twiddled-name3"], i2); + assert_equals(form["twiddled-name4"], i2); + assert_equals(form["past-id2"], i2); + assert_equals(form["twiddled-id3"], i2); + assert_equals(form["twiddled-id4"], i2); + + i2.setAttribute("form", "c"); + assert_equals(form["past-name2"], undefined); + assert_equals(form["twiddled-name3"], undefined); + assert_equals(form["twiddled-name4"], undefined); + assert_equals(form["past-id2"], undefined); + assert_equals(form["twiddled-id3"], undefined); + assert_equals(form["twiddled-id4"], undefined); +}, "Past names map should work correctly"); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-input-element/clone.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-input-element/clone.html new file mode 100644 index 0000000..0f7e053b --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-input-element/clone.html
@@ -0,0 +1,150 @@ +<!doctype html> +<meta charset=utf-8> +<title>Test input value retention upon clone</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<style>form {display: none;} </style> +<form> +<p><input type=checkbox> This checkbox is initially unchecked.</p> +<p><input type=checkbox checked="checked"> This checkbox is initially checked.</p> +<p><input type=radio name=radio> This radiobutton is initially unchecked.</p> +<p><input type=radio checked="checked" name=radio> This radiobutton is initially checked.</p> +<p><input type=hidden value="DEFAULT +DEFAULT"> This hidden field has the initial value "DEFAULT\nDEFAULT".</p> +<p><input type=text value=DEFAULT> This text field has the initial value "DEFAULT".</p> +<p><input type=search value=DEFAULT> This search field has the initial value "DEFAULT".</p> +<p><input type=tel value=DEFAULT> This phone number field has the initial value "DEFAULT".</p> +<p><input type=url value=https://default.invalid/> This URL field has the initial value "https://default.invalid/".</p> +<p><input type=email value=default@default.invalid> This email field has the initial value "default@default.invalid".</p> +<p><input type=password value=DEFAULT> This password field has the initial value "DEFAULT".</p> +<p><input type=date value=2015-01-01> This date field has the initial value "2015-01-01".</p> +<p><input type=month value=2015-01> This month field has the initial value "2015-01".</p> +<p><input type=week value=2015-W01> This week field has the initial value "2015-W01".</p> +<p><input type=time value=12:00> This time field has the initial value "12:00".</p> +<p><input type=datetime-local value=2015-01-01T12:00> This datetime (local) field has the initial value "2015-01-01T12:00".</p> +<p><input type=number value=1> This number field has the initial value "1".</p> +<p><input type=range value=1> This range control has the initial value "1".</p> +<p><input type=color value=#ff0000> This color picker has the initial value "#FF0000".</p> +<p><input type="button" value="Clone" onclick="clone();"></p> +</form> +<script> +setup(function() { + let form = document.getElementsByTagName("form")[0]; + let inputs = form.getElementsByTagName("input"); + inputs[0].checked = true; + inputs[1].checked = false; + inputs[2].checked = true; + inputs[4].value = "CHANGED\nCHANGED"; + inputs[5].value = "CHANGED"; + inputs[6].value = "CHANGED"; + inputs[7].value = "CHANGED"; + inputs[8].value = "https://changed.invalid/"; + inputs[9].value = "changed@changed.invalid"; + inputs[10].value = "CHANGED"; + inputs[11].value = "2016-01-01"; + inputs[12].value = "2016-01"; + inputs[13].value = "2016-W01"; + inputs[14].value = "12:30"; + inputs[15].value = "2016-01-01T12:30"; + inputs[16].value = "2"; + inputs[17].value = "2"; + inputs[18].value = "#00ff00"; + let clone = form.cloneNode(true); + document.body.appendChild(clone); +}); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_true(inputs[0].checked, "Should have retained checked state"); +}, "Checkbox must retain checked state."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_false(inputs[1].checked, "Should have retained unchecked state"); +}, "Checkbox must retain unchecked state."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_true(inputs[2].checked, "Should have retained checked state"); +}, "Radiobutton must retain checked state."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_false(inputs[3].checked, "Should have retained unchecked state"); +}, "Radiobutton must retain unchecked state."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[4].value, "CHANGED\nCHANGED", "Should have retained the changed value."); +}, "Hidden field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[5].value, "CHANGED", "Should have retained the changed value."); +}, "Text field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[6].value, "CHANGED", "Should have retained the changed value."); +}, "Search field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[7].value, "CHANGED", "Should have retained the changed value."); +}, "Phone number field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[8].value, "https://changed.invalid/", "Should have retained the changed value."); +}, "URL field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[9].value, "changed@changed.invalid", "Should have retained the changed value."); +}, "Email field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[10].value, "CHANGED", "Should have retained the changed value."); +}, "Password field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[11].value, "2016-01-01", "Should have retained the changed value."); +}, "Date field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[12].value, "2016-01", "Should have retained the changed value."); +}, "Month field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[13].value, "2016-W01", "Should have retained the changed value."); +}, "Week field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[14].value, "12:30", "Should have retained the changed value."); +}, "Time field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[15].value, "2016-01-01T12:30", "Should have retained the changed value."); +}, "Datetime (local) field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[16].value, "2", "Should have retained the changed value."); +}, "Number field must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[17].value, "2", "Should have retained the changed value."); +}, "Range control must retain changed value."); +test(function() { + let clone = document.getElementsByTagName("form")[1]; + let inputs = clone.getElementsByTagName("input"); + assert_equals(inputs[18].value, "#00ff00", "Should have retained the changed value."); +}, "Color picker must retain changed value."); +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-select-element/select-validity.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-select-element/select-validity.html new file mode 100644 index 0000000..73f41df --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/forms/the-select-element/select-validity.html
@@ -0,0 +1,95 @@ +<!doctype html> +<meta charset=utf-8> +<title>HTMLSelectElement.checkValidity</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#the-select-element:attr-select-required-4"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> + +test(function() { + var select = document.createElement('select'); + assert_true(select.willValidate, "A select element is a submittable element that is a candidate for constraint validation."); + var placeholder = document.createElement('option'); + select.appendChild(placeholder); + assert_true(select.checkValidity(), "Always valid when the select isn't a required value."); + select.required = true; + assert_true(placeholder.selected, "If display size is 1, multiple is absent and no options have selectedness true, the first option is selected."); + assert_equals(select.value, "", "The placeholder's value should be the select's value right now"); + assert_false(select.checkValidity(), "A selected placeholder option should invalidate the select."); + var emptyOption = document.createElement('option'); + select.appendChild(emptyOption); + emptyOption.selected = true; + assert_equals(select.value, "", "The empty value should be set."); + assert_true(select.checkValidity(), "An empty non-placeholder option should be a valid choice."); + var filledOption = document.createElement('option'); + filledOption.value = "test"; + select.appendChild(filledOption); + filledOption.selected = true; + assert_equals(select.value, "test", "The non-empty value should be set."); + assert_true(select.checkValidity(), "A non-empty non-placeholder option should be a valid choice."); + select.removeChild(placeholder); + select.appendChild(emptyOption); // move emptyOption to second place + emptyOption.selected = true; + assert_equals(select.value, "", "The empty value should be set."); + assert_true(select.checkValidity(), "Only the first option can be seen as a placeholder."); + placeholder.disabled = true; + select.insertBefore(placeholder, filledOption); + placeholder.selected = true; + assert_equals(select.value, "", "A disabled first placeholder option should result in an empty value."); + assert_false(select.checkValidity(), "A disabled first placeholder option should invalidate the select."); +}, "Placeholder label options within a select"); + +test(function() { + var select = document.createElement('select'); + select.required = true; + var optgroup = document.createElement('optgroup'); + var emptyOption = document.createElement('option'); + optgroup.appendChild(emptyOption); + select.appendChild(optgroup); + emptyOption.selected = true; + assert_equals(select.value, "", "The empty value should be set."); + assert_true(select.checkValidity(), "The first option is not considered a placeholder if it is located within an optgroup."); + var otherEmptyOption = document.createElement('option'); + otherEmptyOption.value = ""; + select.appendChild(otherEmptyOption); + otherEmptyOption.selected = true; + assert_equals(select.value, "", "The empty value should be set."); + assert_true(select.checkValidity(), "The empty option should be accepted as it is not the first option in the tree ordered list."); +}, "Placeholder label-like options within optgroup"); + +test(function() { + var select = document.createElement('select'); + select.required = true; + select.size = 2; + var emptyOption = document.createElement('option'); + select.appendChild(emptyOption); + assert_false(emptyOption.selected, "Display size is not 1, so the first option should not be selected."); + assert_false(select.checkValidity(), "If no options are selected the select must be seen as invalid."); + emptyOption.selected = true; + assert_true(select.checkValidity(), "If one option is selected, the select should be considered valid."); + var otherEmptyOption = document.createElement('option'); + otherEmptyOption.value = ""; + select.appendChild(otherEmptyOption); + otherEmptyOption.selected = true; + assert_false(emptyOption.selected, "Whenever an option has its selectiveness set to true, the other options must be set to false."); + otherEmptyOption.selected = false; + assert_false(otherEmptyOption.selected, "It should be possible to set the selectiveness to false with a display size more than one."); + assert_false(select.checkValidity(), "If no options are selected the select must be seen as invalid."); +}, "Validation on selects with display size set as more than one"); + +test(function() { + var select = document.createElement('select'); + select.required = true; + select.multiple = true; + var emptyOption = document.createElement('option'); + select.appendChild(emptyOption); + assert_false(select.checkValidity(), "If no options are selected the select must be seen as invalid."); + emptyOption.selected = true; + assert_true(select.checkValidity(), "If one option is selected, the select should be considered valid."); + var optgroup = document.createElement('optgroup'); + optgroup.appendChild(emptyOption); // Move option to optgroup + select.appendChild(optgroup); + assert_true(select.checkValidity(), "If one option within an optgroup or not is selected, the select should be considered valid."); +}, "Validation on selects with multiple set"); +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html index 6ca9189..30b30e1 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html
@@ -55,11 +55,9 @@ test(function(){ assert_false(d1.open); - assert_false(b0.commandDisabled); d1.showModal(); this.add_cleanup(function() { d1.close(); }); assert_true(d1.open); - assert_true(b0.commandDisabled); assert_equals(document.activeElement, b1); }); @@ -80,11 +78,8 @@ test(function(){ assert_false(d3.open); - assert_false(b3.commandDisabled); assert_false(d4.open); - assert_false(b4.commandDisabled); assert_false(d5.open); - assert_false(b5.commandDisabled); d3.showModal(); this.add_cleanup(function() { d3.close(); }); d4.showModal(); @@ -92,11 +87,8 @@ d5.showModal(); this.add_cleanup(function() { d5.close(); }); assert_true(d3.open); - assert_true(b3.commandDisabled); assert_true(d4.open); - assert_true(b4.commandDisabled); assert_true(d5.open); - assert_false(b5.commandDisabled); }, "when opening multiple dialogs, only the newest one is non-inert"); test(function(){
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-add.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-add.js index c41c7bc..237ba47 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-add.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-add.js
@@ -84,6 +84,26 @@ }, 'Cache.add with request with null body (not consumed)'); cache_test(function(cache, test) { + return assert_promise_rejects( + test, + new TypeError(), + cache.add('../resources/fetch-status.py?status=206'), + 'Cache.add should reject on partial response'); + }, 'Cache.add with 206 response'); + +cache_test(function(cache, test) { + var urls = ['../resources/fetch-status.py?status=206', + '../resources/fetch-status.py?status=200']; + var requests = urls.map(function(url) { + return new Request(url); + }); + return promise_rejects( + new TypeError(), + cache.addAll(requests), + 'Cache.addAll should reject with TypeError if any request fails'); + }, 'Cache.addAll with 206 response'); + +cache_test(function(cache, test) { return promise_rejects( test, new TypeError(), @@ -91,6 +111,7 @@ 'Cache.add should reject if response is !ok'); }, 'Cache.add with request that results in a status of 404'); + cache_test(function(cache, test) { return promise_rejects( test,
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-delete.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-delete.js index 446818c..bf7841a 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-delete.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-delete.js
@@ -56,6 +56,25 @@ }, 'Cache.delete called with a Request object'); cache_test(function(cache) { + var request = new Request(test_url); + var response = new_test_response(); + return cache.put(request, response) + .then(function() { + return cache.delete(new Request(test_url, {method: 'HEAD'})); + }) + .then(function(result) { + assert_false(result, + 'Cache.delete should not match a non-GET request ' + + 'unless ignoreMethod option is set.'); + return cache.match(test_url); + }) + .then(function(result) { + assert_response_equals(result, response, + 'Cache.delete should leave non-matching response in the cache.'); + }); + }, 'Cache.delete called with a HEAD request'); + +cache_test(function(cache) { return cache.delete(test_url) .then(function(result) { assert_false(result,
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-match.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-match.js index fbe564d..32c9ec9 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-match.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-match.js
@@ -36,6 +36,14 @@ }, 'Cache.match with new Request'); prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.match(new Request(entries.a.request.url, {method: 'HEAD'})) + .then(function(result) { + assert_equals(result, undefined, + 'Cache.match should not match HEAD Request.'); + }); + }, 'Cache.match with HEAD'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.match(entries.a.request, {ignoreSearch: true}) .then(function(result) { @@ -189,4 +197,28 @@ }); }, 'Cache.match with a network error Response'); +cache_test(function(cache) { + // This test validates that we can get a Response from the Cache API, + // clone it, and read just one side of the clone. This was previously + // bugged in FF for Responses with large bodies. + var data = []; + data.length = 80 * 1024; + data.fill('F'); + var response; + return cache.put('/', new Response(data.toString())) + .then(function(result) { + return cache.match('/'); + }) + .then(function(r) { + // Make sure the original response is not GC'd. + response = r; + // Return only the clone. We purposefully test that the other + // half of the clone does not need to be read here. + return response.clone().text(); + }) + .then(function(text) { + assert_equals(text, data.toString(), 'cloned body text can be read correctly'); + }) + }, 'Cache produces large Responses that can be cloned and read correctly.'); + done();
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-matchAll.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-matchAll.js index 5de9a5e..feace5a9 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-matchAll.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-matchAll.js
@@ -39,6 +39,16 @@ }, 'Cache.matchAll with new Request'); prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.matchAll(new Request(entries.a.request.url, {method: 'HEAD'}), + {ignoreSearch: true}) + .then(function(result) { + assert_response_array_equals( + result, [], + 'Cache.matchAll should not match HEAD Request.'); + }); + }, 'Cache.matchAll with HEAD'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.matchAll(entries.a.request, {ignoreSearch: true}) .then(function(result) {
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-put.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-put.js index 71a0e4d9..9e9fd67a 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-put.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-put.js
@@ -103,6 +103,19 @@ }, 'Cache.put with an empty response body'); cache_test(function(cache) { + var request = new Request(test_url); + var response = new Response('', { + status: 206, + headers: [['Content-Type', 'text/plain']] + }); + + return assert_promise_rejects( + cache.put(request, response), + new TypeError(), + 'Cache.put should reject 206 Responses with a TypeError.'); + }, 'Cache.put with 206 response'); + +cache_test(function(cache) { var test_url = new URL('../resources/fetch-status.py?status=500', location.href).href; var request = new Request(test_url); var response; @@ -290,4 +303,22 @@ 'TypeError.'); }, 'Cache.put with an embedded VARY:* Response'); +cache_test(function(cache) { + var url = 'foo.html'; + var redirectURL = 'http://example.com/foo-bar.html'; + var redirectResponse = Response.redirect(redirectURL); + assert_equals(redirectResponse.headers.get('Location'), redirectURL, + 'Response.redirect() should set Location header.'); + return cache.put(url, redirectResponse.clone()) + .then(function() { + return cache.match(url); + }) + .then(function(response) { + assert_response_equals(response, redirectResponse, + 'Redirect response is reproduced by the Cache API'); + assert_equals(response.headers.get('Location'), redirectURL, + 'Location header is preserved by Cache API.'); + }); + }, 'Cache.put should store Response.redirect() correctly'); + done();
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-storage-match.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-storage-match.js index 3c1cdd7..21517b1e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-storage-match.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/cache-storage/script-tests/cache-storage-match.js
@@ -93,6 +93,19 @@ }); }, 'CacheStorageMatch a string request'); +cache_test(function(cache) { + var transaction = create_unique_transaction(); + return cache.put(transaction.request.clone(), transaction.response.clone()) + .then(function() { + return self.caches.match(new Request(transaction.request.url, + {method: 'HEAD'})); + }) + .then(function(response) { + assert_equals(response, undefined, + 'A HEAD request should not be matched'); + }); +}, 'CacheStorageMatch a HEAD request'); + promise_test(function(test) { var transaction = create_unique_transaction(); return self.caches.match(transaction.request) @@ -117,7 +130,7 @@ }) .then(function(has_foo) { assert_false(has_foo, "The cache should still not exist."); - }) + }); }, 'CacheStorageMatch with no caches available but name provided'); done();
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/extendable-event-async-waituntil.https.html b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/extendable-event-async-waituntil.https.html index c06bf84..783a712e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/extendable-event-async-waituntil.https.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/extendable-event-async-waituntil.https.html
@@ -4,27 +4,79 @@ <script src="/resources/testharnessreport.js"></script> <script src="resources/test-helpers.sub.js"></script> <script> -promise_test(function(t) { - var script = 'resources/extendable-event-async-waituntil.js'; - var scope = 'resources/async-waituntil'; - var worker; - return service_worker_unregister_and_register(t, script, scope) - .then(function(registration) { - worker = registration.installing; - return wait_for_state(t, worker, 'activated'); - }) - .then(function() { - var channel = new MessageChannel(); - var saw_message = new Promise(function(resolve) { - channel.port1.onmessage = function(e) { resolve(e.data); } - }); - worker.postMessage({port: channel.port2}, [channel.port2]); - return saw_message; - }) - .then(function(message) { - assert_equals(message, 'PASS'); - return service_worker_unregister_and_done(t, scope); - }) - }, 'Calling waitUntil asynchronously throws an exception'); +function sync_message(worker, message, transfer) { + let wait = new Promise((res, rej) => { + navigator.serviceWorker.addEventListener('message', function(e) { + if (e.data === 'ACK') { + res(); + } else { + rej(); + } + }); + }); + worker.postMessage(message, transfer); + return wait; +} + +function runTest(test, step, testBody) { + var scope = './resources/' + step; + var script = 'resources/extendable-event-async-waituntil.js?' + scope; + service_worker_unregister_and_register(test, script, scope) + .then(function(registration) { + let worker = registration.installing; + var channel = new MessageChannel(); + var saw_message = new Promise(function(resolve) { + channel.port1.onmessage = function(e) { resolve(e.data); } + }); + + wait_for_state(test, worker, 'activated') + .then(function() { + return sync_message(worker, { step: 'init', port: channel.port2 }, + [channel.port2]); + }) + .then(function() { return testBody(worker); }) + .then(function() { return saw_message; }) + .then(function(output) { + assert_equals(output.result, output.expected); + }) + .then(function() { return sync_message(worker, { step: 'done' }); }) + .then(() => { service_worker_unregister_and_done(test, scope); }) + .catch(unreached_rejection(test)); + }); +} + +function msg_event_test(scope, test) { + var testBody = function(worker) { + return sync_message(worker, { step: scope }); + }; + runTest(test, scope, testBody); +} + +async_test(msg_event_test.bind(this, 'no-current-extension-different-task'), + 'Test calling waitUntil in a different task without an existing extension throws'); + +async_test(msg_event_test.bind(this, 'no-current-extension-different-microtask'), + 'Test calling waitUntil in a different microtask without an existing extension throws'); + +async_test(msg_event_test.bind(this, 'current-extension-different-task'), + 'Test calling waitUntil in a different task with an existing extension succeeds'); + +async_test(msg_event_test.bind(this, 'current-extension-expired-same-microtask-turn'), + 'Test calling waitUntil with an existing extension promise handler succeeds'); + +// The promise handler will queue a new microtask after the check for new +// extensions was performed. +async_test(msg_event_test.bind(this, 'current-extension-expired-same-microtask-turn-extra'), + 'Test calling waitUntil at the end of the microtask turn throws'); + +async_test(msg_event_test.bind(this, 'current-extension-expired-different-task'), + 'Test calling waitUntil after the current extension expired in a different task fails'); + +async_test(function(t) { + var testBody = function(worker) { + return with_iframe('./resources/pending-respondwith-async-waituntil/dummy.html'); + } + runTest(t, 'pending-respondwith-async-waituntil', testBody); + }, 'Test calling waitUntil asynchronously with pending respondWith promise.'); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/extendable-event-waituntil.https.html b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/extendable-event-waituntil.https.html index 003e703b..b2029ae 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/extendable-event-waituntil.https.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/extendable-event-waituntil.https.html
@@ -68,11 +68,13 @@ async_test(function(t) { var scope = 'resources/install-reject-precedence'; var onRegister = function(worker) { + var obj = {}; wait_for_state(t, worker, 'redundant') .then(function() { service_worker_unregister_and_done(t, scope); }) .catch(unreached_rejection(t)); + syncWorker(t, worker, obj); }; runTest(t, scope, onRegister); }, 'Test ExtendableEvent waitUntil reject precedence.');
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/fetch-event.https.html b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/fetch-event.https.html index a9b0d6ca..6f8618b 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/fetch-event.https.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/fetch-event.https.html
@@ -88,7 +88,7 @@ .then(function(response_text) { assert_equals( response_text, - 'Referrer: about:client\n' + + 'Referrer: \n' + 'ReferrerPolicy: no-referrer-when-downgrade', 'Service Worker should respond to fetch with no referrer when a member of RequestInit is present with an HTTP request'); return frame.contentWindow.fetch('resources/simple.html?referrerFull', @@ -110,7 +110,7 @@ .then(function(response_text) { assert_equals( response_text, - 'Referrer: about:client\n' + + 'Referrer: \n' + 'ReferrerPolicy: no-referrer-when-downgrade', 'Service Worker should respond to fetch with no referrer with ""'); return frame.contentWindow.fetch('resources/simple.html?referrerFull', @@ -176,7 +176,7 @@ .then(function(response_text) { assert_equals( response_text, - 'Referrer: about:client\n' + + 'Referrer: \n' + 'ReferrerPolicy: no-referrer-when-downgrade', 'Service Worker should respond to fetch with no referrer with "no-referrer-when-downgrade" and an HTTP request'); var http_url = get_host_info()['HTTP_ORIGIN'] + base_path() + @@ -197,9 +197,99 @@ .then(function(response_text) { assert_equals( response_text, - 'Referrer: about:client\n' + + 'Referrer: \n' + 'ReferrerPolicy: no-referrer', 'Service Worker should respond to fetch with no referrer URL with "no-referrer"'); + return frame.contentWindow.fetch('resources/simple.html?referrerFull', + {referrerPolicy: "same-origin", referrer: referrer}); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + assert_equals( + response_text, + 'Referrer: ' + href + '\n' + + 'ReferrerPolicy: same-origin', + 'Service Worker should respond to fetch with referrer URL with "same-origin" and a same origin request'); + var http_url = get_host_info()['HTTPS_REMOTE_ORIGIN'] + base_path() + + '/resources/simple.html?referrerFull'; + return frame.contentWindow.fetch(http_url, + {referrerPolicy: "same-origin", referrer: referrer}); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + assert_equals( + response_text, + 'Referrer: \n' + + 'ReferrerPolicy: same-origin', + 'Service Worker should respond to fetch with no referrer with "same-origin" and cross origin request'); + var http_url = get_host_info()['HTTPS_REMOTE_ORIGIN'] + base_path() + + '/resources/simple.html?referrerFull'; + return frame.contentWindow.fetch(http_url, + {referrerPolicy: "strict-origin", referrer: referrer}); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + assert_equals( + response_text, + 'Referrer: ' + origin + '/' + '\n' + + 'ReferrerPolicy: strict-origin', + 'Service Worker should respond to fetch with the referrer origin with "strict-origin" and a HTTPS cross origin request'); + return frame.contentWindow.fetch('resources/simple.html?referrerFull', + {referrerPolicy: "strict-origin", referrer: referrer}); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + assert_equals( + response_text, + 'Referrer: ' + origin + '/' + '\n' + + 'ReferrerPolicy: strict-origin', + 'Service Worker should respond to fetch with the referrer origin with "strict-origin" and a same origin request'); + var http_url = get_host_info()['HTTP_ORIGIN'] + base_path() + + '/resources/simple.html?referrerFull'; + return frame.contentWindow.fetch(http_url, + {referrerPolicy: "strict-origin", referrer: referrer}); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + assert_equals( + response_text, + 'Referrer: \n' + + 'ReferrerPolicy: strict-origin', + 'Service Worker should respond to fetch with no referrer with "strict-origin" and a HTTP request'); + return frame.contentWindow.fetch('resources/simple.html?referrerFull', + {referrerPolicy: "strict-origin-when-cross-origin", referrer: referrer}); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + assert_equals( + response_text, + 'Referrer: ' + href + '\n' + + 'ReferrerPolicy: strict-origin-when-cross-origin', + 'Service Worker should respond to fetch with the referrer URL with "strict-origin-when-cross-origin" and a same origin request'); + var http_url = get_host_info()['HTTPS_REMOTE_ORIGIN'] + base_path() + + '/resources/simple.html?referrerFull'; + return frame.contentWindow.fetch(http_url, + {referrerPolicy: "strict-origin-when-cross-origin", referrer: referrer}); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + assert_equals( + response_text, + 'Referrer: ' + origin + '/' + '\n' + + 'ReferrerPolicy: strict-origin-when-cross-origin', + 'Service Worker should respond to fetch with the referrer origin with "strict-origin-when-cross-origin" and a HTTPS cross origin request'); + var http_url = get_host_info()['HTTP_ORIGIN'] + base_path() + + '/resources/simple.html?referrerFull'; + return frame.contentWindow.fetch(http_url, + {referrerPolicy: "strict-origin-when-cross-origin", referrer: referrer}); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + assert_equals( + response_text, + 'Referrer: \n' + + 'ReferrerPolicy: strict-origin-when-cross-origin', + 'Service Worker should respond to fetch with no referrer with "strict-origin-when-cross-origin" and a HTTP request'); }); } @@ -419,14 +509,13 @@ .then(function(frame) { assert_equals( frame.contentDocument.body.textContent, - 'Fragment Not Found', - 'Service worker should not expose URL fragments.'); + 'Fragment Found :' + fragment, + 'Service worker should expose URL fragments in request.'); frame.remove(); return service_worker_unregister_and_done(t, scope); }) .catch(unreached_rejection(t)); }, 'Service Worker must not expose FetchEvent URL fragments.'); - async_test(function(t) { var scope = 'resources/simple.html?cache'; var frame;
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/oninstall-script-error.https.html b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/oninstall-script-error.https.html index a9ca19ca..fe7f6e9 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/oninstall-script-error.https.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/oninstall-script-error.https.html
@@ -33,18 +33,23 @@ { name: 'install handler throws an error', script: 'resources/oninstall-throw-error-worker.js', - expect_install: false + expect_install: true }, { name: 'install handler throws an error, error handler does not cancel', script: 'resources/oninstall-throw-error-with-empty-onerror-worker.js', - expect_install: false + expect_install: true }, { name: 'install handler dispatches an event that throws an error', script: 'resources/oninstall-throw-error-from-nested-event-worker.js', expect_install: true }, + { + name: 'install handler throws an error in the waitUntil', + script: 'resources/oninstall-waituntil-throw-error-worker.js', + expect_install: false + }, // The following two cases test what happens when the ServiceWorkerGlobalScope // 'error' event handler cancels the resulting error event. Since the @@ -54,12 +59,12 @@ { name: 'install handler throws an error that is cancelled', script: 'resources/oninstall-throw-error-then-cancel-worker.js', - expect_install: false + expect_install: true }, { name: 'install handler throws an error and prevents default', script: 'resources/oninstall-throw-error-then-prevent-default-worker.js', - expect_install: false + expect_install: true } ].forEach(function(test_case) { make_test(test_case.name, test_case.script, test_case.expect_install);
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/performance-timeline.https.html b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/performance-timeline.https.html index 182076b..d2ed677 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/performance-timeline.https.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/performance-timeline.https.html
@@ -8,4 +8,45 @@ 'resources/performance-timeline-worker.js', 'Test Performance Timeline API in Service Worker'); +// The purpose of this test is to verify that service worker overhead +// is included in the Performance API's timing information. +promise_test(t => { + let script = 'resources/empty-but-slow-worker.js'; + let scope = 'resources/dummy.txt?slow-sw-timing'; + let url = new URL(scope, window.location).href; + let slowURL = url + '&slow'; + let frame; + return service_worker_unregister_and_register(t, script, scope) + .then(reg => wait_for_state(t, reg.installing, 'activated')) + .then(_ => with_iframe(scope)) + .then(f => { + frame = f; + return Promise.all([ + // This will get effectively an empty service worker FetchEvent + // handler. It should have no additional delay. Note that the + // text() call is necessary to complete the response and have the + // timings show up in the performance entries. + frame.contentWindow.fetch(url).then(r => r && r.text()), + // This will cause the service worker to spin for two seconds + // in its FetchEvent handler. + frame.contentWindow.fetch(slowURL).then(r => r && r.text()) + ]); + }) + .then(_ => { + function elapsed(u) { + let entry = frame.contentWindow.performance.getEntriesByName(u); + return entry[0] ? entry[0].duration : undefined; + } + let urlTime = elapsed(url); + let slowURLTime = elapsed(slowURL); + // Verify the request slowed by the service worker is indeed measured + // to be slower. Note, we compare to smaller delay instead of the exact + // delay amount to avoid making the test racy under automation. + assert_true(slowURLTime >= urlTime + 1500, + 'Slow service worker request should measure increased delay.'); + frame.remove(); + return service_worker_unregister_and_done(t, scope); + }) +}, 'empty service worker fetch event included in performance timings'); + </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/empty-but-slow-worker.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/empty-but-slow-worker.js new file mode 100644 index 0000000..92abac7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/empty-but-slow-worker.js
@@ -0,0 +1,8 @@ +addEventListener('fetch', evt => { + if (evt.request.url.endsWith('slow')) { + // Performance.now() might be a bit better here, but Date.now() has + // better compat in workers right now. + let start = Date.now(); + while(Date.now() - start < 2000); + } +});
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/extendable-event-async-waituntil.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/extendable-event-async-waituntil.js index d77238d9..21b4e28 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/extendable-event-async-waituntil.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/extendable-event-async-waituntil.js
@@ -1,20 +1,100 @@ -var result = 'FAIL: did not throw.'; +// controlled by 'init'/'done' messages. +var resolveLockPromise; +var port; self.addEventListener('message', function(event) { - event.data.port.postMessage(result); - }); + var waitPromise; + var resolveTestPromise; -self.addEventListener('install', function(event) { - self.installEvent = event; - }); - -self.addEventListener('activate', function(event) { - try { - self.installEvent.waitUntil(new Promise(function(){})); - } catch (error) { - if (error.name == 'InvalidStateError') - result = 'PASS'; - else - result = 'FAIL: unexpected exception: ' + error; + switch (event.data.step) { + case 'init': + event.waitUntil(new Promise((res) => { resolveLockPromise = res; })); + port = event.data.port; + break; + case 'done': + resolveLockPromise(); + break; + case 'no-current-extension-different-task': + async_task_waituntil(event).then(reportResultExpecting('InvalidStateError')); + break; + case 'no-current-extension-different-microtask': + async_microtask_waituntil(event).then(reportResultExpecting('InvalidStateError')); + break; + case 'current-extension-different-task': + event.waitUntil(new Promise((res) => { resolveTestPromise = res; })); + async_task_waituntil(event).then(reportResultExpecting('OK')).then(resolveTestPromise); + break; + case 'current-extension-expired-same-microtask-turn': + waitPromise = Promise.resolve(); + event.waitUntil(waitPromise); + waitPromise.then(() => { return sync_waituntil(event); }) + .then(reportResultExpecting('OK')) + break; + case 'current-extension-expired-same-microtask-turn-extra': + // The promise handler queues a new microtask *after* the check for new + // extensions was performed. + waitPromise = Promise.resolve(); + event.waitUntil(waitPromise); + waitPromise.then(() => { return async_microtask_waituntil(event); }) + .then(reportResultExpecting('InvalidStateError')) + break; + case 'current-extension-expired-different-task': + event.waitUntil(Promise.resolve()); + async_task_waituntil(event).then(reportResultExpecting('InvalidStateError')); + break; } + event.source.postMessage('ACK'); }); + +self.addEventListener('fetch', function(event) { + var resolveFetch; + let response = new Promise((res) => { resolveFetch = res; }); + event.respondWith(response); + async_task_waituntil(event) + .then(reportResultExpecting('OK')) + .then(() => { resolveFetch(new Response('OK')); }); + }); + +function reportResultExpecting(expectedResult) { + return function (result) { + port.postMessage({result : result, expected: expectedResult}); + return result; + }; +} + +function sync_waituntil(event) { + return new Promise((res, rej) => { + try { + event.waitUntil(Promise.resolve()); + res('OK'); + } catch (error) { + res(error.name); + } + }); +} + +function async_microtask_waituntil(event) { + return new Promise((res, rej) => { + Promise.resolve().then(() => { + try { + event.waitUntil(Promise.resolve()); + res('OK'); + } catch (error) { + res(error.name); + } + }); + }); +} + +function async_task_waituntil(event) { + return new Promise((res, rej) => { + setTimeout(() => { + try { + event.waitUntil(Promise.resolve()); + res('OK'); + } catch (error) { + res(error.name); + } + }, 0); + }); +}
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-cors-xhr-iframe.html b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-cors-xhr-iframe.html index 48f61839..121c5c34 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-cors-xhr-iframe.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-cors-xhr-iframe.html
@@ -66,8 +66,8 @@ [remote_url + '?reject', false, FAIL], [remote_url + '?reject', true, FAIL], // Event handler exception tests - [url + '?throw', false, FAIL], - [url + '?throw', true, FAIL], + [url + '?throw', false, SUCCESS], + [url + '?throw', true, SUCCESS], [remote_url + '?throw', false, FAIL], [remote_url + '?throw', true, FAIL], // Reject(resolve-null) tests
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-network-error-controllee-iframe.html b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-network-error-controllee-iframe.html index a4c9307e..e28f623 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-network-error-controllee-iframe.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-network-error-controllee-iframe.html
@@ -40,7 +40,8 @@ { name: 'unused-body', expect_load: true }, { name: 'used-body', expect_load: false }, { name: 'unused-fetched-body', expect_load: true }, - { name: 'used-fetched-body', expect_load: false } + { name: 'used-fetched-body', expect_load: false }, + { name: 'throw-exception', expect_load: true }, ].map(make_test); Promise.all(tests)
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-network-error-worker.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-network-error-worker.js index 52d4c8e..5bfe3a0b 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-network-error-worker.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-network-error-worker.js
@@ -32,6 +32,9 @@ return res; })); break; + case '?throw-exception': + throw('boom'); + break; } });
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-test-worker.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-test-worker.js index 32a1b4f2..55ba4ab 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-test-worker.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-event-test-worker.js
@@ -80,21 +80,19 @@ 'bodyUsed: ' + lastResponseForUsedCheck.bodyUsed)); } } - function handleFragmentCheck(event) { var body; if (event.request.url.indexOf('#') === -1) { body = 'Fragment Not Found'; } else { - body = 'Fragment Found'; + body = 'Fragment Found :' + + event.request.url.substring(event.request.url.indexOf('#')); } event.respondWith(new Response(body)); } - function handleCache(event) { event.respondWith(new Response(event.request.cache)); } - function handleEventSource(event) { if (event.request.mode === 'navigate') { return;
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-rewrite-worker.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-rewrite-worker.js index 4a7646e..9806f2b 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-rewrite-worker.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/fetch-rewrite-worker.js
@@ -76,6 +76,7 @@ } else { event.respondWith(new Response('NO_ACCEPT')); } + return; } event.respondWith(new Promise(function(resolve, reject) { var request = event.request;
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/oninstall-waituntil-throw-error-worker.js b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/oninstall-waituntil-throw-error-worker.js new file mode 100644 index 0000000..6cb8f6e --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/service-workers/service-worker/resources/oninstall-waituntil-throw-error-worker.js
@@ -0,0 +1,5 @@ +self.addEventListener('install', function(event) { + event.waitUntil(new Promise(function(aRequest, aResponse) { + throw new Error(); + })); +});
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/uievents/order-of-events/focus-events/focus-automated-blink-webkit.html b/third_party/WebKit/LayoutTests/imported/wpt/uievents/order-of-events/focus-events/focus-automated-blink-webkit.html new file mode 100644 index 0000000..41de454 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/uievents/order-of-events/focus-events/focus-automated-blink-webkit.html
@@ -0,0 +1,159 @@ +<!DOCTYPE html> +<!-- Modified from Chris Rebert's manual version --> +<!-- This documents the behavior according to blink's implementation --> +<html> + <head> + <meta charset="utf-8"> + <title>Focus-related events should fire in the correct order</title> + <link rel="help" href="https://w3c.github.io/uievents/#events-focusevent-event-order"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body id="body"> + <input type="text" id="a" value="First"> + <input type="text" id="b" value="Second"> + <br> + <input type="text" id="c" value="Third"> + <iframe id="iframe"> + </iframe> + <br> + <script> + + var test_id = 0; + var tests = ['normal', 'iframe'] + + function record(evt) { + if (done && (evt.type == 'focusin' || evt.type == 'focus') && (evt.target == c)) { + startNext(); + } + if (!done) { + var activeElement = document.activeElement ? + (document.activeElement.tagName === 'IFRAME' ? + document.activeElement.contentDocument.activeElement.id : + document.activeElement.id) : null; + events[tests[test_id]].push(evt.type); + targets[tests[test_id]].push(evt.target.id); + focusedElements[tests[test_id]].push(activeElement); + relatedTargets[tests[test_id]].push(evt.relatedTarget ? evt.relatedTarget.id : null); + } + } + function startNext() { + done = false; + test_id++; + } + function finish() { + done = true; + } + var relevantEvents = [ + 'focus', + 'blur', + 'focusin', + 'focusout' + ]; + + var iframe = document.getElementById('iframe'); + var a = document.getElementById('a'); + var b = document.getElementById('b'); + var c = document.getElementById('c'); + var d = document.createElement('input'); + + d.setAttribute('id', 'd'); + d.setAttribute('type', 'text'); + d.setAttribute('value', 'Fourth'); + + var events = {'normal': [], 'iframe': []}; + var targets = {'normal': [], 'iframe': []}; + var focusedElements = {'normal': [], 'iframe': []}; + var relatedTargets = {'normal': [], 'iframe': []}; + var done = false; + + var async_test_normal = async_test('Focus-related events should fire in the correct order (same DocumentOwner)'); + var async_test_iframe_static = async_test('Focus-related events should fire in the correct order (different DocumentOwner)'); + + window.onload = function(evt) { + + iframe.contentDocument.body.appendChild(d); + + var inputs = [a, b, c, d]; + + for (var i = 0; i < inputs.length; i++) { + for (var k = 0; k < relevantEvents.length; k++) { + inputs[i].addEventListener(relevantEvents[k], record, false); + } + } + + a.addEventListener('focusin', function() { b.focus(); }, false); + b.addEventListener('focusin', function() { + async_test_normal.step( function() { + assert_array_equals( + events['normal'], + ['focus', 'focusin', 'blur', 'focusout', 'focus', 'focusin'], + 'Focus-related events should fire in this order: focusin, focus, focusout, focusin, blur, focus' + ); + + assert_array_equals( + targets['normal'], + [ 'a', 'a', 'a', 'a', 'b', 'b'], + 'Focus-related events should fire at the correct targets' + ); + + assert_array_equals( + relatedTargets['normal'], + [ null, null, 'b', 'b', 'a', 'a'], + 'Focus-related events should reference correct relatedTargets' + ); + + assert_array_equals( + focusedElements['normal'], + [ 'a', 'a', 'body', 'body', 'b', 'b'], + 'Focus-related events should fire at the correct time relative to actual focus changes' + ); + + async_test_normal.done(); + }); + + b.addEventListener('focusout', function() { finish(); c.focus(); }); + b.blur(); + + }, false); + + c.addEventListener('focusin', function() {d.focus();}); + d.addEventListener('focusin', function() { + async_test_iframe_static.step(function() { + assert_array_equals( + events['iframe'], + ['focus', 'focusin', 'blur', 'focusout', 'focus', 'focusin'], + 'Focus-related events should fire in this order: focusin, focus, focusout, focusin, blur, focus' + ); + + assert_array_equals( + targets['iframe'], + [ 'c', 'c', 'c', 'c', 'd', 'd'], + 'Focus-related events should fire at the correct targets' + ); + + assert_array_equals( + relatedTargets['iframe'], + [ null, null, null, null, null, null], + 'Focus-related events should reference correct relatedTargets' + ); + + assert_array_equals( + focusedElements['iframe'], + [ 'c', 'c', 'body', 'body', 'd', 'd'], + 'Focus-related events should fire at the correct time relative to actual focus changes' + ); + + async_test_iframe_static.done(); + }); + + d.addEventListener('focusout', function() { finish();}); + + }, false); + + a.focus(); + } + + </script> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/user-timing/resources/webperftestharness.js b/third_party/WebKit/LayoutTests/imported/wpt/user-timing/resources/webperftestharness.js index 750946d..f1597bbe 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/user-timing/resources/webperftestharness.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/user-timing/resources/webperftestharness.js
@@ -12,7 +12,7 @@ // Helper Functions for NavigationTiming W3C tests // -var performanceNamespace = window.performance; +var performanceNamespace = self.performance; var timingAttributes = [ 'connectEnd', 'connectStart',
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes.html b/third_party/WebKit/LayoutTests/imported/wpt/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes.html new file mode 100644 index 0000000..aea8cb6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>exception test of performance.mark and performance.measure</title> + <meta rel="help" href="http://www.w3.org/TR/user-timing/#extensions-performance-interface"/> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/webperftestharness.js"></script> + </head> + <body> + <script> + setup({explicit_done: true}); + test_namespace(); + + test(function() { + for (var i in timingAttributes) { + assert_throws("SyntaxError", function() { window.performance.mark(timingAttributes[i]); }); + assert_throws("SyntaxError", function() { window.performance.measure(timingAttributes[i]); }); + } + }, "performance.mark and performance.measure should throw if used with timing attribute values"); + + fetch_tests_from_worker(new Worker("test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes.js")); + + done(); + + </script> + <h1>Description</h1> + <p>This test validates exception scenarios of invoking mark() and measure() with timing attributes as value.</p> + <div id="log"></div> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes.js b/third_party/WebKit/LayoutTests/imported/wpt/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes.js new file mode 100644 index 0000000..f015402 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes.js
@@ -0,0 +1,14 @@ +importScripts("/resources/testharness.js"); +importScripts("resources/webperftestharness.js"); + +test(function() { + for (var i in timingAttributes) { + performance.mark(timingAttributes[i]); + performance.clearMarks(timingAttributes[i]); + + performance.measure(timingAttributes[i]); + performance.clearMeasures(timingAttributes[i]); + } +}, "performance.mark and performance.measure should not throw if used with timing attribute values in workers"); + +done();
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/addition-per-property.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/addition-per-property.html new file mode 100644 index 0000000..b6210c6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/addition-per-property.html
@@ -0,0 +1,57 @@ +<!doctype html> +<meta charset=utf-8> +<title>Tests for animation type of addition</title> +<link rel="help" href="https://w3c.github.io/web-animations/#animation-types"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<script src="property-list.js"></script> +<script src="property-types.js"></script> +<style> +html { + font-size: 10px; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +for (var property in gCSSProperties) { + if (!isSupported(property)) { + continue; + } + + var animationTypes = gCSSProperties[property].types; + var setupFunction = gCSSProperties[property].setup; + animationTypes.forEach(function(animationType) { + var typeObject; + var animationTypeString; + if (typeof animationType === 'string') { + typeObject = types[animationType]; + animationTypeString = animationType; + } else if (typeof animationType === 'object' && + animationType.type && typeof animationType.type === 'string') { + typeObject = types[animationType.type]; + animationTypeString = animationType.type; + } + + // First, test that the animation type object has 'testAddition'. + // We use test() function here so that we can continue the remainder tests + // even if this test fails. + test(function(t) { + assert_own_property(typeObject, 'testAddition', animationTypeString + + ' should have testAddition property'); + assert_equals(typeof typeObject.testAddition, 'function', + 'testAddition method should be a function'); + }, animationTypeString + ' has testAddition function'); + + if (typeObject.testAddition && + typeof typeObject.testAddition === 'function') { + typeObject.testAddition(property, + setupFunction, + animationType.options); + } + }); +} +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/interpolation-per-property.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/interpolation-per-property.html new file mode 100644 index 0000000..9062116 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/interpolation-per-property.html
@@ -0,0 +1,57 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Tests for animation type of interpolation</title> +<link rel="help" href="https://w3c.github.io/web-animations/#animation-types"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<script src="property-list.js"></script> +<script src="property-types.js"></script> +<style> +html { + font-size: 10px; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +for (var property in gCSSProperties) { + if (!isSupported(property)) { + continue; + } + + var animationTypes = gCSSProperties[property].types; + var setupFunction = gCSSProperties[property].setup; + animationTypes.forEach(function(animationType) { + var typeObject; + var animationTypeString; + if (typeof animationType === 'string') { + typeObject = types[animationType]; + animationTypeString = animationType; + } else if (typeof animationType === 'object' && + animationType.type && typeof animationType.type === 'string') { + typeObject = types[animationType.type]; + animationTypeString = animationType.type; + } + + // First, test that the animation type object has 'testInterpolation'. + // We use test() function() here so that we can continue the remainder tests + // even if this test fails. + test(function(t) { + assert_own_property(typeObject, 'testInterpolation', animationTypeString + + ' should have testInterpolation property'); + assert_equals(typeof typeObject.testInterpolation, 'function', + 'testInterpolation method should be a function'); + }, animationTypeString + ' has testInterpolation function'); + + if (typeObject.testInterpolation && + typeof typeObject.testInterpolation === 'function') { + typeObject.testInterpolation(property, + setupFunction, + animationType.options); + } + }); +} +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/property-list.js b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/property-list.js new file mode 100644 index 0000000..a2f47285 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/property-list.js
@@ -0,0 +1,1523 @@ +'use strict'; + +var gCSSProperties = { + 'align-content': { + // https://drafts.csswg.org/css-align/#propdef-align-content + types: [ + { type: 'discrete' , options: [ [ 'flex-start', 'flex-end' ] ] } + ] + }, + 'align-items': { + // https://drafts.csswg.org/css-align/#propdef-align-items + types: [ + { type: 'discrete', options: [ [ 'flex-start', 'flex-end' ] ] } + ] + }, + 'align-self': { + // https://drafts.csswg.org/css-align/#propdef-align-self + types: [ + { type: 'discrete', options: [ [ 'flex-start', 'flex-end' ] ] } + ] + }, + 'backface-visibility': { + // https://drafts.csswg.org/css-transforms/#propdef-backface-visibility + types: [ + { type: 'discrete', options: [ [ 'visible', 'hidden' ] ] } + ] + }, + 'background-attachment': { + // https://drafts.csswg.org/css-backgrounds-3/#background-attachment + types: [ + { type: 'discrete', options: [ [ 'fixed', 'local' ] ] } + ] + }, + 'background-color': { + // https://drafts.csswg.org/css-backgrounds-3/#background-color + types: [ 'color' ] + }, + 'background-blend-mode': { + // https://drafts.fxtf.org/compositing-1/#propdef-background-blend-mode + types: [ + { type: 'discrete', options: [ [ 'multiply', 'screen' ] ] } + ] + }, + 'background-clip': { + // https://drafts.csswg.org/css-backgrounds-3/#background-clip + types: [ + { type: 'discrete', options: [ [ 'padding-box', 'content-box' ] ] } + ] + }, + 'background-image': { + // https://drafts.csswg.org/css-backgrounds-3/#background-image + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'background-origin': { + // https://drafts.csswg.org/css-backgrounds-3/#background-origin + types: [ + { type: 'discrete', options: [ [ 'padding-box', 'content-box' ] ] } + ] + }, + 'background-position': { + // https://drafts.csswg.org/css-backgrounds-3/#background-position + types: [ + ] + }, + 'background-position-x': { + // https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x + types: [ + ] + }, + 'background-position-y': { + // https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y + types: [ + ] + }, + 'background-repeat': { + // https://drafts.csswg.org/css-backgrounds-3/#background-repeat + types: [ + { type: 'discrete', options: [ [ 'space', 'round' ] ] } + ] + }, + 'background-size': { + // https://drafts.csswg.org/css-backgrounds-3/#background-size + types: [ + ] + }, + 'block-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-block-size + types: [ + ] + }, + 'border-block-end-color': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-end-color + types: [ + ] + }, + 'border-block-end-style': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-end-style + types: [ + ] + }, + 'border-block-end-width': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-end-width + types: [ + ] + }, + 'border-block-start-color': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-start-color + types: [ + ] + }, + 'border-block-start-style': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-start-style + types: [ + ] + }, + 'border-block-start-width': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-start-width + types: [ + ] + }, + 'border-bottom-color': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-color + types: [ 'color' ] + }, + 'border-bottom-left-radius': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-left-radius + types: [ + ] + }, + 'border-bottom-right-radius': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-right-radius + types: [ + ] + }, + 'border-bottom-style': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-style + types: [ + { type: 'discrete', options: [ [ 'dotted', 'solid' ] ] } + ] + }, + 'border-bottom-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-bottom-width + types: [ 'length' ], + setup: t => { + var element = createElement(t); + element.style.borderBottomStyle = 'solid'; + return element; + } + }, + 'border-collapse': { + // https://drafts.csswg.org/css-tables/#propdef-border-collapse + types: [ + { type: 'discrete', options: [ [ 'collapse', 'separate' ] ] } + ] + }, + 'border-inline-end-color': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-end-color + types: [ + ] + }, + 'border-inline-end-style': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-end-style + types: [ + ] + }, + 'border-inline-end-width': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-end-width + types: [ + ] + }, + 'border-inline-start-color': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-start-color + types: [ + ] + }, + 'border-inline-start-style': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-block-start-style + types: [ + ] + }, + 'border-inline-start-width': { + // https://drafts.csswg.org/css-logical-props/#propdef-border-inline-start-width + types: [ + ] + }, + 'border-image-outset': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-outset + types: [ + { type: 'discrete', options: [ [ '1 1 1 1', '5 5 5 5' ] ] } + ] + }, + 'border-image-repeat': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-repeat + types: [ + { type: 'discrete', options: [ [ 'stretch stretch', 'repeat repeat' ] ] } + ] + }, + 'border-image-slice': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-slice + types: [ + { type: 'discrete', options: [ [ '1 1 1 1', '5 5 5 5' ] ] } + ] + }, + 'border-image-source': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-source + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'border-image-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-image-width + types: [ + { type: 'discrete', options: [ [ '1 1 1 1', '5 5 5 5' ] ] } + ] + }, + 'border-left-color': { + // https://drafts.csswg.org/css-backgrounds-3/#border-left-color + types: [ 'color' ] + }, + 'border-left-style': { + // https://drafts.csswg.org/css-backgrounds-3/#border-left-style + types: [ + { type: 'discrete', options: [ [ 'dotted', 'solid' ] ] } + ] + }, + 'border-left-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-left-width + types: [ 'length' ], + setup: t => { + var element = createElement(t); + element.style.borderLeftStyle = 'solid'; + return element; + } + }, + 'border-right-color': { + // https://drafts.csswg.org/css-backgrounds-3/#border-right-color + types: [ 'color' ] + }, + 'border-right-style': { + // https://drafts.csswg.org/css-backgrounds-3/#border-right-style + types: [ + { type: 'discrete', options: [ [ 'dotted', 'solid' ] ] } + ] + }, + 'border-right-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-right-width + types: [ 'length' ], + setup: t => { + var element = createElement(t); + element.style.borderRightStyle = 'solid'; + return element; + } + }, + 'border-spacing': { + // https://drafts.csswg.org/css-tables/#propdef-border-spacing + types: [ + ] + }, + 'border-top-color': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-color + types: [ 'color' ] + }, + 'border-top-left-radius': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-left-radius + types: [ + ] + }, + 'border-top-right-radius': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-right-radius + types: [ + ] + }, + 'border-top-style': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-style + types: [ + { type: 'discrete', options: [ [ 'dotted', 'solid' ] ] } + ] + }, + 'border-top-width': { + // https://drafts.csswg.org/css-backgrounds-3/#border-top-width + types: [ 'length' ], + setup: t => { + var element = createElement(t); + element.style.borderTopStyle = 'solid'; + return element; + } + }, + 'bottom': { + // https://drafts.csswg.org/css-position/#propdef-bottom + types: [ + ] + }, + 'box-decoration-break': { + // https://drafts.csswg.org/css-break/#propdef-box-decoration-break + types: [ + { type: 'discrete', options: [ [ 'slice', 'clone' ] ] } + ] + }, + 'box-shadow': { + // https://drafts.csswg.org/css-backgrounds/#box-shadow + types: [ 'boxShadowList' ], + }, + 'box-sizing': { + // https://drafts.csswg.org/css-ui-4/#box-sizing + types: [ + { type: 'discrete', options: [ [ 'content-box', 'border-box' ] ] } + ] + }, + 'caption-side': { + // https://drafts.csswg.org/css-tables/#propdef-caption-side + types: [ + { type: 'discrete', options: [ [ 'top', 'bottom' ] ] } + ] + }, + 'clear': { + // https://drafts.csswg.org/css-page-floats/#propdef-clear + types: [ + { type: 'discrete', options: [ [ 'inline-start', 'inline-end' ] ] } + ] + }, + 'clip': { + // https://drafts.fxtf.org/css-masking-1/#propdef-clip + types: [ + ] + }, + 'clip-path': { + // https://drafts.fxtf.org/css-masking-1/#propdef-clip-path + types: [ + ] + }, + 'clip-rule': { + // https://drafts.fxtf.org/css-masking-1/#propdef-clip-rule + types: [ + { type: 'discrete', options: [ [ 'evenodd', 'nonzero' ] ] } + ] + }, + 'color': { + // https://drafts.csswg.org/css-color/#propdef-color + types: [ 'color' ] + }, + 'color-adjust': { + // https://drafts.csswg.org/css-color-4/#color-adjust + types: [ + { type: 'discrete', options: [ [ 'economy', 'exact' ] ] } + ] + }, + 'color-interpolation': { + // https://svgwg.org/svg2-draft/painting.html#ColorInterpolationProperty + types: [ + { type: 'discrete', options: [ [ 'linearRGB', 'auto' ] ] } + ] + }, + 'color-interpolation-filters': { + // https://drafts.fxtf.org/filters-1/#propdef-color-interpolation-filters + types: [ + { type: 'discrete', options: [ [ 'sRGB', 'linearRGB' ] ] } + ] + }, + 'column-count': { + // https://drafts.csswg.org/css-multicol/#propdef-column-count + types: [ + ] + }, + 'column-gap': { + // https://drafts.csswg.org/css-multicol/#propdef-column-gap + types: [ 'length' ] + }, + 'column-rule-color': { + // https://drafts.csswg.org/css-multicol/#propdef-column-rule-color + types: [ 'color' ] + }, + 'column-fill': { + // https://drafts.csswg.org/css-multicol/#propdef-column-fill + types: [ + { type: 'discrete', options: [ [ 'auto', 'balance' ] ] } + ] + }, + 'column-rule-style': { + // https://drafts.csswg.org/css-multicol/#propdef-column-rule-style + types: [ + { type: 'discrete', options: [ [ 'none', 'dotted' ] ] } + ] + }, + 'column-rule-width': { + // https://drafts.csswg.org/css-multicol/#propdef-column-rule-width + types: [ 'length' ], + setup: t => { + var element = createElement(t); + element.style.columnRuleStyle = 'solid'; + return element; + } + }, + 'column-width': { + // https://drafts.csswg.org/css-multicol/#propdef-column-width + types: [ 'length', + { type: 'discrete', options: [ [ 'auto', '1px' ] ] } + ] + }, + 'contain': { + // https://drafts.csswg.org/css-containment/#propdef-contain + types: [ + { type: 'discrete', options: [ [ 'strict', 'none' ] ] } + ] + }, + 'content': { + // https://drafts.csswg.org/css-content-3/#propdef-content + types: [ + { type: 'discrete', options: [ [ '"a"', '"b"' ] ] } + ], + setup: t => { + return createPseudo(t, 'before'); + } + }, + 'counter-increment': { + // https://drafts.csswg.org/css-lists-3/#propdef-counter-increment + types: [ + { type: 'discrete', options: [ [ 'ident-1 1', 'ident-2 2' ] ] } + ] + }, + 'counter-reset': { + // https://drafts.csswg.org/css-lists-3/#propdef-counter-reset + types: [ + { type: 'discrete', options: [ [ 'ident-1 1', 'ident-2 2' ] ] } + ] + }, + 'cursor': { + // https://drafts.csswg.org/css2/ui.html#propdef-cursor + types: [ + { type: 'discrete', options: [ [ 'pointer', 'wait' ] ] } + ] + }, + 'direction': { + // https://drafts.csswg.org/css-writing-modes-3/#propdef-direction + types: [ + { type: 'discrete', options: [ [ 'ltr', 'rtl' ] ] } + ] + }, + 'dominant-baseline': { + // https://drafts.csswg.org/css-inline/#propdef-dominant-baseline + types: [ + { type: 'discrete', options: [ [ 'ideographic', 'alphabetic' ] ] } + ] + }, + 'empty-cells': { + // https://drafts.csswg.org/css-tables/#propdef-empty-cells + types: [ + { type: 'discrete', options: [ [ 'show', 'hide' ] ] } + ] + }, + 'fill': { + // https://svgwg.org/svg2-draft/painting.html#FillProperty + types: [ + ] + }, + 'fill-opacity': { + // https://svgwg.org/svg2-draft/painting.html#FillOpacityProperty + types: [ + ] + }, + 'fill-rule': { + // https://svgwg.org/svg2-draft/painting.html#FillRuleProperty + types: [ + { type: 'discrete', options: [ [ 'evenodd', 'nonzero' ] ] } + ] + }, + 'filter': { + // https://drafts.fxtf.org/filters/#propdef-filter + types: [ 'filterList' ] + }, + 'flex-basis': { + // https://drafts.csswg.org/css-flexbox/#propdef-flex-basis + types: [ + 'lengthPercentageOrCalc', + { type: 'discrete', options: [ [ 'auto', '10px' ] ] } + ] + }, + 'flex-direction': { + // https://drafts.csswg.org/css-flexbox/#propdef-flex-direction + types: [ + { type: 'discrete', options: [ [ 'row', 'row-reverse' ] ] } + ] + }, + 'flex-grow': { + // https://drafts.csswg.org/css-flexbox/#flex-grow-property + types: [ 'positiveNumber' ] + }, + 'flex-shrink': { + // https://drafts.csswg.org/css-flexbox/#propdef-flex-shrink + types: [ 'positiveNumber' ] + }, + 'flex-wrap': { + // https://drafts.csswg.org/css-flexbox/#propdef-flex-wrap + types: [ + { type: 'discrete', options: [ [ 'nowrap', 'wrap' ] ] } + ] + }, + 'flood-color': { + // https://drafts.fxtf.org/filters/#FloodColorProperty + types: [ 'color' ] + }, + 'flood-opacity': { + // https://drafts.fxtf.org/filters/#propdef-flood-opacity + types: [ + ] + }, + 'font-size': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-size + types: [ + ] + }, + 'font-size-adjust': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-size-adjust + types: [ + ] + }, + 'font-stretch': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-stretch + types: [ + ] + }, + 'font-style': { + // https://drafts.csswg.org/css-fonts/#propdef-font-style + types: [ + { type: 'discrete', options: [ [ 'italic', 'oblique' ] ] } + ] + }, + 'float': { + // https://drafts.csswg.org/css-page-floats/#propdef-float + types: [ + { type: 'discrete', options: [ [ 'left', 'right' ] ] } + ] + }, + 'font-family': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-family + types: [ + { type: 'discrete', options: [ [ 'helvetica', 'verdana' ] ] } + ] + }, + 'font-feature-settings': { + // https://drafts.csswg.org/css-fonts/#descdef-font-feature-settings + types: [ + { type: 'discrete', options: [ [ '"liga" 5', 'normal' ] ] } + ] + }, + 'font-kerning': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-kerning + types: [ + { type: 'discrete', options: [ [ 'auto', 'normal' ] ] } + ] + }, + 'font-language-override': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-language-override + types: [ + { type: 'discrete', options: [ [ '"eng"', 'normal' ] ] } + ] + }, + 'font-style': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-style + types: [ + { type: 'discrete', options: [ [ 'italic', 'oblique' ] ] } + ] + }, + 'font-synthesis': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-synthesis + types: [ + { type: 'discrete', options: [ [ 'none', 'weight style' ] ] } + ] + }, + 'font-variant-alternates': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-alternates + types: [ + { type: 'discrete', + options: [ [ 'swash(unknown)', 'stylistic(unknown)' ] ] } + ] + }, + 'font-variant-caps': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-caps + types: [ + { type: 'discrete', options: [ [ 'small-caps', 'unicase' ] ] } + ] + }, + 'font-variant-east-asian': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-east-asian + types: [ + { type: 'discrete', options: [ [ 'full-width', 'proportional-width' ] ] } + ] + }, + 'font-variant-ligatures': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-ligatures + types: [ + { type: 'discrete', + options: [ [ 'common-ligatures', 'no-common-ligatures' ] ] } + ] + }, + 'font-variant-numeric': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-numeric + types: [ + { type: 'discrete', options: [ [ 'lining-nums', 'oldstyle-nums' ] ] } + ] + }, + 'font-variant-position': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-variant-position + types: [ + { type: 'discrete', options: [ [ 'sub', 'super' ] ] } + ] + }, + 'font-weight': { + // https://drafts.csswg.org/css-fonts-3/#propdef-font-weight + types: [ + ] + }, + 'grid-auto-columns': { + // https://drafts.csswg.org/css-grid/#propdef-grid-auto-columns + types: [ + { type: 'discrete', options: [ [ '1px', '5px' ] ] } + ] + }, + 'grid-auto-flow': { + // https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow + types: [ + { type: 'discrete', options: [ [ 'row', 'column' ] ] } + ] + }, + 'grid-auto-rows': { + // https://drafts.csswg.org/css-grid/#propdef-grid-auto-rows + types: [ + { type: 'discrete', options: [ [ '1px', '5px' ] ] } + ] + }, + 'grid-column-end': { + // https://drafts.csswg.org/css-grid/#propdef-grid-column-end + types: [ + { type: 'discrete', options: [ [ '1', '5' ] ] } + ] + }, + 'grid-column-gap': { + // https://drafts.csswg.org/css-grid/#propdef-grid-column-gap + types: [ + ] + }, + 'grid-column-start': { + // https://drafts.csswg.org/css-grid/#propdef-grid-column-start + types: [ + { type: 'discrete', options: [ [ '1', '5' ] ] } + ] + }, + 'grid-row-end': { + // https://drafts.csswg.org/css-grid/#propdef-grid-row-end + types: [ + { type: 'discrete', options: [ [ '1', '5' ] ] } + ] + }, + 'grid-row-gap': { + // https://drafts.csswg.org/css-grid/#propdef-grid-row-gap + types: [ + ] + }, + 'grid-row-start': { + // https://drafts.csswg.org/css-grid/#propdef-grid-row-start + types: [ + { type: 'discrete', options: [ [ '1', '5' ] ] } + ] + }, + 'grid-template-areas': { + // https://drafts.csswg.org/css-template/#grid-template-areas + types: [ + { type: 'discrete', options: [ [ '". . a b" ". .a b"', 'none' ] ] } + ] + }, + 'grid-template-columns': { + // https://drafts.csswg.org/css-template/#grid-template-columns + types: [ + { type: 'discrete', options: [ [ '1px', '5px' ] ] } + ] + }, + 'grid-template-rows': { + // https://drafts.csswg.org/css-template/#grid-template-rows + types: [ + { type: 'discrete', options: [ [ '1px', '5px' ] ] } + ] + }, + 'height': { + // https://drafts.csswg.org/css21/visudet.html#propdef-height + types: [ + ] + }, + 'hyphens': { + // https://drafts.csswg.org/css-text-3/#propdef-hyphens + types: [ + { type: 'discrete', options: [ [ 'manual', 'auto' ] ] } + ] + }, + 'image-orientation': { + // https://drafts.csswg.org/css-images-3/#propdef-image-orientation + types: [ + { type: 'discrete', options: [ [ '0deg', '90deg' ] ] } + ] + }, + 'image-rendering': { + // https://drafts.csswg.org/css-images-3/#propdef-image-rendering + types: [ + ] + }, + 'ime-mode': { + // https://drafts.csswg.org/css-ui/#input-method-editor + types: [ + { type: 'discrete', options: [ [ 'disabled', 'auto' ] ] } + ] + }, + 'initial-letter': { + // https://drafts.csswg.org/css-inline/#propdef-initial-letter + types: [ + { type: 'discrete', options: [ [ '1 2', '3 4' ] ] } + ] + }, + 'inline-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-inline-size + types: [ + ] + }, + 'isolation': { + // https://drafts.fxtf.org/compositing-1/#propdef-isolation + types: [ + { type: 'discrete', options: [ [ 'auto', 'isolate' ] ] } + ] + }, + 'justify-content': { + // https://drafts.csswg.org/css-align/#propdef-justify-content + types: [ + { type: 'discrete', options: [ [ 'baseline', 'last baseline' ] ] } + ] + }, + 'justify-items': { + // https://drafts.csswg.org/css-align/#propdef-justify-items + types: [ + { type: 'discrete', options: [ [ 'baseline', 'last baseline' ] ] } + ] + }, + 'justify-self': { + // https://drafts.csswg.org/css-align/#propdef-justify-self + types: [ + { type: 'discrete', options: [ [ 'baseline', 'last baseline' ] ] } + ] + }, + 'left': { + // https://drafts.csswg.org/css-position/#propdef-left + types: [ + ] + }, + 'letter-spacing': { + // https://drafts.csswg.org/css-text-3/#propdef-letter-spacing + types: [ 'length' ] + }, + 'lighting-color': { + // https://drafts.fxtf.org/filters/#LightingColorProperty + types: [ 'color' ] + }, + 'line-height': { + // https://drafts.csswg.org/css21/visudet.html#propdef-line-height + types: [ + ] + }, + 'list-style-image': { + // https://drafts.csswg.org/css-lists-3/#propdef-list-style-image + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'list-style-position': { + // https://drafts.csswg.org/css-lists-3/#propdef-list-style-position + types: [ + { type: 'discrete', options: [ [ 'inside', 'outside' ] ] } + ] + }, + 'list-style-type': { + // https://drafts.csswg.org/css-lists-3/#propdef-list-style-type + types: [ + { type: 'discrete', options: [ [ 'circle', 'square' ] ] } + ] + }, + 'margin-block-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-margin-block-end + types: [ + ] + }, + 'margin-block-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-margin-block-start + types: [ + ] + }, + 'margin-bottom': { + // https://drafts.csswg.org/css-box/#propdef-margin-bottom + types: [ + ] + }, + 'margin-inline-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-margin-inline-end + types: [ + ] + }, + 'margin-inline-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-margin-inline-start + types: [ + ] + }, + 'margin-left': { + // https://drafts.csswg.org/css-box/#propdef-margin-left + types: [ + ] + }, + 'margin-right': { + // https://drafts.csswg.org/css-box/#propdef-margin-right + types: [ + ] + }, + 'margin-top': { + // https://drafts.csswg.org/css-box/#propdef-margin-top + types: [ + ] + }, + 'marker-end': { + // https://svgwg.org/specs/markers/#MarkerEndProperty + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'marker-mid': { + // https://svgwg.org/specs/markers/#MarkerMidProperty + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'marker-start': { + // https://svgwg.org/specs/markers/#MarkerStartProperty + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'mask': { + // https://drafts.fxtf.org/css-masking-1/#the-mask + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'mask-clip': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-clip + types: [ + { type: 'discrete', options: [ [ 'content-box', 'border-box' ] ] } + ] + }, + 'mask-composite': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-composite + types: [ + { type: 'discrete', options: [ [ 'add', 'subtract' ] ] } + ] + }, + 'mask-image': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-image + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'mask-mode': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-mode + types: [ + { type: 'discrete', options: [ [ 'alpha', 'luminance' ] ] } + ] + }, + 'mask-origin': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-origin + types: [ + { type: 'discrete', options: [ [ 'content-box', 'border-box' ] ] } + ] + }, + 'mask-position': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-position + types: [ + ] + }, + 'mask-position-x': { + // https://lists.w3.org/Archives/Public/www-style/2014Jun/0166.html + types: [ + ] + }, + 'mask-position-y': { + // https://lists.w3.org/Archives/Public/www-style/2014Jun/0166.html + types: [ + ] + }, + 'mask-repeat': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-repeat + types: [ + { type: 'discrete', options: [ [ 'space', 'round' ] ] } + ] + }, + 'mask-size': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-size + types: [ + ] + }, + 'mask-type': { + // https://drafts.fxtf.org/css-masking-1/#propdef-mask-type + types: [ + { type: 'discrete', options: [ [ 'alpha', 'luminance' ] ] } + ] + }, + 'max-block-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-max-block-size + types: [ + ] + }, + 'max-height': { + // https://drafts.csswg.org/css21/visudet.html#propdef-max-height + types: [ + ] + }, + 'max-inline-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-max-inline-size + types: [ + ] + }, + 'max-width': { + // https://drafts.csswg.org/css21/visudet.html#propdef-max-width + types: [ + ] + }, + 'min-block-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-min-block-size + types: [ + ] + }, + 'min-height': { + // https://drafts.csswg.org/css21/visudet.html#propdef-min-height + types: [ + ] + }, + 'min-inline-size': { + // https://drafts.csswg.org/css-logical-props/#propdef-min-inline-size + types: [ + ] + }, + 'min-width': { + // https://drafts.csswg.org/css21/visudet.html#propdef-min-width + types: [ + ] + }, + 'mix-blend-mode': { + // https://drafts.fxtf.org/compositing-1/#propdef-mix-blend-mode + types: [ + { type: 'discrete', options: [ [ 'multiply', 'screen' ] ] } + ] + }, + 'object-fit': { + // https://drafts.csswg.org/css-images-3/#propdef-object-fit + types: [ + { type: 'discrete', options: [ [ 'fill', 'contain' ] ] } + ] + }, + 'object-position': { + // https://drafts.csswg.org/css-images-3/#propdef-object-position + types: [ + ] + }, + 'offset-block-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-offset-block-end + types: [ + ] + }, + 'offset-block-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-offset-block-start + types: [ + ] + }, + 'offset-inline-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-offset-inline-end + types: [ + ] + }, + 'offset-inline-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-offset-inline-start + types: [ + ] + }, + 'opacity': { + // https://drafts.csswg.org/css-color/#propdef-opacity + types: [ + ] + }, + 'order': { + // https://drafts.csswg.org/css-flexbox/#propdef-order + types: [ 'integer' ] + }, + 'outline-color': { + // https://drafts.csswg.org/css-ui-3/#propdef-outline-color + types: [ 'color' ] + }, + 'outline-offset': { + // https://drafts.csswg.org/css-ui-3/#propdef-outline-offset + types: [ 'length' ] + }, + 'outline-style': { + // https://drafts.csswg.org/css-ui/#propdef-outline-style + types: [ + { type: 'discrete', options: [ [ 'none', 'dotted' ] ] } + ] + }, + 'outline-width': { + // https://drafts.csswg.org/css-ui-3/#propdef-outline-width + types: [ 'length' ], + setup: t => { + var element = createElement(t); + element.style.outlineStyle = 'solid'; + return element; + } + }, + 'overflow': { + // https://drafts.csswg.org/css-overflow/#propdef-overflow + types: [ + ] + }, + 'overflow-clip-box': { + // https://developer.mozilla.org/en/docs/Web/CSS/overflow-clip-box + types: [ + { type: 'discrete', options: [ [ 'padding-box', 'content-box' ] ] } + ] + }, + 'overflow-wrap': { + // https://drafts.csswg.org/css-text-3/#propdef-overflow-wrap + types: [ + { type: 'discrete', options: [ [ 'normal', 'break-word' ] ] } + ] + }, + 'overflow-x': { + // https://drafts.csswg.org/css-overflow-3/#propdef-overflow-x + types: [ + { type: 'discrete', options: [ [ 'visible', 'hidden' ] ] } + ] + }, + 'overflow-y': { + // https://drafts.csswg.org/css-overflow-3/#propdef-overflow-y + types: [ + { type: 'discrete', options: [ [ 'visible', 'hidden' ] ] } + ] + }, + 'padding-block-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-padding-block-end + types: [ + ] + }, + 'padding-block-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-padding-block-start + types: [ + ] + }, + 'padding-bottom': { + // https://drafts.csswg.org/css-box/#propdef-padding-bottom + types: [ + ] + }, + 'padding-inline-end': { + // https://drafts.csswg.org/css-logical-props/#propdef-padding-inline-end + types: [ + ] + }, + 'padding-inline-start': { + // https://drafts.csswg.org/css-logical-props/#propdef-padding-inline-start + types: [ + ] + }, + 'padding-left': { + // https://drafts.csswg.org/css-box/#propdef-padding-left + types: [ + ] + }, + 'padding-right': { + // https://drafts.csswg.org/css-box/#propdef-padding-right + types: [ + ] + }, + 'padding-top': { + // https://drafts.csswg.org/css-box/#propdef-padding-top + types: [ + ] + }, + 'page-break-after': { + // https://drafts.csswg.org/css-break-3/#propdef-break-after + types: [ + { type: 'discrete', options: [ [ 'always', 'auto' ] ] } + ] + }, + 'page-break-before': { + // https://drafts.csswg.org/css-break-3/#propdef-break-before + types: [ + { type: 'discrete', options: [ [ 'always', 'auto' ] ] } + ] + }, + 'page-break-inside': { + // https://drafts.csswg.org/css-break-3/#propdef-break-inside + types: [ + { type: 'discrete', options: [ [ 'auto', 'avoid' ] ] } + ] + }, + 'paint-order': { + // https://svgwg.org/svg2-draft/painting.html#PaintOrderProperty + types: [ + { type: 'discrete', options: [ [ 'fill', 'stroke' ] ] } + ] + }, + 'perspective': { + // https://drafts.csswg.org/css-transforms-1/#propdef-perspective + types: [ 'length' ] + }, + 'perspective-origin': { + // https://drafts.csswg.org/css-transforms-1/#propdef-perspective-origin + types: [ + ] + }, + 'pointer-events': { + // https://svgwg.org/svg2-draft/interact.html#PointerEventsProperty + types: [ + { type: 'discrete', options: [ [ 'fill', 'none' ] ] } + ] + }, + 'position': { + // https://drafts.csswg.org/css-position/#propdef-position + types: [ + { type: 'discrete', options: [ [ 'absolute', 'fixed' ] ] } + ] + }, + 'quotes': { + // https://drafts.csswg.org/css-content-3/#propdef-quotes + types: [ + { type: 'discrete', options: [ [ '"“" "”" "‘" "’"', '"‘" "’" "“" "”"' ] ] } + ] + }, + 'resize': { + // https://drafts.csswg.org/css-ui/#propdef-resize + types: [ + { type: 'discrete', options: [ [ 'both', 'horizontal' ] ] } + ] + }, + 'right': { + // https://drafts.csswg.org/css-position/#propdef-right + types: [ + ] + }, + 'ruby-align': { + // https://drafts.csswg.org/css-ruby-1/#propdef-ruby-align + types: [ + { type: 'discrete', options: [ [ 'start', 'center' ] ] } + ] + }, + 'ruby-position': { + // https://drafts.csswg.org/css-ruby-1/#propdef-ruby-position + types: [ + { type: 'discrete', options: [ [ 'under', 'over' ] ] } + ], + setup: t => { + return createElement(t, 'ruby'); + } + }, + 'scroll-behavior': { + // https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior + types: [ + { type: 'discrete', options: [ [ 'auto', 'smooth' ] ] } + ] + }, + 'scroll-snap-type-x': { + // https://developer.mozilla.org/en/docs/Web/CSS/scroll-snap-type-x + types: [ + { type: 'discrete', options: [ [ 'mandatory', 'proximity' ] ] } + ] + }, + 'scroll-snap-type-y': { + // https://developer.mozilla.org/en/docs/Web/CSS/scroll-snap-type-y + types: [ + { type: 'discrete', options: [ [ 'mandatory', 'proximity' ] ] } + ] + }, + 'shape-outside': { + // http://dev.w3.org/csswg/css-shapes/#propdef-shape-outside + types: [ + { type: 'discrete', + options: [ [ 'url("http://localhost/test-1")', + 'url("http://localhost/test-2")' ] ] } + ] + }, + 'shape-rendering': { + // https://svgwg.org/svg2-draft/painting.html#ShapeRenderingProperty + types: [ + { type: 'discrete', options: [ [ 'optimizeSpeed', 'crispEdges' ] ] } + ] + }, + 'stop-color': { + // https://svgwg.org/svg2-draft/pservers.html#StopColorProperty + types: [ 'color' ] + }, + 'stop-opacity': { + // https://svgwg.org/svg2-draft/pservers.html#StopOpacityProperty + types: [ + ] + }, + 'stroke': { + // https://svgwg.org/svg2-draft/painting.html#StrokeProperty + types: [ + ] + }, + 'stroke-dasharray': { + // https://svgwg.org/svg2-draft/painting.html#StrokeDasharrayProperty + types: [ + ] + }, + 'stroke-dashoffset': { + // https://svgwg.org/svg2-draft/painting.html#StrokeDashoffsetProperty + types: [ + ] + }, + 'stroke-linecap': { + // https://svgwg.org/svg2-draft/painting.html#StrokeLinecapProperty + types: [ + { type: 'discrete', options: [ [ 'round', 'square' ] ] } + ] + }, + 'stroke-linejoin': { + // https://svgwg.org/svg2-draft/painting.html#StrokeLinejoinProperty + types: [ + { type: 'discrete', options: [ [ 'round', 'miter' ] ] } + ], + setup: t => { + return createElement(t, 'rect'); + } + }, + 'stroke-miterlimit': { + // https://svgwg.org/svg2-draft/painting.html#StrokeMiterlimitProperty + types: [ + ] + }, + 'stroke-opacity': { + // https://svgwg.org/svg2-draft/painting.html#StrokeOpacityProperty + types: [ + ] + }, + 'stroke-width': { + // https://svgwg.org/svg2-draft/painting.html#StrokeWidthProperty + types: [ + ] + }, + 'table-layout': { + // https://drafts.csswg.org/css-tables/#propdef-table-layout + types: [ + { type: 'discrete', options: [ [ 'auto', 'fixed' ] ] } + ] + }, + 'text-align': { + // https://drafts.csswg.org/css-text-3/#propdef-text-align + types: [ + { type: 'discrete', options: [ [ 'start', 'end' ] ] } + ] + }, + 'text-align-last': { + // https://drafts.csswg.org/css-text-3/#propdef-text-align-last + types: [ + { type: 'discrete', options: [ [ 'start', 'end' ] ] } + ] + }, + 'text-anchor': { + // https://svgwg.org/svg2-draft/text.html#TextAnchorProperty + types: [ + { type: 'discrete', options: [ [ 'middle', 'end' ] ] } + ] + }, + 'text-combine-upright': { + // https://drafts.csswg.org/css-writing-modes-3/#propdef-text-combine-upright + types: [ + { type: 'discrete', options: [ [ 'all', 'none' ] ] } + ] + }, + 'text-decoration-color': { + // https://drafts.csswg.org/css-text-decor-3/#propdef-text-decoration-color + types: [ 'color' ] + }, + 'text-decoration-line': { + // https://drafts.csswg.org/css-text-decor-3/#propdef-text-decoration-line + types: [ + { type: 'discrete', options: [ [ 'underline', 'overline' ] ] } + ] + }, + 'text-decoration-style': { + // http://dev.w3.org/csswg/css-text-decor-3/#propdef-text-decoration-style + types: [ + { type: 'discrete', options: [ [ 'solid', 'dotted' ] ] } + ] + }, + 'text-emphasis-color': { + // https://drafts.csswg.org/css-text-decor-3/#propdef-text-emphasis-color + types: [ 'color' ] + }, + 'text-emphasis-position': { + // http://dev.w3.org/csswg/css-text-decor-3/#propdef-text-emphasis-position + types: [ + { type: 'discrete', options: [ [ 'over right', 'under left' ] ] } + ] + }, + 'text-emphasis-style': { + // http://dev.w3.org/csswg/css-text-decor-3/#propdef-text-emphasis-style + types: [ + { type: 'discrete', options: [ [ 'filled circle', 'open dot' ] ] } + ] + }, + 'text-indent': { + // https://drafts.csswg.org/css-text-3/#propdef-text-indent + types: [ + ] + }, + 'text-orientation': { + // https://drafts.csswg.org/css-writing-modes-3/#propdef-text-orientation + types: [ + { type: 'discrete', options: [ [ 'upright', 'sideways' ] ] } + ] + }, + 'text-overflow': { + // https://drafts.csswg.org/css-ui/#propdef-text-overflow + types: [ + { type: 'discrete', options: [ [ 'clip', 'ellipsis' ] ] } + ] + }, + 'text-rendering': { + // https://svgwg.org/svg2-draft/painting.html#TextRenderingProperty + types: [ + { type: 'discrete', options: [ [ 'optimizeSpeed', 'optimizeLegibility' ] ] } + ] + }, + 'text-shadow': { + // https://drafts.csswg.org/css-text-decor-3/#propdef-text-shadow + types: [ 'textShadowList' ], + setup: t => { + var element = createElement(t); + element.style.color = 'green'; + return element; + } + }, + 'text-transform': { + // https://drafts.csswg.org/css-text-3/#propdef-text-transform + types: [ + { type: 'discrete', options: [ [ 'capitalize', 'uppercase' ] ] } + ] + }, + 'touch-action': { + // https://w3c.github.io/pointerevents/#the-touch-action-css-property + types: [ + { type: 'discrete', options: [ [ 'auto', 'none' ] ] } + ] + }, + 'top': { + // https://drafts.csswg.org/css-position/#propdef-top + types: [ + ] + }, + 'transform': { + // https://drafts.csswg.org/css-transforms/#propdef-transform + types: [ 'transformList' ] + }, + 'transform-box': { + // https://drafts.csswg.org/css-transforms/#propdef-transform-box + types: [ + { type: 'discrete', options: [ [ 'fill-box', 'border-box' ] ] } + ] + }, + 'transform-origin': { + // https://drafts.csswg.org/css-transforms/#propdef-transform-origin + types: [ + ] + }, + 'transform-style': { + // https://drafts.csswg.org/css-transforms/#propdef-transform-style + types: [ + { type: 'discrete', options: [ [ 'flat', 'preserve-3d' ] ] } + ] + }, + 'unicode-bidi': { + // https://drafts.csswg.org/css-writing-modes-3/#propdef-unicode-bidi + types: [ + { type: 'discrete', options: [ [ 'embed', 'bidi-override' ] ] }, + ] + }, + 'vector-effect': { + // https://svgwg.org/svg2-draft/coords.html#VectorEffectProperty + types: [ + { type: 'discrete', options: [ [ 'none', 'non-scaling-stroke' ] ] }, + ] + }, + 'vertical-align': { + // https://drafts.csswg.org/css21/visudet.html#propdef-vertical-align + types: [ + ] + }, + 'visibility': { + // https://drafts.csswg.org/css2/visufx.html#propdef-visibility + types: [ 'visibility' ] + }, + 'white-space': { + // https://drafts.csswg.org/css-text-4/#propdef-white-space + types: [ + { type: 'discrete', options: [ [ 'pre', 'nowrap' ] ] } + ] + }, + 'width': { + // https://drafts.csswg.org/css21/visudet.html#propdef-width + types: [ + ] + }, + 'word-break': { + // https://drafts.csswg.org/css-text-3/#propdef-word-break + types: [ + { type: 'discrete', options: [ [ 'keep-all', 'break-all' ] ] } + ] + }, + 'word-spacing': { + // https://drafts.csswg.org/css-text-3/#propdef-word-spacing + types: [ + ] + }, + 'will-change': { + // http://dev.w3.org/csswg/css-will-change/#propdef-will-change + types: [ + { type: 'discrete', options: [ [ 'scroll-position', 'contents' ] ] } + ] + }, + 'writing-mode': { + // https://drafts.csswg.org/css-writing-modes-3/#propdef-writing-mode + types: [ + { type: 'discrete', options: [ [ 'vertical-rl', 'sideways-rl' ] ] } + ] + }, + 'z-index': { + // https://drafts.csswg.org/css-position/#propdef-z-index + types: [ + ] + }, +}; + +function testAnimationSamples(animation, idlName, testSamples) { + var type = animation.effect.target.type; + var target = type + ? animation.effect.target.parentElement + : animation.effect.target; + testSamples.forEach(function(testSample) { + animation.currentTime = testSample.time; + assert_equals(getComputedStyle(target, type)[idlName], + testSample.expected, + 'The value should be ' + testSample.expected + + ' at ' + testSample.time + 'ms'); + }); +} + +function testAnimationSampleMatrices(animation, idlName, testSamples) { + var target = animation.effect.target; + testSamples.forEach(function(testSample) { + animation.currentTime = testSample.time; + var actual = getComputedStyle(target)[idlName]; + var expected = createMatrixFromArray(testSample.expected); + assert_matrix_equals(actual, expected, + 'The value should be ' + expected + + ' at ' + testSample.time + 'ms but got ' + actual); + }); +} + +function createTestElement(t, setup) { + return setup ? setup(t) : createElement(t); +} + +function isSupported(property) { + var testKeyframe = new TestKeyframe(propertyToIDL(property)); + try { + // Since TestKeyframe returns 'undefined' for |property|, + // the KeyframeEffect constructor will throw + // if the string 'undefined' is not a valid value for the property. + new KeyframeEffect(null, testKeyframe); + } catch(e) {} + return testKeyframe.propAccessCount !== 0; +} + +function TestKeyframe(testProp) { + var _propAccessCount = 0; + + Object.defineProperty(this, testProp, { + get: function() { _propAccessCount++; }, + enumerable: true + }); + + Object.defineProperty(this, 'propAccessCount', { + get: function() { return _propAccessCount; } + }); +} + +function propertyToIDL(property) { + // https://w3c.github.io/web-animations/#animation-property-name-to-idl-attribute-name + if (property === 'float') { + return 'cssFloat'; + } + return property.replace(/-[a-z]/gi, + function (str) { + return str.substr(1).toUpperCase(); }); +} +
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/property-types.js b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/property-types.js new file mode 100644 index 0000000..14c8f27 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/property-types.js
@@ -0,0 +1,972 @@ +const discreteType = { + testInterpolation: function(property, setup, options) { + options.forEach(function(keyframes) { + var [ from, to ] = keyframes; + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: [from, to] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }, + { time: 499, expected: from.toLowerCase() }, + { time: 500, expected: to.toLowerCase() }, + { time: 1000, expected: to.toLowerCase() }]); + }, property + ' uses discrete animation when animating between "' + + from + '" and "' + to + '" with linear easing'); + + test(function(t) { + // Easing: http://cubic-bezier.com/#.68,0,1,.01 + // With this curve, we don't reach the 50% point until about 95% of + // the time has expired. + var idlName = propertyToIDL(property); + var keyframes = {}; + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: [from, to] }, + { duration: 1000, fill: 'both', + easing: 'cubic-bezier(0.68,0,1,0.01)' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }, + { time: 940, expected: from.toLowerCase() }, + { time: 960, expected: to.toLowerCase() }]); + }, property + ' uses discrete animation when animating between "' + + from + '" and "' + to + '" with effect easing'); + + test(function(t) { + // Easing: http://cubic-bezier.com/#.68,0,1,.01 + // With this curve, we don't reach the 50% point until about 95% of + // the time has expired. + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: [from, to], + easing: 'cubic-bezier(0.68,0,1,0.01)' }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }, + { time: 940, expected: from.toLowerCase() }, + { time: 960, expected: to.toLowerCase() }]); + }, property + ' uses discrete animation when animating between "' + + from + '" and "' + to + '" with keyframe easing'); + }); + }, + + testAddition: function(property, setup, options) { + options.forEach(function(keyframes) { + var [ from, to ] = keyframes; + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.animate({ [idlName]: [from, from] }, 1000); + var animation = target.animate({ [idlName]: [to, to] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: to.toLowerCase() }]); + }, property + ': "' + to + '" onto "' + from + '"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.animate({ [idlName]: [to, to] }, 1000); + var animation = target.animate({ [idlName]: [from, from] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }]); + }, property + ': "' + from + '" onto "' + to + '"'); + }); + }, + +}; + +const lengthType = { + testInterpolation: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['10px', '50px'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '10px' }, + { time: 500, expected: '30px' }, + { time: 1000, expected: '50px' }]); + }, property + ' supports animating as a length'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['1rem', '5rem'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '10px' }, + { time: 500, expected: '30px' }, + { time: 1000, expected: '50px' }]); + }, property + ' supports animating as a length of rem'); + }, + + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '10px'; + var animation = target.animate({ [idlName]: ['10px', '50px'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '20px' }]); + }, property + ': length'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '1rem'; + var animation = target.animate({ [idlName]: ['1rem', '5rem'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '20px' }]); + }, property + ': length of rem'); + }, + +}; + +const percentageType = { + testInterpolation: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['10%', '50%'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '10%' }, + { time: 500, expected: '30%' }, + { time: 1000, expected: '50%' }]); + }, property + ' supports animating as a percentage'); + }, + + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '60%'; + var animation = target.animate({ [idlName]: ['70%', '100%'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '130%' }]); + }, property + ': percentage'); + }, + +}; + +const integerType = { + testInterpolation: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: [-2, 2] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-2' }, + { time: 500, expected: '0' }, + { time: 1000, expected: '2' }]); + }, property + ' supports animating as an integer'); + }, + + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = -1; + var animation = target.animate({ [idlName]: [-2, 2] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '-3' }]); + }, property + ': integer'); + }, + +}; + +const lengthPercentageOrCalcType = { + testInterpolation: function(property, setup) { + lengthType.testInterpolation(property, setup); + percentageType.testInterpolation(property, setup); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['10px', '20%'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '10px' }, + { time: 500, expected: 'calc(5px + 10%)' }, + { time: 1000, expected: '20%' }]); + }, property + ' supports animating as combination units "px" and "%"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['10%', '2em'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '10%' }, + { time: 500, expected: 'calc(10px + 5%)' }, + { time: 1000, expected: '20px' }]); + }, property + ' supports animating as combination units "%" and "em"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['1em', '2rem'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '10px' }, + { time: 500, expected: '15px' }, + { time: 1000, expected: '20px' }]); + }, property + ' supports animating as combination units "em" and "rem"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['10px', 'calc(1em + 20%)'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '10px' }, + { time: 500, expected: 'calc(10px + 10%)' }, + { time: 1000, expected: 'calc(10px + 20%)' }]); + }, property + ' supports animating as combination units "px" and "calc"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate( + { [idlName]: ['calc(10px + 10%)', 'calc(1em + 1rem + 20%)'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, + expected: 'calc(10px + 10%)' }, + { time: 500, + expected: 'calc(15px + 15%)' }, + { time: 1000, + expected: 'calc(20px + 20%)' }]); + }, property + ' supports animating as a calc'); + }, + + testAddition: function(property, setup) { + lengthType.testAddition(property, setup); + percentageType.testAddition(property, setup); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '10px'; + var animation = target.animate({ [idlName]: ['10%', '50%'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(10px + 10%)' }]); + }, property + ': units "%" onto "px"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '10%'; + var animation = target.animate({ [idlName]: ['10px', '50px'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(10px + 10%)' }]); + }, property + ': units "px" onto "%"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '10%'; + var animation = target.animate({ [idlName]: ['2rem', '5rem'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(20px + 10%)' }]); + }, property + ': units "rem" onto "%"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '2rem'; + var animation = target.animate({ [idlName]: ['10%', '50%'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(20px + 10%)' }]); + }, property + ': units "%" onto "rem"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '2em'; + var animation = target.animate({ [idlName]: ['2rem', '5rem'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '40px' }]); + }, property + ': units "rem" onto "em"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '2rem'; + var animation = target.animate({ [idlName]: ['2em', '5em'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '40px' }]); + }, property + ': units "em" onto "rem"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '10px'; + var animation = target.animate({ [idlName]: ['calc(2em + 20%)', + 'calc(5rem + 50%)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(30px + 20%)' }]); + }, property + ': units "calc" onto "px"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'calc(10px + 10%)'; + var animation = target.animate({ [idlName]: ['calc(20px + 20%)', + 'calc(2em + 3rem + 40%)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'calc(30px + 30%)' }]); + }, property + ': calc'); + }, + +}; + +const positiveNumberType = { + testInterpolation: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: [1.1, 1.5] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: '1.1' }, + { time: 500, expected: '1.3' }, + { time: 1000, expected: '1.5' }]); + }, property + ' supports animating as a positive number'); + }, + + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 1.1; + var animation = target.animate({ [idlName]: [1.1, 1.5] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '2.2' }]); + }, property + ': positive number'); + }, + +}; + +const visibilityType = { + testInterpolation: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['visible', 'hidden'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'visible' }, + { time: 999, expected: 'visible' }, + { time: 1000, expected: 'hidden' }]); + }, property + ' uses visibility animation when animating ' + + 'from "visible" to "hidden"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['hidden', 'visible'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'hidden' }, + { time: 1, expected: 'visible' }, + { time: 1000, expected: 'visible' }]); + }, property + ' uses visibility animation when animating ' + + 'from "hidden" to "visible"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['hidden', 'collapse'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'hidden' }, + { time: 499, expected: 'hidden' }, + { time: 500, expected: 'collapse' }, + { time: 1000, expected: 'collapse' }]); + }, property + ' uses visibility animation when animating ' + + 'from "hidden" to "collapse"'); + + test(function(t) { + // Easing: http://cubic-bezier.com/#.68,-.55,.26,1.55 + // With this curve, the value is less than 0 till about 34% + // also more than 1 since about 63% + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = + target.animate({ [idlName]: ['visible', 'hidden'] }, + { duration: 1000, fill: 'both', + easing: 'cubic-bezier(0.68, -0.55, 0.26, 1.55)' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'visible' }, + { time: 1, expected: 'visible' }, + { time: 330, expected: 'visible' }, + { time: 340, expected: 'visible' }, + { time: 620, expected: 'visible' }, + { time: 630, expected: 'hidden' }, + { time: 1000, expected: 'hidden' }]); + }, property + ' uses visibility animation when animating ' + + 'from "visible" to "hidden" with easeInOutBack easing'); + }, + + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'visible'; + var animation = target.animate({ [idlName]: ['visible', 'hidden'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'visible' }, + { time: 1000, expected: 'visible' }]); + }, property + ': onto "visible"'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'hidden'; + var animation = target.animate({ [idlName]: ['hidden', 'visible'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'hidden' }, + { time: 1000, expected: 'visible' }]); + }, property + ': onto "hidden"'); + }, + +}; + +const colorType = { + testInterpolation: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['rgb(255, 0, 0)', + 'rgb(0, 0, 255)'] }, + 1000); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(128, 0, 128)' }]); + }, property + ' supports animating as color of rgb()'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['#ff0000', '#0000ff'] }, + 1000); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(128, 0, 128)' }]); + }, property + ' supports animating as color of #RGB'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['hsl(0, 100%, 50%)', + 'hsl(240, 100%, 50%)'] }, + 1000); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgb(128, 0, 128)' }]); + }, property + ' supports animating as color of hsl()'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['#ff000066', '#0000ffcc'] }, + 1000); + // R: 255 * (0.4 * 0.5) / 0.6 = 85 + // G: 255 * (0.8 * 0.5) / 0.6 = 170 + testAnimationSamples(animation, idlName, + [{ time: 500, expected: 'rgba(85, 0, 170, 0.6)' }]); + }, property + ' supports animating as color of #RGBa'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['rgba(255, 0, 0, 0.4)', + 'rgba(0, 0, 255, 0.8)'] }, + 1000); + testAnimationSamples(animation, idlName, // Same as above. + [{ time: 500, expected: 'rgba(85, 0, 170, 0.6)' }]); + }, property + ' supports animating as color of rgba()'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['hsla(0, 100%, 50%, 0.4)', + 'hsla(240, 100%, 50%, 0.8)'] }, + 1000); + testAnimationSamples(animation, idlName, // Same as above. + [{ time: 500, expected: 'rgba(85, 0, 170, 0.6)' }]); + }, property + ' supports animating as color of hsla()'); + }, + + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + var animation = target.animate({ [idlName]: ['rgb(255, 0, 0)', + 'rgb(0, 0, 255)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'rgb(255, 128, 128)' }, + // The value at 50% is interpolated + // from 'rgb(128+255, 128, 128)' + // to 'rgb(128, 128, 128+255)'. + { time: 500, expected: 'rgb(255, 128, 255)' }]); + }, property + ' supports animating as color of rgb() with overflowed ' + + 'from and to values'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + var animation = target.animate({ [idlName]: ['#ff0000', '#0000ff'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'rgb(255, 128, 128)' }]); + }, property + ' supports animating as color of #RGB'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + var animation = target.animate({ [idlName]: ['hsl(0, 100%, 50%)', + 'hsl(240, 100%, 50%)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'rgb(255, 128, 128)' }]); + }, property + ' supports animating as color of hsl()'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + var animation = target.animate({ [idlName]: ['#ff000066', '#0000ffcc'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: 'rgb(230, 128, 128)' }]); + }, property + ' supports animating as color of #RGBa'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + var animation = target.animate({ [idlName]: ['rgba(255, 0, 0, 0.4)', + 'rgba(0, 0, 255, 0.8)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, // Same as above. + [{ time: 0, expected: 'rgb(230, 128, 128)' }]); + }, property + ' supports animating as color of rgba()'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rgb(128, 128, 128)'; + var animation = target.animate({ [idlName]: ['hsla(0, 100%, 50%, 0.4)', + 'hsla(240, 100%, 50%, 0.8)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, // Same as above. + [{ time: 0, expected: 'rgb(230, 128, 128)' }]); + }, property + ' supports animating as color of hsla()'); + }, + +}; + +const transformListType = { + testInterpolation: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['translate(200px, -200px)', + 'translate(400px, 400px)'] }, + 1000); + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ 1, 0, 0, 1, 300, 100 ] }]); + }, property + ': translate'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['rotate(45deg)', + 'rotate(135deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 0, 0] }]); + }, property + ': rotate'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['scale(3)', 'scale(5)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ 4, 0, 0, 4, 0, 0 ] }]); + }, property + ': scale'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: ['skew(30deg, 60deg)', + 'skew(60deg, 30deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ 1, Math.tan(Math.PI / 4), + Math.tan(Math.PI / 4), 1, + 0, 0] }]); + }, property + ': skew'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = + target.animate({ [idlName]: ['translateX(100px) rotate(45deg)', + 'translateX(200px) rotate(135deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 150, 0 ] }]); + }, property + ': rotate and translate'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = + target.animate({ [idlName]: ['rotate(45deg) translateX(100px)', + 'rotate(135deg) translateX(200px)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI / 2), + Math.sin(Math.PI / 2), + -Math.sin(Math.PI / 2), + Math.cos(Math.PI / 2), + 150 * Math.cos(Math.PI / 2), + 150 * Math.sin(Math.PI / 2) ] }]); + }, property + ': translate and rotate'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = // matrix(0, 1, -1, 0, 0, 100) + target.animate({ [idlName]: ['rotate(90deg) translateX(100px)', + // matrix(-1, 0, 0, -1, 200, 0) + 'translateX(200px) rotate(180deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI * 3 / 4), + Math.sin(Math.PI * 3 / 4), + -Math.sin(Math.PI * 3 / 4), + Math.cos(Math.PI * 3 / 4), + 100, 50 ] }]); + }, property + ': mismatch order of translate and rotate'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = // Same matrices as above. + target.animate({ [idlName]: [ 'matrix(0, 1, -1, 0, 0, 100)', + 'matrix(-1, 0, 0, -1, 200, 0)' ] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: [ Math.cos(Math.PI * 3 / 4), + Math.sin(Math.PI * 3 / 4), + -Math.sin(Math.PI * 3 / 4), + Math.cos(Math.PI * 3 / 4), + 100, 50 ] }]); + }, property + ': matrix'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = + target.animate({ [idlName]: [ 'rotate3d(1, 1, 0, 0deg)', + 'rotate3d(1, 1, 0, 90deg)'] }, + 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: rotate3dToMatrix(1, 1, 0, Math.PI / 4) }]); + }, property + ': rotate3d'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + // To calculate expected matrices easily, generate input matrices from + // rotate3d. + var from = rotate3dToMatrix3d(1, 1, 0, Math.PI / 4); + var to = rotate3dToMatrix3d(1, 1, 0, Math.PI * 3 / 4); + var animation = + target.animate({ [idlName]: [ from, to ] }, 1000); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 500, expected: rotate3dToMatrix(1, 1, 0, Math.PI * 2 / 4) }]); + }, property + ': matrix3d'); + + }, + + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'translateX(100px)'; + var animation = target.animate({ [idlName]: ['translateX(-200px)', + 'translateX(500px)'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + testAnimationSampleMatrices(animation, idlName, + [ { time: 0, expected: [ 1, 0, 0, 1, -100, 0 ] }, + { time: 1000, expected: [ 1, 0, 0, 1, 600, 0 ] }]); + }, property + ': translate'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rotate(45deg)'; + var animation = target.animate({ [idlName]: ['rotate(-90deg)', + 'rotate(90deg)'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ Math.cos(-Math.PI / 4), + Math.sin(-Math.PI / 4), + -Math.sin(-Math.PI / 4), + Math.cos(-Math.PI / 4), + 0, 0] }, + { time: 1000, expected: [ Math.cos(Math.PI * 3 / 4), + Math.sin(Math.PI * 3 / 4), + -Math.sin(Math.PI * 3 / 4), + Math.cos(Math.PI * 3 / 4), + 0, 0] }]); + }, property + ': rotate'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'scale(2)'; + var animation = target.animate({ [idlName]: ['scale(-3)', 'scale(5)'] }, + { duration: 1000, fill: 'both', + composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ -6, 0, 0, -6, 0, 0 ] }, // scale(-3) scale(2) + { time: 1000, expected: [ 10, 0, 0, 10, 0, 0 ] }]); // scale(5) scale(2) + }, property + ': scale'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + // matrix(1, tan(10deg), tan(10deg), 1) + target.style[idlName] = 'skew(10deg, 10deg)'; + var animation = // matrix(1, tan(20deg), tan(-30deg), 1) + target.animate({ [idlName]: ['skew(-30deg, 20deg)', + // matrix(1, tan(-30deg), tan(20deg), 1) + 'skew(20deg, -30deg)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + // matrix at 0%. + // [ 1 tan(10deg) ] [ 1 tan(-30deg) ] + // [ tan(10deg) 1 ] [ tan(20deg) 1 ] = + // + // [ 1 + tan(10deg) * tan(20deg) tan(-30deg) + tan(10deg) ] + // [ tan(10deg) + tan(20deg) tan(10deg) * tan(-30deg) + 1 ] + + // matrix at 100%. + // [ 1 tan(10deg) ] [ 1 tan(20deg) ] + // [ tan(10deg) 1 ] [ tan(-30deg) 1 ] = + // + // [ 1 + tan(10deg) * tan(-30deg) tan(20deg) + tan(10deg) ] + // [ tan(10deg) + tan(-30deg) tan(10deg) * tan(20deg) + 1 ] + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 1 + Math.tan(Math.PI/18) * Math.tan(Math.PI/9), + Math.tan(Math.PI/18) + Math.tan(Math.PI/9), + Math.tan(-Math.PI/6) + Math.tan(Math.PI/18), + 1 + Math.tan(Math.PI/18) * Math.tan(-Math.PI/6), + 0, 0] }, + { time: 1000, expected: [ 1 + Math.tan(Math.PI/18) * Math.tan(-Math.PI/6), + Math.tan(Math.PI/18) + Math.tan(-Math.PI/6), + Math.tan(Math.PI/9) + Math.tan(Math.PI/18), + 1 + Math.tan(Math.PI/18) * Math.tan(Math.PI/9), + 0, 0] }]); + }, property + ': skew'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + // matrix(1, 0, 0, 1, 100, 0) + target.style[idlName] = 'translateX(100px)'; + var animation = // matrix(0, 1, -1, 0, 0, 0) + target.animate({ [idlName]: ['rotate(90deg)', + // matrix(-1, 0, 0, -1, 0, 0) + 'rotate(180deg)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 0, 1, -1, 0, 100, 0 ] }, + { time: 1000, expected: [ -1, 0, 0, -1, 100, 0 ] }]); + }, property + ': rotate on translate'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + // matrix(0, 1, -1, 0, 0, 0) + target.style[idlName] = 'rotate(90deg)'; + var animation = // matrix(1, 0, 0, 1, 100, 0) + target.animate({ [idlName]: ['translateX(100px)', + // matrix(1, 0, 0, 1, 200, 0) + 'translateX(200px)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 0, 1, -1, 0, 0, 100 ] }, + { time: 1000, expected: [ 0, 1, -1, 0, 0, 200 ] }]); + }, property + ': translate on rotate'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'matrix(0, 1, -1, 0, 0, 0)'; + var animation = // Same matrices as above. + target.animate({ [idlName]: [ 'matrix(1, 0, 0, 1, 100, 0)', + 'matrix(1, 0, 0, 1, 200, 0)' ] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: [ 0, 1, -1, 0, 0, 100 ] }, + { time: 1000, expected: [ 0, 1, -1, 0, 0, 200 ] }]); + }, property + ': matrix'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rotate3d(1, 1, 0, 45deg)'; + var animation = + target.animate({ [idlName]: [ 'rotate3d(1, 1, 0, -90deg)', + 'rotate3d(1, 1, 0, 90deg)'] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: rotate3dToMatrix(1, 1, 0, -Math.PI / 4) }, + { time: 1000, expected: rotate3dToMatrix(1, 1, 0, 3 * Math.PI / 4) }]); + }, property + ': rotate3d'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + // To calculate expected matrices easily, generate input matrices from + // rotate3d. + target.style[idlName] = rotate3dToMatrix3d(1, 1, 0, Math.PI / 4); + var from = rotate3dToMatrix3d(1, 1, 0, -Math.PI / 2); + var to = rotate3dToMatrix3d(1, 1, 0, Math.PI / 2); + var animation = + target.animate({ [idlName]: [ from, to ] }, + { duration: 1000, fill: 'both', composite: 'add' }); + + testAnimationSampleMatrices(animation, idlName, + [{ time: 0, expected: rotate3dToMatrix(1, 1, 0, -Math.PI / 4) }, + { time: 1000, expected: rotate3dToMatrix(1, 1, 0, 3 * Math.PI / 4) }]); + }, property + ': matrix3d'); + }, + +}; + +const filterListType = { + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'blur(10px)'; + var animation = target.animate({ [idlName]: ['blur(20px)', + 'blur(50px)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'blur(10px) blur(20px)' }]); + }, property + ': blur on blur'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'blur(10px)'; + var animation = target.animate({ [idlName]: ['brightness(80%)', + 'brightness(40%)'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'blur(10px) brightness(0.8)' }]); + }, property + ': different filter functions'); + }, +}; + +const textShadowListType = { + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rgb(0, 0, 0) 0px 0px 0px'; + var animation = + target.animate({ [idlName]: [ 'rgb(120, 120, 120) 10px 10px 10px', + 'rgb(120, 120, 120) 10px 10px 10px'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'rgb(0, 0, 0) 0px 0px 0px, ' + + 'rgb(120, 120, 120) 10px 10px 10px' }]); + }, property + ': shadow'); + }, +}; + + +const boxShadowListType = { + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 'rgb(0, 0, 0) 0px 0px 0px 0px'; + var animation = + target.animate({ [idlName]: [ 'rgb(120, 120, 120) 10px 10px 10px 0px', + 'rgb(120, 120, 120) 10px 10px 10px 0px'] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, + [ { time: 0, expected: 'rgb(0, 0, 0) 0px 0px 0px 0px, ' + + 'rgb(120, 120, 120) 10px 10px 10px 0px' }]); + }, property + ': shadow'); + }, +}; + +const types = { + color: colorType, + discrete: discreteType, + filterList: filterListType, + integer: integerType, + length: lengthType, + percentage: percentageType, + lengthPercentageOrCalc: lengthPercentageOrCalcType, + positiveNumber: positiveNumberType, + transformList: transformListType, + visibility: visibilityType, + boxShadowList: boxShadowListType, + textShadowList: textShadowListType, +}; +
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters.html new file mode 100644 index 0000000..11c865a --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters.html
@@ -0,0 +1,210 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Keyframe spacing tests on filters</title> +<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +"use strict"; + +// Help function for testing the computed offsets by the distance array. +function assert_animation_offsets(anim, dist) { + const frames = anim.effect.getKeyframes(); + const cumDist = dist.reduce( (prev, curr) => { + prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]); + return prev; + }, []); + + const total = cumDist[cumDist.length - 1]; + for (var i = 0; i < frames.length; ++i) { + assert_equals(frames[i].computedOffset, cumDist[i] / total, + 'computedOffset of frame ' + i); + } +} + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'blur(1px)'}, + { filter: 'none' }, // The default value is 0px. + { filter: 'blur(10px)' }, + { filter: 'blur(8px)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, 1, 10, (10 - 8) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on blur' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'brightness(50%)'}, + { filter: 'none' }, // The default value is 1. + { filter: 'brightness(2)' }, + { filter: 'brightness(175%)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, (1 - 0.5), (2 - 1), (2.0 - 1.75) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on brightness' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'contrast(50%)'}, + { filter: 'none' }, // The default value is 1. + { filter: 'contrast(2)' }, + { filter: 'contrast(175%)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, (1 - 0.5), (2 - 1), (2.0 - 1.75) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on contrast' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'drop-shadow(10px 10px 10px blue)'}, + { filter: 'none' }, + // none filter: 'drop-shadow(0, 0, 0, rgba(0, 0, 0, 0))' + { filter: 'drop-shadow(5px 5px 1px black)' }, + { filter: 'drop-shadow(20px 20px yellow)' } ], + { spacing: 'paced(filter)' }); + + // Blue: rgba(0, 0, 255, 1.0) = rgba( 0%, 0%, 100%, 100%). + // Black: rgba(0, 0, 0, 1.0) = rgba( 0%, 0%, 0%, 100%). + // Yellow: rgba(255, 255, 0, 1.0) = rgba(100%, 100%, 0%, 100%). + var dist = [ 0, + Math.sqrt(10 * 10 + 10 * 10 + 10 * 10 + (1 * 1 + 1 * 1)), + Math.sqrt(5 * 5 + 5 * 5 + 1 * 1 + (1 * 1)), + Math.sqrt(15 * 15 + 15 * 15 + 1 * 1 + (1 * 1 + 1 * 1)) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on drop-shadow' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'drop-shadow(10px 10px 10px)'}, + { filter: 'drop-shadow(0 0)' }, + { filter: 'drop-shadow(5px 5px 1px black)' }, + { filter: 'drop-shadow(20px 20px yellow)' } ], + { spacing: 'paced(filter)' }); + + // Black: rgba(0, 0, 0, 1.0) = rgba( 0%, 0%, 0%, 100%). + // Yellow: rgba(255, 255, 0, 1.0) = rgba(100%, 100%, 0%, 100%). + var dist = [ 0, + Math.sqrt(10 * 10 + 10 * 10 + 10 * 10), + 0, // The distance is zero because the 2nd frame uses no-color. + Math.sqrt(15 * 15 + 15 * 15 + 1 * 1 + (1 * 1 + 1 * 1)) ]; + assert_animation_offsets(anim, dist); +}, 'Test getting zero distance when computing distance between ' + + 'color and no-color on drop-shadow'); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'grayscale(50%)'}, + { filter: 'none' }, // The default value is 0. + // Values of grayscale over 100% are clamped to 1. + { filter: 'grayscale(2)' }, + { filter: 'grayscale(75%)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, 0.5, 1, (1.0 - 0.75) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on grayscale' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'hue-rotate(180deg)'}, + { filter: 'none' }, // The default value is 0deg. + { filter: 'hue-rotate(720deg)' }, + { filter: 'hue-rotate(-180deg)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, 180, 720, 720 + 180 ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on hue-rotate' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'invert(50%)'}, + { filter: 'none' }, // The default value is 0. + // Values of invert over 100% are clamped to 1. + { filter: 'invert(2)' }, + { filter: 'invert(75%)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, 0.5, 1, (1.0 - 0.75) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on invert' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'opacity(50%)'}, + { filter: 'none' }, // The default value is 1. + // Values of opacity over 100% are clamped to 1. + { filter: 'opacity(2)' }, + { filter: 'opacity(75%)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, (1 - 0.5), (1 - 1), (1.0 - 0.75) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on opacity' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'saturate(50%)'}, + { filter: 'none' }, // The default value is 1. + { filter: 'saturate(2)' }, + { filter: 'saturate(175%)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, (1 - 0.5), (2 - 1), (2.0 - 1.75) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on saturate' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'sepia(50%)'}, + { filter: 'none' }, // The default value is 0. + // Values of sepia over 100% are clamped to 1. + { filter: 'sepia(2)' }, + { filter: 'sepia(75%)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, 0.5, 1, (1.0 - 0.75) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on sepia' ); + + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'grayscale(50%) opacity(100%) blur(5px)' }, + { filter: 'none' }, + // none filter: 'grayscale(0) opacity(1) blur(0px)' + { filter: 'grayscale(100%) opacity(50%) blur(1px)' }, + { filter: 'grayscale(75%) opacity(50%)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, + Math.sqrt(0.5 * 0.5 + 5 * 5), + Math.sqrt(1 * 1 + 0.5 * 0.5 + 1 * 1), + Math.sqrt(0.25 * 0.25 + 1 * 1) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on filter function lists' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { filter: 'grayscale(50%) opacity(100%)' }, + { filter: 'opacity(10%) grayscale(50%)' }, + { filter: 'grayscale(100%) opacity(50%) blur(1px)' }, + { filter: 'grayscale(75%) opacity(50%)' } ], + { spacing: 'paced(filter)' }); + + var dist = [ 0, + 0, + 0, + Math.sqrt(0.25 * 0.25 + 1 * 1) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on filter function lists' ); + +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes.html new file mode 100644 index 0000000..9f7cfae --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes.html
@@ -0,0 +1,152 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Keyframe spacing tests on shapes</title> +<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +"use strict"; + +// Help function for testing the computed offsets by the distance array. +function assert_animation_offsets(anim, dist) { + const frames = anim.effect.getKeyframes(); + const cumDist = dist.reduce( (prev, curr) => { + prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]); + return prev; + }, []); + + const total = cumDist[cumDist.length - 1]; + for (var i = 0; i < frames.length; ++i) { + assert_equals(frames[i].computedOffset, cumDist[i] / total, + 'computedOffset of frame ' + i); + } +} + +test(function(t) { + var anim = + createDiv(t).animate([ { clipPath: 'circle(20px)' }, + { clipPath: 'ellipse(10px 20px)' }, + { clipPath: 'polygon(50px 0px, 100px 50px, ' + + ' 50px 100px, 0px 50px)' }, + { clipPath: 'inset(20px round 10px)' } ], + { spacing: 'paced(clip-path)' }); + + const frames = anim.effect.getKeyframes(); + const slots = frames.length - 1; + for (var i = 0; i < frames.length; ++i) { + assert_equals(frames[i].computedOffset, i / slots, + 'computedOffset of frame ' + i); + } +}, 'Test falling back to distribute spacing when using different basic shapes'); + +test(function(t) { + var anim = + createDiv(t).animate([ { clipPath: 'circle(10px)' }, + { clipPath: 'circle(20px) content-box' }, + { clipPath: 'circle(70px)' }, + { clipPath: 'circle(10px) padding-box' } ], + { spacing: 'paced(clip-path)' }); + + const frames = anim.effect.getKeyframes(); + const slots = frames.length - 1; + for (var i = 0; i < frames.length; ++i) { + assert_equals(frames[i].computedOffset, i / slots, + 'computedOffset of frame ' + i); + } +}, 'Test falling back to distribute spacing when using different ' + + 'reference boxes'); + +test(function(t) { + // 1st: circle(calc(20px) at calc(20px + 0%) calc(10px + 0%)) + // 2nd: circle(calc(50px) at calc(10px + 0%) calc(10px + 0%)) + // 3rd: circle(70px at calc(10px + 0%) calc(50px + 0%)) + // 4th: circle(10px at calc(50px + 0%) calc(30px + 0%)) + var anim = + createDiv(t).animate([ { clipPath: 'circle(calc(10px + 10px) ' + + ' at 20px 10px)' }, + { clipPath: 'circle(calc(20px + 30px) ' + + ' at 10px 10px)' }, + { clipPath: 'circle(70px at 10px 50px)' }, + { clipPath: 'circle(10px at 50px 30px)' } ], + { spacing: 'paced(clip-path)' }); + + var dist = [ 0, + Math.sqrt(30 * 30 + 10 * 10), + Math.sqrt(20 * 20 + 40 * 40), + Math.sqrt(60 * 60 + 40 * 40 + 20 * 20) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on circle' ); + +test(function(t) { + // 1st: ellipse(20px calc(20px) at calc(0px + 50%) calc(0px + 50%)) + // 2nd: ellipse(20px calc(50px) at calc(0px + 50%) calc(0px + 50%)) + // 3rd: ellipse(30px 70px at calc(0px + 50%) calc(0px + 50%)) + // 4th: ellipse(30px 10px at calc(0px + 50%) calc(0px + 50%)) + var anim = + createDiv(t).animate([ { clipPath: 'ellipse(20px calc(10px + 10px))' }, + { clipPath: 'ellipse(20px calc(20px + 30px))' }, + { clipPath: 'ellipse(30px 70px)' }, + { clipPath: 'ellipse(30px 10px)' } ], + { spacing: 'paced(clip-path)' }); + + var dist = [ 0, + Math.sqrt(30 * 30), + Math.sqrt(10 * 10 + 20 * 20), + Math.sqrt(60 * 60) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on ellipse' ); + +test(function(t) { + // 1st: polygon(nonzero, 50px 0px, 100px 50px, 50px 100px, 0px 50px) + // 2nd: polygon(nonzero, 40px 0px, 100px 70px, 10px 100px, 0px 70px) + // 3rd: polygon(nonzero, 100px 0px, 100px 100px, 10px 80px, 0px 50px) + // 4th: polygon(nonzero, 100px 100px, -10px 100px, 20px 80px, 20px 50px) + var anim = + createDiv(t).animate([ { clipPath: 'polygon(50px 0px, 100px 50px, ' + + ' 50px 100px, 0px 50px)' }, + { clipPath: 'polygon(40px 0px, 100px 70px, ' + + ' 10px 100px, 0px 70px)' }, + { clipPath: 'polygon(100px 0px, 100px 100px, ' + + ' 10px 80px, 0px 50px)' }, + { clipPath: 'polygon(100px 100px, -10px 100px, ' + + ' 20px 80px, 20px 50px)' } ], + { spacing: 'paced(clip-path)' }); + + var dist = [ 0, + Math.sqrt(10 * 10 + 20 * 20 + 40 * 40 + 20 * 20), + Math.sqrt(60 * 60 + 30 * 30 + 20 * 20 + 20 * 20), + Math.sqrt(100 * 100 + 110 * 110 + 10 * 10 + 20 * 20) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on polygon' ); + +test(function(t) { + // Note: Rounding corners are 4 CSS pair values and + // each pair has x & y components. + // 1st: inset(5px 5px 5px 5px round 40px 30px 20px 5px / 40px 30px 20px 5px) + // 2nd: inset(10px 5px 10px 5px round 50px 60px / 50px 60px) + // 3rd: inset(40px 40px 40px 40px round 10px / 10px) + // 4th: inset(30px 40px 30px 40px round 20px / 20px) + var anim = + createDiv(t).animate([ { clipPath: 'inset(5px 5px 5px 5px ' + + ' round 40px 30px 20px 5px)' }, + { clipPath: 'inset(10px 5px round 50px 60px)' }, + { clipPath: 'inset(40px 40px round 10px)' }, + { clipPath: 'inset(30px 40px round 20px)' } ], + { spacing: 'paced(clip-path)' }); + + var dist = [ 0, + Math.sqrt(5 * 5 * 2 + (50 - 40) * (50 - 40) * 2 + + (60 - 30) * (60 - 30) * 2 + + (50 - 20) * (50 - 20) * 2 + + (60 - 5) * (60 - 5) * 2), + Math.sqrt(30 * 30 * 2 + 35 * 35 * 2 + (50 - 10) * (50 - 10) * 4 + + (60 - 10) * (60 - 10) * 4), + Math.sqrt(10 * 10 * 2 + (20 - 10) * (20 - 10) * 8) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on inset' ); + +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform.html new file mode 100644 index 0000000..189a25e --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform.html
@@ -0,0 +1,242 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Keyframe spacing tests on transform</title> +<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +"use strict"; + +const pi = Math.PI; +const cos = Math.cos; +const sin = Math.sin; +const tan = Math.tan; +const sqrt = Math.sqrt; + +// Help function for testing the computed offsets by the distance array. +function assert_animation_offsets(anim, dist) { + const epsilon = 0.00000001; + const frames = anim.effect.getKeyframes(); + const cumDist = dist.reduce( (prev, curr) => { + prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]); + return prev; + }, []); + + const total = cumDist[cumDist.length - 1]; + for (var i = 0; i < frames.length; ++i) { + assert_approx_equals(frames[i].computedOffset, cumDist[i] / total, + epsilon, 'computedOffset of frame ' + i); + } +} + +function getAngleDist(rotate1, rotate2) { + function quaternion(axis, angle) { + var x = axis[0] * sin(angle/2.0); + var y = axis[1] * sin(angle/2.0); + var z = axis[2] * sin(angle/2.0); + var w = cos(angle/2.0); + return { 'x': x, 'y': y, 'z': z, 'w': w }; + } + var q1 = quaternion(rotate1.axis, rotate1.angle); + var q2 = quaternion(rotate2.axis, rotate2.angle); + var dotProduct = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + return 2.0 * Math.acos(dotProduct); +} + +function createMatrix(elements, Is3D) { + return (Is3D ? "matrix3d" : "matrix") + "(" + elements.join() + ")"; +} + +test(function(t) { + var anim = createDiv(t).animate([ { transform: "none" }, + { transform: "translate(-20px)" }, + { transform: "translate(100px)" }, + { transform: "translate(50px)"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, [ 0, 20, 120, 50 ]); +}, 'Test spacing on translate' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { transform: "none" }, + { transform: "translate3d(-20px, 10px, 100px)" }, + { transform: "translate3d(100px, 200px, 50px)" }, + { transform: "translate(50px, -10px)"} ], + { spacing: "paced(transform)" }); + var dist = [ 0, + sqrt(20 * 20 + 10 * 10 + 100 * 100), + sqrt(120 * 120 + 190 * 190 + 50 * 50), + sqrt(50 * 50 + 210 * 210 + 50 * 50) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on translate3d' ); + +test(function(t) { + var anim = createDiv(t).animate([ { transform: "scale(0.5)" }, + { transform: "scale(4.5)" }, + { transform: "scale(2.5)" }, + { transform: "none"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, [ 0, 4.0, 2.0, 1.5 ]); +}, 'Test spacing on scale' ); + +test(function(t) { + var anim = createDiv(t).animate([ { transform: "scale(0.5, 0.5)" }, + { transform: "scale3d(4.5, 5.0, 2.5)" }, + { transform: "scale3d(2.5, 1.0, 2.0)" }, + { transform: "scale3d(1, 0.5, 1.0)"} ], + { spacing:"paced(transform)" }); + var dist = [ 0, + sqrt(4.0 * 4.0 + 4.5 * 4.5 + 1.5 * 1.5), + sqrt(2.0 * 2.0 + 4.0 * 4.0 + 0.5 * 0.5), + sqrt(1.5 * 1.5 + 0.5 * 0.5 + 1.0 * 1.0) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on scale3d' ); + +test(function(t) { + var anim = createDiv(t).animate([ { transform: "rotate(60deg)" }, + { transform: "none" }, + { transform: "rotate(720deg)" }, + { transform: "rotate(-360deg)"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, [ 0, 60, 720, 1080 ]); +}, 'Test spacing on rotate' ); + +test(function(t) { + var anim = createDiv(t).animate([ { transform: "rotate3d(1,0,0,60deg)" }, + { transform: "rotate3d(1,0,0,70deg)" }, + { transform: "rotate3d(0,0,1,-110deg)" }, + { transform: "rotate3d(1,0,0,219deg)"} ], + { spacing: "paced(transform)" }); + var dist = [ 0, + getAngleDist({ axis: [1,0,0], angle: 60 * pi / 180 }, + { axis: [1,0,0], angle: 70 * pi / 180 }), + getAngleDist({ axis: [0,1,0], angle: 70 * pi / 180 }, + { axis: [0,0,1], angle: -110 * pi / 180 }), + getAngleDist({ axis: [0,0,1], angle: -110 * pi / 180 }, + { axis: [1,0,0], angle: 219 * pi / 180 }) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on rotate3d' ); + +test(function(t) { + var anim = createDiv(t).animate([ { transform: "skew(60deg)" }, + { transform: "none" }, + { transform: "skew(-90deg)" }, + { transform: "skew(90deg)"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, [ 0, 60, 90, 180 ]); +}, 'Test spacing on skew' ); + +test(function(t) { + var anim = createDiv(t).animate([ { transform: "skew(60deg, 30deg)" }, + { transform: "none" }, + { transform: "skew(-90deg, 60deg)" }, + { transform: "skew(90deg, 60deg)"} ], + { spacing: "paced(transform)" }); + var dist = [ 0, + sqrt(60 * 60 + 30 * 30), + sqrt(90 * 90 + 60 * 60), + sqrt(180 * 180 + 0) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on skew along both X and Y' ); + +test(function(t) { + // We calculate the distance of two perspective functions by converting them + // into two matrix3ds, and then do matrix decomposition to get two + // perspective vectors, so the equivalent perspective vectors are: + // perspective 1: (0, 0, -1/128, 1); + // perspective 2: (0, 0, -1/infinity = 0, 1); + // perspective 3: (0, 0, -1/1024, 1); + // perspective 4: (0, 0, -1/32, 1); + var anim = createDiv(t).animate([ { transform: "perspective(128px)" }, + { transform: "none" }, + { transform: "perspective(1024px)" }, + { transform: "perspective(32px)"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, [ 0, 1/128, 1/1024, 1/32 - 1/1024 ]); +}, 'Test spacing on perspective' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { transform: "none" }, + { transform: "rotate(180deg) translate(0px)" }, + { transform: "rotate(180deg) translate(1000px)" }, + { transform: "rotate(360deg) translate(1000px)"} ], + { spacing: "paced(transform)" }); + var dist = [ 0, + sqrt(pi * pi + 0), + sqrt(1000 * 1000), + sqrt(pi * pi + 0) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on matched transform lists' ); + +test(function(t) { + // matrix1 => translate(100px, 50px), skewX(60deg). + // matrix2 => translate(1000px), rotate(180deg). + // matrix3 => translate(1000px), scale(1.5, 0.7). + const matrix1 = createMatrix([ 1, 0, tan(pi/4.0), 1, 100, 50 ]); + const matrix2 = createMatrix([ cos(pi), sin(pi), + -sin(pi), cos(pi), + 1000, 0 ]); + const matrix3 = createMatrix([ 1.5, 0, 0, 0.7, 1000, 0 ]); + var anim = createDiv(t).animate([ { transform: "none" }, + { transform: matrix1 }, + { transform: matrix2 }, + { transform: matrix3 } ], + { spacing: "paced(transform)" }); + var dist = [ 0, + sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4), + sqrt(900 * 900 + 50 * 50 + pi * pi + pi/4 * pi/4), + sqrt(pi * pi + 0.5 * 0.5 + 0.3 * 0.3) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on matrix' ); + +test(function(t) { + // matrix1 => translate3d(100px, 50px, -10px), skew(60deg). + // matrix2 => translate3d(1000px, 0, 0), rotate3d(1, 0, 0, 180deg). + // matrix3 => translate3d(1000px, 0, 0), scale3d(1.5, 0.7, 2.2). + const matrix1 = createMatrix([ 1, 0, 0, 0, + tan(pi/4.0), 1, 0, 0, + 0, 0, 1, 0, + 100, 50, -10, 1 ], true); + const matrix2 = createMatrix([ 1, 0, 0, 0, + 0, cos(pi), sin(pi), 0, + 0, -sin(pi), cos(pi), 0, + 1000, 0, 0, 1 ], true); + const matrix3 = createMatrix([ 1.5, 0, 0, 0, + 0, 0.7, 0, 0, + 0, 0, 2.2, 0, + 1000, 0, 0, 1 ], true); + var anim = createDiv(t).animate([ { transform: "none" }, + { transform: matrix1 }, + { transform: matrix2 }, + { transform: matrix3 } ], + { spacing: "paced(transform)" }); + var dist = [ 0, + sqrt(100 * 100 + 50 * 50 + 10 * 10 + pi/4 * pi/4), + sqrt(900 * 900 + 50 * 50 + 10 * 10 + pi/4 * pi/4 + pi * pi), + sqrt(0.5 * 0.5 + 0.3 * 0.3 + 1.2 * 1.2 + pi * pi) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on matrix3d' ); + +test(function(t) { + var anim = + createDiv(t).animate([ { transform: "none" }, + { transform: "translate(100px, 50px) skew(45deg)" }, + { transform: "translate(1000px) " + + "rotate3d(1, 0, 0, 180deg)" }, + { transform: "translate(1000px) " + + "scale3d(2.5, 0.5, 0.7)" } ], + { spacing: "paced(transform)" }); + + var dist = [ 0, + sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4), + sqrt(900 * 900 + 50 * 50 + pi/4 * pi/4 + pi * pi), + sqrt(1.5 * 1.5 + 0.5 * 0.5 + 0.3 * 0.3 + pi * pi) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on mismatched transform list' ); + +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/type-per-property.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/type-per-property.html deleted file mode 100644 index 683b0093..0000000 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/animation-types/type-per-property.html +++ /dev/null
@@ -1,569 +0,0 @@ -<!DOCTYPE html> -<meta charset=utf-8> -<title>Tests for animation types</title> -<link rel="help" href="https://w3c.github.io/web-animations/#animation-types"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="../../testcommon.js"></script> -<style> -html { - font-size: 10px; -} -</style> -<body> -<div id="log"></div> -<script> -"use strict"; - -var gCSSProperties = { - "align-content": { - // https://drafts.csswg.org/css-align/#propdef-align-content - tests: [ - discrete("flex-start", "flex-end") - ] - }, - "align-items": { - // https://drafts.csswg.org/css-align/#propdef-align-items - tests: [ - discrete("flex-start", "flex-end") - ] - }, - "align-self": { - // https://drafts.csswg.org/css-align/#propdef-align-self - tests: [ - discrete("flex-start", "flex-end") - ] - }, - "clip-rule": { - // https://drafts.fxtf.org/css-masking-1/#propdef-clip-rule - tests: [ - discrete("evenodd", "nonzero") - ] - }, - "color-interpolation": { - // https://svgwg.org/svg2-draft/painting.html#ColorInterpolationProperty - tests: [ - discrete("linearRGB", "auto") - ] - }, - "color-interpolation-filters": { - // https://drafts.fxtf.org/filters-1/#propdef-color-interpolation-filters - tests: [ - discrete("sRGB", "linearRGB") - ] - }, - "dominant-baseline": { - // https://drafts.csswg.org/css-inline/#propdef-dominant-baseline - tests: [ - discrete("ideographic", "alphabetic") - ] - }, - "fill-rule": { - // https://svgwg.org/svg2-draft/painting.html#FillRuleProperty - tests: [ - discrete("evenodd", "nonzero") - ] - }, - "flex-basis": { - // https://drafts.csswg.org/css-flexbox/#propdef-flex-basis - tests: [ - lengthPercentageOrCalc(), - discrete("auto", "10px") - ] - }, - "flex-direction": { - // https://drafts.csswg.org/css-flexbox/#propdef-flex-direction - tests: [ - discrete("row", "row-reverse") - ] - }, - "flex-grow": { - // https://drafts.csswg.org/css-flexbox/#flex-grow-property - tests: [ - positiveNumber() - ] - }, - "flex-shrink": { - // https://drafts.csswg.org/css-flexbox/#propdef-flex-shrink - tests: [ - positiveNumber() - ] - }, - "flex-wrap": { - // https://drafts.csswg.org/css-flexbox/#propdef-flex-wrap - tests: [ - discrete("nowrap", "wrap") - ] - }, - "font-style": { - // https://drafts.csswg.org/css-fonts/#propdef-font-style - tests: [ - discrete("italic", "oblique") - ] - }, - "image-rendering": { - // https://drafts.csswg.org/css-images/#propdef-image-rendering - tests: [ - discrete("optimizeQuality", "pixelated") - ] - }, - "justify-content": { - // https://drafts.csswg.org/css-align/#propdef-justify-content - tests: [ - discrete("baseline", "last-baseline") - ] - }, - "justify-items": { - // https://drafts.csswg.org/css-align/#propdef-justify-items - tests: [ - discrete("baseline", "last-baseline") - ] - }, - "justify-self": { - // https://drafts.csswg.org/css-align/#propdef-justify-self - tests: [ - discrete("baseline", "last-baseline") - ] - }, - "mask-type": { - // https://drafts.fxtf.org/css-masking-1/#propdef-mask-type - tests: [ - discrete("alpha", "luminance") - ] - }, - "order": { - // https://drafts.csswg.org/css-flexbox/#propdef-order - tests: [ - integer() - ] - }, - "pointer-events": { - // https://svgwg.org/svg2-draft/interact.html#PointerEventsProperty - tests: [ - discrete("fill", "none") - ] - }, - "ruby-align": { - // https://drafts.csswg.org/css-ruby-1/#propdef-ruby-align - tests: [ - discrete("start", "center") - ] - }, - "ruby-position": { - // https://drafts.csswg.org/css-ruby-1/#propdef-ruby-position - tests: [ - discrete("under", "over") - ], - tagName: "ruby" - }, - "shape-rendering": { - // https://svgwg.org/svg2-draft/painting.html#ShapeRenderingProperty - tests: [ - discrete("optimizeSpeed", "crispEdges") - ] - }, - "stroke-linecap": { - // https://svgwg.org/svg2-draft/painting.html#StrokeLinecapProperty - tests: [ - discrete("round", "square") - ] - }, - "stroke-linejoin": { - // https://svgwg.org/svg2-draft/painting.html#StrokeLinejoinProperty - tests: [ - discrete("round", "miter") - ], - tagName: "rect" - }, - "text-anchor": { - // https://svgwg.org/svg2-draft/text.html#TextAnchorProperty - tests: [ - discrete("middle", "end") - ] - }, - "text-combine-upright": { - // https://drafts.csswg.org/css-writing-modes-3/#propdef-text-combine-upright - tests: [ - discrete("all", "digits") - ] - }, - "text-decoration-line": { - // https://drafts.csswg.org/css-text-decor-3/#propdef-text-decoration-line - tests: [ - discrete("underline", "overline") - ] - }, - "text-orientation": { - // https://drafts.csswg.org/css-writing-modes-3/#propdef-text-orientation - tests: [ - discrete("upright", "sideways") - ] - }, - "text-rendering": { - // https://svgwg.org/svg2-draft/painting.html#TextRenderingProperty - tests: [ - discrete("optimizeSpeed", "optimizeLegibility") - ] - }, - "vector-effect": { - // https://svgwg.org/svg2-draft/coords.html#VectorEffectProperty - tests: [ - discrete("none", "non-scaling-stroke") - ] - }, - "visibility": { - // https://drafts.csswg.org/css2/visufx.html#propdef-visibility - tests: [ - visibility() - ] - }, - "word-break": { - // https://drafts.csswg.org/css-text-3/#propdef-word-break - tests: [ - discrete("keep-all", "break-all") - ] - }, - "writing-mode": { - // https://drafts.csswg.org/css-writing-modes-3/#propdef-writing-mode - tests: [ - discrete("vertical-rl", "sideways-rl") - ] - }, -} - -for (var property in gCSSProperties) { - if (!isSupported(property)) { - continue; - } - var testData = gCSSProperties[property]; - testData.tests.forEach(function(testFunction) { - testFunction(property, testData); - }); -} - -function discrete(from, to) { - return function(property, options) { - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = [from, to]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: from.toLowerCase() }, - { time: 499, expected: from.toLowerCase() }, - { time: 500, expected: to.toLowerCase() }, - { time: 1000, expected: to.toLowerCase() }]); - }, property + " uses discrete animation when animating between '" - + from + "' and '" + to + "' with linear easing"); - - test(function(t) { - // Easing: http://cubic-bezier.com/#.68,0,1,.01 - // With this curve, we don't reach the 50% point until about 95% of - // the time has expired. - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = [from, to]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both", - easing: "cubic-bezier(0.68,0,1,0.01)" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: from.toLowerCase() }, - { time: 940, expected: from.toLowerCase() }, - { time: 960, expected: to.toLowerCase() }]); - }, property + " uses discrete animation when animating between '" - + from + "' and '" + to + "' with effect easing"); - - test(function(t) { - // Easing: http://cubic-bezier.com/#.68,0,1,.01 - // With this curve, we don't reach the 50% point until about 95% of - // the time has expired. - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = [from, to]; - keyframes.easing = "cubic-bezier(0.68,0,1,0.01)"; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: from.toLowerCase() }, - { time: 940, expected: from.toLowerCase() }, - { time: 960, expected: to.toLowerCase() }]); - }, property + " uses discrete animation when animating between '" - + from + "' and '" + to + "' with keyframe easing"); - } -} - -function length() { - return function(property, options) { - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["10px", "50px"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "10px" }, - { time: 500, expected: "30px" }, - { time: 1000, expected: "50px" }]); - }, property + " supports animating as a length"); - - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["1rem", "5rem"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "10px" }, - { time: 500, expected: "30px" }, - { time: 1000, expected: "50px" }]); - }, property + " supports animating as a length of rem"); - } -} - -function percentage() { - return function(property, options) { - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["10%", "50%"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "10%" }, - { time: 500, expected: "30%" }, - { time: 1000, expected: "50%" }]); - }, property + " supports animating as a percentage"); - } -} - -function integer() { - return function(property, options) { - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = [-2, 2]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "-2" }, - { time: 500, expected: "0" }, - { time: 1000, expected: "2" }]); - }, property + " supports animating as an integer"); - } -} - -function positiveNumber() { - return function(property, options) { - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = [1.1, 1.5]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "1.1" }, - { time: 500, expected: "1.3" }, - { time: 1000, expected: "1.5" }]); - }, property + " supports animating as a positive number"); - } -} - -function lengthPercentageOrCalc() { - return function(property, options) { - length()(property, options); - percentage()(property, options); - - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["10px", "20%"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "10px" }, - { time: 500, expected: "calc(5px + 10%)" }, - { time: 1000, expected: "20%" }]); - }, property + " supports animating as combination units 'px' and '%'"); - - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["10%", "2em"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "10%" }, - { time: 500, expected: "calc(10px + 5%)" }, - { time: 1000, expected: "20px" }]); - }, property + " supports animating as combination units '%' and 'em'"); - - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["1em", "2rem"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "10px" }, - { time: 500, expected: "15px" }, - { time: 1000, expected: "20px" }]); - }, property + " supports animating as combination units 'em' and 'rem'"); - - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["10px", "calc(1em + 20%)"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "10px" }, - { time: 500, expected: "calc(10px + 10%)" }, - { time: 1000, expected: "calc(10px + 20%)" }]); - }, property + " supports animating as combination units 'px' and 'calc'"); - - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["calc(10px + 10%)", "calc(1em + 1rem + 20%)"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, - expected: "calc(10px + 10%)" }, - { time: 500, - expected: "calc(15px + 15%)" }, - { time: 1000, - expected: "calc(20px + 20%)" }]); - }, property + " supports animating as a calc"); - } -} - -function visibility() { - return function(property, options) { - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["visible", "hidden"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "visible" }, - { time: 999, expected: "visible" }, - { time: 1000, expected: "hidden" }]); - }, property + " uses visibility animation when animating " - + "from 'visible' to 'hidden'"); - - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["hidden", "visible"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "hidden" }, - { time: 1, expected: "visible" }, - { time: 1000, expected: "visible" }]); - }, property + " uses visibility animation when animating " - + "from 'hidden' to 'visible'"); - - test(function(t) { - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["hidden", "collapse"]; - var target = createElement(t, options.tagName); - var animation = target.animate(keyframes, - { duration: 1000, fill: "both" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "hidden" }, - { time: 499, expected: "hidden" }, - { time: 500, expected: "collapse" }, - { time: 1000, expected: "collapse" }]); - }, property + " uses visibility animation when animating " - + "from 'hidden' to 'collapse'"); - - test(function(t) { - // Easing: http://cubic-bezier.com/#.68,-.55,.26,1.55 - // With this curve, the value is less than 0 till about 34% - // also more than 1 since about 63% - var idlName = propertyToIDL(property); - var keyframes = {}; - keyframes[idlName] = ["visible", "hidden"]; - var target = createElement(t, options.tagName); - var animation = - target.animate(keyframes, - { duration: 1000, fill: "both", - easing: "cubic-bezier(0.68, -0.55, 0.26, 1.55)" }); - testAnimationSamples(animation, idlName, - [{ time: 0, expected: "visible" }, - { time: 1, expected: "visible" }, - { time: 330, expected: "visible" }, - { time: 340, expected: "visible" }, - { time: 620, expected: "visible" }, - { time: 630, expected: "hidden" }, - { time: 1000, expected: "hidden" }]); - }, property + " uses visibility animation when animating " - + "from 'visible' to 'hidden' with easeInOutBack easing"); - } -} - -function testAnimationSamples(animation, idlName, testSamples) { - var target = animation.effect.target; - testSamples.forEach(function(testSample) { - animation.currentTime = testSample.time; - assert_equals(getComputedStyle(target)[idlName], testSample.expected, - "The value should be " + testSample.expected + - " at " + testSample.time + "ms"); - }); -} - -function isSupported(property) { - var testKeyframe = new TestKeyframe(propertyToIDL(property)); - try { - // Since TestKeyframe returns 'undefined' for |property|, - // the KeyframeEffect constructor will throw - // if the string "undefined" is not a valid value for the property. - new KeyframeEffect(null, testKeyframe); - } catch(e) {} - return testKeyframe.propAccessCount !== 0; -} - -function TestKeyframe(testProp) { - var _propAccessCount = 0; - - Object.defineProperty(this, testProp, { - get: function() { _propAccessCount++; }, - enumerable: true - }); - - Object.defineProperty(this, 'propAccessCount', { - get: function() { return _propAccessCount; } - }); -} - -function propertyToIDL(property) { - // https://w3c.github.io/web-animations/#animation-property-name-to-idl-attribute-name - if (property === "float") { - return "cssFloat"; - } - return property.replace(/-[a-z]/gi, - function (str) { - return str.substr(1).toUpperCase(); }); -} - -</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/combining-effects/effect-composition.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/combining-effects/effect-composition.html new file mode 100644 index 0000000..7604bd21 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/combining-effects/effect-composition.html
@@ -0,0 +1,85 @@ +<!doctype html> +<meta charset=utf-8> +<title>Test for effect composition</title> +<link rel="help" href="https://w3c.github.io/web-animations/#effect-composition"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src="../../testcommon.js"></script> +<div id="log"></div> +<script> +'use strict'; + +[ 'accumulate', 'add' ].forEach(function(composite) { + test(function(t) { + var div = createDiv(t); + div.style.marginLeft = '10px'; + var anim = + div.animate({ marginLeft: ['0px', '10px'], composite }, 100); + + anim.currentTime = 50; + assert_equals(getComputedStyle(div).marginLeft, '15px', + 'Animated margin-left style at 50%'); + }, composite + ' onto the base value'); + + test(function(t) { + var div = createDiv(t); + var anims = []; + anims.push(div.animate({ marginLeft: ['10px', '20px'], + composite: 'replace' }, + 100)); + anims.push(div.animate({ marginLeft: ['0px', '10px'], + composite }, + 100)); + + anims.forEach(function(anim) { + anim.currentTime = 50; + }); + + assert_equals(getComputedStyle(div).marginLeft, '20px', + 'Animated style at 50%'); + }, composite + ' onto an underlying animation value'); + + test(function(t) { + var div = createDiv(t); + div.style.marginLeft = '10px'; + var anim = + div.animate([{ marginLeft: '10px', composite }, + { marginLeft: '30px', composite: 'replace' }], + 100); + + anim.currentTime = 50; + assert_equals(getComputedStyle(div).marginLeft, '25px', + 'Animated style at 50%'); + }, 'Composite when mixing ' + composite + ' and replace'); + + test(function(t) { + var div = createDiv(t); + div.style.marginLeft = '10px'; + var anim = + div.animate([{ marginLeft: '10px', composite: 'replace' }, + { marginLeft: '20px' }], + { duration: 100 , composite }); + + anim.currentTime = 50; + assert_equals(getComputedStyle(div).marginLeft, '20px', + 'Animated style at 50%'); + }, composite + ' specified on a keyframe overrides the composite mode of ' + + 'the effect'); + + test(function(t) { + var div = createDiv(t); + div.style.marginLeft = '10px'; + var anim = + div.animate([{ marginLeft: '10px', composite: 'replace' }, + { marginLeft: '20px' }], + 100); + + anim.effect.composite = composite; + anim.currentTime = 50; // (10 + (10 + 20)) * 0.5 + assert_equals(getComputedStyle(div).marginLeft, '20px', + 'Animated style at 50%'); + }, 'unspecified composite mode on a keyframe is overriden by setting ' + + composite + ' of the effect'); +}); + +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/endDelay.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/endDelay.html index 3f27daa..40136b4 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/endDelay.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/endDelay.html
@@ -66,30 +66,17 @@ var div = createDiv(t); var anim = div.animate({ opacity: [ 0, 1 ] }, { duration: 100000, endDelay: 30000 }); - var finishedTimelineTime; - anim.finished.then(function() { - finishedTimelineTime = anim.timeline.currentTime; - }); - - var receivedEvents = []; - anim.onfinish = function(event) { - receivedEvents.push(event); - } - anim.ready.then(function() { anim.currentTime = 110000; // during endDelay + anim.onfinish = t.step_func(function(event) { + assert_unreached('onfinish event should not be fired during endDelay'); + }); return waitForAnimationFrames(2); }).then(t.step_func(function() { - assert_equals(receivedEvents.length, 0, - 'onfinish event is should not be fired' + - 'when currentTime is during endDelay'); + anim.onfinish = t.step_func(function(event) { + t.done(); + }); anim.currentTime = 130000; // after endTime - return waitForAnimationFrames(2); - })).then(t.step_func_done(function() { - assert_equals(receivedEvents.length, 1, 'length of array should be one'); - assert_equals(receivedEvents[0].timelineTime, finishedTimelineTime, - 'receivedEvents[0].timelineTime should equal to the animation timeline ' - + 'when finished promise is resolved'); })); }, 'onfinish event is fired currentTime is after endTime');
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/composite.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/composite.html new file mode 100644 index 0000000..1825b71 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/composite.html
@@ -0,0 +1,47 @@ +<!doctype html> +<meta charset=utf-8> +<title>KeyframeEffect.composite tests</title> +<link rel="help" + href="https://w3c.github.io/web-animations/#dom-keyframeeffect-composite"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function(t) { + var anim = createDiv(t).animate(null); + assert_equals(anim.effect.composite, 'replace', + 'The default value should be replace'); +}, 'Default value'); + +test(function(t) { + var anim = createDiv(t).animate(null); + anim.effect.composite = 'add'; + assert_equals(anim.effect.composite, 'add', + 'The effect composite value should be replaced'); +}, 'Change composite value'); + +test(function(t) { + var anim = createDiv(t).animate({ left: '10px' }); + + anim.effect.composite = 'add'; + var keyframes = anim.effect.getKeyframes(); + assert_equals(keyframes[0].composite, undefined, + 'unspecified keyframe composite value should be absent even ' + + 'if effect composite is set'); +}, 'Unspecified keyframe composite value when setting effect composite'); + +test(function(t) { + var anim = createDiv(t).animate({ left: '10px', composite: 'replace' }); + + anim.effect.composite = 'add'; + var keyframes = anim.effect.getKeyframes(); + assert_equals(keyframes[0].composite, 'replace', + 'specified keyframe composite value should not be overridden ' + + 'by setting effect composite'); +}, 'Specified keyframe composite value when setting effect composite'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/constructor.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/constructor.html index 97c7613..f7c61995 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/constructor.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/constructor.html
@@ -110,7 +110,7 @@ var effect = new KeyframeEffectReadOnly(target, { left: ["10px", "20px"] }, { composite: composite }); - assert_equals(effect.getKeyframes()[0].composite, composite, + assert_equals(effect.getKeyframes()[0].composite, undefined, "resulting composite for '" + composite + "'"); }); gBadCompositeValueTests.forEach(function(composite) { @@ -120,8 +120,8 @@ }, { composite: composite }); }); }); -}, "composite values are parsed correctly when passed to the " + - "KeyframeEffectReadOnly constructor in KeyframeTimingOptions"); +}, "composite value is absent if the composite operation specified on the " + + "keyframe effect is being used"); gPropertyIndexedKeyframesTests.forEach(function(subtest) { test(function(t) {
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/copy-contructor.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/copy-contructor.html new file mode 100644 index 0000000..bc27838 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/copy-contructor.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>KeyframeEffect copy constructor tests</title> +<link rel="help" +href="https://w3c.github.io/web-animations/#dom-keyframeeffect-keyframeeffect-source"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +"use strict"; + +test(function(t) { + var effect = new KeyframeEffectReadOnly(createDiv(t), null); + assert_equals(effect.constructor.name, 'KeyframeEffectReadOnly'); + assert_equals(effect.timing.constructor.name, + 'AnimationEffectTimingReadOnly'); + + // Make a mutable copy + var copiedEffect = new KeyframeEffect(effect); + assert_equals(copiedEffect.constructor.name, 'KeyframeEffect'); + assert_equals(copiedEffect.timing.constructor.name, 'AnimationEffectTiming'); +}, 'Test mutable copy from a KeyframeEffectReadOnly source'); + +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite.html index 743d108..eb5c032 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite.html
@@ -12,6 +12,26 @@ test(function(t) { var div = createDiv(t); var anim = + div.animate({ alignContent: ['flex-start', 'flex-end'] }, + { duration: 100 * MS_PER_SEC, + easing: 'linear', + iterations: 10, + iterationComposite: 'accumulate' }); + + anim.currentTime = anim.effect.timing.duration / 2; + assert_equals(getComputedStyle(div).alignContent, 'flex-end', + 'Animated align-content style at 50s of the first iteration'); + anim.currentTime = anim.effect.timing.duration * 2; + assert_equals(getComputedStyle(div).alignContent, 'flex-start', + 'Animated align-content style at 0s of the third iteration'); + anim.currentTime += anim.effect.timing.duration / 2; + assert_equals(getComputedStyle(div).alignContent, 'flex-end', + 'Animated align-content style at 50s of the third iteration'); +}, 'iterationComposite of discrete type animation (align-content)'); + +test(function(t) { + var div = createDiv(t); + var anim = div.animate({ marginLeft: ['0px', '10px'] }, { duration: 100 * MS_PER_SEC, easing: 'linear', @@ -541,9 +561,35 @@ test(function(t) { var div = createDiv(t); - // The transform list whose order is mismatched is compounded, - // so below animation is the same as; - // from matrix(2, 0, 0, 2, 0, 0) to matrix(3, 0, 0, 3, 30, 0) + var anim = + div.animate({ transform: ['matrix(2, 0, 0, 2, 0, 0)', + 'matrix(3, 0, 0, 3, 30, 0)'] }, + { duration: 100 * MS_PER_SEC, + easing: 'linear', + iterations: 10, + iterationComposite: 'accumulate' }); + anim.pause(); + + anim.currentTime = anim.effect.timing.duration / 2; + assert_equals(getComputedStyle(div).transform, + 'matrix(2.5, 0, 0, 2.5, 15, 0)', + 'Animated transform of matrix function at 50s of the first iteration'); + anim.currentTime = anim.effect.timing.duration * 2; + assert_equals(getComputedStyle(div).transform, + // scale(2) + (scale(3-1)*2) + translateX(30px)*2 + 'matrix(6, 0, 0, 6, 60, 0)', + 'Animated transform of matrix function at 0s of the third iteration'); + anim.currentTime += anim.effect.timing.duration / 2; + assert_equals(getComputedStyle(div).transform, + // from: matrix(6, 0, 0, 6, 60, 0) + // to: matrix(7, 0, 0, 7, 90, 0) + // = scale(3) + (scale(3-1)*2) + translateX(30px)*3 + 'matrix(6.5, 0, 0, 6.5, 75, 0)', + 'Animated transform of matrix function at 50s of the third iteration'); +}, 'iterationComposite of transform of matrix function'); + +test(function(t) { + var div = createDiv(t); var anim = div.animate({ transform: ['translateX(0px) scale(2)', 'scale(3) translateX(10px)'] }, @@ -555,25 +601,29 @@ anim.currentTime = anim.effect.timing.duration / 2; assert_equals(getComputedStyle(div).transform, - 'matrix(2.5, 0, 0, 2.5, 15, 0)', // scale(2.5) (0px + 30px*2) / 2 + // Interpolate between matrix(2, 0, 0, 2, 0, 0) = translateX(0px) scale(2) + // and matrix(3, 0, 0, 3, 30, 0) = scale(3) translateX(10px) + 'matrix(2.5, 0, 0, 2.5, 15, 0)', 'Animated transform list at 50s of the first iteration'); anim.currentTime = anim.effect.timing.duration * 2; assert_equals(getComputedStyle(div).transform, - 'matrix(4, 0, 0, 4, 60, 0)', // scale(2+(3-2)*2) (0px + 30px*2) + // 'from' and 'to' value are mismatched, so accumulate + // matrix(2, 0, 0, 2, 0, 0) onto matrix(3, 0, 0, 3, 30, 0) * 2 + // = scale(2) + (scale(3-1)*2) + translateX(30px)*2 + 'matrix(6, 0, 0, 6, 60, 0)', 'Animated transform list at 0s of the third iteration'); anim.currentTime += anim.effect.timing.duration / 2; assert_equals(getComputedStyle(div).transform, - 'matrix(5.5, 0, 0, 5.5, 135, 0)', // scale(4+7)/2 (60px + 210px) + // Interpolate between matrix(6, 0, 0, 6, 60, 0) + // and matrix(7, 0, 0, 7, 210, 0) = scale(7) translate(30px) + 'matrix(6.5, 0, 0, 6.5, 135, 0)', 'Animated transform list at 50s of the third iteration'); }, 'iterationComposite of transform list animation whose order is mismatched'); test(function(t) { var div = createDiv(t); // Even if each transform list does not have functions which exist in - // other pair of the list, we don't fill any missing functions at all, - // it's just computed as compounded matrices - // Below animation is the same as; - // from matrix(1, 0, 0, 1, 0, 0) to matrix(2, 0, 0, 2, 20, 0) + // other pair of the list, we don't fill any missing functions at all. var anim = div.animate({ transform: ['translateX(0px)', 'scale(2) translateX(10px)'] }, @@ -585,17 +635,110 @@ anim.currentTime = anim.effect.timing.duration / 2; assert_equals(getComputedStyle(div).transform, - 'matrix(1.5, 0, 0, 1.5, 10, 0)', // scale(1.5) (0px + 10px*2) / 2 + // Interpolate between matrix(1, 0, 0, 1, 0, 0) = translateX(0px) + // and matrix(2, 0, 0, 2, 20, 0) = scale(2) translateX(10px) + 'matrix(1.5, 0, 0, 1.5, 10, 0)', 'Animated transform list at 50s of the first iteration'); anim.currentTime = anim.effect.timing.duration * 2; assert_equals(getComputedStyle(div).transform, - 'matrix(3, 0, 0, 3, 40, 0)', // scale(1+(2-1)*2) (0px + 20px*2) + // 'from' and 'to' value are mismatched, so accumulate + // matrix(1, 0, 0, 1, 0, 0) onto matrix(2, 0, 0, 2, 20, 0) * 2 + // = scale(1) + (scale(2-1)*2) + translateX(20px)*2 + 'matrix(3, 0, 0, 3, 40, 0)', 'Animated transform list at 0s of the third iteration'); anim.currentTime += anim.effect.timing.duration / 2; assert_equals(getComputedStyle(div).transform, - 'matrix(3.5, 0, 0, 3.5, 80, 0)', // scale(3+4)/2 (40px + 20px) + // Interpolate between matrix(3, 0, 0, 3, 40, 0) + // and matrix(4, 0, 0, 4, 120, 0) = + // scale(2 + (2-1)*2) translate(10px * 3) + 'matrix(3.5, 0, 0, 3.5, 80, 0)', 'Animated transform list at 50s of the third iteration'); -}, 'iterationComposite of transform list animation whose order is mismatched'); +}, 'iterationComposite of transform list animation whose order is mismatched ' + + 'because of missing functions'); + +test(function(t) { + var div = createDiv(t); + var anim = + div.animate({ transform: ['none', + 'translateX(10px)'] }, + { duration: 100 * MS_PER_SEC, + easing: 'linear', + iterations: 10, + iterationComposite: 'accumulate' }); + anim.pause(); + + anim.currentTime = anim.effect.timing.duration / 2; + assert_equals(getComputedStyle(div).transform, + 'matrix(1, 0, 0, 1, 5, 0)', // (0px + 10px) / 2 + 'Animated transform list at 50s of the first iteration'); + anim.currentTime = anim.effect.timing.duration * 2; + assert_equals(getComputedStyle(div).transform, + 'matrix(1, 0, 0, 1, 0, 0)', // 'none' overrides any transforms. + 'Animated transform list at 0s of the third iteration'); + anim.currentTime += anim.effect.timing.duration / 2; + assert_equals(getComputedStyle(div).transform, + 'matrix(1, 0, 0, 1, 15, 0)', // (0px + 10px*2)/2 + 'Animated transform list at 50s of the third iteration'); +}, 'iterationComposite of transform from none to translate'); + +test(function(t) { + var div = createDiv(t); + var anim = + div.animate({ transform: ['matrix3d(1, 0, 0, 0, ' + + '0, 1, 0, 0, ' + + '0, 0, 1, 0, ' + + '0, 0, 30, 1)', + 'matrix3d(1, 0, 0, 0, ' + + '0, 1, 0, 0, ' + + '0, 0, 1, 0, ' + + '0, 0, 50, 1)'] }, + { duration: 100 * MS_PER_SEC, + easing: 'linear', + iterations: 10, + iterationComposite: 'accumulate' }); + anim.pause(); + + anim.currentTime = anim.effect.timing.duration / 2; + assert_equals(getComputedStyle(div).transform, + 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 40, 1)', + 'Animated transform of matrix3d function at 50s of the first iteration'); + anim.currentTime = anim.effect.timing.duration * 2; + assert_equals(getComputedStyle(div).transform, + // translateZ(30px) + (translateZ(50px)*2) + 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 130, 1)', + 'Animated transform of matrix3d function at 0s of the third iteration'); + anim.currentTime += anim.effect.timing.duration / 2; + assert_equals(getComputedStyle(div).transform, + // from: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 130, 1) + // to: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 150, 1) + 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 140, 1)', + 'Animated transform of matrix3d function at 50s of the third iteration'); +}, 'iterationComposite of transform of matrix3d function'); + +test(function(t) { + var div = createDiv(t); + var anim = + div.animate({ transform: ['rotate3d(1, 1, 0, 0deg)', + 'rotate3d(1, 1, 0, 90deg)'] }, + { duration: 100 * MS_PER_SEC, + easing: 'linear', + iterations: 10, + iterationComposite: 'accumulate' }); + anim.pause(); + + anim.currentTime = 0; + assert_equals(getComputedStyle(div).transform, + 'matrix(1, 0, 0, 1, 0, 0)', // Actually not rotated at all. + 'Animated transform of rotate3d function at 50s of the first iteration'); + anim.currentTime = anim.effect.timing.duration * 2; + assert_matrix_equals(getComputedStyle(div).transform, + rotate3dToMatrix3d(1, 1, 0, Math.PI), // 180deg + 'Animated transform of rotate3d function at 0s of the third iteration'); + anim.currentTime += anim.effect.timing.duration / 2; + assert_matrix_equals(getComputedStyle(div).transform, + rotate3dToMatrix3d(1, 1, 0, 225 * Math.PI / 180), //((270 + 180) * 0.5)deg + 'Animated transform of rotate3d function at 50s of the third iteration'); +}, 'iterationComposite of transform of rotate3d function'); test(function(t) { var div = createDiv(t);
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor.html new file mode 100644 index 0000000..287ffe1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor.html
@@ -0,0 +1,94 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>KeyframeEffectReadOnly copy constructor tests</title> +<link rel="help" +href="https://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-keyframeeffectreadonly-source"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +"use strict"; + +test(function(t) { + var effect = new KeyframeEffectReadOnly(createDiv(t), null); + var copiedEffect = new KeyframeEffectReadOnly(effect); + assert_equals(copiedEffect.target, effect.target, 'same target'); +}, 'Test copied keyframeEffectReadOnly has the same target'); + +test(function(t) { + var effect = + new KeyframeEffectReadOnly(null, + [ { marginLeft: '0px' }, + { marginLeft: '-20px', easing: 'ease-in', + offset: 0.1 }, + { marginLeft: '100px', easing: 'ease-out' }, + { marginLeft: '50px' } ], + { spacing: 'paced(margin-left)' }); + + var copiedEffect = new KeyframeEffectReadOnly(effect); + var KeyframesA = effect.getKeyframes(); + var KeyframesB = copiedEffect.getKeyframes(); + assert_equals(KeyframesA.length, KeyframesB.length, 'same keyframes length'); + + for (var i = 0; i < KeyframesA.length; ++i) { + assert_equals(KeyframesA[i].offset, KeyframesB[i].offset, + 'Keyframe ' + i + ' has the same offset'); + assert_equals(KeyframesA[i].computedOffset, KeyframesB[i].computedOffset, + 'keyframe ' + i + ' has the same computedOffset'); + assert_equals(KeyframesA[i].easing, KeyframesB[i].easing, + 'keyframe ' + i + ' has the same easing'); + assert_equals(KeyframesA[i].composite, KeyframesB[i].composite, + 'keyframe ' + i + ' has the same composite'); + + assert_true(!!KeyframesA[i].marginLeft, + 'original keyframe ' + i + ' has the valid property value'); + assert_true(!!KeyframesB[i].marginLeft, + 'new keyframe ' + i + ' has the valid property value'); + assert_equals(KeyframesA[i].marginLeft, KeyframesB[i].marginLeft, + 'keyframe ' + i + ' has the same property value pair'); + } +}, 'Test copied keyframeEffectReadOnly has the same keyframes'); + +test(function(t) { + var effect = new KeyframeEffectReadOnly(null, null, + { spacing: 'paced(margin-left)', + iterationComposite: 'accumulate' }); + + var copiedEffect = new KeyframeEffectReadOnly(effect); + assert_equals(copiedEffect.spacing, effect.spacing, 'same spacing'); + assert_equals(copiedEffect.iterationComposite, effect.iterationComposite, + 'same iterationCompositeOperation'); + assert_equals(copiedEffect.composite, effect.composite, + 'same compositeOperation'); +}, 'Test copied keyframeEffectReadOnly has the same keyframeEffectOptions'); + +test(function(t) { + var effect = new KeyframeEffectReadOnly(null, null, + { duration: 100 * MS_PER_SEC, + delay: -1 * MS_PER_SEC, + endDelay: 2 * MS_PER_SEC, + fill: 'forwards', + iterationStart: 2, + iterations: 20, + easing: 'ease-out', + direction: 'alternate' } ); + + var copiedEffect = new KeyframeEffectReadOnly(effect); + var timingA = effect.timing; + var timingB = copiedEffect.timing; + assert_not_equals(timingA, timingB, 'different timing objects'); + assert_equals(timingA.delay, timingB.delay, 'same delay'); + assert_equals(timingA.endDelay, timingB.endDelay, 'same endDelay'); + assert_equals(timingA.fill, timingB.fill, 'same fill'); + assert_equals(timingA.iterationStart, timingB.iterationStart, + 'same iterationStart'); + assert_equals(timingA.iterations, timingB.iterations, 'same iterations'); + assert_equals(timingA.duration, timingB.duration, 'same duration'); + assert_equals(timingA.direction, timingB.direction, 'same direction'); + assert_equals(timingA.easing, timingB.easing, 'same easing'); +}, 'Test copied keyframeEffectReadOnly has the same timing content'); + +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/keyframe-utils.js b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/keyframe-utils.js index 626f0bf..8f4126c3 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/keyframe-utils.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/keyframe-utils.js
@@ -182,7 +182,7 @@ var gKeyframeSequenceTests = [ { desc: "a one property one keyframe sequence", input: [{ offset: 1, left: "10px" }], - output: [{ offset: null, computedOffset: 1, easing: "linear", + output: [{ offset: 1, computedOffset: 1, easing: "linear", left: "10px" }] }, { desc: "a one property two keyframe sequence", input: [{ offset: 0, left: "10px" }, @@ -259,7 +259,7 @@ left: "10px" }] }, { desc: "a single keyframe sequence with string offset", input: [{ offset: '0.5', left: "10px" }], - output: [{ offset: 0.5, computedOffset: 1, easing: "linear", + output: [{ offset: 0.5, computedOffset: 0.5, easing: "linear", left: "10px" }] }, { desc: "a one property keyframe sequence with some omitted offsets", input: [{ offset: 0.00, left: "10px" }, @@ -341,9 +341,9 @@ composite: "replace", left: "10px" }, { offset: 0.0, computedOffset: 0.0, easing: "linear", composite: "replace", top: "20px" }, - { offset: 0.5, computedOffset: 0.0, easing: "linear", + { offset: 0.5, computedOffset: 0.5, easing: "linear", composite: "add", left: "30px" }, - { offset: 0.5, computedOffset: 0.0, easing: "linear", + { offset: 0.5, computedOffset: 0.5, easing: "linear", composite: "add", top: "40px" }, { offset: 1.0, computedOffset: 1.0, easing: "linear", composite: "replace", left: "50px" },
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/testcommon.js b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/testcommon.js index 31ebdfaf..348af6e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/testcommon.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/testcommon.js
@@ -174,3 +174,68 @@ }()); }); } + +// Returns 'matrix()' or 'matrix3d()' function string generated from an array. +function createMatrixFromArray(array) { + return (array.length == 16 ? 'matrix3d' : 'matrix') + + '(' + array.join() + ')'; +} + +// Returns 'matrix3d()' function string equivalent to +// 'rotate3d(x, y, z, radian)'. +function rotate3dToMatrix3d(x, y, z, radian) { + return createMatrixFromArray(rotate3dToMatrix(x, y, z, radian)); +} + +// Returns an array of the 4x4 matrix equivalent to 'rotate3d(x, y, z, radian)'. +// https://www.w3.org/TR/css-transforms-1/#Rotate3dDefined +function rotate3dToMatrix(x, y, z, radian) { + var sc = Math.sin(radian / 2) * Math.cos(radian / 2); + var sq = Math.sin(radian / 2) * Math.sin(radian / 2); + + // Normalize the vector. + var length = Math.sqrt(x*x + y*y + z*z); + x /= length; + y /= length; + z /= length; + + return [ + 1 - 2 * (y*y + z*z) * sq, + 2 * (x * y * sq + z * sc), + 2 * (x * z * sq - y * sc), + 0, + 2 * (x * y * sq - z * sc), + 1 - 2 * (x*x + z*z) * sq, + 2 * (y * z * sq + x * sc), + 0, + 2 * (x * z * sq + y * sc), + 2 * (y * z * sq - x * sc), + 1 - 2 * (x*x + y*y) * sq, + 0, + 0, + 0, + 0, + 1 + ]; +} + +// Compare matrix string like 'matrix(1, 0, 0, 1, 100, 0)' with tolerances. +function assert_matrix_equals(actual, expected, description) { + var matrixRegExp = /^matrix(?:3d)*\((.+)\)/; + assert_regexp_match(actual, matrixRegExp, + 'Actual value is not a matrix') + assert_regexp_match(expected, matrixRegExp, + 'Expected value is not a matrix'); + + var actualMatrixArray = + actual.match(matrixRegExp)[1].split(',').map(Number); + var expectedMatrixArray = + expected.match(matrixRegExp)[1].split(',').map(Number); + + assert_equals(actualMatrixArray.length, expectedMatrixArray.length, + 'dimension of the matrix: ' + description); + for (var i = 0; i < actualMatrixArray.length; i++) { + assert_approx_equals(actualMatrixArray[i], expectedMatrixArray[i], 0.0001, + 'expecetd ' + expected + ' but got ' + actual + ": " + description); + } +}
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animations/current-time.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animations/current-time.html index efc7ba7..df7228f 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animations/current-time.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animations/current-time.html
@@ -45,7 +45,7 @@ }, 'The current time is unresolved when the start time is unresolved ' + '(and no hold time is set)'); -promise_test(function(t) { +test(function(t) { var animation = new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC), document.timeline);
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/webrtc/datachannel-emptystring.html b/third_party/WebKit/LayoutTests/imported/wpt/webrtc/datachannel-emptystring.html index 9cd32a3b..6af436a 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/webrtc/datachannel-emptystring.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/webrtc/datachannel-emptystring.html
@@ -33,13 +33,13 @@ // When the data channel is open, send an empty string message // followed by a message that contains the string "done". - var onSendChannelOpen = function (event) { + var onSendChannelOpen = test.step_func(function (event) { var msgEl = document.getElementById('msg'); sendChannel.send(''); msgEl.innerHTML += 'Sent: [empty string]<br>'; sendChannel.send('done'); msgEl.innerHTML += 'Sent: "done"<br>'; - }; + }); // Check the messages received on the other side. // There should be an empty string message followed by a message that
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_badleftbounds.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_badleftbounds.html new file mode 100644 index 0000000..110b847 --- /dev/null +++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_badleftbounds.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../resources/mojo-helpers.js"></script> +<script src="resources/fake-vr-displays.js"></script> +<script src="resources/mock-vr-service.js"></script> +<canvas id="webgl-canvas"></canvas> +<script src="resources/presentation-setup.js"></script> +<script> +let fakeDisplays = fakeVRDisplays(); + +vr_test((service) => { + return navigator.getVRDisplays().then(displays => { + assert_true(displays != null); + assert_equals(1, displays.length); + var asyncTest = async_test( + "requestPresent rejects and does not present"); + runWithUserGesture( () => { + displays[0].requestPresent([{ + source : webglCanvas, + leftBounds: [0, 1] // Too short + }]).then( () => { + asyncTest.step( () => { + assert_unreached(); + }, "Display should not be presenting"); + }, (err) => { + asyncTest.step( () => { + assert_false(displays[0].isPresenting); + }, "requestPresent rejected and not presenting"); + }).then( () => { + asyncTest.done(); + }); + }); + }); +}, [fakeDisplays['Pixel']], +'Test requestPresent rejects if provided a bad leftBounds'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_badrightbounds.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_badrightbounds.html new file mode 100644 index 0000000..0ff2a673 --- /dev/null +++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_badrightbounds.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../resources/mojo-helpers.js"></script> +<script src="resources/fake-vr-displays.js"></script> +<script src="resources/mock-vr-service.js"></script> +<canvas id="webgl-canvas"></canvas> +<script src="resources/presentation-setup.js"></script> +<script> +let fakeDisplays = fakeVRDisplays(); + +vr_test((service) => { + return navigator.getVRDisplays().then(displays => { + assert_true(displays != null); + assert_equals(1, displays.length); + var asyncTest = async_test( + "requestPresent rejects and does not present"); + runWithUserGesture( () => { + displays[0].requestPresent([{ + source : webglCanvas, + rightBounds: [0, 1, 2, 3, 4] // Too long + }]).then( () => { + asyncTest.step( () => { + assert_unreached(); + }, "Display should not be presenting"); + }, (err) => { + asyncTest.step( () => { + assert_false(displays[0].isPresenting); + }, "requestPresent rejected and not presenting"); + }).then( () => { + asyncTest.done(); + }); + }); + }); +}, [fakeDisplays['Pixel']], +'Test requestPresent rejects if provided a bad rightBounds'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nolayers.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nolayers.html new file mode 100644 index 0000000..60949774 --- /dev/null +++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nolayers.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../resources/mojo-helpers.js"></script> +<script src="resources/fake-vr-displays.js"></script> +<script src="resources/mock-vr-service.js"></script> +<canvas id="webgl-canvas"></canvas> +<script src="resources/presentation-setup.js"></script> +<script> +let fakeDisplays = fakeVRDisplays(); + +vr_test((service) => { + return navigator.getVRDisplays().then(displays => { + assert_true(displays != null); + assert_equals(1, displays.length); + var asyncTest = async_test( + "requestPresent rejects and does not present"); + runWithUserGesture( () => { + displays[0].requestPresent([]).then( () => { + asyncTest.step( () => { + assert_unreached(); + }, "Display should not be presenting"); + }, (err) => { + asyncTest.step( () => { + assert_false(displays[0].isPresenting); + }, "requestPresent rejected and not presenting"); + }).then( () => { + asyncTest.done(); + }); + }); + }); +}, [fakeDisplays['Pixel']], +'Test requestPresent rejects if not provided any layers'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nosource.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nosource.html new file mode 100644 index 0000000..e339134 --- /dev/null +++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nosource.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../resources/mojo-helpers.js"></script> +<script src="resources/fake-vr-displays.js"></script> +<script src="resources/mock-vr-service.js"></script> +<canvas id="webgl-canvas"></canvas> +<script src="resources/presentation-setup.js"></script> +<script> +let fakeDisplays = fakeVRDisplays(); + +vr_test((service) => { + return navigator.getVRDisplays().then(displays => { + assert_true(displays != null); + assert_equals(1, displays.length); + var asyncTest = async_test( + "requestPresent rejects and does not present"); + runWithUserGesture( () => { + displays[0].requestPresent([{}]).then( () => { + asyncTest.step( () => { + assert_unreached(); + }, "Display should not be presenting"); + }, (err) => { + asyncTest.step( () => { + assert_false(displays[0].isPresenting); + }, "requestPresent rejected and not presenting"); + }).then( () => { + asyncTest.done(); + }); + }); + }); +}, [fakeDisplays['Pixel']], +'Test requestPresent rejects if not provided a layer source'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_notsupported.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_notsupported.html index 4f0f69e..5e4bd6a 100644 --- a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_notsupported.html +++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_notsupported.html
@@ -19,7 +19,7 @@ displays[0].requestPresent([{ source : webglCanvas }]).then( () => { asyncTest.step( () => { assert_unreached(); - }, "Display should be presenting"); + }, "Display should not be presenting"); }, (err) => { asyncTest.step( () => { assert_false(displays[0].isPresenting);
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nowebgl.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nowebgl.html new file mode 100644 index 0000000..f11d809 --- /dev/null +++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_nowebgl.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../resources/mojo-helpers.js"></script> +<script src="resources/fake-vr-displays.js"></script> +<script src="resources/mock-vr-service.js"></script> +<canvas id="webgl-canvas"></canvas> +<canvas id="canvas-2d"></canvas> +<script src="resources/presentation-setup.js"></script> +<script> +let fakeDisplays = fakeVRDisplays(); + +vr_test((service) => { + return navigator.getVRDisplays().then(displays => { + assert_true(displays != null); + assert_equals(1, displays.length); + var canvas2d = document.getElementById("canvas-2d"); + var ctx = canvas2d.getContext("2d"); + var asyncTest = async_test( + "requestPresent rejects and does not present"); + runWithUserGesture( () => { + displays[0].requestPresent([{ source : canvas2d }]).then( () => { + asyncTest.step( () => { + assert_unreached(); + }, "Display should not be presenting"); + }, (err) => { + asyncTest.step( () => { + assert_false(displays[0].isPresenting); + }, "requestPresent rejected and not presenting"); + }).then( () => { + asyncTest.done(); + }); + }); + }); +}, [fakeDisplays['Pixel']], +'Test requestPresent rejects if provided a non-webgl canvas'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_toomanylayers.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_toomanylayers.html new file mode 100644 index 0000000..4ca4b932 --- /dev/null +++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_toomanylayers.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../resources/mojo-helpers.js"></script> +<script src="resources/fake-vr-displays.js"></script> +<script src="resources/mock-vr-service.js"></script> +<canvas id="webgl-canvas"></canvas> +<script src="resources/presentation-setup.js"></script> +<script> +let fakeDisplays = fakeVRDisplays(); + +vr_test((service) => { + return navigator.getVRDisplays().then(displays => { + assert_true(displays != null); + assert_equals(1, displays.length); + var max_layers = displays[0].capabilities.maxLayers; + var layers = []; + for (var i = 0; i <= max_layers; ++i) { + layers.push({ source : webglCanvas }); + } + var asyncTest = async_test( + "requestPresent rejects and does not present"); + runWithUserGesture( () => { + displays[0].requestPresent(layers).then( () => { + asyncTest.step( () => { + assert_unreached(); + }, "Display should not be presenting"); + }, (err) => { + asyncTest.step( () => { + assert_false(displays[0].isPresenting); + }, "requestPresent rejected and not presenting"); + }).then( () => { + asyncTest.done(); + }); + }); + }); +}, [fakeDisplays['Pixel']], +'Test requestPresent rejects if provided too many layers'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_resolve_repeatwithoutgesture.html b/third_party/WebKit/LayoutTests/vr/requestPresent_resolve_repeatwithoutgesture.html new file mode 100644 index 0000000..1f2e6d5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/vr/requestPresent_resolve_repeatwithoutgesture.html
@@ -0,0 +1,51 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../resources/mojo-helpers.js"></script> +<script src="resources/fake-vr-displays.js"></script> +<script src="resources/mock-vr-service.js"></script> +<canvas id="webgl-canvas"></canvas> +<script src="resources/presentation-setup.js"></script> +<script> +let fakeDisplays = fakeVRDisplays(); + +vr_test((service) => { + return navigator.getVRDisplays().then(displays => { + assert_true(displays != null); + assert_equals(1, displays.length); + var asyncTest = async_test( + "requestPresent resolves and actually presents"); + runWithUserGesture( () => { + displays[0].requestPresent([{ source : webglCanvas }]).then( () => { + asyncTest.step( () => { + assert_true(displays[0].isPresenting); + }, "Display should be presenting"); + + // Call requestPresent again after a short delay, but without a user + // gesture. Should resolve because it's already presenting. + setTimeout(() => { + displays[0].requestPresent([{ source : webglCanvas }]).then( () => { + asyncTest.step( () => { + assert_true(displays[0].isPresenting); + }, "Display should still be presenting"); + }, (err) => { + asyncTest.step( () => { + assert_unreached(err); + }, "Should never reach here"); + }).then( () => { + asyncTest.done(); + }); + }, 100); + + }, (err) => { + asyncTest.step( () => { + assert_unreached(err); + }, "Should never reach here"); + asyncTest.done(); + }); + }); + }); +}, [fakeDisplays['Pixel']], +'Test requestPresent resolves without a user gesture when already presenting'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_resolve_webgl2.html b/third_party/WebKit/LayoutTests/vr/requestPresent_resolve_webgl2.html new file mode 100644 index 0000000..d45e05b --- /dev/null +++ b/third_party/WebKit/LayoutTests/vr/requestPresent_resolve_webgl2.html
@@ -0,0 +1,41 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../resources/mojo-helpers.js"></script> +<script src="resources/fake-vr-displays.js"></script> +<script src="resources/mock-vr-service.js"></script> +<canvas id="webgl2-canvas"></canvas> +<script src="resources/presentation-setup.js"></script> +<script> +let fakeDisplays = fakeVRDisplays(); + +vr_test((service) => { + if (!gl) { + // WebGL 2 is not supported. This is legal. + return Promise.resolve(); + } else { + return navigator.getVRDisplays().then(displays => { + assert_true(displays != null); + assert_equals(1, displays.length); + + var asyncTest = async_test( + "requestPresent resolves and actually presents"); + runWithUserGesture( () => { + displays[0].requestPresent([{ source : webglCanvas }]).then( () => { + asyncTest.step( () => { + assert_true(displays[0].isPresenting); + }, "Display should be presenting"); + }, (err) => { + asyncTest.step( () => { + assert_unreached(err); + }, "Should never reach here"); + }).then( () => { + asyncTest.done(); + }); + }); + }); + } +}, [fakeDisplays['Pixel']], +'Test requestPresent resolves when provided a WebGL2 canvas'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/vr/resources/fake-vr-displays.js b/third_party/WebKit/LayoutTests/vr/resources/fake-vr-displays.js index f469e9c..ce8fb48 100644 --- a/third_party/WebKit/LayoutTests/vr/resources/fake-vr-displays.js +++ b/third_party/WebKit/LayoutTests/vr/resources/fake-vr-displays.js
@@ -38,6 +38,7 @@ hasPosition : false, hasExternalDisplay : false, canPresent : true, + maxLayers: 1 }, stageParameters : null, leftEye : {
diff --git a/third_party/WebKit/LayoutTests/vr/resources/presentation-setup.js b/third_party/WebKit/LayoutTests/vr/resources/presentation-setup.js index 33c8269e..b024216 100644 --- a/third_party/WebKit/LayoutTests/vr/resources/presentation-setup.js +++ b/third_party/WebKit/LayoutTests/vr/resources/presentation-setup.js
@@ -1,9 +1,14 @@ +var webgl2 = false; var webglCanvas = document.getElementById("webgl-canvas"); +if (!webglCanvas) { + webglCanvas = document.getElementById("webgl2-canvas"); + webgl2 = true; +} var glAttributes = { alpha : false, antialias : false, }; -var gl = webglCanvas.getContext("webgl", glAttributes); +var gl = webglCanvas.getContext(webgl2 ? "webgl2" : "webgl", glAttributes); function runWithUserGesture(fn) { function thunk() {
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp index 8a4f76b..6b0a0ed 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -244,7 +244,7 @@ DocumentMarker::MarkerTypeIndex markerListIndex = MarkerTypeToMarkerIndex(newMarker.type()); if (!markers->at(markerListIndex)) { - markers->insert(markerListIndex, new MarkerList); + markers->at(markerListIndex) = new MarkerList; } Member<MarkerList>& list = markers->at(markerListIndex);
diff --git a/third_party/WebKit/Source/core/events/MouseEvent.cpp b/third_party/WebKit/Source/core/events/MouseEvent.cpp index 6d6f1cf54..5d64a5f 100644 --- a/third_party/WebKit/Source/core/events/MouseEvent.cpp +++ b/third_party/WebKit/Source/core/events/MouseEvent.cpp
@@ -186,6 +186,40 @@ bool canBubble, bool cancelable, AbstractView* abstractView, + PlatformMouseEvent::SyntheticEventType syntheticEventType, + const String& region, + const WebMouseEvent& event) + : UIEventWithKeyState( + eventType, + canBubble, + cancelable, + abstractView, + 0, + static_cast<PlatformEvent::Modifiers>(event.modifiers), + TimeTicks::FromSeconds(event.timeStampSeconds), + syntheticEventType == PlatformMouseEvent::FromTouch + ? InputDeviceCapabilities::firesTouchEventsSourceCapabilities() + : InputDeviceCapabilities:: + doesntFireTouchEventsSourceCapabilities()), + m_screenLocation(event.globalX, event.globalY), + m_movementDelta(flooredIntPoint(event.movementInRootFrame())), + m_positionType(syntheticEventType == PlatformMouseEvent::Positionless + ? PositionType::Positionless + : PositionType::Position), + m_button(0), + m_buttons(platformModifiersToButtons(event.modifiers)), + m_syntheticEventType(syntheticEventType), + m_region(region) { + IntPoint rootFrameCoordinates = flooredIntPoint(event.positionInRootFrame()); + initCoordinatesFromRootFrame(rootFrameCoordinates.x(), + rootFrameCoordinates.y()); +} + +MouseEvent::MouseEvent( + const AtomicString& eventType, + bool canBubble, + bool cancelable, + AbstractView* abstractView, int detail, int screenX, int screenY, @@ -225,36 +259,7 @@ m_region(region) { if (mouseEvent) m_mouseEvent.reset(new PlatformMouseEvent(*mouseEvent)); - - DoublePoint adjustedPageLocation; - DoubleSize scrollOffset; - - LocalFrame* frame = view() && view()->isLocalDOMWindow() - ? toLocalDOMWindow(view())->frame() - : nullptr; - if (frame && hasPosition()) { - if (FrameView* frameView = frame->view()) { - adjustedPageLocation = - frameView->rootFrameToContents(IntPoint(windowX, windowY)); - scrollOffset = frameView->scrollOffsetInt(); - float scaleFactor = 1 / frame->pageZoomFactor(); - if (scaleFactor != 1.0f) { - adjustedPageLocation.scale(scaleFactor, scaleFactor); - scrollOffset.scale(scaleFactor, scaleFactor); - } - } - } - - m_clientLocation = adjustedPageLocation - scrollOffset; - m_pageLocation = adjustedPageLocation; - - // Set up initial values for coordinates. - // Correct values are computed lazily, see computeRelativePosition. - m_layerLocation = m_pageLocation; - m_offsetLocation = m_pageLocation; - - computePageLocation(); - m_hasCachedRelativePosition = false; + initCoordinatesFromRootFrame(windowX, windowY); } MouseEvent::MouseEvent(const AtomicString& eventType, @@ -286,6 +291,38 @@ m_hasCachedRelativePosition = false; } +void MouseEvent::initCoordinatesFromRootFrame(int windowX, int windowY) { + DoublePoint adjustedPageLocation; + DoubleSize scrollOffset; + + LocalFrame* frame = view() && view()->isLocalDOMWindow() + ? toLocalDOMWindow(view())->frame() + : nullptr; + if (frame && hasPosition()) { + if (FrameView* frameView = frame->view()) { + adjustedPageLocation = + frameView->rootFrameToContents(IntPoint(windowX, windowY)); + scrollOffset = frameView->scrollOffsetInt(); + float scaleFactor = 1 / frame->pageZoomFactor(); + if (scaleFactor != 1.0f) { + adjustedPageLocation.scale(scaleFactor, scaleFactor); + scrollOffset.scale(scaleFactor, scaleFactor); + } + } + } + + m_clientLocation = adjustedPageLocation - scrollOffset; + m_pageLocation = adjustedPageLocation; + + // Set up initial values for coordinates. + // Correct values are computed lazily, see computeRelativePosition. + m_layerLocation = m_pageLocation; + m_offsetLocation = m_pageLocation; + + computePageLocation(); + m_hasCachedRelativePosition = false; +} + MouseEvent::~MouseEvent() {} unsigned short MouseEvent::platformModifiersToButtons(unsigned modifiers) {
diff --git a/third_party/WebKit/Source/core/events/MouseEvent.h b/third_party/WebKit/Source/core/events/MouseEvent.h index d554587..a6fa57b 100644 --- a/third_party/WebKit/Source/core/events/MouseEvent.h +++ b/third_party/WebKit/Source/core/events/MouseEvent.h
@@ -199,6 +199,14 @@ bool canBubble, bool cancelable, AbstractView*, + PlatformMouseEvent::SyntheticEventType, + const String& region, + const WebMouseEvent&); + + MouseEvent(const AtomicString& type, + bool canBubble, + bool cancelable, + AbstractView*, int detail, int screenX, int screenY, @@ -239,6 +247,7 @@ unsigned short buttons = 0); void initCoordinates(const double clientX, const double clientY); + void initCoordinatesFromRootFrame(int windowX, int windowY); void receivedTarget() final; void computePageLocation();
diff --git a/third_party/WebKit/Source/core/events/UIEventWithKeyState.h b/third_party/WebKit/Source/core/events/UIEventWithKeyState.h index 88c6e19..43bde9fe 100644 --- a/third_party/WebKit/Source/core/events/UIEventWithKeyState.h +++ b/third_party/WebKit/Source/core/events/UIEventWithKeyState.h
@@ -27,6 +27,7 @@ #include "core/CoreExport.h" #include "core/events/EventModifierInit.h" #include "core/events/UIEvent.h" +#include "platform/PlatformEvent.h" namespace blink {
diff --git a/third_party/WebKit/Source/core/events/WheelEvent.cpp b/third_party/WebKit/Source/core/events/WheelEvent.cpp index 40ee82e..5f39f8b 100644 --- a/third_party/WebKit/Source/core/events/WheelEvent.cpp +++ b/third_party/WebKit/Source/core/events/WheelEvent.cpp
@@ -25,49 +25,32 @@ #include "core/clipboard/DataTransfer.h" #include "platform/PlatformMouseEvent.h" -#include "platform/PlatformWheelEvent.h" namespace blink { -inline static unsigned convertDeltaMode(const PlatformWheelEvent& event) { - return event.granularity() == ScrollByPageWheelEvent - ? WheelEvent::kDomDeltaPage - : WheelEvent::kDomDeltaPixel; +namespace { + +unsigned convertDeltaMode(const WebMouseWheelEvent& event) { + return event.scrollByPage ? WheelEvent::kDomDeltaPage + : WheelEvent::kDomDeltaPixel; } // Negate a long value without integer overflow. -inline static long negateIfPossible(long value) { +long negateIfPossible(long value) { if (value == LONG_MIN) return value; return -value; } -WheelEvent* WheelEvent::create(const PlatformWheelEvent& event, +} // namespace + +WheelEvent* WheelEvent::create(const WebMouseWheelEvent& event, AbstractView* view) { - return new WheelEvent( - FloatPoint(event.wheelTicksX(), event.wheelTicksY()), - FloatPoint(event.deltaX(), event.deltaY()), convertDeltaMode(event), view, - event.globalPosition(), event.position(), event.getModifiers(), - MouseEvent::platformModifiersToButtons(event.getModifiers()), - event.timestamp(), event.resendingPluginId(), - event.hasPreciseScrollingDeltas(), - static_cast<Event::RailsMode>(event.getRailsMode()), event.cancelable() -#if OS(MACOSX) - , - static_cast<WheelEventPhase>(event.phase()), - static_cast<WheelEventPhase>(event.momentumPhase()) -#endif - ); + return new WheelEvent(event, view); } WheelEvent::WheelEvent() - : m_deltaX(0), - m_deltaY(0), - m_deltaZ(0), - m_deltaMode(kDomDeltaPixel), - m_resendingPluginId(-1), - m_hasPreciseScrollingDeltas(false), - m_railsMode(RailsModeFree) {} + : m_deltaX(0), m_deltaY(0), m_deltaZ(0), m_deltaMode(kDomDeltaPixel) {} WheelEvent::WheelEvent(const AtomicString& type, const WheelEventInit& initializer) @@ -83,120 +66,26 @@ ? initializer.deltaY() : negateIfPossible(initializer.wheelDeltaY())), m_deltaZ(initializer.deltaZ()), - m_deltaMode(initializer.deltaMode()), - m_resendingPluginId(-1), - m_hasPreciseScrollingDeltas(false), - m_railsMode(RailsModeFree) -#if OS(MACOSX) - , - m_phase(WheelEventPhaseNone), - m_momentumPhase(WheelEventPhaseNone) -#endif -{ -} + m_deltaMode(initializer.deltaMode()) {} -WheelEvent::WheelEvent(const FloatPoint& wheelTicks, - const FloatPoint& rawDelta, - unsigned deltaMode, - AbstractView* view, - const IntPoint& screenLocation, - const IntPoint& windowLocation, - PlatformEvent::Modifiers modifiers, - unsigned short buttons, - TimeTicks platformTimeStamp, - int resendingPluginId, - bool hasPreciseScrollingDeltas, - RailsMode railsMode, - bool cancelable) +WheelEvent::WheelEvent(const WebMouseWheelEvent& event, AbstractView* view) : MouseEvent(EventTypeNames::wheel, true, - cancelable, + event.isCancelable(), view, - 0, - screenLocation.x(), - screenLocation.y(), - windowLocation.x(), - windowLocation.y(), - 0, - 0, - modifiers, - 0, - buttons, - nullptr, - platformTimeStamp, PlatformMouseEvent::RealOrIndistinguishable, // TODO(zino): Should support canvas hit region because the // wheel event is a kind of mouse event. Please see // http://crbug.com/594075 String(), - nullptr), - m_wheelDelta(wheelTicks.x() * TickMultiplier, - wheelTicks.y() * TickMultiplier), - m_deltaX(-rawDelta.x()), - m_deltaY(-rawDelta.y()), + event), + m_wheelDelta(event.wheelTicksX * TickMultiplier, + event.wheelTicksY * TickMultiplier), + m_deltaX(-event.deltaXInRootFrame()), + m_deltaY(-event.deltaYInRootFrame()), m_deltaZ(0), - m_deltaMode(deltaMode), - m_resendingPluginId(resendingPluginId), - m_hasPreciseScrollingDeltas(hasPreciseScrollingDeltas), - m_railsMode(railsMode) -#if OS(MACOSX) - , - m_phase(WheelEventPhaseNone), - m_momentumPhase(WheelEventPhaseNone) -#endif -{ -} - -#if OS(MACOSX) -WheelEvent::WheelEvent(const FloatPoint& wheelTicks, - const FloatPoint& rawDelta, - unsigned deltaMode, - AbstractView* view, - const IntPoint& screenLocation, - const IntPoint& windowLocation, - PlatformEvent::Modifiers modifiers, - unsigned short buttons, - TimeTicks platformTimeStamp, - int resendingPluginId, - bool hasPreciseScrollingDeltas, - RailsMode railsMode, - bool cancelable, - WheelEventPhase phase, - WheelEventPhase momentumPhase) - : MouseEvent(EventTypeNames::wheel, - true, - cancelable, - view, - 0, - screenLocation.x(), - screenLocation.y(), - windowLocation.x(), - windowLocation.y(), - 0, - 0, - modifiers, - 0, - buttons, - nullptr, - platformTimeStamp, - PlatformMouseEvent::RealOrIndistinguishable, - // TODO(zino): Should support canvas hit region because the - // wheel event is a kind of mouse event. Please see - // http://crbug.com/594075 - String(), - nullptr), - m_wheelDelta(wheelTicks.x() * TickMultiplier, - wheelTicks.y() * TickMultiplier), - m_deltaX(-rawDelta.x()), - m_deltaY(-rawDelta.y()), - m_deltaZ(0), - m_deltaMode(deltaMode), - m_resendingPluginId(resendingPluginId), - m_hasPreciseScrollingDeltas(hasPreciseScrollingDeltas), - m_railsMode(railsMode), - m_phase(phase), - m_momentumPhase(momentumPhase) {} -#endif + m_deltaMode(convertDeltaMode(event)), + m_nativeEvent(event) {} const AtomicString& WheelEvent::interfaceName() const { return EventNames::WheelEvent;
diff --git a/third_party/WebKit/Source/core/events/WheelEvent.h b/third_party/WebKit/Source/core/events/WheelEvent.h index c263d43..4e7043c 100644 --- a/third_party/WebKit/Source/core/events/WheelEvent.h +++ b/third_party/WebKit/Source/core/events/WheelEvent.h
@@ -30,23 +30,10 @@ #include "core/events/MouseEvent.h" #include "core/events/WheelEventInit.h" #include "platform/geometry/FloatPoint.h" +#include "public/platform/WebMouseWheelEvent.h" namespace blink { -class PlatformWheelEvent; - -#if OS(MACOSX) -enum WheelEventPhase { - WheelEventPhaseNone = 0, - WheelEventPhaseBegan = 1 << 0, - WheelEventPhaseStationary = 1 << 1, - WheelEventPhaseChanged = 1 << 2, - WheelEventPhaseEnded = 1 << 3, - WheelEventPhaseCancelled = 1 << 4, - WheelEventPhaseMayBegin = 1 << 5, -}; -#endif - class CORE_EXPORT WheelEvent final : public MouseEvent { DEFINE_WRAPPERTYPEINFO(); @@ -57,7 +44,7 @@ static WheelEvent* create() { return new WheelEvent; } - static WheelEvent* create(const PlatformWheelEvent& platformEvent, + static WheelEvent* create(const WebMouseWheelEvent& nativeEvent, AbstractView*); static WheelEvent* create(const AtomicString& type, @@ -65,36 +52,6 @@ return new WheelEvent(type, initializer); } - static WheelEvent* create(const FloatPoint& wheelTicks, - const FloatPoint& rawDelta, - unsigned deltaMode, - AbstractView* view, - const IntPoint& screenLocation, - const IntPoint& windowLocation, - PlatformEvent::Modifiers modifiers, - unsigned short buttons, - TimeTicks platformTimeStamp, - int resendingPluginId, - bool hasPreciseScrollingDeltas, - RailsMode railsMode, - bool cancelable -#if OS(MACOSX) - , - WheelEventPhase phase, - WheelEventPhase momentumPhase -#endif - ) { - return new WheelEvent(wheelTicks, rawDelta, deltaMode, view, screenLocation, - windowLocation, modifiers, buttons, platformTimeStamp, - resendingPluginId, hasPreciseScrollingDeltas, - railsMode, cancelable -#if OS(MACOSX) - , - phase, momentumPhase -#endif - ); - } - double deltaX() const { return m_deltaX; } // Positive when scrolling right. double deltaY() const { return m_deltaY; } // Positive when scrolling down. double deltaZ() const { return m_deltaZ; } @@ -108,15 +65,6 @@ return m_wheelDelta.y(); } // Deprecated, negative when scrolling down. unsigned deltaMode() const { return m_deltaMode; } - float ticksX() const { - return static_cast<float>(m_wheelDelta.x()) / TickMultiplier; - } - float ticksY() const { - return static_cast<float>(m_wheelDelta.y()) / TickMultiplier; - } - int resendingPluginId() const { return m_resendingPluginId; } - bool hasPreciseScrollingDeltas() const { return m_hasPreciseScrollingDeltas; } - RailsMode getRailsMode() const { return m_railsMode; } const AtomicString& interfaceName() const override; bool isMouseEvent() const override; @@ -124,59 +72,21 @@ EventDispatchMediator* createMediator() override; -#if OS(MACOSX) - WheelEventPhase phase() const { return m_phase; } - WheelEventPhase momentumPhase() const { return m_momentumPhase; } -#endif + const WebMouseWheelEvent& nativeEvent() const { return m_nativeEvent; } DECLARE_VIRTUAL_TRACE(); private: WheelEvent(); WheelEvent(const AtomicString&, const WheelEventInit&); - WheelEvent(const FloatPoint& wheelTicks, - const FloatPoint& rawDelta, - unsigned, - AbstractView*, - const IntPoint& screenLocation, - const IntPoint& windowLocation, - PlatformEvent::Modifiers, - unsigned short buttons, - TimeTicks platformTimeStamp, - int resendingPluginId, - bool hasPreciseScrollingDeltas, - RailsMode, - bool cancelable); -#if OS(MACOSX) - WheelEvent(const FloatPoint& wheelTicks, - const FloatPoint& rawDelta, - unsigned, - AbstractView*, - const IntPoint& screenLocation, - const IntPoint& windowLocation, - PlatformEvent::Modifiers, - unsigned short buttons, - TimeTicks platformTimeStamp, - int resendingPluginId, - bool hasPreciseScrollingDeltas, - RailsMode, - bool cancelable, - WheelEventPhase phase, - WheelEventPhase momentumPhase); -#endif + WheelEvent(const WebMouseWheelEvent&, AbstractView*); IntPoint m_wheelDelta; double m_deltaX; double m_deltaY; double m_deltaZ; unsigned m_deltaMode; - int m_resendingPluginId; - bool m_hasPreciseScrollingDeltas; - RailsMode m_railsMode; -#if OS(MACOSX) - WheelEventPhase m_phase; - WheelEventPhase m_momentumPhase; -#endif + WebMouseWheelEvent m_nativeEvent; }; DEFINE_EVENT_TYPE_CASTS(WheelEvent);
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp index 32a751c9..77571b8 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.cpp +++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -88,7 +88,6 @@ #include "core/style/CursorData.h" #include "core/svg/SVGDocumentExtensions.h" #include "platform/PlatformTouchEvent.h" -#include "platform/PlatformWheelEvent.h" #include "platform/RuntimeEnabledFeatures.h" #include "platform/WindowsKeyboardCodes.h" #include "platform/geometry/FloatPoint.h" @@ -98,6 +97,7 @@ #include "platform/scroll/ScrollAnimatorBase.h" #include "platform/scroll/Scrollbar.h" #include "public/platform/WebInputEvent.h" +#include "public/platform/WebMouseWheelEvent.h" #include "wtf/Assertions.h" #include "wtf/CurrentTime.h" #include "wtf/PtrUtil.h" @@ -1270,17 +1270,18 @@ } WebInputEventResult EventHandler::handleWheelEvent( - const PlatformWheelEvent& event) { + const WebMouseWheelEvent& event) { #if OS(MACOSX) // Filter Mac OS specific phases, usually with a zero-delta. // https://crbug.com/553732 - // TODO(chongz): EventSender sends events with |PlatformWheelEventPhaseNone|, + // TODO(chongz): EventSender sends events with + // |WebMouseWheelEvent::PhaseNone|, // but it shouldn't. - const int kPlatformWheelEventPhaseNoEventMask = - PlatformWheelEventPhaseEnded | PlatformWheelEventPhaseCancelled | - PlatformWheelEventPhaseMayBegin; - if ((event.phase() & kPlatformWheelEventPhaseNoEventMask) || - (event.momentumPhase() & kPlatformWheelEventPhaseNoEventMask)) + const int kWheelEventPhaseNoEventMask = WebMouseWheelEvent::PhaseEnded | + WebMouseWheelEvent::PhaseCancelled | + WebMouseWheelEvent::PhaseMayBegin; + if ((event.phase & kWheelEventPhaseNoEventMask) || + (event.momentumPhase & kWheelEventPhaseNoEventMask)) return WebInputEventResult::NotHandled; #endif Document* doc = m_frame->document(); @@ -1292,7 +1293,8 @@ if (!view) return WebInputEventResult::NotHandled; - LayoutPoint vPoint = view->rootFrameToContents(event.position()); + LayoutPoint vPoint = + view->rootFrameToContents(flooredIntPoint(event.positionInRootFrame())); HitTestRequest request(HitTestRequest::ReadOnly); HitTestResult result(request, vPoint);
diff --git a/third_party/WebKit/Source/core/input/EventHandler.h b/third_party/WebKit/Source/core/input/EventHandler.h index 0d6cca7..9f29bc4d 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.h +++ b/third_party/WebKit/Source/core/input/EventHandler.h
@@ -70,12 +70,12 @@ class Node; class OptionalCursor; class PlatformTouchEvent; -class PlatformWheelEvent; class ScrollableArea; class Scrollbar; class SelectionController; class TextEvent; class WebGestureEvent; +class WebMouseWheelEvent; class CORE_EXPORT EventHandler final : public GarbageCollectedFinalized<EventHandler> { @@ -149,7 +149,7 @@ WebInputEventResult handleMousePressEvent(const PlatformMouseEvent&); WebInputEventResult handleMouseReleaseEvent(const PlatformMouseEvent&); - WebInputEventResult handleWheelEvent(const PlatformWheelEvent&); + WebInputEventResult handleWheelEvent(const WebMouseWheelEvent&); // Called on the local root frame exactly once per gesture event. WebInputEventResult handleGestureEvent(const WebGestureEvent&);
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp index 7189ef4..53356ee 100644 --- a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp
@@ -336,36 +336,31 @@ } int LayoutThemeDefault::menuListArrowWidthInDIP() const { + if (m_menuListArrowWidthInDIP > 0) + return m_menuListArrowWidthInDIP; int width = Platform::current() ->themeEngine() ->getSize(WebThemeEngine::PartScrollbarUpArrow) .width; - return width > 0 ? width : 15; + const_cast<LayoutThemeDefault*>(this)->m_menuListArrowWidthInDIP = + width > 0 ? width : 15; + return m_menuListArrowWidthInDIP; } float LayoutThemeDefault::clampedMenuListArrowPaddingSize( const HostWindow* host, const ComputedStyle& style) const { - if (m_cachedMenuListArrowPaddingSize > 0 && - style.effectiveZoom() == m_cachedMenuListArrowZoomLevel) - return m_cachedMenuListArrowPaddingSize; - m_cachedMenuListArrowZoomLevel = style.effectiveZoom(); int originalSize = menuListArrowWidthInDIP(); int scaledSize = host ? host->windowToViewportScalar(originalSize) : originalSize; // The result should not be samller than the scrollbar thickness in order to // secure space for scrollbar in popup. float deviceScale = 1.0f * scaledSize / originalSize; - float size; - if (m_cachedMenuListArrowZoomLevel < deviceScale) { - size = scaledSize; - } else { - // The value should be zoomed though scrollbars aren't scaled by zoom. - // crbug.com/432795. - size = originalSize * m_cachedMenuListArrowZoomLevel; - } - m_cachedMenuListArrowPaddingSize = size; - return size; + if (style.effectiveZoom() < deviceScale) + return scaledSize; + // The value should be zoomed though scrollbars aren't scaled by zoom. + // crbug.com/432795. + return originalSize * style.effectiveZoom(); } // static
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.h b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.h index bec946e..498edfd 100644 --- a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.h +++ b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.h
@@ -159,9 +159,7 @@ static unsigned m_inactiveSelectionForegroundColor; ThemePainterDefault m_painter; - // Cached values for crbug.com/673754. - mutable float m_cachedMenuListArrowZoomLevel = 0; - mutable float m_cachedMenuListArrowPaddingSize = 0; + int m_menuListArrowWidthInDIP = 0; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp index 2213c24..372dd6a4 100644 --- a/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp +++ b/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp
@@ -226,13 +226,14 @@ // Emulate starting a real load, but don't expect any "real" // WebURLLoaderClient callbacks. - ImageResource* cachedImage = ImageResource::create(ResourceRequest(testURL)); - cachedImage->setIdentifier(createUniqueIdentifier()); - fetcher->startLoad(cachedImage); + ImageResource* imageResource = + ImageResource::create(ResourceRequest(testURL)); + imageResource->setIdentifier(createUniqueIdentifier()); + fetcher->startLoad(imageResource); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(cachedImage); - EXPECT_EQ(Resource::Pending, cachedImage->getStatus()); + new MockImageResourceClient(imageResource); + EXPECT_EQ(Resource::Pending, imageResource->getStatus()); // Send the multipart response. No image or data buffer is created. Note that // the response must be routed through ResourceLoader to ensure the load is @@ -240,58 +241,58 @@ ResourceResponse multipartResponse(KURL(), "multipart/x-mixed-replace", 0, nullAtom, String()); multipartResponse.setMultipartBoundary("boundary", strlen("boundary")); - cachedImage->loader()->didReceiveResponse( + imageResource->loader()->didReceiveResponse( WrappedResourceResponse(multipartResponse), nullptr); - EXPECT_FALSE(cachedImage->resourceBuffer()); - EXPECT_FALSE(cachedImage->getContent()->hasImage()); + EXPECT_FALSE(imageResource->resourceBuffer()); + EXPECT_FALSE(imageResource->getContent()->hasImage()); EXPECT_EQ(0, client->imageChangedCount()); EXPECT_FALSE(client->notifyFinishedCalled()); - EXPECT_EQ("multipart/x-mixed-replace", cachedImage->response().mimeType()); + EXPECT_EQ("multipart/x-mixed-replace", imageResource->response().mimeType()); const char firstPart[] = "--boundary\n" "Content-Type: image/svg+xml\n\n"; - cachedImage->appendData(firstPart, strlen(firstPart)); + imageResource->appendData(firstPart, strlen(firstPart)); // Send the response for the first real part. No image or data buffer is // created. - EXPECT_FALSE(cachedImage->resourceBuffer()); - EXPECT_FALSE(cachedImage->getContent()->hasImage()); + EXPECT_FALSE(imageResource->resourceBuffer()); + EXPECT_FALSE(imageResource->getContent()->hasImage()); EXPECT_EQ(0, client->imageChangedCount()); EXPECT_FALSE(client->notifyFinishedCalled()); - EXPECT_EQ("image/svg+xml", cachedImage->response().mimeType()); + EXPECT_EQ("image/svg+xml", imageResource->response().mimeType()); const char secondPart[] = "<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1'><rect " "width='1' height='1' fill='green'/></svg>\n"; // The first bytes arrive. The data buffer is created, but no image is // created. - cachedImage->appendData(secondPart, strlen(secondPart)); - EXPECT_TRUE(cachedImage->resourceBuffer()); - EXPECT_FALSE(cachedImage->getContent()->hasImage()); + imageResource->appendData(secondPart, strlen(secondPart)); + EXPECT_TRUE(imageResource->resourceBuffer()); + EXPECT_FALSE(imageResource->getContent()->hasImage()); EXPECT_EQ(0, client->imageChangedCount()); EXPECT_FALSE(client->notifyFinishedCalled()); // Add a client to check an assertion error doesn't happen // (crbug.com/630983). Persistent<MockImageResourceClient> client2 = - new MockImageResourceClient(cachedImage); + new MockImageResourceClient(imageResource); EXPECT_EQ(0, client2->imageChangedCount()); EXPECT_FALSE(client2->notifyFinishedCalled()); const char thirdPart[] = "--boundary"; - cachedImage->appendData(thirdPart, strlen(thirdPart)); - ASSERT_TRUE(cachedImage->resourceBuffer()); - EXPECT_EQ(strlen(secondPart) - 1, cachedImage->resourceBuffer()->size()); + imageResource->appendData(thirdPart, strlen(thirdPart)); + ASSERT_TRUE(imageResource->resourceBuffer()); + EXPECT_EQ(strlen(secondPart) - 1, imageResource->resourceBuffer()->size()); // This part finishes. The image is created, callbacks are sent, and the data // buffer is cleared. - cachedImage->loader()->didFinishLoading(0.0, 0, 0); - EXPECT_TRUE(cachedImage->resourceBuffer()); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); - EXPECT_EQ(1, cachedImage->getContent()->getImage()->width()); - EXPECT_EQ(1, cachedImage->getContent()->getImage()->height()); + imageResource->loader()->didFinishLoading(0.0, 0, 0); + EXPECT_TRUE(imageResource->resourceBuffer()); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->width()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->height()); EXPECT_EQ(1, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_EQ(1, client2->imageChangedCount()); @@ -306,94 +307,95 @@ ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); // Emulate starting a real load. - ImageResource* cachedImage = ImageResource::create(ResourceRequest(testURL)); - cachedImage->setIdentifier(createUniqueIdentifier()); + ImageResource* imageResource = + ImageResource::create(ResourceRequest(testURL)); + imageResource->setIdentifier(createUniqueIdentifier()); - fetcher->startLoad(cachedImage); - memoryCache()->add(cachedImage); + fetcher->startLoad(imageResource); + memoryCache()->add(imageResource); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(cachedImage); - EXPECT_EQ(Resource::Pending, cachedImage->getStatus()); + new MockImageResourceClient(imageResource); + EXPECT_EQ(Resource::Pending, imageResource->getStatus()); // The load should still be alive, but a timer should be started to cancel the // load inside removeClient(). client->removeAsClient(); - EXPECT_EQ(Resource::Pending, cachedImage->getStatus()); + EXPECT_EQ(Resource::Pending, imageResource->getStatus()); EXPECT_TRUE(memoryCache()->resourceForURL(testURL)); // Trigger the cancel timer, ensure the load was cancelled and the resource // was evicted from the cache. blink::testing::runPendingTasks(); - EXPECT_EQ(Resource::LoadError, cachedImage->getStatus()); + EXPECT_EQ(Resource::LoadError, imageResource->getStatus()); EXPECT_FALSE(memoryCache()->resourceForURL(testURL)); } TEST(ImageResourceTest, DecodedDataRemainsWhileHasClients) { - ImageResource* cachedImage = ImageResource::create(ResourceRequest()); - cachedImage->setStatus(Resource::Pending); + ImageResource* imageResource = ImageResource::create(ResourceRequest()); + imageResource->setStatus(Resource::Pending); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(cachedImage); + new MockImageResourceClient(imageResource); // Send the image response. - cachedImage->responseReceived( + imageResource->responseReceived( ResourceResponse(KURL(), "multipart/x-mixed-replace", 0, nullAtom, String()), nullptr); - cachedImage->responseReceived( + imageResource->responseReceived( ResourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage), nullAtom, String()), nullptr); - cachedImage->appendData(reinterpret_cast<const char*>(kJpegImage), - sizeof(kJpegImage)); - EXPECT_NE(0u, cachedImage->encodedSizeMemoryUsageForTesting()); - cachedImage->finish(); - EXPECT_EQ(0u, cachedImage->encodedSizeMemoryUsageForTesting()); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); + imageResource->appendData(reinterpret_cast<const char*>(kJpegImage), + sizeof(kJpegImage)); + EXPECT_NE(0u, imageResource->encodedSizeMemoryUsageForTesting()); + imageResource->finish(); + EXPECT_EQ(0u, imageResource->encodedSizeMemoryUsageForTesting()); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); EXPECT_TRUE(client->notifyFinishedCalled()); // The prune comes when the ImageResource still has clients. The image should // not be deleted. - cachedImage->prune(); - EXPECT_TRUE(cachedImage->isAlive()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); + imageResource->prune(); + EXPECT_TRUE(imageResource->isAlive()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); // The ImageResource no longer has clients. The decoded image data should be // deleted by prune. client->removeAsClient(); - cachedImage->prune(); - EXPECT_FALSE(cachedImage->isAlive()); - EXPECT_TRUE(cachedImage->getContent()->hasImage()); - // TODO(hajimehoshi): Should check cachedImage doesn't have decoded image + imageResource->prune(); + EXPECT_FALSE(imageResource->isAlive()); + EXPECT_TRUE(imageResource->getContent()->hasImage()); + // TODO(hajimehoshi): Should check imageResource doesn't have decoded image // data. } TEST(ImageResourceTest, UpdateBitmapImages) { - ImageResource* cachedImage = ImageResource::create(ResourceRequest()); - cachedImage->setStatus(Resource::Pending); + ImageResource* imageResource = ImageResource::create(ResourceRequest()); + imageResource->setStatus(Resource::Pending); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(cachedImage); + new MockImageResourceClient(imageResource); // Send the image response. - cachedImage->responseReceived( + imageResource->responseReceived( ResourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage), nullAtom, String()), nullptr); - cachedImage->appendData(reinterpret_cast<const char*>(kJpegImage), - sizeof(kJpegImage)); - cachedImage->finish(); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); + imageResource->appendData(reinterpret_cast<const char*>(kJpegImage), + sizeof(kJpegImage)); + imageResource->finish(); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); EXPECT_EQ(2, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); - EXPECT_TRUE(cachedImage->getContent()->getImage()->isBitmapImage()); + EXPECT_TRUE(imageResource->getContent()->getImage()->isBitmapImage()); } TEST(ImageResourceTest, ReloadIfLoFiOrPlaceholderAfterFinished) { @@ -401,11 +403,11 @@ ScopedRegisteredURL scopedRegisteredURL(testURL); ResourceRequest request = ResourceRequest(testURL); request.setLoFiState(WebURLRequest::LoFiOn); - ImageResource* cachedImage = ImageResource::create(request); - cachedImage->setStatus(Resource::Pending); + ImageResource* imageResource = ImageResource::create(request); + imageResource->setStatus(Resource::Pending); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(cachedImage); + new MockImageResourceClient(imageResource); ResourceFetcher* fetcher = ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); @@ -415,13 +417,13 @@ resourceResponse.addHTTPHeaderField("chrome-proxy-content-transform", "empty-image"); - cachedImage->responseReceived(resourceResponse, nullptr); - cachedImage->appendData(reinterpret_cast<const char*>(kJpegImage), - sizeof(kJpegImage)); - cachedImage->finish(); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); + imageResource->responseReceived(resourceResponse, nullptr); + imageResource->appendData(reinterpret_cast<const char*>(kJpegImage), + sizeof(kJpegImage)); + imageResource->finish(); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); EXPECT_EQ(2, client->imageChangedCount()); EXPECT_EQ(1, client->imageNotifyFinishedCount()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnLastImageChanged()); @@ -429,27 +431,28 @@ EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnNotifyFinished()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnImageNotifyFinished()); - EXPECT_TRUE(cachedImage->getContent()->getImage()->isBitmapImage()); - EXPECT_EQ(1, cachedImage->getContent()->getImage()->width()); - EXPECT_EQ(1, cachedImage->getContent()->getImage()->height()); + EXPECT_TRUE(imageResource->getContent()->getImage()->isBitmapImage()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->width()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->height()); // Call reloadIfLoFiOrPlaceholderImage() after the image has finished loading. - cachedImage->reloadIfLoFiOrPlaceholderImage(fetcher, Resource::kReloadAlways); - EXPECT_FALSE(cachedImage->errorOccurred()); - EXPECT_FALSE(cachedImage->resourceBuffer()); - EXPECT_FALSE(cachedImage->getContent()->hasImage()); + imageResource->reloadIfLoFiOrPlaceholderImage(fetcher, + Resource::kReloadAlways); + EXPECT_FALSE(imageResource->errorOccurred()); + EXPECT_FALSE(imageResource->resourceBuffer()); + EXPECT_FALSE(imageResource->getContent()->hasImage()); EXPECT_EQ(3, client->imageChangedCount()); EXPECT_EQ(1, client->imageNotifyFinishedCount()); - cachedImage->loader()->didReceiveResponse( + imageResource->loader()->didReceiveResponse( WrappedResourceResponse(resourceResponse), nullptr); - cachedImage->loader()->didReceiveData( + imageResource->loader()->didReceiveData( reinterpret_cast<const char*>(kJpegImage2), sizeof(kJpegImage2)); - cachedImage->loader()->didFinishLoading(0.0, sizeof(kJpegImage2), - sizeof(kJpegImage2)); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); + imageResource->loader()->didFinishLoading(0.0, sizeof(kJpegImage2), + sizeof(kJpegImage2)); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); EXPECT_EQ(sizeof(kJpegImage2), client->encodedSizeOnLastImageChanged()); EXPECT_TRUE(client->notifyFinishedCalled()); @@ -457,9 +460,9 @@ EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnNotifyFinished()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnImageNotifyFinished()); - EXPECT_TRUE(cachedImage->getContent()->getImage()->isBitmapImage()); - EXPECT_EQ(50, cachedImage->getContent()->getImage()->width()); - EXPECT_EQ(50, cachedImage->getContent()->getImage()->height()); + EXPECT_TRUE(imageResource->getContent()->getImage()->isBitmapImage()); + EXPECT_EQ(50, imageResource->getContent()->getImage()->width()); + EXPECT_EQ(50, imageResource->getContent()->getImage()->height()); } TEST(ImageResourceTest, ReloadIfLoFiOrPlaceholderDuringFetch) { @@ -472,62 +475,63 @@ ResourceFetcher* fetcher = ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); - ImageResource* cachedImage = ImageResource::fetch(fetchRequest, fetcher); + ImageResource* imageResource = ImageResource::fetch(fetchRequest, fetcher); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(cachedImage); + new MockImageResourceClient(imageResource); // Send the image response. ResourceResponse initialResourceResponse( testURL, "image/jpeg", sizeof(kJpegImage), nullAtom, String()); initialResourceResponse.addHTTPHeaderField("chrome-proxy", "q=low"); - cachedImage->loader()->didReceiveResponse( + imageResource->loader()->didReceiveResponse( WrappedResourceResponse(initialResourceResponse)); - cachedImage->loader()->didReceiveData( + imageResource->loader()->didReceiveData( reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); EXPECT_EQ(1, client->imageChangedCount()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnLastImageChanged()); EXPECT_FALSE(client->notifyFinishedCalled()); - EXPECT_TRUE(cachedImage->getContent()->getImage()->isBitmapImage()); - EXPECT_EQ(1, cachedImage->getContent()->getImage()->width()); - EXPECT_EQ(1, cachedImage->getContent()->getImage()->height()); + EXPECT_TRUE(imageResource->getContent()->getImage()->isBitmapImage()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->width()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->height()); // Call reloadIfLoFiOrPlaceholderImage() while the image is still loading. - cachedImage->reloadIfLoFiOrPlaceholderImage(fetcher, Resource::kReloadAlways); - EXPECT_FALSE(cachedImage->errorOccurred()); - EXPECT_FALSE(cachedImage->resourceBuffer()); - EXPECT_FALSE(cachedImage->getContent()->hasImage()); + imageResource->reloadIfLoFiOrPlaceholderImage(fetcher, + Resource::kReloadAlways); + EXPECT_FALSE(imageResource->errorOccurred()); + EXPECT_FALSE(imageResource->resourceBuffer()); + EXPECT_FALSE(imageResource->getContent()->hasImage()); EXPECT_EQ(2, client->imageChangedCount()); EXPECT_EQ(0U, client->encodedSizeOnLastImageChanged()); // The client should not have been notified of completion yet, since the image // is still loading. EXPECT_FALSE(client->notifyFinishedCalled()); - cachedImage->loader()->didReceiveResponse( + imageResource->loader()->didReceiveResponse( WrappedResourceResponse(ResourceResponse( testURL, "image/jpeg", sizeof(kJpegImage2), nullAtom, String())), nullptr); - cachedImage->loader()->didReceiveData( + imageResource->loader()->didReceiveData( reinterpret_cast<const char*>(kJpegImage2), sizeof(kJpegImage2)); - cachedImage->loader()->didFinishLoading(0.0, sizeof(kJpegImage2), - sizeof(kJpegImage2)); + imageResource->loader()->didFinishLoading(0.0, sizeof(kJpegImage2), + sizeof(kJpegImage2)); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); EXPECT_EQ(sizeof(kJpegImage2), client->encodedSizeOnLastImageChanged()); // The client should have been notified of completion only after the reload // completed. EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_EQ(sizeof(kJpegImage2), client->encodedSizeOnNotifyFinished()); EXPECT_EQ(sizeof(kJpegImage2), client->encodedSizeOnImageNotifyFinished()); - EXPECT_TRUE(cachedImage->getContent()->getImage()->isBitmapImage()); - EXPECT_EQ(50, cachedImage->getContent()->getImage()->width()); - EXPECT_EQ(50, cachedImage->getContent()->getImage()->height()); + EXPECT_TRUE(imageResource->getContent()->getImage()->isBitmapImage()); + EXPECT_EQ(50, imageResource->getContent()->getImage()->width()); + EXPECT_EQ(50, imageResource->getContent()->getImage()->height()); } TEST(ImageResourceTest, ReloadIfLoFiOrPlaceholderForPlaceholder) { @@ -538,12 +542,13 @@ ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); FetchRequest request(testURL, FetchInitiatorInfo()); request.setAllowImagePlaceholder(); - ImageResource* image = ImageResource::fetch(request, fetcher); + ImageResource* imageResource = ImageResource::fetch(request, fetcher); EXPECT_EQ(FetchRequest::AllowPlaceholder, request.placeholderImageRequestType()); - EXPECT_EQ("bytes=0-2047", image->resourceRequest().httpHeaderField("range")); + EXPECT_EQ("bytes=0-2047", + imageResource->resourceRequest().httpHeaderField("range")); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(image); + new MockImageResourceClient(imageResource); ResourceResponse response(testURL, "image/jpeg", kJpegImageSubrangeWithDimensionsLength, nullAtom, @@ -552,24 +557,30 @@ response.setHTTPHeaderField( "content-range", buildContentRange(kJpegImageSubrangeWithDimensionsLength, sizeof(kJpegImage))); - image->loader()->didReceiveResponse(WrappedResourceResponse(response)); - image->loader()->didReceiveData(reinterpret_cast<const char*>(kJpegImage), - kJpegImageSubrangeWithDimensionsLength); - image->loader()->didFinishLoading(0.0, kJpegImageSubrangeWithDimensionsLength, - kJpegImageSubrangeWithDimensionsLength); + imageResource->loader()->didReceiveResponse( + WrappedResourceResponse(response)); + imageResource->loader()->didReceiveData( + reinterpret_cast<const char*>(kJpegImage), + kJpegImageSubrangeWithDimensionsLength); + imageResource->loader()->didFinishLoading( + 0.0, kJpegImageSubrangeWithDimensionsLength, + kJpegImageSubrangeWithDimensionsLength); - EXPECT_EQ(Resource::Cached, image->getStatus()); - EXPECT_TRUE(image->isPlaceholder()); + EXPECT_EQ(Resource::Cached, imageResource->getStatus()); + EXPECT_TRUE(imageResource->isPlaceholder()); - image->reloadIfLoFiOrPlaceholderImage(fetcher, Resource::kReloadAlways); + imageResource->reloadIfLoFiOrPlaceholderImage(fetcher, + Resource::kReloadAlways); - EXPECT_EQ(Resource::Pending, image->getStatus()); - EXPECT_FALSE(image->isPlaceholder()); - EXPECT_EQ(nullAtom, image->resourceRequest().httpHeaderField("range")); - EXPECT_EQ(static_cast<int>(WebCachePolicy::BypassingCache), - static_cast<int>(image->resourceRequest().getCachePolicy())); + EXPECT_EQ(Resource::Pending, imageResource->getStatus()); + EXPECT_FALSE(imageResource->isPlaceholder()); + EXPECT_EQ(nullAtom, + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_EQ( + static_cast<int>(WebCachePolicy::BypassingCache), + static_cast<int>(imageResource->resourceRequest().getCachePolicy())); - image->loader()->cancel(); + imageResource->loader()->cancel(); } TEST(ImageResourceTest, SVGImage) { @@ -850,15 +861,15 @@ ResourceFetcher* fetcher = ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); FetchRequest request(testURL, FetchInitiatorInfo()); - ImageResource* cachedImage = ImageResource::fetch(request, fetcher); + ImageResource* imageResource = ImageResource::fetch(request, fetcher); - cachedImage->loader()->didReceiveResponse( + imageResource->loader()->didReceiveResponse( WrappedResourceResponse( ResourceResponse(testURL, "image/jpeg", 18, nullAtom, String())), nullptr); - cachedImage->loader()->didReceiveData("notactuallyanimage", 18); - EXPECT_EQ(Resource::DecodeError, cachedImage->getStatus()); - EXPECT_FALSE(cachedImage->isLoading()); + imageResource->loader()->didReceiveData("notactuallyanimage", 18); + EXPECT_EQ(Resource::DecodeError, imageResource->getStatus()); + EXPECT_FALSE(imageResource->isLoading()); } TEST(ImageResourceTest, FetchDisallowPlaceholder) { @@ -866,36 +877,38 @@ ScopedRegisteredURL scopedRegisteredURL(testURL); FetchRequest request(testURL, FetchInitiatorInfo()); - ImageResource* image = ImageResource::fetch( + ImageResource* imageResource = ImageResource::fetch( request, ResourceFetcher::create(ImageResourceTestMockFetchContext::create())); EXPECT_EQ(FetchRequest::DisallowPlaceholder, request.placeholderImageRequestType()); - EXPECT_EQ(nullAtom, image->resourceRequest().httpHeaderField("range")); - EXPECT_FALSE(image->isPlaceholder()); + EXPECT_EQ(nullAtom, + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_FALSE(imageResource->isPlaceholder()); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(image); + new MockImageResourceClient(imageResource); - image->loader()->didReceiveResponse(WrappedResourceResponse(ResourceResponse( - testURL, "image/jpeg", sizeof(kJpegImage), nullAtom, String()))); - image->loader()->didReceiveData(reinterpret_cast<const char*>(kJpegImage), - sizeof(kJpegImage)); - image->loader()->didFinishLoading(0.0, sizeof(kJpegImage), - sizeof(kJpegImage)); + imageResource->loader()->didReceiveResponse( + WrappedResourceResponse(ResourceResponse( + testURL, "image/jpeg", sizeof(kJpegImage), nullAtom, String()))); + imageResource->loader()->didReceiveData( + reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); + imageResource->loader()->didFinishLoading(0.0, sizeof(kJpegImage), + sizeof(kJpegImage)); - EXPECT_EQ(Resource::Cached, image->getStatus()); - EXPECT_EQ(sizeof(kJpegImage), image->encodedSize()); - EXPECT_FALSE(image->isPlaceholder()); + EXPECT_EQ(Resource::Cached, imageResource->getStatus()); + EXPECT_EQ(sizeof(kJpegImage), imageResource->encodedSize()); + EXPECT_FALSE(imageResource->isPlaceholder()); EXPECT_LT(0, client->imageChangedCount()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnLastImageChanged()); EXPECT_TRUE(client->notifyFinishedCalled()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnNotifyFinished()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnImageNotifyFinished()); - ASSERT_TRUE(image->getContent()->hasImage()); - EXPECT_EQ(1, image->getContent()->getImage()->width()); - EXPECT_EQ(1, image->getContent()->getImage()->height()); - EXPECT_TRUE(image->getContent()->getImage()->isBitmapImage()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->width()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->height()); + EXPECT_TRUE(imageResource->getContent()->getImage()->isBitmapImage()); } TEST(ImageResourceTest, FetchAllowPlaceholderDataURL) { @@ -905,13 +918,14 @@ sizeof(kJpegImage))); FetchRequest request(testURL, FetchInitiatorInfo()); request.setAllowImagePlaceholder(); - ImageResource* image = ImageResource::fetch( + ImageResource* imageResource = ImageResource::fetch( request, ResourceFetcher::create(ImageResourceTestMockFetchContext::create())); EXPECT_EQ(FetchRequest::DisallowPlaceholder, request.placeholderImageRequestType()); - EXPECT_EQ(nullAtom, image->resourceRequest().httpHeaderField("range")); - EXPECT_FALSE(image->isPlaceholder()); + EXPECT_EQ(nullAtom, + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_FALSE(imageResource->isPlaceholder()); } TEST(ImageResourceTest, FetchAllowPlaceholderPostRequest) { @@ -921,15 +935,16 @@ resourceRequest.setHTTPMethod("POST"); FetchRequest request(resourceRequest, FetchInitiatorInfo()); request.setAllowImagePlaceholder(); - ImageResource* image = ImageResource::fetch( + ImageResource* imageResource = ImageResource::fetch( request, ResourceFetcher::create(ImageResourceTestMockFetchContext::create())); EXPECT_EQ(FetchRequest::DisallowPlaceholder, request.placeholderImageRequestType()); - EXPECT_EQ(nullAtom, image->resourceRequest().httpHeaderField("range")); - EXPECT_FALSE(image->isPlaceholder()); + EXPECT_EQ(nullAtom, + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_FALSE(imageResource->isPlaceholder()); - image->loader()->cancel(); + imageResource->loader()->cancel(); } TEST(ImageResourceTest, FetchAllowPlaceholderExistingRangeHeader) { @@ -939,15 +954,16 @@ resourceRequest.setHTTPHeaderField("range", "bytes=128-255"); FetchRequest request(resourceRequest, FetchInitiatorInfo()); request.setAllowImagePlaceholder(); - ImageResource* image = ImageResource::fetch( + ImageResource* imageResource = ImageResource::fetch( request, ResourceFetcher::create(ImageResourceTestMockFetchContext::create())); EXPECT_EQ(FetchRequest::DisallowPlaceholder, request.placeholderImageRequestType()); - EXPECT_EQ("bytes=128-255", image->resourceRequest().httpHeaderField("range")); - EXPECT_FALSE(image->isPlaceholder()); + EXPECT_EQ("bytes=128-255", + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_FALSE(imageResource->isPlaceholder()); - image->loader()->cancel(); + imageResource->loader()->cancel(); } TEST(ImageResourceTest, FetchAllowPlaceholderSuccessful) { @@ -956,15 +972,16 @@ FetchRequest request(testURL, FetchInitiatorInfo()); request.setAllowImagePlaceholder(); - ImageResource* image = ImageResource::fetch( + ImageResource* imageResource = ImageResource::fetch( request, ResourceFetcher::create(ImageResourceTestMockFetchContext::create())); EXPECT_EQ(FetchRequest::AllowPlaceholder, request.placeholderImageRequestType()); - EXPECT_EQ("bytes=0-2047", image->resourceRequest().httpHeaderField("range")); - EXPECT_TRUE(image->isPlaceholder()); + EXPECT_EQ("bytes=0-2047", + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_TRUE(imageResource->isPlaceholder()); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(image); + new MockImageResourceClient(imageResource); ResourceResponse response(testURL, "image/jpeg", kJpegImageSubrangeWithDimensionsLength, nullAtom, @@ -973,15 +990,19 @@ response.setHTTPHeaderField( "content-range", buildContentRange(kJpegImageSubrangeWithDimensionsLength, sizeof(kJpegImage))); - image->loader()->didReceiveResponse(WrappedResourceResponse(response)); - image->loader()->didReceiveData(reinterpret_cast<const char*>(kJpegImage), - kJpegImageSubrangeWithDimensionsLength); - image->loader()->didFinishLoading(0.0, kJpegImageSubrangeWithDimensionsLength, - kJpegImageSubrangeWithDimensionsLength); + imageResource->loader()->didReceiveResponse( + WrappedResourceResponse(response)); + imageResource->loader()->didReceiveData( + reinterpret_cast<const char*>(kJpegImage), + kJpegImageSubrangeWithDimensionsLength); + imageResource->loader()->didFinishLoading( + 0.0, kJpegImageSubrangeWithDimensionsLength, + kJpegImageSubrangeWithDimensionsLength); - EXPECT_EQ(Resource::Cached, image->getStatus()); - EXPECT_EQ(kJpegImageSubrangeWithDimensionsLength, image->encodedSize()); - EXPECT_TRUE(image->isPlaceholder()); + EXPECT_EQ(Resource::Cached, imageResource->getStatus()); + EXPECT_EQ(kJpegImageSubrangeWithDimensionsLength, + imageResource->encodedSize()); + EXPECT_TRUE(imageResource->isPlaceholder()); EXPECT_LT(0, client->imageChangedCount()); EXPECT_EQ(kJpegImageSubrangeWithDimensionsLength, client->encodedSizeOnLastImageChanged()); @@ -991,11 +1012,11 @@ EXPECT_EQ(kJpegImageSubrangeWithDimensionsLength, client->encodedSizeOnImageNotifyFinished()); - ASSERT_TRUE(image->getContent()->hasImage()); - EXPECT_EQ(1, image->getContent()->getImage()->width()); - EXPECT_EQ(1, image->getContent()->getImage()->height()); - EXPECT_FALSE(image->getContent()->getImage()->isBitmapImage()); - EXPECT_FALSE(image->getContent()->getImage()->isSVGImage()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->width()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->height()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isBitmapImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isSVGImage()); } TEST(ImageResourceTest, FetchAllowPlaceholderUnsuccessful) { @@ -1004,42 +1025,47 @@ FetchRequest request(testURL, FetchInitiatorInfo()); request.setAllowImagePlaceholder(); - ImageResource* image = ImageResource::fetch( + ImageResource* imageResource = ImageResource::fetch( request, ResourceFetcher::create(ImageResourceTestMockFetchContext::create())); EXPECT_EQ(FetchRequest::AllowPlaceholder, request.placeholderImageRequestType()); - EXPECT_EQ("bytes=0-2047", image->resourceRequest().httpHeaderField("range")); - EXPECT_TRUE(image->isPlaceholder()); + EXPECT_EQ("bytes=0-2047", + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_TRUE(imageResource->isPlaceholder()); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(image); + new MockImageResourceClient(imageResource); const char kBadData[] = "notanimageresponse"; - image->loader()->didReceiveResponse(WrappedResourceResponse(ResourceResponse( - testURL, "image/jpeg", sizeof(kBadData), nullAtom, String()))); - image->loader()->didReceiveData(kBadData, sizeof(kBadData)); + imageResource->loader()->didReceiveResponse( + WrappedResourceResponse(ResourceResponse( + testURL, "image/jpeg", sizeof(kBadData), nullAtom, String()))); + imageResource->loader()->didReceiveData(kBadData, sizeof(kBadData)); // The dimensions could not be extracted, so the full original image should be // loading. - EXPECT_EQ(Resource::Pending, image->getStatus()); - EXPECT_FALSE(image->isPlaceholder()); - EXPECT_EQ(nullAtom, image->resourceRequest().httpHeaderField("range")); - EXPECT_EQ(static_cast<int>(WebCachePolicy::BypassingCache), - static_cast<int>(image->resourceRequest().getCachePolicy())); + EXPECT_EQ(Resource::Pending, imageResource->getStatus()); + EXPECT_FALSE(imageResource->isPlaceholder()); + EXPECT_EQ(nullAtom, + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_EQ( + static_cast<int>(WebCachePolicy::BypassingCache), + static_cast<int>(imageResource->resourceRequest().getCachePolicy())); EXPECT_FALSE(client->notifyFinishedCalled()); EXPECT_EQ(0, client->imageNotifyFinishedCount()); - image->loader()->didReceiveResponse(WrappedResourceResponse(ResourceResponse( - testURL, "image/jpeg", sizeof(kJpegImage), nullAtom, String()))); - image->loader()->didReceiveData(reinterpret_cast<const char*>(kJpegImage), - sizeof(kJpegImage)); - image->loader()->didFinishLoading(0.0, sizeof(kJpegImage), - sizeof(kJpegImage)); + imageResource->loader()->didReceiveResponse( + WrappedResourceResponse(ResourceResponse( + testURL, "image/jpeg", sizeof(kJpegImage), nullAtom, String()))); + imageResource->loader()->didReceiveData( + reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); + imageResource->loader()->didFinishLoading(0.0, sizeof(kJpegImage), + sizeof(kJpegImage)); - EXPECT_EQ(Resource::Cached, image->getStatus()); - EXPECT_EQ(sizeof(kJpegImage), image->encodedSize()); - EXPECT_FALSE(image->isPlaceholder()); + EXPECT_EQ(Resource::Cached, imageResource->getStatus()); + EXPECT_EQ(sizeof(kJpegImage), imageResource->encodedSize()); + EXPECT_FALSE(imageResource->isPlaceholder()); EXPECT_LT(0, client->imageChangedCount()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnLastImageChanged()); EXPECT_TRUE(client->notifyFinishedCalled()); @@ -1047,10 +1073,10 @@ EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnNotifyFinished()); EXPECT_EQ(sizeof(kJpegImage), client->encodedSizeOnImageNotifyFinished()); - ASSERT_TRUE(image->getContent()->hasImage()); - EXPECT_EQ(1, image->getContent()->getImage()->width()); - EXPECT_EQ(1, image->getContent()->getImage()->height()); - EXPECT_TRUE(image->getContent()->getImage()->isBitmapImage()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->width()); + EXPECT_EQ(1, imageResource->getContent()->getImage()->height()); + EXPECT_TRUE(imageResource->getContent()->getImage()->isBitmapImage()); } TEST(ImageResourceTest, FetchAllowPlaceholderThenDisallowPlaceholder) { @@ -1061,22 +1087,25 @@ ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); FetchRequest placeholderRequest(testURL, FetchInitiatorInfo()); placeholderRequest.setAllowImagePlaceholder(); - ImageResource* image = ImageResource::fetch(placeholderRequest, fetcher); + ImageResource* imageResource = + ImageResource::fetch(placeholderRequest, fetcher); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(image); + new MockImageResourceClient(imageResource); FetchRequest nonPlaceholderRequest(testURL, FetchInitiatorInfo()); - ImageResource* secondImage = + ImageResource* secondImageResource = ImageResource::fetch(nonPlaceholderRequest, fetcher); - EXPECT_EQ(image, secondImage); - EXPECT_EQ(Resource::Pending, image->getStatus()); - EXPECT_FALSE(image->isPlaceholder()); - EXPECT_EQ(nullAtom, image->resourceRequest().httpHeaderField("range")); - EXPECT_EQ(static_cast<int>(WebCachePolicy::UseProtocolCachePolicy), - static_cast<int>(image->resourceRequest().getCachePolicy())); + EXPECT_EQ(imageResource, secondImageResource); + EXPECT_EQ(Resource::Pending, imageResource->getStatus()); + EXPECT_FALSE(imageResource->isPlaceholder()); + EXPECT_EQ(nullAtom, + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_EQ( + static_cast<int>(WebCachePolicy::UseProtocolCachePolicy), + static_cast<int>(imageResource->resourceRequest().getCachePolicy())); EXPECT_FALSE(client->notifyFinishedCalled()); - image->loader()->cancel(); + imageResource->loader()->cancel(); } TEST(ImageResourceTest, @@ -1088,9 +1117,10 @@ ResourceFetcher::create(ImageResourceTestMockFetchContext::create()); FetchRequest placeholderRequest(testURL, FetchInitiatorInfo()); placeholderRequest.setAllowImagePlaceholder(); - ImageResource* image = ImageResource::fetch(placeholderRequest, fetcher); + ImageResource* imageResource = + ImageResource::fetch(placeholderRequest, fetcher); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(image); + new MockImageResourceClient(imageResource); ResourceResponse response(testURL, "image/jpeg", kJpegImageSubrangeWithDimensionsLength, nullAtom, @@ -1099,29 +1129,35 @@ response.setHTTPHeaderField( "content-range", buildContentRange(kJpegImageSubrangeWithDimensionsLength, sizeof(kJpegImage))); - image->loader()->didReceiveResponse(WrappedResourceResponse(response)); - image->loader()->didReceiveData(reinterpret_cast<const char*>(kJpegImage), - kJpegImageSubrangeWithDimensionsLength); - image->loader()->didFinishLoading(0.0, kJpegImageSubrangeWithDimensionsLength, - kJpegImageSubrangeWithDimensionsLength); + imageResource->loader()->didReceiveResponse( + WrappedResourceResponse(response)); + imageResource->loader()->didReceiveData( + reinterpret_cast<const char*>(kJpegImage), + kJpegImageSubrangeWithDimensionsLength); + imageResource->loader()->didFinishLoading( + 0.0, kJpegImageSubrangeWithDimensionsLength, + kJpegImageSubrangeWithDimensionsLength); - EXPECT_EQ(Resource::Cached, image->getStatus()); - EXPECT_EQ(kJpegImageSubrangeWithDimensionsLength, image->encodedSize()); - EXPECT_TRUE(image->isPlaceholder()); + EXPECT_EQ(Resource::Cached, imageResource->getStatus()); + EXPECT_EQ(kJpegImageSubrangeWithDimensionsLength, + imageResource->encodedSize()); + EXPECT_TRUE(imageResource->isPlaceholder()); EXPECT_LT(0, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); FetchRequest nonPlaceholderRequest(testURL, FetchInitiatorInfo()); - ImageResource* secondImage = + ImageResource* secondImageResource = ImageResource::fetch(nonPlaceholderRequest, fetcher); - EXPECT_EQ(image, secondImage); - EXPECT_EQ(Resource::Pending, image->getStatus()); - EXPECT_FALSE(image->isPlaceholder()); - EXPECT_EQ(nullAtom, image->resourceRequest().httpHeaderField("range")); - EXPECT_EQ(static_cast<int>(WebCachePolicy::UseProtocolCachePolicy), - static_cast<int>(image->resourceRequest().getCachePolicy())); + EXPECT_EQ(imageResource, secondImageResource); + EXPECT_EQ(Resource::Pending, imageResource->getStatus()); + EXPECT_FALSE(imageResource->isPlaceholder()); + EXPECT_EQ(nullAtom, + imageResource->resourceRequest().httpHeaderField("range")); + EXPECT_EQ( + static_cast<int>(WebCachePolicy::UseProtocolCachePolicy), + static_cast<int>(imageResource->resourceRequest().getCachePolicy())); - image->loader()->cancel(); + imageResource->loader()->cancel(); } TEST(ImageResourceTest, PeriodicFlushTest) { @@ -1130,29 +1166,29 @@ URLTestHelpers::registerMockedURLLoad(testURL, "cancelTest.html", "text/html"); ResourceRequest request = ResourceRequest(testURL); - ImageResource* cachedImage = ImageResource::create(request); - cachedImage->setStatus(Resource::Pending); + ImageResource* imageResource = ImageResource::create(request); + imageResource->setStatus(Resource::Pending); Persistent<MockImageResourceClient> client = - new MockImageResourceClient(cachedImage); + new MockImageResourceClient(imageResource); // Send the image response. ResourceResponse resourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage2), nullAtom, String()); resourceResponse.addHTTPHeaderField("chrome-proxy", "q=low"); - cachedImage->responseReceived(resourceResponse, nullptr); + imageResource->responseReceived(resourceResponse, nullptr); // This is number is sufficiently large amount of bytes necessary for the // image to be created (since the size is known). This was determined by // appending one byte at a time (with flushes) until the image was decoded. size_t meaningfulImageSize = 280; - cachedImage->appendData(reinterpret_cast<const char*>(kJpegImage2), - meaningfulImageSize); + imageResource->appendData(reinterpret_cast<const char*>(kJpegImage2), + meaningfulImageSize); size_t bytesSent = meaningfulImageSize; - EXPECT_FALSE(cachedImage->errorOccurred()); - EXPECT_TRUE(cachedImage->getContent()->hasImage()); + EXPECT_FALSE(imageResource->errorOccurred()); + EXPECT_TRUE(imageResource->getContent()->hasImage()); EXPECT_EQ(1, client->imageChangedCount()); platform.runForPeriodSeconds(1.); @@ -1160,8 +1196,8 @@ // Sanity check that we created an image after appending |meaningfulImageSize| // bytes just once. - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); EXPECT_EQ(1, client->imageChangedCount()); for (int flushCount = 1; flushCount <= 3; ++flushCount) { @@ -1172,11 +1208,11 @@ // increases. for (int i = 0; i < 5; ++i) { SCOPED_TRACE(i); - cachedImage->appendData( + imageResource->appendData( reinterpret_cast<const char*>(kJpegImage2) + bytesSent, 1); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); EXPECT_EQ(flushCount, client->imageChangedCount()); ++bytesSent; @@ -1187,25 +1223,25 @@ // Increasing time by a large number only causes one extra flush. platform.runForPeriodSeconds(10.); platform.advanceClockSeconds(10.); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); EXPECT_EQ(4, client->imageChangedCount()); // Append the rest of the data and finish (which causes another flush). - cachedImage->appendData( + imageResource->appendData( reinterpret_cast<const char*>(kJpegImage2) + bytesSent, sizeof(kJpegImage2) - bytesSent); - cachedImage->finish(); + imageResource->finish(); - EXPECT_FALSE(cachedImage->errorOccurred()); - ASSERT_TRUE(cachedImage->getContent()->hasImage()); - EXPECT_FALSE(cachedImage->getContent()->getImage()->isNull()); + EXPECT_FALSE(imageResource->errorOccurred()); + ASSERT_TRUE(imageResource->getContent()->hasImage()); + EXPECT_FALSE(imageResource->getContent()->getImage()->isNull()); EXPECT_EQ(5, client->imageChangedCount()); EXPECT_TRUE(client->notifyFinishedCalled()); - EXPECT_TRUE(cachedImage->getContent()->getImage()->isBitmapImage()); - EXPECT_EQ(50, cachedImage->getContent()->getImage()->width()); - EXPECT_EQ(50, cachedImage->getContent()->getImage()->height()); + EXPECT_TRUE(imageResource->getContent()->getImage()->isBitmapImage()); + EXPECT_EQ(50, imageResource->getContent()->getImage()->width()); + EXPECT_EQ(50, imageResource->getContent()->getImage()->height()); WTF::setTimeFunctionsForTesting(nullptr); }
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h index 3642ae1..fa93940 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
@@ -28,7 +28,6 @@ #include "core/CoreExport.h" #include "core/paint/LayerHitTestRects.h" -#include "platform/PlatformWheelEvent.h" #include "platform/geometry/IntRect.h" #include "platform/heap/Handle.h" #include "platform/scroll/MainThreadScrollingReason.h"
diff --git a/third_party/WebKit/Source/devtools/package.json b/third_party/WebKit/Source/devtools/package.json index 6d3b5125..aba895be 100644 --- a/third_party/WebKit/Source/devtools/package.json +++ b/third_party/WebKit/Source/devtools/package.json
@@ -6,6 +6,7 @@ "chrome": "node scripts/chrome_debug_launcher/launch_chrome.js", "server": "node scripts/hosted_mode/server.js", "test": "node scripts/npm_test.js", + "debug-test": "node scripts/npm_test.js --debug-devtools", "lint": "eslint front_end", "format": "node scripts/format.js", "closure": "python scripts/compile_frontend.py"
diff --git a/third_party/WebKit/Source/devtools/readme.md b/third_party/WebKit/Source/devtools/readme.md index 7895561..3ea053d 100644 --- a/third_party/WebKit/Source/devtools/readme.md +++ b/third_party/WebKit/Source/devtools/readme.md
@@ -58,7 +58,7 @@ * `npm test -- --fetch-content-shell` - even if you're using a full chromium checkout and have a compiled content shell, this will fetch a pre-compiled content shell. This is useful if you haven't compiled your content shell recently. * `npm test -- -f --child-processes=16` - pass in additional flags to the test harness * `npm test -- inspector/sources inspector/console` - run specific tests -* `npm test -- inspector/cookie-resource-match.html --debug-devtools` - debug a specific test (non-bundled & minified). You can use "-d" as a shorthand for "--debug-devtools". +* `npm test -- inspector/cookie-resource-match.html --debug-devtools` OR `npm run debug-test inspector/cookie-resource-match.html` - debug a specific test (non-bundled & minified). You can use "-d" as a shorthand for "--debug-devtools". #### Development * All devtools commits: [View the log], [RSS feed] or [@DevToolsCommits] on Twitter
diff --git a/third_party/WebKit/Source/devtools/scripts/npm_test.js b/third_party/WebKit/Source/devtools/scripts/npm_test.js index 4522399..b493f0c7a 100644 --- a/third_party/WebKit/Source/devtools/scripts/npm_test.js +++ b/third_party/WebKit/Source/devtools/scripts/npm_test.js
@@ -233,6 +233,8 @@ ]); if (useDebugDevtools) { testArgs.push("--additional-driver-flag=--debug-devtools"); + } else { + console.log("TIP: You can debug a test using: npm run debug-test inspector/test-name.html") } if (IS_DEBUG_ENABLED) { testArgs.push("--additional-driver-flag=--remote-debugging-port=9222");
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index d7edb9e..aa663aa 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -319,7 +319,6 @@ "PlatformResourceLoader.h", "PlatformTouchEvent.h", "PlatformTouchPoint.h", - "PlatformWheelEvent.h", "PluginScriptForbiddenScope.cpp", "PluginScriptForbiddenScope.h", "PopupMenu.h", @@ -355,6 +354,8 @@ "WebFrameScheduler.h", "WebGestureEvent.cpp", "WebIconSizesParser.cpp", + "WebMouseEvent.cpp", + "WebMouseWheelEvent.cpp", "WebScheduler.cpp", "WebTaskRunner.cpp", "WebTaskRunner.h",
diff --git a/third_party/WebKit/Source/platform/PlatformEvent.h b/third_party/WebKit/Source/platform/PlatformEvent.h index 7621db6..473a2de 100644 --- a/third_party/WebKit/Source/platform/PlatformEvent.h +++ b/third_party/WebKit/Source/platform/PlatformEvent.h
@@ -43,9 +43,6 @@ MouseReleased, MouseScroll, - // PlatformWheelEvent - Wheel, - // PlatformTouchEvent TouchStart, TouchMove,
diff --git a/third_party/WebKit/Source/platform/PlatformWheelEvent.h b/third_party/WebKit/Source/platform/PlatformWheelEvent.h deleted file mode 100644 index 794fc19..0000000 --- a/third_party/WebKit/Source/platform/PlatformWheelEvent.h +++ /dev/null
@@ -1,117 +0,0 @@ -/* - * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PlatformWheelEvent_h -#define PlatformWheelEvent_h - -#include "platform/PlatformEvent.h" -#include "platform/PlatformMouseEvent.h" -#include "platform/geometry/IntPoint.h" - -namespace blink { - -enum PlatformWheelEventGranularity { - // Indicates that the wheel event should scroll an entire page. In this case - // WebCore's built in paging behavior is used to page up and down (you get the - // same behavior as if the user was clicking in a scrollbar track to page up - // or page down). - ScrollByPageWheelEvent, - // A fine-grained event that specifies the precise number of pixels to scroll. - // It is sent directly by MacBook touchpads on OS X, and synthesized in other - // cases where platforms generate line-by-line scrolling events. - ScrollByPixelWheelEvent, -}; - -#if OS(MACOSX) -enum PlatformWheelEventPhase { - PlatformWheelEventPhaseNone = 0, - PlatformWheelEventPhaseBegan = 1 << 0, - PlatformWheelEventPhaseStationary = 1 << 1, - PlatformWheelEventPhaseChanged = 1 << 2, - PlatformWheelEventPhaseEnded = 1 << 3, - PlatformWheelEventPhaseCancelled = 1 << 4, - PlatformWheelEventPhaseMayBegin = 1 << 5, -}; -#endif - -class PlatformWheelEvent : public PlatformMouseEvent { - public: - PlatformWheelEvent() - : PlatformMouseEvent(PlatformEvent::Wheel), - m_deltaX(0), - m_deltaY(0), - m_wheelTicksX(0), - m_wheelTicksY(0), - m_granularity(ScrollByPixelWheelEvent), - m_hasPreciseScrollingDeltas(false), - m_resendingPluginId(-1), - m_railsMode(RailsModeFree), - m_dispatchType(Blocking) -#if OS(MACOSX) - , - m_phase(PlatformWheelEventPhaseNone), - m_momentumPhase(PlatformWheelEventPhaseNone) -#endif - { - } - - float deltaX() const { return m_deltaX; } - float deltaY() const { return m_deltaY; } - - float wheelTicksX() const { return m_wheelTicksX; } - float wheelTicksY() const { return m_wheelTicksY; } - - PlatformWheelEventGranularity granularity() const { return m_granularity; } - - bool hasPreciseScrollingDeltas() const { return m_hasPreciseScrollingDeltas; } - void setHasPreciseScrollingDeltas(bool b) { m_hasPreciseScrollingDeltas = b; } - int resendingPluginId() const { return m_resendingPluginId; } - RailsMode getRailsMode() const { return m_railsMode; } - DispatchType dispatchType() const { return m_dispatchType; } - bool cancelable() const { return m_dispatchType == PlatformEvent::Blocking; } -#if OS(MACOSX) - PlatformWheelEventPhase phase() const { return m_phase; } - PlatformWheelEventPhase momentumPhase() const { return m_momentumPhase; } -#endif - - protected: - float m_deltaX; - float m_deltaY; - float m_wheelTicksX; - float m_wheelTicksY; - PlatformWheelEventGranularity m_granularity; - bool m_hasPreciseScrollingDeltas; - int m_resendingPluginId; - RailsMode m_railsMode; - DispatchType m_dispatchType; -#if OS(MACOSX) - PlatformWheelEventPhase m_phase; - PlatformWheelEventPhase m_momentumPhase; -#endif -}; - -} // namespace blink - -#endif // PlatformWheelEvent_h
diff --git a/third_party/WebKit/Source/platform/WebMouseEvent.cpp b/third_party/WebKit/Source/platform/WebMouseEvent.cpp new file mode 100644 index 0000000..67cf41d8 --- /dev/null +++ b/third_party/WebKit/Source/platform/WebMouseEvent.cpp
@@ -0,0 +1,26 @@ +// 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 "public/platform/WebInputEvent.h" + +namespace blink { + +WebFloatPoint WebMouseEvent::movementInRootFrame() const { + return WebFloatPoint((movementX / m_frameScale), (movementY / m_frameScale)); +} + +WebFloatPoint WebMouseEvent::positionInRootFrame() const { + return WebFloatPoint((x / m_frameScale) + m_frameTranslate.x, + (y / m_frameScale) + m_frameTranslate.y); +} + +void WebMouseEvent::flattenTransformSelf() { + x = (x / m_frameScale) + m_frameTranslate.x; + y = (y / m_frameScale) + m_frameTranslate.y; + m_frameTranslate.x = 0; + m_frameTranslate.y = 0; + m_frameScale = 1; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/WebMouseWheelEvent.cpp b/third_party/WebKit/Source/platform/WebMouseWheelEvent.cpp new file mode 100644 index 0000000..e3085cb --- /dev/null +++ b/third_party/WebKit/Source/platform/WebMouseWheelEvent.cpp
@@ -0,0 +1,25 @@ +// 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 "public/platform/WebMouseWheelEvent.h" + +namespace blink { + +float WebMouseWheelEvent::deltaXInRootFrame() const { + return deltaX / m_frameScale; +} + +float WebMouseWheelEvent::deltaYInRootFrame() const { + return deltaY / m_frameScale; +} + +WebMouseWheelEvent WebMouseWheelEvent::flattenTransform() const { + WebMouseWheelEvent result = *this; + result.deltaX /= result.m_frameScale; + result.deltaY /= result.m_frameScale; + result.flattenTransformSelf(); + return result; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp index 26a5dba..2a66531 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
@@ -30,6 +30,14 @@ namespace blink { +#define EXPECT_BLINK_FLOAT_RECT_EQ(expected, actual) \ + do { \ + EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \ + EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \ + EXPECT_FLOAT_EQ((expected).width(), (actual).width()); \ + EXPECT_FLOAT_EQ((expected).height(), (actual).height()); \ + } while (false) + using ::blink::testing::createOpacityOnlyEffect; using ::testing::Pointee; @@ -1466,7 +1474,7 @@ EXPECT_TRUE(pendingLayer.backfaceHidden); EXPECT_TRUE(pendingLayer.knownToBeOpaque); - EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 30, 40), pendingLayer.bounds); + EXPECT_BLINK_FLOAT_RECT_EQ(FloatRect(0, 0, 30, 40), pendingLayer.bounds); PaintChunk chunk2; chunk2.properties.propertyTreeState = chunk1.properties.propertyTreeState; @@ -1478,7 +1486,7 @@ EXPECT_TRUE(pendingLayer.backfaceHidden); // Bounds not equal to one PaintChunk. EXPECT_FALSE(pendingLayer.knownToBeOpaque); - EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 40, 60), pendingLayer.bounds); + EXPECT_BLINK_FLOAT_RECT_EQ(FloatRect(0, 0, 40, 60), pendingLayer.bounds); PaintChunk chunk3; chunk3.properties.propertyTreeState = chunk1.properties.propertyTreeState; @@ -1489,7 +1497,7 @@ EXPECT_TRUE(pendingLayer.backfaceHidden); EXPECT_FALSE(pendingLayer.knownToBeOpaque); - EXPECT_FLOAT_RECT_EQ(FloatRect(-5, -25, 45, 85), pendingLayer.bounds); + EXPECT_BLINK_FLOAT_RECT_EQ(FloatRect(-5, -25, 45, 85), pendingLayer.bounds); } TEST_F(PaintArtifactCompositorTestWithPropertyTrees, PendingLayerWithGeometry) { @@ -1507,7 +1515,7 @@ PaintArtifactCompositor::PendingLayer pendingLayer(chunk1); - EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 30, 40), pendingLayer.bounds); + EXPECT_BLINK_FLOAT_RECT_EQ(FloatRect(0, 0, 30, 40), pendingLayer.bounds); PaintChunk chunk2; chunk2.properties.propertyTreeState = chunk1.properties.propertyTreeState; @@ -1516,7 +1524,7 @@ GeometryMapper geometryMapper; pendingLayer.add(chunk2, &geometryMapper); - EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 70, 85), pendingLayer.bounds); + EXPECT_BLINK_FLOAT_RECT_EQ(FloatRect(0, 0, 70, 85), pendingLayer.bounds); } TEST_F(PaintArtifactCompositorTestWithPropertyTrees, PendingLayerKnownOpaque) {
diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm index 434bd1ef..6b2452b 100644 --- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm +++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm
@@ -25,7 +25,6 @@ #include "platform/mac/ScrollAnimatorMac.h" -#include "platform/PlatformWheelEvent.h" #include "platform/Timer.h" #include "platform/animation/TimingFunction.h" #include "platform/geometry/FloatRect.h"
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h index 758431c..fc004bd 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h
@@ -32,7 +32,6 @@ #define ScrollAnimatorBase_h #include "platform/PlatformExport.h" -#include "platform/PlatformWheelEvent.h" #include "platform/heap/Handle.h" #include "platform/scroll/ScrollAnimatorCompositorCoordinator.h" #include "platform/scroll/ScrollTypes.h"
diff --git a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp index 5c4b237..6b6c2e83 100644 --- a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp +++ b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
@@ -574,32 +574,6 @@ STATIC_ASSERT_ENUM(WebMediaPlayer::ReadyStateHaveEnoughData, HTMLMediaElement::kHaveEnoughData); -#if OS(MACOSX) -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseNone, PlatformWheelEventPhaseNone); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseBegan, - PlatformWheelEventPhaseBegan); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseStationary, - PlatformWheelEventPhaseStationary); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseChanged, - PlatformWheelEventPhaseChanged); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseEnded, - PlatformWheelEventPhaseEnded); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseCancelled, - PlatformWheelEventPhaseCancelled); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseMayBegin, - PlatformWheelEventPhaseMayBegin); - -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseNone, WheelEventPhaseNone); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseBegan, WheelEventPhaseBegan); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseStationary, - WheelEventPhaseStationary); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseChanged, WheelEventPhaseChanged); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseEnded, WheelEventPhaseEnded); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseCancelled, - WheelEventPhaseCancelled); -STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseMayBegin, WheelEventPhaseMayBegin); -#endif - STATIC_ASSERT_ENUM(WebScrollbar::Horizontal, HorizontalScrollbar); STATIC_ASSERT_ENUM(WebScrollbar::Vertical, VerticalScrollbar);
diff --git a/third_party/WebKit/Source/web/InspectorOverlay.cpp b/third_party/WebKit/Source/web/InspectorOverlay.cpp index 92ab7a9..a81df3fb 100644 --- a/third_party/WebKit/Source/web/InspectorOverlay.cpp +++ b/third_party/WebKit/Source/web/InspectorOverlay.cpp
@@ -237,14 +237,14 @@ if (WebInputEvent::isGestureEventType(inputEvent.type) && inputEvent.type == WebInputEvent::GestureTap) { // We only have a use for gesture tap. - WebGestureEvent scaledEvent = TransformWebGestureEvent( + WebGestureEvent transformedEvent = TransformWebGestureEvent( m_frameImpl->frameView(), static_cast<const WebGestureEvent&>(inputEvent)); - handled = handleGestureEvent(scaledEvent); + handled = handleGestureEvent(transformedEvent); if (handled) return true; - overlayMainFrame()->eventHandler().handleGestureEvent(scaledEvent); + overlayMainFrame()->eventHandler().handleGestureEvent(transformedEvent); } if (WebInputEvent::isMouseEventType(inputEvent.type) && inputEvent.type != WebInputEvent::MouseEnter) { @@ -295,11 +295,11 @@ } if (inputEvent.type == WebInputEvent::MouseWheel) { - PlatformWheelEvent wheelEvent = PlatformWheelEventBuilder( + WebMouseWheelEvent transformedEvent = TransformWebMouseWheelEvent( m_frameImpl->frameView(), static_cast<const WebMouseWheelEvent&>(inputEvent)); - handled = overlayMainFrame()->eventHandler().handleWheelEvent(wheelEvent) != - WebInputEventResult::NotHandled; + handled = overlayMainFrame()->eventHandler().handleWheelEvent( + transformedEvent) != WebInputEventResult::NotHandled; } return handled;
diff --git a/third_party/WebKit/Source/web/PageWidgetDelegate.cpp b/third_party/WebKit/Source/web/PageWidgetDelegate.cpp index e16d29ea..7afa9fc8 100644 --- a/third_party/WebKit/Source/web/PageWidgetDelegate.cpp +++ b/third_party/WebKit/Source/web/PageWidgetDelegate.cpp
@@ -250,8 +250,9 @@ WebInputEventResult PageWidgetEventHandler::handleMouseWheel( LocalFrame& mainFrame, const WebMouseWheelEvent& event) { - return mainFrame.eventHandler().handleWheelEvent( - PlatformWheelEventBuilder(mainFrame.view(), event)); + WebMouseWheelEvent transformedEvent = + TransformWebMouseWheelEvent(mainFrame.view(), event); + return mainFrame.eventHandler().handleWheelEvent(transformedEvent); } WebInputEventResult PageWidgetEventHandler::handleTouchEvent(
diff --git a/third_party/WebKit/Source/web/WebInputEventConversion.cpp b/third_party/WebKit/Source/web/WebInputEventConversion.cpp index 96c62ee..5269947 100644 --- a/third_party/WebKit/Source/web/WebInputEventConversion.cpp +++ b/third_party/WebKit/Source/web/WebInputEventConversion.cpp
@@ -210,38 +210,15 @@ } } -// PlatformWheelEventBuilder -------------------------------------------------- - -PlatformWheelEventBuilder::PlatformWheelEventBuilder( +WebMouseWheelEvent TransformWebMouseWheelEvent( Widget* widget, - const WebMouseWheelEvent& e) { - m_position = widget->convertFromRootFrame(flooredIntPoint( - convertHitPointToRootFrame(widget, FloatPoint(e.x, e.y)))); - m_globalPosition = IntPoint(e.globalX, e.globalY); - m_deltaX = scaleDeltaToWindow(widget, e.deltaX); - m_deltaY = scaleDeltaToWindow(widget, e.deltaY); - m_wheelTicksX = e.wheelTicksX; - m_wheelTicksY = e.wheelTicksY; - m_granularity = - e.scrollByPage ? ScrollByPageWheelEvent : ScrollByPixelWheelEvent; - - m_type = PlatformEvent::Wheel; - - m_timestamp = TimeTicks::FromSeconds(e.timeStampSeconds); - m_modifiers = e.modifiers; - m_dispatchType = toPlatformDispatchType(e.dispatchType); - - m_hasPreciseScrollingDeltas = e.hasPreciseScrollingDeltas; - m_resendingPluginId = e.resendingPluginId; - m_railsMode = static_cast<PlatformEvent::RailsMode>(e.railsMode); -#if OS(MACOSX) - m_phase = static_cast<PlatformWheelEventPhase>(e.phase); - m_momentumPhase = static_cast<PlatformWheelEventPhase>(e.momentumPhase); -#endif + const WebMouseWheelEvent& event) { + WebMouseWheelEvent result = event; + result.setFrameScale(frameScale(widget)); + result.setFrameTranslate(frameTranslation(widget)); + return result; } -// PlatformGestureEventBuilder ----------------------------------------------- - WebGestureEvent TransformWebGestureEvent(Widget* widget, const WebGestureEvent& event) { WebGestureEvent result = event; @@ -484,31 +461,6 @@ pointerType = WebPointerProperties::PointerType::Touch; } -WebMouseWheelEventBuilder::WebMouseWheelEventBuilder( - const Widget* widget, - const LayoutItem layoutItem, - const WheelEvent& event) { - if (event.type() != EventTypeNames::wheel && - event.type() != EventTypeNames::mousewheel) - return; - type = WebInputEvent::MouseWheel; - updateWebMouseEventFromCoreMouseEvent(event, widget, layoutItem, *this); - deltaX = -event.deltaX(); - deltaY = -event.deltaY(); - wheelTicksX = event.ticksX(); - wheelTicksY = event.ticksY(); - scrollByPage = event.deltaMode() == WheelEvent::kDomDeltaPage; - resendingPluginId = event.resendingPluginId(); - railsMode = static_cast<RailsMode>(event.getRailsMode()); - hasPreciseScrollingDeltas = event.hasPreciseScrollingDeltas(); - dispatchType = event.cancelable() ? WebInputEvent::Blocking - : WebInputEvent::EventNonBlocking; -#if OS(MACOSX) - phase = static_cast<Phase>(event.phase()); - momentumPhase = static_cast<Phase>(event.momentumPhase()); -#endif -} - WebKeyboardEventBuilder::WebKeyboardEventBuilder(const KeyboardEvent& event) { if (const WebKeyboardEvent* webEvent = event.keyEvent()) { *static_cast<WebKeyboardEvent*>(this) = *webEvent;
diff --git a/third_party/WebKit/Source/web/WebInputEventConversion.h b/third_party/WebKit/Source/web/WebInputEventConversion.h index 495f6ed..8aeb4c8 100644 --- a/third_party/WebKit/Source/web/WebInputEventConversion.h +++ b/third_party/WebKit/Source/web/WebInputEventConversion.h
@@ -33,7 +33,6 @@ #include "platform/PlatformMouseEvent.h" #include "platform/PlatformTouchEvent.h" -#include "platform/PlatformWheelEvent.h" #include "platform/scroll/ScrollTypes.h" #include "public/platform/WebInputEvent.h" #include "public/platform/WebMouseWheelEvent.h" @@ -51,7 +50,6 @@ class WebMouseEvent; class WebKeyboardEvent; class WebTouchEvent; -class WheelEvent; class Widget; // These classes are used to convert from WebInputEvent subclasses to @@ -63,12 +61,6 @@ PlatformMouseEventBuilder(Widget*, const WebMouseEvent&); }; -class WEB_EXPORT PlatformWheelEventBuilder - : NON_EXPORTED_BASE(public PlatformWheelEvent) { - public: - PlatformWheelEventBuilder(Widget*, const WebMouseWheelEvent&); -}; - // Converts a WebTouchPoint to a PlatformTouchPoint. class WEB_EXPORT PlatformTouchPointBuilder : NON_EXPORTED_BASE(public PlatformTouchPoint) { @@ -94,14 +86,6 @@ WebMouseEventBuilder(const Widget*, const LayoutItem, const TouchEvent&); }; -// Converts a WheelEvent to a corresponding WebMouseWheelEvent. -// If the event mapping fails, the event type will be set to Undefined. -class WEB_EXPORT WebMouseWheelEventBuilder - : NON_EXPORTED_BASE(public WebMouseWheelEvent) { - public: - WebMouseWheelEventBuilder(const Widget*, const LayoutItem, const WheelEvent&); -}; - // Converts a KeyboardEvent to a corresponding WebKeyboardEvent. // NOTE: For KeyboardEvent, this is only implemented for keydown, // keyup, and keypress. If the event mapping fails, the event type will be set @@ -125,6 +109,8 @@ // and translation. WEB_EXPORT WebGestureEvent TransformWebGestureEvent(Widget*, const WebGestureEvent&); +WEB_EXPORT WebMouseWheelEvent +TransformWebMouseWheelEvent(Widget*, const WebMouseWheelEvent&); Vector<PlatformMouseEvent> WEB_EXPORT createPlatformMouseEventVector(Widget*,
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp index 16da91b..4c6d88d4b 100644 --- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp +++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -758,13 +758,17 @@ } void WebPluginContainerImpl::handleWheelEvent(WheelEvent* event) { - WebMouseWheelEventBuilder webEvent( - this, LayoutItem(m_element->layoutObject()), *event); - if (webEvent.type == WebInputEvent::Undefined) - return; + WebFloatPoint absoluteRootFrameLocation = + event->nativeEvent().positionInRootFrame(); + IntPoint localPoint = + roundedIntPoint(m_element->layoutObject()->absoluteToLocal( + absoluteRootFrameLocation, UseTransforms)); + WebMouseWheelEvent translatedEvent = event->nativeEvent().flattenTransform(); + translatedEvent.x = localPoint.x(); + translatedEvent.y = localPoint.y(); WebCursorInfo cursorInfo; - if (m_webPlugin->handleInputEvent(webEvent, cursorInfo) != + if (m_webPlugin->handleInputEvent(translatedEvent, cursorInfo) != WebInputEventResult::NotHandled) event->setDefaultHandled(); }
diff --git a/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp b/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp index e666873..8cfba8b 100644 --- a/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp
@@ -937,11 +937,14 @@ webMouseWheelEvent.globalX = 10; webMouseWheelEvent.globalY = 10; - PlatformWheelEventBuilder platformWheelBuilder(view, webMouseWheelEvent); - EXPECT_EQ(5 + visualOffset.x(), platformWheelBuilder.position().x()); - EXPECT_EQ(5 + visualOffset.y(), platformWheelBuilder.position().y()); - EXPECT_EQ(10, platformWheelBuilder.globalPosition().x()); - EXPECT_EQ(10, platformWheelBuilder.globalPosition().y()); + WebMouseWheelEvent scaledMouseWheelEvent = + TransformWebMouseWheelEvent(view, webMouseWheelEvent); + IntPoint position = + flooredIntPoint(scaledMouseWheelEvent.positionInRootFrame()); + EXPECT_EQ(5 + visualOffset.x(), position.x()); + EXPECT_EQ(5 + visualOffset.y(), position.y()); + EXPECT_EQ(10, scaledMouseWheelEvent.globalX); + EXPECT_EQ(10, scaledMouseWheelEvent.globalY); } { @@ -1108,178 +1111,4 @@ } } -TEST(WebInputEventConversionTest, WebMouseWheelEventBuilder) { - const std::string baseURL("http://www.test7.com/"); - const std::string fileName("fixed_layout.html"); - - URLTestHelpers::registerMockedURLFromBaseURL( - WebString::fromUTF8(baseURL.c_str()), - WebString::fromUTF8("fixed_layout.html")); - FrameTestHelpers::WebViewHelper webViewHelper; - WebViewImpl* webViewImpl = - webViewHelper.initializeAndLoad(baseURL + fileName, true); - int pageWidth = 640; - int pageHeight = 480; - webViewImpl->resize(WebSize(pageWidth, pageHeight)); - webViewImpl->updateAllLifecyclePhases(); - - Document* document = - toLocalFrame(webViewImpl->page()->mainFrame())->document(); - { - WheelEvent* event = WheelEvent::create( - FloatPoint(1, 3), FloatPoint(5, 10), WheelEvent::kDomDeltaPage, - document->domWindow(), IntPoint(2, 6), IntPoint(10, 30), - PlatformEvent::CtrlKey, 0, TimeTicks(), -1 /* null plugin id */, - true /* hasPreciseScrollingDeltas */, Event::RailsModeHorizontal, - true /*cancelable*/ -#if OS(MACOSX) - , - WheelEventPhaseBegan, WheelEventPhaseChanged -#endif - ); - WebMouseWheelEventBuilder webMouseWheel( - toLocalFrame(webViewImpl->page()->mainFrame())->view(), - document->layoutViewItem(), *event); - EXPECT_EQ(1, webMouseWheel.wheelTicksX); - EXPECT_EQ(3, webMouseWheel.wheelTicksY); - EXPECT_EQ(5, webMouseWheel.deltaX); - EXPECT_EQ(10, webMouseWheel.deltaY); - EXPECT_EQ(2, webMouseWheel.globalX); - EXPECT_EQ(6, webMouseWheel.globalY); - EXPECT_EQ(10, webMouseWheel.windowX); - EXPECT_EQ(30, webMouseWheel.windowY); - EXPECT_TRUE(webMouseWheel.scrollByPage); - EXPECT_EQ(WebInputEvent::ControlKey, webMouseWheel.modifiers); - EXPECT_EQ(WebInputEvent::RailsModeHorizontal, webMouseWheel.railsMode); - EXPECT_TRUE(webMouseWheel.hasPreciseScrollingDeltas); - EXPECT_EQ(WebInputEvent::Blocking, webMouseWheel.dispatchType); -#if OS(MACOSX) - EXPECT_EQ(WebMouseWheelEvent::PhaseBegan, webMouseWheel.phase); - EXPECT_EQ(WebMouseWheelEvent::PhaseChanged, webMouseWheel.momentumPhase); -#endif - } - - { - WheelEvent* event = WheelEvent::create( - FloatPoint(1, 3), FloatPoint(5, 10), WheelEvent::kDomDeltaPage, - document->domWindow(), IntPoint(2, 6), IntPoint(10, 30), - PlatformEvent::CtrlKey, 0, TimeTicks(), -1 /* null plugin id */, - true /* hasPreciseScrollingDeltas */, Event::RailsModeHorizontal, false -#if OS(MACOSX) - , - WheelEventPhaseNone, WheelEventPhaseNone -#endif - ); - WebMouseWheelEventBuilder webMouseWheel( - toLocalFrame(webViewImpl->page()->mainFrame())->view(), - document->layoutViewItem(), *event); - EXPECT_EQ(WebInputEvent::EventNonBlocking, webMouseWheel.dispatchType); - } -} - -TEST(WebInputEventConversionTest, PlatformWheelEventBuilder) { - const std::string baseURL("http://www.test8.com/"); - const std::string fileName("fixed_layout.html"); - - URLTestHelpers::registerMockedURLFromBaseURL( - WebString::fromUTF8(baseURL.c_str()), - WebString::fromUTF8("fixed_layout.html")); - FrameTestHelpers::WebViewHelper webViewHelper; - WebViewImpl* webViewImpl = - webViewHelper.initializeAndLoad(baseURL + fileName, true); - int pageWidth = 640; - int pageHeight = 480; - webViewImpl->resize(WebSize(pageWidth, pageHeight)); - webViewImpl->updateAllLifecyclePhases(); - - FrameView* view = toLocalFrame(webViewImpl->page()->mainFrame())->view(); - - { - WebMouseWheelEvent webMouseWheelEvent(WebInputEvent::MouseWheel, - WebInputEvent::ControlKey, - WebInputEvent::TimeStampForTesting); - webMouseWheelEvent.x = 0; - webMouseWheelEvent.y = 5; - webMouseWheelEvent.deltaX = 10; - webMouseWheelEvent.deltaY = 15; - webMouseWheelEvent.hasPreciseScrollingDeltas = true; - webMouseWheelEvent.railsMode = WebInputEvent::RailsModeHorizontal; - webMouseWheelEvent.phase = WebMouseWheelEvent::PhaseBegan; - webMouseWheelEvent.momentumPhase = WebMouseWheelEvent::PhaseChanged; - - PlatformWheelEventBuilder platformWheelBuilder(view, webMouseWheelEvent); - EXPECT_EQ(0, platformWheelBuilder.position().x()); - EXPECT_EQ(5, platformWheelBuilder.position().y()); - EXPECT_EQ(10, platformWheelBuilder.deltaX()); - EXPECT_EQ(15, platformWheelBuilder.deltaY()); - EXPECT_EQ(PlatformEvent::CtrlKey, platformWheelBuilder.getModifiers()); - EXPECT_TRUE(platformWheelBuilder.hasPreciseScrollingDeltas()); - EXPECT_EQ(platformWheelBuilder.getRailsMode(), - PlatformEvent::RailsModeHorizontal); -#if OS(MACOSX) - EXPECT_EQ(PlatformWheelEventPhaseBegan, platformWheelBuilder.phase()); - EXPECT_EQ(PlatformWheelEventPhaseChanged, - platformWheelBuilder.momentumPhase()); -#endif - } - - { - WebMouseWheelEvent webMouseWheelEvent(WebInputEvent::MouseWheel, - WebInputEvent::ShiftKey, - WebInputEvent::TimeStampForTesting); - webMouseWheelEvent.x = 5; - webMouseWheelEvent.y = 0; - webMouseWheelEvent.deltaX = 15; - webMouseWheelEvent.deltaY = 10; - webMouseWheelEvent.hasPreciseScrollingDeltas = false; - webMouseWheelEvent.railsMode = WebInputEvent::RailsModeFree; - webMouseWheelEvent.phase = WebMouseWheelEvent::PhaseNone; - webMouseWheelEvent.momentumPhase = WebMouseWheelEvent::PhaseNone; - - PlatformWheelEventBuilder platformWheelBuilder(view, webMouseWheelEvent); - EXPECT_EQ(5, platformWheelBuilder.position().x()); - EXPECT_EQ(0, platformWheelBuilder.position().y()); - EXPECT_EQ(15, platformWheelBuilder.deltaX()); - EXPECT_EQ(10, platformWheelBuilder.deltaY()); - EXPECT_EQ(PlatformEvent::ShiftKey, platformWheelBuilder.getModifiers()); - EXPECT_FALSE(platformWheelBuilder.hasPreciseScrollingDeltas()); - EXPECT_EQ(platformWheelBuilder.getRailsMode(), - PlatformEvent::RailsModeFree); -#if OS(MACOSX) - EXPECT_EQ(PlatformWheelEventPhaseNone, platformWheelBuilder.phase()); - EXPECT_EQ(PlatformWheelEventPhaseNone, - platformWheelBuilder.momentumPhase()); -#endif - } - - { - WebMouseWheelEvent webMouseWheelEvent(WebInputEvent::MouseWheel, - WebInputEvent::AltKey, - WebInputEvent::TimeStampForTesting); - webMouseWheelEvent.x = 5; - webMouseWheelEvent.y = 0; - webMouseWheelEvent.deltaX = 15; - webMouseWheelEvent.deltaY = 10; - webMouseWheelEvent.hasPreciseScrollingDeltas = true; - webMouseWheelEvent.railsMode = WebInputEvent::RailsModeVertical; - webMouseWheelEvent.phase = WebMouseWheelEvent::PhaseNone; - webMouseWheelEvent.momentumPhase = WebMouseWheelEvent::PhaseNone; - - PlatformWheelEventBuilder platformWheelBuilder(view, webMouseWheelEvent); - EXPECT_EQ(5, platformWheelBuilder.position().x()); - EXPECT_EQ(0, platformWheelBuilder.position().y()); - EXPECT_EQ(15, platformWheelBuilder.deltaX()); - EXPECT_EQ(10, platformWheelBuilder.deltaY()); - EXPECT_EQ(PlatformEvent::AltKey, platformWheelBuilder.getModifiers()); - EXPECT_TRUE(platformWheelBuilder.hasPreciseScrollingDeltas()); - EXPECT_EQ(platformWheelBuilder.getRailsMode(), - PlatformEvent::RailsModeVertical); -#if OS(MACOSX) - EXPECT_EQ(PlatformWheelEventPhaseNone, platformWheelBuilder.phase()); - EXPECT_EQ(PlatformWheelEventPhaseNone, - platformWheelBuilder.momentumPhase()); -#endif - } -} - } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp index 566324a2..0d41df2 100644 --- a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
@@ -48,6 +48,7 @@ #include "public/platform/WebClipboard.h" #include "public/platform/WebCompositorSupport.h" #include "public/platform/WebLayer.h" +#include "public/platform/WebMouseWheelEvent.h" #include "public/platform/WebThread.h" #include "public/platform/WebURLLoaderMockFactory.h" #include "public/web/WebCache.h" @@ -456,12 +457,22 @@ WebInputEventResult handleInputEvent(const WebInputEvent& event, WebCursorInfo&) override { m_lastEventType = event.type; + if (WebInputEvent::isMouseEventType(event.type) || + event.type == WebInputEvent::MouseWheel) { + const WebMouseEvent& mouseEvent = + static_cast<const WebMouseEvent&>(event); + m_lastMouseEventLocation = IntPoint(mouseEvent.x, mouseEvent.y); + } + return WebInputEventResult::HandledSystem; } WebInputEvent::Type getLastInputEventType() { return m_lastEventType; } + IntPoint getLastMouseEventLocation() { return m_lastMouseEventLocation; } + private: WebInputEvent::Type m_lastEventType; + IntPoint m_lastMouseEventLocation; }; TEST_F(WebPluginContainerTest, GestureLongPressReachesPlugin) { @@ -515,6 +526,45 @@ testPlugin->getLastInputEventType()); } +TEST_F(WebPluginContainerTest, MouseWheelEventTranslated) { + URLTestHelpers::registerMockedURLFromBaseURL( + WebString::fromUTF8(m_baseURL.c_str()), + WebString::fromUTF8("plugin_container.html")); + CustomPluginWebFrameClient<EventTestPlugin> + pluginWebFrameClient; // Must outlive webViewHelper. + FrameTestHelpers::WebViewHelper webViewHelper; + WebView* webView = webViewHelper.initializeAndLoad( + m_baseURL + "plugin_container.html", true, &pluginWebFrameClient); + DCHECK(webView); + webView->settings()->setPluginsEnabled(true); + webView->resize(WebSize(300, 300)); + webView->updateAllLifecyclePhases(); + runPendingTasks(); + + WebElement pluginContainerOneElement = + webView->mainFrame()->document().getElementById( + WebString::fromUTF8("translated-plugin")); + WebPlugin* plugin = static_cast<WebPluginContainerImpl*>( + pluginContainerOneElement.pluginContainer()) + ->plugin(); + EventTestPlugin* testPlugin = static_cast<EventTestPlugin*>(plugin); + + WebMouseWheelEvent event(WebInputEvent::MouseWheel, + WebInputEvent::NoModifiers, + WebInputEvent::TimeStampForTesting); + + WebRect rect = pluginContainerOneElement.boundsInViewport(); + event.x = rect.x + rect.width / 2; + event.y = rect.y + rect.height / 2; + + webView->handleInputEvent(event); + runPendingTasks(); + + EXPECT_EQ(WebInputEvent::MouseWheel, testPlugin->getLastInputEventType()); + EXPECT_EQ(rect.width / 2, testPlugin->getLastMouseEventLocation().x()); + EXPECT_EQ(rect.height / 2, testPlugin->getLastMouseEventLocation().y()); +} + // Verify that isRectTopmost returns false when the document is detached. TEST_F(WebPluginContainerTest, IsRectTopmostTest) { URLTestHelpers::registerMockedURLFromBaseURL(
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/layout_test_results_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/layout_test_results_unittest.py index d8f9daa..a4f5bb2 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/layout_test_results_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/layout_test_results_unittest.py
@@ -90,7 +90,6 @@ "layout_tests_dir": "/b/build/slave/Webkit_Mac10_5/build/src/third_party/WebKit/LayoutTests", "version": 3, "num_passes": 77, - "has_pretty_patch": false, "fixable": 1220, "num_flaky": 0, "chromium_revision": "1234",
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py index e58a5de..617be65 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py
@@ -329,7 +329,6 @@ results['interrupted'] = initial_results.interrupted results['layout_tests_dir'] = port_obj.layout_tests_dir() results['has_wdiff'] = port_obj.wdiff_available() - results['has_pretty_patch'] = True results['pixel_tests_enabled'] = port_obj.get_option('pixel_tests') results['seconds_since_epoch'] = int(time.time()) results['build_number'] = port_obj.get_option('build_number') @@ -337,9 +336,6 @@ if port_obj.get_option('order') == 'random': results['random_order_seed'] = port_obj.get_option('seed') results['path_delimiter'] = '/' - # The pretty-diff.html files should always be available. - # TODO(qyearsley): Change this key since PrettyPatch.rb has been removed. - results['has_pretty_patch'] = True # Don't do this by default since it takes >100ms. # It's only used for rebaselining and uploading data to the flakiness dashboard.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py index 838ff12..885b525 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -800,7 +800,9 @@ path_in_wpt = match.group(1) manifest_items = self._manifest_items_for_path(path_in_wpt) assert manifest_items is not None - if len(manifest_items) != 1 or manifest_items[0]['url'][1:] != path_in_wpt: + # For most testharness tests, manifest_items looks like: + # [["/some/test/path.html", {}]] + if len(manifest_items) != 1 or manifest_items[0][0][1:] != path_in_wpt: # TODO(tkent): foo.any.js and bar.worker.js should be accessed # as foo.any.html, foo.any.worker, and bar.worker with WPTServe. continue @@ -813,16 +815,14 @@ return json.loads(self._filesystem.read_text_file(path)) def _manifest_items_for_path(self, path_in_wpt): - """Returns a list of a dict representing ManifestItem for the specified - path, or None if MANIFEST.json has no items for the specified path. + """Returns a manifest item for the given WPT path, or None if not found. - A ManifestItem has 'path', 'url', and optional 'timeout' fields. Also, - it has "references" list for reference tests. It's defined in - web-platform-tests/tools/manifest/item.py. + The format of a manifest item depends on + https://github.com/w3c/wpt-tools/blob/master/manifest/item.py + and is assumed to be a list of the format [url, extras], + or [url, references, extras] for reftests, or None if not found. """ - # Because we generate MANIFEST.json before finishing import, all - # entries are in 'local_changes'. - items = self._wpt_manifest()['local_changes']['items'] + items = self._wpt_manifest()['items'] if path_in_wpt in items['manual']: return items['manual'][path_in_wpt] elif path_in_wpt in items['reftest']:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py index 0ca0e36..76006bba 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -305,26 +305,19 @@ @staticmethod def _add_manifest_to_mock_file_system(filesystem): filesystem.write_text_file(LAYOUT_TEST_DIR + '/imported/wpt/MANIFEST.json', json.dumps({ - "local_changes": { - "items": { - 'testharness': { - 'dom/ranges/Range-attributes.html': [{ - 'path': 'dom/ranges/Range-attributes.html', - 'url': '/dom/ranges/Range-attributes.html' - }], - 'console/console-is-a-namespace.any.js': [ - { - 'path': 'console/console-is-a-namespace.any.js', - 'url': '/console/console-is-a-namespace.any.html' - }, - { - 'path': 'console/console-is-a-namespace.any.js', - 'url': '/console/console-is-a-namespace.any.worker' - } - ]}, - 'manual': {}, - 'reftest': {} - }}})) + 'items': { + 'testharness': { + 'dom/ranges/Range-attributes.html': [ + ['/dom/ranges/Range-attributes.html', {}] + ], + 'console/console-is-a-namespace.any.js': [ + ['/console/console-is-a-namespace.any.html', {}], + ['/console/console-is-a-namespace.any.worker.html', {}], + ], + }, + 'manual': {}, + 'reftest': {}, + }})) filesystem.write_text_file(LAYOUT_TEST_DIR + '/imported/wpt/dom/ranges/Range-attributes.html', '') filesystem.write_text_file(LAYOUT_TEST_DIR + '/imported/wpt/console/console-is-a-namespace.any.js', '') filesystem.write_text_file(LAYOUT_TEST_DIR + '/imported/wpt/common/blank.html', 'foo')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py index 2c60207f..63b43ca5 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -979,7 +979,6 @@ full_results_text = host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json') full_results = json.loads(full_results_text.replace("ADD_RESULTS(", "").replace(");", "")) self.assertEqual(full_results['has_wdiff'], False) - self.assertEqual(full_results['has_pretty_patch'], True) def test_unsupported_platform(self): stdout = StringIO.StringIO()
diff --git a/third_party/WebKit/public/platform/WebInputEvent.h b/third_party/WebKit/public/platform/WebInputEvent.h index c3341c6..82b34ff 100644 --- a/third_party/WebKit/public/platform/WebInputEvent.h +++ b/third_party/WebKit/public/platform/WebInputEvent.h
@@ -429,6 +429,11 @@ WebMouseEvent() : WebInputEvent(sizeof(WebMouseEvent)), WebPointerProperties() {} +#if INSIDE_BLINK + BLINK_PLATFORM_EXPORT WebFloatPoint movementInRootFrame() const; + BLINK_PLATFORM_EXPORT WebFloatPoint positionInRootFrame() const; +#endif + protected: explicit WebMouseEvent(unsigned sizeParam) : WebInputEvent(sizeParam), WebPointerProperties() {} @@ -439,6 +444,7 @@ double timeStampSeconds) : WebInputEvent(sizeParam, type, modifiers, timeStampSeconds), WebPointerProperties() {} + void flattenTransformSelf(); }; // WebTouchEvent --------------------------------------------------------------
diff --git a/third_party/WebKit/public/platform/WebMouseWheelEvent.h b/third_party/WebKit/public/platform/WebMouseWheelEvent.h index a252e638..b699d3fd 100644 --- a/third_party/WebKit/public/platform/WebMouseWheelEvent.h +++ b/third_party/WebKit/public/platform/WebMouseWheelEvent.h
@@ -85,6 +85,17 @@ momentumPhase(PhaseNone), railsMode(RailsModeFree), dispatchType(Blocking) {} + +#if INSIDE_BLINK + BLINK_PLATFORM_EXPORT float deltaXInRootFrame() const; + BLINK_PLATFORM_EXPORT float deltaYInRootFrame() const; + + // Sets any scaled values to be their computed values and sets |frameScale| + // back to 1 and |translateX|, |translateY| back to 0. + BLINK_PLATFORM_EXPORT WebMouseWheelEvent flattenTransform() const; + + bool isCancelable() const { return dispatchType == Blocking; } +#endif }; #pragma pack(pop)
diff --git a/third_party/retrolambda/README.chromium b/third_party/retrolambda/README.chromium index 5fc43cf..9262188 100644 --- a/third_party/retrolambda/README.chromium +++ b/third_party/retrolambda/README.chromium
@@ -16,5 +16,5 @@ Source of the .jar: Downloaded from Maven Central. Link: -http://search.maven.org/remotecontent?filepath=net/orfjackal/retrolambda/retrolambda/2.3.0/retrolambda-2.3.0.jar +http://central.maven.org/maven2/net/orfjackal/retrolambda/retrolambda/2.3.0/retrolambda-2.3.0.jar
diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp index 0365ec1e..e2b797f 100644 --- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp +++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -121,6 +121,13 @@ return true; } +void PrintForDiagnostics(clang::raw_ostream& os, + const clang::FunctionDecl& decl) { + decl.getLocStart().print(os, decl.getASTContext().getSourceManager()); + os << ": "; + decl.getNameForDiagnostic(os, decl.getASTContext().getPrintingPolicy(), true); +} + template <typename T> bool MatchAllOverriddenMethods( const clang::CXXMethodDecl& decl, @@ -145,13 +152,54 @@ // one we did not rename which creates a behaviour change. So assert and // demand the user to fix the code first (or add the method to our // blacklist T_T). - if (override_matches || override_not_matches) - assert(override_matches != override_not_matches); + if (override_matches && override_not_matches) { + // blink::InternalSettings::trace method overrides + // 1) blink::InternalSettingsGenerated::trace + // (won't be renamed because it is in generated code) + // 2) blink::Supplement<blink::Page>::trace + // (will be renamed). + // It is safe to rename blink::InternalSettings::trace, because + // both 1 and 2 will both be renamed (#1 via manual changes of the code + // generator for DOM bindings and #2 via the clang tool). + auto internal_settings_class_decl = cxxRecordDecl( + hasName("InternalSettings"), + hasParent(namespaceDecl(hasName("blink"), + hasParent(translationUnitDecl())))); + auto is_method_safe_to_rename = cxxMethodDecl( + hasName("trace"), + anyOf(hasParent(internal_settings_class_decl), // in .h file + has(nestedNameSpecifier(specifiesType( // in .cpp file + hasDeclaration(internal_settings_class_decl)))))); + if (IsMatching(is_method_safe_to_rename, decl, decl.getASTContext())) + return true; + + // For previously unknown conflicts, error out and require a human to + // analyse the problem (rather than falling back to a potentially unsafe / + // code semantics changing rename). + llvm::errs() << "ERROR: "; + PrintForDiagnostics(llvm::errs(), decl); + llvm::errs() << " method overrides " + << "some virtual methods that will be automatically renamed " + << "and some that won't be renamed."; + llvm::errs() << "\n"; + for (auto it = decl.begin_overridden_methods(); + it != decl.end_overridden_methods(); ++it) { + if (MatchAllOverriddenMethods(**it, inner_matcher, finder, builder)) + llvm::errs() << "Overriden method that will be renamed: "; + else + llvm::errs() << "Overriden method that will not be renamed: "; + PrintForDiagnostics(llvm::errs(), **it); + llvm::errs() << "\n"; + } + llvm::errs() << "\n"; + assert(false); + } // If the method overrides something that doesn't match, so the method itself // doesn't match. if (override_not_matches) return false; + // If the method overrides something that matches, so the method ifself // matches. if (override_matches)
diff --git a/tools/licenses.py b/tools/licenses.py index 3d37d3f..9bdc018 100755 --- a/tools/licenses.py +++ b/tools/licenses.py
@@ -78,8 +78,6 @@ # Redistribution does not require attribution in documentation. os.path.join('third_party','directxsdk'), - os.path.join('third_party','platformsdk_win2008_6_1'), - os.path.join('third_party','platformsdk_win7'), # For testing only, presents on some bots. os.path.join('isolate_deps_dir'),
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index f6a72bb..1cf29a3 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -1786,7 +1786,7 @@ 'ozone_linux': { 'gn_args': ('ozone_auto_platforms=false ozone_platform_wayland=true ' 'ozone_platform_x11=true ozone_platform_gbm=true ' - 'enable_package_mash_services=true use_ash=false'), + 'use_ozone=true use_ash=false'), }, 'pdf_xfa': {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 3761fc61..d8ad21e 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -107372,13 +107372,13 @@ <enum name="WebsiteSettingsAction" type="int"> <int value="0" label="Opened"/> - <int value="1" label="Selected Permissions tab"/> - <int value="2" label="Selected Connection tab"/> - <int value="3" label="Connection tab shown immediately"/> + <int value="1" label="(Deprecated) Selected Permissions tab"/> + <int value="2" label="(Deprecated) Selected Connection tab"/> + <int value="3" label="(Deprecated) Connection tab shown immediately"/> <int value="4" label="Cookies dialog opened"/> <int value="5" label="Changed permission"/> <int value="6" label="Certificate dialog opened"/> - <int value="7" label="Transparency viewer opened"/> + <int value="7" label="(Deprecated) Transparency viewer opened"/> <int value="8" label="Connection help opened"/> <int value="9" label="Site settings opened"/> <int value="10" label="Security details opened"/>
diff --git a/ui/app_list/views/search_result_container_view.cc b/ui/app_list/views/search_result_container_view.cc index db0da6a..d51974f 100644 --- a/ui/app_list/views/search_result_container_view.cc +++ b/ui/app_list/views/search_result_container_view.cc
@@ -33,7 +33,7 @@ if (results_) results_->AddObserver(this); - DoUpdate(); + Update(); } void SearchResultContainerView::SetSelectedIndex(int selected_index) { @@ -53,14 +53,12 @@ return index >= 0 && index <= num_results() - 1; } -void SearchResultContainerView::ScheduleUpdate() { - // When search results are added one by one, each addition generates an update - // request. Consolidates those update requests into one Update call. - if (!update_factory_.HasWeakPtrs()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&SearchResultContainerView::DoUpdate, - update_factory_.GetWeakPtr())); - } +void SearchResultContainerView::Update() { + update_factory_.InvalidateWeakPtrs(); + num_results_ = DoUpdate(); + Layout(); + if (delegate_) + delegate_->OnSearchResultContainerResultsChanged(); } bool SearchResultContainerView::UpdateScheduled() { @@ -84,12 +82,14 @@ ScheduleUpdate(); } -void SearchResultContainerView::DoUpdate() { - update_factory_.InvalidateWeakPtrs(); - num_results_ = Update(); - Layout(); - if (delegate_) - delegate_->OnSearchResultContainerResultsChanged(); +void SearchResultContainerView::ScheduleUpdate() { + // When search results are added one by one, each addition generates an update + // request. Consolidates those update requests into one Update call. + if (!update_factory_.HasWeakPtrs()) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&SearchResultContainerView::Update, + update_factory_.GetWeakPtr())); + } } } // namespace app_list
diff --git a/ui/app_list/views/search_result_container_view.h b/ui/app_list/views/search_result_container_view.h index 8c941a8a..e4f5fd82 100644 --- a/ui/app_list/views/search_result_container_view.h +++ b/ui/app_list/views/search_result_container_view.h
@@ -61,9 +61,8 @@ // container. virtual int GetYSize() = 0; - // Schedules an Update call using |update_factory_|. Do nothing if there is a - // pending call. - void ScheduleUpdate(); + // Batching method that actually performs the update and updates layout. + void Update(); // Returns whether an update is currently scheduled for this container. bool UpdateScheduled(); @@ -83,15 +82,16 @@ bool directional_movement) = 0; private: + // Schedules an Update call using |update_factory_|. Do nothing if there is a + // pending call. + void ScheduleUpdate(); + // Updates UI with model. Returns the number of visible results. - virtual int Update() = 0; + virtual int DoUpdate() = 0; // Updates UI for a change in the selected index. virtual void UpdateSelectedIndex(int old_selected, int new_selected) = 0; - // Batching method that actually performs the update and updates layout. - void DoUpdate(); - Delegate* delegate_; int selected_index_;
diff --git a/ui/app_list/views/search_result_list_view.cc b/ui/app_list/views/search_result_list_view.cc index 91cb319..dda5431 100644 --- a/ui/app_list/views/search_result_list_view.cc +++ b/ui/app_list/views/search_result_list_view.cc
@@ -153,7 +153,7 @@ return num_results(); } -int SearchResultListView::Update() { +int SearchResultListView::DoUpdate() { std::vector<SearchResult*> display_results = AppListModel::FilterSearchResultsByDisplayType( results(),
diff --git a/ui/app_list/views/search_result_list_view.h b/ui/app_list/views/search_result_list_view.h index c8649b5..661989e 100644 --- a/ui/app_list/views/search_result_list_view.h +++ b/ui/app_list/views/search_result_list_view.h
@@ -64,7 +64,7 @@ friend class test::SearchResultListViewTest; // Overridden from SearchResultContainerView: - int Update() override; + int DoUpdate() override; void UpdateSelectedIndex(int old_selected, int new_selected) override; // Updates the auto launch states.
diff --git a/ui/app_list/views/search_result_tile_item_list_view.cc b/ui/app_list/views/search_result_tile_item_list_view.cc index b62f2e50..6ff0a83 100644 --- a/ui/app_list/views/search_result_tile_item_list_view.cc +++ b/ui/app_list/views/search_result_tile_item_list_view.cc
@@ -72,7 +72,7 @@ return num_results() ? 1 : 0; } -int SearchResultTileItemListView::Update() { +int SearchResultTileItemListView::DoUpdate() { std::vector<SearchResult*> display_results = AppListModel::FilterSearchResultsByDisplayType( results(), SearchResult::DISPLAY_TILE, kNumSearchResultTiles);
diff --git a/ui/app_list/views/search_result_tile_item_list_view.h b/ui/app_list/views/search_result_tile_item_list_view.h index 13e1c7d..d7285a5 100644 --- a/ui/app_list/views/search_result_tile_item_list_view.h +++ b/ui/app_list/views/search_result_tile_item_list_view.h
@@ -38,7 +38,7 @@ private: // Overridden from SearchResultContainerView: - int Update() override; + int DoUpdate() override; void UpdateSelectedIndex(int old_selected, int new_selected) override; std::vector<SearchResultTileItemView*> tile_views_;
diff --git a/ui/app_list/views/start_page_view.cc b/ui/app_list/views/start_page_view.cc index 0bac15b..fb19777 100644 --- a/ui/app_list/views/start_page_view.cc +++ b/ui/app_list/views/start_page_view.cc
@@ -126,7 +126,7 @@ AllAppsTileItemView* all_apps_button() { return all_apps_button_; } // Overridden from SearchResultContainerView: - int Update() override; + int DoUpdate() override; void UpdateSelectedIndex(int old_selected, int new_selected) override; void OnContainerSelected(bool from_bottom, bool directional_movement) override; @@ -171,7 +171,7 @@ return search_result_tile_views_[index]; } -int StartPageView::StartPageTilesContainer::Update() { +int StartPageView::StartPageTilesContainer::DoUpdate() { // Ignore updates and disable buttons when transitioning to a different // state. if (contents_view_->GetActiveState() != AppListModel::STATE_START) { @@ -211,10 +211,10 @@ void StartPageView::StartPageTilesContainer::UpdateSelectedIndex( int old_selected, int new_selected) { - if (old_selected >= 0) + if (old_selected >= 0 && old_selected < num_results()) GetTileItemView(old_selected)->SetSelected(false); - if (new_selected >= 0) + if (new_selected >= 0 && new_selected < num_results()) GetTileItemView(new_selected)->SetSelected(true); } @@ -360,8 +360,8 @@ custom_page_view->SetVisible( app_list_main_view_->ShouldShowCustomLauncherPage()); } - tiles_container_->Update(); tiles_container_->ClearSelectedIndex(); + tiles_container_->Update(); custom_launcher_page_background_->SetSelected(false); }
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn index a9d9699..1492857 100644 --- a/ui/aura/BUILD.gn +++ b/ui/aura/BUILD.gn
@@ -71,6 +71,8 @@ "mus/capture_synchronizer.cc", "mus/capture_synchronizer.h", "mus/capture_synchronizer_delegate.h", + "mus/client_surface_embedder.cc", + "mus/client_surface_embedder.h", "mus/drag_drop_controller_host.h", "mus/drag_drop_controller_mus.cc", "mus/drag_drop_controller_mus.h", @@ -114,7 +116,6 @@ "scoped_window_targeter.h", "window.cc", "window.h", - "window_delegate.cc", "window_delegate.h", "window_event_dispatcher.cc", "window_event_dispatcher.h",
diff --git a/ui/aura/mus/DEPS b/ui/aura/mus/DEPS index 8fe8d6d1..39280c0f 100644 --- a/ui/aura/mus/DEPS +++ b/ui/aura/mus/DEPS
@@ -6,6 +6,7 @@ "+cc/surfaces/surface_id_allocator.h", "+cc/surfaces/surface_info.h", "+cc/surfaces/surface_manager.h", + "+cc/surfaces/surface_reference_factory.h", "+gpu/command_buffer/client/gpu_memory_buffer_manager.h", "+gpu/ipc/client/gpu_channel_host.h", "+mojo/public/cpp/system/buffer.h",
diff --git a/ui/aura/mus/client_surface_embedder.cc b/ui/aura/mus/client_surface_embedder.cc new file mode 100644 index 0000000..ba34a52 --- /dev/null +++ b/ui/aura/mus/client_surface_embedder.cc
@@ -0,0 +1,90 @@ +// 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 "ui/aura/mus/client_surface_embedder.h" + +#include "cc/surfaces/surface_reference_factory.h" +#include "ui/aura/mus/surface_id_handler.h" +#include "ui/aura/window.h" + +namespace aura { +namespace { + +// TODO(mfomitchev, samans): Remove these stub classes once the SurfaceReference +// work is complete. +class StubSurfaceReference : public cc::SurfaceReferenceBase { + public: + StubSurfaceReference(scoped_refptr<const cc::SurfaceReferenceFactory> factory) + : cc::SurfaceReferenceBase(factory) {} + + ~StubSurfaceReference() override { Destroy(); } + + private: + DISALLOW_COPY_AND_ASSIGN(StubSurfaceReference); +}; + +class StubSurfaceReferenceFactory : public cc::SurfaceReferenceFactory { + public: + StubSurfaceReferenceFactory() = default; + + // cc::SurfaceReferenceFactory: + std::unique_ptr<cc::SurfaceReferenceBase> CreateReference( + cc::SurfaceReferenceOwner* owner, + const cc::SurfaceId& surface_id) const override { + return base::MakeUnique<StubSurfaceReference>(make_scoped_refptr(this)); + } + + protected: + ~StubSurfaceReferenceFactory() override = default; + + private: + // cc::SurfaceReferenceFactory: + void DestroyReference(cc::SurfaceReferenceBase* surface_ref) const override {} + + DISALLOW_COPY_AND_ASSIGN(StubSurfaceReferenceFactory); +}; +} // namespace + +ClientSurfaceEmbedder::ClientSurfaceEmbedder(Window* window) : window_(window) { + surface_layer_ = base::MakeUnique<ui::Layer>(ui::LAYER_TEXTURED); + surface_layer_->SetVisible(true); + // The frame provided by the parent window->layer() needs to show through + // the surface layer. + surface_layer_->SetFillsBoundsOpaquely(false); + + clip_layer_ = base::MakeUnique<ui::Layer>(ui::LAYER_NOT_DRAWN); + clip_layer_->SetFillsBoundsOpaquely(false); + + clip_layer_->Add(surface_layer_.get()); + window_->layer()->Add(clip_layer_.get()); + + // Window's layer may contain content from this client (the embedder), e.g. + // this is the case with window decorations provided by Window Manager. + // This content should appear underneath the content of the embedded client. + window_->layer()->StackAtTop(clip_layer_.get()); + + // We can't set this on window's layer, because that would clip the window + // shadow. + clip_layer_->SetMasksToBounds(true); +} + +ClientSurfaceEmbedder::~ClientSurfaceEmbedder() = default; + +void ClientSurfaceEmbedder::UpdateSurface(const cc::SurfaceInfo& surface_info) { + // TODO(mfomitchev): Currently the frame size may not match the window size. + // In the future the surface id will be created by Ash (and used with the + // surface layer) when the window resize happens, which will ensure that the + // surface size matches the window size (unless a timeout occurs). + gfx::Size frame_size = surface_info.size_in_pixels(); + surface_layer_->SetBounds( + gfx::Rect(0, 0, frame_size.width(), frame_size.height())); + // Clip to window bounds. + clip_layer_->SetBounds( + gfx::Rect(0, 0, window_->bounds().width(), window_->bounds().height())); + + surface_layer_->SetShowSurface( + surface_info, make_scoped_refptr(new StubSurfaceReferenceFactory)); +} + +} // namespace aura
diff --git a/ui/aura/mus/client_surface_embedder.h b/ui/aura/mus/client_surface_embedder.h new file mode 100644 index 0000000..75b45c2 --- /dev/null +++ b/ui/aura/mus/client_surface_embedder.h
@@ -0,0 +1,45 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> + +#include "base/macros.h" + +namespace cc { +class SurfaceInfo; +} + +namespace ui { +class Layer; +} + +namespace aura { + +class Window; + +// Used by WindowPortMus when it is embedding a client. Responsible for setting +// up layers containing content from the client, parenting them to the window's +// layer, and updating them when the client submits new surfaces. +class ClientSurfaceEmbedder { + public: + explicit ClientSurfaceEmbedder(Window* window); + ~ClientSurfaceEmbedder(); + + // Updates the surface layer and the clip layer based on the surface info. + void UpdateSurface(const cc::SurfaceInfo& surface_info); + + private: + // The window which embeds the client. + Window* window_; + + // Contains the client's content. + std::unique_ptr<ui::Layer> surface_layer_; + + // Used for clipping the surface layer to the window bounds. + std::unique_ptr<ui::Layer> clip_layer_; + + DISALLOW_COPY_AND_ASSIGN(ClientSurfaceEmbedder); +}; + +} // namespace aura
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc index 305fcfc..da1ae15 100644 --- a/ui/aura/mus/window_port_mus.cc +++ b/ui/aura/mus/window_port_mus.cc
@@ -7,6 +7,7 @@ #include "base/memory/ptr_util.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/transient_window_client.h" +#include "ui/aura/mus/client_surface_embedder.h" #include "ui/aura/mus/property_converter.h" #include "ui/aura/mus/surface_id_handler.h" #include "ui/aura/mus/window_tree_client.h" @@ -255,10 +256,22 @@ } } WindowPortMus* parent = Get(window_->parent()); + // TODO(mfomitchev): This is unused. We probably don't need this. if (parent && parent->surface_id_handler_) { parent->surface_id_handler_->OnChildWindowSurfaceChanged(window_, surface_info); } + + // The fact that SetSurfaceIdFromServer was called means that this window + // corresponds to an embedded client. + if (!client_surface_embedder && surface_info.id().is_valid()) + client_surface_embedder = base::MakeUnique<ClientSurfaceEmbedder>(window_); + + if (surface_info.id().is_valid()) + client_surface_embedder->UpdateSurface(surface_info); + else + client_surface_embedder.reset(); + surface_info_ = surface_info; }
diff --git a/ui/aura/mus/window_port_mus.h b/ui/aura/mus/window_port_mus.h index fd598d0f5..f687f42b 100644 --- a/ui/aura/mus/window_port_mus.h +++ b/ui/aura/mus/window_port_mus.h
@@ -26,6 +26,7 @@ namespace aura { +class ClientSurfaceEmbedder; class PropertyConverter; class SurfaceIdHandler; class Window; @@ -243,6 +244,9 @@ Window* window_ = nullptr; + // Used when this window is embedding a client. + std::unique_ptr<ClientSurfaceEmbedder> client_surface_embedder; + ServerChangeIdType next_server_change_id_ = 0; ServerChanges server_changes_;
diff --git a/ui/aura/window_delegate.cc b/ui/aura/window_delegate.cc deleted file mode 100644 index c3503d8..0000000 --- a/ui/aura/window_delegate.cc +++ /dev/null
@@ -1,11 +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 "ui/aura/window_delegate.h" - -namespace aura { - -void WindowDelegate::OnRequestClose() {} - -} // namespace aura
diff --git a/ui/aura/window_delegate.h b/ui/aura/window_delegate.h index 434dcad5..644c0ce 100644 --- a/ui/aura/window_delegate.h +++ b/ui/aura/window_delegate.h
@@ -94,9 +94,6 @@ // above returns true. virtual void GetHitTestMask(gfx::Path* mask) const = 0; - // Sent when the server requests the window to close. - virtual void OnRequestClose(); - protected: ~WindowDelegate() override {} };
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc index 8f674a6..9150bf5 100644 --- a/ui/compositor/layer_unittest.cc +++ b/ui/compositor/layer_unittest.cc
@@ -98,7 +98,6 @@ enum DrawFunction { STRING_WITH_HALO, STRING_FADED, - STRING_WITH_SHADOWS }; DrawStringLayerDelegate( @@ -127,14 +126,6 @@ recorder.canvas()->DrawFadedString( text, font_list_, SK_ColorRED, bounds, 0); break; - case STRING_WITH_SHADOWS: { - gfx::ShadowValues shadows; - shadows.push_back( - gfx::ShadowValue(gfx::Vector2d(2, 2), 2, SK_ColorRED)); - recorder.canvas()->DrawStringRectWithShadows( - text, font_list_, SK_ColorRED, bounds, 0, 0, shadows); - break; - } default: NOTREACHED(); } @@ -1526,41 +1517,6 @@ large_error_allowed, small_error_allowed))); } - -TEST_F(LayerWithRealCompositorTest, CanvasDrawStringRectWithShadows) { - gfx::Size size(50, 50); - GetCompositor()->SetScaleAndSize(1.0f, size); - DrawStringLayerDelegate delegate( - SK_ColorBLUE, SK_ColorWHITE, - DrawStringLayerDelegate::STRING_WITH_SHADOWS, - size); - std::unique_ptr<Layer> layer( - CreateDrawStringLayer(gfx::Rect(size), &delegate)); - DrawTree(layer.get()); - - SkBitmap bitmap; - ReadPixels(&bitmap); - ASSERT_FALSE(bitmap.empty()); - - base::FilePath ref_img = - test_data_directory().AppendASCII("string_with_shadows.png"); - // WritePNGFile(bitmap, ref_img, true); - - float percentage_pixels_large_error = 7.4f; // 185px / (50*50) - float percentage_pixels_small_error = 0.0f; - float average_error_allowed_in_bad_pixels = 60.f; - int large_error_allowed = 246; - int small_error_allowed = 0; - - EXPECT_TRUE(MatchesPNGFile(bitmap, ref_img, - cc::FuzzyPixelComparator( - true, - percentage_pixels_large_error, - percentage_pixels_small_error, - average_error_allowed_in_bad_pixels, - large_error_allowed, - small_error_allowed))); -} #endif // defined(OS_WIN) // Opacity is rendered correctly.
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc index 9e82c7f..5f2bff97 100644 --- a/ui/gfx/canvas.cc +++ b/ui/gfx/canvas.cc
@@ -463,15 +463,6 @@ DefaultCanvasTextAlignment()); } -void Canvas::DrawStringRectWithFlags(const base::string16& text, - const FontList& font_list, - SkColor color, - const Rect& display_rect, - int flags) { - DrawStringRectWithShadows(text, font_list, color, display_rect, 0, flags, - ShadowValues()); -} - void Canvas::TileImageInt(const ImageSkia& image, int x, int y,
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h index 00f5b91..adf1286 100644 --- a/ui/gfx/canvas.h +++ b/ui/gfx/canvas.h
@@ -16,7 +16,6 @@ #include "third_party/skia/include/core/SkRefCnt.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/native_widget_types.h" -#include "ui/gfx/shadow_value.h" #include "ui/gfx/text_constants.h" namespace gfx { @@ -28,6 +27,7 @@ class PointF; class Size; class Transform; +class Vector2d; // Canvas is a SkCanvas wrapper that provides a number of methods for // common operations used throughout an application built using ui/gfx. @@ -407,17 +407,6 @@ const Rect& display_rect, int flags); - // Similar to above DrawStringRect method but with text shadows support. - // Currently it's only implemented for canvas skia. Specifying a 0 line_height - // will cause the default height to be used. - void DrawStringRectWithShadows(const base::string16& text, - const FontList& font_list, - SkColor color, - const Rect& text_bounds, - int line_height, - int flags, - const ShadowValues& shadows); - // Draws a dotted gray rectangle used for focus purposes. // DEPRECATED in favor of the RectF version below. // TODO(funkysidd): Remove this (http://crbug.com/553726)
diff --git a/ui/gfx/canvas_notimplemented.cc b/ui/gfx/canvas_notimplemented.cc index f31de5a..dc661b5 100644 --- a/ui/gfx/canvas_notimplemented.cc +++ b/ui/gfx/canvas_notimplemented.cc
@@ -27,13 +27,11 @@ NOTIMPLEMENTED(); } -void Canvas::DrawStringRectWithShadows(const base::string16& text, - const FontList& font_list, - SkColor color, - const Rect& text_bounds, - int line_height, - int flags, - const ShadowValues& shadows) { +void Canvas::DrawStringRectWithFlags(const base::string16& text, + const FontList& font_list, + SkColor color, + const Rect& text_bounds, + int flags) { NOTIMPLEMENTED(); }
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc index 7aa114b1..3fd8f36 100644 --- a/ui/gfx/canvas_skia.cc +++ b/ui/gfx/canvas_skia.cc
@@ -143,26 +143,20 @@ } } -void Canvas::DrawStringRectWithShadows(const base::string16& text, - const FontList& font_list, - SkColor color, - const Rect& text_bounds, - int line_height, - int flags, - const ShadowValues& shadows) { +void Canvas::DrawStringRectWithFlags(const base::string16& text, + const FontList& font_list, + SkColor color, + const Rect& text_bounds, + int flags) { if (!IntersectsClipRect(RectToSkRect(text_bounds))) return; - Rect clip_rect(text_bounds); - clip_rect.Inset(ShadowValue::GetMargin(shadows)); - canvas_->save(); - ClipRect(clip_rect); + ClipRect(text_bounds); Rect rect(text_bounds); std::unique_ptr<RenderText> render_text(RenderText::CreateInstance()); - render_text->set_shadows(shadows); render_text->set_halo_effect(!!(flags & HALO_EFFECT)); if (flags & MULTI_LINE) { @@ -182,10 +176,7 @@ UpdateRenderText(rect, strings[i], font_list, flags, color, render_text.get()); int line_padding = 0; - if (line_height > 0) - line_padding = line_height - render_text->GetStringSize().height(); - else - line_height = render_text->GetStringSize().height(); + const int line_height = render_text->GetStringSize().height(); // TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357 #if !defined(OS_WIN)
diff --git a/ui/gfx/test/data/compositor/string_with_shadows.png b/ui/gfx/test/data/compositor/string_with_shadows.png deleted file mode 100644 index e9b8926..0000000 --- a/ui/gfx/test/data/compositor/string_with_shadows.png +++ /dev/null Binary files differ
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc index af86e79..24eaae3 100644 --- a/ui/native_theme/native_theme_win.cc +++ b/ui/native_theme/native_theme_win.cc
@@ -17,7 +17,6 @@ #include "base/win/scoped_select_object.h" #include "base/win/win_util.h" #include "base/win/windows_version.h" -#include "skia/ext/bitmap_platform_device.h" #include "skia/ext/platform_canvas.h" #include "skia/ext/skia_utils_win.h" #include "third_party/skia/include/core/SkCanvas.h"
diff --git a/ui/views/bubble/bubble_border.cc b/ui/views/bubble/bubble_border.cc index 0746d87..f932250 100644 --- a/ui/views/bubble/bubble_border.cc +++ b/ui/views/bubble/bubble_border.cc
@@ -5,6 +5,7 @@ #include "ui/views/bubble/bubble_border.h" #include <algorithm> +#include <vector> #include "base/logging.h" #include "third_party/skia/include/core/SkDrawLooper.h" @@ -16,6 +17,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/path.h" #include "ui/gfx/scoped_canvas.h" +#include "ui/gfx/shadow_value.h" #include "ui/gfx/skia_util.h" #include "ui/resources/grit/ui_resources.h" #include "ui/views/painter.h"
diff --git a/ui/views/controls/button/toggle_button.cc b/ui/views/controls/button/toggle_button.cc index c0ad3922..37c2ce1 100644 --- a/ui/views/controls/button/toggle_button.cc +++ b/ui/views/controls/button/toggle_button.cc
@@ -11,6 +11,7 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/shadow_value.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/border.h"