diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java index f958dc8e..446acfb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -423,8 +423,7 @@ intent.setData(contentUri); intent.putExtra(CustomTabIntentDataProvider.EXTRA_IS_MEDIA_VIEWER, true); intent.putExtra(CustomTabIntentDataProvider.EXTRA_MEDIA_VIEWER_URL, fileUri.toString()); - intent.putExtra(CustomTabIntentDataProvider.EXTRA_ENABLE_EMBEDDED_MEDIA_EXPERIENCE, - isMimeTypeVideo(mimeType)); + intent.putExtra(CustomTabIntentDataProvider.EXTRA_ENABLE_EMBEDDED_MEDIA_EXPERIENCE, true); intent.putExtra( CustomTabIntentDataProvider.EXTRA_INITIAL_BACKGROUND_COLOR, mediaColor); intent.putExtra(
diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc index fa072b9..f06c6169 100644 --- a/content/browser/media/media_internals.cc +++ b/content/browser/media/media_internals.cc
@@ -297,6 +297,7 @@ base::TimeDelta src_watch_time = media::kNoTimestamp; base::TimeDelta ac_watch_time = media::kNoTimestamp; base::TimeDelta battery_watch_time = media::kNoTimestamp; + base::TimeDelta embedded_experience_watch_time = media::kNoTimestamp; }; struct PipelineInfo { @@ -358,6 +359,8 @@ MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoMse, mse_watch_time); MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoEme, eme_watch_time); MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoSrc, src_watch_time); + MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoEmbeddedExperience, + embedded_experience_watch_time); } else { DCHECK_EQ(finalize_type, FinalizeType::POWER_ONLY); } @@ -369,6 +372,8 @@ MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioMse, mse_watch_time); MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioEme, eme_watch_time); MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioSrc, src_watch_time); + MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioEmbeddedExperience, + embedded_experience_watch_time); } else { DCHECK_EQ(finalize_type, FinalizeType::POWER_ONLY); } @@ -467,6 +472,9 @@ &wti.battery_watch_time); MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioAc, &wti.ac_watch_time); + MaybeSaveWatchTime(event, + media::MediaLog::kWatchTimeAudioEmbeddedExperience, + &wti.embedded_experience_watch_time); // Save audio+video watch time information. MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoAll, @@ -481,6 +489,9 @@ &wti.battery_watch_time); MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoAc, &wti.ac_watch_time); + MaybeSaveWatchTime( + event, media::MediaLog::kWatchTimeAudioVideoEmbeddedExperience, + &wti.embedded_experience_watch_time); if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) { bool should_finalize;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 5a7b201..aa76a1ed 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -2810,9 +2810,12 @@ scoped_refptr<media::MediaLog> media_log( new RenderMediaLog(url::Origin(frame_->getSecurityOrigin()).GetURL())); + bool embedded_media_experience_enabled = false; #if defined(OS_ANDROID) if (!UseMediaPlayerRenderer(url) && !media_surface_manager_) media_surface_manager_ = new RendererSurfaceViewManager(this); + embedded_media_experience_enabled = + GetWebkitPreferences().embedded_media_experience_enabled; #endif // defined(OS_ANDROID) #if BUILDFLAG(ENABLE_MEDIA_REMOTING) @@ -2846,7 +2849,8 @@ // in the renderer process. See https://crbug.com/681160. GetWebkitPreferences().max_keyframe_distance_to_disable_background_video, GetWebkitPreferences().enable_instant_source_buffer_gc, - GetContentClient()->renderer()->AllowMediaSuspend()); + GetContentClient()->renderer()->AllowMediaSuspend(), + embedded_media_experience_enabled); bool use_fallback_path = false; #if defined(OS_ANDROID)
diff --git a/media/base/media_log.cc b/media/base/media_log.cc index 52bf031..8aa0db34 100644 --- a/media/base/media_log.cc +++ b/media/base/media_log.cc
@@ -28,6 +28,8 @@ const char MediaLog::kWatchTimeAudioVideoBattery[] = "Media.WatchTime.AudioVideo.Battery"; const char MediaLog::kWatchTimeAudioVideoAc[] = "Media.WatchTime.AudioVideo.AC"; +const char MediaLog::kWatchTimeAudioVideoEmbeddedExperience[] = + "Media.WatchTime.AudioVideo.EmbeddedExperience"; // Audio only "watch time" metrics. const char MediaLog::kWatchTimeAudioAll[] = "Media.WatchTime.Audio.All"; @@ -36,6 +38,8 @@ const char MediaLog::kWatchTimeAudioSrc[] = "Media.WatchTime.Audio.SRC"; const char MediaLog::kWatchTimeAudioBattery[] = "Media.WatchTime.Audio.Battery"; const char MediaLog::kWatchTimeAudioAc[] = "Media.WatchTime.Audio.AC"; +const char MediaLog::kWatchTimeAudioEmbeddedExperience[] = + "Media.WatchTime.Audio.EmbeddedExperience"; const char MediaLog::kWatchTimeFinalize[] = "FinalizeWatchTime"; const char MediaLog::kWatchTimeFinalizePower[] = "FinalizePowerWatchTime";
diff --git a/media/base/media_log.h b/media/base/media_log.h index 6ef04e1..eba57bc 100644 --- a/media/base/media_log.h +++ b/media/base/media_log.h
@@ -96,12 +96,14 @@ static const char kWatchTimeAudioSrc[]; static const char kWatchTimeAudioBattery[]; static const char kWatchTimeAudioAc[]; + static const char kWatchTimeAudioEmbeddedExperience[]; static const char kWatchTimeAudioVideoAll[]; static const char kWatchTimeAudioVideoMse[]; static const char kWatchTimeAudioVideoEme[]; static const char kWatchTimeAudioVideoSrc[]; static const char kWatchTimeAudioVideoBattery[]; static const char kWatchTimeAudioVideoAc[]; + static const char kWatchTimeAudioVideoEmbeddedExperience[]; // Markers which signify the watch time should be finalized immediately. static const char kWatchTimeFinalize[];
diff --git a/media/blink/watch_time_reporter.cc b/media/blink/watch_time_reporter.cc index e9872cb..06e9764 100644 --- a/media/blink/watch_time_reporter.cc +++ b/media/blink/watch_time_reporter.cc
@@ -26,6 +26,7 @@ bool has_video, bool is_mse, bool is_encrypted, + bool is_embedded_media_experience_enabled, scoped_refptr<MediaLog> media_log, const gfx::Size& initial_video_size, const GetMediaTimeCB& get_media_time_cb) @@ -33,6 +34,8 @@ has_video_(has_video), is_mse_(is_mse), is_encrypted_(is_encrypted), + is_embedded_media_experience_enabled_( + is_embedded_media_experience_enabled), media_log_(std::move(media_log)), initial_video_size_(initial_video_size), get_media_time_cb_(get_media_time_cb) { @@ -227,6 +230,13 @@ elapsed.InSecondsF()); } + if (is_embedded_media_experience_enabled_) { + log_event->params.SetDoubleWithoutPathExpansion( + has_video_ ? MediaLog::kWatchTimeAudioVideoEmbeddedExperience + : MediaLog::kWatchTimeAudioEmbeddedExperience, + elapsed.InSecondsF()); + } + // Record watch time using the last known value for |is_on_battery_power_|; // if there's a |pending_power_change_| use that to accurately finalize the // last bits of time in the previous bucket.
diff --git a/media/blink/watch_time_reporter.h b/media/blink/watch_time_reporter.h index d0ded92..81ea7bd 100644 --- a/media/blink/watch_time_reporter.h +++ b/media/blink/watch_time_reporter.h
@@ -60,6 +60,7 @@ bool has_video, bool is_mse, bool is_encrypted, + bool is_embedded_media_experience_enabled, scoped_refptr<MediaLog> media_log, const gfx::Size& initial_video_size, const GetMediaTimeCB& get_media_time_cb); @@ -116,6 +117,7 @@ const bool has_video_; const bool is_mse_; const bool is_encrypted_; + const bool is_embedded_media_experience_enabled_; scoped_refptr<MediaLog> media_log_; const gfx::Size initial_video_size_; const GetMediaTimeCB get_media_time_cb_;
diff --git a/media/blink/watch_time_reporter_unittest.cc b/media/blink/watch_time_reporter_unittest.cc index 380ccf6..85e9b709 100644 --- a/media/blink/watch_time_reporter_unittest.cc +++ b/media/blink/watch_time_reporter_unittest.cc
@@ -81,7 +81,7 @@ bool is_encrypted, const gfx::Size& initial_video_size) { wtr_.reset(new WatchTimeReporter( - has_audio, has_video_, is_mse, is_encrypted, media_log_, + has_audio, has_video_, is_mse, is_encrypted, false, media_log_, initial_video_size, base::Bind(&WatchTimeReporterTest::GetCurrentMediaTime, base::Unretained(this))));
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index a81ad7c..813a643f 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -239,7 +239,9 @@ max_keyframe_distance_to_disable_background_video_( params.max_keyframe_distance_to_disable_background_video()), enable_instant_source_buffer_gc_( - params.enable_instant_source_buffer_gc()) { + params.enable_instant_source_buffer_gc()), + embedded_media_experience_enabled_( + params.embedded_media_experience_enabled()) { DVLOG(1) << __func__; DCHECK(!adjust_allocated_memory_cb_.is_null()); DCHECK(renderer_factory_); @@ -2124,10 +2126,11 @@ void WebMediaPlayerImpl::CreateWatchTimeReporter() { // Create the watch time reporter and synchronize its initial state. - watch_time_reporter_.reset(new WatchTimeReporter( - hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_, - pipeline_metadata_.natural_size, - base::Bind(&GetCurrentTimeInternal, this))); + watch_time_reporter_.reset( + new WatchTimeReporter(hasAudio(), hasVideo(), !!chunk_demuxer_, + is_encrypted_, embedded_media_experience_enabled_, + media_log_, pipeline_metadata_.natural_size, + base::Bind(&GetCurrentTimeInternal, this))); watch_time_reporter_->OnVolumeChange(volume_); if (delegate_->IsFrameHidden()) watch_time_reporter_->OnHidden();
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index e29603d..308da41 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -707,6 +707,9 @@ // the background. Affects the value of ShouldPauseVideoWhenHidden(). bool video_locked_when_paused_when_hidden_ = false; + // Whether embedded media experience is currently enabled. + bool embedded_media_experience_enabled_ = false; + DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl); };
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc index 5eb1a8d7..a040b02 100644 --- a/media/blink/webmediaplayer_impl_unittest.cc +++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -213,7 +213,7 @@ media_thread_.task_runner(), message_loop_.task_runner(), message_loop_.task_runner(), WebMediaPlayerParams::Context3DCB(), base::Bind(&OnAdjustAllocatedMemory), nullptr, nullptr, nullptr, - base::TimeDelta::FromSeconds(10), false, allow_suspend)); + base::TimeDelta::FromSeconds(10), false, allow_suspend, false)); } ~WebMediaPlayerImplTest() override {
diff --git a/media/blink/webmediaplayer_params.cc b/media/blink/webmediaplayer_params.cc index ebace61..a89f693 100644 --- a/media/blink/webmediaplayer_params.cc +++ b/media/blink/webmediaplayer_params.cc
@@ -25,7 +25,8 @@ base::WeakPtr<MediaObserver> media_observer, base::TimeDelta max_keyframe_distance_to_disable_background_video, bool enable_instant_source_buffer_gc, - bool allow_suspend) + bool allow_suspend, + bool embedded_media_experience_enabled) : defer_load_cb_(defer_load_cb), audio_renderer_sink_(audio_renderer_sink), media_log_(media_log), @@ -40,7 +41,8 @@ max_keyframe_distance_to_disable_background_video_( max_keyframe_distance_to_disable_background_video), enable_instant_source_buffer_gc_(enable_instant_source_buffer_gc), - allow_suspend_(allow_suspend) {} + allow_suspend_(allow_suspend), + embedded_media_experience_enabled_(embedded_media_experience_enabled) {} WebMediaPlayerParams::~WebMediaPlayerParams() {}
diff --git a/media/blink/webmediaplayer_params.h b/media/blink/webmediaplayer_params.h index 00aa774..b16ee3a 100644 --- a/media/blink/webmediaplayer_params.h +++ b/media/blink/webmediaplayer_params.h
@@ -61,7 +61,8 @@ base::WeakPtr<MediaObserver> media_observer, base::TimeDelta max_keyframe_distance_to_disable_background_video, bool enable_instant_source_buffer_gc, - bool allow_suspend); + bool allow_suspend, + bool embedded_media_experience_enabled); ~WebMediaPlayerParams(); @@ -115,6 +116,10 @@ bool allow_suspend() const { return allow_suspend_; } + bool embedded_media_experience_enabled() const { + return embedded_media_experience_enabled_; + } + private: DeferLoadCB defer_load_cb_; scoped_refptr<SwitchableAudioRendererSink> audio_renderer_sink_; @@ -131,6 +136,7 @@ base::TimeDelta max_keyframe_distance_to_disable_background_video_; bool enable_instant_source_buffer_gc_; const bool allow_suspend_; + const bool embedded_media_experience_enabled_; DISALLOW_IMPLICIT_CONSTRUCTORS(WebMediaPlayerParams); };
diff --git a/services/ui/ws/BUILD.gn b/services/ui/ws/BUILD.gn index 8bb2e24..71bcc321 100644 --- a/services/ui/ws/BUILD.gn +++ b/services/ui/ws/BUILD.gn
@@ -29,6 +29,8 @@ "display.h", "display_binding.cc", "display_binding.h", + "display_client_compositor_frame_sink.cc", + "display_client_compositor_frame_sink.h", "display_manager.cc", "display_manager.h", "drag_controller.cc",
diff --git a/services/ui/ws/display_client_compositor_frame_sink.cc b/services/ui/ws/display_client_compositor_frame_sink.cc new file mode 100644 index 0000000..5d719fa --- /dev/null +++ b/services/ui/ws/display_client_compositor_frame_sink.cc
@@ -0,0 +1,106 @@ +// 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 "services/ui/ws/display_client_compositor_frame_sink.h" + +#include "base/threading/thread_checker.h" +#include "cc/output/compositor_frame_sink_client.h" + +namespace ui { +namespace ws { + +DisplayClientCompositorFrameSink::DisplayClientCompositorFrameSink( + const cc::FrameSinkId& frame_sink_id, + cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink, + cc::mojom::DisplayPrivateAssociatedPtr display_private, + cc::mojom::MojoCompositorFrameSinkClientRequest client_request) + : cc::CompositorFrameSink(nullptr, nullptr, nullptr, nullptr), + compositor_frame_sink_(std::move(compositor_frame_sink)), + client_binding_(this, std::move(client_request)), + display_private_(std::move(display_private)), + frame_sink_id_(frame_sink_id) {} + +DisplayClientCompositorFrameSink::~DisplayClientCompositorFrameSink() {} + +bool DisplayClientCompositorFrameSink::BindToClient( + cc::CompositorFrameSinkClient* client) { + if (!cc::CompositorFrameSink::BindToClient(client)) + return false; + DCHECK(!thread_checker_); + thread_checker_ = base::MakeUnique<base::ThreadChecker>(); + + begin_frame_source_ = base::MakeUnique<cc::ExternalBeginFrameSource>(this); + + client->SetBeginFrameSource(begin_frame_source_.get()); + return true; +} + +void DisplayClientCompositorFrameSink::DetachFromClient() { + client_->SetBeginFrameSource(nullptr); + begin_frame_source_.reset(); + cc::CompositorFrameSink::DetachFromClient(); +} + +void DisplayClientCompositorFrameSink::SubmitCompositorFrame( + cc::CompositorFrame frame) { + DCHECK(thread_checker_->CalledOnValidThread()); + if (!compositor_frame_sink_) + return; + + gfx::Size frame_size = last_submitted_frame_size_; + if (!frame.render_pass_list.empty()) + frame_size = frame.render_pass_list.back()->output_rect.size(); + + if (!local_surface_id_.is_valid() || + frame_size != last_submitted_frame_size_) { + local_surface_id_ = id_allocator_.GenerateId(); + display_private_->ResizeDisplay(frame_size); + } + display_private_->SetLocalSurfaceId(local_surface_id_, + frame.metadata.device_scale_factor); + compositor_frame_sink_->SubmitCompositorFrame(local_surface_id_, + std::move(frame)); + last_submitted_frame_size_ = frame_size; +} + +void DisplayClientCompositorFrameSink::DidReceiveCompositorFrameAck() { + DCHECK(thread_checker_->CalledOnValidThread()); + if (!client_) + return; + client_->DidReceiveCompositorFrameAck(); +} + +void DisplayClientCompositorFrameSink::OnBeginFrame( + const cc::BeginFrameArgs& begin_frame_args) { + DCHECK(thread_checker_->CalledOnValidThread()); + begin_frame_source_->OnBeginFrame(begin_frame_args); +} + +void DisplayClientCompositorFrameSink::ReclaimResources( + const cc::ReturnedResourceArray& resources) { + DCHECK(thread_checker_->CalledOnValidThread()); + if (!client_) + return; + client_->ReclaimResources(resources); +} + +void DisplayClientCompositorFrameSink::WillDrawSurface( + const cc::LocalSurfaceId& local_surface_id, + const gfx::Rect& damage_rect) { + // TODO(fsamuel, staraz): Implement this. +} + +void DisplayClientCompositorFrameSink::OnNeedsBeginFrames( + bool needs_begin_frames) { + DCHECK(thread_checker_->CalledOnValidThread()); + compositor_frame_sink_->SetNeedsBeginFrame(needs_begin_frames); +} + +void DisplayClientCompositorFrameSink::OnDidFinishFrame( + const cc::BeginFrameAck& ack) { + // TODO(eseckler): Pass on the ack to compositor_frame_sink_. +} + +} // namespace ws +} // namespace ui
diff --git a/services/ui/ws/display_client_compositor_frame_sink.h b/services/ui/ws/display_client_compositor_frame_sink.h new file mode 100644 index 0000000..90846896 --- /dev/null +++ b/services/ui/ws/display_client_compositor_frame_sink.h
@@ -0,0 +1,71 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_UI_PUBLIC_CPP_DISPLAY_CLIENT_COMPOSITOR_FRAME_SINK_H_ +#define SERVICES_UI_PUBLIC_CPP_DISPLAY_CLIENT_COMPOSITOR_FRAME_SINK_H_ + +#include "cc/ipc/display_compositor.mojom.h" +#include "cc/ipc/mojo_compositor_frame_sink.mojom.h" +#include "cc/output/compositor_frame_sink.h" +#include "cc/scheduler/begin_frame_source.h" +#include "cc/surfaces/local_surface_id.h" +#include "cc/surfaces/local_surface_id_allocator.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "ui/gfx/geometry/size.h" + +namespace base { +class ThreadChecker; +} // namespace base + +namespace ui { +namespace ws { + +class DisplayClientCompositorFrameSink + : public cc::CompositorFrameSink, + public cc::mojom::MojoCompositorFrameSinkClient, + public cc::ExternalBeginFrameSourceClient { + public: + DisplayClientCompositorFrameSink( + const cc::FrameSinkId& frame_sink_id, + cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink, + cc::mojom::DisplayPrivateAssociatedPtr display_private, + cc::mojom::MojoCompositorFrameSinkClientRequest client_request); + + ~DisplayClientCompositorFrameSink() override; + + // cc::CompositorFrameSink implementation: + bool BindToClient(cc::CompositorFrameSinkClient* client) override; + void DetachFromClient() override; + void SubmitCompositorFrame(cc::CompositorFrame frame) override; + + private: + // cc::mojom::MojoCompositorFrameSinkClient implementation: + void DidReceiveCompositorFrameAck() override; + void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) override; + void ReclaimResources(const cc::ReturnedResourceArray& resources) override; + void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id, + const gfx::Rect& damage_rect) override; + + // cc::ExternalBeginFrameSourceClient implementation: + void OnNeedsBeginFrames(bool needs_begin_frame) override; + void OnDidFinishFrame(const cc::BeginFrameAck& ack) override; + + gfx::Size last_submitted_frame_size_; + cc::LocalSurfaceId local_surface_id_; + cc::LocalSurfaceIdAllocator id_allocator_; + cc::mojom::MojoCompositorFrameSinkClientRequest client_request_; + cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink_; + mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> client_binding_; + cc::mojom::DisplayPrivateAssociatedPtr display_private_; + std::unique_ptr<base::ThreadChecker> thread_checker_; + std::unique_ptr<cc::ExternalBeginFrameSource> begin_frame_source_; + const cc::FrameSinkId frame_sink_id_; + + DISALLOW_COPY_AND_ASSIGN(DisplayClientCompositorFrameSink); +}; + +} // namspace ws +} // namespace ui + +#endif // SERVICES_UI_PUBLIC_CPP_DISPLAY_CLIENT_COMPOSITOR_FRAME_SINK_H_
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc index b1574c4..30b17f3 100644 --- a/services/ui/ws/frame_generator.cc +++ b/services/ui/ws/frame_generator.cc
@@ -7,44 +7,40 @@ #include <utility> #include <vector> -#include "base/containers/adapters.h" #include "cc/output/compositor_frame.h" +#include "cc/output/compositor_frame_sink.h" #include "cc/quads/render_pass.h" #include "cc/quads/render_pass_draw_quad.h" #include "cc/quads/shared_quad_state.h" #include "cc/quads/surface_draw_quad.h" #include "services/ui/ws/frame_generator_delegate.h" #include "services/ui/ws/server_window.h" -#include "services/ui/ws/server_window_compositor_frame_sink_manager.h" -#include "services/ui/ws/server_window_delegate.h" namespace ui { namespace ws { -FrameGenerator::FrameGenerator(FrameGeneratorDelegate* delegate, - ServerWindow* root_window, - gfx::AcceleratedWidget widget) - : delegate_(delegate), root_window_(root_window), binding_(this) { +FrameGenerator::FrameGenerator( + FrameGeneratorDelegate* delegate, + ServerWindow* root_window, + std::unique_ptr<cc::CompositorFrameSink> compositor_frame_sink) + : delegate_(delegate), + root_window_(root_window), + compositor_frame_sink_(std::move(compositor_frame_sink)) { DCHECK(delegate_); - DCHECK_NE(gfx::kNullAcceleratedWidget, widget); - cc::mojom::MojoCompositorFrameSinkAssociatedRequest sink_request = - mojo::MakeRequest(&compositor_frame_sink_); - cc::mojom::DisplayPrivateAssociatedRequest display_request = - mojo::MakeRequest(&display_private_); - root_window_->CreateRootCompositorFrameSink( - widget, std::move(sink_request), binding_.CreateInterfacePtrAndBind(), - std::move(display_request)); + compositor_frame_sink_->BindToClient(this); } -FrameGenerator::~FrameGenerator() = default; +FrameGenerator::~FrameGenerator() { + compositor_frame_sink_->DetachFromClient(); +} void FrameGenerator::SetDeviceScaleFactor(float device_scale_factor) { if (device_scale_factor_ == device_scale_factor) return; device_scale_factor_ = device_scale_factor; if (window_manager_surface_info_.is_valid()) - compositor_frame_sink_->SetNeedsBeginFrame(true); + SetNeedsBeginFrame(true); } void FrameGenerator::OnSurfaceCreated(const cc::SurfaceInfo& surface_info) { @@ -54,39 +50,23 @@ // changing is handled immediately after the CompositorFrame is submitted. if (surface_info != window_manager_surface_info_) { window_manager_surface_info_ = surface_info; - compositor_frame_sink_->SetNeedsBeginFrame(true); + SetNeedsBeginFrame(true); } } void FrameGenerator::OnWindowDamaged() { if (window_manager_surface_info_.is_valid()) - compositor_frame_sink_->SetNeedsBeginFrame(true); + SetNeedsBeginFrame(true); } -void FrameGenerator::DidReceiveCompositorFrameAck() {} +void FrameGenerator::SetBeginFrameSource(cc::BeginFrameSource* source) { + if (begin_frame_source_ && observing_begin_frames_) + begin_frame_source_->RemoveObserver(this); -void FrameGenerator::OnBeginFrame(const cc::BeginFrameArgs& begin_frame_arags) { - if (!root_window_->visible()) - return; + begin_frame_source_ = source; - // TODO(fsamuel): We should add a trace for generating a top level frame. - cc::CompositorFrame frame(GenerateCompositorFrame(root_window_->bounds())); - - gfx::Size frame_size = last_submitted_frame_size_; - if (!frame.render_pass_list.empty()) - frame_size = frame.render_pass_list.back()->output_rect.size(); - - if (!local_surface_id_.is_valid() || - frame_size != last_submitted_frame_size_) { - local_surface_id_ = id_allocator_.GenerateId(); - display_private_->ResizeDisplay(frame_size); - } - - display_private_->SetLocalSurfaceId(local_surface_id_, device_scale_factor_); - compositor_frame_sink_->SubmitCompositorFrame(local_surface_id_, - std::move(frame)); - compositor_frame_sink_->SetNeedsBeginFrame(false); - last_submitted_frame_size_ = frame_size; + if (begin_frame_source_ && observing_begin_frames_) + begin_frame_source_->AddObserver(this); } void FrameGenerator::ReclaimResources( @@ -96,11 +76,40 @@ DCHECK(resources.empty()); } -void FrameGenerator::WillDrawSurface(const cc::LocalSurfaceId& local_surface_id, - const gfx::Rect& damage_rect) { - // TODO(fsamuel, staraz): Implement this. +void FrameGenerator::SetTreeActivationCallback(const base::Closure& callback) {} + +void FrameGenerator::DidReceiveCompositorFrameAck() {} + +void FrameGenerator::DidLoseCompositorFrameSink() {} + +void FrameGenerator::OnDraw(const gfx::Transform& transform, + const gfx::Rect& viewport, + bool resourceless_software_draw) {} + +void FrameGenerator::SetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) {} + +void FrameGenerator::SetExternalTilePriorityConstraints( + const gfx::Rect& viewport_rect, + const gfx::Transform& transform) {} + +void FrameGenerator::OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) { + if (!root_window_->visible()) + return; + + // TODO(fsamuel): We should add a trace for generating a top level frame. + cc::CompositorFrame frame(GenerateCompositorFrame(root_window_->bounds())); + + compositor_frame_sink_->SubmitCompositorFrame(std::move(frame)); + SetNeedsBeginFrame(false); + last_begin_frame_args_ = begin_frame_args; } +const cc::BeginFrameArgs& FrameGenerator::LastUsedBeginFrameArgs() const { + return last_begin_frame_args_; +} + +void FrameGenerator::OnBeginFrameSourcePausedChanged(bool paused) {} + cc::CompositorFrame FrameGenerator::GenerateCompositorFrame( const gfx::Rect& output_rect) { const int render_pass_id = 1; @@ -173,6 +182,20 @@ cc::SurfaceDrawQuadType::PRIMARY, nullptr); } +void FrameGenerator::SetNeedsBeginFrame(bool needs_begin_frame) { + if (needs_begin_frame == observing_begin_frames_) + return; + + if (needs_begin_frame) { + begin_frame_source_->AddObserver(this); + observing_begin_frames_ = true; + return; + } + + begin_frame_source_->RemoveObserver(this); + observing_begin_frames_ = false; +} + } // namespace ws } // namespace ui
diff --git a/services/ui/ws/frame_generator.h b/services/ui/ws/frame_generator.h index 4372581..baf0479 100644 --- a/services/ui/ws/frame_generator.h +++ b/services/ui/ws/frame_generator.h
@@ -10,38 +10,36 @@ #include "base/macros.h" #include "base/timer/timer.h" #include "cc/ipc/display_compositor.mojom.h" +#include "cc/output/compositor_frame_sink_client.h" +#include "cc/scheduler/begin_frame_source.h" #include "cc/surfaces/frame_sink_id.h" #include "cc/surfaces/local_surface_id_allocator.h" #include "cc/surfaces/surface_id.h" #include "cc/surfaces/surface_reference.h" #include "services/ui/public/interfaces/window_tree_constants.mojom.h" -#include "services/ui/ws/ids.h" -#include "services/ui/ws/server_window_delegate.h" -#include "services/ui/ws/server_window_tracker.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" namespace cc { +class CompositorFrameSink; class RenderPass; } namespace ui { namespace ws { -namespace test { -class FrameGeneratorTest; -} - class FrameGeneratorDelegate; class ServerWindow; // Responsible for redrawing the display in response to the redraw requests by // submitting CompositorFrames to the owned CompositorFrameSink. -class FrameGenerator : public cc::mojom::MojoCompositorFrameSinkClient { +class FrameGenerator : public cc::CompositorFrameSinkClient, + public cc::BeginFrameObserver { public: - FrameGenerator(FrameGeneratorDelegate* delegate, - ServerWindow* root_window, - gfx::AcceleratedWidget widget); + FrameGenerator( + FrameGeneratorDelegate* delegate, + ServerWindow* root_window, + std::unique_ptr<cc::CompositorFrameSink> compositor_frame_sink); ~FrameGenerator() override; void SetDeviceScaleFactor(float device_scale_factor); @@ -52,14 +50,24 @@ void OnWindowDamaged(); private: - friend class ui::ws::test::FrameGeneratorTest; - - // cc::mojom::MojoCompositorFrameSinkClient implementation: - void DidReceiveCompositorFrameAck() override; - void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_arags) override; + // cc::CompositorFrameSinkClient implementation: + void SetBeginFrameSource(cc::BeginFrameSource* source) override; void ReclaimResources(const cc::ReturnedResourceArray& resources) override; - void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id, - const gfx::Rect& damage_rect) override; + void SetTreeActivationCallback(const base::Closure& callback) override; + void DidReceiveCompositorFrameAck() override; + void DidLoseCompositorFrameSink() override; + void OnDraw(const gfx::Transform& transform, + const gfx::Rect& viewport, + bool resourceless_software_draw) override; + void SetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override; + void SetExternalTilePriorityConstraints( + const gfx::Rect& viewport_rect, + const gfx::Transform& transform) override; + + // cc::BeginFrameObserver implementation: + void OnBeginFrame(const cc::BeginFrameArgs& args) override; + const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override; + void OnBeginFrameSourcePausedChanged(bool paused) override; // Generates the CompositorFrame. cc::CompositorFrame GenerateCompositorFrame(const gfx::Rect& output_rect); @@ -68,20 +76,21 @@ // the provided cc::RenderPass. void DrawWindow(cc::RenderPass* pass); + // SetNeedsBeginFrame sets observing_begin_frames_ and add/remove + // FrameGenerator as an observer to/from begin_frame_source_ accordingly. + void SetNeedsBeginFrame(bool needs_begin_frame); + FrameGeneratorDelegate* delegate_; ServerWindow* const root_window_; float device_scale_factor_ = 1.f; - gfx::Size last_submitted_frame_size_; - cc::LocalSurfaceId local_surface_id_; - cc::LocalSurfaceIdAllocator id_allocator_; - cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink_; - cc::mojom::DisplayPrivateAssociatedPtr display_private_; + std::unique_ptr<cc::CompositorFrameSink> compositor_frame_sink_; + cc::BeginFrameArgs last_begin_frame_args_; + cc::BeginFrameSource* begin_frame_source_ = nullptr; + bool observing_begin_frames_ = false; cc::SurfaceInfo window_manager_surface_info_; - mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> binding_; - DISALLOW_COPY_AND_ASSIGN(FrameGenerator); };
diff --git a/services/ui/ws/platform_display_default.cc b/services/ui/ws/platform_display_default.cc index 6d32827f0..fcf12c8 100644 --- a/services/ui/ws/platform_display_default.cc +++ b/services/ui/ws/platform_display_default.cc
@@ -7,6 +7,7 @@ #include "base/memory/ptr_util.h" #include "gpu/ipc/client/gpu_channel_host.h" #include "services/ui/display/screen_manager.h" +#include "services/ui/ws/display_client_compositor_frame_sink.h" #include "services/ui/ws/platform_display_init_params.h" #include "services/ui/ws/server_window.h" #include "ui/base/cursor/image_cursors.h" @@ -248,8 +249,26 @@ DCHECK_EQ(gfx::kNullAcceleratedWidget, widget_); widget_ = widget; delegate_->OnAcceleratedWidgetAvailable(); - frame_generator_ = - base::MakeUnique<FrameGenerator>(this, root_window_, widget_); + + cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink; + cc::mojom::DisplayPrivateAssociatedPtr display_private; + cc::mojom::MojoCompositorFrameSinkClientPtr compositor_frame_sink_client; + cc::mojom::MojoCompositorFrameSinkClientRequest + compositor_frame_sink_client_request = + mojo::MakeRequest(&compositor_frame_sink_client); + + root_window_->CreateRootCompositorFrameSink( + widget_, mojo::MakeRequest(&compositor_frame_sink), + std::move(compositor_frame_sink_client), + mojo::MakeRequest(&display_private)); + + auto display_client_compositor_frame_sink = + base::MakeUnique<DisplayClientCompositorFrameSink>( + root_window_->frame_sink_id(), std::move(compositor_frame_sink), + std::move(display_private), + std::move(compositor_frame_sink_client_request)); + frame_generator_ = base::MakeUnique<FrameGenerator>( + this, root_window_, std::move(display_client_compositor_frame_sink)); frame_generator_->SetDeviceScaleFactor(init_device_scale_factor_); }
diff --git a/services/ui/ws/platform_display_default.h b/services/ui/ws/platform_display_default.h index 54d36d8..04252ee 100644 --- a/services/ui/ws/platform_display_default.h +++ b/services/ui/ws/platform_display_default.h
@@ -18,6 +18,7 @@ namespace ui { class ImageCursors; +class LocatedEvent; class PlatformWindow; namespace ws {
diff --git a/third_party/WebKit/LayoutTests/virtual/layout_ng/fast/block/margin-collapse/self-collapsing-block-discards-margin-expected.txt b/third_party/WebKit/LayoutTests/virtual/layout_ng/fast/block/margin-collapse/self-collapsing-block-discards-margin-expected.txt new file mode 100644 index 0000000..9229098 --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/layout_ng/fast/block/margin-collapse/self-collapsing-block-discards-margin-expected.txt
@@ -0,0 +1,2 @@ +crbug.com/479275: Don't ASSERT when a self-collapsing block discards its margin +
diff --git a/third_party/WebKit/Source/core/frame/DOMTimer.cpp b/third_party/WebKit/Source/core/frame/DOMTimer.cpp index 331376e..fb011686 100644 --- a/third_party/WebKit/Source/core/frame/DOMTimer.cpp +++ b/third_party/WebKit/Source/core/frame/DOMTimer.cpp
@@ -59,10 +59,6 @@ bool singleShot) { int timeoutID = context->timers()->installNewTimeout(context, action, timeout, singleShot); - TRACE_EVENT_INSTANT1("devtools.timeline", "TimerInstall", - TRACE_EVENT_SCOPE_THREAD, "data", - InspectorTimerInstallEvent::data(context, timeoutID, - timeout, singleShot)); return timeoutID; } @@ -103,6 +99,10 @@ startRepeating(intervalMilliseconds, BLINK_FROM_HERE); suspendIfNeeded(); + TRACE_EVENT_INSTANT1("devtools.timeline", "TimerInstall", + TRACE_EVENT_SCOPE_THREAD, "data", + InspectorTimerInstallEvent::data(context, timeoutID, + interval, singleShot)); probe::asyncTaskScheduledBreakable( context, singleShot ? "setTimeout" : "setInterval", this, !singleShot); }
diff --git a/third_party/WebKit/Source/core/html/MediaDocument.cpp b/third_party/WebKit/Source/core/html/MediaDocument.cpp index 2e953ef4..3d9202b 100644 --- a/third_party/WebKit/Source/core/html/MediaDocument.cpp +++ b/third_party/WebKit/Source/core/html/MediaDocument.cpp
@@ -193,7 +193,8 @@ div->appendChild(content); if (document()->settings() && - document()->settings()->getEmbeddedMediaExperienceEnabled()) { + document()->settings()->getEmbeddedMediaExperienceEnabled() && + source->type().startsWith("video/", TextCaseASCIIInsensitive)) { EventListener* listener = MediaLoadedEventListener::create(); AddEventListenerOptions options; options.setOnce(true);
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp index 5eb7dca..778de8c3 100644 --- a/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp +++ b/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp
@@ -936,13 +936,24 @@ void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event) { if (event->type() == EventTypeNames::click) { + bool isEmbeddedExperienceEnabled = + document().settings() && + document().settings()->getEmbeddedMediaExperienceEnabled(); if (mediaElement().isFullscreen()) { Platform::current()->recordAction( UserMetricsAction("Media.Controls.ExitFullscreen")); + if (isEmbeddedExperienceEnabled) { + Platform::current()->recordAction(UserMetricsAction( + "Media.Controls.ExitFullscreen.EmbeddedExperience")); + } mediaControls().exitFullscreen(); } else { Platform::current()->recordAction( UserMetricsAction("Media.Controls.EnterFullscreen")); + if (isEmbeddedExperienceEnabled) { + Platform::current()->recordAction(UserMetricsAction( + "Media.Controls.EnterFullscreen.EmbeddedExperience")); + } mediaControls().enterFullscreen(); } event->setDefaultHandled();
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp index 4c483b2..cb3d3139 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp
@@ -39,6 +39,7 @@ #include "core/inspector/InspectorNetworkAgent.h" #include "core/inspector/InspectorPageAgent.h" #include "core/inspector/InspectorSession.h" +#include "core/inspector/InspectorTraceEvents.h" #include "core/inspector/MainThreadDebugger.h" #include "core/inspector/ThreadDebugger.h" #include "core/inspector/WorkerInspectorController.h" @@ -46,6 +47,7 @@ #include "core/workers/MainThreadWorkletGlobalScope.h" #include "core/workers/WorkerGlobalScope.h" #include "core/workers/WorkerThread.h" +#include "platform/instrumentation/tracing/TraceEvent.h" #include "platform/loader/fetch/FetchInitiatorInfo.h" namespace blink { @@ -75,6 +77,7 @@ AsyncTask::AsyncTask(ExecutionContext* context, void* task, bool enabled) : m_debugger(enabled ? ThreadDebugger::from(toIsolate(context)) : nullptr), m_task(task) { + TRACE_EVENT_FLOW_END0("devtools.timeline.async", "AsyncTask", task); if (m_debugger) m_debugger->asyncTaskStarted(m_task); } @@ -88,6 +91,8 @@ const String& name, void* task, bool recurring) { + TRACE_EVENT_FLOW_BEGIN1("devtools.timeline.async", "AsyncTask", task, "data", + InspectorAsyncTask::data(name)); if (ThreadDebugger* debugger = ThreadDebugger::from(toIsolate(context))) debugger->asyncTaskScheduled(name, task, recurring); }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp index 0de5ae0..41c59523 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
@@ -1192,4 +1192,10 @@ return value; } +std::unique_ptr<TracedValue> InspectorAsyncTask::data(const String& name) { + std::unique_ptr<TracedValue> value = TracedValue::create(); + value->setString("name", name); + return value; +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h index 23734812..5fe45d7 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h +++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
@@ -444,6 +444,10 @@ const HitTestResult&); } +namespace InspectorAsyncTask { +std::unique_ptr<TracedValue> data(const String&); +} + CORE_EXPORT String toHexString(const void* p); CORE_EXPORT void setCallStack(TracedValue*);
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index 07ed841b..2d85a29 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -2401,7 +2401,7 @@ containerOffset.move(layer()->offsetForInFlowPosition()); } - bool preserve3D = container->style()->preserves3D() || style()->preserves3D(); + bool preserve3D = container->style()->preserves3D(); TransformState::TransformAccumulation accumulation = preserve3D ? TransformState::AccumulateTransform
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp index 6992af87..4a8cf22 100644 --- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -1211,7 +1211,7 @@ if (!container) return true; - bool preserve3D = container->style()->preserves3D() || style()->preserves3D(); + bool preserve3D = container->style()->preserves3D(); TransformState::TransformAccumulation accumulation = preserve3D ? TransformState::AccumulateTransform
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp index baecf0e..077c6726 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -1306,8 +1306,7 @@ transformState.setQuad(FloatQuad(FloatRect(rect))); } - bool preserve3D = (parent->style()->preserves3D() && !parent->isText()) || - (style()->preserves3D() && !isText()); + bool preserve3D = parent->style()->preserves3D() && !parent->isText(); TransformState::TransformAccumulation accumulation = preserve3D ? TransformState::AccumulateTransform
diff --git a/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp b/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp index 4020dfa..a4b9c5d 100644 --- a/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp +++ b/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp
@@ -6,6 +6,7 @@ #include "core/layout/LayoutView.h" #include "core/layout/PaintInvalidationState.h" #include "core/paint/PaintLayer.h" +#include "core/paint/PaintPropertyTreePrinter.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { @@ -24,16 +25,47 @@ toLayoutBox(object).flipForWritingMode(rect); const LayoutBoxModelObject& paintInvalidationContainer = object.containerForPaintInvalidation(); - object.mapToVisualRectInAncestorSpace(&paintInvalidationContainer, rect); - if (rect.isEmpty() && object.visualRect().isEmpty()) + + checkVisualRect(object, paintInvalidationContainer, rect, + object.visualRect(), true); + } + + void checkVisualRect(const LayoutObject& object, + const LayoutBoxModelObject& ancestor, + const LayoutRect& localRect, + const LayoutRect& expectedVisualRect, + bool adjustForBacking = false) { + LayoutRect slowMapRect = localRect; + object.mapToVisualRectInAncestorSpace(&ancestor, slowMapRect); + if (slowMapRect.isEmpty() && object.visualRect().isEmpty()) return; + + FloatRect geometryMapperRect(localRect); + if (object.paintProperties()) { + geometryMapperRect.moveBy(FloatPoint(object.paintOffset())); + document().view()->geometryMapper().sourceToDestinationVisualRect( + *object.paintProperties()->localBorderBoxProperties(), + *ancestor.paintProperties()->contentsProperties(), + geometryMapperRect); + geometryMapperRect.moveBy(-FloatPoint(ancestor.paintOffset())); + } + // The following condition can be false if paintInvalidationContainer is // a LayoutView and compositing is not enabled. - if (paintInvalidationContainer.isPaintInvalidationContainer()) { - PaintLayer::mapRectInPaintInvalidationContainerToBacking( - paintInvalidationContainer, rect); + if (adjustForBacking && ancestor.isPaintInvalidationContainer()) { + PaintLayer::mapRectInPaintInvalidationContainerToBacking(ancestor, + slowMapRect); + LayoutRect temp(geometryMapperRect); + PaintLayer::mapRectInPaintInvalidationContainerToBacking(ancestor, temp); + geometryMapperRect = FloatRect(temp); } - EXPECT_EQ(enclosingIntRect(rect), enclosingIntRect(object.visualRect())); + EXPECT_TRUE(enclosingIntRect(slowMapRect) + .contains(enclosingIntRect(expectedVisualRect))); + + if (object.paintProperties()) { + EXPECT_EQ(enclosingIntRect(expectedVisualRect), + enclosingIntRect(geometryMapperRect)); + } } }; @@ -241,11 +273,8 @@ // This rect is in physical coordinates of target. EXPECT_EQ(LayoutRect(0, 0, 140, 70), rect); - rect = localVisualRect; - target->flipForWritingMode(rect); - EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); - EXPECT_EQ(LayoutRect(222, 111, 140, 70), rect); - EXPECT_EQ(rect, target->visualRect()); + checkPaintInvalidationVisualRect(*target); + EXPECT_EQ(LayoutRect(222, 111, 140, 70), target->visualRect()); } TEST_F(VisualRectMappingTest, ContainerFlippedWritingMode) { @@ -278,11 +307,11 @@ EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); // 100 is the physical x location of target in container. EXPECT_EQ(LayoutRect(100, 0, 140, 110), rect); + rect = targetLocalVisualRect; target->flipForWritingMode(rect); - EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); - EXPECT_EQ(LayoutRect(322, 111, 140, 110), rect); - EXPECT_EQ(rect, target->visualRect()); + checkPaintInvalidationVisualRect(*target); + EXPECT_EQ(LayoutRect(322, 111, 140, 110), target->visualRect()); LayoutRect containerLocalVisualRect = container->localVisualRect(); EXPECT_EQ(LayoutRect(0, 0, 200, 100), containerLocalVisualRect); @@ -332,13 +361,11 @@ // overflow:scroll. EXPECT_EQ(LayoutRect(2, 3, 140, 110), rect); - rect = targetLocalVisualRect; - EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); + checkPaintInvalidationVisualRect(*target); // (2, 3, 140, 100) is first clipped by container's overflow clip, to // (10, 10, 50, 80), then is by added container's offset in LayoutView // (111, 222). - EXPECT_EQ(LayoutRect(232, 121, 50, 80), rect); - EXPECT_EQ(rect, target->visualRect()); + EXPECT_EQ(LayoutRect(232, 121, 50, 80), target->visualRect()); LayoutRect containerLocalVisualRect = container->localVisualRect(); // Because container has overflow clip, its visual overflow doesn't include @@ -351,10 +378,8 @@ // Container should not apply overflow clip on its own overflow rect. EXPECT_EQ(LayoutRect(0, 0, 70, 100), rect); - rect = containerLocalVisualRect; - EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(&layoutView(), rect)); - EXPECT_EQ(LayoutRect(222, 111, 70, 100), rect); - EXPECT_EQ(rect, container->visualRect()); + checkPaintInvalidationVisualRect(*container); + EXPECT_EQ(LayoutRect(222, 111, 70, 100), container->visualRect()); } TEST_F(VisualRectMappingTest, ContainerFlippedWritingModeAndOverflowScroll) { @@ -403,17 +428,14 @@ // Rect is clipped by container's overflow clip because of overflow:scroll. EXPECT_EQ(LayoutRect(-2, 3, 140, 110), rect); - rect = targetLocalVisualRect; - target->flipForWritingMode(rect); - EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); + checkPaintInvalidationVisualRect(*target); // (-2, 3, 140, 100) is first clipped by container's overflow clip, to // (40, 10, 50, 80), then is added by container's offset in LayoutView // (111, 222). // TODO(crbug.com/600039): rect.x() should be 262 (left + border-left), but is // offset // by extra horizontal border-widths because of layout error. - EXPECT_EQ(LayoutRect(322, 121, 50, 80), rect); - EXPECT_EQ(rect, target->visualRect()); + EXPECT_EQ(LayoutRect(322, 121, 50, 80), target->visualRect()); LayoutRect containerLocalVisualRect = container->localVisualRect(); // Because container has overflow clip, its visual overflow doesn't include @@ -427,14 +449,11 @@ EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(container, rect)); EXPECT_EQ(LayoutRect(0, 0, 110, 120), rect); - rect = containerLocalVisualRect; - container->flipForWritingMode(rect); - EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(&layoutView(), rect)); // TODO(crbug.com/600039): rect.x() should be 222 (left), but is offset by // extra horizontal // border-widths because of layout error. - EXPECT_EQ(LayoutRect(282, 111, 110, 120), rect); - EXPECT_EQ(rect, container->visualRect()); + checkPaintInvalidationVisualRect(*container); + EXPECT_EQ(LayoutRect(282, 111, 110, 120), container->visualRect()); } TEST_F(VisualRectMappingTest, ContainerOverflowHidden) { @@ -464,9 +483,8 @@ EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect); rect = targetLocalVisualRect; - EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); // Rect is not clipped by container's overflow clip. - EXPECT_EQ(LayoutRect(10, 10, 140, 110), rect); + checkVisualRect(*target, *container, rect, LayoutRect(10, 10, 140, 110)); } TEST_F(VisualRectMappingTest, ContainerFlippedWritingModeAndOverflowHidden) { @@ -507,9 +525,9 @@ rect = targetLocalVisualRect; target->flipForWritingMode(rect); - EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); // 58 = target_physical_x(100) + container_border_left(40) - scroll_left(58) - EXPECT_EQ(LayoutRect(-10, 10, 140, 110), rect); + checkVisualRect(*target, *container, rect, LayoutRect(-10, 10, 140, 110)); + EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); } TEST_F(VisualRectMappingTest, ContainerAndTargetDifferentFlippedWritingMode) { @@ -595,12 +613,9 @@ EXPECT_EQ(stackingContext, &absolute->containerForPaintInvalidation()); EXPECT_EQ(stackingContext, absolute->container()); - LayoutRect absoluteVisualRect = absolute->localVisualRect(); - EXPECT_EQ(LayoutRect(0, 0, 50, 50), absoluteVisualRect); - rect = absoluteVisualRect; - EXPECT_TRUE(absolute->mapToVisualRectInAncestorSpace(stackingContext, rect)); - EXPECT_EQ(LayoutRect(222, 111, 50, 50), rect); - EXPECT_EQ(rect, absolute->visualRect()); + EXPECT_EQ(LayoutRect(0, 0, 50, 50), absolute->localVisualRect()); + checkPaintInvalidationVisualRect(*absolute); + EXPECT_EQ(LayoutRect(222, 111, 50, 50), absolute->visualRect()); } TEST_F(VisualRectMappingTest, @@ -649,12 +664,9 @@ LayoutBox* target = toLayoutBox(getLayoutObjectByElementId("target")); - LayoutRect targetLocalVisualRect = target->localVisualRect(); - EXPECT_EQ(LayoutRect(0, 0, 400, 400), targetLocalVisualRect); - LayoutRect rect = targetLocalVisualRect; - EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); - EXPECT_EQ(LayoutRect(0, 0, 200, 200), rect); - EXPECT_EQ(rect, target->visualRect()); + EXPECT_EQ(LayoutRect(0, 0, 400, 400), target->localVisualRect()); + checkPaintInvalidationVisualRect(*target); + EXPECT_EQ(LayoutRect(0, 0, 200, 200), target->visualRect()); } TEST_F(VisualRectMappingTest, ContainPaint) { @@ -666,12 +678,9 @@ LayoutBox* target = toLayoutBox(getLayoutObjectByElementId("target")); - LayoutRect targetLocalVisualRect = target->localVisualRect(); - EXPECT_EQ(LayoutRect(0, 0, 400, 400), targetLocalVisualRect); - LayoutRect rect = targetLocalVisualRect; - EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); - EXPECT_EQ(LayoutRect(0, 0, 200, 200), rect); - EXPECT_EQ(rect, target->visualRect()); + EXPECT_EQ(LayoutRect(0, 0, 400, 400), target->localVisualRect()); + checkPaintInvalidationVisualRect(*target); + EXPECT_EQ(LayoutRect(0, 0, 200, 200), target->visualRect()); } TEST_F(VisualRectMappingTest, FloatUnderInline) { @@ -696,8 +705,8 @@ EXPECT_EQ(rect, target->visualRect()); rect = targetVisualRect; - EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(span, rect)); - EXPECT_EQ(LayoutRect(-200, -100, 33, 44), rect); + + checkVisualRect(*target, *span, rect, LayoutRect(-200, -100, 33, 44)); } TEST_F(VisualRectMappingTest, ShouldAccountForPreserve3d) { @@ -722,13 +731,40 @@ LayoutRect originalRect(0, 0, 100, 100); // Multiply both matrices together before flattening. TransformationMatrix matrix = container->layer()->currentTransform(); - matrix *= target->layer()->currentTransform(); matrix.flattenTo2d(); - FloatRect output = matrix.mapRect(FloatRect(originalRect)); + matrix *= target->layer()->currentTransform(); + LayoutRect output(matrix.mapRect(FloatRect(originalRect))); - EXPECT_TRUE( - target->mapToVisualRectInAncestorSpace(target->view(), originalRect)); - EXPECT_EQ(LayoutRect(enclosingIntRect(output)), originalRect); + checkVisualRect(*target, *target->view(), originalRect, output); +} + +TEST_F(VisualRectMappingTest, ShouldAccountForPreserve3dNested) { + enableCompositing(); + setBodyInnerHTML( + "<style>" + "* { margin: 0; }" + "#container {" + " transform-style: preserve-3d;" + " transform: rotateX(-45deg);" + " width: 100px; height: 100px;" + "}" + "#target {" + " transform-style: preserve-3d; transform: rotateX(45deg);" + " background: lightblue;" + " width: 100px; height: 100px;" + "}" + "</style>" + "<div id='container'><div id='target'></div></div>"); + LayoutBlock* container = + toLayoutBlock(getLayoutObjectByElementId("container")); + LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); + LayoutRect originalRect(0, 0, 100, 100); + // Multiply both matrices together before flattening. + TransformationMatrix matrix = container->layer()->currentTransform(); + matrix *= target->layer()->currentTransform(); + LayoutRect output(matrix.mapRect(FloatRect(originalRect))); + + checkVisualRect(*target, *target->view(), originalRect, output); } TEST_F(VisualRectMappingTest, ShouldAccountForPerspective) { @@ -752,17 +788,47 @@ LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); LayoutRect originalRect(0, 0, 100, 100); TransformationMatrix matrix = container->layer()->currentTransform(); + matrix.flattenTo2d(); TransformationMatrix targetMatrix; // getTransformfromContainter includes transform and perspective matrix // of the container. target->getTransformFromContainer(container, LayoutSize(), targetMatrix); matrix *= targetMatrix; - matrix.flattenTo2d(); - FloatRect output = matrix.mapRect(FloatRect(originalRect)); + LayoutRect output(matrix.mapRect(FloatRect(originalRect))); - EXPECT_TRUE( - target->mapToVisualRectInAncestorSpace(target->view(), originalRect)); - EXPECT_EQ(LayoutRect(enclosingIntRect(output)), originalRect); + checkVisualRect(*target, *target->view(), originalRect, output); +} + +TEST_F(VisualRectMappingTest, ShouldAccountForPerspectiveNested) { + enableCompositing(); + setBodyInnerHTML( + "<style>" + "* { margin: 0; }" + "#container {" + " transform-style: preserve-3d;" + " transform: rotateX(-45deg); perspective: 100px;" + " width: 100px; height: 100px;" + "}" + "#target {" + " transform-style: preserve-3d; transform: rotateX(45deg);" + " background: lightblue;" + " width: 100px; height: 100px;" + "}" + "</style>" + "<div id='container'><div id='target'></div></div>"); + LayoutBlock* container = + toLayoutBlock(getLayoutObjectByElementId("container")); + LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); + LayoutRect originalRect(0, 0, 100, 100); + TransformationMatrix matrix = container->layer()->currentTransform(); + TransformationMatrix targetMatrix; + // getTransformfromContainter includes transform and perspective matrix + // of the container. + target->getTransformFromContainer(container, LayoutSize(), targetMatrix); + matrix *= targetMatrix; + LayoutRect output(matrix.mapRect(FloatRect(originalRect))); + + checkVisualRect(*target, *target->view(), originalRect, output); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc index 75f6bc60..1211480 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -458,7 +458,10 @@ CreateConstraintSpaceForChild(child); if (child->Type() == NGLayoutInputNode::kLegacyInline) { - LayoutInlineChildren(toNGInlineNode(child), child_space.get()); + LayoutInlineChild(toNGInlineNode(child), child_space.get()); + // TODO(kojii): We need to get NGInlineNode::NextSibiling() and continue, + // but currently it always return nullptr. This needs to change when it + // supports inline/block mixed children. break; } @@ -519,23 +522,17 @@ return builder_.ToBoxFragment(); } -void NGBlockLayoutAlgorithm::LayoutInlineChildren( - NGInlineNode* inline_child, - NGConstraintSpace* child_space) { +void NGBlockLayoutAlgorithm::LayoutInlineChild(NGInlineNode* inline_child, + NGConstraintSpace* child_space) { // TODO(kojii): This logic does not handle when children are mix of // inline/block. We need to detect the case and setup appropriately; e.g., // constraint space, margin collapsing, next siblings, etc. - NGLineBuilder line_builder(inline_child, child_space); + NGLineBuilder line_builder(inline_child, child_space, &builder_); // TODO(kojii): Need to determine when to invalidate PrepareLayout() more // efficiently than "everytime". inline_child->InvalidatePrepareLayout(); inline_child->LayoutInline(child_space, &line_builder); - // TODO(kojii): The wrapper fragment should not be needed. - NGFragmentBuilder wrapper_fragment_builder(NGPhysicalFragment::kFragmentBox, - inline_child); - line_builder.CreateFragments(&wrapper_fragment_builder); - RefPtr<NGLayoutResult> child_result = - wrapper_fragment_builder.ToBoxFragment(); + RefPtr<NGLayoutResult> child_result = line_builder.CreateFragments(); line_builder.CopyFragmentDataToLayoutBlockFlow(); FinishChildLayout(inline_child, child_space, child_result); }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h index 904777d..a14a042 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -47,8 +47,8 @@ NGConstraintSpace*, RefPtr<NGLayoutResult>); - // Layout inline children. - void LayoutInlineChildren(NGInlineNode*, NGConstraintSpace*); + // Layout inline child. + void LayoutInlineChild(NGInlineNode*, NGConstraintSpace*); // Final adjustments before fragment creation. We need to prevent the // fragment from crossing fragmentainer boundaries, and rather create a break
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc index a4ba2f3..3e7717d 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc
@@ -92,7 +92,10 @@ builder->SetIsSVGText(node->isSVGInlineText()); builder->Append(toLayoutText(node)->text(), node->style(), node); } else if (node->isFloating() || node->isOutOfFlowPositioned()) { - // Skip positioned objects. + // Add floats and positioned objects in the same way as atomic inlines. + // Because these objects need positions, they will be handled in + // NGLineBuilder. + builder->Append(objectReplacementCharacter, nullptr, node); } else if (!node->isInline()) { // TODO(kojii): Implement when inline has block children. } else { @@ -273,7 +276,7 @@ .SetTextDirection(BlockStyle()->direction()) .SetAvailableSize({LayoutUnit(), NGSizeIndefinite}) .ToConstraintSpace(writing_mode); - NGLineBuilder line_builder(this, constraint_space.get()); + NGLineBuilder line_builder(this, constraint_space.get(), nullptr); LayoutInline(constraint_space.get(), &line_builder); MinMaxContentSize sizes; sizes.min_content = line_builder.MaxInlineSize();
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc index 4a11633..99c6a75 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc
@@ -82,14 +82,12 @@ RefPtr<NGConstraintSpace> constraint_space = NGConstraintSpaceBuilder(kHorizontalTopBottom) .ToConstraintSpace(kHorizontalTopBottom); - NGLineBuilder line_builder(node, constraint_space.get()); + NGLineBuilder line_builder(node, constraint_space.get(), nullptr); NGTextLayoutAlgorithm algorithm(node, constraint_space.get()); algorithm.LayoutInline(&line_builder); - NGFragmentBuilder fragment_builder(NGPhysicalFragment::kFragmentBox, node); - line_builder.CreateFragments(&fragment_builder); - RefPtr<NGLayoutResult> result = fragment_builder.ToBoxFragment(); + RefPtr<NGLayoutResult> result = line_builder.CreateFragments(); for (const auto& child : toNGPhysicalBoxFragment(result->PhysicalFragment().get()) ->Children()) {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc index de7113fd..198796b 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc
@@ -20,9 +20,11 @@ namespace blink { NGLineBuilder::NGLineBuilder(NGInlineNode* inline_box, - NGConstraintSpace* constraint_space) + NGConstraintSpace* constraint_space, + NGFragmentBuilder* containing_block_builder) : inline_box_(inline_box), constraint_space_(constraint_space), + containing_block_builder_(containing_block_builder), baseline_type_(constraint_space->WritingMode() == NGWritingMode::kHorizontalTopBottom ? FontBaseline::AlphabeticBaseline @@ -214,11 +216,7 @@ LayoutUnit top, height; const ComputedStyle* style = item.Style(); - if (!style) { - // TODO(kojii): Implement atomic inline. - style = item.GetLayoutObject()->style(); - top = content_size_; - } else { + if (style) { // |InlineTextBoxPainter| sets the baseline at |top + // ascent-of-primary-font|. Compute |top| to match. InlineItemMetrics metrics(*style, baseline_type_); @@ -229,6 +227,25 @@ // Take all used fonts into account if 'line-height: normal'. if (style->lineHeight().isNegative()) AccumulateUsedFonts(item, line_item_chunk, &line_box_data); + } else { + LayoutObject* layout_object = item.GetLayoutObject(); + if (layout_object->isOutOfFlowPositioned()) { + if (containing_block_builder_) { + // Absolute positioning blockifies the box's display type. + // https://drafts.csswg.org/css-display/#transformations + containing_block_builder_->AddOutOfFlowChildCandidate( + new NGBlockNode(layout_object), + NGLogicalOffset(line_box_data.inline_size, content_size_)); + } + continue; + } else if (layout_object->isFloating()) { + // TODO(kojii): Implement float. + continue; + } + DCHECK(layout_object->isAtomicInlineLevel()); + // TODO(kojii): Implement atomic inline. + style = layout_object->style(); + top = content_size_; } // The direction of a fragment is the CSS direction to resolve logical @@ -337,21 +354,27 @@ current_opportunity_ = opportunity; } -void NGLineBuilder::CreateFragments(NGFragmentBuilder* container_builder) { +RefPtr<NGLayoutResult> NGLineBuilder::CreateFragments() { DCHECK(!HasItems()) << "Must call CreateLine()"; DCHECK_EQ(fragments_.size(), offsets_.size()); + NGFragmentBuilder container_builder(NGPhysicalFragment::kFragmentBox, + inline_box_); + for (unsigned i = 0; i < fragments_.size(); i++) { // TODO(layout-dev): This should really be a std::move but // CopyFragmentDataToLayoutBlockFlow also uses the fragments. - container_builder->AddChild(fragments_[i].get(), offsets_[i]); + container_builder.AddChild(fragments_[i].get(), offsets_[i]); } // TODO(kojii): Check if the line box width should be content or available. - container_builder->SetInlineSize(max_inline_size_) + // TODO(kojii): Need to take constraint_space into account. + container_builder.SetInlineSize(max_inline_size_) .SetInlineOverflow(max_inline_size_) .SetBlockSize(content_size_) .SetBlockOverflow(content_size_); + + return container_builder.ToBoxFragment(); } void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.h index 6dcb0ef..4e9fea39 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.h
@@ -31,7 +31,7 @@ STACK_ALLOCATED(); public: - NGLineBuilder(NGInlineNode*, NGConstraintSpace*); + NGLineBuilder(NGInlineNode*, NGConstraintSpace*, NGFragmentBuilder*); const NGConstraintSpace& ConstraintSpace() const { return *constraint_space_; @@ -81,7 +81,7 @@ void SetStartOfHangables(unsigned offset); // Create fragments for all lines created so far. - void CreateFragments(NGFragmentBuilder*); + RefPtr<NGLayoutResult> CreateFragments(); // Copy fragment data of all lines created by this NGLineBuilder to // LayoutBlockFlow. @@ -145,6 +145,7 @@ Persistent<NGInlineNode> inline_box_; NGConstraintSpace* constraint_space_; // Not owned as STACK_ALLOCATED. + NGFragmentBuilder* containing_block_builder_; Vector<RefPtr<NGPhysicalFragment>, 32> fragments_; Vector<NGLogicalOffset, 32> offsets_; Vector<LineBoxData, 32> line_box_data_list_;
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js index f2e18b8..10ca4c15 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/Main.js +++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -113,6 +113,7 @@ Runtime.experiments.register('timelineShowAllProcesses', 'Show all processes on Timeline', true); Runtime.experiments.register('timelinePaintTimingMarkers', 'Show paint timing markers on Timeline', true); Runtime.experiments.register('sourceDiff', 'Source diff'); + Runtime.experiments.register('timelineFlowEvents', 'Timeline flow events', true); Runtime.experiments.register('terminalInDrawer', 'Terminal in drawer', true); Runtime.experiments.register('timelineInvalidationTracking', 'Timeline invalidation tracking', true); Runtime.experiments.register('timelineMultipleMainViews', 'Tabbed views on Performance panel');
diff --git a/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js b/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js index 49249c4..7c1c6e9 100644 --- a/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js +++ b/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js
@@ -699,9 +699,11 @@ context.fillStyle = this._dataProvider.textColor(entryIndex); context.fillText(text, barX + textPadding, barY + textBaseHeight); } + context.restore(); this._drawGroupHeaders(width, height); + this._drawFlowEvents(context, width, height); this._drawMarkers(); var headerHeight = this._rulerEnabled ? PerfUI.FlameChart.HeaderHeight : 0; PerfUI.TimelineGrid.drawCanvasGrid(context, this._calculator, 3, headerHeight); @@ -940,6 +942,57 @@ } } + /** + * @param {!CanvasRenderingContext2D} context + * @param {number} height + * @param {number} width + */ + _drawFlowEvents(context, width, height) { + context.save(); + var ratio = window.devicePixelRatio; + var top = this.getScrollOffset(); + var arrowWidth = 6; + context.scale(ratio, ratio); + context.translate(0, -top); + + context.fillStyle = '#7f0000'; + context.strokeStyle = '#7f0000'; + var td = this._timelineData(); + var endIndex = td.flowStartTimes.lowerBound(this._timeWindowRight); + + context.lineWidth = 0.5; + for (var i = 0; i < endIndex; ++i) { + if (td.flowEndTimes[i] < this._timeWindowLeft) + continue; + var startX = this._timeToPosition(td.flowStartTimes[i]); + var endX = this._timeToPosition(td.flowEndTimes[i]); + var startY = this._levelToHeight(td.flowStartLevels[i]) + this._barHeight / 2; + var endY = this._levelToHeight(td.flowEndLevels[i]) + this._barHeight / 2; + var distance = (endY - startY) / 10; + var spread = 30; + var lineY = spread + Math.max(0, startY + distance * (i % spread)); + + var segment = Math.min((endX - startX) / 4, 40); + context.beginPath(); + context.moveTo(startX, startY); + context.bezierCurveTo(startX + segment, startY, startX + segment, lineY, startX + segment * 2, lineY); + context.lineTo(endX - segment * 2, lineY); + context.bezierCurveTo(endX - segment, lineY, endX - segment, endY, endX - arrowWidth, endY); + context.stroke(); + + context.beginPath(); + context.arc(startX, startY, 2, -Math.PI / 2, Math.PI / 2, false); + context.fill(); + + context.beginPath(); + context.moveTo(endX, endY); + context.lineTo(endX - arrowWidth, endY - 3); + context.lineTo(endX - arrowWidth, endY + 3); + context.fill(); + } + context.restore(); + } + _drawMarkers() { var markers = this._timelineData().markers; var left = this._markerIndexBeforeTime(this._calculator.minimumBoundary()); @@ -1265,6 +1318,10 @@ this.groups = groups; /** @type {!Array.<!PerfUI.FlameChartMarker>} */ this.markers = []; + this.flowStartTimes = []; + this.flowStartLevels = []; + this.flowEndTimes = []; + this.flowEndLevels = []; } };
diff --git a/third_party/WebKit/Source/devtools/front_end/text_editor/TextEditorAutocompleteController.js b/third_party/WebKit/Source/devtools/front_end/text_editor/TextEditorAutocompleteController.js index f0f76cf6..0364441a 100644 --- a/third_party/WebKit/Source/devtools/front_end/text_editor/TextEditorAutocompleteController.js +++ b/third_party/WebKit/Source/devtools/front_end/text_editor/TextEditorAutocompleteController.js
@@ -250,8 +250,10 @@ this._onSuggestionsShownForTest([]); return; } - if (!this._suggestBox) + if (!this._suggestBox) { this._suggestBox = new UI.SuggestBox(this, 20, this._config.captureEnter); + this._suggestBox.setDefaultSelectionIsDimmed(!!this._config.captureEnter); + } var oldQueryRange = this._queryRange; this._queryRange = queryRange;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js index dbfd06d..2b5862c 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js
@@ -50,6 +50,9 @@ ]; categoriesArray.push(TimelineModel.TimelineModel.Category.LatencyInfo); + if (Runtime.experiments.isEnabled('timelineFlowEvents')) + categoriesArray.push('devtools.timeline.async'); + if (Runtime.experiments.isEnabled('timelineV8RuntimeCallStats') && options.enableJSSampling) categoriesArray.push(disabledByDefault('v8.runtime_stats_sampling')); if (Runtime.experiments.isEnabled('timelineTracingJSProfile') && options.enableJSSampling) {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js index 356dd8e..e85439f 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
@@ -74,6 +74,9 @@ (Object.assign({useFirstLineForOverview: true}, defaultGroupStyle)); this._interactionsHeaderLevel2 = /** @type {!PerfUI.FlameChart.GroupStyle} */ (Object.assign({}, defaultGroupStyle, {padding: 2, nestingLevel: 1})); + + /** @type {!Map<string, number>} */ + this._flowEventIndexById = new Map(); } /** @@ -175,6 +178,8 @@ if (!this._model) return this._timelineData; + this._flowEventIndexById.clear(); + this._minimumBoundary = this._model.minimumRecordTime(); this._timeSpan = this._model.isEmpty() ? 1000 : this._model.maximumRecordTime() - this._minimumBoundary; this._currentLevel = 0; @@ -240,6 +245,7 @@ this._markers.sort(compareStartTime); this._timelineData.markers = this._markers; + this._flowEventIndexById.clear(); return this._timelineData; } @@ -296,6 +302,7 @@ _appendSyncEvents(events, title, style, entryType, forceExpanded) { var isExtension = entryType === Timeline.TimelineFlameChartEntryType.ExtensionEvent; var openEvents = []; + var flowEventsEnabled = Runtime.experiments.isEnabled('timelineFlowEvents'); var blackboxingEnabled = !isExtension && Runtime.experiments.isEnabled('blackboxJSFramesOnTimeline'); var maxStackDepth = 0; for (var i = 0; i < events.length; ++i) { @@ -328,6 +335,8 @@ } var level = this._currentLevel + openEvents.length; + if (flowEventsEnabled) + this._appendFlowEvent(e, level); this._appendEvent(e, level); if (!isExtension && TimelineModel.TimelineModel.isMarkerEvent(e)) this._timelineData.entryTotalTimes[this._entryData.length] = undefined; @@ -592,7 +601,7 @@ if (type === Timeline.TimelineFlameChartEntryType.InteractionRecord) { var color = Timeline.TimelineUIUtils.interactionPhaseColor( - /** @type {!TimelineModel.TimelineIRModel.Phases} */ (this._entryData[entryIndex])); + /** @type {!TimelineModel.TimelineIRModel.Phases} */ (data)); context.fillStyle = color; context.fillRect(barX, barY, barWidth - 1, 2); context.fillRect(barX, barY - 3, 2, 3); @@ -601,7 +610,7 @@ } if (type === Timeline.TimelineFlameChartEntryType.Event) { - var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); + var event = /** @type {!SDK.TracingModel.Event} */ (data); if (event.hasCategory(TimelineModel.TimelineModel.Category.LatencyInfo)) { var timeWaitingForMainThread = TimelineModel.TimelineData.forEvent(event).timeWaitingForMainThread; if (timeWaitingForMainThread) { @@ -643,10 +652,14 @@ */ forceDecoration(entryIndex) { var type = this._entryType(entryIndex); - return type === Timeline.TimelineFlameChartEntryType.Frame || - type === Timeline.TimelineFlameChartEntryType.Event && - !!TimelineModel.TimelineData.forEvent(/** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex])) - .warning; + if (type === Timeline.TimelineFlameChartEntryType.Frame) + return true; + + if (type === Timeline.TimelineFlameChartEntryType.Event) { + var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); + return !!TimelineModel.TimelineData.forEvent(event).warning; + } + return false; } /** @@ -721,6 +734,47 @@ } /** + * @param {!SDK.TracingModel.Event} event + * @param {number} level + */ + _appendFlowEvent(event, level) { + var timelineData = this._timelineData; + /** + * @param {!SDK.TracingModel.Event} event + * @return {number} + */ + function pushStartFlow(event) { + var flowIndex = timelineData.flowStartTimes.length; + timelineData.flowStartTimes.push(event.startTime); + timelineData.flowStartLevels.push(level); + return flowIndex; + } + + /** + * @param {!SDK.TracingModel.Event} event + * @param {number} flowIndex + */ + function pushEndFlow(event, flowIndex) { + timelineData.flowEndTimes[flowIndex] = event.startTime; + timelineData.flowEndLevels[flowIndex] = level; + } + + switch (event.phase) { + case SDK.TracingModel.Phase.FlowBegin: + this._flowEventIndexById.set(event.id, pushStartFlow(event)); + break; + case SDK.TracingModel.Phase.FlowStep: + pushEndFlow(event, this._flowEventIndexById.get(event.id)); + this._flowEventIndexById.set(event.id, pushStartFlow(event)); + break; + case SDK.TracingModel.Phase.FlowEnd: + pushEndFlow(event, this._flowEventIndexById.get(event.id)); + this._flowEventIndexById.delete(event.id); + break; + } + } + + /** * @param {!TimelineModel.TimelineFrame} frame */ _appendFrame(frame) {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js index 1dbcfe13..ff89a85 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -174,6 +174,9 @@ eventStyles[recordTypes.GCCollectGarbage] = new Timeline.TimelineRecordStyle(Common.UIString('DOM GC'), categories['scripting']); + eventStyles[recordTypes.AsyncTask] = + new Timeline.TimelineRecordStyle(Common.UIString('Async Task'), categories['async']); + Timeline.TimelineUIUtils._eventStylesMap = eventStyles; return eventStyles; } @@ -527,6 +530,10 @@ detailsText = Common.UIString('collect'); break; + case recordType.AsyncTask: + detailsText = eventData ? eventData['name'] : null; + break; + default: if (event.hasCategory(TimelineModel.TimelineModel.Category.Console)) detailsText = null; @@ -1473,6 +1480,8 @@ 'painting', Common.UIString('Painting'), true, 'hsl(109, 33%, 64%)', 'hsl(109, 33%, 55%)'), gpu: new Timeline.TimelineCategory( 'gpu', Common.UIString('GPU'), false, 'hsl(109, 33%, 64%)', 'hsl(109, 33%, 55%)'), + async: new Timeline.TimelineCategory( + 'async', Common.UIString('Async'), false, 'hsl(0, 100%, 50%)', 'hsl(0, 100%, 40%)'), other: new Timeline.TimelineCategory('other', Common.UIString('Other'), false, 'hsl(0, 0%, 87%)', 'hsl(0, 0%, 79%)'), idle: new Timeline.TimelineCategory('idle', Common.UIString('Idle'), false, 'hsl(0, 0%, 98%)', 'hsl(0, 0%, 98%)')
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js index 63ba41e5..d9e3925e 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js
@@ -1163,7 +1163,9 @@ // CpuProfile is a virtual event created on frontend to support // serialization of CPU Profiles within tracing timeline data. CpuProfile: 'CpuProfile', - Profile: 'Profile' + Profile: 'Profile', + + AsyncTask: 'AsyncTask', }; TimelineModel.TimelineModel.Category = {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/SuggestBox.js b/third_party/WebKit/Source/devtools/front_end/ui/SuggestBox.js index 592de32a..06d7a9c6 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/SuggestBox.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/SuggestBox.js
@@ -78,6 +78,21 @@ } /** + * @param {boolean} value + */ + setDefaultSelectionIsDimmed(value) { + this._element.classList.toggle('default-selection-is-dimmed', value); + } + + /** + * @param {boolean} value + */ + _setUserInteracted(value) { + this._userInteracted = value; + this._element.classList.toggle('user-has-interacted', value); + } + + /** * @return {boolean} */ visible() { @@ -137,7 +152,7 @@ hide() { if (!this.visible()) return; - this._userInteracted = false; + this._setUserInteracted(false); this._glassPane.hide(); } @@ -209,7 +224,7 @@ element.addEventListener('click', event => { this._list.selectItem(item); - this._userInteracted = true; + this._setUserInteracted(true); event.consume(true); this.acceptSuggestion(); }); @@ -335,7 +350,7 @@ return false; } if (selected) { - this._userInteracted = true; + this._setUserInteracted(true); return true; } return false;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/suggestBox.css b/third_party/WebKit/Source/devtools/front_end/ui/suggestBox.css index 816bc72..0a0ec31 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/suggestBox.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/suggestBox.css
@@ -90,6 +90,22 @@ } .suggest-box-content-item.selected > span { + color: #fff; +} + +.default-selection-is-dimmed .suggest-box-content-item.selected { + background-color: whitesmoke; +} + +.default-selection-is-dimmed .suggest-box-content-item.selected > span { + color: inherit; +} + +.user-has-interacted .suggest-box-content-item.selected { + background-color: rgb(56, 121, 217); +} + +.user-has-interacted .suggest-box-content-item.selected > span { color: #FFF; }
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index a894063..ba5ff4b 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -861,6 +861,8 @@ "graphics/WebGraphicsContext3DProviderWrapper.h", "graphics/compositing/PaintArtifactCompositor.cpp", "graphics/compositing/PaintArtifactCompositor.h", + "graphics/compositing/PaintChunksToCcLayer.cpp", + "graphics/compositing/PaintChunksToCcLayer.h", "graphics/compositing/PropertyTreeManager.cpp", "graphics/compositing/PropertyTreeManager.h", "graphics/cpu/arm/WebGLImageConversionNEON.h",
diff --git a/third_party/WebKit/Source/platform/ScriptForbiddenScope.h b/third_party/WebKit/Source/platform/ScriptForbiddenScope.h index b8ddadf..4aa19b5 100644 --- a/third_party/WebKit/Source/platform/ScriptForbiddenScope.h +++ b/third_party/WebKit/Source/platform/ScriptForbiddenScope.h
@@ -44,11 +44,15 @@ ++s_scriptForbiddenCount; } static void exit() { + DCHECK(isMainThread()); DCHECK(s_scriptForbiddenCount); --s_scriptForbiddenCount; } static bool isScriptForbidden() { - return isMainThread() && s_scriptForbiddenCount; + // Check s_scriptForbiddenCount first to avoid any calls to isMainThread() + // since under normal situations where we check this (ex. inside + // V8ScriptRunner) the value should always be zero. + return s_scriptForbiddenCount && isMainThread(); } private:
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp index b0927fb..a3588a3 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -19,6 +19,7 @@ #include "cc/trees/layer_tree_host.h" #include "platform/RuntimeEnabledFeatures.h" #include "platform/graphics/GraphicsContext.h" +#include "platform/graphics/compositing/PaintChunksToCcLayer.h" #include "platform/graphics/compositing/PropertyTreeManager.h" #include "platform/graphics/paint/ClipPaintPropertyNode.h" #include "platform/graphics/paint/DisplayItem.h" @@ -222,29 +223,7 @@ return json; } -namespace { - -static gfx::Rect largeRect(-200000, -200000, 400000, 400000); - -static void appendDisplayItemToCcDisplayItemList(const DisplayItem& displayItem, - cc::DisplayItemList* list) { - if (DisplayItem::isDrawingType(displayItem.getType())) { - const PaintRecord* record = - static_cast<const DrawingDisplayItem&>(displayItem).GetPaintRecord(); - if (!record) - return; - // In theory we would pass the bounds of the record, previously done as: - // gfx::Rect bounds = gfx::SkIRectToRect(record->cullRect().roundOut()); - // or use the visual rect directly. However, clip content layers attempt - // to raster in a different space than that of the visual rects. We'll be - // reworking visual rects further for SPv2, so for now we just pass a - // visual rect large enough to make sure items raster. - list->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>(largeRect, - sk_ref_sp(record)); - } -} - -scoped_refptr<cc::Layer> foreignLayerForPaintChunk( +static scoped_refptr<cc::Layer> foreignLayerForPaintChunk( const PaintArtifact& paintArtifact, const PaintChunk& paintChunk, gfx::Vector2dF& layerOffset) { @@ -266,210 +245,6 @@ return layer; } -enum EndDisplayItemType { EndTransform, EndClip, EndEffect }; - -// Applies the clips between |localState| and |ancestorState| into a single -// combined cc::FloatClipDisplayItem on |ccList|. -static void applyClipsBetweenStates(const PropertyTreeState& localState, - const PropertyTreeState& ancestorState, - cc::DisplayItemList& ccList, - Vector<EndDisplayItemType>& endDisplayItems, - GeometryMapper& geometryMapper) { - DCHECK(localState.transform() == ancestorState.transform()); -#if DCHECK_IS_ON() - const TransformPaintPropertyNode* transformNode = - localState.clip()->localTransformSpace(); - if (transformNode != ancestorState.transform()) { - const TransformationMatrix& localToAncestorMatrix = - geometryMapper.localToAncestorMatrix(transformNode, - ancestorState.transform()); - // Clips are only in descendant spaces that are transformed by one - // or more scrolls. - DCHECK(localToAncestorMatrix.isIdentityOrTranslation()); - } -#endif - - const FloatClipRect& combinedClip = - geometryMapper.localToAncestorClipRect(localState, ancestorState); - - ccList.CreateAndAppendPairedBeginItem<cc::FloatClipDisplayItem>( - gfx::RectF(combinedClip.rect())); - endDisplayItems.push_back(EndClip); -} - -static void recordPairedBeginDisplayItems( - const Vector<PropertyTreeState>& pairedStates, - const PropertyTreeState& pendingLayerState, - cc::DisplayItemList& ccList, - Vector<EndDisplayItemType>& endDisplayItems, - GeometryMapper& geometryMapper) { - PropertyTreeState mappedClipDestinationSpace = pendingLayerState; - PropertyTreeState clipSpace = pendingLayerState; - bool hasClip = false; - - for (Vector<PropertyTreeState>::const_reverse_iterator pairedState = - pairedStates.rbegin(); - pairedState != pairedStates.rend(); ++pairedState) { - switch (pairedState->innermostNode()) { - case PropertyTreeState::Transform: { - if (hasClip) { - applyClipsBetweenStates(clipSpace, mappedClipDestinationSpace, ccList, - endDisplayItems, geometryMapper); - hasClip = false; - } - mappedClipDestinationSpace = *pairedState; - clipSpace = *pairedState; - - TransformationMatrix matrix = pairedState->transform()->matrix(); - matrix.applyTransformOrigin(pairedState->transform()->origin()); - - gfx::Transform transform(gfx::Transform::kSkipInitialization); - transform.matrix() = TransformationMatrix::toSkMatrix44(matrix); - - ccList.CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>( - transform); - endDisplayItems.push_back(EndTransform); - break; - } - case PropertyTreeState::Clip: { - // Clips are handled in |applyClips| when ending the iterator, or - // transitioning between transform spaces. Here we store off the - // PropertyTreeState of the first found clip, under the transform of - // pairedState->transform(). All subsequent clips before applying the - // transform will be applied in applyClips. - clipSpace = *pairedState; - hasClip = true; -#if DCHECK_IS_ON() - if (pairedState->clip()->localTransformSpace() != - pairedState->transform()) { - const TransformationMatrix& localTransformMatrix = - pairedState->effect()->localTransformSpace()->matrix(); - // Clips are only in descendant spaces that are transformed by scroll. - DCHECK(localTransformMatrix.isIdentityOrTranslation()); - } -#endif - break; - } - case PropertyTreeState::Effect: { - // TODO(chrishtr): skip effect and/or compositing display items if - // not necessary. - - FloatRect clipRect = - pairedState->effect()->outputClip()->clipRect().rect(); - // TODO(chrishtr): specify origin of the filter. - FloatPoint filterOrigin; - if (pairedState->effect()->localTransformSpace() != - pairedState->transform()) { - const TransformPaintPropertyNode* transformNode = - pairedState->effect()->localTransformSpace(); - const TransformationMatrix& localToAncestorMatrix = - geometryMapper.localToAncestorMatrix(transformNode, - pairedState->transform()); - // Effects are only in descendant spaces that are transformed by one - // or more scrolls. - DCHECK(localToAncestorMatrix.isIdentityOrTranslation()); - - clipRect = localToAncestorMatrix.mapRect(clipRect); - filterOrigin = localToAncestorMatrix.mapPoint(filterOrigin); - } - - const bool kLcdTextRequiresOpaqueLayer = true; - ccList.CreateAndAppendPairedBeginItem<cc::CompositingDisplayItem>( - static_cast<uint8_t>( - gfx::ToFlooredInt(255 * pairedState->effect()->opacity())), - pairedState->effect()->blendMode(), - // TODO(chrishtr): compute bounds as necessary. - nullptr, GraphicsContext::WebCoreColorFilterToSkiaColorFilter( - pairedState->effect()->colorFilter()), - kLcdTextRequiresOpaqueLayer); - - ccList.CreateAndAppendPairedBeginItem<cc::FilterDisplayItem>( - pairedState->effect()->filter().asCcFilterOperations(), clipRect, - gfx::PointF(filterOrigin.x(), filterOrigin.y())); - - endDisplayItems.push_back(EndEffect); - break; - } - case PropertyTreeState::None: - break; - } - } - - if (hasClip) { - applyClipsBetweenStates(clipSpace, mappedClipDestinationSpace, ccList, - endDisplayItems, geometryMapper); - } -} - -static void recordPairedEndDisplayItems( - const Vector<EndDisplayItemType>& endDisplayItemTypes, - cc::DisplayItemList* ccList) { - for (Vector<EndDisplayItemType>::const_reverse_iterator endType = - endDisplayItemTypes.rbegin(); - endType != endDisplayItemTypes.rend(); ++endType) { - switch (*endType) { - case EndTransform: - ccList->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); - break; - case EndClip: - ccList->CreateAndAppendPairedEndItem<cc::EndFloatClipDisplayItem>(); - break; - case EndEffect: - ccList->CreateAndAppendPairedEndItem<cc::EndFilterDisplayItem>(); - ccList->CreateAndAppendPairedEndItem<cc::EndCompositingDisplayItem>(); - break; - } - } -} - -} // namespace - -scoped_refptr<cc::DisplayItemList> PaintArtifactCompositor::recordPendingLayer( - const PaintArtifact& artifact, - const PendingLayer& pendingLayer, - const gfx::Rect& combinedBounds, - GeometryMapper& geometryMapper) { - auto ccList = make_scoped_refptr(new cc::DisplayItemList); - - gfx::Transform translation; - translation.Translate(-combinedBounds.x(), -combinedBounds.y()); - // Passing combinedBounds as the visual rect for the begin/end transform item - // would normally be the sensible thing to do, but see comment above re: - // visual rects for drawing items and further rework in flight. - ccList->CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>(translation); - - const DisplayItemList& displayItems = artifact.getDisplayItemList(); - for (const auto& paintChunk : pendingLayer.paintChunks) { - const PropertyTreeState* state = &paintChunk->properties.propertyTreeState; - PropertyTreeStateIterator iterator(*state); - Vector<PropertyTreeState> pairedStates; - for (; state && *state != pendingLayer.propertyTreeState; - state = iterator.next()) { - if (state->innermostNode() != PropertyTreeState::None) - pairedStates.push_back(*state); - } - - // TODO(chrishtr): we can avoid some extra paired display items if - // multiple PaintChunks share them. We can also collapse clips between - // transforms into single clips in the same way that PaintLayerClipper does. - Vector<EndDisplayItemType> endDisplayItems; - - recordPairedBeginDisplayItems(pairedStates, pendingLayer.propertyTreeState, - *ccList.get(), endDisplayItems, - geometryMapper); - - for (const auto& displayItem : displayItems.itemsInPaintChunk(*paintChunk)) - appendDisplayItemToCcDisplayItemList(displayItem, ccList.get()); - - recordPairedEndDisplayItems(endDisplayItems, ccList.get()); - } - - ccList->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); - - ccList->Finalize(); - return ccList; -} - std::unique_ptr<PaintArtifactCompositor::ContentLayerClientImpl> PaintArtifactCompositor::clientForPaintChunk( const PaintChunk& paintChunk, @@ -514,13 +289,14 @@ gfx::Rect ccCombinedBounds(enclosingIntRect(pendingLayer.bounds)); - scoped_refptr<cc::DisplayItemList> displayList = recordPendingLayer( - paintArtifact, pendingLayer, ccCombinedBounds, geometryMapper); + layerOffset = ccCombinedBounds.OffsetFromOrigin(); + scoped_refptr<cc::DisplayItemList> displayList = + PaintChunksToCcLayer::convert( + pendingLayer.paintChunks, pendingLayer.propertyTreeState, layerOffset, + paintArtifact.getDisplayItemList(), geometryMapper); contentLayerClient->SetDisplayList(std::move(displayList)); contentLayerClient->SetPaintableRegion(gfx::Rect(ccCombinedBounds.size())); - layerOffset = ccCombinedBounds.OffsetFromOrigin(); - scoped_refptr<cc::PictureLayer> ccPictureLayer = contentLayerClient->ccPictureLayer(); ccPictureLayer->SetBounds(ccCombinedBounds.size());
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h index 50aed96..c5464c8 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h
@@ -16,7 +16,6 @@ #include <memory> namespace cc { -class DisplayItemList; class Layer; } @@ -135,13 +134,6 @@ const PaintChunk&, const PaintArtifact&); - // This method is an implementation of Algorithm step 4 from goo.gl/6xP8Oe. - static scoped_refptr<cc::DisplayItemList> recordPendingLayer( - const PaintArtifact&, - const PendingLayer&, - const gfx::Rect& combinedBounds, - GeometryMapper&); - static bool canMergeInto(const PaintArtifact&, const PaintChunk& newChunk, const PendingLayer& candidatePendingLayer);
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp new file mode 100644 index 0000000..0abb746 --- /dev/null +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
@@ -0,0 +1,244 @@ +// 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 "platform/graphics/compositing/PaintChunksToCcLayer.h" + +#include "cc/playback/compositing_display_item.h" +#include "cc/playback/display_item_list.h" +#include "cc/playback/drawing_display_item.h" +#include "cc/playback/filter_display_item.h" +#include "cc/playback/float_clip_display_item.h" +#include "cc/playback/transform_display_item.h" +#include "platform/graphics/GraphicsContext.h" +#include "platform/graphics/paint/DisplayItemList.h" +#include "platform/graphics/paint/DrawingDisplayItem.h" +#include "platform/graphics/paint/GeometryMapper.h" +#include "platform/graphics/paint/PaintChunk.h" +#include "platform/graphics/paint/PropertyTreeState.h" + +namespace blink { + +namespace { + +enum EndDisplayItemType { EndTransform, EndClip, EndEffect }; + +// Applies the clips between |localState| and |ancestorState| into a single +// combined cc::FloatClipDisplayItem on |ccList|. +static void applyClipsBetweenStates(const PropertyTreeState& localState, + const PropertyTreeState& ancestorState, + cc::DisplayItemList& ccList, + Vector<EndDisplayItemType>& endDisplayItems, + GeometryMapper& geometryMapper) { + DCHECK(localState.transform() == ancestorState.transform()); +#if DCHECK_IS_ON() + const TransformPaintPropertyNode* transformNode = + localState.clip()->localTransformSpace(); + if (transformNode != ancestorState.transform()) { + const TransformationMatrix& localToAncestorMatrix = + geometryMapper.localToAncestorMatrix(transformNode, + ancestorState.transform()); + // Clips are only in descendant spaces that are transformed by one + // or more scrolls. + DCHECK(localToAncestorMatrix.isIdentityOrTranslation()); + } +#endif + + const FloatClipRect& combinedClip = + geometryMapper.localToAncestorClipRect(localState, ancestorState); + + ccList.CreateAndAppendPairedBeginItem<cc::FloatClipDisplayItem>( + gfx::RectF(combinedClip.rect())); + endDisplayItems.push_back(EndClip); +} + +static void recordPairedBeginDisplayItems( + const Vector<PropertyTreeState>& pairedStates, + const PropertyTreeState& pendingLayerState, + cc::DisplayItemList& ccList, + Vector<EndDisplayItemType>& endDisplayItems, + GeometryMapper& geometryMapper) { + PropertyTreeState mappedClipDestinationSpace = pendingLayerState; + PropertyTreeState clipSpace = pendingLayerState; + bool hasClip = false; + + for (Vector<PropertyTreeState>::const_reverse_iterator pairedState = + pairedStates.rbegin(); + pairedState != pairedStates.rend(); ++pairedState) { + switch (pairedState->innermostNode()) { + case PropertyTreeState::Transform: { + if (hasClip) { + applyClipsBetweenStates(clipSpace, mappedClipDestinationSpace, ccList, + endDisplayItems, geometryMapper); + hasClip = false; + } + mappedClipDestinationSpace = *pairedState; + clipSpace = *pairedState; + + TransformationMatrix matrix = pairedState->transform()->matrix(); + matrix.applyTransformOrigin(pairedState->transform()->origin()); + + gfx::Transform transform(gfx::Transform::kSkipInitialization); + transform.matrix() = TransformationMatrix::toSkMatrix44(matrix); + + ccList.CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>( + transform); + endDisplayItems.push_back(EndTransform); + break; + } + case PropertyTreeState::Clip: { + // Clips are handled in |applyClips| when ending the iterator, or + // transitioning between transform spaces. Here we store off the + // PropertyTreeState of the first found clip, under the transform of + // pairedState->transform(). All subsequent clips before applying the + // transform will be applied in applyClips. + clipSpace = *pairedState; + hasClip = true; +#if DCHECK_IS_ON() + if (pairedState->clip()->localTransformSpace() != + pairedState->transform()) { + const TransformationMatrix& localTransformMatrix = + pairedState->effect()->localTransformSpace()->matrix(); + // Clips are only in descendant spaces that are transformed by scroll. + DCHECK(localTransformMatrix.isIdentityOrTranslation()); + } +#endif + break; + } + case PropertyTreeState::Effect: { + // TODO(chrishtr): skip effect and/or compositing display items if + // not necessary. + + FloatRect clipRect = + pairedState->effect()->outputClip()->clipRect().rect(); + // TODO(chrishtr): specify origin of the filter. + FloatPoint filterOrigin; + if (pairedState->effect()->localTransformSpace() != + pairedState->transform()) { + const TransformPaintPropertyNode* transformNode = + pairedState->effect()->localTransformSpace(); + const TransformationMatrix& localToAncestorMatrix = + geometryMapper.localToAncestorMatrix(transformNode, + pairedState->transform()); + // Effects are only in descendant spaces that are transformed by one + // or more scrolls. + DCHECK(localToAncestorMatrix.isIdentityOrTranslation()); + + clipRect = localToAncestorMatrix.mapRect(clipRect); + filterOrigin = localToAncestorMatrix.mapPoint(filterOrigin); + } + + const bool kLcdTextRequiresOpaqueLayer = true; + ccList.CreateAndAppendPairedBeginItem<cc::CompositingDisplayItem>( + static_cast<uint8_t>( + gfx::ToFlooredInt(255 * pairedState->effect()->opacity())), + pairedState->effect()->blendMode(), + // TODO(chrishtr): compute bounds as necessary. + nullptr, + GraphicsContext::WebCoreColorFilterToSkiaColorFilter( + pairedState->effect()->colorFilter()), + kLcdTextRequiresOpaqueLayer); + + ccList.CreateAndAppendPairedBeginItem<cc::FilterDisplayItem>( + pairedState->effect()->filter().asCcFilterOperations(), clipRect, + gfx::PointF(filterOrigin.x(), filterOrigin.y())); + + endDisplayItems.push_back(EndEffect); + break; + } + case PropertyTreeState::None: + break; + } + } + + if (hasClip) { + applyClipsBetweenStates(clipSpace, mappedClipDestinationSpace, ccList, + endDisplayItems, geometryMapper); + } +} + +static void recordPairedEndDisplayItems( + const Vector<EndDisplayItemType>& endDisplayItemTypes, + cc::DisplayItemList* ccList) { + for (Vector<EndDisplayItemType>::const_reverse_iterator endType = + endDisplayItemTypes.rbegin(); + endType != endDisplayItemTypes.rend(); ++endType) { + switch (*endType) { + case EndTransform: + ccList->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); + break; + case EndClip: + ccList->CreateAndAppendPairedEndItem<cc::EndFloatClipDisplayItem>(); + break; + case EndEffect: + ccList->CreateAndAppendPairedEndItem<cc::EndFilterDisplayItem>(); + ccList->CreateAndAppendPairedEndItem<cc::EndCompositingDisplayItem>(); + break; + } + } +} + +static gfx::Rect largeRect(-200000, -200000, 400000, 400000); +static void appendDisplayItemToCcDisplayItemList(const DisplayItem& displayItem, + cc::DisplayItemList* list) { + if (DisplayItem::isDrawingType(displayItem.getType())) { + const PaintRecord* record = + static_cast<const DrawingDisplayItem&>(displayItem).GetPaintRecord(); + if (!record) + return; + // In theory we would pass the bounds of the record, previously done as: + // gfx::Rect bounds = gfx::SkIRectToRect(record->cullRect().roundOut()); + // or use the visual rect directly. However, clip content layers attempt + // to raster in a different space than that of the visual rects. We'll be + // reworking visual rects further for SPv2, so for now we just pass a + // visual rect large enough to make sure items raster. + list->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>(largeRect, + sk_ref_sp(record)); + } +} + +} // unnamed namespace + +scoped_refptr<cc::DisplayItemList> PaintChunksToCcLayer::convert( + const Vector<const PaintChunk*>& paintChunks, + const PropertyTreeState& layerState, + const gfx::Vector2dF& layerOffset, + const DisplayItemList& displayItems, + GeometryMapper& geometryMapper) { + auto ccList = make_scoped_refptr(new cc::DisplayItemList); + + gfx::Transform counterOffset; + counterOffset.Translate(-layerOffset.x(), -layerOffset.y()); + ccList->CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>( + counterOffset); + + for (const auto& paintChunk : paintChunks) { + const PropertyTreeState* state = &paintChunk->properties.propertyTreeState; + PropertyTreeStateIterator iterator(*state); + Vector<PropertyTreeState> pairedStates; + for (; state && *state != layerState; state = iterator.next()) { + if (state->innermostNode() != PropertyTreeState::None) + pairedStates.push_back(*state); + } + + // TODO(chrishtr): we can avoid some extra paired display items if + // multiple PaintChunks share them. We can also collapse clips between + // transforms into single clips in the same way that PaintLayerClipper does. + Vector<EndDisplayItemType> endDisplayItems; + + recordPairedBeginDisplayItems(pairedStates, layerState, *ccList.get(), + endDisplayItems, geometryMapper); + + for (const auto& displayItem : displayItems.itemsInPaintChunk(*paintChunk)) + appendDisplayItemToCcDisplayItemList(displayItem, ccList.get()); + + recordPairedEndDisplayItems(endDisplayItems, ccList.get()); + } + + ccList->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); + + ccList->Finalize(); + return ccList; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h new file mode 100644 index 0000000..3c9a095 --- /dev/null +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h
@@ -0,0 +1,39 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PaintChunksToCcLayer_h +#define PaintChunksToCcLayer_h + +#include "base/memory/ref_counted.h" +#include "platform/PlatformExport.h" +#include "wtf/Vector.h" + +namespace cc { +class DisplayItemList; +} // namespace cc + +namespace gfx { +class Vector2dF; +} // namespace gfx + +namespace blink { + +class DisplayItemList; +class GeometryMapper; +struct PaintChunk; +class PropertyTreeState; + +class PLATFORM_EXPORT PaintChunksToCcLayer { + public: + static scoped_refptr<cc::DisplayItemList> convert( + const Vector<const PaintChunk*>&, + const PropertyTreeState& layerState, + const gfx::Vector2dF& layerOffset, + const DisplayItemList&, + GeometryMapper&); +}; + +} // namespace blink + +#endif // PaintArtifactCompositor_h
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp index 6258d642..55f018c 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp
@@ -373,6 +373,14 @@ it++) { TransformationMatrix localTransformMatrix = (*it)->matrix(); localTransformMatrix.applyTransformOrigin((*it)->origin()); + + // Flattening Lemma: flatten(A * flatten(B)) = flatten(flatten(A) * B). + // goo.gl/DNKyOc. Thus we can flatten transformMatrix rather than + // localTransformMatrix, because GeometryMapper only supports transforms + // into a flattened destination space. + if ((*it)->flattensInheritedTransform()) + transformMatrix.flattenTo2d(); + transformMatrix = transformMatrix * localTransformMatrix; (*it)->getTransformCache().setCachedTransform(ancestorTransformNode, transformMatrix);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.h b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.h index c5a8ec36..0b414c5e 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.h +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.h
@@ -113,6 +113,10 @@ // Returns the matrix used in |LocalToAncestorRect|. DCHECK fails iff // |localTransformNode| is not equal to or a descendant of // |ancestorTransformNode|. + // This matrix may not be flattened. Since GeometryMapper only supports + // flattened ancestor spaces, the returned matrix must be flattened to have + // the correct semantics (calling mapRect() on it implicitly applies + // flattening to the input; flattenTo2d() does it explicitly to tme matrix). const TransformationMatrix& localToAncestorMatrix( const TransformPaintPropertyNode* localTransformNode, const TransformPaintPropertyNode* ancestorTransformNode);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp index 7c44f7b1..cdda820d 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp
@@ -276,6 +276,32 @@ *getTransform(transform1.get(), rootPropertyTreeState().transform())); } +TEST_F(GeometryMapperTest, NestedTransformsFlattening) { + TransformationMatrix rotateTransform; + rotateTransform.rotate3d(45, 0, 0); + RefPtr<TransformPaintPropertyNode> transform1 = + TransformPaintPropertyNode::create(rootPropertyTreeState().transform(), + rotateTransform, FloatPoint3D()); + + TransformationMatrix inverseRotateTransform; + inverseRotateTransform.rotate3d(-45, 0, 0); + RefPtr<TransformPaintPropertyNode> transform2 = + TransformPaintPropertyNode::create(transform1, inverseRotateTransform, + FloatPoint3D(), + true); // Flattens + + PropertyTreeState localState = rootPropertyTreeState(); + localState.setTransform(transform2.get()); + + FloatRect input(0, 0, 100, 100); + rotateTransform.flattenTo2d(); + TransformationMatrix final = rotateTransform * inverseRotateTransform; + FloatRect output = final.mapRect(input); + bool hasRadius = false; + CHECK_MAPPINGS(input, output, output, final, FloatClipRect(), localState, + rootPropertyTreeState(), hasRadius); +} + TEST_F(GeometryMapperTest, NestedTransformsScaleAndTranslation) { TransformationMatrix scaleTransform; scaleTransform.scale(2); @@ -819,11 +845,11 @@ EXPECT_EQ(FloatRect(-150, -150, 450, 450), output); bool hasRadius = false; - CHECK_MAPPINGS( - input, output, FloatRect(0, 0, 300, 300), - transformAboveEffect->matrix() * transformBelowEffect->matrix(), - FloatClipRect(FloatRect(30, 30, 270, 270)), localState, - rootPropertyTreeState(), hasRadius); + TransformationMatrix combinedTransform = + transformAboveEffect->matrix() * transformBelowEffect->matrix(); + CHECK_MAPPINGS(input, output, FloatRect(0, 0, 300, 300), combinedTransform, + FloatClipRect(FloatRect(30, 30, 270, 270)), localState, + rootPropertyTreeState(), hasRadius); } TEST_F(GeometryMapperTest, ReflectionWithPaintOffset) {
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTransformCache.h b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTransformCache.h index 9d08f72..7b82beca 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTransformCache.h +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTransformCache.h
@@ -24,6 +24,8 @@ // Returns the transformed rect (see GeometryMapper.h) of |this| in the // space of |ancestorTransform|, if there is one cached. Otherwise returns // null. + // + // These transforms are not flattened to 2d. const TransformationMatrix* getCachedTransform( const TransformPaintPropertyNode* ancestorTransform);
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index aedcb02..0ed10fe 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -8994,11 +8994,29 @@ <description>The user entered fullscreen mode from the controls.</description> </action> +<action name="Media.Controls.EnterFullscreen.EmbeddedExperience"> + <owner>shaktisahu@chromium.org</owner> + <description> + The user has entered fullscreen mode from the controls. Recorded only for + downloaded media on Android and is a subset of + Media.Controls.EnterFullscreen. + </description> +</action> + <action name="Media.Controls.ExitFullscreen"> <owner>mlamouri@chromium.org</owner> <description>The user left fullscreen mode from the controls.</description> </action> +<action name="Media.Controls.ExitFullscreen.EmbeddedExperience"> + <owner>shaktisahu@chromium.org</owner> + <description> + The user has left fullscreen mode from the controls. Recorded only for + downloaded media on Android and is a subset of + Media.Controls.ExitFullscreen. + </description> +</action> + <action name="Media.Controls.Mute"> <owner>mlamouri@chromium.org</owner> <description>The user muted a media element from the controls.</description>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index a6958aa8..35bf3ee 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -117404,6 +117404,9 @@ label="Watch time for SRC media with only an audio track."/> <suffix name="Audio.EME" label="Watch time for EME media with only an audio track."/> + <suffix name="Audio.EmbeddedExperience." + label="Watch time for downloaded media on Android with only an audio + track."/> <suffix name="AudioVideo.All" label="Watch time for all media with both an audio and video track."/> <suffix name="AudioVideo.AC" @@ -117418,6 +117421,9 @@ label="Watch time for SRC media with both an audio and video track."/> <suffix name="AudioVideo.EME" label="Watch time for EME media with both an audio and video track."/> + <suffix name="AudioVideo.EmbeddedExperience." + label="Watch time for downloaded media on Android with both an audio + and video track."/> <affected-histogram name="Media.WatchTime"/> </histogram_suffixes>
diff --git a/tools/vim/PRESUBMIT.py b/tools/vim/PRESUBMIT.py index 33cdd6d..1cd25f9 100644 --- a/tools/vim/PRESUBMIT.py +++ b/tools/vim/PRESUBMIT.py
@@ -1,12 +1,12 @@ # Copyright 2015 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """Presubmit tests for /tools/vim. Runs Python unit tests in /tools/vim/tests on upload. """ + def CheckChangeOnUpload(input_api, output_api): results = [] @@ -14,7 +14,8 @@ # relative to the directory containing PRESUBMIT.py. affected_files = [ input_api.os_path.relpath(f, input_api.PresubmitLocalPath()) - for f in input_api.AbsoluteLocalPaths()] + for f in input_api.AbsoluteLocalPaths() + ] # Run the chromium.ycm_extra_conf_unittest test if the YCM config file is # changed or if any change is affecting the tests directory. This specific @@ -24,8 +25,8 @@ 'ninja_output.py' in affected_files or \ any([input_api.re.match(r'tests(/|\\)',f) for f in affected_files]): results += input_api.RunTests( - input_api.canned_checks.GetUnitTests( - input_api, output_api, - ['tests/chromium.ycm_extra_conf_unittest.py'])) + input_api.canned_checks.GetUnitTests(input_api, output_api, [ + 'tests/chromium.ycm_extra_conf_unittest.py' + ])) return results
diff --git a/tools/vim/chromium.ycm_extra_conf.py b/tools/vim/chromium.ycm_extra_conf.py index 9456394..2669573 100644 --- a/tools/vim/chromium.ycm_extra_conf.py +++ b/tools/vim/chromium.ycm_extra_conf.py
@@ -47,7 +47,6 @@ # # * This has only been tested on gPrecise. - import os import os.path import re @@ -57,19 +56,20 @@ # Flags from YCM's default config. _default_flags = [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', - 'c++', + '-DUSE_CLANG_COMPLETER', + '-std=c++11', + '-x', + 'c++', ] _header_alternates = ('.cc', '.cpp', '.c', '.mm', '.m') _extension_flags = { - '.m': ['-x', 'objective-c'], - '.mm': ['-x', 'objective-c++'], + '.m': ['-x', 'objective-c'], + '.mm': ['-x', 'objective-c++'], } + def PathExists(*args): return os.path.exists(os.path.join(*args)) @@ -86,10 +86,9 @@ (String) Path of 'src/', or None if unable to find. """ curdir = os.path.normpath(os.path.dirname(filename)) - while not (os.path.basename(curdir) == 'src' - and PathExists(curdir, 'DEPS') - and (PathExists(curdir, '..', '.gclient') - or PathExists(curdir, '.git'))): + while not ( + os.path.basename(curdir) == 'src' and PathExists(curdir, 'DEPS') and + (PathExists(curdir, '..', '.gclient') or PathExists(curdir, '.git'))): nextdir = os.path.normpath(os.path.join(curdir, '..')) if nextdir == curdir: return None @@ -138,9 +137,11 @@ # directory. rel_filename = os.path.relpath(filename, out_dir) - p = subprocess.Popen(['ninja', '-C', out_dir, '-t', 'query', rel_filename], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - universal_newlines=True) + p = subprocess.Popen( + ['ninja', '-C', out_dir, '-t', 'query', rel_filename], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True) stdout, _ = p.communicate() if p.returncode != 0: return [] @@ -154,8 +155,10 @@ # outputs_text = stdout.partition('\n outputs:\n')[2] output_lines = [line.strip() for line in outputs_text.split('\n')] - return [target for target in output_lines - if target and (target.endswith('.o') or target.endswith('.obj'))] + return [ + target for target in output_lines + if target and (target.endswith('.o') or target.endswith('.obj')) + ] def GetClangCommandLineForNinjaOutput(out_dir, build_target): @@ -172,9 +175,10 @@ (String or None) Clang command line or None if a Clang command line couldn't be determined. """ - p = subprocess.Popen(['ninja', '-v', '-C', out_dir, - '-t', 'commands', build_target], - stdout=subprocess.PIPE, universal_newlines=True) + p = subprocess.Popen( + ['ninja', '-v', '-C', out_dir, '-t', 'commands', build_target], + stdout=subprocess.PIPE, + universal_newlines=True) stdout, stderr = p.communicate() if p.returncode != 0: return None @@ -319,8 +323,10 @@ # If ninja didn't know about filename or it's companion files, then try a # default build target. It is possible that the file is new, or build.ninja # is stale. - clang_line = GetClangCommandLineFromNinjaForSource( - out_dir, GetDefaultSourceFile(chrome_root, filename)) + clang_line = GetClangCommandLineFromNinjaForSource(out_dir, + GetDefaultSourceFile( + chrome_root, + filename)) if not clang_line: return additional_flags @@ -350,7 +356,4 @@ final_flags = _default_flags + clang_flags - return { - 'flags': final_flags, - 'do_cache': should_cache_flags_for_file - } + return {'flags': final_flags, 'do_cache': should_cache_flags_for_file}
diff --git a/tools/vim/ninja_output.py b/tools/vim/ninja_output.py index f959dc2..6695fcfa 100644 --- a/tools/vim/ninja_output.py +++ b/tools/vim/ninja_output.py
@@ -2,7 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - import sys import os import itertools @@ -13,6 +12,7 @@ except ImportError: pass + def GetNinjaOutputDirectory(chrome_root): """Returns <chrome_root>/<output_dir>/(Release|Debug|<other>). @@ -65,8 +65,8 @@ try: return max(generate_paths(), key=approx_directory_mtime) except ValueError: - raise RuntimeError( - 'Unable to find a valid ninja output directory.') + raise RuntimeError('Unable to find a valid ninja output directory.') + if __name__ == '__main__': if len(sys.argv) != 2:
diff --git a/tools/vim/tests/chromium.ycm_extra_conf_unittest.py b/tools/vim/tests/chromium.ycm_extra_conf_unittest.py index 3443fa3..5ed29e91 100755 --- a/tools/vim/tests/chromium.ycm_extra_conf_unittest.py +++ b/tools/vim/tests/chromium.ycm_extra_conf_unittest.py
@@ -3,7 +3,6 @@ # Copyright 2015 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - """Tests for chromium.ycm_extra_conf. These tests should be getting picked up by the PRESUBMIT.py in /tools/vim. @@ -21,10 +20,8 @@ import tempfile import unittest -def CreateFile(path, - copy_from = None, - format_with = None, - make_executable = False): + +def CreateFile(path, copy_from=None, format_with=None, make_executable=False): """Creates a file. If a file already exists at |path|, it will be overwritten. @@ -53,21 +50,26 @@ statinfo = os.stat(path) os.chmod(path, statinfo.st_mode | stat.S_IXUSR) + def GetLastLangFlag(flags): lastLang = None for i, flag in enumerate(flags): - if flag =='-x': - lastLang = flags[i+1] + if flag == '-x': + lastLang = flags[i + 1] return lastLang + def TestLanguage(test_file, language): + def test(self): result = self.ycm_extra_conf.FlagsForFile( os.path.join(self.chrome_root, test_file)) self.assertTrue(result) self.assertEqual(GetLastLangFlag(result['flags']), language) + return test + class Chromium_ycmExtraConfTest(unittest.TestCase): def SetUpFakeChromeTreeBelowPath(self): @@ -89,8 +91,8 @@ +-- gn build.ninja """ - self.chrome_root = os.path.abspath(os.path.normpath( - os.path.join(self.test_root, 'src'))) + self.chrome_root = os.path.abspath( + os.path.normpath(os.path.join(self.test_root, 'src'))) self.out_dir = os.path.join(self.chrome_root, 'out', 'gn') os.makedirs(self.chrome_root) @@ -104,9 +106,9 @@ # Fake ninja build file. Applications of 'cxx' rule are tagged by which # source file was used as input so that the test can verify that the correct # build dependency was used. - CreateFile(os.path.join(self.out_dir, 'build.ninja'), - copy_from=os.path.join(self.test_data_path, - 'fake_build_ninja.txt')) + CreateFile( + os.path.join(self.out_dir, 'build.ninja'), + copy_from=os.path.join(self.test_data_path, 'fake_build_ninja.txt')) def NormalizeString(self, string): return string.replace(self.out_dir, '[OUT]').\ @@ -147,8 +149,8 @@ def testCommandLineForKnownCppFile(self): command_line = self.ycm_extra_conf.GetClangCommandLineFromNinjaForSource( self.out_dir, os.path.join(self.chrome_root, 'one.cpp')) - self.assertEquals( - command_line, ('../../fake-clang++ -Ia -isysroot /mac.sdk -Itag-one ' + self.assertEquals(command_line, + ('../../fake-clang++ -Ia -isysroot /mac.sdk -Itag-one ' '../../one.cpp -o obj/one.o')) def testCommandLineForUnknownCppFile(self): @@ -160,28 +162,24 @@ clang_options = \ self.ycm_extra_conf.GetClangOptionsFromNinjaForFilename( self.chrome_root, os.path.join(self.chrome_root, 'one.cpp')) - self.assertEquals(self.NormalizeStringsInList(clang_options), [ - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-one' + self.assertEquals( + self.NormalizeStringsInList(clang_options), [ + '-I[SRC]', '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', + '/mac.sdk', '-I[OUT]/tag-one' ]) def testOutDirNames(self): out_root = os.path.join(self.chrome_root, 'out_with_underscore') out_dir = os.path.join(out_root, 'gn') - shutil.move(os.path.join(self.chrome_root, 'out'), - out_root) + shutil.move(os.path.join(self.chrome_root, 'out'), out_root) clang_options = \ self.ycm_extra_conf.GetClangOptionsFromNinjaForFilename( self.chrome_root, os.path.join(self.chrome_root, 'one.cpp')) self.assertIn('-I%s/a' % self.NormalizeString(out_dir), - self.NormalizeStringsInList(clang_options)) + self.NormalizeStringsInList(clang_options)) self.assertIn('-I%s/tag-one' % self.NormalizeString(out_dir), - self.NormalizeStringsInList(clang_options)) + self.NormalizeStringsInList(clang_options)) def testGetFlagsForFileForKnownCppFile(self): result = self.ycm_extra_conf.FlagsForFile( @@ -190,16 +188,11 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-one' + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', '-std=c++11', '-x', 'c++', '-I[SRC]', + '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', '/mac.sdk', + '-I[OUT]/tag-one' ]) def testGetFlagsForFileForUnknownCppFile(self): @@ -209,16 +202,11 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-default' + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', '-std=c++11', '-x', 'c++', '-I[SRC]', + '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', '/mac.sdk', + '-I[OUT]/tag-default' ]) def testGetFlagsForFileForUnknownCppNotTestFile(self): @@ -228,26 +216,20 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-default' + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', '-std=c++11', '-x', 'c++', '-I[SRC]', + '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', '/mac.sdk', + '-I[OUT]/tag-default' ]) - testGetFlagsForFileForKnownObjcFile = TestLanguage( - 'eight.m', 'objective-c') + testGetFlagsForFileForKnownObjcFile = TestLanguage('eight.m', 'objective-c') testGetFlagsForFileForKnownObjcHeaderFile = TestLanguage( 'eight.h', 'objective-c') - testGetFlagsForFileForUnknownObjcFile = TestLanguage( - 'nonexistent.m', 'objective-c') - testGetFlagsForFileForKnownObjcppFile = TestLanguage( - 'nine.mm', 'objective-c++') + testGetFlagsForFileForUnknownObjcFile = TestLanguage('nonexistent.m', + 'objective-c') + testGetFlagsForFileForKnownObjcppFile = TestLanguage('nine.mm', + 'objective-c++') testGetFlagsForFileForKnownObjcppHeaderFile = TestLanguage( 'nine.h', 'objective-c++') testGetFlagsForFileForUnknownObjcppFile = TestLanguage( @@ -260,16 +242,11 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-default' + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', '-std=c++11', '-x', 'c++', '-I[SRC]', + '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', '/mac.sdk', + '-I[OUT]/tag-default' ]) def testGetFlagsForFileForUnknownUnittestFile(self): @@ -279,16 +256,11 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-default-test' + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', '-std=c++11', '-x', 'c++', '-I[SRC]', + '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', '/mac.sdk', + '-I[OUT]/tag-default-test' ]) def testGetFlagsForFileForUnknownBrowsertestFile2(self): @@ -298,16 +270,11 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-default-test' + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', '-std=c++11', '-x', 'c++', '-I[SRC]', + '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', '/mac.sdk', + '-I[OUT]/tag-default-test' ]) def testGetFlagsForFileForKnownHeaderFileWithAssociatedCppFile(self): @@ -317,29 +284,24 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-three' + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', '-std=c++11', '-x', 'c++', '-I[SRC]', + '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', '/mac.sdk', + '-I[OUT]/tag-three' ]) def testSourceFileWithNonClangOutputs(self): # Verify assumption that four.cc has non-compiler-output listed as the first # output. - p = subprocess.Popen(['ninja', '-C', self.out_dir, '-t', - 'query', '../../four.cc'], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - universal_newlines=True) + p = subprocess.Popen( + ['ninja', '-C', self.out_dir, '-t', 'query', '../../four.cc'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True) stdout, _ = p.communicate() self.assertFalse(p.returncode) - self.assertEquals(stdout, - '../../four.cc:\n' + self.assertEquals(stdout, '../../four.cc:\n' ' outputs:\n' ' obj/linker-output.o\n' ' obj/four.o\n') @@ -350,16 +312,11 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-four' + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', '-std=c++11', '-x', 'c++', '-I[SRC]', + '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', '/mac.sdk', + '-I[OUT]/tag-four' ]) def testSourceFileWithOnlyNonClangOutputs(self): @@ -369,16 +326,11 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '-isysroot', - '/mac.sdk', - '-I[OUT]/tag-default' + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', '-std=c++11', '-x', 'c++', '-I[SRC]', + '-Wno-unknown-warning-option', '-I[OUT]/a', '-isysroot', '/mac.sdk', + '-I[OUT]/tag-default' ]) def testGetFlagsForSysrootAbsPath(self): @@ -388,14 +340,16 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '--sysroot=/usr/lib/sysroot-image', + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', + '-std=c++11', + '-x', + 'c++', + '-I[SRC]', + '-Wno-unknown-warning-option', + '-I[OUT]/a', + '--sysroot=/usr/lib/sysroot-image', ]) def testGetFlagsForSysrootRelPath(self): @@ -405,16 +359,19 @@ self.assertTrue('do_cache' in result) self.assertTrue(result['do_cache']) self.assertTrue('flags' in result) - self.assertEquals(self.NormalizeStringsInList(result['flags']), [ - '-DUSE_CLANG_COMPLETER', - '-std=c++11', - '-x', 'c++', - '-I[SRC]', - '-Wno-unknown-warning-option', - '-I[OUT]/a', - '--sysroot=[SRC]/build/sysroot-image', + self.assertEquals( + self.NormalizeStringsInList(result['flags']), [ + '-DUSE_CLANG_COMPLETER', + '-std=c++11', + '-x', + 'c++', + '-I[SRC]', + '-Wno-unknown-warning-option', + '-I[OUT]/a', + '--sysroot=[SRC]/build/sysroot-image', ]) + if __name__ == '__main__': if not os.path.isfile('chromium.ycm_extra_conf.py'): print('The test must be run from src/tools/vim/ directory')