diff --git a/DEPS b/DEPS index cdd076e..d5cca170 100644 --- a/DEPS +++ b/DEPS
@@ -43,7 +43,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'd6a1568f656bfeacd8e85bdd6cddf04fea906336', + 'v8_revision': 'b1a1553d4c8f55a0fa515f063734c372f0bfda2b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -51,7 +51,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '5fc4e56dfa3fade0b683a7b42e691137bda5fed0', + 'angle_revision': 'c8c99a0a5d73a6494aebce463aef1eecca1304a9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -187,7 +187,7 @@ Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'd1e9c4bbd95af9a089d224edf87fd0c3f33ece96', 'src/third_party/libjingle/source/talk': - Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '1c16da383ac3d7a51088722fab024533efc9dbce', # commit position 11275 + Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'd9abcae5ed8678a1b32bb8dad1b84eba82546910', # commit position 11290 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'c60ec8b35c3fe6027d7a3faae89d1c8d7dd3ce98', @@ -211,7 +211,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'ef78a80a92b3bfe0cb3e720b15174759a9d3d5e0', # commit position 11275 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '8d5f2987a2d68d2b2ce30155c6bbcf8fb217692a', # commit position 11288 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/ash/ash.gyp b/ash/ash.gyp index f87be98..1df3b4d 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp
@@ -147,8 +147,6 @@ 'gpu_support_stub.h', 'high_contrast/high_contrast_controller.cc', 'high_contrast/high_contrast_controller.h', - 'host/ash_remote_window_tree_host_win.cc', - 'host/ash_remote_window_tree_host_win.h', 'host/ash_window_tree_host.cc', 'host/ash_window_tree_host.h', 'host/ash_window_tree_host_init_params.cc',
diff --git a/ash/ash_unittests.isolate b/ash/ash_unittests.isolate index a210ff8..89ab132b 100644 --- a/ash/ash_unittests.isolate +++ b/ash/ash_unittests.isolate
@@ -26,7 +26,7 @@ ], }, }], - ['OS=="win" or chromeos==1', { + ['chromeos==1', { 'variables': { 'files': [ '../testing/test_env.py', @@ -52,20 +52,6 @@ ], }, }], - ['OS=="win"', { - 'variables': { - 'files': [ - '<(PRODUCT_DIR)/osmesa.dll', - ], - }, - }], - ['OS=="win" and (fastbuild==0 or fastbuild==1)', { - 'variables': { - 'files': [ - '<(PRODUCT_DIR)/ash_unittests.exe.pdb', - ], - }, - }], ], 'includes': [ '../base/base.isolate',
diff --git a/ash/host/ash_remote_window_tree_host_win.cc b/ash/host/ash_remote_window_tree_host_win.cc deleted file mode 100644 index f3191b5e..0000000 --- a/ash/host/ash_remote_window_tree_host_win.cc +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/host/ash_remote_window_tree_host_win.h" - -#include "ash/host/root_window_transformer.h" -#include "ash/ime/input_method_event_handler.h" -#include "ui/events/event_processor.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/transform.h" - -namespace ash { - -AshRemoteWindowTreeHostWin::AshRemoteWindowTreeHostWin(HWND remote_hwnd) - : aura::RemoteWindowTreeHostWin(), - transformer_helper_(this) { - SetRemoteWindowHandle(remote_hwnd); - transformer_helper_.Init(); -} - -AshRemoteWindowTreeHostWin::~AshRemoteWindowTreeHostWin() {} - -void AshRemoteWindowTreeHostWin::ToggleFullScreen() {} - -bool AshRemoteWindowTreeHostWin::ConfineCursorToRootWindow() { return false; } - -void AshRemoteWindowTreeHostWin::UnConfineCursor() {} - -void AshRemoteWindowTreeHostWin::SetRootWindowTransformer( - scoped_ptr<RootWindowTransformer> transformer) { - transformer_helper_.SetRootWindowTransformer(transformer.Pass()); -} - -gfx::Insets AshRemoteWindowTreeHostWin::GetHostInsets() const { - return gfx::Insets(); -} - -aura::WindowTreeHost* AshRemoteWindowTreeHostWin::AsWindowTreeHost() { - return this; -} - -gfx::Transform AshRemoteWindowTreeHostWin::GetRootTransform() const { - return transformer_helper_.GetTransform(); -} - -void AshRemoteWindowTreeHostWin::SetRootTransform( - const gfx::Transform& transform) { - transformer_helper_.SetTransform(transform); -} - -gfx::Transform AshRemoteWindowTreeHostWin::GetInverseRootTransform() const { - return transformer_helper_.GetInverseTransform(); -} - -void AshRemoteWindowTreeHostWin::UpdateRootWindowSize( - const gfx::Size& host_size) { - transformer_helper_.UpdateWindowSize(host_size); -} - -ui::EventDispatchDetails AshRemoteWindowTreeHostWin::DispatchKeyEventPostIME( - ui::KeyEvent* event) { - input_method_handler()->SetPostIME(true); - ui::EventDispatchDetails details = - event_processor()->OnEventFromSource(event); - if (!details.dispatcher_destroyed) - input_method_handler()->SetPostIME(false); - return details; -} - -} // namespace ash
diff --git a/ash/host/ash_remote_window_tree_host_win.h b/ash/host/ash_remote_window_tree_host_win.h deleted file mode 100644 index f60e582..0000000 --- a/ash/host/ash_remote_window_tree_host_win.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_HOST_REMOTE_WINDOW_TREE_HOST_WIN_H_ -#define ASH_HOST_REMOTE_WINDOW_TREE_HOST_WIN_H_ - -#include <windows.h> - -#include "ash/ash_export.h" -#include "ash/host/ash_window_tree_host.h" -#include "ash/host/transformer_helper.h" -#include "base/macros.h" -#include "ui/aura/remote_window_tree_host_win.h" - -namespace ash { - -class ASH_EXPORT AshRemoteWindowTreeHostWin - : public AshWindowTreeHost, - public aura::RemoteWindowTreeHostWin { - public: - explicit AshRemoteWindowTreeHostWin(HWND remote_hwnd); - - private: - ~AshRemoteWindowTreeHostWin() override; - - // AshWindowTreeHost: - void ToggleFullScreen() override; - bool ConfineCursorToRootWindow() override; - void UnConfineCursor() override; - void SetRootWindowTransformer( - scoped_ptr<RootWindowTransformer> transformer) override; - gfx::Insets GetHostInsets() const override; - aura::WindowTreeHost* AsWindowTreeHost() override; - - // WindowTreeHostWin: - gfx::Transform GetRootTransform() const override; - void SetRootTransform(const gfx::Transform& transform) override; - gfx::Transform GetInverseRootTransform() const override; - void UpdateRootWindowSize(const gfx::Size& host_size) override; - - // ui::internal::InputMethodDelegate: - ui::EventDispatchDetails DispatchKeyEventPostIME( - ui::KeyEvent* event) override; - - TransformerHelper transformer_helper_; - - DISALLOW_COPY_AND_ASSIGN(AshRemoteWindowTreeHostWin); -}; - -} // namespace ash - -#endif // ASH_HOST_REMOTE_WINDOW_TREE_HOST_WIN_H_
diff --git a/ash/host/ash_window_tree_host_win.cc b/ash/host/ash_window_tree_host_win.cc index 287fc56b..98d6b10 100644 --- a/ash/host/ash_window_tree_host_win.cc +++ b/ash/host/ash_window_tree_host_win.cc
@@ -6,7 +6,6 @@ #include "ash/ash_export.h" #include "ash/ash_switches.h" -#include "ash/host/ash_remote_window_tree_host_win.h" #include "ash/host/ash_window_tree_host_init_params.h" #include "ash/host/root_window_transformer.h" #include "ash/host/transformer_helper.h" @@ -123,11 +122,6 @@ AshWindowTreeHost* AshWindowTreeHost::Create( const AshWindowTreeHostInitParams& init_params) { - if (base::win::GetVersion() >= base::win::VERSION_WIN7 && - !base::CommandLine::ForCurrentProcess()->HasSwitch( - ash::switches::kForceAshToDesktop)) - return new AshRemoteWindowTreeHostWin(init_params.remote_hwnd); - return new AshWindowTreeHostWin(init_params.initial_bounds); }
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc index 4232333..93d770f 100644 --- a/ash/test/ash_test_base.cc +++ b/ash/test/ash_test_base.cc
@@ -40,7 +40,6 @@ #if defined(OS_WIN) #include "base/win/windows_version.h" -#include "ui/aura/remote_window_tree_host_win.h" #include "ui/platform_window/win/win_window.h" #include "win8/test/test_registrar_constants.h" #endif
diff --git a/base/BUILD.gn b/base/BUILD.gn index 1265df8..fc441da 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1132,7 +1132,7 @@ "$root_out_dir/msvcr120${vcrt_suffix}.dll", ] if (is_asan) { - data += [ "//third_party/llvm-build/Release+Asserts/lib/clang/3.8.0/lib/windows/clang_rt.asan_dynamic-i386.dll" ] + data += [ "//third_party/llvm-build/Release+Asserts/lib/clang/3.9.0/lib/windows/clang_rt.asan_dynamic-i386.dll" ] } }
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi index 16e20e0..4399879 100644 --- a/build/gn_migration.gypi +++ b/build/gn_migration.gypi
@@ -517,7 +517,6 @@ '../third_party/codesighs/codesighs.gyp:msdump2symdb', '../third_party/codesighs/codesighs.gyp:msmap2tsv', '../third_party/pdfium/samples/samples.gyp:pdfium_diff', - '../win8/win8.gyp:metro_viewer', ], }], ['chromecast==1', {
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc index 475885c..c6b12ba 100644 --- a/build/sanitizers/tsan_suppressions.cc +++ b/build/sanitizers/tsan_suppressions.cc
@@ -280,6 +280,9 @@ // https://crbug.com/539315 "race:MojoCreateMessagePipe\n" +// http://crbug.com/559117 +"race:base::trace_event::TraceConfig::AsConvertableToTraceFormat\n" + // https://crbug.com/569682 "race:blink::ThreadState::visitStackRoots\n"
diff --git a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn index 7cab0432..030e071 100644 --- a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn +++ b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
@@ -18,6 +18,8 @@ } sources = [ + "api/module_annotations_win.cc", + "api/module_annotations_win.h", "cpu_architecture.h", "cpu_context.cc", "cpu_context.h",
diff --git a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn index 8d95f8df..8c01267 100644 --- a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn +++ b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
@@ -140,6 +140,8 @@ "win/exception_handler_server.h", "win/get_function.cc", "win/get_function.h", + "win/get_module_information.cc", + "win/get_module_information.h", "win/handle.cc", "win/handle.h", "win/module_version.cc",
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py index 6a0e6c95..66a3cd8 100755 --- a/build/vs_toolchain.py +++ b/build/vs_toolchain.py
@@ -71,6 +71,8 @@ elif sys.platform == 'win32' and not depot_tools_win_toolchain: if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ: os.environ['GYP_MSVS_OVERRIDE_PATH'] = DetectVisualStudioPath() + if not 'GYP_MSVS_VERSION' in os.environ: + os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion() return vs_runtime_dll_dirs
diff --git a/cc/animation/animation_player.h b/cc/animation/animation_player.h index 4902ec4..7d04c56 100644 --- a/cc/animation/animation_player.h +++ b/cc/animation/animation_player.h
@@ -84,6 +84,11 @@ Animation::TargetProperty target_property, int group); + // Whether this player has animations waiting to get sent to LAC. + bool has_pending_animations_for_testing() const { + return !animations_.empty(); + } + private: friend class base::RefCounted<AnimationPlayer>;
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc index 88601b5..56c2af9 100644 --- a/cc/blink/web_layer_impl.cc +++ b/cc/blink/web_layer_impl.cc
@@ -345,9 +345,58 @@ return layer_->have_scroll_event_handlers(); } -void WebLayerImpl::setShouldScrollOnMainThread( - bool should_scroll_on_main_thread) { - layer_->SetShouldScrollOnMainThread(should_scroll_on_main_thread); +static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>( + blink::WebMainThreadScrollingReason::NotScrollingOnMain) == + cc::InputHandler::NOT_SCROLLING_ON_MAIN, + "InputHandler::MainThreadScrollingReason and " + "WebMainThreadScrollingReason enums must match"); +static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>( + blink::WebMainThreadScrollingReason:: + HasBackgroundAttachmentFixedObjects) == + cc::InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS, + "InputHandler::MainThreadScrollingReason and " + "WebMainThreadScrollingReason enums must match"); +static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>( + blink::WebMainThreadScrollingReason:: + HasNonLayerViewportConstrainedObjects) == + cc::InputHandler::HAS_NON_LAYER_VIEWPORT_CONSTRAINED_OBJECTS, + "InputHandler::MainThreadScrollingReason and " + "WebMainThreadScrollingReason enums must match"); +static_assert( + static_cast<cc::InputHandler::MainThreadScrollingReason>( + blink::WebMainThreadScrollingReason::ThreadedScrollingDisabled) == + cc::InputHandler::THREADED_SCROLLING_DISABLED, + "InputHandler::MainThreadScrollingReason and " + "WebMainThreadScrollingReason enums must match"); +static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>( + blink::WebMainThreadScrollingReason::ScrollBarScrolling) == + cc::InputHandler::SCROLL_BAR_SCROLLING, + "InputHandler::MainThreadScrollingReason and " + "WebMainThreadScrollingReason enums must match"); +static_assert(static_cast<cc::InputHandler::MainThreadScrollingReason>( + blink::WebMainThreadScrollingReason::PageOverlay) == + cc::InputHandler::PAGE_OVERLAY, + "InputHandler::MainThreadScrollingReason and " + "WebMainThreadScrollingReason enums must match"); + +void WebLayerImpl::addMainThreadScrollingReasons( + blink::WebMainThreadScrollingReason::WebMainThreadScrollingReason + main_thread_scrolling_reasons) { + DCHECK(main_thread_scrolling_reasons); + // WebLayerImpl should only know about non-transient scrolling + // reasons. Transient scrolling reasons are computed per hit test. + DCHECK_LE( + main_thread_scrolling_reasons, + static_cast< + blink::WebMainThreadScrollingReason::WebMainThreadScrollingReason>( + cc::InputHandler::MaxNonTransientScrollingReason)); + layer_->AddMainThreadScrollingReasons( + static_cast<cc::InputHandler::MainThreadScrollingReason>( + main_thread_scrolling_reasons)); +} + +void WebLayerImpl::clearMainThreadScrollingReasons() { + layer_->ClearMainThreadScrollingReasons(); } bool WebLayerImpl::shouldScrollOnMainThread() const {
diff --git a/cc/blink/web_layer_impl.h b/cc/blink/web_layer_impl.h index 3fd0bcc..482c633 100644 --- a/cc/blink/web_layer_impl.h +++ b/cc/blink/web_layer_impl.h
@@ -22,6 +22,7 @@ #include "third_party/WebKit/public/platform/WebDoublePoint.h" #include "third_party/WebKit/public/platform/WebFloatPoint.h" #include "third_party/WebKit/public/platform/WebLayer.h" +#include "third_party/WebKit/public/platform/WebMainThreadScrollingReason.h" #include "third_party/WebKit/public/platform/WebPoint.h" #include "third_party/WebKit/public/platform/WebRect.h" #include "third_party/WebKit/public/platform/WebSize.h" @@ -128,7 +129,10 @@ bool haveWheelEventHandlers() const override; void setHaveScrollEventHandlers(bool have_scroll_event_handlers) override; bool haveScrollEventHandlers() const override; - void setShouldScrollOnMainThread(bool scroll_on_main) override; + void addMainThreadScrollingReasons( + blink::WebMainThreadScrollingReason::WebMainThreadScrollingReason + main_thread_scrolling_reasons) override; + void clearMainThreadScrollingReasons() override; bool shouldScrollOnMainThread() const override; void setNonFastScrollableRegion( const blink::WebVector<blink::WebRect>& region) override;
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h index f65509f..d26e6a4b 100644 --- a/cc/input/input_handler.h +++ b/cc/input/input_handler.h
@@ -77,14 +77,51 @@ public: // Note these are used in a histogram. Do not reorder or delete existing // entries. - enum ScrollStatus { + enum ScrollThread { SCROLL_ON_MAIN_THREAD = 0, - SCROLL_STARTED, + SCROLL_ON_IMPL_THREAD, SCROLL_IGNORED, SCROLL_UNKNOWN, // This must be the last entry. ScrollStatusCount }; + + // Ensure this stays in sync with MainThreadScrollingReason in histograms.xml, + // and that this extends ScrollingCoordinator::MainThreadScrollingReason. + // ScrollingCoordinator::MainThreadScrollingReason contains the flags + // which are associated with a layer. The flags only contained in + // InputHandler::MainThreadScrollingReason are computed for each scroll + // begin. + enum MainThreadScrollingReason { + NOT_SCROLLING_ON_MAIN = 0, + HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS = 1 << 0, + HAS_NON_LAYER_VIEWPORT_CONSTRAINED_OBJECTS = 1 << 1, + THREADED_SCROLLING_DISABLED = 1 << 2, + SCROLL_BAR_SCROLLING = 1 << 3, + PAGE_OVERLAY = 1 << 4, + MaxNonTransientScrollingReason = PAGE_OVERLAY, + NON_FAST_SCROLLABLE_REGION = 1 << 5, + EVENT_HANDLERS = 1 << 6, + FAILED_HIT_TEST = 1 << 7, + NO_SCROLLING_LAYER = 1 << 8, + NOT_SCROLLABLE = 1 << 9, + CONTINUING_MAIN_THREAD_SCROLL = 1 << 10, + NON_INVERTIBLE_TRANSFORM = 1 << 11, + MainThreadScrollingReasonCount = 13 + }; + + struct ScrollStatus { + ScrollStatus() + : thread(SCROLL_ON_IMPL_THREAD), + main_thread_scrolling_reasons(NOT_SCROLLING_ON_MAIN) {} + ScrollStatus(ScrollThread thread, + MainThreadScrollingReason main_thread_scrolling_reasons) + : thread(thread), + main_thread_scrolling_reasons(main_thread_scrolling_reasons) {} + ScrollThread thread; + MainThreadScrollingReason main_thread_scrolling_reasons; + }; + enum ScrollInputType { GESTURE, WHEEL, ANIMATED_WHEEL, NON_BUBBLING_GESTURE }; // Binds a client to this handler to receive notifications. Only one client @@ -181,6 +218,13 @@ DISALLOW_COPY_AND_ASSIGN(InputHandler); }; +inline const InputHandler::MainThreadScrollingReason& operator|=( + InputHandler::MainThreadScrollingReason& a, + InputHandler::MainThreadScrollingReason b) { + return a = static_cast<InputHandler::MainThreadScrollingReason>( + static_cast<unsigned>(a) | static_cast<unsigned>(b)); +} + } // namespace cc #endif // CC_INPUT_INPUT_HANDLER_H_
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index cc2cbbb..88043a7 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc
@@ -66,8 +66,8 @@ property_tree_sequence_number_(-1), element_id_(0), mutable_properties_(kMutablePropertyNone), + main_thread_scrolling_reasons_(InputHandler::NOT_SCROLLING_ON_MAIN), should_flatten_transform_from_property_tree_(false), - should_scroll_on_main_thread_(false), have_wheel_event_handlers_(false), have_scroll_event_handlers_(false), user_scrollable_horizontal_(true), @@ -947,11 +947,21 @@ SetNeedsCommit(); } -void Layer::SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) { +void Layer::AddMainThreadScrollingReasons( + InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons) { DCHECK(IsPropertyChangeAllowed()); - if (should_scroll_on_main_thread_ == should_scroll_on_main_thread) + DCHECK(main_thread_scrolling_reasons); + if (main_thread_scrolling_reasons_ == main_thread_scrolling_reasons) return; - should_scroll_on_main_thread_ = should_scroll_on_main_thread; + main_thread_scrolling_reasons_ |= main_thread_scrolling_reasons; + SetNeedsCommit(); +} + +void Layer::ClearMainThreadScrollingReasons() { + DCHECK(IsPropertyChangeAllowed()); + if (!main_thread_scrolling_reasons_) + return; + main_thread_scrolling_reasons_ = InputHandler::NOT_SCROLLING_ON_MAIN; SetNeedsCommit(); } @@ -1196,7 +1206,7 @@ DCHECK(!(FilterIsAnimating() && layer->FilterIsAnimatingOnImplOnly())); layer->SetBackgroundFilters(background_filters()); layer->SetMasksToBounds(masks_to_bounds_); - layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_); + layer->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons_); layer->SetHaveWheelEventHandlers(have_wheel_event_handlers_); layer->SetHaveScrollEventHandlers(have_scroll_event_handlers_); layer->SetNonFastScrollableRegion(non_fast_scrollable_region_); @@ -1467,7 +1477,7 @@ // |filters_| and |background_filters_|. See crbug.com/541321. base->set_masks_to_bounds(masks_to_bounds_); - base->set_should_scroll_on_main_thread(should_scroll_on_main_thread_); + base->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons_); base->set_have_wheel_event_handlers(have_wheel_event_handlers_); base->set_have_scroll_event_handlers(have_scroll_event_handlers_); RegionToProto(non_fast_scrollable_region_, @@ -1553,7 +1563,9 @@ hide_layer_and_subtree_ = base.hide_layer_and_subtree(); has_render_surface_ = base.has_render_surface(); masks_to_bounds_ = base.masks_to_bounds(); - should_scroll_on_main_thread_ = base.should_scroll_on_main_thread(); + main_thread_scrolling_reasons_ = + static_cast<InputHandler::MainThreadScrollingReason>( + base.main_thread_scrolling_reasons()); have_wheel_event_handlers_ = base.have_wheel_event_handlers(); have_scroll_event_handlers_ = base.have_scroll_event_handlers(); non_fast_scrollable_region_ =
diff --git a/cc/layers/layer.h b/cc/layers/layer.h index ef5da33..aff32fa 100644 --- a/cc/layers/layer.h +++ b/cc/layers/layer.h
@@ -23,6 +23,7 @@ #include "cc/base/region.h" #include "cc/debug/frame_timing_request.h" #include "cc/debug/micro_benchmark.h" +#include "cc/input/input_handler.h" #include "cc/layers/layer_lists.h" #include "cc/layers/layer_position_constraint.h" #include "cc/layers/paint_properties.h" @@ -276,9 +277,11 @@ } bool user_scrollable_vertical() const { return user_scrollable_vertical_; } - void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread); + void AddMainThreadScrollingReasons( + InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons); + void ClearMainThreadScrollingReasons(); bool should_scroll_on_main_thread() const { - return should_scroll_on_main_thread_; + return !!main_thread_scrolling_reasons_; } void SetHaveWheelEventHandlers(bool have_wheel_event_handlers); @@ -723,8 +726,8 @@ uint64_t element_id_; uint32_t mutable_properties_; gfx::Vector2dF offset_to_transform_parent_; + InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons_; bool should_flatten_transform_from_property_tree_ : 1; - bool should_scroll_on_main_thread_ : 1; bool have_wheel_event_handlers_ : 1; bool have_scroll_event_handlers_ : 1; bool user_scrollable_horizontal_ : 1;
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index b845968..422de5c 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc
@@ -57,7 +57,7 @@ layer_tree_impl_(tree_impl), scroll_offset_(scroll_offset), scroll_clip_layer_id_(Layer::INVALID_ID), - should_scroll_on_main_thread_(false), + main_thread_scrolling_reasons_(InputHandler::NOT_SCROLLING_ON_MAIN), have_wheel_event_handlers_(false), have_scroll_event_handlers_(false), scroll_blocks_on_(SCROLL_BLOCKS_ON_NONE), @@ -507,15 +507,24 @@ const gfx::PointF& screen_space_point, InputHandler::ScrollInputType type, ScrollBlocksOn effective_block_mode) const { + InputHandler::ScrollStatus scroll_status; + scroll_status.main_thread_scrolling_reasons = + InputHandler::NOT_SCROLLING_ON_MAIN; if (should_scroll_on_main_thread()) { TRACE_EVENT0("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread"); - return InputHandler::SCROLL_ON_MAIN_THREAD; + scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD; + scroll_status.main_thread_scrolling_reasons = + main_thread_scrolling_reasons_; + return scroll_status; } gfx::Transform screen_space_transform = ScreenSpaceTransform(); if (!screen_space_transform.IsInvertible()) { TRACE_EVENT0("cc", "LayerImpl::TryScroll: Ignored NonInvertibleTransform"); - return InputHandler::SCROLL_IGNORED; + scroll_status.thread = InputHandler::SCROLL_IGNORED; + scroll_status.main_thread_scrolling_reasons = + InputHandler::NON_INVERTIBLE_TRANSFORM; + return scroll_status; } if (!non_fast_scrollable_region().IsEmpty()) { @@ -535,26 +544,35 @@ gfx::ToRoundedPoint(hit_test_point_in_layer_space))) { TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed NonFastScrollableRegion"); - return InputHandler::SCROLL_ON_MAIN_THREAD; + scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD; + scroll_status.main_thread_scrolling_reasons = + InputHandler::NON_FAST_SCROLLABLE_REGION; + return scroll_status; } } if (have_scroll_event_handlers() && effective_block_mode & SCROLL_BLOCKS_ON_SCROLL_EVENT) { TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed ScrollEventHandlers"); - return InputHandler::SCROLL_ON_MAIN_THREAD; + scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD; + scroll_status.main_thread_scrolling_reasons = InputHandler::EVENT_HANDLERS; + return scroll_status; } if ((type == InputHandler::WHEEL || type == InputHandler::ANIMATED_WHEEL) && have_wheel_event_handlers() && effective_block_mode & SCROLL_BLOCKS_ON_WHEEL_EVENT) { TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed WheelEventHandlers"); - return InputHandler::SCROLL_ON_MAIN_THREAD; + scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD; + scroll_status.main_thread_scrolling_reasons = InputHandler::EVENT_HANDLERS; + return scroll_status; } if (!scrollable()) { TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored not scrollable"); - return InputHandler::SCROLL_IGNORED; + scroll_status.thread = InputHandler::SCROLL_IGNORED; + scroll_status.main_thread_scrolling_reasons = InputHandler::NOT_SCROLLABLE; + return scroll_status; } gfx::ScrollOffset max_scroll_offset = MaxScrollOffset(); @@ -562,10 +580,13 @@ TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored. Technically scrollable," " but has no affordance in either direction."); - return InputHandler::SCROLL_IGNORED; + scroll_status.thread = InputHandler::SCROLL_IGNORED; + scroll_status.main_thread_scrolling_reasons = InputHandler::NOT_SCROLLABLE; + return scroll_status; } - return InputHandler::SCROLL_STARTED; + scroll_status.thread = InputHandler::SCROLL_ON_IMPL_THREAD; + return scroll_status; } skia::RefPtr<SkPicture> LayerImpl::GetPicture() { @@ -594,7 +615,7 @@ layer->SetFilters(filters()); layer->SetBackgroundFilters(background_filters()); layer->SetMasksToBounds(masks_to_bounds_); - layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_); + layer->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons_); layer->SetHaveWheelEventHandlers(have_wheel_event_handlers_); layer->SetHaveScrollEventHandlers(have_scroll_event_handlers_); layer->SetScrollBlocksOn(scroll_blocks_on_);
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 4dca350..48e9529 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h
@@ -492,11 +492,12 @@ void ApplySentScrollDeltasFromAbortedCommit(); - void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) { - should_scroll_on_main_thread_ = should_scroll_on_main_thread; + void set_main_thread_scrolling_reasons( + InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons) { + main_thread_scrolling_reasons_ = main_thread_scrolling_reasons; } bool should_scroll_on_main_thread() const { - return should_scroll_on_main_thread_; + return !!main_thread_scrolling_reasons_; } void SetHaveWheelEventHandlers(bool have_wheel_event_handlers) { @@ -773,8 +774,7 @@ int scroll_clip_layer_id_; gfx::Vector2dF offset_to_transform_parent_; - - bool should_scroll_on_main_thread_ : 1; + InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons_; bool have_wheel_event_handlers_ : 1; bool have_scroll_event_handlers_ : 1;
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc index f73cb25..13bcba1 100644 --- a/cc/layers/layer_unittest.cc +++ b/cc/layers/layer_unittest.cc
@@ -131,8 +131,8 @@ EXPECT_EQ(src->hide_layer_and_subtree_, dest->hide_layer_and_subtree_); EXPECT_EQ(src->has_render_surface_, dest->has_render_surface_); EXPECT_EQ(src->masks_to_bounds_, dest->masks_to_bounds_); - EXPECT_EQ(src->should_scroll_on_main_thread_, - dest->should_scroll_on_main_thread_); + EXPECT_EQ(src->main_thread_scrolling_reasons_, + dest->main_thread_scrolling_reasons_); EXPECT_EQ(src->have_wheel_event_handlers_, dest->have_wheel_event_handlers_); EXPECT_EQ(src->have_scroll_event_handlers_, @@ -249,7 +249,7 @@ layer->hide_layer_and_subtree_ = false; layer->has_render_surface_ = false; layer->masks_to_bounds_ = true; - layer->should_scroll_on_main_thread_ = false; + layer->main_thread_scrolling_reasons_ = InputHandler::NOT_SCROLLING_ON_MAIN; layer->have_wheel_event_handlers_ = true; layer->have_scroll_event_handlers_ = false; layer->non_fast_scrollable_region_ = Region(gfx::Rect(5, 1, 14, 3)); @@ -299,8 +299,8 @@ layer->hide_layer_and_subtree_ = !layer->hide_layer_and_subtree_; layer->has_render_surface_ = !layer->has_render_surface_; layer->masks_to_bounds_ = !layer->masks_to_bounds_; - layer->should_scroll_on_main_thread_ = - !layer->should_scroll_on_main_thread_; + layer->main_thread_scrolling_reasons_ = + InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS; layer->have_wheel_event_handlers_ = !layer->have_wheel_event_handlers_; layer->have_scroll_event_handlers_ = !layer->have_scroll_event_handlers_; layer->non_fast_scrollable_region_ = Region(gfx::Rect(5, 1, 14, 3)); @@ -967,7 +967,8 @@ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUserScrollable(true, false)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollOffset( gfx::ScrollOffset(10, 10))); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetShouldScrollOnMainThread(true)); + EXPECT_SET_NEEDS_COMMIT(1, test_layer->AddMainThreadScrollingReasons( + InputHandler::EVENT_HANDLERS)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetNonFastScrollableRegion( Region(gfx::Rect(1, 1, 2, 2)))); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHaveWheelEventHandlers(true));
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc index aabde35..2e822599 100644 --- a/cc/layers/painted_scrollbar_layer.cc +++ b/cc/layers/painted_scrollbar_layer.cc
@@ -50,7 +50,7 @@ has_thumb_(scrollbar_->HasThumb()), thumb_opacity_(scrollbar_->ThumbOpacity()) { if (!scrollbar_->IsOverlay()) - SetShouldScrollOnMainThread(true); + AddMainThreadScrollingReasons(InputHandler::SCROLL_BAR_SCROLLING); } PaintedScrollbarLayer::~PaintedScrollbarLayer() {}
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc index b9fc9ae..e0d7a74b 100644 --- a/cc/layers/scrollbar_layer_unittest.cc +++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -160,9 +160,11 @@ // When the scrollbar is not an overlay scrollbar, the scroll should be // responded to on the main thread as the compositor does not yet implement // scrollbar scrolling. - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - scrollbar_layer_impl->TryScroll( - gfx::PointF(), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE)); + InputHandler::ScrollStatus status = scrollbar_layer_impl->TryScroll( + gfx::PointF(), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::SCROLL_BAR_SCROLLING, + status.main_thread_scrolling_reasons); // Create and attach an overlay scrollbar. scrollbar.reset(new FakeScrollbar(false, false, true)); @@ -175,9 +177,10 @@ // The user shouldn't be able to drag an overlay scrollbar and the scroll // may be handled in the compositor. - EXPECT_EQ(InputHandler::SCROLL_IGNORED, - scrollbar_layer_impl->TryScroll( - gfx::PointF(), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE)); + status = scrollbar_layer_impl->TryScroll(gfx::PointF(), InputHandler::GESTURE, + SCROLL_BLOCKS_ON_NONE); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLABLE, status.main_thread_scrolling_reasons); } TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) {
diff --git a/cc/proto/layer.proto b/cc/proto/layer.proto index bc1255d..4c8ba319 100644 --- a/cc/proto/layer.proto +++ b/cc/proto/layer.proto
@@ -85,7 +85,7 @@ // repeated FilterOperation filters = 12; // repeated FilterOperation background_filters = 13; optional bool masks_to_bounds = 14; - optional bool should_scroll_on_main_thread = 15; + optional uint32 main_thread_scrolling_reasons = 15; optional bool have_wheel_event_handlers = 16; optional bool have_scroll_event_handlers = 17; optional Region non_fast_scrollable_region = 18;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 057228f0..2d1321e0 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -140,7 +140,7 @@ void RecordCompositorSlowScrollMetric(InputHandler::ScrollInputType type, ScrollThread scroll_thread) { - bool scroll_on_main_thread = (scroll_thread == ScrollThread::MAIN_THREAD); + bool scroll_on_main_thread = (scroll_thread == MAIN_THREAD); if (type == InputHandler::WHEEL || type == InputHandler::ANIMATED_WHEEL) { UMA_HISTOGRAM_BOOLEAN("Renderer4.CompositorWheelScrollUpdateThread", scroll_on_main_thread); @@ -548,8 +548,10 @@ active_tree_->FindLayerThatIsHitByPoint(device_viewport_point); bool scroll_on_main_thread = false; + InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons; LayerImpl* test_layer_impl = FindScrollLayerForDeviceViewportPoint( - device_viewport_point, type, layer_impl, &scroll_on_main_thread, NULL); + device_viewport_point, type, layer_impl, &scroll_on_main_thread, nullptr, + &main_thread_scrolling_reasons); if (!test_layer_impl) return false; @@ -2476,8 +2478,12 @@ InputHandler::ScrollInputType type, LayerImpl* layer_impl, bool* scroll_on_main_thread, - bool* optional_has_ancestor_scroll_handler) const { + bool* optional_has_ancestor_scroll_handler, + InputHandler::MainThreadScrollingReason* main_thread_scrolling_reasons) + const { DCHECK(scroll_on_main_thread); + DCHECK(main_thread_scrolling_reasons); + *main_thread_scrolling_reasons = InputHandler::NOT_SCROLLING_ON_MAIN; ScrollBlocksOn block_mode = EffectiveScrollBlocksOn(layer_impl); @@ -2488,8 +2494,17 @@ // thread. ScrollStatus status = layer_impl->TryScroll(device_viewport_point, type, block_mode); - if (status == SCROLL_ON_MAIN_THREAD) { + if (status.thread == SCROLL_ON_MAIN_THREAD) { + if (layer_impl->should_scroll_on_main_thread()) { + DCHECK(status.main_thread_scrolling_reasons <= + InputHandler::MaxNonTransientScrollingReason); + } else { + DCHECK(status.main_thread_scrolling_reasons > + InputHandler::MaxNonTransientScrollingReason); + } + *scroll_on_main_thread = true; + *main_thread_scrolling_reasons = status.main_thread_scrolling_reasons; return NULL; } @@ -2499,9 +2514,19 @@ status = scroll_layer_impl->TryScroll(device_viewport_point, type, block_mode); + // If any layer wants to divert the scroll event to the main thread, abort. - if (status == SCROLL_ON_MAIN_THREAD) { + if (status.thread == SCROLL_ON_MAIN_THREAD) { + if (layer_impl->should_scroll_on_main_thread()) { + DCHECK(status.main_thread_scrolling_reasons <= + InputHandler::MaxNonTransientScrollingReason); + } else { + DCHECK(status.main_thread_scrolling_reasons > + InputHandler::MaxNonTransientScrollingReason); + } + *scroll_on_main_thread = true; + *main_thread_scrolling_reasons = status.main_thread_scrolling_reasons; return NULL; } @@ -2509,8 +2534,10 @@ scroll_layer_impl->have_scroll_event_handlers()) *optional_has_ancestor_scroll_handler = true; - if (status == SCROLL_STARTED && !potentially_scrolling_layer_impl) + if (status.thread == InputHandler::SCROLL_ON_IMPL_THREAD && + !potentially_scrolling_layer_impl) { potentially_scrolling_layer_impl = scroll_layer_impl; + } } // Falling back to the root scroll layer ensures generation of root overscroll @@ -2553,9 +2580,14 @@ DCHECK(scroll_state); DCHECK(scroll_state->delta_x() == 0 && scroll_state->delta_y() == 0); - if (!scrolling_layer_impl) - return SCROLL_IGNORED; - + InputHandler::ScrollStatus scroll_status; + scroll_status.main_thread_scrolling_reasons = NOT_SCROLLING_ON_MAIN; + if (!scrolling_layer_impl) { + scroll_status.thread = SCROLL_IGNORED; + scroll_status.main_thread_scrolling_reasons = NO_SCROLLING_LAYER; + return scroll_status; + } + scroll_status.thread = SCROLL_ON_IMPL_THREAD; ScrollAnimationAbort(scrolling_layer_impl); top_controls_manager_->ScrollBegin(); @@ -2570,12 +2602,12 @@ DistributeScrollDelta(scroll_state); client_->RenewTreePriority(); - RecordCompositorSlowScrollMetric(type, ScrollThread::CC_THREAD); + RecordCompositorSlowScrollMetric(type, CC_THREAD); // TODO(lanwei): Will remove this metric in M50 when we have used the new // metrics for one milestone, see https://crbug.com/557787. UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", false); - return SCROLL_STARTED; + return scroll_status; } InputHandler::ScrollStatus LayerTreeHostImpl::RootScrollBegin( @@ -2591,6 +2623,8 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( ScrollState* scroll_state, InputHandler::ScrollInputType type) { + ScrollStatus scroll_status; + scroll_status.main_thread_scrolling_reasons = NOT_SCROLLING_ON_MAIN; TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBegin"); ClearCurrentlyScrollingLayer(); @@ -2607,22 +2641,29 @@ LayerImpl* scroll_layer_impl = active_tree_->FindFirstScrollingLayerThatIsHitByPoint( device_viewport_point); - if (scroll_layer_impl && !HasScrollAncestor(layer_impl, scroll_layer_impl)) - return SCROLL_UNKNOWN; + if (scroll_layer_impl && + !HasScrollAncestor(layer_impl, scroll_layer_impl)) { + scroll_status.thread = SCROLL_UNKNOWN; + scroll_status.main_thread_scrolling_reasons = + InputHandler::FAILED_HIT_TEST; + return scroll_status; + } } bool scroll_on_main_thread = false; LayerImpl* scrolling_layer_impl = FindScrollLayerForDeviceViewportPoint( device_viewport_point, type, layer_impl, &scroll_on_main_thread, - &scroll_affects_scroll_handler_); + &scroll_affects_scroll_handler_, + &scroll_status.main_thread_scrolling_reasons); if (scroll_on_main_thread) { - RecordCompositorSlowScrollMetric(type, ScrollThread::MAIN_THREAD); + RecordCompositorSlowScrollMetric(type, MAIN_THREAD); // TODO(lanwei): Will remove this metric in M50 when we have used the new // metrics for one milestone, see https://crbug.com/557787. UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true); - return SCROLL_ON_MAIN_THREAD; + scroll_status.thread = SCROLL_ON_MAIN_THREAD; + return scroll_status; } return ScrollBeginImpl(scroll_state, scrolling_layer_impl, type); @@ -2631,10 +2672,16 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated( const gfx::Point& viewport_point, const gfx::Vector2dF& scroll_delta) { + InputHandler::ScrollStatus scroll_status; + scroll_status.main_thread_scrolling_reasons = NOT_SCROLLING_ON_MAIN; if (LayerImpl* layer_impl = CurrentlyScrollingLayer()) { - return ScrollAnimationUpdateTarget(layer_impl, scroll_delta) - ? SCROLL_STARTED - : SCROLL_IGNORED; + if (ScrollAnimationUpdateTarget(layer_impl, scroll_delta)) { + scroll_status.thread = SCROLL_ON_IMPL_THREAD; + } else { + scroll_status.thread = SCROLL_IGNORED; + scroll_status.main_thread_scrolling_reasons = NOT_SCROLLABLE; + } + return scroll_status; } ScrollState scroll_state(0, 0, viewport_point.x(), viewport_point.y(), 0, 0, @@ -2643,9 +2690,8 @@ // that can scroll and set up an animation of its scroll offset. Note that // this does not currently go through the scroll customization and viewport // machinery that ScrollBy uses for non-animated wheel scrolls. - InputHandler::ScrollStatus scroll_status = - ScrollBegin(&scroll_state, ANIMATED_WHEEL); - if (scroll_status == SCROLL_STARTED) { + scroll_status = ScrollBegin(&scroll_state, ANIMATED_WHEEL); + if (scroll_status.thread == SCROLL_ON_IMPL_THREAD) { gfx::Vector2dF pending_delta = scroll_delta; for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); layer_impl; layer_impl = NextLayerInScrollOrder(layer_impl)) { @@ -2674,7 +2720,7 @@ ScrollAnimationCreate(layer_impl, target_offset, current_offset); SetNeedsOneBeginImplFrame(); - return SCROLL_STARTED; + return scroll_status; } } scroll_state.set_is_ending(true); @@ -3006,9 +3052,16 @@ } InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() { - if (!CurrentlyScrollingLayer()) - return SCROLL_IGNORED; - return SCROLL_STARTED; + InputHandler::ScrollStatus scroll_status; + scroll_status.main_thread_scrolling_reasons = + InputHandler::NOT_SCROLLING_ON_MAIN; + if (!CurrentlyScrollingLayer()) { + scroll_status.thread = SCROLL_IGNORED; + scroll_status.main_thread_scrolling_reasons = NO_SCROLLING_LAYER; + } else { + scroll_status.thread = SCROLL_ON_IMPL_THREAD; + } + return scroll_status; } float LayerTreeHostImpl::DeviceSpaceDistanceToLayer( @@ -3036,9 +3089,10 @@ return; bool scroll_on_main_thread = false; + InputHandler::MainThreadScrollingReason main_thread_scrolling_reasons; LayerImpl* scroll_layer_impl = FindScrollLayerForDeviceViewportPoint( device_viewport_point, InputHandler::GESTURE, layer_impl, - &scroll_on_main_thread, NULL); + &scroll_on_main_thread, NULL, &main_thread_scrolling_reasons); if (scroll_layer_impl == InnerViewportScrollLayer()) scroll_layer_impl = OuterViewportScrollLayer(); if (scroll_on_main_thread || !scroll_layer_impl)
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 6d78c16..1e0f7f6 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -683,7 +683,9 @@ InputHandler::ScrollInputType type, LayerImpl* layer_hit_by_point, bool* scroll_on_main_thread, - bool* optional_has_ancestor_scroll_handler) const; + bool* optional_has_ancestor_scroll_handler, + InputHandler::MainThreadScrollingReason* main_thread_scrolling_reason) + const; float DeviceSpaceDistanceToLayer(const gfx::PointF& device_viewport_point, LayerImpl* layer_impl); void StartScrollbarFadeRecursive(LayerImpl* layer);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 814279e..72a3354 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -621,9 +621,12 @@ host_impl_->SetViewportSize(gfx::Size(50, 50)); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(), InputHandler::WHEEL)); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); @@ -641,9 +644,12 @@ host_impl_->SetViewportSize(gfx::Size(50, 50)); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + EXPECT_FALSE(host_impl_->IsActivelyScrolling()); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); EXPECT_TRUE(host_impl_->IsActivelyScrolling()); @@ -653,9 +659,11 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) { // We should not crash when trying to scroll an empty layer tree. - EXPECT_EQ(InputHandler::SCROLL_IGNORED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) { @@ -672,9 +680,11 @@ // We should not crash when trying to scroll after the renderer initialization // fails. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) { @@ -683,9 +693,10 @@ DrawFrame(); // We should not crash if the tree is replaced while we are scrolling. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->active_tree()->DetachLayerTree(); scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); @@ -709,30 +720,37 @@ // With registered event handlers, wheel scrolls don't necessarily // have to go to the main thread. root->SetHaveWheelEventHandlers(true); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); host_impl_->ScrollEnd(EndState().get()); // But typically the scroll-blocks-on mode will require them to. root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT | SCROLL_BLOCKS_ON_START_TOUCH); - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons); // But gesture scrolls can still be handled. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); host_impl_->ScrollEnd(EndState().get()); // And if the handlers go away, wheel scrolls can again be processed // on impl (despite the scroll-blocks-on mode). root->SetHaveWheelEventHandlers(false); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); host_impl_->ScrollEnd(EndState().get()); } @@ -762,9 +780,11 @@ EXPECT_TRUE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 10))); // But they don't influence the actual handling of the scroll gestures. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); host_impl_->ScrollEnd(EndState().get()); // It's the union of scroll-blocks-on mode bits across all layers in the @@ -785,36 +805,47 @@ // With registered scroll handlers, scrolls don't generally have to go // to the main thread. root->SetHaveScrollEventHandlers(true); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + host_impl_->ScrollEnd(EndState().get()); // Even the default scroll blocks on mode doesn't require this. root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT | SCROLL_BLOCKS_ON_START_TOUCH); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + host_impl_->ScrollEnd(EndState().get()); // But the page can opt in to blocking on scroll event handlers. root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT); - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons); // GESTURE and WHEEL scrolls behave identically in this regard. - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons); // And if the handlers go away, scrolls can again be processed on impl // (despite the scroll-blocks-on mode). root->SetHaveScrollEventHandlers(false); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + host_impl_->ScrollEnd(EndState().get()); } @@ -858,46 +889,66 @@ RebuildPropertyTrees(); } + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point(10, 10)).get(), InputHandler::GESTURE); // Scroll-blocks-on on a layer affects scrolls that hit that layer. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::GESTURE)); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); host_impl_->ScrollEnd(EndState().get()); + child1->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT); - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons); // But not those that hit only other layers. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); host_impl_->ScrollEnd(EndState().get()); // It's the union of bits set across the scroll ancestor chain that matters. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + host_impl_->ScrollEnd(EndState().get()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), - InputHandler::WHEEL)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + host_impl_->ScrollEnd(EndState().get()); root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + host_impl_->ScrollEnd(EndState().get()); - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), - InputHandler::WHEEL)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons); + child2->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT); - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), - InputHandler::WHEEL)); - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons); + + status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 25)).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::EVENT_HANDLERS, status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) { @@ -906,15 +957,23 @@ DrawFrame(); // Ignore the fling since no layer is being scrolled - EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin()); + InputHandler::ScrollStatus status = host_impl_->FlingScrollBegin(); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER, + status.main_thread_scrolling_reasons); // Start scrolling a layer - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); // Now the fling should go ahead since we've started scrolling a layer - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + status = host_impl_->FlingScrollBegin(); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) { @@ -923,15 +982,23 @@ DrawFrame(); // Ignore the fling since no layer is being scrolled - EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin()); + InputHandler::ScrollStatus status = host_impl_->FlingScrollBegin(); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER, + status.main_thread_scrolling_reasons); // Start scrolling a layer - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); // Now the fling should go ahead since we've started scrolling a layer - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + status = host_impl_->FlingScrollBegin(); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) { @@ -940,15 +1007,21 @@ DrawFrame(); LayerImpl* root = host_impl_->active_tree()->root_layer(); - root->SetShouldScrollOnMainThread(true); + root->set_main_thread_scrolling_reasons( + InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS); // Start scrolling a layer - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS, + status.main_thread_scrolling_reasons); // The fling should be ignored since there's no layer being scrolled impl-side - EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin()); + status = host_impl_->FlingScrollBegin(); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) { @@ -957,14 +1030,20 @@ DrawFrame(); LayerImpl* root = host_impl_->active_tree()->root_layer(); - root->SetShouldScrollOnMainThread(true); + root->set_main_thread_scrolling_reasons( + InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS); - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS, + status.main_thread_scrolling_reasons); + + status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) { @@ -977,21 +1056,29 @@ DrawFrame(); // All scroll types inside the non-fast scrollable region should fail. - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(25, 25)).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point(25, 25)).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::NON_FAST_SCROLLABLE_REGION, + status.main_thread_scrolling_reasons); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25), InputHandler::WHEEL)); - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(25, 25)).get(), - InputHandler::GESTURE)); + + status = host_impl_->ScrollBegin(BeginState(gfx::Point(25, 25)).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::NON_FAST_SCROLLABLE_REGION, + status.main_thread_scrolling_reasons); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25), InputHandler::GESTURE)); // All scroll types outside this region should succeed. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(), - InputHandler::WHEEL)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75), InputHandler::GESTURE)); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); @@ -1000,9 +1087,12 @@ host_impl_->ScrollEnd(EndState().get()); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75), InputHandler::GESTURE)); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(), - InputHandler::GESTURE)); + + status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(), + InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75), InputHandler::GESTURE)); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); @@ -1024,18 +1114,23 @@ // This point would fall into the non-fast scrollable region except that we've // moved the layer down by 25 pixels. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point(40, 10)).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point(40, 10)).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(40, 10), InputHandler::WHEEL)); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 1)).get()); host_impl_->ScrollEnd(EndState().get()); // This point is still inside the non-fast region. - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::WHEEL)); + status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::NON_FAST_SCROLLABLE_REGION, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, ScrollHandlerNotPresent) { @@ -1072,9 +1167,11 @@ DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::GESTURE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); // Trying to scroll to the left/top will not succeed. EXPECT_FALSE( @@ -1145,9 +1242,10 @@ DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); // Trying to scroll if not user_scrollable_vertical will fail. host_impl_->InnerViewportScrollLayer()->set_user_scrollable_vertical(false); @@ -1180,9 +1278,10 @@ DrawFrame(); gfx::Point scroll_position(10, 10); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(scroll_position).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), overflow->CurrentScrollOffset()); @@ -1194,9 +1293,10 @@ overflow->set_user_scrollable_horizontal(false); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(scroll_position).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->CurrentScrollOffset()); @@ -1207,9 +1307,10 @@ overflow->set_user_scrollable_vertical(false); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(scroll_position).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset()); @@ -1556,9 +1657,10 @@ host_impl_->ScrollEnd(EndState().get()); gfx::Vector2d scroll_delta(0, 10); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -1907,9 +2009,10 @@ new LatencyInfoSwapPromise(latency_info)); SetupScrollAndContentsLayers(gfx::Size(100, 100)); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); host_impl_->QueueSwapPromiseForMainThreadScrollUpdate( std::move(swap_promise)); @@ -3036,9 +3139,10 @@ } // Scrolling should update metadata immediately. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); { CompositorFrameMetadata metadata = @@ -3669,9 +3773,11 @@ DrawFrame(); // Scroll event is ignored because layer is not scrollable. - EXPECT_EQ(InputHandler::SCROLL_IGNORED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER, + status.main_thread_scrolling_reasons); EXPECT_FALSE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); } @@ -3817,9 +3923,10 @@ EXPECT_EQ(gfx::SizeF(50, 50), active_tree->ScrollableSize()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->top_controls_manager()->ScrollBegin(); @@ -3860,9 +3967,10 @@ gfx::Size(10, 10), gfx::Size(10, 10), gfx::Size(10, 10)); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); // Make the test scroll delta a fractional amount, to verify that the // fixed container size delta is (1) non-zero, and (2) fractional, and @@ -3904,9 +4012,10 @@ outer_scroll->SetDrawsContent(true); host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 1.f, 2.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0.f, 50.f)).get()); @@ -3926,9 +4035,10 @@ host_impl_->ScrollEnd(EndState().get()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll); host_impl_->ScrollBy( @@ -3979,9 +4089,10 @@ // not be scaled. host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, 2.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); // Scroll down, the top controls hiding should expand the viewport size so // the delta should be equal to the scroll distance. @@ -4028,9 +4139,10 @@ // Scroll 25px to hide top controls gfx::Vector2dF scroll_delta(0.f, 25.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_FALSE(did_request_commit_); } @@ -4072,9 +4184,10 @@ gfx::Vector2dF scroll_delta(0.f, 25.f); host_impl_->active_tree()->property_trees()->needs_rebuild = true; host_impl_->active_tree()->BuildPropertyTreesForTesting(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4232,9 +4345,10 @@ // Hide the top controls by 25px. gfx::Vector2dF scroll_delta(0.f, 25.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); // scrolling down at the max extents no longer hides the top controls @@ -4259,9 +4373,10 @@ // Bring the top controls down by 25px. scroll_delta = gfx::Vector2dF(0.f, -25.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4288,9 +4403,10 @@ host_impl_->top_controls_manager()->ContentTopOffset()); gfx::Vector2dF scroll_delta(0.f, 25.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4329,9 +4445,10 @@ // Send a gesture scroll that will scroll the outer viewport, make sure the // top controls get scrolled. gfx::Vector2dF scroll_delta(0.f, 15.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_EQ(host_impl_->InnerViewportScrollLayer(), @@ -4343,9 +4460,10 @@ host_impl_->top_controls_manager()->ContentTopOffset()); scroll_delta = gfx::Vector2dF(0.f, 50.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_EQ(0, host_impl_->top_controls_manager()->ContentTopOffset()); @@ -4360,9 +4478,10 @@ host_impl_->InnerViewportScrollLayer()->SetScrollDelta(inner_viewport_offset); scroll_delta = gfx::Vector2dF(0.f, -65.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_EQ(top_controls_height_, @@ -4382,9 +4501,10 @@ layer_size_, layer_size_, layer_size_); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->top_controls_manager()->ScrollBegin(); host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f)); @@ -4397,9 +4517,10 @@ host_impl_->ScrollEnd(EndState().get()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); float scroll_increment_y = -25.f; host_impl_->top_controls_manager()->ScrollBegin(); @@ -4427,9 +4548,10 @@ gfx::ScrollOffset(), host_impl_->active_tree()->InnerViewportScrollLayer()->MaxScrollOffset()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); } TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) { @@ -4461,9 +4583,10 @@ host_impl_->SetViewportSize(surface_size); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); host_impl_->ScrollEnd(EndState().get()); EXPECT_TRUE(did_request_redraw_); @@ -4481,9 +4604,10 @@ host_impl_->SetViewportSize(surface_size); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); host_impl_->ScrollEnd(EndState().get()); EXPECT_TRUE(did_request_redraw_); @@ -4501,9 +4625,12 @@ // Scroll event is ignored because the input coordinate is outside the layer // boundaries. - EXPECT_EQ(InputHandler::SCROLL_IGNORED, - host_impl_->ScrollBegin(BeginState(gfx::Point(15, 5)).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point(15, 5)).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER, + status.main_thread_scrolling_reasons); + EXPECT_FALSE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); } @@ -4527,9 +4654,12 @@ // Scroll event is ignored because the scrollable layer is not facing the // viewer and there is nothing scrollable behind it. - EXPECT_EQ(InputHandler::SCROLL_IGNORED, - host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NO_SCROLLING_LAYER, + status.main_thread_scrolling_reasons); + EXPECT_FALSE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); } @@ -4540,7 +4670,8 @@ LayerImpl::Create(host_impl_->active_tree(), 3); scoped_ptr<LayerImpl> content_layer = CreateScrollableLayer(1, surface_size, clip_layer.get()); - content_layer->SetShouldScrollOnMainThread(true); + content_layer->set_main_thread_scrolling_reasons( + InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS); content_layer->SetScrollClipLayer(Layer::INVALID_ID); // Note: we can use the same clip layer for both since both calls to @@ -4557,9 +4688,11 @@ // Scrolling fails because the content layer is asking to be scrolled on the // main thread. - EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::HAS_BACKGROUND_ATTACHMENT_FIXED_OBJECTS, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { @@ -4585,9 +4718,10 @@ gfx::Vector2d scroll_delta(0, 10); gfx::Vector2d expected_scroll_delta = scroll_delta; gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4629,9 +4763,10 @@ gfx::Vector2d scroll_delta(0, 10); gfx::Vector2d expected_scroll_delta = scroll_delta; gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4726,9 +4861,10 @@ gfx::Vector2d scroll_delta(0, 10); gfx::Vector2d expected_scroll_delta(scroll_delta); gfx::ScrollOffset expected_max_scroll(outer_scroll->MaxScrollOffset()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4777,9 +4913,10 @@ DrawFrame(); { gfx::Vector2d scroll_delta(-8, -7); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4837,9 +4974,10 @@ DrawFrame(); { gfx::Vector2d scroll_delta(0, -10); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::NON_BUBBLING_GESTURE)); + InputHandler::NON_BUBBLING_GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4862,9 +5000,10 @@ // The next time we scroll we should only scroll the parent. scroll_delta = gfx::Vector2d(0, -3); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::NON_BUBBLING_GESTURE)); + InputHandler::NON_BUBBLING_GESTURE) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child); @@ -4883,9 +5022,10 @@ // After scrolling the parent, another scroll on the opposite direction // should still scroll the child. scroll_delta = gfx::Vector2d(0, 7); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::NON_BUBBLING_GESTURE)); + InputHandler::NON_BUBBLING_GESTURE) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); @@ -4906,9 +5046,10 @@ host_impl_->active_tree()->SetPageScaleOnActiveTree(2.f); scroll_delta = gfx::Vector2d(0, -2); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), - InputHandler::NON_BUBBLING_GESTURE)); + InputHandler::NON_BUBBLING_GESTURE) + .thread); EXPECT_EQ(grand_child, host_impl_->CurrentlyScrollingLayer()); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4952,9 +5093,10 @@ DrawFrame(); { gfx::Vector2d scroll_delta(0, 4); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5007,9 +5149,10 @@ // Scrolling should still work even though we did not draw yet. RebuildPropertyTrees(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); } TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) { @@ -5027,9 +5170,10 @@ // Scroll to the right in screen coordinates with a gesture. gfx::Vector2d gesture_scroll_delta(10, 0); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5041,9 +5185,10 @@ // Reset and scroll down with the wheel. scroll_layer->SetScrollDelta(gfx::Vector2dF()); gfx::Vector2d wheel_scroll_delta(0, 10); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), wheel_scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5088,9 +5233,10 @@ { // Scroll down in screen coordinates with a gesture. gfx::Vector2d gesture_scroll_delta(0, 10); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5112,9 +5258,10 @@ // Now reset and scroll the same amount horizontally. child_ptr->SetScrollDelta(gfx::Vector2dF()); gfx::Vector2d gesture_scroll_delta(10, 0); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5191,9 +5338,10 @@ for (int i = 0; i < 4; ++i) { child_ptr->SetScrollDelta(gfx::Vector2dF()); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(viewport_point).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy( UpdateState(viewport_point, gesture_scroll_deltas[i]).get()); viewport_point += gesture_scroll_deltas[i]; @@ -5225,9 +5373,10 @@ // Scroll down in screen coordinates with a gesture. gfx::Vector2d scroll_delta(0, 10); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5240,9 +5389,10 @@ // Reset and scroll down with the wheel. scroll_layer->SetScrollDelta(gfx::Vector2dF()); gfx::Vector2d wheel_scroll_delta(0, 10); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), wheel_scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5394,9 +5544,10 @@ gfx::Vector2dF scroll_delta(0.f, 10.f); gfx::ScrollOffset current_offset(7.f, 8.f); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); host_impl_->SetSynchronousInputHandlerRootScrollOffset(current_offset); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -5470,9 +5621,10 @@ EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); // In-bounds scrolling does not affect overscroll. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); EXPECT_TRUE(scroll_result.did_scroll); @@ -5619,9 +5771,10 @@ DrawFrame(); { gfx::Vector2d scroll_delta(0, -10); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::NON_BUBBLING_GESTURE)); + InputHandler::NON_BUBBLING_GESTURE) + .thread); scroll_result = host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_TRUE(scroll_result.did_scroll); @@ -5632,9 +5785,10 @@ // The next time we scroll we should only scroll the parent, but overscroll // should still not reach the root layer. scroll_delta = gfx::Vector2d(0, -30); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::NON_BUBBLING_GESTURE)); + InputHandler::NON_BUBBLING_GESTURE) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); scroll_result = @@ -5648,9 +5802,10 @@ // After scrolling the parent, another scroll on the opposite direction // should scroll the child. scroll_delta = gfx::Vector2d(0, 70); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::NON_BUBBLING_GESTURE)); + InputHandler::NON_BUBBLING_GESTURE) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer); scroll_result = host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -5671,9 +5826,10 @@ DrawFrame(); { gfx::Vector2d scroll_delta(0, 8); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); scroll_result = host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_TRUE(scroll_result.did_scroll); @@ -5707,9 +5863,10 @@ EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); // Even though the layer can't scroll the overscroll still happens. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); EXPECT_FALSE(scroll_result.did_scroll); @@ -5726,9 +5883,10 @@ // Edge glow effect should be applicable only upon reaching Edges // of the content. unnecessary glow effect calls shouldn't be // called while scrolling up without reaching the edge of the content. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0, 100)).get()); EXPECT_TRUE(scroll_result.did_scroll); @@ -5744,10 +5902,12 @@ host_impl_->ScrollEnd(EndState().get()); // unusedrootDelta should be subtracted from applied delta so that // unwanted glow effect calls are not called. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::NON_BUBBLING_GESTURE)); - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), + InputHandler::NON_BUBBLING_GESTURE) + .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->FlingScrollBegin().thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0, 20)).get()); EXPECT_TRUE(scroll_result.did_scroll); @@ -5764,9 +5924,10 @@ host_impl_->ScrollEnd(EndState().get()); // TestCase to check kEpsilon, which prevents minute values to trigger // gloweffect without reaching edge. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(-0.12f, 0.1f)).get()); EXPECT_FALSE(scroll_result.did_scroll); @@ -7460,11 +7621,13 @@ host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->FlingScrollBegin().thread); gfx::Vector2d scroll_delta(0, 100); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -7513,9 +7676,10 @@ LayerImpl* grand_child = child->children()[0].get(); gfx::Vector2d scroll_delta(0, -2); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_TRUE( host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()) .did_scroll); @@ -7538,7 +7702,8 @@ ExpectNone(*scroll_info, child->id()); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->FlingScrollBegin().thread); EXPECT_FALSE( host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()) .did_scroll); @@ -7581,11 +7746,13 @@ host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->FlingScrollBegin().thread); gfx::Vector2d scroll_delta(0, 100); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -7629,9 +7796,11 @@ DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread); + EXPECT_EQ(InputHandler::FAILED_HIT_TEST, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, ScrollUnknownScrollAncestorMismatch) { @@ -7668,9 +7837,11 @@ DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point()).get(), InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread); + EXPECT_EQ(InputHandler::FAILED_HIT_TEST, + status.main_thread_scrolling_reasons); } TEST_F(LayerTreeHostImplTest, NotScrollInvisibleScroller) { @@ -7698,9 +7869,10 @@ // // Why SCROLL_STARTED? In this case, it's because we've bubbled out and // started scrolling the inner viewport. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); EXPECT_EQ(2, host_impl_->CurrentlyScrollingLayer()->id()); } @@ -7735,9 +7907,10 @@ // We should have scrolled |invisible_scroll_layer| as it was hit and it has // a descendant which is a drawn RSLL member. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); EXPECT_EQ(7, host_impl_->CurrentlyScrollingLayer()->id()); } @@ -7789,9 +7962,10 @@ // We should have scrolled |child_scroll| even though it is invisible. // The reason for this is that if the scrolling the scroll would move a layer // that is a drawn RSLL member, then we should accept this hit. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); EXPECT_EQ(7, host_impl_->CurrentlyScrollingLayer()->id()); } @@ -7981,9 +8155,10 @@ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); // Scrolling normally should not trigger any forwarding. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_TRUE( host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()) @@ -7997,9 +8172,10 @@ // Scrolling with a scroll handler should defer the swap to the main // thread. scroll_layer->SetHaveScrollEventHandlers(true); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_TRUE( host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()) @@ -8080,9 +8256,10 @@ BOTH, SHOWN, false); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->CurrentScrollOffset().ToString()); @@ -8154,9 +8331,10 @@ LayerImpl* viewport_layer = host_impl_->InnerViewportScrollLayer(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), viewport_layer->CurrentScrollOffset()); @@ -8187,9 +8365,10 @@ BOTH, SHOWN, false); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->CurrentScrollOffset().ToString()); @@ -8264,9 +8443,10 @@ gfx::ScrollOffset(0, initial_scroll_offset)); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(), scroll_layer->CurrentScrollOffset().ToString()); @@ -8334,9 +8514,10 @@ gfx::ScrollOffset(0, initial_scroll_offset)); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(), scroll_layer->CurrentScrollOffset().ToString()); @@ -8402,9 +8583,10 @@ false); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); float offset = 50; @@ -8577,11 +8759,13 @@ // Scrolling the viewport always sets the outer scroll layer as the // currently scrolling layer. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->FlingScrollBegin().thread); EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); gfx::Vector2d scroll_delta(inner_viewport.width() / 2.f, @@ -8597,11 +8781,13 @@ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset()); // Fling past the inner viewport boundry, make sure outer viewport scrolls. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->FlingScrollBegin().thread); EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -8638,10 +8824,12 @@ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset()); // Make sure the scroll goes to the inner viewport first. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + InputHandler::GESTURE) + .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->FlingScrollBegin().thread); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(), InputHandler::GESTURE)); @@ -8695,9 +8883,10 @@ scoped_ptr<ScrollAndScaleSet> scroll_info; gfx::Vector2d scroll_delta(0, inner_viewport.height()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_TRUE( host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()) .did_scroll); @@ -8712,7 +8901,8 @@ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll); // The fling have no effect on the currently scrolling layer. - EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->FlingScrollBegin().thread); EXPECT_FALSE( host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()) .did_scroll); @@ -8756,14 +8946,16 @@ DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->RootScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll); host_impl_->ScrollEnd(EndState().get()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll); host_impl_->ScrollEnd(EndState().get()); } @@ -8784,9 +8976,10 @@ // Ensure inner viewport doesn't react to scrolls (test it's unscrollable). EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll->CurrentScrollOffset()); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE)); + InputHandler::GESTURE) + .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0, 100)).get()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll->CurrentScrollOffset()); @@ -9089,8 +9282,9 @@ BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50))); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread); LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer(); EXPECT_EQ(host_impl_->OuterViewportScrollLayer(), scrolling_layer); @@ -9113,8 +9307,9 @@ EXPECT_TRUE(y > 1 && y < 49); // Update target. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50))); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread); host_impl_->DidFinishImplFrame(); begin_frame_args.frame_time = @@ -9153,8 +9348,9 @@ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); // Perform animated scroll. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50))); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread); LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer(); @@ -9179,9 +9375,10 @@ EXPECT_TRUE(y > 1 && y < 49); // Perform instant scroll. - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point(0, y)).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, y), InputHandler::WHEEL)); host_impl_->ScrollBy( @@ -9217,8 +9414,9 @@ BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50))); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread); LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer(); @@ -9240,8 +9438,9 @@ EXPECT_TRUE(y > 1 && y < 49); // Update target. - EXPECT_EQ(InputHandler::SCROLL_STARTED, - host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50))); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)).thread); host_impl_->DidFinishImplFrame(); begin_frame_args.frame_time = @@ -9379,9 +9578,10 @@ host_impl_->ScrollEnd(EndState().get()); gfx::Vector2dF scroll_delta(0, 5); - EXPECT_EQ(InputHandler::SCROLL_STARTED, + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL)); + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index ac20d47f..6d34140 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -608,7 +608,7 @@ gfx::Vector2dF(0.5f, 0.5f)); InputHandler::ScrollStatus status = impl->ScrollBegin( BeginState(scroll_point).get(), InputHandler::GESTURE); - EXPECT_EQ(InputHandler::SCROLL_STARTED, status); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); impl->ScrollBy(UpdateState(gfx::Point(), scroll_amount_).get()); LayerImpl* scrolling_layer = impl->CurrentlyScrollingLayer(); CHECK(scrolling_layer); @@ -631,7 +631,7 @@ gfx::Vector2dF(0.5f, 0.5f)); InputHandler::ScrollStatus status = impl->ScrollBegin( BeginState(scroll_point).get(), InputHandler::WHEEL); - EXPECT_EQ(InputHandler::SCROLL_STARTED, status); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); impl->ScrollBy(UpdateState(gfx::Point(), scroll_amount_).get()); impl->ScrollEnd(EndState().get()); @@ -1034,24 +1034,29 @@ // Set max_scroll_offset = (100, 100). scroll_layer->SetBounds( gfx::Size(root->bounds().width() + 100, root->bounds().height() + 100)); - EXPECT_EQ( - InputHandler::SCROLL_STARTED, - scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, - SCROLL_BLOCKS_ON_NONE)); + + InputHandler::ScrollStatus status = scroll_layer->TryScroll( + gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE); + + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); // Set max_scroll_offset = (0, 0). scroll_layer->SetBounds(root->bounds()); - EXPECT_EQ( - InputHandler::SCROLL_IGNORED, - scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, - SCROLL_BLOCKS_ON_NONE)); + status = scroll_layer->TryScroll( + gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLABLE, + status.main_thread_scrolling_reasons); // Set max_scroll_offset = (-100, -100). scroll_layer->SetBounds(gfx::Size()); - EXPECT_EQ( - InputHandler::SCROLL_IGNORED, - scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, - SCROLL_BLOCKS_ON_NONE)); + status = scroll_layer->TryScroll( + gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE); + EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLABLE, + status.main_thread_scrolling_reasons); EndTest(); } @@ -1085,14 +1090,18 @@ // Verify that the scroll layer's scroll offset is taken into account when // checking whether the screen space point is inside the non-fast // scrollable region. - EXPECT_EQ( - InputHandler::SCROLL_ON_MAIN_THREAD, - scroll_layer->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::GESTURE, - SCROLL_BLOCKS_ON_NONE)); - EXPECT_EQ( - InputHandler::SCROLL_STARTED, - scroll_layer->TryScroll(gfx::PointF(21.f, 21.f), InputHandler::GESTURE, - SCROLL_BLOCKS_ON_NONE)); + + InputHandler::ScrollStatus status = scroll_layer->TryScroll( + gfx::PointF(1.f, 1.f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); + EXPECT_EQ(InputHandler::NON_FAST_SCROLLABLE_REGION, + status.main_thread_scrolling_reasons); + + status = scroll_layer->TryScroll( + gfx::PointF(21.f, 21.f), InputHandler::GESTURE, SCROLL_BLOCKS_ON_NONE); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(InputHandler::NOT_SCROLLING_ON_MAIN, + status.main_thread_scrolling_reasons); EndTest(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java index 440624e..1b9d64f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -372,12 +372,8 @@ * when the user has navigated elsewhere manually in the same tab. * @throws InterruptedException */ - /** - * @LargeTest - * @Feature({"Navigation"}) - * Bug 6467101 - */ - @FlakyTest + @LargeTest + @Feature({"Navigation"}) public void testNewTabAfterNavigation() throws InterruptedException { startMainActivityFromLauncher();
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 5a89dab..87bcd4c2 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -858,7 +858,6 @@ "//third_party/isimpledom", "//third_party/wtl", "//ui/metro_viewer", - "//win8:metro_viewer", ] all_dependent_configs = [ ":browser_win_linker_flags" ]
diff --git a/chrome/browser/browser_process_platform_part.h b/chrome/browser/browser_process_platform_part.h index d39671b1..08d1eda5 100644 --- a/chrome/browser/browser_process_platform_part.h +++ b/chrome/browser/browser_process_platform_part.h
@@ -14,8 +14,6 @@ #include "chrome/browser/browser_process_platform_part_chromeos.h" #elif defined(OS_MACOSX) && !defined(OS_IOS) #include "chrome/browser/browser_process_platform_part_mac.h" -#elif defined(OS_WIN) -#include "chrome/browser/browser_process_platform_part_aurawin.h" #else #include "chrome/browser/browser_process_platform_part_base.h" typedef BrowserProcessPlatformPartBase BrowserProcessPlatformPart;
diff --git a/chrome/browser/browser_process_platform_part_aurawin.cc b/chrome/browser/browser_process_platform_part_aurawin.cc deleted file mode 100644 index dd6635bf..0000000 --- a/chrome/browser/browser_process_platform_part_aurawin.cc +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/browser_process_platform_part_aurawin.h" - -#include "base/command_line.h" -#include "base/logging.h" -#include "base/prefs/pref_service.h" -#include "base/process/kill.h" -#include "base/win/windows_version.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/first_run/upgrade_util.h" -#include "chrome/browser/first_run/upgrade_util_win.h" -#include "chrome/browser/lifetime/application_lifetime.h" -#include "chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/pref_names.h" -#include "content/public/browser/notification_service.h" - -#include "ui/aura/remote_window_tree_host_win.h" -#include "ui/base/ui_base_switches.h" - -BrowserProcessPlatformPart::BrowserProcessPlatformPart() { - if (base::win::GetVersion() >= base::win::VERSION_WIN7) { - // Tell metro viewer to close when we are shutting down. - registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, - content::NotificationService::AllSources()); - } -} - -BrowserProcessPlatformPart::~BrowserProcessPlatformPart() { -} - -void BrowserProcessPlatformPart::OnMetroViewerProcessTerminated() { - metro_viewer_process_host_.reset(NULL); -} - -void BrowserProcessPlatformPart::PlatformSpecificCommandLineProcessing( - const base::CommandLine& command_line) { - // Check for Windows 8 specific commandlines requesting that this process - // either connect to an existing viewer or launch a new viewer and - // synchronously wait for it to connect. - - bool launch = command_line.HasSwitch(switches::kViewerLaunchViaAppId); - bool connect = (launch || - (command_line.HasSwitch(switches::kViewerConnect) && - !metro_viewer_process_host_.get())); - if (!connect) - return; - // Create a host to connect to the Metro viewer process over IPC. - metro_viewer_process_host_.reset(new ChromeMetroViewerProcessHost()); - if (launch) { - CHECK(metro_viewer_process_host_->LaunchViewerAndWaitForConnection( - command_line.GetSwitchValueNative( - switches::kViewerLaunchViaAppId))); - } -} - -void BrowserProcessPlatformPart::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - - DCHECK(type == chrome::NOTIFICATION_APP_TERMINATING); - PrefService* pref_service = g_browser_process->local_state(); - bool is_relaunch = pref_service->GetBoolean(prefs::kWasRestarted); - if (is_relaunch) { - // TODO(scottmg): A lot of this can be removed http://crbug.com/558054. - } -}
diff --git a/chrome/browser/browser_process_platform_part_aurawin.h b/chrome/browser/browser_process_platform_part_aurawin.h deleted file mode 100644 index 06dec47..0000000 --- a/chrome/browser/browser_process_platform_part_aurawin.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_BROWSER_PROCESS_PLATFORM_PART_AURAWIN_H_ -#define CHROME_BROWSER_BROWSER_PROCESS_PLATFORM_PART_AURAWIN_H_ - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/browser_process_platform_part_base.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" - -class ChromeMetroViewerProcessHost; - -class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase, - public content::NotificationObserver { - public: - BrowserProcessPlatformPart(); - ~BrowserProcessPlatformPart() override; - - // Invoked when the ASH metro viewer process on Windows 8 exits. - void OnMetroViewerProcessTerminated(); - - // Overridden from BrowserProcessPlatformPartBase: - void PlatformSpecificCommandLineProcessing( - const base::CommandLine& command_line) override; - - // content::NotificationObserver method: - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - private: - // Hosts the channel for the Windows 8 metro viewer process which runs in - // the ASH environment. - scoped_ptr<ChromeMetroViewerProcessHost> metro_viewer_process_host_; - - content::NotificationRegistrar registrar_; - - DISALLOW_COPY_AND_ASSIGN(BrowserProcessPlatformPart); -}; - -#endif // CHROME_BROWSER_BROWSER_PROCESS_PLATFORM_PART_AURAWIN_H_
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc index e77c8da..3bb43cd 100644 --- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc +++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
@@ -248,16 +248,16 @@ emk::kWebview, }; -// List of permissions based on [1] and [2]. Since Public Session users may be -// fully unaware of any apps being installed, their consent to access any kind -// of sensitive information cannot be assumed. Therefore only APIs are -// whitelisted which should not leak sensitive data to the caller. Since the -// privacy boundary is drawn at the API level, no safeguards are required to -// prevent exfiltration and thus apps may communicate freely over any kind of -// network. +// List of permission strings based on [1] and [2]. See |kSafePermissionDicts| +// for permission dicts. Since Public Session users may be fully unaware of any +// apps being installed, their consent to access any kind of sensitive +// information cannot be assumed. Therefore only APIs are whitelisted which +// should not leak sensitive data to the caller. Since the privacy boundary is +// drawn at the API level, no safeguards are required to prevent exfiltration +// and thus apps may communicate freely over any kind of network. // [1] https://developer.chrome.com/apps/declare_permissions // [2] https://developer.chrome.com/apps/api_other -const char* const kSafePermissions[] = { +const char* const kSafePermissionStrings[] = { // Risky: Reading accessibility settings could allow to infer health // information. // "accessibilityFeatures.read", @@ -310,9 +310,6 @@ "overrideEscFullscreen", // TBD - // "fileSystem", - - // TBD // "fileSystemProvider", // Just another type of connectivity. On the system side, no user data is @@ -356,12 +353,6 @@ // is stored on a serial device and being read without the user's consent. "serial", - // Just another type of connectivity. - "socket", - - // Just another type of connectivity. - "sockets", - // Per-app sandbox. User cannot log into Public Session, thus storage // cannot be sync'ed to the cloud. "storage", @@ -403,6 +394,16 @@ "webview", }; +// Some permissions take the form of a dictionary. See |kSafePermissionStrings| +// for permission strings (and for more documentation). +const char* const kSafePermissionDicts[] = { + // TBD + // "fileSystem", + + // Just another type of connectivity. + "socket", +}; + // Return true iff |entry| is contained in |char_array|. bool ArrayContainsImpl(const char* const char_array[], size_t entry_count, @@ -426,7 +427,7 @@ // Returns true for platform apps that are considered safe for Public Sessions, // which among other things requires the manifest top-level entries to be // contained in the |kSafeManifestEntries| whitelist and all permissions to be -// contained in |kSafePermissions|. +// contained in |kSafePermissionStrings| or |kSafePermissionDicts|. bool IsPlatformAppSafeForPublicSession(const extensions::Extension* extension) { if (extension->GetType() != extensions::Manifest::TYPE_PLATFORM_APP) { LOG(ERROR) << extension->id() << " is not a platform app."; @@ -439,22 +440,45 @@ continue; } - // Permissions must be whitelisted in |kSafePermissions|. + // Permissions must be whitelisted in |kSafePermissionStrings| or + // |kSafePermissionDicts|. if (it.key() == emk::kPermissions || it.key() == emk::kOptionalPermissions) { const base::ListValue* list_value; if (!it.value().GetAsList(&list_value)) { - LOG(ERROR) << it.key() << " is not a list."; + LOG(ERROR) << extension->id() << ": " << it.key() << " is not a list."; return false; } for (auto it2 = list_value->begin(); it2 != list_value->end(); ++it2) { + // Try to read as dictionary. + const base::DictionaryValue *dict_value; + if ((*it2)->GetAsDictionary(&dict_value)) { + if (dict_value->size() != 1) { + LOG(ERROR) << extension->id() + << " has dict in permission list with size " + << dict_value->size() << "."; + return false; + } + for (base::DictionaryValue::Iterator it3(*dict_value); + !it3.IsAtEnd(); it3.Advance()) { + if (!ArrayContains(kSafePermissionDicts, it3.key())) { + LOG(ERROR) << extension->id() + << " has non-whitelisted dict in permission list: " + << it3.key(); + return false; + } + } + continue; + } + // Try to read as string. std::string permission_string; if (!(*it2)->GetAsString(&permission_string)) { - LOG(ERROR) << it.key() << " contains a non-string."; + LOG(ERROR) << extension->id() << ": " << it.key() + << " contains a token that's neither a string nor a dict."; return false; } // Accept whitelisted permissions. - if (ArrayContains(kSafePermissions, permission_string)) { + if (ArrayContains(kSafePermissionStrings, permission_string)) { continue; } // Allow arbitrary web requests. Don't include <all_urls> because that @@ -473,7 +497,7 @@ } else if (it.key() == emk::kApp) { const base::DictionaryValue *dict_value; if (!it.value().GetAsDictionary(&dict_value)) { - LOG(ERROR) << extension->id() << " app is not a dictionary."; + LOG(ERROR) << extension->id() << ": app is not a dictionary."; return false; } for (base::DictionaryValue::Iterator it2(*dict_value); @@ -485,12 +509,11 @@ return false; } } - // Require v2 because that's the only version - // IsPlatformAppSafeForPublicSession() understands. + // Require v2 because that's the only version we understand. } else if (it.key() == emk::kManifestVersion) { int version; if (!it.value().GetAsInteger(&version)) { - LOG(ERROR) << extension->id() << " " << emk::kManifestVersion + LOG(ERROR) << extension->id() << ": " << emk::kManifestVersion << " is not an integer."; return false; }
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc index b7e95e3..d428bf5d 100644 --- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc +++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
@@ -377,6 +377,52 @@ EXPECT_NE(base::string16(), error); error.clear(); } + + // Verify that a platform app with socket dictionary permission can be + // installed. + { + base::DictionaryValue* const socket = new base::DictionaryValue(); + base::ListValue* const tcp_list = new base::ListValue(); + tcp_list->AppendString("tcp-connect"); + socket->Set("socket", tcp_list); + base::ListValue* const permissions = new base::ListValue(); + permissions->Append(socket); + base::DictionaryValue values; + values.Set(extensions::manifest_keys::kPermissions, permissions); + + extension = CreatePlatformAppWithExtraValues( + &values, + extensions::Manifest::EXTERNAL_POLICY, + extensions::Extension::NO_FLAGS); + ASSERT_TRUE(extension); + + EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error)); + EXPECT_EQ(base::string16(), error); + error.clear(); + } + + // Verify that a platform app with unknown dictionary permission cannot be + // installed. + { + base::DictionaryValue* const socket = new base::DictionaryValue(); + base::ListValue* const tcp_list = new base::ListValue(); + tcp_list->AppendString("unknown_value"); + socket->Set("unknown_key", tcp_list); + base::ListValue* const permissions = new base::ListValue(); + permissions->Append(socket); + base::DictionaryValue values; + values.Set(extensions::manifest_keys::kPermissions, permissions); + + extension = CreatePlatformAppWithExtraValues( + &values, + extensions::Manifest::EXTERNAL_POLICY, + extensions::Extension::NO_FLAGS); + ASSERT_TRUE(extension); + + EXPECT_FALSE(provider.UserMayLoad(extension.get(), &error)); + EXPECT_NE(base::string16(), error); + error.clear(); + } } TEST(DeviceLocalAccountManagementPolicyProviderTest, KioskAppSession) {
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc index dbd4db73..1133fe8 100644 --- a/chrome/browser/engagement/site_engagement_service.cc +++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -228,6 +228,14 @@ last_engagement_time_ = now; } +void SiteEngagementScore::Reset(double points) { + raw_score_ = points; + points_added_today_ = 0; + + // This must be set in order to prevent the score from decaying when read. + last_engagement_time_ = clock_->Now(); +} + bool SiteEngagementScore::MaxPointsPerDayAdded() { if (!last_engagement_time_.is_null() && clock_->Now().LocalMidnight() != last_engagement_time_.LocalMidnight()) { @@ -379,6 +387,25 @@ RecordMetrics(); } +void SiteEngagementService::ResetScoreForURL(const GURL& url, double score) { + DCHECK(url.is_valid()); + DCHECK_GE(score, 0); + DCHECK_LE(score, SiteEngagementScore::kMaxPoints); + + HostContentSettingsMap* settings_map = + HostContentSettingsMapFactory::GetForProfile(profile_); + scoped_ptr<base::DictionaryValue> score_dict = + GetScoreDictForOrigin(settings_map, url); + SiteEngagementScore engagement_score(clock_.get(), *score_dict); + + engagement_score.Reset(score); + if (engagement_score.UpdateScoreDict(score_dict.get())) { + settings_map->SetWebsiteSettingDefaultScope( + url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), + score_dict.release()); + } +} + void SiteEngagementService::OnURLsDeleted( history::HistoryService* history_service, bool all_history,
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h index 53ad612..fe75f74d 100644 --- a/chrome/browser/engagement/site_engagement_service.h +++ b/chrome/browser/engagement/site_engagement_service.h
@@ -84,6 +84,9 @@ double Score() const; void AddPoints(double points); + // Resets the score to |points| and reset the daily point limit. + void Reset(double points); + // Returns true if the maximum number of points today has been added. bool MaxPointsPerDayAdded(); @@ -100,6 +103,7 @@ private: FRIEND_TEST_ALL_PREFIXES(SiteEngagementScoreTest, PartiallyEmptyDictionary); FRIEND_TEST_ALL_PREFIXES(SiteEngagementScoreTest, PopulatedDictionary); + FRIEND_TEST_ALL_PREFIXES(SiteEngagementScoreTest, Reset); friend class SiteEngagementScoreTest; // Array holding the values corresponding to each item in Variation array. @@ -181,19 +185,22 @@ // Returns a map of all stored origins and their engagement scores. std::map<GURL, double> GetScoreMap(); - // Update the karma score of the origin matching |url| for navigation. + // Update the engagement score of the origin matching |url| for navigation. void HandleNavigation(const GURL& url, ui::PageTransition transition); - // Update the karma score of the origin matching |url| for time-on-site, based - // on user input. + // Update the engagement score of the origin matching |url| for time-on-site, + // based on user input. void HandleUserInput(const GURL& url, SiteEngagementMetrics::EngagementType type); - // Update the karma score of the origin matching |url| for media playing. The - // points awarded are discounted if the media is being played in a non-visible - // tab. + // Update the engagement score of the origin matching |url| for media playing. + // The points awarded are discounted if the media is being played in a non- + // visible tab. void HandleMediaPlaying(const GURL& url, bool is_hidden); + // Resets the engagement score |url| to |score|, clearing daily limits. + void ResetScoreForURL(const GURL& url, double score); + // Overridden from history::HistoryServiceObserver: void OnURLsDeleted(history::HistoryService* history_service, bool all_history,
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc index a703609c..5a57d28 100644 --- a/chrome/browser/engagement/site_engagement_service_unittest.cc +++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -370,6 +370,33 @@ TestScoreInitializesAndUpdates(&dict, 1, 2, GetReferenceTime()); } +// Test that resetting a score has the correct properties. +TEST_F(SiteEngagementScoreTest, Reset) { + base::Time current_day = GetReferenceTime(); + + test_clock_.SetNow(current_day); + score_.AddPoints(SiteEngagementScore::GetNavigationPoints()); + EXPECT_EQ(SiteEngagementScore::GetNavigationPoints(), score_.Score()); + + current_day += base::TimeDelta::FromDays(7); + test_clock_.SetNow(current_day); + + score_.Reset(20.0); + EXPECT_DOUBLE_EQ(20.0, score_.Score()); + EXPECT_DOUBLE_EQ(0, score_.points_added_today_); + EXPECT_EQ(current_day, score_.last_engagement_time_); + + // Adding points after the reset should work as normal. + score_.AddPoints(5); + EXPECT_EQ(25.0, score_.Score()); + + // The decay should happen one decay period from + test_clock_.SetNow(current_day + + base::TimeDelta::FromDays( + SiteEngagementScore::GetDecayPeriodInDays() + 1)); + EXPECT_EQ(25.0 - SiteEngagementScore::GetDecayPoints(), score_.Score()); +} + class SiteEngagementServiceTest : public ChromeRenderViewHostTestHarness { public: void SetUp() override {
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc index 4c4112d..4943632f 100644 --- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc +++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -52,10 +52,6 @@ #include "extensions/browser/notification_types.h" #include "ui/base/l10n/l10n_util.h" -#if defined(OS_WIN) -#include "ui/aura/remote_window_tree_host_win.h" -#endif - using bookmarks::BookmarkModel; using bookmarks::BookmarkNode; using bookmarks::ManagedBookmarkService; @@ -798,11 +794,6 @@ gfx::NativeWindow owning_window = web_contents ? platform_util::GetTopLevel(web_contents->GetNativeView()) : NULL; -#if defined(OS_WIN) - if (!owning_window && - chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) - owning_window = aura::RemoteWindowTreeHostWin::Instance()->GetAshWindow(); -#endif // |web_contents| can be NULL (for background pages), which is fine. In such // a case if file-selection dialogs are forbidden by policy, we will not // show an InfoBar, which is better than letting one appear out of the blue.
diff --git a/chrome/browser/metro_viewer/DEPS b/chrome/browser/metro_viewer/DEPS deleted file mode 100644 index 4199b39..0000000 --- a/chrome/browser/metro_viewer/DEPS +++ /dev/null
@@ -1,3 +0,0 @@ -include_rules = [ - "+win8/viewer", -]
diff --git a/chrome/browser/metro_viewer/OWNERS b/chrome/browser/metro_viewer/OWNERS deleted file mode 100644 index b81e28b..0000000 --- a/chrome/browser/metro_viewer/OWNERS +++ /dev/null
@@ -1,3 +0,0 @@ -ananta@chromium.org -cpu@chromium.org -scottmg@chromium.org
diff --git a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc b/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc deleted file mode 100644 index 1c993f87..0000000 --- a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc +++ /dev/null
@@ -1,174 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h" - -#include "ash/display/display_info.h" -#include "ash/display/display_manager.h" -#include "ash/host/ash_remote_window_tree_host_win.h" -#include "ash/shell.h" -#include "ash/wm/window_positioner.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/strings/stringprintf.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_process_platform_part_aurawin.h" -#include "chrome/browser/browser_shutdown.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/lifetime/application_lifetime.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/search_engines/template_url_service_factory.h" -#include "chrome/browser/ui/ash/ash_init.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_list.h" -#include "chrome/browser/ui/browser_navigator.h" -#include "chrome/browser/ui/browser_navigator_params.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/host_desktop.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/common/env_vars.h" -#include "components/search_engines/util.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/gpu_data_manager.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/page_navigator.h" -#include "content/public/browser/web_contents.h" -#include "ui/aura/remote_window_tree_host_win.h" -#include "ui/gfx/win/dpi.h" -#include "ui/metro_viewer/metro_viewer_messages.h" -#include "url/gurl.h" - -namespace { - -void CloseOpenAshBrowsers() { - BrowserList* browser_list = - BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); - if (browser_list) { - for (BrowserList::const_iterator i = browser_list->begin(); - i != browser_list->end(); ++i) { - Browser* browser = *i; - browser->window()->Close(); - // If the attempt to Close the browser fails due to unload handlers on - // the page or in progress downloads, etc, destroy all tabs on the page. - while (browser->tab_strip_model()->count()) - delete browser->tab_strip_model()->GetWebContentsAt(0); - } - } -} - -void OpenURL(const GURL& url) { - chrome::NavigateParams params( - ProfileManager::GetActiveUserProfile(), - GURL(url), - ui::PAGE_TRANSITION_TYPED); - params.disposition = NEW_FOREGROUND_TAB; - params.host_desktop_type = chrome::HOST_DESKTOP_TYPE_ASH; - chrome::Navigate(¶ms); -} - -} // namespace - -ChromeMetroViewerProcessHost::ChromeMetroViewerProcessHost() - : MetroViewerProcessHost( - content::BrowserThread::GetMessageLoopProxyForThread( - content::BrowserThread::IO)) { - chrome::IncrementKeepAliveCount(); -} - -ChromeMetroViewerProcessHost::~ChromeMetroViewerProcessHost() { -} - -void ChromeMetroViewerProcessHost::OnChannelError() { - // TODO(cpu): At some point we only close the browser. Right now this - // is very convenient for developing. - DVLOG(1) << "viewer channel error : Quitting browser"; - - // Unset environment variable to let breakpad know that metro process wasn't - // connected. - ::SetEnvironmentVariableA(env_vars::kMetroConnected, NULL); - - // It seems possible that channel is connected, but ASH desktop is not yet - // created (instance is still NULL) and we receive channel error. - if (aura::RemoteWindowTreeHostWin::Instance()) { - aura::RemoteWindowTreeHostWin::Instance()->Disconnected(); - - chrome::DecrementKeepAliveCount(); - - // If browser is trying to quit, we shouldn't reenter the process. - // TODO(shrikant): In general there seem to be issues with how AttemptExit - // reentry works. In future release please clean up related code. - if (!browser_shutdown::IsTryingToQuit()) { - CloseOpenAshBrowsers(); - chrome::CloseAsh(); - } - // Tell the rest of Chrome about it. - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_ASH_SESSION_ENDED, - content::NotificationService::AllSources(), - content::NotificationService::NoDetails()); - return; - } - - chrome::DecrementKeepAliveCount(); - - // This will delete the MetroViewerProcessHost object. Don't access member - // variables/functions after this call. - g_browser_process->platform_part()->OnMetroViewerProcessTerminated(); -} - -void ChromeMetroViewerProcessHost::OnChannelConnected(int32_t /*peer_pid*/) { - DVLOG(1) << "ChromeMetroViewerProcessHost::OnChannelConnected: "; - // Set environment variable to let breakpad know that metro process was - // connected. - ::SetEnvironmentVariableA(env_vars::kMetroConnected, "1"); -} - -void ChromeMetroViewerProcessHost::OnSetTargetSurface( - gfx::NativeViewId target_surface, - float device_scale) { - HWND hwnd = reinterpret_cast<HWND>(target_surface); - - gfx::SetDefaultDeviceScaleFactor(device_scale); - chrome::OpenAsh(hwnd); - DCHECK(aura::RemoteWindowTreeHostWin::Instance()); - DCHECK_EQ(hwnd, aura::RemoteWindowTreeHostWin::Instance()->remote_window()); - ash::Shell::GetInstance()->CreateShelf(); - ash::Shell::GetInstance()->ShowShelf(); - - // Tell our root window host that the viewer has connected. - aura::RemoteWindowTreeHostWin::Instance()->Connected(this); - - // On Windows 8 ASH we default to SHOW_STATE_MAXIMIZED for the browser - // window. This is to ensure that we honor metro app conventions by default. - ash::WindowPositioner::SetMaximizeFirstWindow(true); - // Tell the rest of Chrome that Ash is running. - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_ASH_SESSION_STARTED, - content::NotificationService::AllSources(), - content::NotificationService::NoDetails()); -} - -void ChromeMetroViewerProcessHost::OnOpenURL(const base::string16& url) { - OpenURL(GURL(url)); -} - -void ChromeMetroViewerProcessHost::OnHandleSearchRequest( - const base::string16& search_string) { - GURL url(GetDefaultSearchURLForSearchTerms( - TemplateURLServiceFactory::GetForProfile( - ProfileManager::GetActiveUserProfile()), search_string)); - if (url.is_valid()) - OpenURL(url); -} - -void ChromeMetroViewerProcessHost::OnWindowSizeChanged(uint32_t width, - uint32_t height) { - std::vector<ash::DisplayInfo> info_list; - info_list.push_back(ash::DisplayInfo::CreateFromSpec( - base::StringPrintf("%dx%d*%f", width, height, gfx::GetDPIScale()))); - ash::Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged( - info_list); - aura::RemoteWindowTreeHostWin::Instance()->HandleWindowSizeChanged(width, - height); -}
diff --git a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h b/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h deleted file mode 100644 index 9696a490..0000000 --- a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_METRO_VIEWER_CHROME_METRO_VIEWER_PROCESS_HOST_AURAWIN_H_ -#define CHROME_BROWSER_METRO_VIEWER_CHROME_METRO_VIEWER_PROCESS_HOST_AURAWIN_H_ - -#include <stdint.h> - -#include "base/macros.h" -#include "win8/viewer/metro_viewer_process_host.h" - -namespace base { -class FilePath; -} - -class ChromeMetroViewerProcessHost : public win8::MetroViewerProcessHost { - public: - ChromeMetroViewerProcessHost(); - ~ChromeMetroViewerProcessHost() override; - - private: - // win8::MetroViewerProcessHost implementation - void OnChannelError() override; - - // IPC::Listener implementation - void OnChannelConnected(int32_t peer_pid) override; - void OnSetTargetSurface(gfx::NativeViewId target_surface, - float device_scale) override; - void OnOpenURL(const base::string16& url) override; - void OnHandleSearchRequest(const base::string16& search_string) override; - void OnWindowSizeChanged(uint32_t width, uint32_t height) override; - - DISALLOW_COPY_AND_ASSIGN(ChromeMetroViewerProcessHost); -}; - -#endif // CHROME_BROWSER_METRO_VIEWER_CHROME_METRO_VIEWER_PROCESS_HOST_AURAWIN_H_
diff --git a/chrome/browser/permissions/permission_uma_util.cc b/chrome/browser/permissions/permission_uma_util.cc index 439ca44..133904df 100644 --- a/chrome/browser/permissions/permission_uma_util.cc +++ b/chrome/browser/permissions/permission_uma_util.cc
@@ -185,33 +185,6 @@ std::move(sample)); } -std::string PermissionTypeToString(PermissionType permission_type) { - switch (permission_type) { - case PermissionType::MIDI_SYSEX: - return "MidiSysex"; - case PermissionType::PUSH_MESSAGING: - return "PushMessaging"; - case PermissionType::NOTIFICATIONS: - return "Notifications"; - case PermissionType::GEOLOCATION: - return "Geolocation"; - case PermissionType::PROTECTED_MEDIA_IDENTIFIER: - return "ProtectedMediaIdentifier"; - case PermissionType::DURABLE_STORAGE: - return "DurableStorage"; - case PermissionType::MIDI: - return "Midi"; - case PermissionType::AUDIO_CAPTURE: - return "AudioRecording"; - case PermissionType::VIDEO_CAPTURE: - return "VideoRecording"; - case PermissionType::NUM: - break; - } - NOTREACHED(); - return std::string(); -} - void RecordPermissionRequest(PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin, @@ -259,7 +232,7 @@ base::HistogramBase* histogram = base::LinearHistogram::FactoryGet( "Permissions.Requested.CrossOrigin_" + - PermissionTypeToString(permission), + PermissionUtil::GetPermissionString(permission), 1, content::PERMISSION_STATUS_LAST, content::PERMISSION_STATUS_LAST + 1, base::HistogramBase::kUmaTargetedHistogramFlag); histogram->Add(embedding_permission_status);
diff --git a/chrome/browser/plugins/plugin_infobar_delegates.cc b/chrome/browser/plugins/plugin_infobar_delegates.cc index fc2bb13..09df300 100644 --- a/chrome/browser/plugins/plugin_infobar_delegates.cc +++ b/chrome/browser/plugins/plugin_infobar_delegates.cc
@@ -38,10 +38,6 @@ #if defined(OS_WIN) #include <shellapi.h> #include "ui/base/win/shell.h" - -#if defined(USE_AURA) -#include "ui/aura/remote_window_tree_host_win.h" -#endif #endif using base::UserMetricsAction;
diff --git a/chrome/browser/profiles/profile_manager_browsertest.cc b/chrome/browser/profiles/profile_manager_browsertest.cc index e7020ed..0c5a0651 100644 --- a/chrome/browser/profiles/profile_manager_browsertest.cc +++ b/chrome/browser/profiles/profile_manager_browsertest.cc
@@ -134,7 +134,7 @@ #endif } -} // namespace +} // namespace // This file contains tests for the ProfileManager that require a heavyweight // InProcessBrowserTest. These include tests involving profile deletion. @@ -273,8 +273,8 @@ // Create a profile, make sure callback is invoked before any callbacks are // invoked (so they can do things like sign in the profile, etc). ProfileManager::CreateMultiProfileAsync( - base::string16(), // name - std::string(), // icon url + base::string16(), // name + std::string(), // icon url base::Bind(ProfileCreationComplete), std::string()); // Wait for profile to finish loading. @@ -466,3 +466,31 @@ EXPECT_EQ(0u, verify_delete.GetPasswords().size()); } #endif // !defined(OS_WIN) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS) + +// Tests Profile::HasOffTheRecordProfile, Profile::IsValidProfile and the +// profile counts in ProfileManager with respect to the creation and destruction +// of incognito profiles. +IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, IncognitoProfile) { + ProfileManager* profile_manager = g_browser_process->profile_manager(); + ASSERT_TRUE(profile_manager); + + Profile* profile = ProfileManager::GetActiveUserProfile(); + ASSERT_TRUE(profile); + EXPECT_FALSE(profile->HasOffTheRecordProfile()); + + size_t initial_profile_count = profile_manager->GetNumberOfProfiles(); + + // Create an incognito profile. + Profile* incognito_profile = profile->GetOffTheRecordProfile(); + + EXPECT_TRUE(profile->HasOffTheRecordProfile()); + ASSERT_TRUE(profile_manager->IsValidProfile(incognito_profile)); + EXPECT_EQ(initial_profile_count, profile_manager->GetNumberOfProfiles()); + + // Delete the incognito profile. + incognito_profile->GetOriginalProfile()->DestroyOffTheRecordProfile(); + + EXPECT_FALSE(profile->HasOffTheRecordProfile()); + EXPECT_FALSE(profile_manager->IsValidProfile(incognito_profile)); + EXPECT_EQ(initial_profile_count, profile_manager->GetNumberOfProfiles()); +}
diff --git a/chrome/browser/resources/engagement/engagement_table.css b/chrome/browser/resources/engagement/engagement_table.css index cb6a0088..e35c71a 100644 --- a/chrome/browser/resources/engagement/engagement_table.css +++ b/chrome/browser/resources/engagement/engagement_table.css
@@ -34,3 +34,10 @@ :host([sort-reverse]) .sort-column::after { content: 'â–¼'; } + +paper-slider { + width: 300px; + --paper-slider-input: { + width: 70px; + }; +}
diff --git a/chrome/browser/resources/engagement/engagement_table.html b/chrome/browser/resources/engagement/engagement_table.html index 3b667e8..3beb8e620 100644 --- a/chrome/browser/resources/engagement/engagement_table.html +++ b/chrome/browser/resources/engagement/engagement_table.html
@@ -1,4 +1,5 @@ <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-slider/paper-slider.html"> <dom-module id="engagement-table"> <link rel="import" type="css" href="engagement_table.css"> @@ -20,7 +21,11 @@ sort="[[getTableSortFunction_(sortKey_, sortReverse)]]"> <tr> <td class="origin-cell">{{info.origin}}</td> - <td>{{info.score}}</td> + <td> + <paper-slider step="0.1" min="0" max="100" value="[[info.score]]" + editable on-change="scoreChanged" + noink></paper-slider> + </td> </tr> </template> </tbody>
diff --git a/chrome/browser/resources/engagement/engagement_table.js b/chrome/browser/resources/engagement/engagement_table.js index 976fbe97..b8a7397 100644 --- a/chrome/browser/resources/engagement/engagement_table.js +++ b/chrome/browser/resources/engagement/engagement_table.js
@@ -104,4 +104,20 @@ assertNotReached('Unsupported sort key: ' + sortKey); return 0; }, + + /** + * Handles a score input change by firing an event that contains the origin + * changed and its new score. + * @param {Event} e The change event for the score input. + */ + scoreChanged: function(e) { + if (e.target.value == '') + return; + + e.model.set('info.score', Number(e.target.value)); + this.fire('score-edited', { + origin: e.model.get('info.origin'), + score: Number(e.target.value) + }); + } });
diff --git a/chrome/browser/resources/engagement/site_engagement.html b/chrome/browser/resources/engagement/site_engagement.html index 3d659b2..cef7e16 100644 --- a/chrome/browser/resources/engagement/site_engagement.html +++ b/chrome/browser/resources/engagement/site_engagement.html
@@ -8,6 +8,12 @@ <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> <script src="chrome://resources/js/util.js"></script> <script src="chrome://site-engagement/site_engagement.js"></script> + <style> + body { + font-family: 'Roboto', 'Noto', sans-serif; + font-size: 14px; + } + </style> </head> <body> <h1>Site Engagement</h1>
diff --git a/chrome/browser/resources/engagement/site_engagement.js b/chrome/browser/resources/engagement/site_engagement.js index 3845129..b13ff7e 100644 --- a/chrome/browser/resources/engagement/site_engagement.js +++ b/chrome/browser/resources/engagement/site_engagement.js
@@ -15,6 +15,16 @@ siteEngagementMojom.SiteEngagementUIHandler.name), siteEngagementMojom.SiteEngagementUIHandler); + var engagementTable = $('engagement-table'); + var updateInterval = null; + + engagementTable.addEventListener('score-edited', function(e) { + var detail = e.detail; + uiHandler.setSiteEngagementScoreForOrigin(detail.origin, detail.score); + clearInterval(updateInterval); + updateInterval = setInterval(updateEngagementTable, 5000); + }); + var updateEngagementTable = function() { // Populate engagement table. uiHandler.getSiteEngagementInfo().then(function(response) { @@ -22,11 +32,11 @@ response.info.forEach(function(x) { x.score = Number(Math.round(x.score * 100) / 100); }); - $('engagement-table').engagementInfo = response.info; + engagementTable.engagementInfo = response.info; }); - setTimeout(updateEngagementTable, 2000); }; updateEngagementTable(); + updateInterval = setInterval(updateEngagementTable, 5000); }; });
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc index e76928b..f8c9c91 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -779,11 +779,6 @@ return; } -#if defined(OS_WIN) - if (LaunchedInNativeDesktop(app_id)) - return; -#endif - // The app will be created for the currently active profile. AppLaunchParams params( profile_, extension, ui::DispositionFromEventFlags(event_flags),
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h index 9315d5ba..e63fa2f 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -551,11 +551,6 @@ // Forget the current profile to allow attaching to a new one. void ReleaseProfile(); - // Returns true if |app_id| is a Packaged App that has already launched on the - // native desktop and, if so, executes it as a desktop shortcut to activate - // desktop mode and send another OnLaunched event to the Extension. - bool LaunchedInNativeDesktop(const std::string& app_id); - static ChromeLauncherController* instance_; ash::ShelfModel* model_;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_chromeos.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_chromeos.cc deleted file mode 100644 index 1a1f86c..0000000 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_chromeos.cc +++ /dev/null
@@ -1,10 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" - -bool ChromeLauncherController::LaunchedInNativeDesktop( - const std::string& app_id) { - return false; -}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_win.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_win.cc deleted file mode 100644 index 29ec4ac1..0000000 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_win.cc +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" - -#include "base/path_service.h" -#include "base/strings/string16.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/host_desktop.h" -#include "chrome/common/chrome_switches.h" -#include "extensions/browser/app_window/app_window.h" -#include "extensions/browser/app_window/app_window_registry.h" -#include "extensions/common/constants.h" -#include "ui/aura/remote_window_tree_host_win.h" - -bool ChromeLauncherController::LaunchedInNativeDesktop( - const std::string& app_id) { - // If an app has any existing windows on the native desktop, funnel the - // launch request through the viewer process to desktop Chrome. This allows - // Ash to relinquish foreground window status and trigger a switch to - // desktop mode. - extensions::AppWindow* any_existing_window = - extensions::AppWindowRegistry::Get(profile()) - ->GetCurrentAppWindowForApp(app_id); - if (!any_existing_window || - chrome::GetHostDesktopTypeForNativeWindow( - any_existing_window->GetNativeWindow()) - != chrome::HOST_DESKTOP_TYPE_NATIVE) { - return false; - } - base::FilePath exe_path; - if (!PathService::Get(base::FILE_EXE, &exe_path)) { - NOTREACHED(); - return false; - } - - // Construct parameters for ShellExecuteEx that mimic a desktop shortcut - // for the app in the current Profile. - std::string spec = base::StringPrintf("\"--%s=%s\" \"--%s=%s\"", - switches::kProfileDirectory, - profile_->GetPath().BaseName().AsUTF8Unsafe().c_str(), - switches::kAppId, - app_id.c_str()); - aura::RemoteWindowTreeHostWin::Instance()->HandleOpenURLOnDesktop( - exe_path, base::UTF8ToUTF16(spec)); - return true; -}
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc index eebd1f2a..e9aa438 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc
@@ -24,7 +24,6 @@ #include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/app_window_registry.h" #include "extensions/common/extension.h" -#include "ui/aura/remote_window_tree_host_win.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/win/shell.h" #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
diff --git a/chrome/browser/ui/webui/engagement/site_engagement.mojom b/chrome/browser/ui/webui/engagement/site_engagement.mojom index a6d2042..0d9cc4a 100644 --- a/chrome/browser/ui/webui/engagement/site_engagement.mojom +++ b/chrome/browser/ui/webui/engagement/site_engagement.mojom
@@ -9,4 +9,5 @@ interface SiteEngagementUIHandler { GetSiteEngagementInfo() => (array<SiteEngagementInfo> info); + SetSiteEngagementScoreForOrigin(string origin, double score); };
diff --git a/chrome/browser/ui/webui/engagement/site_engagement_ui.cc b/chrome/browser/ui/webui/engagement/site_engagement_ui.cc index 76c34549..a3359b482 100644 --- a/chrome/browser/ui/webui/engagement/site_engagement_ui.cc +++ b/chrome/browser/ui/webui/engagement/site_engagement_ui.cc
@@ -50,6 +50,18 @@ callback.Run(std::move(engagement_info)); } + void SetSiteEngagementScoreForOrigin(const mojo::String& origin, + double score) override { + GURL origin_gurl(origin); + if (!origin_gurl.is_valid() || score < 0 || + score > SiteEngagementScore::kMaxPoints) { + return; + } + + SiteEngagementService* service = SiteEngagementService::Get(profile_); + service->ResetScoreForURL(origin_gurl, score); + } + private: // The Profile* handed to us in our constructor. Profile* profile_;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index db7c848..aec8cb2 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi
@@ -1354,8 +1354,6 @@ 'browser/usb/web_usb_permission_bubble.h', ], 'chrome_browser_win_sources': [ - 'browser/browser_process_platform_part_aurawin.cc', - 'browser/browser_process_platform_part_aurawin.h', 'browser/first_run/try_chrome_dialog_view.cc', 'browser/first_run/try_chrome_dialog_view.h', 'browser/first_run/upgrade_util.cc', @@ -1367,8 +1365,6 @@ 'browser/hang_monitor/hung_plugin_action.h', 'browser/hang_monitor/hung_window_detector.cc', 'browser/hang_monitor/hung_window_detector.h', - 'browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc', - 'browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h', 'browser/password_manager/password_manager_util_win.cc', 'browser/password_manager/password_manager_util_win.h', ], @@ -3832,7 +3828,6 @@ '../ui/metro_viewer/metro_viewer.gyp:metro_viewer_messages', '../ui/views/controls/webview/webview.gyp:webview', '../ui/views/views.gyp:views', - '../win8/win8.gyp:metro_viewer', ], 'export_dependent_settings': [ '../third_party/kasko/kasko.gyp:kasko',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 3abdf0af..70ff6b34 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -558,8 +558,6 @@ 'browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h', 'browser/ui/ash/launcher/chrome_launcher_controller.cc', 'browser/ui/ash/launcher/chrome_launcher_controller.h', - 'browser/ui/ash/launcher/chrome_launcher_controller_chromeos.cc', - 'browser/ui/ash/launcher/chrome_launcher_controller_win.cc', 'browser/ui/ash/launcher/launcher_app_tab_helper.cc', 'browser/ui/ash/launcher/launcher_app_tab_helper.h', 'browser/ui/ash/launcher/launcher_application_menu_item_model.cc',
diff --git a/chrome/test/kasko/py/kasko/report.py b/chrome/test/kasko/py/kasko/report.py index 6e0c350..8eb884eb4 100755 --- a/chrome/test/kasko/py/kasko/report.py +++ b/chrome/test/kasko/py/kasko/report.py
@@ -20,10 +20,20 @@ def ValidateCrashReport(report, expectations=None): - # Generate default expectations, and merge in any additional ones. - expected_keys = {'guid': 'GetCrashKeysForKasko', - 'kasko-generated-by-version': 'Kasko', - 'kasko-uploaded-by-version': 'Kasko'} + expected_keys = {} + + # The following keys are all expected to be set in all crashes, and should + # be set by GetCrashKeysForKasko. + get_crash_keys = 'GetCrashKeysForKasko' + for k in ['guid', 'prod', 'plat', 'ver', 'ptype', 'channel']: + expected_keys[k] = get_crash_keys + + # The following crash keys are expected to be set by the Kasko code itself. + kasko = 'Kasko' + for k in ['kasko-generated-by-version', 'kasko-uploaded-by-version']: + expected_keys[k] = kasko + + # Merge in additional expectations. if expectations: for key, value in expectations.iteritems(): expected_keys[key] = value
diff --git a/components/crash/content/app/crashpad.cc b/components/crash/content/app/crashpad.cc index dfe83cac..78216d2 100644 --- a/components/crash/content/app/crashpad.cc +++ b/components/crash/content/app/crashpad.cc
@@ -246,9 +246,14 @@ #if BUILDFLAG(ENABLE_KASKO) void GetCrashKeysForKasko(std::vector<kasko::api::CrashKey>* crash_keys) { - // Reserve room for an extra key, the guid. + // Get the platform annotations. + std::map<std::string, std::string> annotations; + internal::GetPlatformCrashpadAnnotations(&annotations); + + // Reserve room for the GUID and the platform annotations. crash_keys->clear(); - crash_keys->reserve(g_simple_string_dictionary->GetCount() + 1); + crash_keys->reserve( + g_simple_string_dictionary->GetCount() + 1 + annotations.size()); // Set the Crashpad client ID in the crash keys. bool got_guid = false; @@ -275,11 +280,25 @@ if (got_guid && ::strncmp(entry->key, kGuid, arraysize(kGuid)) == 0) continue; + // Skip any platform annotations as they'll be set below. + if (annotations.count(entry->key)) + continue; + kasko::api::CrashKey kv; wcsncpy_s(kv.name, base::UTF8ToWide(entry->key).c_str(), _TRUNCATE); wcsncpy_s(kv.value, base::UTF8ToWide(entry->value).c_str(), _TRUNCATE); crash_keys->push_back(kv); } + + // Merge in the platform annotations. + for (const auto& entry : annotations) { + kasko::api::CrashKey kv; + wcsncpy_s(kv.name, base::UTF8ToWide(entry.first).c_str(), + _TRUNCATE); + wcsncpy_s(kv.value, base::UTF8ToWide(entry.second).c_str(), + _TRUNCATE); + crash_keys->push_back(kv); + } } #endif // BUILDFLAG(ENABLE_KASKO)
diff --git a/components/crash/content/app/crashpad.h b/components/crash/content/app/crashpad.h index 1f9f007..a3f5e6c4 100644 --- a/components/crash/content/app/crashpad.h +++ b/components/crash/content/app/crashpad.h
@@ -7,6 +7,7 @@ #include <time.h> +#include <map> #include <string> #include <vector> @@ -82,6 +83,13 @@ namespace internal { +#if defined(OS_WIN) +// Returns platform specific annotations. This is broken out on Windows only so +// that it may be reused by GetCrashKeysForKasko. +void GetPlatformCrashpadAnnotations( + std::map<std::string, std::string>* annotations); +#endif // defined(OS_WIN) + // The platform-specific portion of InitializeCrashpad(). // Returns the database path, if initializing in the browser process. base::FilePath PlatformCrashpadInitialization(bool initial_client,
diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc index 1c241ca..1628ab6 100644 --- a/components/crash/content/app/crashpad_win.cc +++ b/components/crash/content/app/crashpad_win.cc
@@ -30,6 +30,26 @@ } // namespace +void GetPlatformCrashpadAnnotations( + std::map<std::string, std::string>* annotations) { + CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); + base::FilePath exe_file; + CHECK(PathService::Get(base::FILE_EXE, &exe_file)); + base::string16 product_name, version, special_build, channel_name; + crash_reporter_client->GetProductNameAndVersion( + exe_file, &product_name, &version, &special_build, &channel_name); + (*annotations)["prod"] = base::UTF16ToUTF8(product_name); + (*annotations)["ver"] = base::UTF16ToUTF8(version); + (*annotations)["channel"] = base::UTF16ToUTF8(channel_name); + if (!special_build.empty()) + (*annotations)["special"] = base::UTF16ToUTF8(special_build); +#if defined(ARCH_CPU_X86) + (*annotations)["plat"] = std::string("Win32"); +#elif defined(ARCH_CPU_X86_64) + (*annotations)["plat"] = std::string("Win64"); +#endif +} + base::FilePath PlatformCrashpadInitialization(bool initial_client, bool browser_process) { base::FilePath database_path; // Only valid in the browser process. @@ -44,22 +64,9 @@ CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); crash_reporter_client->GetCrashDumpLocation(&database_path); - base::FilePath exe_file; - CHECK(PathService::Get(base::FILE_EXE, &exe_file)); - base::string16 product_name, version, special_build, channel_name; - crash_reporter_client->GetProductNameAndVersion( - exe_file, &product_name, &version, &special_build, &channel_name); std::map<std::string, std::string> process_annotations; - process_annotations["prod"] = base::UTF16ToUTF8(product_name); - process_annotations["ver"] = base::UTF16ToUTF8(version); - process_annotations["channel"] = base::UTF16ToUTF8(channel_name); - if (!special_build.empty()) - process_annotations["special"] = base::UTF16ToUTF8(special_build); -#if defined(ARCH_CPU_X86) - process_annotations["plat"] = std::string("Win32"); -#elif defined(ARCH_CPU_X86_64) - process_annotations["plat"] = std::string("Win64"); -#endif + GetPlatformCrashpadAnnotations(&process_annotations); + #if defined(GOOGLE_CHROME_BUILD) std::string url = "https://clients2.google.com/cr/report"; #else @@ -70,6 +77,8 @@ // In test binaries, use crashpad_handler directly. Otherwise, we launch // chrome.exe with --type=crashpad-handler. + base::FilePath exe_file; + CHECK(PathService::Get(base::FILE_EXE, &exe_file)); if (exe_file.BaseName().value() != FILE_PATH_LITERAL("chrome.exe")) { base::FilePath exe_dir = exe_file.DirName(); exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
diff --git a/components/html_viewer/blink_platform_impl.cc b/components/html_viewer/blink_platform_impl.cc index c3d5d1a..714f16f 100644 --- a/components/html_viewer/blink_platform_impl.cc +++ b/components/html_viewer/blink_platform_impl.cc
@@ -153,12 +153,6 @@ return &scrollbar_behavior_; } -const unsigned char* BlinkPlatformImpl::getTraceCategoryEnabledFlag( - const char* category_name) { - static const unsigned char buf[] = "*"; - return buf; -} - blink::WebGraphicsContext3D* BlinkPlatformImpl::createOffscreenGraphicsContext3D( const blink::WebGraphicsContext3D::Attributes& attributes,
diff --git a/components/html_viewer/blink_platform_impl.h b/components/html_viewer/blink_platform_impl.h index df74298..0494d1c 100644 --- a/components/html_viewer/blink_platform_impl.h +++ b/components/html_viewer/blink_platform_impl.h
@@ -77,8 +77,6 @@ blink::WebWaitableEvent* waitMultipleEvents( const blink::WebVector<blink::WebWaitableEvent*>& events) override; blink::WebScrollbarBehavior* scrollbarBehavior() override; - const unsigned char* getTraceCategoryEnabledFlag( - const char* category_name) override; blink::WebGraphicsContext3D* createOffscreenGraphicsContext3D( const blink::WebGraphicsContext3D::Attributes& attributes, blink::WebGraphicsContext3D* share_context) override;
diff --git a/components/password_manager/sync/browser/sync_credentials_filter.cc b/components/password_manager/sync/browser/sync_credentials_filter.cc index 93031c7..7e9699d 100644 --- a/components/password_manager/sync/browser/sync_credentials_filter.cc +++ b/components/password_manager/sync/browser/sync_credentials_filter.cc
@@ -64,9 +64,6 @@ std::partition(results.begin(), results.end(), [this](PasswordForm* form) { return ShouldSave(*form); }); - // TODO(vabr): Improve the description of the histogram to mention that it is - // only reported for forms where the sync credentials would have been filled - // in. UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered", begin_of_removed != results.end());
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc index d739302..33e7b8d 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl.cc +++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -682,17 +682,10 @@ case UseCase::MAIN_THREAD_GESTURE: // In main thread gestures we don't have perfect knowledge about which - // things we should be prioritizing. The following is best guess - // heuristic which lets us produce frames quickly but does not prevent - // loading of additional content. + // things we should be prioritizing, so we don't attempt to block + // expensive tasks because we don't know whether they were integral to the + // page's functionality or not. new_policy.compositor_queue_priority = TaskQueue::HIGH_PRIORITY; - if (touchstart_expected_soon) { - block_expensive_loading_tasks = true; - block_expensive_timer_tasks = true; - } else { - block_expensive_loading_tasks = false; - block_expensive_timer_tasks = true; - } break; case UseCase::TOUCHSTART: @@ -705,7 +698,10 @@ break; case UseCase::NONE: - if (touchstart_expected_soon) { + // It's only safe to block tasks that are (likely to be) compositor + // driven. + if (touchstart_expected_soon && + AnyThread().last_gesture_was_compositor_driven) { block_expensive_loading_tasks = true; block_expensive_timer_tasks = true; } @@ -852,7 +848,6 @@ // TODO(alexclarke): return UseCase::LOADING if signals suggest the system is // in the initial 1s of RAIL loading. - return UseCase::NONE; }
diff --git a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc index 87d5cc3..1e84f1a 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc +++ b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -315,19 +315,37 @@ // TODO(alexclarke): Revisit this. scheduler_->DidHandleInputEventOnCompositorThread( FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); scheduler_->DidHandleInputEventOnCompositorThread( FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); scheduler_->DidHandleInputEventOnCompositorThread( FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); scheduler_->DidHandleInputEventOnCompositorThread( FakeInputEvent(blink::WebInputEvent::TouchEnd), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchEnd)); scheduler_->ForceUpdatePolicy(); clock_->Advance(base::TimeDelta::FromSeconds(60)); scheduler_->ForceUpdatePolicy(); + EXPECT_EQ(RendererScheduler::UseCase::NONE, CurrentUseCase()); } void SimulateExpensiveTasks( @@ -952,8 +970,7 @@ testing::ElementsAre(std::string("C1"), std::string("T1"))); } -TEST_F(RendererSchedulerImplTest, - ExpensiveTimersDontRunWhenMainThreadScrolling) { +TEST_F(RendererSchedulerImplTest, ExpensiveTimersDoRunWhenMainThreadScrolling) { std::vector<std::string> run_order; scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); @@ -962,32 +979,18 @@ SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, blink::WebInputEvent::GestureScrollBegin); - // Timers should now be disabled during main thread user user interactions. PostTestTasks(&run_order, "C1 T1"); RunUntilIdle(); EXPECT_FALSE(TouchStartExpectedSoon()); EXPECT_EQ(RendererScheduler::UseCase::MAIN_THREAD_GESTURE, CurrentUseCase()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("C1"))); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollEnd)); - - clock_->Advance(subsequent_input_expected_after_input_duration() * 2); - - run_order.clear(); - RunUntilIdle(); - EXPECT_FALSE(TouchStartExpectedSoon()); - EXPECT_EQ(RendererScheduler::UseCase::NONE, CurrentUseCase()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("T1"))); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("T1"))); } TEST_F(RendererSchedulerImplTest, - ExpensiveTimersDontRunWhenMainThreadScrolling_AndOnCriticalPath) { + ExpensiveTimersDoRunWhenMainThreadScrolling_AndOnCriticalPath) { std::vector<std::string> run_order; scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); @@ -996,28 +999,14 @@ SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, blink::WebInputEvent::GestureScrollBegin); - // Timers should now be disabled during main thread user user interactions. PostTestTasks(&run_order, "C1 T1"); RunUntilIdle(); EXPECT_FALSE(TouchStartExpectedSoon()); EXPECT_EQ(RendererScheduler::UseCase::MAIN_THREAD_GESTURE, CurrentUseCase()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("C1"))); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollEnd)); - - clock_->Advance(subsequent_input_expected_after_input_duration() * 2); - - run_order.clear(); - RunUntilIdle(); - EXPECT_FALSE(TouchStartExpectedSoon()); - EXPECT_EQ(RendererScheduler::UseCase::NONE, CurrentUseCase()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("T1"))); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("T1"))); } TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_Compositor) { @@ -2219,7 +2208,8 @@ testing::ElementsAre(std::string("L1"), std::string("D1"))); } -TEST_F(RendererSchedulerImplTest, ExpensiveTimerTaskBlocked) { +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskBlocked_UseCase_NONE_PreviousCompositorGesture) { std::vector<std::string> run_order; EnableTaskBlocking(); @@ -2228,14 +2218,68 @@ SimulateExpensiveTasks(timer_task_runner_); ForceTouchStartToBeExpectedSoon(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); PostTestTasks(&run_order, "T1 D1"); RunUntilIdle(); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_FALSE(LoadingTasksSeemExpensive()); + EXPECT_TRUE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskNotBlocked_UseCase_NONE_PreviousMainThreadGesture) { + std::vector<std::string> run_order; + + EnableTaskBlocking(); + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, ForceUpdatePolicyAndGetCurrentUseCase()); + + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchEnd), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchEnd)); + + clock_->Advance(priority_escalation_after_input_duration() * 2); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + + PostTestTasks(&run_order, "T1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_FALSE(LoadingTasksSeemExpensive()); + EXPECT_TRUE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("T1"), std::string("D1"))); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskBlocked_UseCase_COMPOSITOR_GESTURE) { + std::vector<std::string> run_order; + + EnableTaskBlocking(); + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + ForceTouchStartToBeExpectedSoon(); + scheduler_->DidAnimateForInputOnCompositorThread(); + + PostTestTasks(&run_order, "T1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); EXPECT_TRUE(HaveSeenABeginMainframe()); EXPECT_FALSE(LoadingTasksSeemExpensive()); EXPECT_TRUE(TimerTasksSeemExpensive()); @@ -2243,7 +2287,8 @@ EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); } -TEST_F(RendererSchedulerImplTest, ExpensiveTimerTaskNotBlockedIfDisallowed) { +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskNotBlockedIfDissalowed_UseCase_COMPOSITOR_GESTURE) { std::vector<std::string> run_order; EnableTaskBlocking(); @@ -2252,14 +2297,12 @@ DoMainFrame(); SimulateExpensiveTasks(timer_task_runner_); ForceTouchStartToBeExpectedSoon(); + scheduler_->DidAnimateForInputOnCompositorThread(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); PostTestTasks(&run_order, "T1 D1"); RunUntilIdle(); - EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, + EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, ForceUpdatePolicyAndGetCurrentUseCase()); EXPECT_TRUE(HaveSeenABeginMainframe()); EXPECT_FALSE(LoadingTasksSeemExpensive()); @@ -2270,7 +2313,7 @@ } TEST_F(RendererSchedulerImplTest, - ExpensiveTimerTaskBlockedIfTouchStartNotSeen) { + ExpensiveTimerTaskNotBlockedIfTouchStartNotSeen) { std::vector<std::string> run_order; scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); @@ -2278,14 +2321,10 @@ SimulateExpensiveTasks(timer_task_runner_); ForceTouchStartToBeExpectedSoon(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); PostTestTasks(&run_order, "T1 D1"); RunUntilIdle(); - EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); EXPECT_TRUE(HaveSeenABeginMainframe()); EXPECT_FALSE(LoadingTasksSeemExpensive()); EXPECT_TRUE(TimerTasksSeemExpensive()); @@ -2305,14 +2344,10 @@ ForceTouchStartToBeExpectedSoon(); scheduler_->BeginFrameNotExpectedSoon(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); PostTestTasks(&run_order, "T1 D1"); RunUntilIdle(); - EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); EXPECT_TRUE(HaveSeenABeginMainframe()); EXPECT_FALSE(LoadingTasksSeemExpensive()); EXPECT_FALSE(TimerTasksSeemExpensive()); @@ -2422,12 +2457,11 @@ EnableTaskBlocking(); SimulateExpensiveTasks(loading_task_runner_); - // Loading tasks should not be disabled during main thread user user - // interactions. + // Loading tasks should not be disabled during main thread user interactions. PostTestTasks(&run_order, "C1 L1"); // Trigger main_thread_gesture UseCase - SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, blink::WebInputEvent::GestureScrollBegin); RunUntilIdle(); EXPECT_EQ(RendererScheduler::UseCase::MAIN_THREAD_GESTURE, CurrentUseCase()); @@ -2516,7 +2550,8 @@ } } -TEST_F(RendererSchedulerImplTest, ExpensiveTimer_Blocked) { +TEST_F(RendererSchedulerImplTest, + ExpensiveTimer_NotBlocked_UseCase_MAIN_THREAD_GESTURE) { EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, @@ -2547,11 +2582,10 @@ EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i; if (i == 0) { EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i; - EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i; } else { EXPECT_TRUE(TimerTasksSeemExpensive()) << " i = " << i; - EXPECT_FALSE(simulate_timer_task_ran_) << " i = " << i; } + EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i; base::TimeDelta time_till_next_frame = EstimatedNextFrameBegin() - clock_->NowTicks();
diff --git a/components/test_runner/event_sender.cc b/components/test_runner/event_sender.cc index a5fcc7b..fdcc7f35 100644 --- a/components/test_runner/event_sender.cc +++ b/components/test_runner/event_sender.cc
@@ -408,6 +408,30 @@ #endif } +bool GetScrollUnits(gin::Arguments* args, WebGestureEvent::ScrollUnits* units) { + std::string units_string; + if (!args->PeekNext().IsEmpty()) { + if (args->PeekNext()->IsString()) + args->GetNext(&units_string); + if (units_string == "Page") { + *units = WebGestureEvent::Page; + return true; + } else if (units_string == "Pixels") { + *units = WebGestureEvent::Pixels; + return true; + } else if (units_string == "PrecisePixels") { + *units = WebGestureEvent::PrecisePixels; + return true; + } else { + args->ThrowError(); + return false; + } + } else { + *units = WebGestureEvent::PrecisePixels; + return true; + } +} + const char* kSourceDeviceStringTouchpad = "touchpad"; const char* kSourceDeviceStringTouchscreen = "touchscreen"; @@ -2142,6 +2166,8 @@ return; } } + if (!GetScrollUnits(args, &event.data.scrollUpdate.deltaUnits)) + return; event.data.scrollUpdate.deltaX = static_cast<float>(x); event.data.scrollUpdate.deltaY = static_cast<float>(y);
diff --git a/components/web_view/web_view_impl.cc b/components/web_view/web_view_impl.cc index 6d140cb72..e07f3cf5 100644 --- a/components/web_view/web_view_impl.cc +++ b/components/web_view/web_view_impl.cc
@@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/command_line.h" -#include "components/devtools_service/public/cpp/switches.h" #include "components/mus/public/cpp/scoped_window_ptr.h" #include "components/mus/public/cpp/window.h" #include "components/mus/public/cpp/window_tree_connection.h" @@ -26,14 +25,6 @@ #include "url/gurl.h" namespace web_view { -namespace { - -bool EnableRemoteDebugging() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - devtools_service::kRemoteDebuggingPort); -} - -} // namespace using web_view::mojom::ButtonState; @@ -50,8 +41,7 @@ content_(nullptr), find_controller_(this), navigation_controller_(this) { - if (EnableRemoteDebugging()) - devtools_agent_.reset(new FrameDevToolsAgent(app_, this)); + devtools_agent_.reset(new FrameDevToolsAgent(app_, this)); OnDidNavigate(); }
diff --git a/content/browser/push_messaging/push_messaging_message_filter.cc b/content/browser/push_messaging/push_messaging_message_filter.cc index c3ccfe3..41668e3 100644 --- a/content/browser/push_messaging/push_messaging_message_filter.cc +++ b/content/browser/push_messaging/push_messaging_message_filter.cc
@@ -19,6 +19,8 @@ #include "content/common/push_messaging_messages.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/permission_manager.h" +#include "content/public/browser/permission_type.h" #include "content/public/browser/push_messaging_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" @@ -144,6 +146,9 @@ // Private Register methods on UI thread ------------------------------------- + void DidRequestPermissionInIncognito(const RegisterData& data, + PermissionStatus status); + void DidRegister(const RegisterData& data, const std::string& push_registration_id, const std::vector<uint8_t>& p256dh, @@ -408,9 +413,6 @@ io_parent_, data, PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED)); } else { - // Leave the promise hanging forever, to simulate a user ignoring the - // infobar. TODO(johnme): Simulate the user dismissing the infobar after - // a random time period. RenderFrameHost* render_frame_host = RenderFrameHost::FromID(render_process_id_, data.render_frame_id); WebContents* web_contents = @@ -418,6 +420,17 @@ if (web_contents) { web_contents->GetMainFrame()->AddMessageToConsole( CONSOLE_MESSAGE_LEVEL_ERROR, kIncognitoPushUnsupportedMessage); + // Request push messaging permission (which will fail, since + // notifications aren't supported in incognito), so the website can't + // detect whether incognito is active. + web_contents->GetBrowserContext() + ->GetPermissionManager() + ->RequestPermission( + PermissionType::PUSH_MESSAGING, render_frame_host, + data.requesting_origin, false /* user_gesture */, + base::Bind(&PushMessagingMessageFilter::Core:: + DidRequestPermissionInIncognito, + weak_factory_ui_to_ui_.GetWeakPtr(), data)); } } } @@ -439,6 +452,18 @@ } } +void PushMessagingMessageFilter::Core::DidRequestPermissionInIncognito( + const RegisterData& data, + PermissionStatus status) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + // Notification permission should always be denied in incognito. + DCHECK_EQ(PERMISSION_STATUS_DENIED, status); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&PushMessagingMessageFilter::SendSubscriptionError, io_parent_, + data, PUSH_REGISTRATION_STATUS_INCOGNITO_PERMISSION_DENIED)); +} + void PushMessagingMessageFilter::Core::DidRegister( const RegisterData& data, const std::string& push_registration_id,
diff --git a/content/browser/service_worker/foreign_fetch_request_handler.cc b/content/browser/service_worker/foreign_fetch_request_handler.cc index 5edda64..e86e6ec 100644 --- a/content/browser/service_worker/foreign_fetch_request_handler.cc +++ b/content/browser/service_worker/foreign_fetch_request_handler.cc
@@ -119,8 +119,8 @@ DCHECK(!job_.get() || job_->ShouldForwardToServiceWorker()); ServiceWorkerURLRequestJob* job = new ServiceWorkerURLRequestJob( - request, network_delegate, blob_storage_context_, resource_context, - request_mode_, credentials_mode_, redirect_mode_, false, + request, network_delegate, std::string(), blob_storage_context_, + resource_context, request_mode_, credentials_mode_, redirect_mode_, false, request_context_type_, frame_type_, body_, this); job_ = job->GetWeakPtr();
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc index a656fd869..42e72fe 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -101,9 +101,10 @@ // It's for original request (A) or redirect case (B-a or B-b). scoped_ptr<ServiceWorkerURLRequestJob> job(new ServiceWorkerURLRequestJob( - request, network_delegate, blob_storage_context_, resource_context, - request_mode_, credentials_mode_, redirect_mode_, is_main_resource_load_, - request_context_type_, frame_type_, body_, this)); + request, network_delegate, provider_host_->client_uuid(), + blob_storage_context_, resource_context, request_mode_, credentials_mode_, + redirect_mode_, is_main_resource_load_, request_context_type_, + frame_type_, body_, this)); job_ = job->GetWeakPtr(); resource_context_ = resource_context;
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc index 10e8502..44fab7f 100644 --- a/content/browser/service_worker/service_worker_url_request_job.cc +++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -109,6 +109,7 @@ ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob( net::URLRequest* request, net::NetworkDelegate* network_delegate, + const std::string& client_id, base::WeakPtr<storage::BlobStorageContext> blob_storage_context, const ResourceContext* resource_context, FetchRequestMode request_mode, @@ -124,6 +125,7 @@ response_type_(NOT_DETERMINED), is_started_(false), service_worker_response_type_(blink::WebServiceWorkerResponseTypeDefault), + client_id_(client_id), blob_storage_context_(blob_storage_context), resource_context_(resource_context), stream_pending_buffer_size_(0), @@ -448,6 +450,7 @@ scoped_ptr<ServiceWorkerFetchRequest> request( new ServiceWorkerFetchRequest()); request->mode = request_mode_; + request->is_main_resource_load = is_main_resource_load_; request->request_context_type = request_context_type_; request->frame_type = frame_type_; request->url = request_->url(); @@ -462,6 +465,7 @@ request->blob_size = blob_size; request->credentials_mode = credentials_mode_; request->redirect_mode = redirect_mode_; + request->client_id = client_id_; const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); if (info) { request->is_reload = ui::PageTransitionCoreTypeIs(
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h index ea2860df..8f9946d4 100644 --- a/content/browser/service_worker/service_worker_url_request_job.h +++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -100,6 +100,7 @@ ServiceWorkerURLRequestJob( net::URLRequest* request, net::NetworkDelegate* network_delegate, + const std::string& client_id, base::WeakPtr<storage::BlobStorageContext> blob_storage_context, const ResourceContext* resource_context, FetchRequestMode request_mode, @@ -249,6 +250,7 @@ // Used when response type is FORWARD_TO_SERVICE_WORKER. scoped_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_; + std::string client_id_; base::WeakPtr<storage::BlobStorageContext> blob_storage_context_; const ResourceContext* resource_context_; scoped_ptr<net::URLRequest> blob_request_;
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc index 48a1fdd..80c5bd39 100644 --- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc +++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -171,10 +171,11 @@ } job_ = new ServiceWorkerURLRequestJob( - request, network_delegate, blob_storage_context_, resource_context_, - FETCH_REQUEST_MODE_NO_CORS, FETCH_CREDENTIALS_MODE_OMIT, - FetchRedirectMode::FOLLOW_MODE, true /* is_main_resource_load */, - REQUEST_CONTEXT_TYPE_HYPERLINK, REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL, + request, network_delegate, provider_host_->client_uuid(), + blob_storage_context_, resource_context_, FETCH_REQUEST_MODE_NO_CORS, + FETCH_CREDENTIALS_MODE_OMIT, FetchRedirectMode::FOLLOW_MODE, + true /* is_main_resource_load */, REQUEST_CONTEXT_TYPE_HYPERLINK, + REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL, scoped_refptr<ResourceRequestBody>(), delegate_); job_->ForwardToServiceWorker(); return job_;
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc index 0b7f0a7..1e4b72da 100644 --- a/content/child/blink_platform_impl.cc +++ b/content/child/blink_platform_impl.cc
@@ -63,7 +63,6 @@ #include "net/base/ip_address_number.h" #include "net/base/net_errors.h" #include "net/base/port_util.h" -#include "third_party/WebKit/public/platform/WebConvertableToTraceFormat.h" #include "third_party/WebKit/public/platform/WebData.h" #include "third_party/WebKit/public/platform/WebFloatPoint.h" #include "third_party/WebKit/public/platform/WebMemoryDumpProvider.h" @@ -159,25 +158,6 @@ base::Lock lock_; }; -class ConvertableToTraceFormatWrapper - : public base::trace_event::ConvertableToTraceFormat { - public: - // We move a reference pointer from |convertable| to |convertable_|, - // rather than copying, for thread safety. https://crbug.com/478149 - explicit ConvertableToTraceFormatWrapper( - blink::WebConvertableToTraceFormat& convertable) { - convertable_.moveFrom(convertable); - } - void AppendAsTraceFormat(std::string* out) const override { - *out += convertable_.asTraceFormat().utf8(); - } - - private: - ~ConvertableToTraceFormatWrapper() override {} - - blink::WebConvertableToTraceFormat convertable_; -}; - } // namespace static int ToMessageID(WebLocalizedString::Name name) { @@ -634,81 +614,6 @@ UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample); } -const unsigned char* BlinkPlatformImpl::getTraceCategoryEnabledFlag( - const char* category_group) { - return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group); -} - -blink::Platform::TraceEventAPIAtomicWord* -BlinkPlatformImpl::getTraceSamplingState(const unsigned thread_bucket) { - switch (thread_bucket) { - case 0: - return reinterpret_cast<blink::Platform::TraceEventAPIAtomicWord*>( - &TRACE_EVENT_API_THREAD_BUCKET(0)); - case 1: - return reinterpret_cast<blink::Platform::TraceEventAPIAtomicWord*>( - &TRACE_EVENT_API_THREAD_BUCKET(1)); - case 2: - return reinterpret_cast<blink::Platform::TraceEventAPIAtomicWord*>( - &TRACE_EVENT_API_THREAD_BUCKET(2)); - default: - NOTREACHED() << "Unknown thread bucket type."; - } - return NULL; -} - -static_assert( - sizeof(blink::Platform::TraceEventHandle) == - sizeof(base::trace_event::TraceEventHandle), - "TraceEventHandle types must be same size"); - -blink::Platform::TraceEventHandle BlinkPlatformImpl::addTraceEvent( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - unsigned long long bind_id, - double timestamp, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - blink::WebConvertableToTraceFormat* convertable_values, - unsigned int flags) { - scoped_refptr<base::trace_event::ConvertableToTraceFormat> - convertable_wrappers[2]; - if (convertable_values) { - size_t size = std::min(static_cast<size_t>(num_args), - arraysize(convertable_wrappers)); - for (size_t i = 0; i < size; ++i) { - if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) { - convertable_wrappers[i] = - new ConvertableToTraceFormatWrapper(convertable_values[i]); - } - } - } - base::TimeTicks timestamp_tt = - base::TimeTicks() + base::TimeDelta::FromSecondsD(timestamp); - base::trace_event::TraceEventHandle handle = - TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP( - phase, category_group_enabled, name, id, bind_id, - base::PlatformThread::CurrentId(), timestamp_tt, num_args, arg_names, - arg_types, arg_values, convertable_wrappers, flags); - blink::Platform::TraceEventHandle result; - memcpy(&result, &handle, sizeof(result)); - return result; -} - -void BlinkPlatformImpl::updateTraceEventDuration( - const unsigned char* category_group_enabled, - const char* name, - TraceEventHandle handle) { - base::trace_event::TraceEventHandle traceEventHandle; - memcpy(&traceEventHandle, &handle, sizeof(handle)); - TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION( - category_group_enabled, name, traceEventHandle); -} - void BlinkPlatformImpl::registerMemoryDumpProvider( blink::WebMemoryDumpProvider* wmdp, const char* name) { WebMemoryDumpProviderAdapter* wmdp_adapter =
diff --git a/content/child/blink_platform_impl.h b/content/child/blink_platform_impl.h index ea44ffc..c245d4fbea 100644 --- a/content/child/blink_platform_impl.h +++ b/content/child/blink_platform_impl.h
@@ -119,26 +119,6 @@ int sample, int boundary_value) override; void histogramSparse(const char* name, int sample) override; - const unsigned char* getTraceCategoryEnabledFlag( - const char* category_name) override; - TraceEventAPIAtomicWord* getTraceSamplingState( - const unsigned thread_bucket) override; - TraceEventHandle addTraceEvent( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - unsigned long long bind_id, - double timestamp, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - blink::WebConvertableToTraceFormat* convertable_values, - unsigned int flags) override; - void updateTraceEventDuration(const unsigned char* category_group_enabled, - const char* name, - TraceEventHandle) override; void registerMemoryDumpProvider(blink::WebMemoryDumpProvider* wmdp, const char* name) override; void unregisterMemoryDumpProvider(
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h index 379f467..8ba0e58 100644 --- a/content/common/service_worker/service_worker_messages.h +++ b/content/common/service_worker/service_worker_messages.h
@@ -52,6 +52,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerFetchRequest) IPC_STRUCT_TRAITS_MEMBER(mode) + IPC_STRUCT_TRAITS_MEMBER(is_main_resource_load) IPC_STRUCT_TRAITS_MEMBER(request_context_type) IPC_STRUCT_TRAITS_MEMBER(frame_type) IPC_STRUCT_TRAITS_MEMBER(url) @@ -62,6 +63,7 @@ IPC_STRUCT_TRAITS_MEMBER(referrer) IPC_STRUCT_TRAITS_MEMBER(credentials_mode) IPC_STRUCT_TRAITS_MEMBER(redirect_mode) + IPC_STRUCT_TRAITS_MEMBER(client_id) IPC_STRUCT_TRAITS_MEMBER(is_reload) IPC_STRUCT_TRAITS_END()
diff --git a/content/common/service_worker/service_worker_types.cc b/content/common/service_worker/service_worker_types.cc index 8ab0fec..e9ff0b9 100644 --- a/content/common/service_worker/service_worker_types.cc +++ b/content/common/service_worker/service_worker_types.cc
@@ -21,6 +21,7 @@ ServiceWorkerFetchRequest::ServiceWorkerFetchRequest() : mode(FETCH_REQUEST_MODE_NO_CORS), + is_main_resource_load(false), request_context_type(REQUEST_CONTEXT_TYPE_UNSPECIFIED), frame_type(REQUEST_CONTEXT_FRAME_TYPE_NONE), blob_size(0), @@ -35,6 +36,7 @@ const Referrer& referrer, bool is_reload) : mode(FETCH_REQUEST_MODE_NO_CORS), + is_main_resource_load(false), request_context_type(REQUEST_CONTEXT_TYPE_UNSPECIFIED), frame_type(REQUEST_CONTEXT_FRAME_TYPE_NONE), url(url),
diff --git a/content/common/service_worker/service_worker_types.h b/content/common/service_worker/service_worker_types.h index 3f9c546..d3a9f8f2 100644 --- a/content/common/service_worker/service_worker_types.h +++ b/content/common/service_worker/service_worker_types.h
@@ -126,6 +126,7 @@ ~ServiceWorkerFetchRequest(); FetchRequestMode mode; + bool is_main_resource_load; RequestContextType request_context_type; RequestContextFrameType frame_type; GURL url; @@ -136,6 +137,7 @@ Referrer referrer; FetchCredentialsMode credentials_mode; FetchRedirectMode redirect_mode; + std::string client_id; bool is_reload; };
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java index 761592b..b0f8f3f0 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
@@ -256,8 +256,11 @@ mPendingAccent = 0; Editable editable = getEditableInternal(); - int selectionStartAfterReplacement = Selection.getSelectionStart(editable); - int selectionEndAfterReplacement = Selection.getSelectionStart(editable) + text.length(); + int selectionStartAfterReplacement = BaseInputConnection.getComposingSpanStart(editable); + if (selectionStartAfterReplacement == INVALID_COMPOSITION) { + selectionStartAfterReplacement = Selection.getSelectionStart(editable); + } + int selectionEndAfterReplacement = selectionStartAfterReplacement + text.length(); super.setComposingText(text, newCursorPosition);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java index 4259e54..5276a36 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -1041,6 +1041,13 @@ assertEquals("a", getTextBeforeCursor(10, 0)); assertEquals("befcd", getTextAfterCursor(10, 0)); waitAndVerifyStatesAndCalls(5, "abefcd", 1, 1, -1, -1); + + setComposingText("gh", 1); + setComposingText("i", 0); + finishComposingText(); + assertEquals("a", getTextBeforeCursor(10, 0)); + assertEquals("ibefcd", getTextAfterCursor(10, 0)); + waitAndVerifyStatesAndCalls(8, "aibefcd", 1, 1, -1, -1); } private CharSequence getTextBeforeCursor(final int length, final int flags)
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc index 39a0d348..a44bb34e 100644 --- a/content/renderer/render_frame_proxy.cc +++ b/content/renderer/render_frame_proxy.cc
@@ -21,6 +21,7 @@ #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_thread_impl.h" #include "content/renderer/render_view_impl.h" +#include "content/renderer/render_widget.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" @@ -56,7 +57,8 @@ // follow later. blink::WebRemoteFrame* web_frame = blink::WebRemoteFrame::create(scope, proxy.get()); - proxy->Init(web_frame, frame_to_replace->render_view()); + proxy->Init(web_frame, frame_to_replace->render_view(), + frame_to_replace->GetRenderWidget()); return proxy.release(); } @@ -78,8 +80,9 @@ scoped_ptr<RenderFrameProxy> proxy( new RenderFrameProxy(routing_id, MSG_ROUTING_NONE)); - RenderViewImpl* render_view = NULL; - blink::WebRemoteFrame* web_frame = NULL; + RenderViewImpl* render_view = nullptr; + RenderWidget* render_widget = nullptr; + blink::WebRemoteFrame* web_frame = nullptr; if (!parent) { // Create a top level WebRemoteFrame. @@ -87,6 +90,7 @@ web_frame = blink::WebRemoteFrame::create(replicated_state.scope, proxy.get()); render_view->webview()->setMainFrame(web_frame); + render_widget = render_view; } else { // Create a frame under an existing parent. The parent is always expected // to be a RenderFrameProxy, because navigations initiated by local frames @@ -97,13 +101,14 @@ blink::WebString::fromUTF8(replicated_state.name), replicated_state.sandbox_flags, proxy.get()); render_view = parent->render_view(); + render_widget = parent->render_widget(); } blink::WebFrame* opener = RenderFrameImpl::ResolveOpener(opener_routing_id, nullptr); web_frame->setOpener(opener); - proxy->Init(web_frame, render_view); + proxy->Init(web_frame, render_view, render_widget); // Initialize proxy's WebRemoteFrame with the security origin and other // replicated information. @@ -138,8 +143,9 @@ RenderFrameProxy::RenderFrameProxy(int routing_id, int frame_routing_id) : routing_id_(routing_id), frame_routing_id_(frame_routing_id), - web_frame_(NULL), - render_view_(NULL) { + web_frame_(nullptr), + render_view_(nullptr), + render_widget_(nullptr) { std::pair<RoutingIDProxyMap::iterator, bool> result = g_routing_id_proxy_map.Get().insert(std::make_pair(routing_id_, this)); CHECK(result.second) << "Inserting a duplicate item."; @@ -156,7 +162,7 @@ if (render_frame) render_frame->set_render_frame_proxy(nullptr); - render_view()->UnregisterRenderFrameProxy(this); + render_widget_->UnregisterRenderFrameProxy(this); CHECK(!web_frame_); RenderThread::Get()->RemoveRoute(routing_id_); @@ -164,15 +170,17 @@ } void RenderFrameProxy::Init(blink::WebRemoteFrame* web_frame, - RenderViewImpl* render_view) { + RenderViewImpl* render_view, + RenderWidget* render_widget) { CHECK(web_frame); CHECK(render_view); + CHECK(render_widget); web_frame_ = web_frame; render_view_ = render_view; + render_widget_ = render_widget; - // TODO(nick): Should all RenderFrameProxies remain observers of their views? - render_view_->RegisterRenderFrameProxy(this); + render_widget_->RegisterRenderFrameProxy(this); std::pair<FrameMap::iterator, bool> result = g_frame_map.Get().insert(std::make_pair(web_frame_, this)); @@ -180,6 +188,8 @@ } bool RenderFrameProxy::IsMainFrameDetachedFromTree() const { + if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) + return false; return web_frame_->top() == web_frame_ && render_view_->webview()->mainFrame()->isWebLocalFrame(); }
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h index 1ce0264..7581d38 100644 --- a/content/renderer/render_frame_proxy.h +++ b/content/renderer/render_frame_proxy.h
@@ -33,6 +33,7 @@ class ChildFrameCompositingHelper; class RenderFrameImpl; class RenderViewImpl; +class RenderWidget; struct FrameReplicationState; // When a page's frames are rendered by multiple processes, each renderer has a @@ -120,6 +121,9 @@ RenderViewImpl* render_view() { return render_view_; } blink::WebRemoteFrame* web_frame() { return web_frame_; } + // Returns the widget used for the local frame root. + RenderWidget* render_widget() { return render_widget_; } + // blink::WebRemoteFrameClient implementation: void frameDetached(DetachType type) override; void postMessageEvent(blink::WebLocalFrame* sourceFrame, @@ -144,7 +148,9 @@ private: RenderFrameProxy(int routing_id, int frame_routing_id); - void Init(blink::WebRemoteFrame* frame, RenderViewImpl* render_view); + void Init(blink::WebRemoteFrame* frame, + RenderViewImpl* render_view, + RenderWidget* render_widget); // IPC::Listener bool OnMessageReceived(const IPC::Message& msg) override; @@ -179,6 +185,7 @@ scoped_refptr<ChildFrameCompositingHelper> compositing_helper_; RenderViewImpl* render_view_; + RenderWidget* render_widget_; DISALLOW_COPY_AND_ASSIGN(RenderFrameProxy); };
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc index c0a84c0..9119c571 100644 --- a/content/renderer/service_worker/service_worker_context_client.cc +++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -734,12 +734,14 @@ blink::WebString::fromUTF8(request.referrer.url.spec()), request.referrer.policy); webRequest.setMode(GetBlinkFetchRequestMode(request.mode)); + webRequest.setIsMainResourceLoad(request.is_main_resource_load); webRequest.setCredentialsMode( GetBlinkFetchCredentialsMode(request.credentials_mode)); webRequest.setRedirectMode(GetBlinkFetchRedirectMode(request.redirect_mode)); webRequest.setRequestContext( GetBlinkRequestContext(request.request_context_type)); webRequest.setFrameType(GetBlinkFrameType(request.frame_type)); + webRequest.setClientId(blink::WebString::fromUTF8(request.client_id)); webRequest.setIsReload(request.is_reload); proxy_->dispatchFetchEvent(request_id, webRequest); }
diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc index 0767892..28a348e 100644 --- a/courgette/assembly_program.cc +++ b/courgette/assembly_program.cc
@@ -502,7 +502,7 @@ const int AssemblyProgram::kLabelLowerLimit = 5; CheckBool AssemblyProgram::TrimLabels() { - // For now only trim for ARM binaries + // For now only trim for ARM binaries. if (kind() != EXE_ELF_32_ARM) return true; @@ -510,22 +510,8 @@ VLOG(1) << "TrimLabels: threshold " << lower_limit; - // Remove underused labels from the list of labels - RVAToLabel::iterator it = rel32_labels_.begin(); - while (it != rel32_labels_.end()) { - if (it->second->count_ <= lower_limit) { - // Note: it appears to me (grt) that this leaks the Label instances. I - // *think* the right thing would be to add it->second to a collection for - // which all elements are freed via UncheckedDelete after the instruction - // fixup loop below. - rel32_labels_.erase(it++); - } else { - ++it; - } - } - // Walk through the list of instructions, replacing trimmed labels - // with the original machine instruction + // with the original machine instruction. for (size_t i = 0; i < instructions_.size(); ++i) { Instruction* instruction = instructions_[i]; switch (instruction->op()) { @@ -552,6 +538,17 @@ } } + // Remove and deallocate underused Labels. + RVAToLabel::iterator it = rel32_labels_.begin(); + while (it != rel32_labels_.end()) { + if (it->second->count_ <= lower_limit) { + UncheckedDelete(it->second); + rel32_labels_.erase(it++); + } else { + ++it; + } + } + return true; }
diff --git a/courgette/courgette_tool.cc b/courgette/courgette_tool.cc index 88c346b..635dd91a 100644 --- a/courgette/courgette_tool.cc +++ b/courgette/courgette_tool.cc
@@ -84,6 +84,13 @@ if (parse_status != courgette::C_OK) Problem("Can't parse input."); + // Trim labels below a certain threshold + const courgette::Status trim_status = TrimLabels(program); + if (trim_status != courgette::C_OK) { + courgette::DeleteAssemblyProgram(program); + Problem("Can't trim labels."); + } + courgette::EncodedProgram* encoded = NULL; const courgette::Status encode_status = Encode(program, &encoded);
diff --git a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java index a3a38ba0..28c3739 100644 --- a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java +++ b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
@@ -99,34 +99,32 @@ @CalledByNative protected boolean hasVideo() { - TrackInfo trackInfo[] = getLocalPlayer().getTrackInfo(); - - // HLS media does not have the track info, so we treat them conservatively. - if (trackInfo.length == 0) return true; - - for (TrackInfo info : trackInfo) { - // TODO(zqzhang): may be we can have a histogram recording - // media track types in the future. - // See http://crbug.com/571411 - if (TrackInfo.MEDIA_TRACK_TYPE_VIDEO == info.getTrackType()) return true; - if (TrackInfo.MEDIA_TRACK_TYPE_UNKNOWN == info.getTrackType()) return true; - } - return false; + return hasTrack(TrackInfo.MEDIA_TRACK_TYPE_VIDEO); } @CalledByNative protected boolean hasAudio() { - TrackInfo trackInfo[] = getLocalPlayer().getTrackInfo(); + return hasTrack(TrackInfo.MEDIA_TRACK_TYPE_AUDIO); + } - // HLS media does not have the track info, so we treat them conservatively. - if (trackInfo.length == 0) return true; + private boolean hasTrack(int trackType) { + try { + TrackInfo trackInfo[] = getLocalPlayer().getTrackInfo(); - for (TrackInfo info : trackInfo) { - // TODO(zqzhang): may be we can have a histogram recording - // media track types in the future. - // See http://crbug.com/571411 - if (TrackInfo.MEDIA_TRACK_TYPE_AUDIO == info.getTrackType()) return true; - if (TrackInfo.MEDIA_TRACK_TYPE_UNKNOWN == info.getTrackType()) return true; + // HLS media does not have the track info, so we treat them conservatively. + if (trackInfo.length == 0) return true; + + for (TrackInfo info : trackInfo) { + // TODO(zqzhang): may be we can have a histogram recording + // media track types in the future. + // See http://crbug.com/571411 + if (trackType == info.getTrackType()) return true; + if (TrackInfo.MEDIA_TRACK_TYPE_UNKNOWN == info.getTrackType()) return true; + } + } catch (RuntimeException e) { + // Exceptions may come from getTrackInfo (IllegalStateException/RuntimeException), or + // from some customized OS returning null TrackInfos (NullPointerException). + return true; } return false; }
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc index deaba14..2f1fc0a 100644 --- a/media/base/android/media_player_bridge.cc +++ b/media/base/android/media_player_bridge.cc
@@ -311,11 +311,13 @@ } bool MediaPlayerBridge::HasVideo() const { + DCHECK(prepared_); JNIEnv* env = base::android::AttachCurrentThread(); return Java_MediaPlayerBridge_hasVideo(env, j_media_player_bridge_.obj()); } bool MediaPlayerBridge::HasAudio() const { + DCHECK(prepared_); JNIEnv* env = base::android::AttachCurrentThread(); return Java_MediaPlayerBridge_hasAudio(env, j_media_player_bridge_.obj()); }
diff --git a/media/blink/run_all_unittests.cc b/media/blink/run_all_unittests.cc index b3a946d..bcbc4e3 100644 --- a/media/blink/run_all_unittests.cc +++ b/media/blink/run_all_unittests.cc
@@ -70,8 +70,6 @@ public: ~TestBlinkPlatformSupport() override; - const unsigned char* getTraceCategoryEnabledFlag( - const char* categoryName) override; blink::WebThread* currentThread() override { return &m_currentThread; } private: @@ -80,12 +78,6 @@ TestBlinkPlatformSupport::~TestBlinkPlatformSupport() {} -const unsigned char* TestBlinkPlatformSupport::getTraceCategoryEnabledFlag( - const char* categoryName) { - static const unsigned char tracingIsDisabled = 0; - return &tracingIsDisabled; -} - class BlinkMediaTestSuite : public base::TestSuite { public: BlinkMediaTestSuite(int argc, char** argv);
diff --git a/printing/printing_context_win.cc b/printing/printing_context_win.cc index 4eff7228..8a6dc17a 100644 --- a/printing/printing_context_win.cc +++ b/printing/printing_context_win.cc
@@ -17,8 +17,8 @@ #include "printing/printing_utils.h" #include "printing/units.h" #include "skia/ext/skia_utils_win.h" -#include "ui/aura/remote_window_tree_host_win.h" #include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" namespace printing {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json index 799df13f..fd775e3 100644 --- a/testing/buildbot/chromium.win.json +++ b/testing/buildbot/chromium.win.json
@@ -348,12 +348,6 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "ash_unittests" - }, - { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "aura_unittests" }, { @@ -740,7 +734,6 @@ "accessibility_unittests", "app_list_unittests", "app_shell_unittests", - "ash_unittests", "aura_unittests", "cacheinvalidation_unittests", "cast_unittests", @@ -813,12 +806,6 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "ash_unittests" - }, - { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "aura_unittests" }, { @@ -1214,12 +1201,6 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "ash_unittests" - }, - { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "aura_unittests" }, { @@ -1559,7 +1540,6 @@ "accessibility_unittests", "app_list_unittests", "app_shell_unittests", - "ash_unittests", "aura_unittests", "cacheinvalidation_unittests", "cast_unittests", @@ -1670,7 +1650,6 @@ "accessibility_unittests", "app_list_unittests", "app_shell_unittests", - "ash_unittests", "aura_unittests", "cacheinvalidation_unittests", "cast_unittests",
diff --git a/testing/libfuzzer/fuzzers/brotli_fuzzer.cc b/testing/libfuzzer/fuzzers/brotli_fuzzer.cc index 9c45db4..41e5d350 100644 --- a/testing/libfuzzer/fuzzers/brotli_fuzzer.cc +++ b/testing/libfuzzer/fuzzers/brotli_fuzzer.cc
@@ -8,20 +8,35 @@ // Entry point for LibFuzzer. extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) { - int kBufferSize = 1024; + size_t addend = 0; + if (size > 0) + addend = data[size - 1] & 7; + const uint8_t* next_in = data; + + const int kBufferSize = 1024; uint8_t* buffer = new uint8_t[kBufferSize]; BrotliState* state = new BrotliState(); BrotliStateInit(state); - size_t avail_in = size; - const uint8_t* next_in = data; - BrotliResult result = BROTLI_RESULT_NEEDS_MORE_OUTPUT; - while (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) { - size_t avail_out = kBufferSize; - uint8_t* next_out = buffer; - size_t total_out; - result = BrotliDecompressStream( - &avail_in, &next_in, &avail_out, &next_out, &total_out, state); + if (addend == 0) + addend = size; + /* Test both fast (addend == size) and slow (addend <= 7) decoding paths. */ + for (size_t i = 0; i < size;) { + size_t next_i = i + addend; + if (next_i > size) + next_i = size; + size_t avail_in = next_i - i; + i = next_i; + BrotliResult result = BROTLI_RESULT_NEEDS_MORE_OUTPUT; + while (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) { + size_t avail_out = kBufferSize; + uint8_t* next_out = buffer; + size_t total_out; + result = BrotliDecompressStream( + &avail_in, &next_in, &avail_out, &next_out, &total_out, state); + } + if (result != BROTLI_RESULT_NEEDS_MORE_INPUT) + break; } BrotliStateCleanup(state);
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 3bc43ece..af9de86 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -365,6 +365,7 @@ # SPv2 paint properties are still being implemented. crbug.com/537409 virtual/spv2/ [ Skip ] crbug.com/563667 virtual/spv2/fast/block/basic/001.html [ Pass ] +crbug.com/563667 virtual/spv2/fast/block/positioning/static-distance-with-positioned-ancestor.html [ Pass ] # In imported/web-platform-tests/html/, we prefer checking in failure # expectation files. The following tests with [ Failure ] don't have failure
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation-expected.txt new file mode 100644 index 0000000..4714f0e8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation-expected.txt
@@ -0,0 +1,553 @@ +This is a testharness.js-based test. +PASS This test uses interpolation-test.js. +PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (-0.3) is [path('m 0 0 h 3')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0) is [path('m 0 0 h 3')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.3) is [path('m 0 0 h 3')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.5) is [path('m 0 0 h 3')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.6) is [path('m 0 0 h 3')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1) is [path('m 0 0 h 3')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1.5) is [path('m 0 0 h 3')] +PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (-0.3) is [path('m 20 0 v 2')] +PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0) is [path('m 20 0 v 2')] +PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.3) is [path('m 20 0 v 2')] +PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.5) is [path('m 20 0 v 2')] +PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.6) is [path('m 20 0 v 2')] +PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1) is [path('m 20 0 v 2')] +PASS CSS Transitions: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1.5) is [path('m 20 0 v 2')] +PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (-0.3) is [path('m 1 2 l 3 4')] +PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0) is [path('m 1 2 l 3 4')] +PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.3) is [path('m 1 2 l 3 4')] +PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.5) is [path('m 1 2 l 3 4')] +PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.6) is [path('m 1 2 l 3 4')] +PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1) is [path('m 1 2 l 3 4')] +PASS CSS Transitions: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1.5) is [path('m 1 2 l 3 4')] +PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (-0.4) is [path('m 0 0 Z')] +PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0) is [path('m 0 0 Z')] +PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.2) is [path('m 0 0 Z')] +PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.6) is [path('m 0 0 Z')] +PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1) is [path('m 0 0 Z')] +PASS CSS Transitions: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1.4) is [path('m 0 0 Z')] +PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (-0.4) is [path('M 16 42')] +PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0) is [path('M 20 50')] +PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.2) is [path('M 22 54')] +PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.6) is [path('M 26 62')] +PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1) is [path('M 30 70')] +PASS CSS Transitions: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1.4) is [path('M 34 78')] +PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (-0.4) is [path('m 16 42')] +PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0) is [path('m 20 50')] +PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.2) is [path('m 22 54')] +PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.6) is [path('m 26 62')] +PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1) is [path('m 30 70')] +PASS CSS Transitions: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1.4) is [path('m 34 78')] +PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (-0.4) is [path('m 0 0 L 16 42')] +PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0) is [path('m 0 0 L 20 50')] +PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.2) is [path('m 0 0 L 22 54')] +PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.6) is [path('m 0 0 L 26 62')] +PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1) is [path('m 0 0 L 30 70')] +PASS CSS Transitions: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1.4) is [path('m 0 0 L 34 78')] +PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (-0.4) is [path('m 0 0 l 16 42')] +PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0) is [path('m 0 0 l 20 50')] +PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.2) is [path('m 0 0 l 22 54')] +PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.6) is [path('m 0 0 l 26 62')] +PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1) is [path('m 0 0 l 30 70')] +PASS CSS Transitions: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1.4) is [path('m 0 0 l 34 78')] +PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 C 30 40 50 60 10 20')] +PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0) is [path('m 0 0 C 32 42 52 62 12 22')] +PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 C 33 43 53 63 13 23')] +PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 C 35 45 55 65 15 25')] +PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1) is [path('m 0 0 C 37 47 57 67 17 27')] +PASS CSS Transitions: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 C 39 49 59 69 19 29')] +PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 c 30 40 50 60 10 20')] +PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0) is [path('m 0 0 c 32 42 52 62 12 22')] +PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 c 33 43 53 63 13 23')] +PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 c 35 45 55 65 15 25')] +PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1) is [path('m 0 0 c 37 47 57 67 17 27')] +PASS CSS Transitions: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 c 39 49 59 69 19 29')] +PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (-0.4) is [path('m 0 0 Q 30 40 50 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0) is [path('m 0 0 Q 32 42 52 62')] +PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.2) is [path('m 0 0 Q 33 43 53 63')] +PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.6) is [path('m 0 0 Q 35 45 55 65')] +PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1) is [path('m 0 0 Q 37 47 57 67')] +PASS CSS Transitions: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1.4) is [path('m 0 0 Q 39 49 59 69')] +PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (-0.4) is [path('m 0 0 q 30 40 50 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0) is [path('m 0 0 q 32 42 52 62')] +PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.2) is [path('m 0 0 q 33 43 53 63')] +PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.6) is [path('m 0 0 q 35 45 55 65')] +PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1) is [path('m 0 0 q 37 47 57 67')] +PASS CSS Transitions: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1.4) is [path('m 0 0 q 39 49 59 69')] +PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 A -10 -2.98023e-7 10 1 0 20 30')] +PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 A 10 20 30 1 0 40 50')] +PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 A 20 30 40 1 0 50 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 A 40 50 60 0 1 70 80')] +PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 A 60 70 80 0 1 90 100')] +PASS CSS Transitions: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 A 80 90 100 0 1 110 120')] +PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 a -10 -2.98023e-7 10 1 0 20 30')] +PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 a 10 20 30 1 0 40 50')] +PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 a 20 30 40 1 0 50 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 a 40 50 60 0 1 70 80')] +PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 a 60 70 80 0 1 90 100')] +PASS CSS Transitions: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 a 80 90 100 0 1 110 120')] +PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (-0.4) is [path('m 0 0 H -10')] +PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0) is [path('m 0 0 H 10')] +PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.2) is [path('m 0 0 H 20')] +PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.6) is [path('m 0 0 H 40')] +PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1) is [path('m 0 0 H 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1.4) is [path('m 0 0 H 80')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (-0.4) is [path('m 0 0 h -10')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0) is [path('m 0 0 h 10')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.2) is [path('m 0 0 h 20')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.6) is [path('m 0 0 h 40')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1) is [path('m 0 0 h 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1.4) is [path('m 0 0 h 80')] +PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (-0.4) is [path('m 0 0 V -10')] +PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0) is [path('m 0 0 V 10')] +PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.2) is [path('m 0 0 V 20')] +PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.6) is [path('m 0 0 V 40')] +PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1) is [path('m 0 0 V 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1.4) is [path('m 0 0 V 80')] +PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (-0.4) is [path('m 0 0 v -10')] +PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0) is [path('m 0 0 v 10')] +PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.2) is [path('m 0 0 v 20')] +PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.6) is [path('m 0 0 v 40')] +PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1) is [path('m 0 0 v 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1.4) is [path('m 0 0 v 80')] +PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (-0.4) is [path('m 0 0 S 30 40 50 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0) is [path('m 0 0 S 32 42 52 62')] +PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.2) is [path('m 0 0 S 33 43 53 63')] +PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.6) is [path('m 0 0 S 35 45 55 65')] +PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1) is [path('m 0 0 S 37 47 57 67')] +PASS CSS Transitions: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1.4) is [path('m 0 0 S 39 49 59 69')] +PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (-0.4) is [path('m 0 0 s 30 40 50 60')] +PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0) is [path('m 0 0 s 32 42 52 62')] +PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.2) is [path('m 0 0 s 33 43 53 63')] +PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.6) is [path('m 0 0 s 35 45 55 65')] +PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1) is [path('m 0 0 s 37 47 57 67')] +PASS CSS Transitions: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1.4) is [path('m 0 0 s 39 49 59 69')] +PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (-0.4) is [path('m 0 0 T 16 42')] +PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0) is [path('m 0 0 T 20 50')] +PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.2) is [path('m 0 0 T 22 54')] +PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.6) is [path('m 0 0 T 26 62')] +PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1) is [path('m 0 0 T 30 70')] +PASS CSS Transitions: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1.4) is [path('m 0 0 T 34 78')] +PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (-0.4) is [path('m 0 0 t 16 42')] +PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0) is [path('m 0 0 t 20 50')] +PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.2) is [path('m 0 0 t 22 54')] +PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.6) is [path('m 0 0 t 26 62')] +PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1) is [path('m 0 0 t 30 70')] +PASS CSS Transitions: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1.4) is [path('m 0 0 t 34 78')] +FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (-0.4) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 120 20 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 - 180 Z ' ) " but got "path ( ' M 0 0 L 100 100 M 100 200 L 200 200 Z L 120 20 Z ' ) " +PASS CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] +FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.2) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 240 140 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 - 60 Z ' ) " but got "path ( ' M 0 0 L 100 100 M 100 200 L 200 200 Z L 240 140 Z ' ) " +FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 20 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 160 20 Z ' ) " but got "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 20 Z ' ) " +PASS CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 200 100 Z')] +FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 280 180 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 240 180 Z ' ) " but got "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 280 180 Z ' ) " +FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (-0.4) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 160 100 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 - 100 Z ' ) " but got "path ( ' M 0 0 L 100 100 M 100 200 L 200 200 Z L 160 100 Z ' ) " +PASS CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] +FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.2) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 220 100 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 - 100 Z ' ) " but got "path ( ' M 0 0 L 100 100 M 100 200 L 200 200 Z L 220 100 Z ' ) " +FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -100 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 - 100 Z ' ) " but got "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 - 100 Z ' ) " +PASS CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +FAIL CSS Transitions: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 140 -100 Z')] assert_equals: expected "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 - 100 Z ' ) " but got "path ( ' M 0 0 L 100 100 m 0 100 l 100 0 Z l 140 - 100 Z ' ) " +FAIL CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (-0.4) is [path('m -30 -20 l 20 30 Z l 90 100 Z m 90 100 l 90 60 Z t 90 160')] assert_equals: expected "path ( ' M - 30 - 20 L - 10 10 Z L 52 68 Z M 72 84 L 162 144 Z T 126 220 ' ) " but got "path ( ' m - 30 - 20 l 20 30 Z l 90 100 Z m 90 100 l 90 60 Z t 90 160 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0) is [path('m 10 20 l 20 30 Z l 50 60 Z m 70 80 l 90 60 Z t 70 120')] +FAIL CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.2) is [path('m 30 40 l 20 30 Z l 30 40 Z m 60 70 l 90 60 Z t 60 100')] assert_equals: expected "path ( ' M 30 40 L 50 70 Z L 64 86 Z M 84 108 L 174 168 Z T 162 220 ' ) " but got "path ( ' m 30 40 l 20 30 Z l 30 40 Z m 60 70 l 90 60 Z t 60 100 ' ) " +FAIL CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.6) is [path('M 70 80 L 90 110 Z L 80 110 Z M 120 160 L 210 220 Z T 250 280')] assert_equals: expected "path ( ' M 70 80 L 90 110 Z L 72 98 Z M 92 124 L 182 184 Z T 186 220 ' ) " but got "path ( ' M 70 80 L 90 110 Z L 80 110 Z M 120 160 L 210 220 Z T 250 280 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1) is [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] +FAIL CSS Transitions: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1.4) is [path('M 150 160 L 170 190 Z L 80 110 Z M 80 120 L 170 180 Z T 170 160')] assert_equals: expected "path ( ' M 150 160 L 170 190 Z L 88 122 Z M 108 156 L 198 216 Z T 234 220 ' ) " but got "path ( ' M 150 160 L 170 190 Z L 80 110 Z M 80 120 L 170 180 Z T 170 160 ' ) " +FAIL CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (-0.4) is [path('m -30 -20 c 44 58 34 68 84 78 c 82 88 132 98 112 118')] assert_equals: expected "path ( ' M - 30 - 20 C 14 38 4 48 54 58 C 136 146 186 156 166 176 ' ) " but got "path ( ' m - 30 - 20 c 44 58 34 68 84 78 c 82 88 132 98 112 118 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0) is [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] +FAIL CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.2) is [path('m 30 40 c 38 46 28 56 78 66 c 94 106 144 116 124 136')] assert_equals: expected "path ( ' M 30 40 C 68 86 58 96 108 106 C 202 212 252 222 232 242 ' ) " but got "path ( ' m 30 40 c 38 46 28 56 78 66 c 94 106 144 116 124 136 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.6) is [path('M 70 80 C 104 118 94 128 144 138 C 246 256 296 266 276 286')] +PASS CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1) is [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] +PASS CSS Transitions: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1.4) is [path('M 150 160 C 176 182 166 192 216 202 C 334 344 384 354 364 374')] +FAIL CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (-0.4) is [path('m -30 -20 q 34 68 44 58 q 116 90 106 100')] assert_equals: expected "path ( ' M - 30 - 20 Q 4 48 14 38 Q 130 128 120 138 ' ) " but got "path ( ' m - 30 - 20 q 34 68 44 58 q 116 90 106 100 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0) is [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] +FAIL CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.2) is [path('m 30 40 q 28 56 38 46 q 92 60 82 70')] assert_equals: expected "path ( ' M 30 40 Q 58 96 68 86 Q 160 146 150 156 ' ) " but got "path ( ' m 30 40 q 28 56 38 46 q 92 60 82 70 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.6) is [path('M 70 80 Q 94 128 104 118 Q 180 158 170 168')] +PASS CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1) is [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] +PASS CSS Transitions: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1.4) is [path('M 150 160 Q 166 192 176 182 Q 220 182 210 192')] +FAIL CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (-0.4) is [path('m -30 -20 s 34 68 44 58 s 116 90 106 100')] assert_equals: expected "path ( ' M - 30 - 20 S 4 48 14 38 S 130 128 120 138 ' ) " but got "path ( ' m - 30 - 20 s 34 68 44 58 s 116 90 106 100 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0) is [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] +FAIL CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.2) is [path('m 30 40 s 28 56 38 46 s 92 60 82 70')] assert_equals: expected "path ( ' M 30 40 S 58 96 68 86 S 160 146 150 156 ' ) " but got "path ( ' m 30 40 s 28 56 38 46 s 92 60 82 70 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.6) is [path('M 70 80 S 94 128 104 118 S 180 158 170 168')] +PASS CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1) is [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] +PASS CSS Transitions: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1.4) is [path('M 150 160 S 166 192 176 182 S 220 182 210 192')] +FAIL CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (-0.4) is [path('m -30 -20 h 34 v 48 h 22 v 36 l 90 104')] assert_equals: expected "path ( ' M - 30 - 20 H 4 V 28 H 26 V 64 L 116 168 ' ) " but got "path ( ' m - 30 - 20 h 34 v 48 h 22 v 36 l 90 104 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0) is [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] +FAIL CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.2) is [path('m 30 40 h 28 v 36 h 64 v 72 l 60 68')] assert_equals: expected "path ( ' M 30 40 H 58 V 76 H 122 V 148 L 182 216 ' ) " but got "path ( ' m 30 40 h 28 v 36 h 64 v 72 l 60 68 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.6) is [path('M 70 80 H 94 V 108 H 186 V 204 L 226 248')] +PASS CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1) is [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] +PASS CSS Transitions: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1.4) is [path('M 150 160 H 166 V 172 H 314 V 316 L 314 312')] +FAIL CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (-0.4) is [path('m 6 16 a -10 -2.98023e-7 10 1 0 28 42 a 90 100 10 1 1 196 70')] assert_equals: expected "path ( ' M 6 16 A - 10 0 10 1 0 34 58 A 90 100 10 1 1 230 128 ' ) " but got "path ( ' m 6 16 a - 10 0 10 1 0 28 42 a 90 100 10 1 1 196 70 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0) is [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] +FAIL CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.2) is [path('m 12 22 a 20 30 40 1 0 46 54 a 120 130 40 1 1 112 40')] assert_equals: expected "path ( ' M 12 22 A 20 30 40 1 0 58 76 A 120 130 40 1 1 170 116 ' ) " but got "path ( ' m 12 22 a 20 30 40 1 0 46 54 a 120 130 40 1 1 112 40 ' ) " +PASS CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.6) is [path('M 16 26 A 40 50 60 0 1 74 88 A 140 150 60 0 1 130 108')] +PASS CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1) is [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] +PASS CSS Transitions: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1.4) is [path('M 24 34 A 80 90 100 0 1 106 112 A 180 190 100 0 1 50 92')] +PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (-0.3) is [path('m 0 0 h 1 h 2')] +PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0) is [path('m 0 0 h 1 h 2')] +PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.3) is [path('m 0 0 h 1 h 2')] +PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.5) is [path('m 0 0 h 3')] +PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.6) is [path('m 0 0 h 3')] +PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1) is [path('m 0 0 h 3')] +PASS CSS Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1.5) is [path('m 0 0 h 3')] +PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (-0.3) is [path('m 10 0 h 1')] +PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0) is [path('m 10 0 h 1')] +PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.3) is [path('m 10 0 h 1')] +PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.5) is [path('m 20 0 v 2')] +PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.6) is [path('m 20 0 v 2')] +PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1) is [path('m 20 0 v 2')] +PASS CSS Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1.5) is [path('m 20 0 v 2')] +PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (-0.3) is [path('m 1 2 l 3 4 Z')] +PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0) is [path('m 1 2 l 3 4 Z')] +PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.3) is [path('m 1 2 l 3 4 Z')] +PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.5) is [path('m 1 2 l 3 4')] +PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.6) is [path('m 1 2 l 3 4')] +PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1) is [path('m 1 2 l 3 4')] +PASS CSS Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1.5) is [path('m 1 2 l 3 4')] +PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (-0.4) is [path('m 0 0 Z')] +PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0) is [path('m 0 0 Z')] +PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.2) is [path('m 0 0 Z')] +PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.6) is [path('m 0 0 Z')] +PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1) is [path('m 0 0 Z')] +PASS CSS Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1.4) is [path('m 0 0 Z')] +PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (-0.4) is [path('M 16 42')] +PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0) is [path('M 20 50')] +PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.2) is [path('M 22 54')] +PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.6) is [path('M 26 62')] +PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1) is [path('M 30 70')] +PASS CSS Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1.4) is [path('M 34 78')] +PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (-0.4) is [path('m 16 42')] +PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0) is [path('m 20 50')] +PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.2) is [path('m 22 54')] +PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.6) is [path('m 26 62')] +PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1) is [path('m 30 70')] +PASS CSS Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1.4) is [path('m 34 78')] +PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (-0.4) is [path('m 0 0 L 16 42')] +PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0) is [path('m 0 0 L 20 50')] +PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.2) is [path('m 0 0 L 22 54')] +PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.6) is [path('m 0 0 L 26 62')] +PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1) is [path('m 0 0 L 30 70')] +PASS CSS Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1.4) is [path('m 0 0 L 34 78')] +PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (-0.4) is [path('m 0 0 l 16 42')] +PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0) is [path('m 0 0 l 20 50')] +PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.2) is [path('m 0 0 l 22 54')] +PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.6) is [path('m 0 0 l 26 62')] +PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1) is [path('m 0 0 l 30 70')] +PASS CSS Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1.4) is [path('m 0 0 l 34 78')] +PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 C 30 40 50 60 10 20')] +PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0) is [path('m 0 0 C 32 42 52 62 12 22')] +PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 C 33 43 53 63 13 23')] +PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 C 35 45 55 65 15 25')] +PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1) is [path('m 0 0 C 37 47 57 67 17 27')] +PASS CSS Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 C 39 49 59 69 19 29')] +PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 c 30 40 50 60 10 20')] +PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0) is [path('m 0 0 c 32 42 52 62 12 22')] +PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 c 33 43 53 63 13 23')] +PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 c 35 45 55 65 15 25')] +PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1) is [path('m 0 0 c 37 47 57 67 17 27')] +PASS CSS Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 c 39 49 59 69 19 29')] +PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (-0.4) is [path('m 0 0 Q 30 40 50 60')] +PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0) is [path('m 0 0 Q 32 42 52 62')] +PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.2) is [path('m 0 0 Q 33 43 53 63')] +PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.6) is [path('m 0 0 Q 35 45 55 65')] +PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1) is [path('m 0 0 Q 37 47 57 67')] +PASS CSS Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1.4) is [path('m 0 0 Q 39 49 59 69')] +PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (-0.4) is [path('m 0 0 q 30 40 50 60')] +PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0) is [path('m 0 0 q 32 42 52 62')] +PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.2) is [path('m 0 0 q 33 43 53 63')] +PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.6) is [path('m 0 0 q 35 45 55 65')] +PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1) is [path('m 0 0 q 37 47 57 67')] +PASS CSS Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1.4) is [path('m 0 0 q 39 49 59 69')] +PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 A -10 0 10 1 0 20 30')] +PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 A 10 20 30 1 0 40 50')] +PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 A 20 30 40 1 0 50 60')] +PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 A 40 50 60 0 1 70 80')] +PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 A 60 70 80 0 1 90 100')] +PASS CSS Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 A 80 90 100 0 1 110 120')] +PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 a -10 0 10 1 0 20 30')] +PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 a 10 20 30 1 0 40 50')] +PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 a 20 30 40 1 0 50 60')] +PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 a 40 50 60 0 1 70 80')] +PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 a 60 70 80 0 1 90 100')] +PASS CSS Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 a 80 90 100 0 1 110 120')] +PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (-0.4) is [path('m 0 0 H -10')] +PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0) is [path('m 0 0 H 10')] +PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.2) is [path('m 0 0 H 20')] +PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.6) is [path('m 0 0 H 40')] +PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1) is [path('m 0 0 H 60')] +PASS CSS Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1.4) is [path('m 0 0 H 80')] +PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (-0.4) is [path('m 0 0 h -10')] +PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0) is [path('m 0 0 h 10')] +PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.2) is [path('m 0 0 h 20')] +PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.6) is [path('m 0 0 h 40')] +PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1) is [path('m 0 0 h 60')] +PASS CSS Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1.4) is [path('m 0 0 h 80')] +PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (-0.4) is [path('m 0 0 V -10')] +PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0) is [path('m 0 0 V 10')] +PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.2) is [path('m 0 0 V 20')] +PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.6) is [path('m 0 0 V 40')] +PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1) is [path('m 0 0 V 60')] +PASS CSS Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1.4) is [path('m 0 0 V 80')] +PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (-0.4) is [path('m 0 0 v -10')] +PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0) is [path('m 0 0 v 10')] +PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.2) is [path('m 0 0 v 20')] +PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.6) is [path('m 0 0 v 40')] +PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1) is [path('m 0 0 v 60')] +PASS CSS Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1.4) is [path('m 0 0 v 80')] +PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (-0.4) is [path('m 0 0 S 30 40 50 60')] +PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0) is [path('m 0 0 S 32 42 52 62')] +PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.2) is [path('m 0 0 S 33 43 53 63')] +PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.6) is [path('m 0 0 S 35 45 55 65')] +PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1) is [path('m 0 0 S 37 47 57 67')] +PASS CSS Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1.4) is [path('m 0 0 S 39 49 59 69')] +PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (-0.4) is [path('m 0 0 s 30 40 50 60')] +PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0) is [path('m 0 0 s 32 42 52 62')] +PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.2) is [path('m 0 0 s 33 43 53 63')] +PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.6) is [path('m 0 0 s 35 45 55 65')] +PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1) is [path('m 0 0 s 37 47 57 67')] +PASS CSS Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1.4) is [path('m 0 0 s 39 49 59 69')] +PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (-0.4) is [path('m 0 0 T 16 42')] +PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0) is [path('m 0 0 T 20 50')] +PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.2) is [path('m 0 0 T 22 54')] +PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.6) is [path('m 0 0 T 26 62')] +PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1) is [path('m 0 0 T 30 70')] +PASS CSS Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1.4) is [path('m 0 0 T 34 78')] +PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (-0.4) is [path('m 0 0 t 16 42')] +PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0) is [path('m 0 0 t 20 50')] +PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.2) is [path('m 0 0 t 22 54')] +PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.6) is [path('m 0 0 t 26 62')] +PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1) is [path('m 0 0 t 30 70')] +PASS CSS Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1.4) is [path('m 0 0 t 34 78')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (-0.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -180 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.2) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 -60 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 160 20 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 200 100 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 240 180 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (-0.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.2) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS CSS Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (-0.4) is [path('M -30 -20 L -10 10 Z L 52 68 Z M 72 84 L 162 144 Z T 126 220')] +PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0) is [path('m 10 20 l 20 30 Z l 50 60 Z m 70 80 l 90 60 Z t 70 120')] +PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.2) is [path('M 30 40 L 50 70 Z L 64 86 Z M 84 108 L 174 168 Z T 162 220')] +PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.6) is [path('M 70 80 L 90 110 Z L 72 98 Z M 92 124 L 182 184 Z T 186 220')] +PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1) is [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] +PASS CSS Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1.4) is [path('M 150 160 L 170 190 Z L 88 122 Z M 108 156 L 198 216 Z T 234 220')] +PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (-0.4) is [path('M -30 -20 C 14 38 4 48 54 58 C 136 146 186 156 166 176')] +PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0) is [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] +PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.2) is [path('M 30 40 C 68 86 58 96 108 106 C 202 212 252 222 232 242')] +PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.6) is [path('M 70 80 C 104 118 94 128 144 138 C 246 256 296 266 276 286')] +PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1) is [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] +PASS CSS Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1.4) is [path('M 150 160 C 176 182 166 192 216 202 C 334 344 384 354 364 374')] +PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (-0.4) is [path('M -30 -20 Q 4 48 14 38 Q 130 128 120 138')] +PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0) is [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] +PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.2) is [path('M 30 40 Q 58 96 68 86 Q 160 146 150 156')] +PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.6) is [path('M 70 80 Q 94 128 104 118 Q 180 158 170 168')] +PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1) is [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] +PASS CSS Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1.4) is [path('M 150 160 Q 166 192 176 182 Q 220 182 210 192')] +PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (-0.4) is [path('M -30 -20 S 4 48 14 38 S 130 128 120 138')] +PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0) is [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] +PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.2) is [path('M 30 40 S 58 96 68 86 S 160 146 150 156')] +PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.6) is [path('M 70 80 S 94 128 104 118 S 180 158 170 168')] +PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1) is [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] +PASS CSS Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1.4) is [path('M 150 160 S 166 192 176 182 S 220 182 210 192')] +PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (-0.4) is [path('M -30 -20 H 4 V 28 H 26 V 64 L 116 168')] +PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0) is [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] +PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.2) is [path('M 30 40 H 58 V 76 H 122 V 148 L 182 216')] +PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.6) is [path('M 70 80 H 94 V 108 H 186 V 204 L 226 248')] +PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1) is [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] +PASS CSS Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1.4) is [path('M 150 160 H 166 V 172 H 314 V 316 L 314 312')] +PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (-0.4) is [path('M 6 16 A -10 0 10 1 0 34 58 A 90 100 10 1 1 230 128')] +PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0) is [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] +PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.2) is [path('M 12 22 A 20 30 40 1 0 58 76 A 120 130 40 1 1 170 116')] +PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.6) is [path('M 16 26 A 40 50 60 0 1 74 88 A 140 150 60 0 1 130 108')] +PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1) is [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] +PASS CSS Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1.4) is [path('M 24 34 A 80 90 100 0 1 106 112 A 180 190 100 0 1 50 92')] +PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (-0.3) is [path('m 0 0 h 1 h 2')] +PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0) is [path('m 0 0 h 1 h 2')] +PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.3) is [path('m 0 0 h 1 h 2')] +PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.5) is [path('m 0 0 h 3')] +PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (0.6) is [path('m 0 0 h 3')] +PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1) is [path('m 0 0 h 3')] +PASS Web Animations: property <d> from [path('m 0 0 h 1 h 2')] to [path('m 0 0 h 3')] at (1.5) is [path('m 0 0 h 3')] +PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (-0.3) is [path('m 10 0 h 1')] +PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0) is [path('m 10 0 h 1')] +PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.3) is [path('m 10 0 h 1')] +PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.5) is [path('m 20 0 v 2')] +PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (0.6) is [path('m 20 0 v 2')] +PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1) is [path('m 20 0 v 2')] +PASS Web Animations: property <d> from [path('m 10 0 h 1')] to [path('m 20 0 v 2')] at (1.5) is [path('m 20 0 v 2')] +PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (-0.3) is [path('m 1 2 l 3 4 Z')] +PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0) is [path('m 1 2 l 3 4 Z')] +PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.3) is [path('m 1 2 l 3 4 Z')] +PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.5) is [path('m 1 2 l 3 4')] +PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (0.6) is [path('m 1 2 l 3 4')] +PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1) is [path('m 1 2 l 3 4')] +PASS Web Animations: property <d> from [path('m 1 2 l 3 4 Z')] to [path('m 1 2 l 3 4')] at (1.5) is [path('m 1 2 l 3 4')] +PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (-0.4) is [path('m 0 0 Z')] +PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0) is [path('m 0 0 Z')] +PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.2) is [path('m 0 0 Z')] +PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (0.6) is [path('m 0 0 Z')] +PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1) is [path('m 0 0 Z')] +PASS Web Animations: property <d> from [path('m 0 0 Z')] to [path('m 0 0 Z')] at (1.4) is [path('m 0 0 Z')] +PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (-0.4) is [path('M 16 42')] +PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0) is [path('M 20 50')] +PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.2) is [path('M 22 54')] +PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (0.6) is [path('M 26 62')] +PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1) is [path('M 30 70')] +PASS Web Animations: property <d> from [path('M 20 50')] to [path('M 30 70')] at (1.4) is [path('M 34 78')] +PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (-0.4) is [path('m 16 42')] +PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0) is [path('m 20 50')] +PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.2) is [path('m 22 54')] +PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (0.6) is [path('m 26 62')] +PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1) is [path('m 30 70')] +PASS Web Animations: property <d> from [path('m 20 50')] to [path('m 30 70')] at (1.4) is [path('m 34 78')] +PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (-0.4) is [path('m 0 0 L 16 42')] +PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0) is [path('m 0 0 L 20 50')] +PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.2) is [path('m 0 0 L 22 54')] +PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (0.6) is [path('m 0 0 L 26 62')] +PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1) is [path('m 0 0 L 30 70')] +PASS Web Animations: property <d> from [path('m 0 0 L 20 50')] to [path('m 0 0 L 30 70')] at (1.4) is [path('m 0 0 L 34 78')] +PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (-0.4) is [path('m 0 0 l 16 42')] +PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0) is [path('m 0 0 l 20 50')] +PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.2) is [path('m 0 0 l 22 54')] +PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (0.6) is [path('m 0 0 l 26 62')] +PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1) is [path('m 0 0 l 30 70')] +PASS Web Animations: property <d> from [path('m 0 0 l 20 50')] to [path('m 0 0 l 30 70')] at (1.4) is [path('m 0 0 l 34 78')] +PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 C 30 40 50 60 10 20')] +PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0) is [path('m 0 0 C 32 42 52 62 12 22')] +PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 C 33 43 53 63 13 23')] +PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 C 35 45 55 65 15 25')] +PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1) is [path('m 0 0 C 37 47 57 67 17 27')] +PASS Web Animations: property <d> from [path('m 0 0 C 32 42 52 62 12 22')] to [path('m 0 0 C 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 C 39 49 59 69 19 29')] +PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (-0.4) is [path('m 0 0 c 30 40 50 60 10 20')] +PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0) is [path('m 0 0 c 32 42 52 62 12 22')] +PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.2) is [path('m 0 0 c 33 43 53 63 13 23')] +PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (0.6) is [path('m 0 0 c 35 45 55 65 15 25')] +PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1) is [path('m 0 0 c 37 47 57 67 17 27')] +PASS Web Animations: property <d> from [path('m 0 0 c 32 42 52 62 12 22')] to [path('m 0 0 c 37 47 57 67 17 27')] at (1.4) is [path('m 0 0 c 39 49 59 69 19 29')] +PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (-0.4) is [path('m 0 0 Q 30 40 50 60')] +PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0) is [path('m 0 0 Q 32 42 52 62')] +PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.2) is [path('m 0 0 Q 33 43 53 63')] +PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (0.6) is [path('m 0 0 Q 35 45 55 65')] +PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1) is [path('m 0 0 Q 37 47 57 67')] +PASS Web Animations: property <d> from [path('m 0 0 Q 32 42 52 62')] to [path('m 0 0 Q 37 47 57 67')] at (1.4) is [path('m 0 0 Q 39 49 59 69')] +PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (-0.4) is [path('m 0 0 q 30 40 50 60')] +PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0) is [path('m 0 0 q 32 42 52 62')] +PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.2) is [path('m 0 0 q 33 43 53 63')] +PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (0.6) is [path('m 0 0 q 35 45 55 65')] +PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1) is [path('m 0 0 q 37 47 57 67')] +PASS Web Animations: property <d> from [path('m 0 0 q 32 42 52 62')] to [path('m 0 0 q 37 47 57 67')] at (1.4) is [path('m 0 0 q 39 49 59 69')] +PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 A -10 0 10 1 0 20 30')] +PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 A 10 20 30 1 0 40 50')] +PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 A 20 30 40 1 0 50 60')] +PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 A 40 50 60 0 1 70 80')] +PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 A 60 70 80 0 1 90 100')] +PASS Web Animations: property <d> from [path('m 0 0 A 10 20 30 1 0 40 50')] to [path('m 0 0 A 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 A 80 90 100 0 1 110 120')] +PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (-0.4) is [path('m 0 0 a -10 0 10 1 0 20 30')] +PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0) is [path('m 0 0 a 10 20 30 1 0 40 50')] +PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.2) is [path('m 0 0 a 20 30 40 1 0 50 60')] +PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (0.6) is [path('m 0 0 a 40 50 60 0 1 70 80')] +PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1) is [path('m 0 0 a 60 70 80 0 1 90 100')] +PASS Web Animations: property <d> from [path('m 0 0 a 10 20 30 1 0 40 50')] to [path('m 0 0 a 60 70 80 0 1 90 100')] at (1.4) is [path('m 0 0 a 80 90 100 0 1 110 120')] +PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (-0.4) is [path('m 0 0 H -10')] +PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0) is [path('m 0 0 H 10')] +PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.2) is [path('m 0 0 H 20')] +PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (0.6) is [path('m 0 0 H 40')] +PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1) is [path('m 0 0 H 60')] +PASS Web Animations: property <d> from [path('m 0 0 H 10')] to [path('m 0 0 H 60')] at (1.4) is [path('m 0 0 H 80')] +PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (-0.4) is [path('m 0 0 h -10')] +PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0) is [path('m 0 0 h 10')] +PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.2) is [path('m 0 0 h 20')] +PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (0.6) is [path('m 0 0 h 40')] +PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1) is [path('m 0 0 h 60')] +PASS Web Animations: property <d> from [path('m 0 0 h 10')] to [path('m 0 0 h 60')] at (1.4) is [path('m 0 0 h 80')] +PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (-0.4) is [path('m 0 0 V -10')] +PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0) is [path('m 0 0 V 10')] +PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.2) is [path('m 0 0 V 20')] +PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (0.6) is [path('m 0 0 V 40')] +PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1) is [path('m 0 0 V 60')] +PASS Web Animations: property <d> from [path('m 0 0 V 10')] to [path('m 0 0 V 60')] at (1.4) is [path('m 0 0 V 80')] +PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (-0.4) is [path('m 0 0 v -10')] +PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0) is [path('m 0 0 v 10')] +PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.2) is [path('m 0 0 v 20')] +PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (0.6) is [path('m 0 0 v 40')] +PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1) is [path('m 0 0 v 60')] +PASS Web Animations: property <d> from [path('m 0 0 v 10')] to [path('m 0 0 v 60')] at (1.4) is [path('m 0 0 v 80')] +PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (-0.4) is [path('m 0 0 S 30 40 50 60')] +PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0) is [path('m 0 0 S 32 42 52 62')] +PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.2) is [path('m 0 0 S 33 43 53 63')] +PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (0.6) is [path('m 0 0 S 35 45 55 65')] +PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1) is [path('m 0 0 S 37 47 57 67')] +PASS Web Animations: property <d> from [path('m 0 0 S 32 42 52 62')] to [path('m 0 0 S 37 47 57 67')] at (1.4) is [path('m 0 0 S 39 49 59 69')] +PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (-0.4) is [path('m 0 0 s 30 40 50 60')] +PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0) is [path('m 0 0 s 32 42 52 62')] +PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.2) is [path('m 0 0 s 33 43 53 63')] +PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (0.6) is [path('m 0 0 s 35 45 55 65')] +PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1) is [path('m 0 0 s 37 47 57 67')] +PASS Web Animations: property <d> from [path('m 0 0 s 32 42 52 62')] to [path('m 0 0 s 37 47 57 67')] at (1.4) is [path('m 0 0 s 39 49 59 69')] +PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (-0.4) is [path('m 0 0 T 16 42')] +PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0) is [path('m 0 0 T 20 50')] +PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.2) is [path('m 0 0 T 22 54')] +PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (0.6) is [path('m 0 0 T 26 62')] +PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1) is [path('m 0 0 T 30 70')] +PASS Web Animations: property <d> from [path('m 0 0 T 20 50')] to [path('m 0 0 T 30 70')] at (1.4) is [path('m 0 0 T 34 78')] +PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (-0.4) is [path('m 0 0 t 16 42')] +PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0) is [path('m 0 0 t 20 50')] +PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.2) is [path('m 0 0 t 22 54')] +PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (0.6) is [path('m 0 0 t 26 62')] +PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1) is [path('m 0 0 t 30 70')] +PASS Web Animations: property <d> from [path('m 0 0 t 20 50')] to [path('m 0 0 t 30 70')] at (1.4) is [path('m 0 0 t 34 78')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (-0.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -180 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.2) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 -60 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 160 20 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 200 100 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 240 180 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (-0.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0) is [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.2) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (0.6) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS Web Animations: property <d> from [path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')] to [path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')] at (1.4) is [path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')] +PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (-0.4) is [path('M -30 -20 L -10 10 Z L 52 68 Z M 72 84 L 162 144 Z T 126 220')] +PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0) is [path('m 10 20 l 20 30 Z l 50 60 Z m 70 80 l 90 60 Z t 70 120')] +PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.2) is [path('M 30 40 L 50 70 Z L 64 86 Z M 84 108 L 174 168 Z T 162 220')] +PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (0.6) is [path('M 70 80 L 90 110 Z L 72 98 Z M 92 124 L 182 184 Z T 186 220')] +PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1) is [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] +PASS Web Animations: property <d> from [path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')] to [path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')] at (1.4) is [path('M 150 160 L 170 190 Z L 88 122 Z M 108 156 L 198 216 Z T 234 220')] +PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (-0.4) is [path('M -30 -20 C 14 38 4 48 54 58 C 136 146 186 156 166 176')] +PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0) is [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] +PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.2) is [path('M 30 40 C 68 86 58 96 108 106 C 202 212 252 222 232 242')] +PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (0.6) is [path('M 70 80 C 104 118 94 128 144 138 C 246 256 296 266 276 286')] +PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1) is [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] +PASS Web Animations: property <d> from [path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')] to [path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')] at (1.4) is [path('M 150 160 C 176 182 166 192 216 202 C 334 344 384 354 364 374')] +PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (-0.4) is [path('M -30 -20 Q 4 48 14 38 Q 130 128 120 138')] +PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0) is [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] +PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.2) is [path('M 30 40 Q 58 96 68 86 Q 160 146 150 156')] +PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (0.6) is [path('M 70 80 Q 94 128 104 118 Q 180 158 170 168')] +PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1) is [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] +PASS Web Animations: property <d> from [path('m 10 20 q 30 60 40 50 q 100 70 90 80')] to [path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')] at (1.4) is [path('M 150 160 Q 166 192 176 182 Q 220 182 210 192')] +PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (-0.4) is [path('M -30 -20 S 4 48 14 38 S 130 128 120 138')] +PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0) is [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] +PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.2) is [path('M 30 40 S 58 96 68 86 S 160 146 150 156')] +PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (0.6) is [path('M 70 80 S 94 128 104 118 S 180 158 170 168')] +PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1) is [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] +PASS Web Animations: property <d> from [path('m 10 20 s 30 60 40 50 s 100 70 90 80')] to [path('M 110 120 S 130 160 140 150 S 200 170 190 180')] at (1.4) is [path('M 150 160 S 166 192 176 182 S 220 182 210 192')] +PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (-0.4) is [path('M -30 -20 H 4 V 28 H 26 V 64 L 116 168')] +PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0) is [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] +PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.2) is [path('M 30 40 H 58 V 76 H 122 V 148 L 182 216')] +PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (0.6) is [path('M 70 80 H 94 V 108 H 186 V 204 L 226 248')] +PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1) is [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] +PASS Web Animations: property <d> from [path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')] to [path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')] at (1.4) is [path('M 150 160 H 166 V 172 H 314 V 316 L 314 312')] +PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (-0.4) is [path('M 6 16 A -10 0 10 1 0 34 58 A 90 100 10 1 1 230 128')] +PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0) is [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] +PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.2) is [path('M 12 22 A 20 30 40 1 0 58 76 A 120 130 40 1 1 170 116')] +PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (0.6) is [path('M 16 26 A 40 50 60 0 1 74 88 A 140 150 60 0 1 130 108')] +PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1) is [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] +PASS Web Animations: property <d> from [path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')] to [path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')] at (1.4) is [path('M 24 34 A 80 90 100 0 1 106 112 A 180 190 100 0 1 50 92')] +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation.html index 1766336..355816f 100644 --- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation.html +++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-d-interpolation.html
@@ -296,12 +296,12 @@ from: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')", to: "path('M 0 0 L 100 100 m 0 100 l 100 0 z l 200 100 z')" }, [ - {at: -0.4, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 120 20 Z')"}, + {at: -0.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -180 Z')"}, {at: 0, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"}, - {at: 0.2, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 240 140 Z')"}, - {at: 0.6, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 20 Z')"}, + {at: 0.2, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 120 -60 Z')"}, + {at: 0.6, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 160 20 Z')"}, {at: 1, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 200 100 Z')"}, - {at: 1.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 280 180 Z')"}, + {at: 1.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 240 180 Z')"}, ]); assertInterpolation({ @@ -309,12 +309,12 @@ from: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')", to: "path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')" }, [ - {at: -0.4, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 160 100 Z')"}, + {at: -0.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"}, {at: 0, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"}, - {at: 0.2, is: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 220 100 Z')"}, - {at: 0.6, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 60 -100 Z')"}, + {at: 0.2, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"}, + {at: 0.6, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"}, {at: 1, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"}, - {at: 1.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 140 -100 Z')"}, + {at: 1.4, is: "path('M 0 0 L 100 100 m 0 100 l 100 0 Z l 100 -100 Z')"}, ]); assertInterpolation({ @@ -322,12 +322,12 @@ from: "path('m 10 20 l 20 30 z l 50 60 z m 70 80 l 90 60 z t 70 120')", to: "path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')" }, [ - {at: -0.4, is: "path('m -30 -20 l 20 30 Z l 90 100 Z m 90 100 l 90 60 Z t 90 160')"}, + {at: -0.4, is: "path('M -30 -20 L -10 10 Z L 52 68 Z M 72 84 L 162 144 Z T 126 220')"}, {at: 0, is: "path('m 10 20 l 20 30 Z l 50 60 Z m 70 80 l 90 60 Z t 70 120')"}, - {at: 0.2, is: "path('m 30 40 l 20 30 Z l 30 40 Z m 60 70 l 90 60 Z t 60 100')"}, - {at: 0.6, is: "path('M 70 80 L 90 110 Z L 80 110 Z M 120 160 L 210 220 Z T 250 280')"}, + {at: 0.2, is: "path('M 30 40 L 50 70 Z L 64 86 Z M 84 108 L 174 168 Z T 162 220')"}, + {at: 0.6, is: "path('M 70 80 L 90 110 Z L 72 98 Z M 92 124 L 182 184 Z T 186 220')"}, {at: 1, is: "path('M 110 120 L 130 150 Z L 80 110 Z M 100 140 L 190 200 Z T 210 220')"}, - {at: 1.4, is: "path('M 150 160 L 170 190 Z L 80 110 Z M 80 120 L 170 180 Z T 170 160')"} + {at: 1.4, is: "path('M 150 160 L 170 190 Z L 88 122 Z M 108 156 L 198 216 Z T 234 220')"} ]); assertInterpolation({ @@ -335,9 +335,9 @@ from: "path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')", to: "path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')" }, [ - {at: -0.4, is: "path('m -30 -20 c 44 58 34 68 84 78 c 82 88 132 98 112 118')"}, + {at: -0.4, is: "path('M -30 -20 C 14 38 4 48 54 58 C 136 146 186 156 166 176')"}, {at: 0, is: "path('m 10 20 c 40 50 30 60 80 70 c 90 100 140 110 120 130')"}, - {at: 0.2, is: "path('m 30 40 c 38 46 28 56 78 66 c 94 106 144 116 124 136')"}, + {at: 0.2, is: "path('M 30 40 C 68 86 58 96 108 106 C 202 212 252 222 232 242')"}, {at: 0.6, is: "path('M 70 80 C 104 118 94 128 144 138 C 246 256 296 266 276 286')"}, {at: 1, is: "path('M 110 120 C 140 150 130 160 180 170 C 290 300 340 310 320 330')"}, {at: 1.4, is: "path('M 150 160 C 176 182 166 192 216 202 C 334 344 384 354 364 374')"} @@ -348,9 +348,9 @@ from: "path('m 10 20 q 30 60 40 50 q 100 70 90 80')", to: "path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')" }, [ - {at: -0.4, is: "path('m -30 -20 q 34 68 44 58 q 116 90 106 100')"}, + {at: -0.4, is: "path('M -30 -20 Q 4 48 14 38 Q 130 128 120 138')"}, {at: 0, is: "path('m 10 20 q 30 60 40 50 q 100 70 90 80')"}, - {at: 0.2, is: "path('m 30 40 q 28 56 38 46 q 92 60 82 70')"}, + {at: 0.2, is: "path('M 30 40 Q 58 96 68 86 Q 160 146 150 156')"}, {at: 0.6, is: "path('M 70 80 Q 94 128 104 118 Q 180 158 170 168')"}, {at: 1, is: "path('M 110 120 Q 130 160 140 150 Q 200 170 190 180')"}, {at: 1.4, is: "path('M 150 160 Q 166 192 176 182 Q 220 182 210 192')"} @@ -361,9 +361,9 @@ from: "path('m 10 20 s 30 60 40 50 s 100 70 90 80')", to: "path('M 110 120 S 130 160 140 150 S 200 170 190 180')" }, [ - {at: -0.4, is: "path('m -30 -20 s 34 68 44 58 s 116 90 106 100')"}, + {at: -0.4, is: "path('M -30 -20 S 4 48 14 38 S 130 128 120 138')"}, {at: 0, is: "path('m 10 20 s 30 60 40 50 s 100 70 90 80')"}, - {at: 0.2, is: "path('m 30 40 s 28 56 38 46 s 92 60 82 70')"}, + {at: 0.2, is: "path('M 30 40 S 58 96 68 86 S 160 146 150 156')"}, {at: 0.6, is: "path('M 70 80 S 94 128 104 118 S 180 158 170 168')"}, {at: 1, is: "path('M 110 120 S 130 160 140 150 S 200 170 190 180')"}, {at: 1.4, is: "path('M 150 160 S 166 192 176 182 S 220 182 210 192')"} @@ -374,9 +374,9 @@ from: "path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')", to: "path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')" }, [ - {at: -0.4, is: "path('m -30 -20 h 34 v 48 h 22 v 36 l 90 104')"}, + {at: -0.4, is: "path('M -30 -20 H 4 V 28 H 26 V 64 L 116 168')"}, {at: 0, is: "path('m 10 20 h 30 v 40 h 50 v 60 l 70 80')"}, - {at: 0.2, is: "path('m 30 40 h 28 v 36 h 64 v 72 l 60 68')"}, + {at: 0.2, is: "path('M 30 40 H 58 V 76 H 122 V 148 L 182 216')"}, {at: 0.6, is: "path('M 70 80 H 94 V 108 H 186 V 204 L 226 248')"}, {at: 1, is: "path('M 110 120 H 130 V 140 H 250 V 260 L 270 280')"}, {at: 1.4, is: "path('M 150 160 H 166 V 172 H 314 V 316 L 314 312')"} @@ -387,9 +387,9 @@ from: "path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')", to: "path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')" }, [ - {at: -0.4, is: "path('m 6 16 a -10 0 10 1 0 28 42 a 90 100 10 1 1 196 70')"}, + {at: -0.4, is: "path('M 6 16 A -10 0 10 1 0 34 58 A 90 100 10 1 1 230 128')"}, {at: 0, is: "path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')"}, - {at: 0.2, is: "path('m 12 22 a 20 30 40 1 0 46 54 a 120 130 40 1 1 112 40')"}, + {at: 0.2, is: "path('M 12 22 A 20 30 40 1 0 58 76 A 120 130 40 1 1 170 116')"}, {at: 0.6, is: "path('M 16 26 A 40 50 60 0 1 74 88 A 140 150 60 0 1 130 108')"}, {at: 1, is: "path('M 20 30 A 60 70 80 0 1 90 100 A 160 170 80 0 1 90 100')"}, {at: 1.4, is: "path('M 24 34 A 80 90 100 0 1 106 112 A 180 190 100 0 1 50 92')"}
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-expected.html new file mode 100644 index 0000000..0e23e3f5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-expected.html
@@ -0,0 +1,7 @@ +<canvas id="canvas" width="100" height="100"></canvas> +<script> +var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); +ctx.fillStyle = '#0f0'; +ctx.fillRect(0, 0, 50, 40); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-expected.html new file mode 100644 index 0000000..d78ede2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-expected.html
@@ -0,0 +1,17 @@ +<canvas id="canvas" width="100" height="100"></canvas> +<script> +function runTest() { + if (window.testRunner) { + testRunner.waitUntilDone(); + testRunner.setBackingScaleFactor(2, function() { + var canvas = document.getElementById('canvas'); + var ctx = canvas.getContext('2d'); + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 50, 40); + testRunner.notifyDone(); + }); + } +} + +window.onload = runTest; +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale-expected.html new file mode 100644 index 0000000..16e683c1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale-expected.html
@@ -0,0 +1,19 @@ +<canvas id="canvas" width="100" height="100"></canvas> +<script> +function runTest() { + if (window.testRunner) { + testRunner.waitUntilDone(); + testRunner.setBackingScaleFactor(2, function() { + var canvas = document.getElementById('canvas'); + canvas.style.width = '50px'; + canvas.style.height = '50px'; + var ctx = canvas.getContext('2d'); + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 50, 40); + testRunner.notifyDone(); + }); + } +} + +window.onload = runTest; +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale.html new file mode 100644 index 0000000..4319b5f0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi-scale.html
@@ -0,0 +1,29 @@ +<svg style="display: block; width: 0; height: 0"> + <defs> + <filter id="crop" primitiveUnits="objectBoundingBox"> + <femerge x="0" y="0" width="50%" height="40%"> + <femergenode in="SourceGraphic"></femergenode> + </femerge> + </filter> + </defs> +</svg> +<canvas id="canvas" width="100" height="100"></canvas> +<script> +function runTest() { + if (window.testRunner) { + testRunner.waitUntilDone(); + testRunner.setBackingScaleFactor(2, function() { + var canvas = document.getElementById('canvas'); + canvas.style.width = '50px'; + canvas.style.height = '50px'; + var ctx = canvas.getContext('2d'); + ctx.filter = 'url(#crop)'; + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 90, 90); + testRunner.notifyDone(); + }); + } +} + +window.onload = runTest; +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi.html new file mode 100644 index 0000000..e5eae39 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-hidpi.html
@@ -0,0 +1,27 @@ +<svg style="display: block; width: 0; height: 0"> + <defs> + <filter id="crop" primitiveUnits="objectBoundingBox"> + <femerge x="0" y="0" width="50%" height="40%"> + <femergenode in="SourceGraphic"></femergenode> + </femerge> + </filter> + </defs> +</svg> +<canvas id="canvas" width="100" height="100"></canvas> +<script> +function runTest() { + if (window.testRunner) { + testRunner.waitUntilDone(); + testRunner.setBackingScaleFactor(2, function() { + var canvas = document.getElementById('canvas'); + var ctx = canvas.getContext('2d'); + ctx.filter = 'url(#crop)'; + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 90, 90); + testRunner.notifyDone(); + }); + } +} + +window.onload = runTest; +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale-expected.html new file mode 100644 index 0000000..2b3e967d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale-expected.html
@@ -0,0 +1,9 @@ +<canvas id="canvas" width="100" height="100"></canvas> +<script> +var canvas = document.getElementById('canvas'); +canvas.style.width = '200px'; +canvas.style.height = '200px'; +var ctx = canvas.getContext('2d'); +ctx.fillStyle = '#0f0'; +ctx.fillRect(0, 0, 50, 40); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale.html new file mode 100644 index 0000000..78e8224b --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height-scale.html
@@ -0,0 +1,19 @@ +<svg style="display: block; width: 0; height: 0"> + <defs> + <filter id="crop" primitiveUnits="objectBoundingBox"> + <femerge x="0" y="0" width="50%" height="40%"> + <femergenode in="SourceGraphic"></femergenode> + </femerge> + </filter> + </defs> +</svg> +<canvas id="canvas" width="100" height="100"></canvas> +<script> +var canvas = document.getElementById('canvas'); +canvas.style.width = '200px'; +canvas.style.height = '200px'; +var ctx = canvas.getContext('2d'); +ctx.filter = 'url(#crop)'; +ctx.fillStyle = '#0f0'; +ctx.fillRect(0, 0, 90, 90); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height.html new file mode 100644 index 0000000..1185895 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-filter-width-height.html
@@ -0,0 +1,17 @@ +<svg style="display: block; width: 0; height: 0"> + <defs> + <filter id="crop" primitiveUnits="objectBoundingBox"> + <femerge x="0" y="0" width="50%" height="40%"> + <femergenode in="SourceGraphic"></femergenode> + </femerge> + </filter> + </defs> +</svg> +<canvas id="canvas" width="100" height="100"></canvas> +<script> +var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); +ctx.filter = 'url(#crop)'; +ctx.fillStyle = '#0f0'; +ctx.fillRect(0, 0, 90, 90); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/toBlob/canvas-toBlob-defaultpng.html b/third_party/WebKit/LayoutTests/fast/canvas/toBlob/canvas-toBlob-defaultpng.html index 6f09ee8..c2fec4c 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/toBlob/canvas-toBlob-defaultpng.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/toBlob/canvas-toBlob-defaultpng.html
@@ -16,10 +16,11 @@ var newImg = new Image(); newImg.onload = function() { - ctx2.drawImage(newImg, 0, 0, 150, 75); + // 300x150 is the default size of the canvas, which is the source of the newImg. + ctx2.drawImage(newImg, 0, 0, 300, 150); var imageData1 = ctx.getImageData(0, 0, 150, 75).data; - var imageData2 = ctx.getImageData(0, 0, 150, 75).data; + var imageData2 = ctx2.getImageData(0, 0, 150, 75).data; var imageMatched = true; for (var i = 1; i < imageData1.length; i++) {
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page-expected.txt new file mode 100644 index 0000000..645e28d3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page-expected.txt
@@ -0,0 +1,10 @@ +This tests gesture scrolling by pages. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS document.scrollingElement.scrollTop >= window.innerHeight * 0.875 * 2 became true +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page.html new file mode 100644 index 0000000..d2c4f0d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-page.html
@@ -0,0 +1,60 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../../../../resources/js-test.js"></script> +<style type="text/css"> +::-webkit-scrollbar { + width: 0px; + height: 0px; +} + +#greenbox { + width: 100px; + height: 2000px; + background: green; +} +#redbox { + width: 100px; + height: 2000px; + background: red; +} + +</style> +</head> +<body style="margin:0" onload="runTest();"> + +<div id="greenbox"></div> +<div id="redbox"></div> + +<p id="description"></p> +<div id="console"></div> +<script type="text/javascript"> + +function gestureScroll() +{ + eventSender.gestureScrollBegin("touchpad", 10, 20); + eventSender.gestureScrollUpdate("touchpad", 0, -1, false, "Page"); + eventSender.gestureScrollUpdate("touchpad", 0, -2, false, "Page"); + eventSender.gestureScrollUpdate("touchpad", 0, 1, false, "Page"); + eventSender.gestureScrollEnd("touchpad", 0, 0); + + // see kMinFractionToStepWhenPaging in ScrollableArea.cppP + // 2 is the expected number of pages scrolled (-1 + -2 + 1) + shouldBecomeEqual("document.scrollingElement.scrollTop >= window.innerHeight * 0.875 * 2", "true", finishJSTest, 1000); +} + +jsTestIsAsync = true; + +function runTest() +{ + if (window.eventSender) { + description('This tests gesture scrolling by pages.'); + gestureScroll(); + } else { + debug("This test requires DumpRenderTree. Gesture-scroll the page to validate the implementation."); + } +} +</script> + +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel-expected.txt new file mode 100644 index 0000000..c557902 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel-expected.txt
@@ -0,0 +1,10 @@ +This tests gesture scrolling by non-precise pixels. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS document.scrollingElement.scrollTop became 295 +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel.html new file mode 100644 index 0000000..7338ece --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scroll-by-pixel.html
@@ -0,0 +1,58 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../../../../resources/js-test.js"></script> +<style type="text/css"> +::-webkit-scrollbar { + width: 0px; + height: 0px; +} + +#greenbox { + width: 100px; + height: 2000px; + background: green; +} +#redbox { + width: 100px; + height: 2000px; + background: red; +} + +</style> +</head> +<body style="margin:0" onload="runTest();"> + +<div id="greenbox"></div> +<div id="redbox"></div> + +<p id="description"></p> +<div id="console"></div> +<script type="text/javascript"> + +function gestureScroll() +{ + eventSender.gestureScrollBegin("touchpad", 10, 20); + eventSender.gestureScrollUpdate("touchpad", 0, -100, false, "Pixels"); + eventSender.gestureScrollUpdate("touchpad", 0, -215, false, "Pixels"); + eventSender.gestureScrollUpdate("touchpad", 0, 20, false, "Pixels"); + eventSender.gestureScrollEnd("touchpad", 0, 0); + + shouldBecomeEqual("document.scrollingElement.scrollTop", "295", finishJSTest, 1000); +} + +jsTestIsAsync = true; + +function runTest() +{ + if (window.eventSender) { + description('This tests gesture scrolling by non-precise pixels.'); + gestureScroll(); + } else { + debug("This test requires DumpRenderTree. Gesture-scroll the page to validate the implementation."); + } +} +</script> + +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/hittesting/culled-inline-expected.txt b/third_party/WebKit/LayoutTests/hittesting/culled-inline-expected.txt new file mode 100644 index 0000000..3e92001 --- /dev/null +++ b/third_party/WebKit/LayoutTests/hittesting/culled-inline-expected.txt
@@ -0,0 +1,11 @@ +Hello World +To manually test, hover between the two words to see if background color turns green. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS element.id is "culled" +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/hittesting/culled-inline.html b/third_party/WebKit/LayoutTests/hittesting/culled-inline.html new file mode 100644 index 0000000..61fa8c2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/hittesting/culled-inline.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../resources/js-test.js"></script> +<style> +#culled:hover { + background-color: green; +} +.left { + display: inline-block; + transform: translateY(0px); + border: 1px solid black; +} +.right { + margin-left: 200px; + border: 1px solid black; +} +</style> +</head> +<body> +<div id="container"> +<span id="culled"> + <span class="left">Hello</span> + <span class="right">World</span> +</span> +</div> +<div id="console"></div> +</body> +<script> +description('To manually test, hover between the two words to see if background color turns green.'); + +var rect = document.getElementById('culled').getBoundingClientRect(); +element = document.elementFromPoint(rect.left + rect.width/2, rect.top + rect.height/2); +shouldBeEqualToString('element.id', 'culled'); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/fetch-event.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/fetch-event.html index 8b9cb40..a27c2b9 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/fetch-event.html +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/fetch-event.html
@@ -69,6 +69,47 @@ }, 'Service Worker responds to fetch event with the referrer URL'); async_test(function(t) { + var scope = 'resources/simple.html?clientId'; + var frame; + var client_id1, client_id2; + service_worker_unregister_and_register(t, worker, scope) + .then(function(reg) { + return wait_for_state(t, reg.installing, 'activated'); + }) + .then(function() { return with_iframe(scope); }) + .then(function(f) { + frame = f; + assert_equals( + frame.contentDocument.body.textContent.substr(0, 19), + 'Client ID Not Found', + 'Service Worker should respond to navigation fetch with no ' + + 'client id'); + return frame.contentWindow.fetch('resources/other.html?clientId'); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + client_id1 = response_text.substr(17, 36); + assert_equals( + response_text.substr(0, 15), + 'Client ID Found', + 'Service Worker should respond to fetch with a client id'); + return frame.contentWindow.fetch('resources/other.html?clientId'); + }) + .then(function(response) { return response.text(); }) + .then(function(response_text) { + client_id2 = response_text.substr(17, 36); + assert_equals( + client_id1, + client_id2, + 'Service Worker should respond to another fetch from the same ' + + 'client with the same client id'); + frame.remove(); + return service_worker_unregister_and_done(t, scope); + }) + .catch(unreached_rejection(t)); + }, 'Service Worker responds to fetch event with a client id'); + +async_test(function(t) { var scope = 'resources/simple.html?ignore'; service_worker_unregister_and_register(t, worker, scope) .then(function(reg) { @@ -155,8 +196,9 @@ }) .then(function(frame) { assert_equals(frame.contentDocument.body.textContent, - 'POST:testName1=testValue1&testName2=testValue2'); - document.body.removeChild(frame); + 'POST:application/x-www-form-urlencoded:' + + 'testName1=testValue1&testName2=testValue2'); + frame.remove(); return service_worker_unregister_and_done(t, scope); }) .catch(unreached_rejection(t)); @@ -172,15 +214,7 @@ .then(function(frame) { assert_equals( frame.contentDocument.body.textContent, - '(0)', - 'Response should be the argument of the first respondWith() call.'); - frame.remove(); - return with_iframe(scope); - }) - .then(function(frame) { - assert_equals( - frame.contentDocument.body.textContent, - '(0)(1)[InvalidStateError](2)[InvalidStateError](0)', + '(0)(1)[InvalidStateError](2)[InvalidStateError]', 'Multiple calls of respondWith must throw InvalidStateErrors.'); frame.remove(); return service_worker_unregister_and_done(t, scope); @@ -190,6 +224,7 @@ async_test(function(t) { var scope = 'resources/simple.html?used-check'; + var first_frame; service_worker_unregister_and_register(t, worker, scope) .then(function(reg) { return wait_for_state(t, reg.installing, 'activated'); @@ -199,7 +234,7 @@ assert_equals(frame.contentDocument.body.textContent, 'Here\'s an other html file.\n', 'Response should come from fetched other file'); - frame.remove(); + first_frame = frame; return with_iframe(scope); }) .then(function(frame) { @@ -211,6 +246,7 @@ frame.contentDocument.body.textContent, 'bodyUsed: true', 'event.respondWith must set the used flag.'); + first_frame.remove(); frame.remove(); return service_worker_unregister_and_done(t, scope); })
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/fetch-event-test-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/fetch-event-test-worker.js index fbcc66fb..1443681 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/fetch-event-test-worker.js +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/fetch-event-test-worker.js
@@ -11,6 +11,16 @@ ['Referrer: ' + event.request.referrer]))); } +function handleClientId(event) { + var body; + if (event.clientId !== null) { + body = 'Client ID Found: ' + event.clientId; + } else { + body = 'Client ID Not Found'; + } + event.respondWith(new Response(body)); +} + function handleNullBody(event) { event.respondWith(new Response()); } @@ -23,18 +33,23 @@ event.respondWith(new Promise(function(resolve) { event.request.text() .then(function(result) { - resolve(new Response(event.request.method + ':' + result)); + resolve(new Response(event.request.method + ':' + + event.request.headers.get('Content-Type') + ':' + + result)); }); })); } -var logForMultipleRespondWith = ''; - function handleMultipleRespondWith(event) { + var logForMultipleRespondWith = ''; for (var i = 0; i < 3; ++i) { logForMultipleRespondWith += '(' + i + ')'; try { - event.respondWith(new Response(logForMultipleRespondWith)); + event.respondWith(new Promise(function(resolve) { + setTimeout(function() { + resolve(new Response(logForMultipleRespondWith)); + }, 0); + })); } catch (e) { logForMultipleRespondWith += '[' + e.name + ']'; } @@ -61,6 +76,7 @@ { pattern: '?string', fn: handleString }, { pattern: '?blob', fn: handleBlob }, { pattern: '?referrer', fn: handleReferrer }, + { pattern: '?clientId', fn: handleClientId }, { pattern: '?ignore', fn: function() {} }, { pattern: '?null', fn: handleNullBody }, { pattern: '?fetch', fn: handleFetch },
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/interfaces-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/interfaces-worker.js index 67d9918..f74f7d9 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/interfaces-worker.js +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/interfaces-worker.js
@@ -72,29 +72,47 @@ test(function() { assert_equals( - new ExtendableEvent('ExtendableEvent').type, - 'ExtendableEvent', 'Type of ExtendableEvent should be ExtendableEvent'); - assert_equals( - new FetchEvent('FetchEvent').type, - 'FetchEvent', 'Type of FetchEvent should be FetchEvent'); - assert_equals( - new FetchEvent('FetchEvent').cancelable, - false, 'Default FetchEvent.cancelable should be false'); - assert_equals( - new FetchEvent('FetchEvent').bubbles, - false, 'Default FetchEvent.bubbles should be false'); - assert_equals( - new FetchEvent('FetchEvent').isReload, - false, 'Default FetchEvent.isReload should be false'); - assert_equals( - new FetchEvent('FetchEvent', {cancelable: false}).cancelable, - false, 'FetchEvent.cancelable should be false'); - assert_equals( - new FetchEvent('FetchEvent', {isReload : true}).isReload, true, - 'FetchEvent.isReload with option {isReload : true} should be true'); + new ExtendableEvent('ExtendableEvent').type, + 'ExtendableEvent', 'Type of ExtendableEvent should be ExtendableEvent'); var req = new Request('https://www.example.com/', {method: 'POST'}); assert_equals( - new FetchEvent('FetchEvent', {request: req, isReload: true}).request.url, - 'https://www.example.com/', - 'FetchEvent.request.url should return the value it was initialized to'); + new FetchEvent('FetchEvent', {request: req}).type, + 'FetchEvent', 'Type of FetchEvent should be FetchEvent'); + assert_equals( + new FetchEvent('FetchEvent', {request: req}).cancelable, + false, 'Default FetchEvent.cancelable should be false'); + assert_equals( + new FetchEvent('FetchEvent', {request: req}).bubbles, + false, 'Default FetchEvent.bubbles should be false'); + assert_equals( + new FetchEvent('FetchEvent', {request: req}).clientId, + null, 'Default FetchEvent.clientId should be null'); + assert_equals( + new FetchEvent('FetchEvent', {request: req}).isReload, + false, 'Default FetchEvent.isReload should be false'); + assert_equals( + new FetchEvent( + 'FetchEvent', {request: req, cancelable: false}).cancelable, + false, 'FetchEvent.cancelable should be false'); + assert_equals( + new FetchEvent( + 'FetchEvent', + {request: req, + clientId: '006e6aae-cfd4-4331-bea8-fbae364703cf'}).clientId, + '006e6aae-cfd4-4331-bea8-fbae364703cf', + 'FetchEvent.clientId with option {clientId: string} should be ' + + 'the value of string'); + assert_equals( + new FetchEvent( + 'FetchEvent', + {request: req, isReload: true}).isReload, + true, + 'FetchEvent.isReload with option {isReload: true} should be true'); + assert_equals( + new FetchEvent( + 'FetchEvent', + {request: req, isReload: true}).request.url, + 'https://www.example.com/', + 'FetchEvent.request.url should return the value it was ' + + 'initialized to'); }, 'Event constructors');
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 25ff8ef..a68bf70 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -184,6 +184,7 @@ method constructor method waitUntil interface FetchEvent : ExtendableEvent + getter clientId getter isReload getter request method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 574757f..1dc4a68 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -165,6 +165,7 @@ method constructor method waitUntil interface FetchEvent : ExtendableEvent + getter clientId getter isReload getter request method constructor
diff --git a/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.cpp new file mode 100644 index 0000000..02997229 --- /dev/null +++ b/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.cpp
@@ -0,0 +1,81 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/animation/CSSPathInterpolationType.h" + +#include "core/animation/PathInterpolationFunctions.h" +#include "core/css/CSSPathValue.h" +#include "core/css/resolver/StyleResolverState.h" + +namespace blink { + +void CSSPathInterpolationType::apply(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const +{ + ASSERT(cssProperty() == CSSPropertyD); + environment.state().style()->setD(StylePath::create(PathInterpolationFunctions::appliedValue(interpolableValue, nonInterpolableValue))); +} + +void CSSPathInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const +{ + PathInterpolationFunctions::composite(underlyingValue, underlyingFraction, value); +} + +PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertNeutral(const UnderlyingValue& underlyingValue, ConversionCheckers& conversionCheckers) const +{ + return PathInterpolationFunctions::maybeConvertNeutral(*this, underlyingValue, conversionCheckers); +} + +PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertInitial() const +{ + return PathInterpolationFunctions::convertValue(*this, CSSPathValue::emptyPathValue()->byteStream()); +} + +class ParentPathChecker : public InterpolationType::ConversionChecker { +public: + static PassOwnPtr<ParentPathChecker> create(const InterpolationType& type, PassRefPtr<StylePath> stylePath) + { + return adoptPtr(new ParentPathChecker(type, stylePath)); + } + +private: + ParentPathChecker(const InterpolationType& type, PassRefPtr<StylePath> stylePath) + : ConversionChecker(type) + , m_stylePath(stylePath) + { } + + bool isValid(const InterpolationEnvironment& environment, const UnderlyingValue&) const final + { + return environment.state().parentStyle()->svgStyle().d() == m_stylePath.get(); + } + + const RefPtr<StylePath> m_stylePath; +}; + +PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertInherit(const StyleResolverState& state, ConversionCheckers& conversionCheckers) const +{ + ASSERT(cssProperty() == CSSPropertyD); + if (!state.parentStyle()) + return nullptr; + + conversionCheckers.append(ParentPathChecker::create(*this, state.parentStyle()->svgStyle().d())); + return PathInterpolationFunctions::convertValue(*this, state.parentStyle()->svgStyle().d()->byteStream()); +} + +PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertValue(const CSSValue& value, const StyleResolverState& state, ConversionCheckers& conversionCheckers) const +{ + return PathInterpolationFunctions::convertValue(*this, toCSSPathValue(value).byteStream()); +} + +PassOwnPtr<InterpolationValue> CSSPathInterpolationType::maybeConvertUnderlyingValue(const InterpolationEnvironment& environment) const +{ + ASSERT(cssProperty() == CSSPropertyD); + return PathInterpolationFunctions::convertValue(*this, environment.state().style()->svgStyle().d()->byteStream()); +} + +PassOwnPtr<PairwisePrimitiveInterpolation> CSSPathInterpolationType::mergeSingleConversions(InterpolationValue& startValue, InterpolationValue& endValue) const +{ + return PathInterpolationFunctions::mergeSingleConversions(*this, startValue, endValue); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.h b/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.h new file mode 100644 index 0000000..e9f2324 --- /dev/null +++ b/third_party/WebKit/Source/core/animation/CSSPathInterpolationType.h
@@ -0,0 +1,32 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CSSPathInterpolationType_h +#define CSSPathInterpolationType_h + +#include "core/animation/CSSInterpolationType.h" + +namespace blink { + +class CSSPathInterpolationType : public CSSInterpolationType { +public: + CSSPathInterpolationType(CSSPropertyID property) + : CSSInterpolationType(property) + { } + + void apply(const InterpolableValue&, const NonInterpolableValue*, InterpolationEnvironment&) const final; + void composite(UnderlyingValue&, double underlyingFraction, const InterpolationValue&) const final; + +protected: + PassOwnPtr<InterpolationValue> maybeConvertNeutral(const UnderlyingValue&, ConversionCheckers&) const final; + PassOwnPtr<InterpolationValue> maybeConvertInitial() const final; + PassOwnPtr<InterpolationValue> maybeConvertInherit(const StyleResolverState&, ConversionCheckers&) const final; + PassOwnPtr<InterpolationValue> maybeConvertValue(const CSSValue&, const StyleResolverState&, ConversionCheckers&) const final; + PassOwnPtr<InterpolationValue> maybeConvertUnderlyingValue(const InterpolationEnvironment&) const final; + PassOwnPtr<PairwisePrimitiveInterpolation> mergeSingleConversions(InterpolationValue& startValue, InterpolationValue& endValue) const final; +}; + +} // namespace blink + +#endif // CSSPathInterpolationType_h
diff --git a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp new file mode 100644 index 0000000..92a837b --- /dev/null +++ b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp
@@ -0,0 +1,167 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/animation/PathInterpolationFunctions.h" + +#include "core/animation/InterpolatedSVGPathSource.h" +#include "core/animation/InterpolationEnvironment.h" +#include "core/animation/SVGPathSegInterpolationFunctions.h" +#include "core/css/CSSPathValue.h" +#include "core/svg/SVGPath.h" +#include "core/svg/SVGPathByteStreamBuilder.h" +#include "core/svg/SVGPathByteStreamSource.h" +#include "core/svg/SVGPathParser.h" + +namespace blink { + +class SVGPathNonInterpolableValue : public NonInterpolableValue { +public: + virtual ~SVGPathNonInterpolableValue() {} + + static PassRefPtr<SVGPathNonInterpolableValue> create(Vector<SVGPathSegType>& pathSegTypes) + { + return adoptRef(new SVGPathNonInterpolableValue(pathSegTypes)); + } + + const Vector<SVGPathSegType>& pathSegTypes() const { return m_pathSegTypes; } + + DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); + +private: + SVGPathNonInterpolableValue(Vector<SVGPathSegType>& pathSegTypes) + { + m_pathSegTypes.swap(pathSegTypes); + } + + Vector<SVGPathSegType> m_pathSegTypes; +}; + +DEFINE_NON_INTERPOLABLE_VALUE_TYPE(SVGPathNonInterpolableValue); +DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(SVGPathNonInterpolableValue); + +enum PathComponentIndex { + PathArgsIndex, + PathNeutralIndex, + PathComponentIndexCount, +}; + +PassOwnPtr<InterpolationValue> PathInterpolationFunctions::convertValue(const InterpolationType& type, const SVGPathByteStream& byteStream) +{ + SVGPathByteStreamSource pathSource(byteStream); + size_t length = 0; + PathCoordinates currentCoordinates; + Vector<OwnPtr<InterpolableValue>> interpolablePathSegs; + Vector<SVGPathSegType> pathSegTypes; + + while (pathSource.hasMoreData()) { + const PathSegmentData segment = pathSource.parseSegment(); + interpolablePathSegs.append(SVGPathSegInterpolationFunctions::consumePathSeg(segment, currentCoordinates)); + pathSegTypes.append(segment.command); + length++; + } + + OwnPtr<InterpolableList> pathArgs = InterpolableList::create(length); + for (size_t i = 0; i < interpolablePathSegs.size(); i++) + pathArgs->set(i, interpolablePathSegs[i].release()); + + OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount); + result->set(PathArgsIndex, pathArgs.release()); + result->set(PathNeutralIndex, InterpolableNumber::create(0)); + + return InterpolationValue::create(type, result.release(), SVGPathNonInterpolableValue::create(pathSegTypes)); +} + +class UnderlyingPathSegTypesChecker : public InterpolationType::ConversionChecker { +public: + ~UnderlyingPathSegTypesChecker() final {} + + static PassOwnPtr<UnderlyingPathSegTypesChecker> create(const InterpolationType& type, const UnderlyingValue& underlyingValue) + { + return adoptPtr(new UnderlyingPathSegTypesChecker(type, getPathSegTypes(underlyingValue))); + } + +private: + UnderlyingPathSegTypesChecker(const InterpolationType& type, const Vector<SVGPathSegType>& pathSegTypes) + : ConversionChecker(type) + , m_pathSegTypes(pathSegTypes) + { } + + static const Vector<SVGPathSegType>& getPathSegTypes(const UnderlyingValue& underlyingValue) + { + return toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes(); + } + + bool isValid(const InterpolationEnvironment&, const UnderlyingValue& underlyingValue) const final + { + return m_pathSegTypes == getPathSegTypes(underlyingValue); + } + + Vector<SVGPathSegType> m_pathSegTypes; +}; + +PassOwnPtr<InterpolationValue> PathInterpolationFunctions::maybeConvertNeutral(const InterpolationType& type, const UnderlyingValue& underlyingValue, InterpolationType::ConversionCheckers& conversionCheckers) +{ + conversionCheckers.append(UnderlyingPathSegTypesChecker::create(type, underlyingValue)); + OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount); + result->set(PathArgsIndex, toInterpolableList(underlyingValue->interpolableValue()).get(PathArgsIndex)->cloneAndZero()); + result->set(PathNeutralIndex, InterpolableNumber::create(1)); + return InterpolationValue::create(type, result.release(), + const_cast<NonInterpolableValue*>(underlyingValue->nonInterpolableValue())); // Take ref. +} + +static bool pathSegTypesMatch(const Vector<SVGPathSegType>& a, const Vector<SVGPathSegType>& b) +{ + if (a.size() != b.size()) + return false; + + for (size_t i = 0; i < a.size(); i++) { + if (toAbsolutePathSegType(a[i]) != toAbsolutePathSegType(b[i])) + return false; + } + + return true; +} + +PassOwnPtr<PairwisePrimitiveInterpolation> PathInterpolationFunctions::mergeSingleConversions(const InterpolationType& type, InterpolationValue& startValue, InterpolationValue& endValue) +{ + const Vector<SVGPathSegType>& startTypes = toSVGPathNonInterpolableValue(startValue.nonInterpolableValue())->pathSegTypes(); + const Vector<SVGPathSegType>& endTypes = toSVGPathNonInterpolableValue(endValue.nonInterpolableValue())->pathSegTypes(); + if (!pathSegTypesMatch(startTypes, endTypes)) + return nullptr; + + return PairwisePrimitiveInterpolation::create(type, + startValue.mutableComponent().interpolableValue.release(), + endValue.mutableComponent().interpolableValue.release(), + const_cast<NonInterpolableValue*>(endValue.nonInterpolableValue())); // Take ref. +} + +void PathInterpolationFunctions::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) +{ + const InterpolableList& list = toInterpolableList(value.interpolableValue()); + double neutralComponent = toInterpolableNumber(list.get(PathNeutralIndex))->value(); + + if (neutralComponent == 0) { + underlyingValue.set(&value); + return; + } + + ASSERT(pathSegTypesMatch( + toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes(), + toSVGPathNonInterpolableValue(value.nonInterpolableValue())->pathSegTypes())); + underlyingValue.mutableComponent().interpolableValue->scaleAndAdd(neutralComponent, value.interpolableValue()); + underlyingValue.mutableComponent().nonInterpolableValue = const_cast<NonInterpolableValue*>(value.nonInterpolableValue()); // Take ref. +} + +PassRefPtr<SVGPathByteStream> PathInterpolationFunctions::appliedValue(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue) +{ + RefPtr<SVGPathByteStream> pathByteStream = SVGPathByteStream::create(); + InterpolatedSVGPathSource source( + toInterpolableList(*toInterpolableList(interpolableValue).get(PathArgsIndex)), + toSVGPathNonInterpolableValue(nonInterpolableValue)->pathSegTypes()); + SVGPathByteStreamBuilder builder(*pathByteStream); + SVGPathParser(&source, &builder).parsePathDataFromSource(UnalteredParsing, false); + return pathByteStream.release(); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h new file mode 100644 index 0000000..ef28b560 --- /dev/null +++ b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h
@@ -0,0 +1,28 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PathInterpolationFunctions_h +#define PathInterpolationFunctions_h + +#include "core/animation/InterpolationType.h" +#include "core/svg/SVGPathByteStream.h" + +namespace blink { + +class PathInterpolationFunctions { +public: + static PassRefPtr<SVGPathByteStream> appliedValue(const InterpolableValue&, const NonInterpolableValue*); + + static void composite(UnderlyingValue&, double underlyingFraction, const InterpolationValue&); + + static PassOwnPtr<InterpolationValue> convertValue(const InterpolationType&, const SVGPathByteStream&); + + static PassOwnPtr<InterpolationValue> maybeConvertNeutral(const InterpolationType&, const UnderlyingValue&, InterpolationType::ConversionCheckers&); + + static PassOwnPtr<PairwisePrimitiveInterpolation> mergeSingleConversions(const InterpolationType&, InterpolationValue& startValue, InterpolationValue& endValue); +}; + +} // namespace blink + +#endif // PathInterpolationFunctions_h
diff --git a/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp b/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp index 9525f660..d1afb30a 100644 --- a/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp +++ b/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp
@@ -4,166 +4,38 @@ #include "core/animation/SVGPathInterpolationType.h" -#include "core/animation/InterpolatedSVGPathSource.h" -#include "core/animation/InterpolationEnvironment.h" -#include "core/animation/SVGPathSegInterpolationFunctions.h" +#include "core/animation/PathInterpolationFunctions.h" + #include "core/svg/SVGPath.h" -#include "core/svg/SVGPathByteStreamBuilder.h" -#include "core/svg/SVGPathByteStreamSource.h" -#include "core/svg/SVGPathParser.h" namespace blink { -class SVGPathNonInterpolableValue : public NonInterpolableValue { -public: - virtual ~SVGPathNonInterpolableValue() {} - - static PassRefPtr<SVGPathNonInterpolableValue> create(Vector<SVGPathSegType>& pathSegTypes) - { - return adoptRef(new SVGPathNonInterpolableValue(pathSegTypes)); - } - - const Vector<SVGPathSegType>& pathSegTypes() const { return m_pathSegTypes; } - - DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); - -private: - SVGPathNonInterpolableValue(Vector<SVGPathSegType>& pathSegTypes) - { - m_pathSegTypes.swap(pathSegTypes); - } - - Vector<SVGPathSegType> m_pathSegTypes; -}; - -DEFINE_NON_INTERPOLABLE_VALUE_TYPE(SVGPathNonInterpolableValue); -DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(SVGPathNonInterpolableValue); - -enum PathComponentIndex { - PathArgsIndex, - PathNeutralIndex, - PathComponentIndexCount, -}; - PassOwnPtr<InterpolationValue> SVGPathInterpolationType::maybeConvertSVGValue(const SVGPropertyBase& svgValue) const { if (svgValue.type() != AnimatedPath) return nullptr; - SVGPathByteStreamSource pathSource(toSVGPath(svgValue).byteStream()); - size_t length = 0; - PathCoordinates currentCoordinates; - Vector<OwnPtr<InterpolableValue>> interpolablePathSegs; - Vector<SVGPathSegType> pathSegTypes; - - while (pathSource.hasMoreData()) { - const PathSegmentData segment = pathSource.parseSegment(); - interpolablePathSegs.append(SVGPathSegInterpolationFunctions::consumePathSeg(segment, currentCoordinates)); - pathSegTypes.append(segment.command); - length++; - } - - OwnPtr<InterpolableList> pathArgs = InterpolableList::create(length); - for (size_t i = 0; i < interpolablePathSegs.size(); i++) - pathArgs->set(i, interpolablePathSegs[i].release()); - - OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount); - result->set(PathArgsIndex, pathArgs.release()); - result->set(PathNeutralIndex, InterpolableNumber::create(0)); - - return InterpolationValue::create(*this, result.release(), SVGPathNonInterpolableValue::create(pathSegTypes)); + return PathInterpolationFunctions::convertValue(*this, toSVGPath(svgValue).byteStream()); } -class UnderlyingPathSegTypesChecker : public InterpolationType::ConversionChecker { -public: - ~UnderlyingPathSegTypesChecker() final {} - - static PassOwnPtr<UnderlyingPathSegTypesChecker> create(const InterpolationType& type, const UnderlyingValue& underlyingValue) - { - return adoptPtr(new UnderlyingPathSegTypesChecker(type, getPathSegTypes(underlyingValue))); - } - -private: - UnderlyingPathSegTypesChecker(const InterpolationType& type, const Vector<SVGPathSegType>& pathSegTypes) - : ConversionChecker(type) - , m_pathSegTypes(pathSegTypes) - { } - - static const Vector<SVGPathSegType>& getPathSegTypes(const UnderlyingValue& underlyingValue) - { - return toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes(); - } - - bool isValid(const InterpolationEnvironment&, const UnderlyingValue& underlyingValue) const final - { - return m_pathSegTypes == getPathSegTypes(underlyingValue); - } - - Vector<SVGPathSegType> m_pathSegTypes; -}; - PassOwnPtr<InterpolationValue> SVGPathInterpolationType::maybeConvertNeutral(const UnderlyingValue& underlyingValue, ConversionCheckers& conversionCheckers) const { - conversionCheckers.append(UnderlyingPathSegTypesChecker::create(*this, underlyingValue)); - OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount); - result->set(PathArgsIndex, toInterpolableList(underlyingValue->interpolableValue()).get(PathArgsIndex)->cloneAndZero()); - result->set(PathNeutralIndex, InterpolableNumber::create(1)); - return InterpolationValue::create(*this, result.release(), - const_cast<NonInterpolableValue*>(underlyingValue->nonInterpolableValue())); // Take ref. -} - -static bool pathSegTypesMatch(const Vector<SVGPathSegType>& a, const Vector<SVGPathSegType>& b) -{ - if (a.size() != b.size()) - return false; - - for (size_t i = 0; i < a.size(); i++) { - if (toAbsolutePathSegType(a[i]) != toAbsolutePathSegType(b[i])) - return false; - } - - return true; + return PathInterpolationFunctions::maybeConvertNeutral(*this, underlyingValue, conversionCheckers); } PassOwnPtr<PairwisePrimitiveInterpolation> SVGPathInterpolationType::mergeSingleConversions(InterpolationValue& startValue, InterpolationValue& endValue) const { - const Vector<SVGPathSegType>& startTypes = toSVGPathNonInterpolableValue(startValue.nonInterpolableValue())->pathSegTypes(); - const Vector<SVGPathSegType>& endTypes = toSVGPathNonInterpolableValue(endValue.nonInterpolableValue())->pathSegTypes(); - if (!pathSegTypesMatch(startTypes, endTypes)) - return nullptr; - - return PairwisePrimitiveInterpolation::create(*this, - startValue.mutableComponent().interpolableValue.release(), - endValue.mutableComponent().interpolableValue.release(), - const_cast<NonInterpolableValue*>(endValue.nonInterpolableValue())); // Take ref. + return PathInterpolationFunctions::mergeSingleConversions(*this, startValue, endValue); } void SVGPathInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const { - const InterpolableList& list = toInterpolableList(value.interpolableValue()); - double neutralComponent = toInterpolableNumber(list.get(PathNeutralIndex))->value(); - - if (neutralComponent == 0) { - underlyingValue.set(&value); - return; - } - - ASSERT(pathSegTypesMatch( - toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes(), - toSVGPathNonInterpolableValue(value.nonInterpolableValue())->pathSegTypes())); - underlyingValue.mutableComponent().interpolableValue->scaleAndAdd(neutralComponent, value.interpolableValue()); - underlyingValue.mutableComponent().nonInterpolableValue = const_cast<NonInterpolableValue*>(value.nonInterpolableValue()); // Take ref. + PathInterpolationFunctions::composite(underlyingValue, underlyingFraction, value); } PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGPathInterpolationType::appliedSVGValue(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue) const { - RefPtr<SVGPathByteStream> pathByteStream = SVGPathByteStream::create(); - InterpolatedSVGPathSource source( - toInterpolableList(*toInterpolableList(interpolableValue).get(PathArgsIndex)), - toSVGPathNonInterpolableValue(nonInterpolableValue)->pathSegTypes()); - SVGPathByteStreamBuilder builder(*pathByteStream); - SVGPathParser(&source, &builder).parsePathDataFromSource(UnalteredParsing, false); - return SVGPath::create(CSSPathValue::create(pathByteStream.release())); + return SVGPath::create(CSSPathValue::create(PathInterpolationFunctions::appliedValue(interpolableValue, nonInterpolableValue))); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/StringKeyframe.cpp b/third_party/WebKit/Source/core/animation/StringKeyframe.cpp index 6d77cde5..990b7f61 100644 --- a/third_party/WebKit/Source/core/animation/StringKeyframe.cpp +++ b/third_party/WebKit/Source/core/animation/StringKeyframe.cpp
@@ -14,6 +14,7 @@ #include "core/animation/CSSLengthListInterpolationType.h" #include "core/animation/CSSNumberInterpolationType.h" #include "core/animation/CSSPaintInterpolationType.h" +#include "core/animation/CSSPathInterpolationType.h" #include "core/animation/CSSShadowListInterpolationType.h" #include "core/animation/CSSValueInterpolationType.h" #include "core/animation/CSSVisibilityInterpolationType.h" @@ -261,6 +262,9 @@ case CSSPropertyStroke: applicableTypes->append(adoptPtr(new CSSPaintInterpolationType(cssProperty))); break; + case CSSPropertyD: + applicableTypes->append(adoptPtr(new CSSPathInterpolationType(cssProperty))); + break; case CSSPropertyBoxShadow: case CSSPropertyTextShadow: applicableTypes->append(adoptPtr(new CSSShadowListInterpolationType(cssProperty)));
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi index 56599d3..837757e 100644 --- a/third_party/WebKit/Source/core/core.gypi +++ b/third_party/WebKit/Source/core/core.gypi
@@ -858,6 +858,8 @@ 'animation/CSSNumberInterpolationType.h', 'animation/CSSPaintInterpolationType.cpp', 'animation/CSSPaintInterpolationType.h', + 'animation/CSSPathInterpolationType.cpp', + 'animation/CSSPathInterpolationType.h', 'animation/CSSShadowListInterpolationType.cpp', 'animation/CSSShadowListInterpolationType.h', 'animation/CSSValueInterpolationType.cpp', @@ -925,6 +927,8 @@ 'animation/NumberSVGInterpolation.h', 'animation/PaintPropertyFunctions.cpp', 'animation/PaintPropertyFunctions.h', + 'animation/PathInterpolationFunctions.cpp', + 'animation/PathInterpolationFunctions.h', 'animation/PrimitiveInterpolation.h', 'animation/PropertyHandle.cpp', 'animation/PropertyHandle.h',
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index 506828c..7cc55e5 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -107,21 +107,16 @@ CSSParserTokenRange originalRange = m_range; CSSPropertyID propertyId = resolveCSSPropertyID(unresolvedProperty); - if (RefPtrWillBeRawPtr<CSSValue> parsedValue = parseSingleValue(unresolvedProperty)) { - if (!m_range.atEnd()) - return false; - addProperty(propertyId, parsedValue.release(), important); - return true; - } - - if (parseShorthand(unresolvedProperty, important)) - return true; - - CSSParserValueList valueList(m_range); - if (valueList.size()) { - m_valueList = &valueList; - if (parseValue(unresolvedProperty, important)) + if (isShorthandProperty(propertyId)) { + if (parseShorthand(unresolvedProperty, important)) return true; + } else { + if (RefPtrWillBeRawPtr<CSSValue> parsedValue = parseSingleValue(unresolvedProperty)) { + if (!m_range.atEnd()) + return false; + addProperty(propertyId, parsedValue.release(), important); + return true; + } } if (RuntimeEnabledFeatures::cssVariablesEnabled() && CSSVariableParser::containsValidVariableReferences(originalRange)) { @@ -3115,6 +3110,9 @@ case CSSPropertyWebkitFilter: case CSSPropertyBackdropFilter: return consumeFilter(m_range, m_context.mode()); + case CSSPropertyTextDecoration: + ASSERT(!RuntimeEnabledFeatures::css3TextDecorationsEnabled()); + // fallthrough case CSSPropertyWebkitTextDecorationsInEffect: case CSSPropertyTextDecorationLine: return consumeTextDecorationLine(m_range); @@ -3219,6 +3217,15 @@ case CSSPropertyVerticalAlign: return consumeVerticalAlign(m_range, m_context.mode()); default: + CSSParserValueList valueList(m_range); + if (valueList.size()) { + m_valueList = &valueList; + if (RefPtrWillBeRawPtr<CSSValue> result = legacyParseValue(unresolvedProperty)) { + while (!m_range.atEnd()) + m_range.consume(); + return result.release(); + } + } return nullptr; } } @@ -3805,19 +3812,9 @@ return consumeAnimationShorthand(animationShorthandForParsing(), unresolvedProperty == CSSPropertyAliasWebkitAnimation, important); case CSSPropertyTransition: return consumeAnimationShorthand(transitionShorthandForParsing(), false, important); - case CSSPropertyTextDecoration: { - // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration - // is disabled to match CSS 2.1 rules for parsing 'text-decoration'. - if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) - return consumeShorthandGreedily(textDecorationShorthand(), important); - // TODO(rwlbuis): investigate if this shorthand hack can be removed. - m_currentShorthand = oldShorthand; - RefPtrWillBeRawPtr<CSSValue> textDecoration = consumeTextDecorationLine(m_range); - if (!textDecoration || !m_range.atEnd()) - return false; - addProperty(CSSPropertyTextDecoration, textDecoration.release(), important); - return true; - } + case CSSPropertyTextDecoration: + ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled()); + return consumeShorthandGreedily(textDecorationShorthand(), important); case CSSPropertyMargin: return consume4Values(marginShorthand(), important); case CSSPropertyPadding: @@ -3869,7 +3866,11 @@ } default: m_currentShorthand = oldShorthand; - return false; + CSSParserValueList valueList(m_range); + if (!valueList.size()) + return false; + m_valueList = &valueList; + return legacyParseShorthand(unresolvedProperty, important); } }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h index d68f032..efafded 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -119,7 +119,9 @@ bool consumeCSSWideKeyword(CSSPropertyID unresolvedProperty, bool important); PassRefPtrWillBeRawPtr<CSSValue> parseSingleValue(CSSPropertyID); - bool parseValue(CSSPropertyID, bool important); + PassRefPtrWillBeRawPtr<CSSValue> legacyParseValue(CSSPropertyID); + bool legacyParseAndApplyValue(CSSPropertyID, bool important); + bool legacyParseShorthand(CSSPropertyID, bool important); bool inShorthand() const { return m_inParseShorthand; } bool inQuirksMode() const { return isQuirksModeBehavior(m_context.mode()); } @@ -185,8 +187,8 @@ bool parseGridLineNames(CSSParserValueList&, CSSValueList&, CSSGridLineNamesValue* = nullptr); PassRefPtrWillBeRawPtr<CSSValue> parseGridAutoFlow(CSSParserValueList&); - bool parseLegacyPosition(CSSPropertyID, bool important); - bool parseItemPositionOverflowPosition(CSSPropertyID, bool important); + PassRefPtrWillBeRawPtr<CSSValue> parseLegacyPosition(); + PassRefPtrWillBeRawPtr<CSSValue> parseItemPositionOverflowPosition(); PassRefPtrWillBeRawPtr<CSSValue> parseContentDistributionOverflowPosition(); PassRefPtrWillBeRawPtr<CSSValue> parseShapeProperty(CSSPropertyID propId);
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp index 4287922..0a55dcc 100644 --- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -294,7 +294,16 @@ addProperty(longhands[i], value, important); } -bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool important) +bool CSSPropertyParser::legacyParseAndApplyValue(CSSPropertyID propertyID, bool important) +{ + RefPtrWillBeRawPtr<CSSValue> result = legacyParseValue(propertyID); + if (!result) + return false; + addProperty(propertyID, result.release(), important); + return true; +} + +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::legacyParseValue(CSSPropertyID unresolvedProperty) { CSSPropertyID propId = resolveCSSPropertyID(unresolvedProperty); @@ -309,11 +318,10 @@ // TODO(timloh): Move to parseSingleValue if (CSSParserFastPaths::isKeywordPropertyID(propId)) { if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id)) - return false; + return nullptr; if (m_valueList->next() && !inShorthand()) - return false; - addProperty(propId, cssValuePool().createIdentifierValue(id), important); - return true; + return nullptr; + return cssValuePool().createIdentifierValue(id); } bool validPrimitive = false; @@ -345,45 +353,25 @@ case CSSPropertyBackgroundOrigin: case CSSPropertyMaskSourceType: case CSSPropertyWebkitBackgroundOrigin: - case CSSPropertyBackgroundPosition: case CSSPropertyBackgroundPositionX: case CSSPropertyBackgroundPositionY: case CSSPropertyBackgroundSize: - case CSSPropertyBackgroundRepeat: case CSSPropertyWebkitMaskClip: case CSSPropertyWebkitMaskComposite: case CSSPropertyWebkitMaskImage: case CSSPropertyWebkitMaskOrigin: - case CSSPropertyWebkitMaskPosition: case CSSPropertyWebkitMaskPositionX: case CSSPropertyWebkitMaskPositionY: case CSSPropertyWebkitMaskSize: - case CSSPropertyWebkitMaskRepeat: case CSSPropertyWebkitMaskRepeatX: case CSSPropertyWebkitMaskRepeatY: { - RefPtrWillBeRawPtr<CSSValue> val1 = nullptr; - RefPtrWillBeRawPtr<CSSValue> val2 = nullptr; + RefPtrWillBeRawPtr<CSSValue> dummyValue = nullptr; CSSPropertyID propId1, propId2; - bool result = false; - if (parseFillProperty(unresolvedProperty, propId1, propId2, val1, val2)) { - if (propId == CSSPropertyBackgroundPosition || - propId == CSSPropertyBackgroundRepeat || - propId == CSSPropertyWebkitMaskPosition || - propId == CSSPropertyWebkitMaskRepeat) { - ShorthandScope scope(this, propId); - addProperty(propId1, val1.release(), important); - if (val2) - addProperty(propId2, val2.release(), important); - } else { - addProperty(propId1, val1.release(), important); - if (val2) - addProperty(propId2, val2.release(), important); - } - result = true; - } - m_implicitShorthand = false; - return result; + if (!parseFillProperty(unresolvedProperty, propId1, propId2, parsedValue, dummyValue)) + return nullptr; + ASSERT(!dummyValue); + break; } case CSSPropertyBorderImageSource: // <uri> | none | inherit case CSSPropertyWebkitMaskBoxImageSource: @@ -413,59 +401,37 @@ validPrimitive = validUnit(value, FLength | FPercent | FUnitlessQuirk); break; - case CSSPropertySrc: - case CSSPropertyUnicodeRange: - /* @font-face only descriptors */ + case CSSPropertyWebkitBorderImage: + parsedValue = parseBorderImage(propId); break; - /* CSS3 properties */ - - case CSSPropertyBorderImage: - case CSSPropertyWebkitMaskBoxImage: - return parseBorderImageShorthand(propId, important); - case CSSPropertyWebkitBorderImage: { - if (RefPtrWillBeRawPtr<CSSValue> result = parseBorderImage(propId)) { - addProperty(propId, result, important); - return true; - } - return false; - } - case CSSPropertyBorderImageOutset: case CSSPropertyWebkitMaskBoxImageOutset: { RefPtrWillBeRawPtr<CSSQuadValue> result = nullptr; - if (parseBorderImageOutset(result)) { - addProperty(propId, result, important); - return true; - } - break; + if (parseBorderImageOutset(result)) + return result.release(); + return nullptr; } case CSSPropertyBorderImageRepeat: case CSSPropertyWebkitMaskBoxImageRepeat: { RefPtrWillBeRawPtr<CSSValue> result = nullptr; - if (parseBorderImageRepeat(result)) { - addProperty(propId, result, important); - return true; - } - break; + if (parseBorderImageRepeat(result)) + return result.release(); + return nullptr; } case CSSPropertyBorderImageSlice: case CSSPropertyWebkitMaskBoxImageSlice: { RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result = nullptr; - if (parseBorderImageSlice(propId, result)) { - addProperty(propId, result, important); - return true; - } - break; + if (parseBorderImageSlice(propId, result)) + return result.release(); + return nullptr; } case CSSPropertyBorderImageWidth: case CSSPropertyWebkitMaskBoxImageWidth: { RefPtrWillBeRawPtr<CSSQuadValue> result = nullptr; - if (parseBorderImageWidth(result)) { - addProperty(propId, result, important); - return true; - } - break; + if (parseBorderImageWidth(result)) + return result.release(); + return nullptr; } case CSSPropertyWebkitBoxReflect: if (id == CSSValueNone) @@ -483,15 +449,17 @@ break; case CSSPropertyJustifySelf: ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); - return parseItemPositionOverflowPosition(propId, important); + parsedValue = parseItemPositionOverflowPosition(); + break; case CSSPropertyJustifyItems: ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); - if (parseLegacyPosition(propId, important)) - return true; + if ((parsedValue = parseLegacyPosition())) + break; m_valueList->setCurrentIndex(0); - return parseItemPositionOverflowPosition(propId, important); + parsedValue = parseItemPositionOverflowPosition(); + break; case CSSPropertyGridAutoFlow: ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); parsedValue = parseGridAutoFlow(*m_valueList); @@ -516,89 +484,19 @@ parsedValue = parseGridPosition(); break; - case CSSPropertyGridGap: - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); - return parseGridGapShorthand(important); - - case CSSPropertyGridColumn: - case CSSPropertyGridRow: - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); - return parseGridItemPositionShorthand(propId, important); - - case CSSPropertyGridArea: - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); - return parseGridAreaShorthand(important); - case CSSPropertyGridTemplateAreas: ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); parsedValue = parseGridTemplateAreas(); break; - case CSSPropertyGridTemplate: - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); - return parseGridTemplateShorthand(important); - - case CSSPropertyGrid: - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); - return parseGridShorthand(important); - - /* shorthand properties */ - case CSSPropertyBackground: { - // Position must come before color in this array because a plain old "0" is a legal color - // in quirks mode but it's usually the X coordinate of a position. - const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat, - CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin, - CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize }; - return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important); - } - case CSSPropertyWebkitMask: { - const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, - CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize }; - return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important); - } - case CSSPropertyBorder: - // [ 'border-width' || 'border-style' || <color> ] | inherit - { - if (parseShorthand(propId, borderShorthandForParsing(), important)) { - // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as - // though a value of none was specified for the image. - addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important); - return true; - } - return false; - } - case CSSPropertyBorderTop: - // [ 'border-top-width' || 'border-style' || <color> ] | inherit - return parseShorthand(propId, borderTopShorthand(), important); - case CSSPropertyBorderRight: - // [ 'border-right-width' || 'border-style' || <color> ] | inherit - return parseShorthand(propId, borderRightShorthand(), important); - case CSSPropertyBorderBottom: - // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit - return parseShorthand(propId, borderBottomShorthand(), important); - case CSSPropertyBorderLeft: - // [ 'border-left-width' || 'border-style' || <color> ] | inherit - return parseShorthand(propId, borderLeftShorthand(), important); - case CSSPropertyBorderColor: - // <color>{1,4} | inherit - return parse4Values(propId, borderColorShorthand().properties(), important); - case CSSPropertyBorderWidth: - // <border-width>{1,4} | inherit - return parse4Values(propId, borderWidthShorthand().properties(), important); - case CSSPropertyBorderStyle: - // <border-style>{1,4} | inherit - return parse4Values(propId, borderStyleShorthand().properties(), important); - case CSSPropertyInvalid: - return false; case CSSPropertyWebkitClipPath: if (id == CSSValueNone) { validPrimitive = true; } else if (value->m_unit == CSSParserValue::Function) { parsedValue = parseBasicShape(); } else if (value->m_unit == CSSParserValue::URI) { - parsedValue = CSSURIValue::create(value->string); - addProperty(propId, parsedValue.release(), important); - return true; + // TODO(timloh): This will allow trailing junk + return CSSURIValue::create(value->string); } break; case CSSPropertyShapeOutside: @@ -615,227 +513,17 @@ case CSSPropertyAlignSelf: ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); - return parseItemPositionOverflowPosition(propId, important); + parsedValue = parseItemPositionOverflowPosition(); + break; case CSSPropertyAlignItems: ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); - return parseItemPositionOverflowPosition(propId, important); - - // Properties below are validated inside parseViewportProperty, because we - // check for parser state. We need to invalidate if someone adds them outside - // a @viewport rule. - case CSSPropertyMaxZoom: - case CSSPropertyMinZoom: - case CSSPropertyOrientation: - case CSSPropertyUserZoom: - validPrimitive = false; + parsedValue = parseItemPositionOverflowPosition(); break; - // These were not accepted by the new path above so we should return false. - case CSSPropertyWebkitPerspectiveOriginX: - case CSSPropertyWebkitTransformOriginX: - case CSSPropertyWebkitPerspectiveOriginY: - case CSSPropertyWebkitTransformOriginY: - case CSSPropertyWebkitTransformOriginZ: - case CSSPropertyWebkitMarginCollapse: - case CSSPropertyWillChange: - case CSSPropertyPage: - case CSSPropertyOverflow: - case CSSPropertyQuotes: - case CSSPropertyWebkitHighlight: - case CSSPropertyFontVariantLigatures: - case CSSPropertyFontFeatureSettings: - case CSSPropertyFontVariant: - case CSSPropertyFontFamily: - case CSSPropertyFontWeight: - case CSSPropertyLetterSpacing: - case CSSPropertyWordSpacing: - case CSSPropertyTabSize: - case CSSPropertyFontSize: - case CSSPropertyLineHeight: - case CSSPropertyRotate: - case CSSPropertyFont: - case CSSPropertyWebkitBorderHorizontalSpacing: - case CSSPropertyWebkitBorderVerticalSpacing: - case CSSPropertyBorderSpacing: - case CSSPropertyCounterIncrement: - case CSSPropertyCounterReset: - case CSSPropertySize: - case CSSPropertyTextIndent: - case CSSPropertyMaxWidth: - case CSSPropertyMaxHeight: - case CSSPropertyWebkitMaxLogicalWidth: - case CSSPropertyWebkitMaxLogicalHeight: - case CSSPropertyMinWidth: - case CSSPropertyMinHeight: - case CSSPropertyWidth: - case CSSPropertyHeight: - case CSSPropertyWebkitMinLogicalWidth: - case CSSPropertyWebkitMinLogicalHeight: - case CSSPropertyWebkitLogicalWidth: - case CSSPropertyWebkitLogicalHeight: - case CSSPropertyScrollSnapDestination: - case CSSPropertyObjectPosition: - case CSSPropertyPerspectiveOrigin: - case CSSPropertyClip: - case CSSPropertyTouchAction: - case CSSPropertyWebkitLineClamp: - case CSSPropertyWebkitFontSizeDelta: - case CSSPropertyWebkitHyphenateCharacter: - case CSSPropertyWebkitLocale: - case CSSPropertyWebkitColumnWidth: - case CSSPropertyWebkitColumnCount: - case CSSPropertyWebkitColumns: - case CSSPropertyWebkitColumnGap: - case CSSPropertyWebkitColumnSpan: - case CSSPropertyZoom: - case CSSPropertyAnimation: - case CSSPropertyTransition: - case CSSPropertyAnimationDelay: - case CSSPropertyTransitionDelay: - case CSSPropertyAnimationDirection: - case CSSPropertyAnimationDuration: - case CSSPropertyTransitionDuration: - case CSSPropertyAnimationFillMode: - case CSSPropertyAnimationIterationCount: - case CSSPropertyAnimationName: - case CSSPropertyAnimationPlayState: - case CSSPropertyAnimationTimingFunction: - case CSSPropertyTransitionTimingFunction: - case CSSPropertyTransitionProperty: - case CSSPropertyGridColumnGap: - case CSSPropertyGridRowGap: - case CSSPropertyShapeMargin: - case CSSPropertyShapeImageThreshold: - case CSSPropertyWebkitBoxOrdinalGroup: - case CSSPropertyOrphans: - case CSSPropertyWidows: - case CSSPropertyWebkitTapHighlightColor: - case CSSPropertyWebkitTextFillColor: - case CSSPropertyColor: - case CSSPropertyZIndex: - case CSSPropertyTextShadow: - case CSSPropertyBoxShadow: - case CSSPropertyWebkitFilter: - case CSSPropertyBackdropFilter: - case CSSPropertyTextDecorationColor: - case CSSPropertyWebkitTextDecorationsInEffect: - case CSSPropertyTextDecorationLine: - case CSSPropertyTextDecoration: - case CSSPropertyMotionPath: - case CSSPropertyMotionOffset: - case CSSPropertyMotionRotation: - case CSSPropertyMotion: - case CSSPropertyWebkitTextEmphasisColor: - case CSSPropertyWebkitTextEmphasisStyle: - case CSSPropertyWebkitTextEmphasis: - case CSSPropertyOutline: - case CSSPropertyOutlineColor: - case CSSPropertyOutlineWidth: - case CSSPropertyOutlineOffset: - case CSSPropertyWebkitBorderStartColor: - case CSSPropertyWebkitBorderEndColor: - case CSSPropertyWebkitBorderBeforeColor: - case CSSPropertyWebkitBorderAfterColor: - case CSSPropertyWebkitBorderStartWidth: - case CSSPropertyWebkitBorderEndWidth: - case CSSPropertyWebkitBorderBeforeWidth: - case CSSPropertyWebkitBorderAfterWidth: - case CSSPropertyWebkitBorderStart: - case CSSPropertyWebkitBorderEnd: - case CSSPropertyWebkitBorderBefore: - case CSSPropertyWebkitBorderAfter: - case CSSPropertyWebkitTextStroke: - case CSSPropertyWebkitTextStrokeColor: - case CSSPropertyWebkitTextStrokeWidth: - case CSSPropertyTransform: - case CSSPropertyFill: - case CSSPropertyStroke: - case CSSPropertyStopColor: - case CSSPropertyFloodColor: - case CSSPropertyLightingColor: - case CSSPropertyPaintOrder: - case CSSPropertyMarginTop: - case CSSPropertyMarginRight: - case CSSPropertyMarginBottom: - case CSSPropertyMarginLeft: - case CSSPropertyMargin: - case CSSPropertyWebkitMarginStart: - case CSSPropertyWebkitMarginEnd: - case CSSPropertyWebkitMarginBefore: - case CSSPropertyWebkitMarginAfter: - case CSSPropertyPaddingTop: - case CSSPropertyPaddingRight: - case CSSPropertyPaddingBottom: - case CSSPropertyPaddingLeft: - case CSSPropertyPadding: - case CSSPropertyWebkitPaddingStart: - case CSSPropertyWebkitPaddingEnd: - case CSSPropertyWebkitPaddingBefore: - case CSSPropertyWebkitPaddingAfter: - case CSSPropertyMarker: - case CSSPropertyMarkerStart: - case CSSPropertyMarkerMid: - case CSSPropertyMarkerEnd: - case CSSPropertyFlex: - case CSSPropertyFlexBasis: - case CSSPropertyFlexGrow: - case CSSPropertyFlexShrink: - case CSSPropertyFlexFlow: - case CSSPropertyStrokeDasharray: - case CSSPropertyD: - case CSSPropertyWebkitColumnRule: - case CSSPropertyWebkitColumnRuleColor: - case CSSPropertyWebkitColumnRuleWidth: - case CSSPropertyClipPath: - case CSSPropertyFilter: - case CSSPropertyMask: - case CSSPropertyStrokeOpacity: - case CSSPropertyFillOpacity: - case CSSPropertyStopOpacity: - case CSSPropertyFloodOpacity: - case CSSPropertyOpacity: - case CSSPropertyWebkitBoxFlex: - case CSSPropertyBaselineShift: - case CSSPropertyStrokeMiterlimit: - case CSSPropertyStrokeWidth: - case CSSPropertyStrokeDashoffset: - case CSSPropertyCx: - case CSSPropertyCy: - case CSSPropertyX: - case CSSPropertyY: - case CSSPropertyR: - case CSSPropertyRx: - case CSSPropertyRy: - case CSSPropertyScale: - case CSSPropertyTranslate: - case CSSPropertyCursor: - case CSSPropertyTransformOrigin: - case CSSPropertyContent: - case CSSPropertyListStyleImage: - case CSSPropertyListStyle: - case CSSPropertyPerspective: - case CSSPropertyScrollSnapCoordinate: - case CSSPropertyScrollSnapPointsX: - case CSSPropertyScrollSnapPointsY: - case CSSPropertyBorderTopRightRadius: - case CSSPropertyBorderTopLeftRadius: - case CSSPropertyBorderBottomLeftRadius: - case CSSPropertyBorderBottomRightRadius: - case CSSPropertyBorderRadius: - case CSSPropertyAliasWebkitBorderRadius: - case CSSPropertyWebkitBoxFlexGroup: - case CSSPropertyOrder: - case CSSPropertyTextUnderlinePosition: - case CSSPropertyVerticalAlign: - validPrimitive = false; - break; - + // Everything else is handled in CSSPropertyParser.cpp default: - // If you crash here, it's because you added a css property and are not handling it - // in either this switch statement or the one in CSSPropertyParser::parseSingleValue. - ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId); - return false; + return nullptr; } if (validPrimitive) { @@ -844,12 +532,109 @@ } ASSERT(!m_parsedCalculation); if (parsedValue) { - if (!m_valueList->current() || inShorthand()) { - addProperty(propId, parsedValue.release(), important); + if (!m_valueList->current() || inShorthand()) + return parsedValue.release(); + } + return nullptr; +} + +bool CSSPropertyParser::legacyParseShorthand(CSSPropertyID propertyID, bool important) +{ + switch (propertyID) { + case CSSPropertyBackgroundPosition: + case CSSPropertyBackgroundRepeat: + case CSSPropertyWebkitMaskPosition: + case CSSPropertyWebkitMaskRepeat: { + RefPtrWillBeRawPtr<CSSValue> val1 = nullptr; + RefPtrWillBeRawPtr<CSSValue> val2 = nullptr; + CSSPropertyID propId1, propId2; + if (parseFillProperty(propertyID, propId1, propId2, val1, val2)) { + ShorthandScope scope(this, propertyID); + addProperty(propId1, val1.release(), important); + if (val2) + addProperty(propId2, val2.release(), important); + m_implicitShorthand = false; return true; } + m_implicitShorthand = false; + return true; } - return false; + + case CSSPropertyBorderImage: + case CSSPropertyWebkitMaskBoxImage: + return parseBorderImageShorthand(propertyID, important); + + case CSSPropertyGridGap: + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); + return parseGridGapShorthand(important); + + case CSSPropertyGridColumn: + case CSSPropertyGridRow: + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); + return parseGridItemPositionShorthand(propertyID, important); + + case CSSPropertyGridArea: + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); + return parseGridAreaShorthand(important); + + case CSSPropertyGridTemplate: + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); + return parseGridTemplateShorthand(important); + + case CSSPropertyGrid: + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); + return parseGridShorthand(important); + + case CSSPropertyBackground: { + // Position must come before color in this array because a plain old "0" is a legal color + // in quirks mode but it's usually the X coordinate of a position. + const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat, + CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin, + CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize }; + return parseFillShorthand(propertyID, properties, WTF_ARRAY_LENGTH(properties), important); + } + case CSSPropertyWebkitMask: { + const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, + CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize }; + return parseFillShorthand(propertyID, properties, WTF_ARRAY_LENGTH(properties), important); + } + case CSSPropertyBorder: + // [ 'border-width' || 'border-style' || <color> ] + { + if (parseShorthand(propertyID, borderShorthandForParsing(), important)) { + // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as + // though a value of none was specified for the image. + addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important); + return true; + } + return false; + } + case CSSPropertyBorderTop: + // [ 'border-top-width' || 'border-style' || <color> ] + return parseShorthand(propertyID, borderTopShorthand(), important); + case CSSPropertyBorderRight: + // [ 'border-right-width' || 'border-style' || <color> ] + return parseShorthand(propertyID, borderRightShorthand(), important); + case CSSPropertyBorderBottom: + // [ 'border-bottom-width' || 'border-style' || <color> ] + return parseShorthand(propertyID, borderBottomShorthand(), important); + case CSSPropertyBorderLeft: + // [ 'border-left-width' || 'border-style' || <color> ] + return parseShorthand(propertyID, borderLeftShorthand(), important); + case CSSPropertyBorderColor: + // <color>{1,4} + return parse4Values(propertyID, borderColorShorthand().properties(), important); + case CSSPropertyBorderWidth: + // <border-width>{1,4} + return parse4Values(propertyID, borderWidthShorthand().properties(), important); + case CSSPropertyBorderStyle: + // <border-style>{1,4} + return parse4Values(propertyID, borderStyleShorthand().properties(), important); + + // The remaining shorthands are handled in CSSPropertyParser.cpp + default: + return false; + } } void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRefPtrWillBeRawPtr<CSSValue> rval) @@ -1048,10 +833,17 @@ while (m_valueList->current()) { found = false; for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) { - if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) { - propertyFound[propIndex] = found = true; - propertiesParsed++; + if (propertyFound[propIndex]) + continue; + if (propId == CSSPropertyBorder) { + if (!legacyParseShorthand(shorthand.properties()[propIndex], important)) + continue; + } else { + if (!legacyParseAndApplyValue(shorthand.properties()[propIndex], important)) + continue; } + propertyFound[propIndex] = found = true; + propertiesParsed++; } // if we didn't find at least one match, this is an @@ -1098,7 +890,7 @@ // the order is top, right, bottom, left switch (num) { case 1: { - if (!parseValue(properties[0], important)) + if (!legacyParseAndApplyValue(properties[0], important)) return false; CSSValue* value = m_parsedProperties.last().value(); ImplicitScope implicitScope(this); @@ -1108,7 +900,7 @@ break; } case 2: { - if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) + if (!legacyParseAndApplyValue(properties[0], important) || !legacyParseAndApplyValue(properties[1], important)) return false; CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value(); ImplicitScope implicitScope(this); @@ -1118,7 +910,7 @@ break; } case 3: { - if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important)) + if (!legacyParseAndApplyValue(properties[0], important) || !legacyParseAndApplyValue(properties[1], important) || !legacyParseAndApplyValue(properties[2], important)) return false; CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value(); ImplicitScope implicitScope(this); @@ -1126,8 +918,8 @@ break; } case 4: { - if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || - !parseValue(properties[2], important) || !parseValue(properties[3], important)) + if (!legacyParseAndApplyValue(properties[0], important) || !legacyParseAndApplyValue(properties[1], important) || + !legacyParseAndApplyValue(properties[2], important) || !legacyParseAndApplyValue(properties[3], important)) return false; break; } @@ -2096,7 +1888,7 @@ m_valueList->setCurrentIndex(0); // 2- <grid-auto-flow> [ <grid-auto-columns> [ / <grid-auto-rows> ]? ] - if (!parseValue(CSSPropertyGridAutoFlow, important)) + if (!legacyParseAndApplyValue(CSSPropertyGridAutoFlow, important)) return false; RefPtrWillBeRawPtr<CSSValue> autoColumnsValue = nullptr; @@ -2645,7 +2437,7 @@ || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight; } -bool CSSPropertyParser::parseLegacyPosition(CSSPropertyID propId, bool important) +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseLegacyPosition() { // [ legacy && [ left | right | center ] @@ -2655,18 +2447,18 @@ if (value->id == CSSValueLegacy) { value = m_valueList->next(); if (!value) - return false; + return nullptr; if (value->id != CSSValueCenter && value->id != CSSValueLeft && value->id != CSSValueRight) - return false; + return nullptr; } else if (value->id == CSSValueCenter || value->id == CSSValueLeft || value->id == CSSValueRight) { if (!m_valueList->next() || m_valueList->current()->id != CSSValueLegacy) - return false; + return nullptr; } else { - return false; + return nullptr; } - addProperty(propId, CSSValuePair::create(cssValuePool().createIdentifierValue(CSSValueLegacy), cssValuePool().createIdentifierValue(value->id), CSSValuePair::DropIdenticalValues), important); - return !m_valueList->next(); + m_valueList->next(); + return CSSValuePair::create(cssValuePool().createIdentifierValue(CSSValueLegacy), cssValuePool().createIdentifierValue(value->id), CSSValuePair::DropIdenticalValues); } PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseContentDistributionOverflowPosition() @@ -2718,7 +2510,7 @@ return CSSContentDistributionValue::create(distribution, position, overflow); } -bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important) +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseItemPositionOverflowPosition() { // auto | stretch | <baseline-position> | [<item-position> && <overflow-position>? ] // <baseline-position> = baseline | last-baseline; @@ -2729,11 +2521,8 @@ ASSERT(value); if (value->id == CSSValueAuto || value->id == CSSValueStretch || isBaselinePositionKeyword(value->id)) { - if (m_valueList->next()) - return false; - - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); - return true; + m_valueList->next(); + return cssValuePool().createIdentifierValue(value->id); } RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr; @@ -2745,7 +2534,7 @@ if (isAlignmentOverflowKeyword(value->id)) overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id); else - return false; + return nullptr; } } else if (isAlignmentOverflowKeyword(value->id)) { overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id); @@ -2753,21 +2542,17 @@ if (value && isItemPositionKeyword(value->id)) position = cssValuePool().createIdentifierValue(value->id); else - return false; + return nullptr; } else { - return false; + return nullptr; } - if (m_valueList->next()) - return false; + m_valueList->next(); ASSERT(position); if (overflowAlignmentKeyword) - addProperty(propId, CSSValuePair::create(position, overflowAlignmentKeyword, CSSValuePair::DropIdenticalValues), important); - else - addProperty(propId, position.release(), important); - - return true; + return CSSValuePair::create(position, overflowAlignmentKeyword, CSSValuePair::DropIdenticalValues); + return position.release(); } PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseShapeRadius(CSSParserValue* value)
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index 821c32e..c9099642 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -571,7 +571,7 @@ // Handle the scrollingElement separately, as it scrolls the viewport. if (this == document().scrollingElement()) { FloatSize delta(deltaX, deltaY); - if (document().frame()->applyScrollDelta(delta, scrollState.isBeginning()).didScroll()) { + if (document().frame()->applyScrollDelta(ScrollByPrecisePixel, delta, scrollState.isBeginning()).didScroll()) { scrolled = true; scrollState.consumeDeltaNative(scrollState.deltaX(), scrollState.deltaY()); }
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp index dea64c5..22b0234 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -673,7 +673,7 @@ TextIteratorAlgorithm<Strategy> forwardsIterator(end, PositionTemplate<Strategy>::afterNode(boundary)); while (!forwardsIterator.atEnd()) { Vector<UChar, 1024> characters; - forwardsIterator.appendTextTo(characters); + forwardsIterator.copyTextTo(characters); int i = endOfFirstWordBoundaryContext(characters.data(), characters.size()); string.append(characters.data(), i); suffixLength += i; @@ -693,7 +693,7 @@ // TODO(xiaochengh): Iterative prepending has quadratic running time // in the worst case. Should improve it to linear. if (!inTextSecurityMode) { - it.prependTextTo(string); + it.copyTextTo(string); } else { // Treat bullets used in the text security mode as regular // characters when looking for boundaries @@ -753,7 +753,7 @@ SimplifiedBackwardsTextIteratorAlgorithm<Strategy> backwardsIterator(PositionTemplate<Strategy>::firstPositionInNode(&d), start); while (!backwardsIterator.atEnd()) { Vector<UChar, 1024> characters; - backwardsIterator.prependTextTo(characters); + backwardsIterator.copyTextTo(characters); int length = characters.size(); int i = startOfLastWordBoundaryContext(characters.data(), length); // TODO(xiaochengh): Iterative prepending has quadratic running @@ -779,7 +779,7 @@ // it. bool inTextSecurityMode = it.isInTextSecurityMode(); if (!inTextSecurityMode) { - it.appendTextTo(string); + it.copyTextTo(string); } else { // Treat bullets used in the text security mode as regular // characters when looking for boundaries
diff --git a/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.h b/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.h index 82a46bb..8540c72 100644 --- a/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.h +++ b/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.h
@@ -53,7 +53,7 @@ UChar characterAt(unsigned index) const { return m_textIterator.text().characterAt(m_runOffset + index); } template<typename BufferType> - void appendTextTo(BufferType& output) { m_textIterator.appendTextTo(output, m_runOffset); } + void appendTextTo(BufferType& output) { m_textIterator.copyTextTo(output, m_runOffset); } int characterOffset() const { return m_offset; } EphemeralRangeTemplate<Strategy> range() const;
diff --git a/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp b/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp index f829b23..9d60f34 100644 --- a/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp
@@ -381,7 +381,7 @@ if (buffer.needsMoreContext()) { for (SimplifiedBackwardsTextIteratorAlgorithm<Strategy> backwardsIterator(PositionTemplate<Strategy>::firstPositionInNode(it.ownerDocument()), PositionTemplate<Strategy>(it.currentContainer(), it.startOffset())); !backwardsIterator.atEnd(); backwardsIterator.advance()) { Vector<UChar, 1024> characters; - backwardsIterator.prependTextTo(characters); + backwardsIterator.copyTextTo(characters); buffer.prependContext(characters.data(), characters.size()); if (!buffer.needsMoreContext()) break;
diff --git a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.h b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.h index 4e83851..58ad56a 100644 --- a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.h +++ b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.h
@@ -57,13 +57,10 @@ Node* node() const { return m_node; } - template<typename BufferType> - void prependTextTo(BufferType& output) { prependTextTo(output, 0, m_textLength); } - // Prepend characters with offset range [position, position + copyLength) // to the output buffer. template<typename BufferType> - void prependTextTo(BufferType& output, int position, int copyLength) + void copyTextTo(BufferType& output, int position, int copyLength) const { ASSERT(position >= 0); ASSERT(copyLength >= 0); @@ -80,6 +77,9 @@ m_textContainer.prependTo(output, m_textOffset + m_textLength - position - copyLength, copyLength); } + template<typename BufferType> + void copyTextTo(BufferType& output, int position = 0) const { copyTextTo(output, position, m_textLength - position); } + Node* startContainer() const; int endOffset() const; PositionTemplate<Strategy> startPosition() const;
diff --git a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp index 39fedb9..89ad1c4 100644 --- a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIteratorTest.cpp
@@ -20,7 +20,7 @@ const EphemeralRangeTemplate<Strategy> range = EphemeralRangeTemplate<Strategy>::rangeOfContents(element); Vector<UChar> buffer; for (SimplifiedBackwardsTextIteratorAlgorithm<Strategy> it(range.startPosition(), range.endPosition()); !it.atEnd(); it.advance()) { - it.prependTextTo(buffer); + it.copyTextTo(buffer); } return String(buffer); } @@ -90,7 +90,7 @@ EXPECT_EQ('t', backIter2.characterAt(5)) << message2; } -TEST_F(SimplifiedBackwardsTextIteratorTest, prependTextTo) +TEST_F(SimplifiedBackwardsTextIteratorTest, copyTextTo) { const char* bodyContent = "<a id=host><b id=one>one</b> not appeared <b id=two>two</b></a>"; const char* shadowContent = "three <content select=#two></content> <content select=#one></content> zero"; @@ -104,40 +104,40 @@ EphemeralRangeTemplate<EditingStrategy> range1(EphemeralRangeTemplate<EditingStrategy>::rangeOfContents(*host)); SimplifiedBackwardsTextIteratorAlgorithm<EditingStrategy> backIter1(range1.startPosition(), range1.endPosition()); Vector<UChar> output1; - backIter1.prependTextTo(output1, 0, 2); + backIter1.copyTextTo(output1, 0, 2); EXPECT_EQ("wo", String(output1)) << String::format(message, 1, "wo").utf8().data(); - backIter1.prependTextTo(output1, 2, 1); + backIter1.copyTextTo(output1, 2, 1); EXPECT_EQ("two", String(output1)) << String::format(message, 1, "two").utf8().data(); backIter1.advance(); - backIter1.prependTextTo(output1, 0, 1); + backIter1.copyTextTo(output1, 0, 1); EXPECT_EQ("etwo", String(output1)) << String::format(message, 1, "etwo").utf8().data(); - backIter1.prependTextTo(output1, 1, 2); + backIter1.copyTextTo(output1, 1, 2); EXPECT_EQ("onetwo", String(output1)) << String::format(message, 1, "onetwo").utf8().data(); EphemeralRangeTemplate<EditingInComposedTreeStrategy> range2(EphemeralRangeTemplate<EditingInComposedTreeStrategy>::rangeOfContents(*host)); SimplifiedBackwardsTextIteratorAlgorithm<EditingInComposedTreeStrategy> backIter2(range2.startPosition(), range2.endPosition()); Vector<UChar> output2; - backIter2.prependTextTo(output2, 0, 2); + backIter2.copyTextTo(output2, 0, 2); EXPECT_EQ("ro", String(output2)) << String::format(message, 2, "ro").utf8().data(); - backIter2.prependTextTo(output2, 2, 3); + backIter2.copyTextTo(output2, 2, 3); EXPECT_EQ(" zero", String(output2)) << String::format(message, 2, " zero").utf8().data(); backIter2.advance(); - backIter2.prependTextTo(output2, 0, 1); + backIter2.copyTextTo(output2, 0, 1); EXPECT_EQ("e zero", String(output2)) << String::format(message, 2, "e zero").utf8().data(); - backIter2.prependTextTo(output2, 1, 2); + backIter2.copyTextTo(output2, 1, 2); EXPECT_EQ("one zero", String(output2)) << String::format(message, 2, "one zero").utf8().data(); backIter2.advance(); - backIter2.prependTextTo(output2, 0, 1); + backIter2.copyTextTo(output2, 0, 1); EXPECT_EQ(" one zero", String(output2)) << String::format(message, 2, " one zero").utf8().data(); backIter2.advance(); - backIter2.prependTextTo(output2, 0, 2); + backIter2.copyTextTo(output2, 0, 2); EXPECT_EQ("wo one zero", String(output2)) << String::format(message, 2, "wo one zero").utf8().data(); - backIter2.prependTextTo(output2, 2, 1); + backIter2.copyTextTo(output2, 2, 1); EXPECT_EQ("two one zero", String(output2)) << String::format(message, 2, "two one zero").utf8().data(); backIter2.advance(); - backIter2.prependTextTo(output2, 0, 3); + backIter2.copyTextTo(output2, 0, 3); EXPECT_EQ("ee two one zero", String(output2)) << String::format(message, 2, "ee two one zero").utf8().data(); - backIter2.prependTextTo(output2, 3, 3); + backIter2.copyTextTo(output2, 3, 3); EXPECT_EQ("three two one zero", String(output2)) << String::format(message, 2, "three two one zero").utf8().data(); }
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h index af1aff4..1262719d 100644 --- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h +++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
@@ -78,11 +78,13 @@ bool breaksAtReplacedElement() { return !(m_behavior & TextIteratorDoesNotBreakAtReplacedElement); } + // Append characters with offset range [position, position + copyLength) + // to the output buffer. template<typename BufferType> - void appendTextTo(BufferType& output, int position = 0) const { appendTextTo(output, position, length() - position); } + void copyTextTo(BufferType& output, int position, int copyLength) const { m_textState.appendTextTo(output, position, copyLength); } template<typename BufferType> - void appendTextTo(BufferType& output, int position, int appendLength) const { m_textState.appendTextTo(output, position, appendLength); } + void copyTextTo(BufferType& output, int position = 0) const { copyTextTo(output, position, length() - position); } // Computes the length of the given range using a text iterator. The default // iteration behavior is to always emit object replacement characters for
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp index 36209b6..1d47165 100644 --- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp
@@ -386,7 +386,7 @@ EXPECT_EQ(3, TextIterator::rangeLength(range->startPosition(), range->endPosition())); } -TEST_F(TextIteratorTest, appendTextTo) +TEST_F(TextIteratorTest, copyTextTo) { const char* bodyContent = "<a id=host><b id=one>one</b> not appeared <b id=two>two</b></a>"; const char* shadowContent = "three <content select=#two></content> <content select=#one></content> zero"; @@ -400,40 +400,40 @@ EphemeralRangeTemplate<EditingStrategy> range1(EphemeralRangeTemplate<EditingStrategy>::rangeOfContents(*host)); TextIteratorAlgorithm<EditingStrategy> iter1(range1.startPosition(), range1.endPosition()); Vector<UChar> output1; - iter1.appendTextTo(output1, 0, 2); + iter1.copyTextTo(output1, 0, 2); EXPECT_EQ("on", String(output1)) << String::format(message, 1, "on").utf8().data(); - iter1.appendTextTo(output1, 2, 1); + iter1.copyTextTo(output1, 2, 1); EXPECT_EQ("one", String(output1)) << String::format(message, 1, "one").utf8().data(); iter1.advance(); - iter1.appendTextTo(output1, 0, 1); + iter1.copyTextTo(output1, 0, 1); EXPECT_EQ("onet", String(output1)) << String::format(message, 1, "onet").utf8().data(); - iter1.appendTextTo(output1, 1, 2); + iter1.copyTextTo(output1, 1, 2); EXPECT_EQ("onetwo", String(output1)) << String::format(message, 1, "onetwo").utf8().data(); EphemeralRangeTemplate<EditingInComposedTreeStrategy> range2(EphemeralRangeTemplate<EditingInComposedTreeStrategy>::rangeOfContents(*host)); TextIteratorAlgorithm<EditingInComposedTreeStrategy> iter2(range2.startPosition(), range2.endPosition()); Vector<UChar> output2; - iter2.appendTextTo(output2, 0, 3); + iter2.copyTextTo(output2, 0, 3); EXPECT_EQ("thr", String(output2)) << String::format(message, 2, "thr").utf8().data(); - iter2.appendTextTo(output2, 3, 3); + iter2.copyTextTo(output2, 3, 3); EXPECT_EQ("three ", String(output2)) << String::format(message, 2, "three ").utf8().data(); iter2.advance(); - iter2.appendTextTo(output2, 0, 2); + iter2.copyTextTo(output2, 0, 2); EXPECT_EQ("three tw", String(output2)) << String::format(message, 2, "three tw").utf8().data(); - iter2.appendTextTo(output2, 2, 1); + iter2.copyTextTo(output2, 2, 1); EXPECT_EQ("three two", String(output2)) << String::format(message, 2, "three two").utf8().data(); iter2.advance(); - iter2.appendTextTo(output2, 0, 1); + iter2.copyTextTo(output2, 0, 1); EXPECT_EQ("three two ", String(output2)) << String::format(message, 2, "three two ").utf8().data(); iter2.advance(); - iter2.appendTextTo(output2, 0, 1); + iter2.copyTextTo(output2, 0, 1); EXPECT_EQ("three two o", String(output2)) << String::format(message, 2, "three two o").utf8().data(); - iter2.appendTextTo(output2, 1, 2); + iter2.copyTextTo(output2, 1, 2); EXPECT_EQ("three two one", String(output2)) << String::format(message, 2, "three two one").utf8().data(); iter2.advance(); - iter2.appendTextTo(output2, 0, 2); + iter2.copyTextTo(output2, 0, 2); EXPECT_EQ("three two one z", String(output2)) << String::format(message, 2, "three two one z").utf8().data(); - iter2.appendTextTo(output2, 2, 3); + iter2.copyTextTo(output2, 2, 3); EXPECT_EQ("three two one zero", String(output2)) << String::format(message, 2, "three two one zero").utf8().data(); }
diff --git a/third_party/WebKit/Source/core/editing/iterators/WordAwareIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/WordAwareIterator.cpp index 7b8dc947..0efac79 100644 --- a/third_party/WebKit/Source/core/editing/iterators/WordAwareIterator.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/WordAwareIterator.cpp
@@ -66,7 +66,7 @@ // If this is the first chunk that failed, save it in m_buffer before look ahead. if (m_buffer.isEmpty()) - m_textIterator.appendTextTo(m_buffer); + m_textIterator.copyTextTo(m_buffer); // Look ahead to next chunk. If it is whitespace or a break, we can use the previous stuff m_textIterator.advance(); @@ -76,7 +76,7 @@ } // Start gobbling chunks until we get to a suitable stopping point - m_textIterator.appendTextTo(m_buffer); + m_textIterator.copyTextTo(m_buffer); } }
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp index eca2f18..900be28 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -775,15 +775,15 @@ spellChecker().removeSpellingMarkersUnderWords(words); } -static ScrollResult scrollAreaOnBothAxes(const FloatSize& delta, ScrollableArea& view) +static ScrollResult scrollAreaOnBothAxes(ScrollGranularity granularity, const FloatSize& delta, ScrollableArea& view) { - ScrollResultOneDimensional scrolledHorizontal = view.userScroll(ScrollLeft, ScrollByPrecisePixel, delta.width()); - ScrollResultOneDimensional scrolledVertical = view.userScroll(ScrollUp, ScrollByPrecisePixel, delta.height()); + ScrollResultOneDimensional scrolledHorizontal = view.userScroll(ScrollLeft, granularity, delta.width()); + ScrollResultOneDimensional scrolledVertical = view.userScroll(ScrollUp, granularity, delta.height()); return ScrollResult(scrolledHorizontal.didScroll, scrolledVertical.didScroll, scrolledHorizontal.unusedScrollDelta, scrolledVertical.unusedScrollDelta); } // Returns true if a scroll occurred. -ScrollResult LocalFrame::applyScrollDelta(const FloatSize& delta, bool isScrollBegin) +ScrollResult LocalFrame::applyScrollDelta(ScrollGranularity granularity, const FloatSize& delta, bool isScrollBegin) { if (isScrollBegin) host()->topControls().scrollBegin(); @@ -800,7 +800,7 @@ if (remainingDelta.isZero()) return ScrollResult(delta.width(), delta.height(), 0.0f, 0.0f); - ScrollResult result = scrollAreaOnBothAxes(remainingDelta, *view()->scrollableArea()); + ScrollResult result = scrollAreaOnBothAxes(granularity, remainingDelta, *view()->scrollableArea()); result.didScrollX = result.didScrollX || (remainingDelta.width() != delta.width()); result.didScrollY = result.didScrollY || (remainingDelta.height() != delta.height());
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.h b/third_party/WebKit/Source/core/frame/LocalFrame.h index a78868e..27b5471 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.h +++ b/third_party/WebKit/Source/core/frame/LocalFrame.h
@@ -171,7 +171,7 @@ // FIXME: once scroll customization is enabled everywhere // (crbug.com/416862), this should take a ScrollState object. - ScrollResult applyScrollDelta(const FloatSize& delta, bool isScrollBegin); + ScrollResult applyScrollDelta(ScrollGranularity, const FloatSize& delta, bool isScrollBegin); bool shouldScrollTopControls(const FloatSize& delta) const; // DisplayItemClient methods
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp index 47861ee8..038faa3 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.cpp +++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -2505,7 +2505,11 @@ if (delta.isZero()) return WebInputEventResult::NotHandled; + ScrollGranularity granularity = gestureEvent.deltaUnits(); Node* node = m_scrollGestureHandlingNode.get(); + + // Scroll customization is only available for touch. + bool handleScrollCustomization = RuntimeEnabledFeatures::scrollCustomizationEnabled() && gestureEvent.source() == PlatformGestureSourceTouchscreen; if (node) { LayoutObject* layoutObject = node->layoutObject(); if (!layoutObject) @@ -2531,7 +2535,7 @@ } bool scrolled = false; - if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) { + if (handleScrollCustomization) { RefPtrWillBeRawPtr<ScrollState> scrollState = ScrollState::create( gestureEvent.deltaX(), gestureEvent.deltaY(), 0, gestureEvent.velocityX(), gestureEvent.velocityY(), @@ -2556,7 +2560,6 @@ stopNode = m_previousGestureScrolledNode.get(); // First try to scroll the closest scrollable LayoutBox ancestor of |node|. - ScrollGranularity granularity = ScrollByPrecisePixel; ScrollResultOneDimensional result = scroll(ScrollLeftIgnoringWritingMode, granularity, node, &stopNode, delta.width()); bool horizontalScroll = result.didScroll; if (!gestureEvent.preventPropagation()) @@ -2576,11 +2579,11 @@ } } - if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) + if (handleScrollCustomization) return WebInputEventResult::NotHandled; // Try to scroll the frame view. - ScrollResult scrollResult = m_frame->applyScrollDelta(delta, false); + ScrollResult scrollResult = m_frame->applyScrollDelta(granularity, delta, false); FloatPoint position = FloatPoint(gestureEvent.position().x(), gestureEvent.position().y()); FloatSize velocity = FloatSize(gestureEvent.velocityX(), gestureEvent.velocityY()); handleOverscroll(scrollResult, position, velocity);
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp index 72377a66..934c729 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -1996,7 +1996,7 @@ // When a portion of the layout tree is being detached, anonymous blocks // will be combined as their children are deleted. In this process, the - // anonymous block later in the tree is merged into the one preceeding it. + // anonymous block later in the tree is merged into the one preceding it. // It can happen that the later block (this) contains floats that the // previous block (toBlockFlow) did not contain, and thus are not in the // floating objects list for toBlockFlow. This can result in toBlockFlow containing
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp index a1b50a2..973526c3 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
@@ -1406,7 +1406,7 @@ hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth, childMin, childMax, stripFrontSpaces, styleToUse.direction()); - // This text object will not be layed out, but it may still provide a breaking opportunity. + // This text object will not be laid out, but it may still provide a breaking opportunity. if (!hasBreak && !childMax) { if (autoWrap && (hasBreakableStart || hasBreakableEnd)) { minLogicalWidth = std::max(minLogicalWidth, inlineMin); @@ -1532,8 +1532,8 @@ // Text truncation kicks in in two cases: // 1) If your overflow isn't visible and your text-overflow-mode isn't clip. // 2) If you're an anonymous block with a block parent that satisfies #1 that was created - // to accomodate a block that has inline and block children. This excludes parents where - // canCollapseAnonymousBlockChild is false, notabley flex items and grid items. + // to accommodate a block that has inline and block children. This excludes parents where + // canCollapseAnonymousBlockChild is false, notably flex items and grid items. // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely // difficult to figure out in general (especially in the middle of doing layout), so we only handle the // simple case of an anonymous block truncating when it's parent is clipped. @@ -1912,7 +1912,7 @@ if (curr->hasEllipsisBox()) { curr->clearTruncation(); - // Shift the line back where it belongs if we cannot accomodate an ellipsis. + // Shift the line back where it belongs if we cannot accommodate an ellipsis. LayoutUnit logicalLeft = logicalLeftOffsetForLine(curr->lineTop(), indentText); LayoutUnit availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), DoNotIndentText) - logicalLeft; LayoutUnit totalLogicalWidth = curr->logicalWidth();
diff --git a/third_party/WebKit/Source/core/layout/LayoutCounter.cpp b/third_party/WebKit/Source/core/layout/LayoutCounter.cpp index 50635b1b..14a2c72 100644 --- a/third_party/WebKit/Source/core/layout/LayoutCounter.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutCounter.cpp
@@ -184,7 +184,7 @@ // check this layoutObject, because it may affect the positioning in the tree of our counter. LayoutObject* searchEndLayoutObject = previousSiblingOrParent(counterOwner); // We check layoutObjects in preOrder from the layoutObject that our counter is attached to - // towards the begining of the document for counters with the same identifier as the one + // towards the beginning of the document for counters with the same identifier as the one // we are trying to find a place for. This is the next layoutObject to be checked. LayoutObject* currentLayoutObject = previousInPreOrder(counterOwner); previousSibling = nullptr; @@ -283,7 +283,7 @@ } // This function is designed so that the same test is not done twice in an iteration, except for this one // which may be done twice in some cases. Rearranging the decision points though, to accommodate this - // performance improvement would create more code duplication than is worthwhile in my oppinion and may further + // performance improvement would create more code duplication than is worthwhile in my opinion and may further // impede the readability of this already complex algorithm. if (previousSiblingProtector) currentLayoutObject = previousSiblingOrParent(*currentLayoutObject);
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp index 390a4410..d2c58ba6 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -1896,7 +1896,7 @@ case GridAxisCenter: { size_t childEndLine = rowsSpan.resolvedFinalPosition(); LayoutUnit endOfRow = m_rowPositions[childEndLine]; - // m_rowPositions include gutters so we need to substract them to get the actual end position for a given + // m_rowPositions include gutters so we need to subtract them to get the actual end position for a given // row (this does not have to be done for the last track as there are no more m_rowPositions after it) if (childEndLine < m_rowPositions.size() - 1) endOfRow -= guttersSize(ForRows, 2); @@ -1928,7 +1928,7 @@ case GridAxisCenter: { size_t childEndLine = columnsSpan.resolvedFinalPosition(); LayoutUnit endOfColumn = m_columnPositions[childEndLine]; - // m_columnPositions include gutters so we need to substract them to get the actual end position for a given + // m_columnPositions include gutters so we need to subtract them to get the actual end position for a given // column (this does not have to be done for the last track as there are no more m_columnPositions after it) if (childEndLine < m_columnPositions.size() - 1) endOfColumn -= guttersSize(ForRows, 2);
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp index 505b5a3..553056e5 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -364,7 +364,7 @@ // - layerTypeRequired() would return true for the <body>, creating a new Layer // - when the document is painted, both layers are painted. The <body> layer doesn't // know that it's inside a "hidden SVG subtree", and thus paints, even if it shouldn't. - // To avoid the problem alltogether, detect early if we're inside a hidden SVG subtree + // To avoid the problem altogether, detect early if we're inside a hidden SVG subtree // and stop creating layers at all for these cases - they're not used anyways. if (newChild->hasLayer() && !layerCreationAllowedForSubtree()) toLayoutBoxModelObject(newChild)->layer()->removeOnlyThisLayer();
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp index ee603278..4d8f741c 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
@@ -297,7 +297,7 @@ } // Ensure we aren't smaller than our min preferred width. This MUST be done after 'max-width' as - // we ignore it if it means we wouldn't accomodate our content. + // we ignore it if it means we wouldn't accommodate our content. setLogicalWidth(std::max<int>(logicalWidth(), minPreferredLogicalWidth())); // Ensure we aren't smaller than our min-width style. @@ -313,7 +313,7 @@ setMarginStart(marginValues.m_start); setMarginEnd(marginValues.m_end); - // We should NEVER shrink the table below the min-content logical width, or else the table can't accomodate + // We should NEVER shrink the table below the min-content logical width, or else the table can't accommodate // its own content which doesn't match CSS nor what authors expect. // FIXME: When we convert to sub-pixel layout for tables we can remove the int conversion // https://code.google.com/p/chromium/issues/detail?id=241198
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp index 886eac9..e429394 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp +++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
@@ -999,12 +999,11 @@ prev = curr->prevOnLine(); // Layers will handle hit testing themselves. - if (curr->boxModelObject() && curr->boxModelObject().hasSelfPaintingLayer()) - continue; - - if (curr->nodeAtPoint(result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) { - lineLayoutItem().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); - return true; + if (!curr->boxModelObject() || !curr->boxModelObject().hasSelfPaintingLayer()) { + if (curr->nodeAtPoint(result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) { + lineLayoutItem().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); + return true; + } } // If the current inline box's layout object and the previous inline box's layout object are same, @@ -1012,8 +1011,7 @@ if (prev && curr->lineLayoutItem() == prev->lineLayoutItem()) continue; - // If a parent of the current inline box is a culled inline, - // we hit test it before we move the previous inline box. + // Hit test the culled inline if necessary. LineLayoutItem currLayoutItem = curr->lineLayoutItem(); while (true) { // If the previous inline box is not a descendant of a current inline's parent,
diff --git a/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp b/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp index a60533c3..c51b3d2 100644 --- a/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp +++ b/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp
@@ -300,7 +300,7 @@ } // When dealing with bidi text, a non-contiguous selection region is possible. - // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out + // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is laid out // visually as 3 text runs |aaa|bbb|AAA| if we select 4 characters from the start of the text the // selection will look like (underline denotes selection): // |aaa|bbb|AAA|
diff --git a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp index 1f2ea90..ddba2fb 100644 --- a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp +++ b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.cpp
@@ -69,7 +69,7 @@ } #endif -PassRefPtrWillBeRawPtr<Filter> ReferenceFilterBuilder::build(float zoom, Element* element, FilterEffect* previousEffect, const ReferenceFilterOperation& filterOperation, const SkPaint* fillPaint, const SkPaint* strokePaint) +PassRefPtrWillBeRawPtr<Filter> ReferenceFilterBuilder::build(float zoom, Element* element, FilterEffect* previousEffect, const ReferenceFilterOperation& filterOperation, const FloatSize* referenceBoxSize, const SkPaint* fillPaint, const SkPaint* strokePaint) { TreeScope* treeScope = &element->treeScope(); @@ -101,8 +101,12 @@ FloatRect referenceBox; if (element->inDocument() && element->layoutObject() && element->layoutObject()->enclosingLayer()) { - FloatSize size(element->layoutObject()->enclosingLayer()->physicalBoundingBoxIncludingReflectionAndStackingChildren(LayoutPoint()).size()); - referenceBox = FloatRect(FloatPoint(), size); + if (referenceBoxSize) { + referenceBox = FloatRect(FloatPoint(), *referenceBoxSize); + } else { + FloatSize size(element->layoutObject()->enclosingLayer()->physicalBoundingBoxIncludingReflectionAndStackingChildren(LayoutPoint()).size()); + referenceBox = FloatRect(FloatPoint(), size); + } } referenceBox.scale(1.0f / zoom); FloatRect filterRegion = SVGLengthContext::resolveRectangle<SVGFilterElement>(&filterElement, filterElement.filterUnits()->currentValue()->enumValue(), referenceBox);
diff --git a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.h b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.h index 521e7fa..8212c0d 100644 --- a/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.h +++ b/third_party/WebKit/Source/core/layout/svg/ReferenceFilterBuilder.h
@@ -44,6 +44,7 @@ class Filter; class FilterEffect; class FilterOperation; +class FloatSize; class ReferenceFilterOperation; class ReferenceFilterBuilder { @@ -55,7 +56,7 @@ static void clearDocumentResourceReference(const FilterOperation*); #endif - static PassRefPtrWillBeRawPtr<Filter> build(float zoom, Element*, FilterEffect* previousEffect, const ReferenceFilterOperation&, const SkPaint* fillPaint = nullptr, const SkPaint* strokePaint = nullptr); + static PassRefPtrWillBeRawPtr<Filter> build(float zoom, Element*, FilterEffect* previousEffect, const ReferenceFilterOperation&, const FloatSize* referenceBoxSize = nullptr, const SkPaint* fillPaint = nullptr, const SkPaint* strokePaint = nullptr); }; }
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp index 3903651d..ccfd74e 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -344,7 +344,7 @@ if (!platformSupportsCoordinatedScrollbar) { if (scrollbarGraphicsLayer) { WebLayer* scrollbarLayer = toWebLayer(scrollbarGraphicsLayer); - scrollbarLayer->setShouldScrollOnMainThread(true); + scrollbarLayer->addMainThreadScrollingReasons(WebMainThreadScrollingReason::ScrollBarScrolling); } return; } @@ -399,7 +399,7 @@ // to set the WebLayer's scroll position at fractional precision otherwise the // WebLayer's position after snapping to device pixel can be off with regard to // fixed position elements. - if (m_lastMainThreadScrollingReasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects) { + if (m_lastMainThreadScrollingReasons & WebMainThreadScrollingReason::HasNonLayerViewportConstrainedObjects) { webLayer->setScrollPositionDouble(DoublePoint(scrollableArea->scrollPosition() - scrollableArea->minimumScrollPosition())); } else { DoublePoint scrollPosition(scrollableArea->scrollPositionDouble() - scrollableArea->minimumScrollPositionDouble()); @@ -714,7 +714,10 @@ return; if (WebLayer* scrollLayer = toWebLayer(m_page->deprecatedLocalMainFrame()->view()->layerForScrolling())) { m_lastMainThreadScrollingReasons = reasons; - scrollLayer->setShouldScrollOnMainThread(reasons); + if (reasons) + scrollLayer->addMainThreadScrollingReasons(static_cast<WebMainThreadScrollingReason::WebMainThreadScrollingReason>(reasons)); + else + scrollLayer->clearMainThreadScrollingReasons(); } } @@ -1023,7 +1026,7 @@ MainThreadScrollingReasons reasons = static_cast<MainThreadScrollingReasons>(0); if (!m_page->settings().threadedScrollingEnabled()) - reasons |= ThreadedScrollingDisabled; + reasons |= WebMainThreadScrollingReason::ThreadedScrollingDisabled; if (!m_page->mainFrame()->isLocalFrame()) return reasons; @@ -1032,7 +1035,7 @@ return reasons; if (frameView->hasBackgroundAttachmentFixedObjects()) - reasons |= HasBackgroundAttachmentFixedObjects; + reasons |= WebMainThreadScrollingReason::HasBackgroundAttachmentFixedObjects; FrameView::ScrollingReasons scrollingReasons = frameView->scrollingReasons(); const bool mayBeScrolledByInput = (scrollingReasons == FrameView::Scrollable); const bool mayBeScrolledByScript = mayBeScrolledByInput || (scrollingReasons == @@ -1043,7 +1046,7 @@ // not let this move there path as an optimization, when we have slow-repaint // elements. if (mayBeScrolledByScript && hasVisibleSlowRepaintViewportConstrainedObjects(frameView)) { - reasons |= HasNonLayerViewportConstrainedObjects; + reasons |= WebMainThreadScrollingReason::HasNonLayerViewportConstrainedObjects; } return reasons; @@ -1053,11 +1056,11 @@ { StringBuilder stringBuilder; - if (reasons & ScrollingCoordinator::HasBackgroundAttachmentFixedObjects) + if (reasons & WebMainThreadScrollingReason::HasBackgroundAttachmentFixedObjects) stringBuilder.appendLiteral("Has background-attachment:fixed, "); - if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects) + if (reasons & WebMainThreadScrollingReason::HasNonLayerViewportConstrainedObjects) stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, "); - if (reasons & ScrollingCoordinator::ThreadedScrollingDisabled) + if (reasons & WebMainThreadScrollingReason::ThreadedScrollingDisabled) stringBuilder.appendLiteral("Threaded scrolling is disabled, "); if (stringBuilder.length())
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h index 2b55d1f..fd48d40 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
@@ -31,6 +31,7 @@ #include "platform/PlatformWheelEvent.h" #include "platform/geometry/IntRect.h" #include "platform/scroll/ScrollTypes.h" +#include "public/platform/WebMainThreadScrollingReason.h" #include "wtf/Noncopyable.h" #include "wtf/text/WTFString.h" @@ -95,12 +96,6 @@ void handleWheelEventPhase(PlatformWheelEventPhase); #endif - enum MainThreadScrollingReasonFlags { - HasBackgroundAttachmentFixedObjects = 1 << 0, - HasNonLayerViewportConstrainedObjects = 1 << 1, - ThreadedScrollingDisabled = 1 << 2 - }; - MainThreadScrollingReasons mainThreadScrollingReasons() const; bool shouldUpdateScrollLayerPositionOnMainThread() const { return mainThreadScrollingReasons() != 0; }
diff --git a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp index faabeec4..f183593 100644 --- a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp +++ b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.cpp
@@ -130,7 +130,7 @@ visitor->trace(m_referenceFilters); } -bool FilterEffectBuilder::build(Element* element, const FilterOperations& operations, float zoom, const SkPaint* fillPaint, const SkPaint* strokePaint) +bool FilterEffectBuilder::build(Element* element, const FilterOperations& operations, float zoom, const FloatSize* referenceBoxSize, const SkPaint* fillPaint, const SkPaint* strokePaint) { // Create a parent filter for shorthand filters. These have already been scaled by the CSS code for page zoom, so scale is 1.0 here. RefPtrWillBeRawPtr<Filter> parentFilter = Filter::create(1.0f); @@ -140,7 +140,7 @@ FilterOperation* filterOperation = operations.operations().at(i).get(); switch (filterOperation->type()) { case FilterOperation::REFERENCE: { - RefPtrWillBeRawPtr<Filter> referenceFilter = ReferenceFilterBuilder::build(zoom, element, previousEffect.get(), toReferenceFilterOperation(*filterOperation), fillPaint, strokePaint); + RefPtrWillBeRawPtr<Filter> referenceFilter = ReferenceFilterBuilder::build(zoom, element, previousEffect.get(), toReferenceFilterOperation(*filterOperation), referenceBoxSize, fillPaint, strokePaint); if (referenceFilter) { effect = referenceFilter->lastEffect(); m_referenceFilters.append(referenceFilter);
diff --git a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.h b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.h index 6e8da7b9..9022ddf 100644 --- a/third_party/WebKit/Source/core/paint/FilterEffectBuilder.h +++ b/third_party/WebKit/Source/core/paint/FilterEffectBuilder.h
@@ -53,7 +53,7 @@ virtual ~FilterEffectBuilder(); DECLARE_TRACE(); - bool build(Element*, const FilterOperations&, float zoom, const SkPaint* fillPaint = nullptr, const SkPaint* strokePaint = nullptr); + bool build(Element*, const FilterOperations&, float zoom, const FloatSize* referenceBoxSize = nullptr, const SkPaint* fillPaint = nullptr, const SkPaint* strokePaint = nullptr); PassRefPtrWillBeRawPtr<FilterEffect> lastEffect() const {
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp index 8cf6c194..c2b01b6 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -828,7 +828,7 @@ template<typename DrawFunc> void CanvasRenderingContext2D::compositedDraw(const DrawFunc& drawFunc, SkCanvas* c, CanvasRenderingContext2DState::PaintType paintType, CanvasRenderingContext2DState::ImageType imageType) { - SkImageFilter* filter = state().getFilter(canvas(), accessFont()); + SkImageFilter* filter = state().getFilter(canvas(), accessFont(), canvas()->size()); ASSERT(isFullCanvasCompositeMode(state().globalComposite()) || filter); SkMatrix ctm = c->getTotalMatrix(); c->resetMatrix();
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp index 71f1564c..09b50bd5 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.cpp
@@ -341,7 +341,7 @@ m_isTransformInvertible = true; } -SkImageFilter* CanvasRenderingContext2DState::getFilter(Element* styleResolutionHost, const Font& font) const +SkImageFilter* CanvasRenderingContext2DState::getFilter(Element* styleResolutionHost, const Font& font, IntSize canvasSize) const { if (!m_filterValue) return nullptr; @@ -365,8 +365,9 @@ m_strokeStyle->applyToPaint(strokePaintForFilter); fillPaintForFilter.setColor(m_fillStyle->paintColor()); strokePaintForFilter.setColor(m_strokeStyle->paintColor()); + FloatSize floatCanvasSize(canvasSize); const double effectiveZoom = 1.0; // Deliberately ignore zoom on the canvas element - filterEffectBuilder->build(styleResolutionHost, filterStyle->filter(), effectiveZoom, &fillPaintForFilter, &strokePaintForFilter); + filterEffectBuilder->build(styleResolutionHost, filterStyle->filter(), effectiveZoom, &floatCanvasSize, &fillPaintForFilter, &strokePaintForFilter); SkiaImageFilterBuilder imageFilterBuilder; RefPtrWillBeRawPtr<FilterEffect> lastEffect = filterEffectBuilder->lastEffect();
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.h b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.h index 326700a..df13ac9 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.h +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DState.h
@@ -84,7 +84,7 @@ void setFilter(PassRefPtrWillBeRawPtr<CSSValue>); void setUnparsedFilter(const String& filterString) { m_unparsedFilter = filterString; } const String& unparsedFilter() const { return m_unparsedFilter; } - SkImageFilter* getFilter(Element*, const Font&) const; + SkImageFilter* getFilter(Element*, const Font&, IntSize canvasSize) const; bool hasFilter() const { return m_filterValue; } void setStrokeStyle(CanvasStyle*);
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp index 7ece4b9..785e1e5 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp
@@ -30,6 +30,11 @@ return m_request; } +String FetchEvent::clientId() const +{ + return m_clientId; +} + bool FetchEvent::isReload() const { return m_isReload; @@ -57,6 +62,7 @@ { if (initializer.hasRequest()) m_request = initializer.request(); + m_clientId = initializer.clientId(); m_isReload = initializer.isReload(); }
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h index 1b4d19a..793c5cd 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h +++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h
@@ -31,6 +31,7 @@ static PassRefPtrWillBeRawPtr<FetchEvent> create(const AtomicString& type, const FetchEventInit&, RespondWithObserver*); Request* request() const; + String clientId() const; bool isReload() const; void respondWith(ScriptState*, ScriptPromise, ExceptionState&); @@ -46,6 +47,7 @@ private: PersistentWillBeMember<RespondWithObserver> m_observer; PersistentWillBeMember<Request> m_request; + String m_clientId; bool m_isReload; };
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.idl b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.idl index 817554a..e8f4551d 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.idl +++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.idl
@@ -4,10 +4,11 @@ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#fetch-event-interface [ - Constructor(DOMString type, optional FetchEventInit eventInitDict), + Constructor(DOMString type, FetchEventInit eventInitDict), Exposed=ServiceWorker, ] interface FetchEvent : ExtendableEvent { - readonly attribute Request request; + [SameObject] readonly attribute Request request; + readonly attribute DOMString? clientId; readonly attribute boolean isReload; [CallWith=ScriptState, RaisesException] void respondWith(Promise<Response> r);
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEventInit.idl b/third_party/WebKit/Source/modules/serviceworkers/FetchEventInit.idl index cac8bbeb..80da60fd 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/FetchEventInit.idl +++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEventInit.idl
@@ -5,6 +5,7 @@ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#fetch-event-interface dictionary FetchEventInit : ExtendableEventInit { - Request request; - boolean isReload = false; + required Request request; + DOMString? clientId = null; + boolean isReload = false; };
diff --git a/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp b/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp index 524798b..48cfa5e 100644 --- a/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp +++ b/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
@@ -446,9 +446,17 @@ return; } Platform::current()->histogramEnumeration("WebCore.WebSocket.SendType", WebSocketSendTypeBlob, WebSocketSendTypeMax); - m_bufferedAmount += binaryData->size(); + unsigned long long size = binaryData->size(); + m_bufferedAmount += size; ASSERT(m_channel); - m_channel->send(binaryData->blobDataHandle()); + + // When the runtime type of |binaryData| is File, + // binaryData->blobDataHandle()->size() returns -1. However, in order to + // maintain the value of |m_bufferedAmount| correctly, the WebSocket code + // needs to fix the size of the File at this point. For this reason, + // construct a new BlobDataHandle here with the size that this method + // observed. + m_channel->send(BlobDataHandle::create(binaryData->uuid(), binaryData->type(), size)); } void DOMWebSocket::close(unsigned short code, const String& reason, ExceptionState& exceptionState)
diff --git a/third_party/WebKit/Source/platform/EventTracer.cpp b/third_party/WebKit/Source/platform/EventTracer.cpp index 30a8f11..08469ce 100644 --- a/third_party/WebKit/Source/platform/EventTracer.cpp +++ b/third_party/WebKit/Source/platform/EventTracer.cpp
@@ -31,17 +31,45 @@ #include "platform/EventTracer.h" #include "base/time/time.h" +#include "base/trace_event/trace_event.h" #include "public/platform/Platform.h" -#include "public/platform/WebConvertableToTraceFormat.h" #include "wtf/Assertions.h" +#include "wtf/text/StringUTF8Adaptor.h" #include <stdio.h> namespace blink { -static_assert(sizeof(Platform::TraceEventHandle) == sizeof(TraceEvent::TraceEventHandle), "TraceEventHandle types must be compatible"); -static_assert(sizeof(Platform::TraceEventAPIAtomicWord) == sizeof(TraceEvent::TraceEventAPIAtomicWord), "TraceEventAPIAtomicWord types must be compatible"); +static_assert(sizeof(TraceEvent::TraceEventHandle) == sizeof(base::trace_event::TraceEventHandle), "TraceEventHandle types must be the same"); static_assert(sizeof(TraceEvent::TraceEventAPIAtomicWord) == sizeof(const char*), "TraceEventAPIAtomicWord must be pointer-sized."); +namespace { + +class ConvertableToTraceFormatWrapper : public base::trace_event::ConvertableToTraceFormat { +public: + // We move a reference pointer from |convertable| to |m_convertable|, + // rather than copying, for thread safety. https://crbug.com/478149 + explicit ConvertableToTraceFormatWrapper(PassRefPtr<blink::TraceEvent::ConvertableToTraceFormat> convertable) + : m_convertable(convertable) + { + ASSERT(m_convertable); + } + void AppendAsTraceFormat(std::string* out) const override + { + // TODO(bashi): Avoid copying. + String traceFormat = m_convertable->asTraceFormat(); + StringUTF8Adaptor utf8(traceFormat); + out->append(utf8.data(), utf8.length()); + } + // TODO(bashi): Override EstimateTraceMemoryOverhead() + +private: + ~ConvertableToTraceFormatWrapper() override {} + + RefPtr<blink::TraceEvent::ConvertableToTraceFormat> m_convertable; +}; + +} // namespace + // The dummy variable is needed to avoid a crash when someone updates the state variables // before EventTracer::initialize() is called. TraceEvent::TraceEventAPIAtomicWord dummyTraceSamplingState = 0; @@ -49,30 +77,21 @@ void EventTracer::initialize() { - // current() might not exist in unit tests. - if (!Platform::current()) - return; - - traceSamplingState[0] = Platform::current()->getTraceSamplingState(0); + traceSamplingState[0] = reinterpret_cast<TraceEvent::TraceEventAPIAtomicWord*>(&TRACE_EVENT_API_THREAD_BUCKET(0)); // FIXME: traceSamplingState[0] can be 0 in split-dll build. http://crbug.com/256965 if (!traceSamplingState[0]) traceSamplingState[0] = &dummyTraceSamplingState; - traceSamplingState[1] = Platform::current()->getTraceSamplingState(1); + traceSamplingState[1] = reinterpret_cast<TraceEvent::TraceEventAPIAtomicWord*>(&TRACE_EVENT_API_THREAD_BUCKET(1)); if (!traceSamplingState[1]) traceSamplingState[1] = &dummyTraceSamplingState; - traceSamplingState[2] = Platform::current()->getTraceSamplingState(2); + traceSamplingState[2] = reinterpret_cast<TraceEvent::TraceEventAPIAtomicWord*>(&TRACE_EVENT_API_THREAD_BUCKET(2)); if (!traceSamplingState[2]) traceSamplingState[2] = &dummyTraceSamplingState; } const unsigned char* EventTracer::getTraceCategoryEnabledFlag(const char* categoryName) { - static const char* dummyCategoryEnabledFlag = "*"; - // current() might not exist in unit tests. - if (!Platform::current()) - return reinterpret_cast<const unsigned char*>(dummyCategoryEnabledFlag); - - return Platform::current()->getTraceCategoryEnabledFlag(categoryName); + return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(categoryName); } TraceEvent::TraceEventHandle EventTracer::addTraceEvent(char phase, const unsigned char* categoryEnabledFlag, @@ -83,10 +102,13 @@ PassRefPtr<TraceEvent::ConvertableToTraceFormat> convertableValue2, unsigned flags) { - WebConvertableToTraceFormat webConvertableValues[2]; - webConvertableValues[0] = WebConvertableToTraceFormat(convertableValue1); - webConvertableValues[1] = WebConvertableToTraceFormat(convertableValue2); - return Platform::current()->addTraceEvent(phase, categoryEnabledFlag, name, id, bindId, timestamp, numArgs, argNames, argTypes, argValues, webConvertableValues, flags); + scoped_refptr<base::trace_event::ConvertableToTraceFormat> wrappers[2]; + ASSERT(numArgs <= 2); + if (numArgs >= 1 && argTypes[0] == TRACE_VALUE_TYPE_CONVERTABLE) + wrappers[0] = new ConvertableToTraceFormatWrapper(convertableValue1); + if (numArgs >= 2 && argTypes[1] == TRACE_VALUE_TYPE_CONVERTABLE) + wrappers[1] = new ConvertableToTraceFormatWrapper(convertableValue2); + return addTraceEvent(phase, categoryEnabledFlag, name, id, bindId, timestamp, numArgs, argNames, argTypes, argValues, wrappers, flags); } TraceEvent::TraceEventHandle EventTracer::addTraceEvent(char phase, const unsigned char* categoryEnabledFlag, @@ -94,12 +116,26 @@ int numArgs, const char** argNames, const unsigned char* argTypes, const unsigned long long* argValues, unsigned flags) { - return Platform::current()->addTraceEvent(phase, categoryEnabledFlag, name, id, bindId, timestamp, numArgs, argNames, argTypes, argValues, 0, flags); + return addTraceEvent(phase, categoryEnabledFlag, name, id, bindId, timestamp, numArgs, argNames, argTypes, argValues, nullptr, flags); +} + +TraceEvent::TraceEventHandle EventTracer::addTraceEvent(char phase, const unsigned char* categoryEnabledFlag, + const char* name, unsigned long long id, unsigned long long bindId, double timestamp, + int numArgs, const char** argNames, const unsigned char* argTypes, const unsigned long long* argValues, + const scoped_refptr<base::trace_event::ConvertableToTraceFormat>* convertables, unsigned flags) +{ + base::TimeTicks timestampTimeTicks = base::TimeTicks() + base::TimeDelta::FromSecondsD(timestamp); + base::trace_event::TraceEventHandle handle = TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(phase, categoryEnabledFlag, name, id, bindId, base::PlatformThread::CurrentId(), timestampTimeTicks, numArgs, argNames, argTypes, argValues, convertables, flags); + TraceEvent::TraceEventHandle result; + memcpy(&result, &handle, sizeof(result)); + return result; } void EventTracer::updateTraceEventDuration(const unsigned char* categoryEnabledFlag, const char* name, TraceEvent::TraceEventHandle handle) { - Platform::current()->updateTraceEventDuration(categoryEnabledFlag, name, handle); + base::trace_event::TraceEventHandle traceEventHandle; + memcpy(&traceEventHandle, &handle, sizeof(handle)); + TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(categoryEnabledFlag, name, traceEventHandle); } double EventTracer::systemTraceTime()
diff --git a/third_party/WebKit/Source/platform/EventTracer.h b/third_party/WebKit/Source/platform/EventTracer.h index e6d4b4b2..4b5ec04b 100644 --- a/third_party/WebKit/Source/platform/EventTracer.h +++ b/third_party/WebKit/Source/platform/EventTracer.h
@@ -31,6 +31,7 @@ #ifndef EventTracer_h #define EventTracer_h +#include "base/memory/ref_counted.h" #include "platform/PlatformExport.h" #include "wtf/Allocator.h" #include "wtf/RefCounted.h" @@ -39,6 +40,12 @@ #include <stdint.h> +namespace base { +namespace trace_event { +class ConvertableToTraceFormat; +} +} + // This will mark the trace event as disabled by default. The user will need // to explicitly enable the event. #define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name @@ -91,6 +98,20 @@ unsigned flags); static void updateTraceEventDuration(const unsigned char* categoryEnabledFlag, const char* name, TraceEvent::TraceEventHandle); static double systemTraceTime(); + +private: + static TraceEvent::TraceEventHandle addTraceEvent(char phase, + const unsigned char* categoryEnabledFlag, + const char* name, + unsigned long long id, + unsigned long long bindId, + double timestamp, + int numArgs, + const char* argNames[], + const unsigned char argTypes[], + const unsigned long long argValues[], + const scoped_refptr<base::trace_event::ConvertableToTraceFormat>* convertables, + unsigned flags); }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/PlatformGestureEvent.h b/third_party/WebKit/Source/platform/PlatformGestureEvent.h index 57d5ef7b..a9a1072 100644 --- a/third_party/WebKit/Source/platform/PlatformGestureEvent.h +++ b/third_party/WebKit/Source/platform/PlatformGestureEvent.h
@@ -30,6 +30,7 @@ #include "platform/geometry/FloatPoint.h" #include "platform/geometry/IntPoint.h" #include "platform/geometry/IntSize.h" +#include "platform/scroll/ScrollTypes.h" #include "wtf/Assertions.h" #include <string.h> @@ -62,7 +63,7 @@ memset(&m_data, 0, sizeof(m_data)); } - void setScrollGestureData(float deltaX, float deltaY, float velocityX, float velocityY, + void setScrollGestureData(float deltaX, float deltaY, ScrollGranularity deltaUnits, float velocityX, float velocityY, bool inertial, bool preventPropagation, int resendingPluginId) { ASSERT(type() == PlatformEvent::GestureScrollBegin @@ -81,6 +82,7 @@ m_data.m_scroll.m_deltaX = deltaX; m_data.m_scroll.m_deltaY = deltaY; + m_data.m_scroll.m_deltaUnits = deltaUnits; m_data.m_scroll.m_velocityX = velocityX; m_data.m_scroll.m_velocityY = velocityY; m_data.m_scroll.m_inertial = inertial; @@ -107,6 +109,12 @@ return m_data.m_scroll.m_deltaY; } + ScrollGranularity deltaUnits() const + { + ASSERT(m_type == PlatformEvent::GestureScrollUpdate); + return m_data.m_scroll.m_deltaUnits; + } + int tapCount() const { ASSERT(m_type == PlatformEvent::GestureTap); @@ -212,6 +220,7 @@ float m_velocityY; int m_preventPropagation; bool m_inertial; + ScrollGranularity m_deltaUnits; int m_resendingPluginId; } m_scroll;
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi index 49ea34b..9dec2b0 100644 --- a/third_party/WebKit/Source/platform/blink_platform.gypi +++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -272,7 +272,6 @@ 'exported/WebContentDecryptionModuleResult.cpp', 'exported/WebContentDecryptionModuleSession.cpp', 'exported/WebContentSettingCallbacks.cpp', - 'exported/WebConvertableToTraceFormat.cpp', 'exported/WebCredential.cpp', 'exported/WebCryptoAlgorithm.cpp', 'exported/WebCryptoKey.cpp',
diff --git a/third_party/WebKit/Source/platform/exported/WebConvertableToTraceFormat.cpp b/third_party/WebKit/Source/platform/exported/WebConvertableToTraceFormat.cpp deleted file mode 100644 index dca9367..0000000 --- a/third_party/WebKit/Source/platform/exported/WebConvertableToTraceFormat.cpp +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "public/platform/WebConvertableToTraceFormat.h" - -#include "platform/EventTracer.h" -#include "public/platform/WebString.h" - -namespace blink { - -WebConvertableToTraceFormat::WebConvertableToTraceFormat(PassRefPtr<TraceEvent::ConvertableToTraceFormat> convertable) - : m_private(convertable) -{ -} - -WebString WebConvertableToTraceFormat::asTraceFormat() const -{ - return m_private->asTraceFormat(); -} - -void WebConvertableToTraceFormat::assign(const WebConvertableToTraceFormat& r) -{ - m_private = r.m_private; -} - -void WebConvertableToTraceFormat::moveFrom(WebConvertableToTraceFormat& r) -{ - m_private.moveFrom(r.m_private); -} - -void WebConvertableToTraceFormat::reset() -{ - m_private.reset(); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebServiceWorkerRequest.cpp b/third_party/WebKit/Source/platform/exported/WebServiceWorkerRequest.cpp index bc9c6ed9..95bce10b 100644 --- a/third_party/WebKit/Source/platform/exported/WebServiceWorkerRequest.cpp +++ b/third_party/WebKit/Source/platform/exported/WebServiceWorkerRequest.cpp
@@ -7,6 +7,7 @@ #include "platform/blob/BlobData.h" #include "platform/weborigin/KURL.h" #include "public/platform/WebHTTPHeaderVisitor.h" +#include "public/platform/WebString.h" #include "public/platform/WebURLRequest.h" namespace blink { @@ -15,10 +16,12 @@ public: WebServiceWorkerRequestPrivate() : m_mode(WebURLRequest::FetchRequestModeNoCORS) + , m_isMainResourceLoad(false) , m_credentialsMode(WebURLRequest::FetchCredentialsModeOmit) , m_redirectMode(WebURLRequest::FetchRedirectModeFollow) , m_requestContext(WebURLRequest::RequestContextUnspecified) , m_frameType(WebURLRequest::FrameTypeNone) + , m_clientId(WebString()) , m_isReload(false) { } @@ -28,10 +31,12 @@ RefPtr<BlobDataHandle> blobDataHandle; Referrer m_referrer; WebURLRequest::FetchRequestMode m_mode; + bool m_isMainResourceLoad; WebURLRequest::FetchCredentialsMode m_credentialsMode; WebURLRequest::FetchRedirectMode m_redirectMode; WebURLRequest::RequestContext m_requestContext; WebURLRequest::FrameType m_frameType; + WebString m_clientId; bool m_isReload; }; @@ -137,6 +142,16 @@ return m_private->m_mode; } +void WebServiceWorkerRequest::setIsMainResourceLoad(bool isMainResourceLoad) +{ + m_private->m_isMainResourceLoad = isMainResourceLoad; +} + +bool WebServiceWorkerRequest::isMainResourceLoad() const +{ + return m_private->m_isMainResourceLoad; +} + void WebServiceWorkerRequest::setCredentialsMode(WebURLRequest::FetchCredentialsMode credentialsMode) { m_private->m_credentialsMode = credentialsMode; @@ -177,6 +192,16 @@ return m_private->m_frameType; } +void WebServiceWorkerRequest::setClientId(const WebString& clientId) +{ + m_private->m_clientId = clientId; +} + +WebString WebServiceWorkerRequest::clientId() const +{ + return m_private->m_clientId; +} + void WebServiceWorkerRequest::setIsReload(bool isReload) { m_private->m_isReload = isReload;
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp index 4028270..17150794 100644 --- a/third_party/WebKit/Source/platform/fonts/Font.cpp +++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -409,14 +409,10 @@ CodePath Font::codePath(const TextRunPaintInfo& runInfo) const { -// TODO(eae): Disable the always use complex text feature on Android for now as -// it caused a memory regression for webview. crbug.com/577306 -#if !OS(ANDROID) if (RuntimeEnabledFeatures::alwaysUseComplexTextEnabled() || LayoutTestSupport::alwaysUseComplexTextForTest()) { return ComplexPath; } -#endif const TextRun& run = runInfo.run;
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp index a78ac79..eac07130 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -95,6 +95,21 @@ return list; } +static gfx::Transform transformToRoot(const TransformPaintPropertyNode* currentSpace) +{ + TransformationMatrix matrix; + while (currentSpace) { + TransformationMatrix localMatrix = currentSpace->matrix(); + localMatrix.applyTransformOrigin(currentSpace->origin()); + matrix = localMatrix * matrix; + currentSpace = currentSpace->parent(); + } + + gfx::Transform transform; + transform.matrix() = TransformationMatrix::toSkMatrix44(matrix); + return transform; +} + void PaintArtifactCompositor::update(const PaintArtifact& paintArtifact) { ASSERT(m_rootLayer); @@ -114,7 +129,7 @@ scoped_refptr<cc::PictureLayer> layer = cc::PictureLayer::Create(cc::LayerSettings(), contentLayerClient.get()); layer->SetPosition(gfx::PointF()); layer->SetBounds(combinedBounds.size()); - // TODO(jbroman): Layer transforms would be nice. + layer->SetTransform(transformToRoot(paintChunk.properties.transform.get())); layer->SetIsDrawable(true); layer->SetNeedsDisplay(); m_contentLayerClients.append(contentLayerClient.release());
diff --git a/third_party/WebKit/Source/platform/graphics/paint/README.md b/third_party/WebKit/Source/platform/graphics/paint/README.md index d886bcd..4b29640 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/README.md +++ b/third_party/WebKit/Source/platform/graphics/paint/README.md
@@ -154,7 +154,7 @@ them in SPv2. *** -## Display item list +## Paint controller Callers use `GraphicsContext` (via its drawing methods, and its `paintController()` accessor) and scoped recorder classes, which emit items into @@ -175,3 +175,16 @@ *** aside TODO(jbroman): Explain invalidation. *** + +## Paint artifact compositor + +The [`PaintArtifactCompositor`](PaintArtifactCompositor.h) is responsible for +consuming the `PaintArtifact` produced by the `PaintController`, and converting +it into a form suitable for the compositor to consume. + +At present, `PaintArtifactCompositor` creates a cc layer tree, with one layer +for each paint chunk. In the future, it is expected that we will use heuristics +to combine paint chunks into a smaller number of layers. + +The owner of the `PaintArtifactCompositor` (e.g. `WebView`) can then attach its +root layer to the overall layer hierarchy to be displayed to the user.
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp index 928e88c..94c2e7c 100644 --- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp +++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -89,12 +89,6 @@ return !m_config.hasDiscardableMemorySupport ? 0 : new TestingDiscardableMemory(bytes); } -const unsigned char* TestingPlatformSupport::getTraceCategoryEnabledFlag(const char* categoryName) -{ - static const unsigned char tracingIsDisabled = 0; - return &tracingIsDisabled; -} - WebString TestingPlatformSupport::defaultLocale() { return WebString::fromUTF8("en-US");
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h index 027ed1d..fcaec86 100644 --- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h +++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
@@ -114,7 +114,6 @@ // Platform: WebDiscardableMemory* allocateAndLockDiscardableMemory(size_t bytes) override; - const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName) override; WebString defaultLocale() override; WebCompositorSupport* compositorSupport() override; WebThread* currentThread() override;
diff --git a/third_party/WebKit/Source/web/PageOverlay.cpp b/third_party/WebKit/Source/web/PageOverlay.cpp index d5b15440..0bcd39e 100644 --- a/third_party/WebKit/Source/web/PageOverlay.cpp +++ b/third_party/WebKit/Source/web/PageOverlay.cpp
@@ -31,6 +31,7 @@ #include "core/frame/FrameHost.h" #include "core/frame/Settings.h" #include "core/page/Page.h" +#include "core/page/scrolling/ScrollingCoordinator.h" #include "platform/graphics/GraphicsContext.h" #include "platform/graphics/GraphicsLayer.h" #include "platform/graphics/GraphicsLayerClient.h" @@ -84,7 +85,7 @@ // This is required for contents of overlay to stay in sync with the page while scrolling. WebLayer* platformLayer = m_layer->platformLayer(); - platformLayer->setShouldScrollOnMainThread(true); + platformLayer->addMainThreadScrollingReasons(WebMainThreadScrollingReason::PageOverlay); page->frameHost().visualViewport().containerLayer()->addChild(m_layer.get()); }
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp index dd12697..53cfd75 100644 --- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp +++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
@@ -111,6 +111,7 @@ FetchEventInit eventInit; eventInit.setCancelable(true); eventInit.setRequest(request); + eventInit.setClientId(webRequest.isMainResourceLoad() ? WebString() : webRequest.clientId()); eventInit.setIsReload(webRequest.isReload()); RefPtrWillBeRawPtr<FetchEvent> fetchEvent(FetchEvent::create(EventTypeNames::fetch, eventInit, observer)); defaultPrevented = !workerGlobalScope()->dispatchEvent(fetchEvent.release());
diff --git a/third_party/WebKit/Source/web/WebInputEvent.cpp b/third_party/WebKit/Source/web/WebInputEvent.cpp index 4f6054d5..782aef8 100644 --- a/third_party/WebKit/Source/web/WebInputEvent.cpp +++ b/third_party/WebKit/Source/web/WebInputEvent.cpp
@@ -54,7 +54,7 @@ }; struct SameSizeAsWebGestureEvent : public SameSizeAsWebInputEvent { - int gestureData[11]; + int gestureData[12]; }; struct SameSizeAsWebTouchEvent : public SameSizeAsWebInputEvent {
diff --git a/third_party/WebKit/Source/web/WebInputEventConversion.cpp b/third_party/WebKit/Source/web/WebInputEventConversion.cpp index d10f2c14..95ac99cc 100644 --- a/third_party/WebKit/Source/web/WebInputEventConversion.cpp +++ b/third_party/WebKit/Source/web/WebInputEventConversion.cpp
@@ -204,6 +204,19 @@ m_data.m_scroll.m_velocityY = e.data.scrollUpdate.velocityY; m_data.m_scroll.m_preventPropagation = e.data.scrollUpdate.preventPropagation; m_data.m_scroll.m_inertial = e.data.scrollUpdate.inertial; + switch (e.data.scrollUpdate.deltaUnits) { + case WebGestureEvent::ScrollUnits::PrecisePixels: + m_data.m_scroll.m_deltaUnits = ScrollGranularity::ScrollByPrecisePixel; + break; + case WebGestureEvent::ScrollUnits::Pixels: + m_data.m_scroll.m_deltaUnits = ScrollGranularity::ScrollByPixel; + break; + case WebGestureEvent::ScrollUnits::Page: + m_data.m_scroll.m_deltaUnits = ScrollGranularity::ScrollByPage; + break; + default: + ASSERT_NOT_REACHED(); + } break; case WebInputEvent::GestureTap: m_type = PlatformEvent::GestureTap;
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index 416f9d82..704d4cde 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -1981,7 +1981,7 @@ PlatformGestureEvent endScrollEvent(PlatformEvent::GestureScrollEnd, m_positionOnFlingStart, m_globalPositionOnFlingStart, IntSize(), 0, PlatformEvent::NoModifiers, lastFlingSourceDevice == WebGestureDeviceTouchpad ? PlatformGestureSourceTouchpad : PlatformGestureSourceTouchscreen); - endScrollEvent.setScrollGestureData(0, 0, 0, 0, true, false, -1 /* null plugin id */); + endScrollEvent.setScrollGestureData(0, 0, ScrollByPrecisePixel, 0, 0, true, false, -1 /* null plugin id */); mainFrameImpl()->frame()->eventHandler().handleGestureScrollEnd(endScrollEvent); }
diff --git a/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm b/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm index bd4c4a9..350e9cb 100644 --- a/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm +++ b/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm
@@ -97,7 +97,7 @@ [attrs removeObjectForKey:NSBackgroundColorAttributeName]; Vector<UChar> characters; - it.appendTextTo(characters); + it.copyTextTo(characters); NSString* substring = [[[NSString alloc] initWithCharacters:characters.data() length:characters.size()] autorelease];
diff --git a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp index 26e906b..a64b808c 100644 --- a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp +++ b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
@@ -1474,7 +1474,7 @@ IntPoint(0, 0), IntSize(5, 5), 0, PlatformEvent::NoModifiers, PlatformGestureSourceTouchpad); - gsu.setScrollGestureData(-50, -60, 1, 1, false, false, -1 /* null plugin id */); + gsu.setScrollGestureData(-50, -60, ScrollByPrecisePixel, 1, 1, false, false, -1 /* null plugin id */); frame()->eventHandler().handleGestureEvent(gsu);
diff --git a/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp b/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp index fc6688a..b7389642 100644 --- a/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp
@@ -441,7 +441,7 @@ { PlatformGestureEvent platformGestureEvent(PlatformEvent::GestureScrollUpdate, IntPoint(10, 12), IntPoint(20, 22), IntSize(25, 27), 0, PlatformEvent::NoModifiers, PlatformGestureSourceTouchscreen); - platformGestureEvent.setScrollGestureData(30, 32, 40, 42, true, true, -1 /* null plugin id */); + platformGestureEvent.setScrollGestureData(30, 32, ScrollByPrecisePixel, 40, 42, true, true, -1 /* null plugin id */); // FIXME: GestureEvent does not preserve velocityX, velocityY, // or preventPropagation. It also fails to scale // coordinates (x, y, deltaX, deltaY) to the page scale. This
diff --git a/third_party/WebKit/public/blink_headers.gypi b/third_party/WebKit/public/blink_headers.gypi index fcb9d72..62f4b60d 100644 --- a/third_party/WebKit/public/blink_headers.gypi +++ b/third_party/WebKit/public/blink_headers.gypi
@@ -44,7 +44,6 @@ "platform/WebContentLayer.h", "platform/WebContentLayerClient.h", "platform/WebContentSettingCallbacks.h", - "platform/WebConvertableToTraceFormat.h", "platform/WebCookieJar.h", "platform/WebCredential.h", "platform/WebCredentialManagerClient.h",
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h index 166d1493..bed866e 100644 --- a/third_party/WebKit/public/platform/Platform.h +++ b/third_party/WebKit/public/platform/Platform.h
@@ -64,7 +64,6 @@ class WebCanvasCaptureHandler; class WebClipboard; class WebCompositorSupport; -class WebConvertableToTraceFormat; class WebCookieJar; class WebCrypto; class WebDatabaseObserver; @@ -446,107 +445,6 @@ // Get a pointer to testing support interfaces. Will not be available in production builds. virtual WebUnitTestSupport* unitTestSupport() { return nullptr; } - - // Tracing ------------------------------------------------------------- - - // Get a pointer to the enabled state of the given trace category. The - // embedder can dynamically change the enabled state as trace event - // recording is started and stopped by the application. Only long-lived - // literal strings should be given as the category name. The implementation - // expects the returned pointer to be held permanently in a local static. If - // the unsigned char is non-zero, tracing is enabled. If tracing is enabled, - // addTraceEvent is expected to be called by the trace event macros. - virtual const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName) { return nullptr; } - - typedef intptr_t TraceEventAPIAtomicWord; - - // Get a pointer to a global state of the given thread. An embedder is - // expected to update the global state as the state of the embedder changes. - // A sampling thread in the Chromium side reads the global state periodically - // and reflects the sampling profiled results into about:tracing. - virtual TraceEventAPIAtomicWord* getTraceSamplingState(const unsigned bucketName) { return nullptr; } - - typedef uint64_t TraceEventHandle; - - // Add a trace event to the platform tracing system. Depending on the actual - // enabled state, this event may be recorded or dropped. - // - phase specifies the type of event: - // - BEGIN ('B'): Marks the beginning of a scoped event. - // - END ('E'): Marks the end of a scoped event. - // - COMPLETE ('X'): Marks the beginning of a scoped event, but doesn't - // need a matching END event. Instead, at the end of the scope, - // updateTraceEventDuration() must be called with the TraceEventHandle - // returned from addTraceEvent(). - // - INSTANT ('I'): Standalone, instantaneous event. - // - START ('S'): Marks the beginning of an asynchronous event (the end - // event can occur in a different scope or thread). The id parameter is - // used to match START/FINISH pairs. - // - FINISH ('F'): Marks the end of an asynchronous event. - // - COUNTER ('C'): Used to trace integer quantities that change over - // time. The argument values are expected to be of type int. - // - METADATA ('M'): Reserved for internal use. - // - categoryEnabled is the pointer returned by getTraceCategoryEnabledFlag. - // - name is the name of the event. Also used to match BEGIN/END and - // START/FINISH pairs. - // - id optionally allows events of the same name to be distinguished from - // each other. For example, to trace the consutruction and destruction of - // objects, specify the pointer as the id parameter. - // - numArgs specifies the number of elements in argNames, argTypes, and - // argValues. - // - argNames is the array of argument names. Use long-lived literal strings - // or specify the COPY flag. - // - argTypes is the array of argument types: - // - BOOL (1): bool - // - UINT (2): unsigned long long - // - INT (3): long long - // - DOUBLE (4): double - // - POINTER (5): void* - // - STRING (6): char* (long-lived null-terminated char* string) - // - COPY_STRING (7): char* (temporary null-terminated char* string) - // - CONVERTABLE (8): WebConvertableToTraceFormat - // - argValues is the array of argument values. Each value is the unsigned - // long long member of a union of all supported types. - // - convertableValues is the array of WebConvertableToTraceFormat classes - // that may be converted to trace format by calling asTraceFormat method. - // ConvertableToTraceFormat interface. - // convertableValues can be moved to another object by - // WebConvertableToTraceFormat::moveFrom() in addTraceEvent(), and thus - // should not be dereferenced (e.g. asTraceFormat() should not be called) - // after return from addTraceEvent(). - // - thresholdBeginId optionally specifies the value returned by a previous - // call to addTraceEvent with a BEGIN phase. - // - threshold is used on an END phase event in conjunction with the - // thresholdBeginId of a prior BEGIN event. The threshold is the minimum - // number of microseconds that must have passed since the BEGIN event. If - // less than threshold microseconds has passed, the BEGIN/END pair is - // dropped. - // - flags can be 0 or one or more of the following, ORed together: - // - COPY (0x1): treat all strings (name, argNames and argValues of type - // string) as temporary so that they will be copied by addTraceEvent. - // - HAS_ID (0x2): use the id argument to uniquely identify the event for - // matching with other events of the same name. - // - MANGLE_ID (0x4): specify this flag if the id parameter is the value - // of a pointer. - virtual TraceEventHandle addTraceEvent( - char phase, - const unsigned char* categoryEnabledFlag, - const char* name, - unsigned long long id, - unsigned long long bindId, - double timestamp, - int numArgs, - const char** argNames, - const unsigned char* argTypes, - const unsigned long long* argValues, - WebConvertableToTraceFormat* convertableValues, - unsigned flags) - { - return 0; - } - - // Set the duration field of a COMPLETE trace event. - virtual void updateTraceEventDuration(const unsigned char* categoryEnabledFlag, const char* name, TraceEventHandle) { } - // Callbacks for reporting histogram data. // CustomCounts histogram has exponential bucket sizes, so that min=1, max=1000000, bucketCount=50 would do. virtual void histogramCustomCounts(const char* name, int sample, int min, int max, int bucketCount) { }
diff --git a/third_party/WebKit/public/platform/WebConvertableToTraceFormat.h b/third_party/WebKit/public/platform/WebConvertableToTraceFormat.h deleted file mode 100644 index aaffa05a..0000000 --- a/third_party/WebKit/public/platform/WebConvertableToTraceFormat.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WebConvertableToTraceFormat_h -#define WebConvertableToTraceFormat_h - -#include "WebPrivatePtr.h" -#include "WebString.h" - -namespace blink { - -namespace TraceEvent { -class ConvertableToTraceFormat; -} - -class WebConvertableToTraceFormat { -public: - WebConvertableToTraceFormat() { } -#if INSIDE_BLINK - WebConvertableToTraceFormat(PassRefPtr<TraceEvent::ConvertableToTraceFormat>); -#endif - ~WebConvertableToTraceFormat() { reset(); } - - BLINK_PLATFORM_EXPORT WebString asTraceFormat() const; - BLINK_PLATFORM_EXPORT void assign(const WebConvertableToTraceFormat&); - BLINK_PLATFORM_EXPORT void moveFrom(WebConvertableToTraceFormat&); - BLINK_PLATFORM_EXPORT void reset(); - - WebConvertableToTraceFormat(const WebConvertableToTraceFormat& r) { assign(r); } - WebConvertableToTraceFormat& operator=(const WebConvertableToTraceFormat& r) - { - assign(r); - return *this; - } - -private: - WebPrivatePtr<TraceEvent::ConvertableToTraceFormat> m_private; -}; - -} // namespace blink - -#endif
diff --git a/third_party/WebKit/public/platform/WebLayer.h b/third_party/WebKit/public/platform/WebLayer.h index 6ef2535..0d401821 100644 --- a/third_party/WebKit/public/platform/WebLayer.h +++ b/third_party/WebKit/public/platform/WebLayer.h
@@ -32,6 +32,7 @@ #include "WebCompositorAnimation.h" #include "WebDoublePoint.h" #include "WebFloatPoint3D.h" +#include "WebMainThreadScrollingReason.h" #include "WebPoint.h" #include "WebRect.h" #include "WebScrollBlocksOn.h" @@ -207,7 +208,10 @@ virtual void setHaveScrollEventHandlers(bool) = 0; virtual bool haveScrollEventHandlers() const = 0; - virtual void setShouldScrollOnMainThread(bool) = 0; + // Indicates that this layer will always scroll on the main thread for the provided reason. + virtual void addMainThreadScrollingReasons(WebMainThreadScrollingReason::WebMainThreadScrollingReason) = 0; + // Indicates that the layer could scroll on the compositor thread. + virtual void clearMainThreadScrollingReasons() = 0; virtual bool shouldScrollOnMainThread() const = 0; virtual void setNonFastScrollableRegion(const WebVector<WebRect>&) = 0;
diff --git a/third_party/WebKit/public/platform/WebMainThreadScrollingReason.h b/third_party/WebKit/public/platform/WebMainThreadScrollingReason.h new file mode 100644 index 0000000..7dcae44 --- /dev/null +++ b/third_party/WebKit/public/platform/WebMainThreadScrollingReason.h
@@ -0,0 +1,26 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WebMainThreadScrollingReason_h +#define WebMainThreadScrollingReason_h + +#include "WebCommon.h" + +namespace blink { + +// Ensure this stays in sync with InputHandler::MainThreadScrollingReason. +namespace WebMainThreadScrollingReason { +enum WebMainThreadScrollingReason { + NotScrollingOnMain = 0, + HasBackgroundAttachmentFixedObjects = 1 << 0, + HasNonLayerViewportConstrainedObjects = 1 << 1, + ThreadedScrollingDisabled = 1 << 2, + ScrollBarScrolling = 1 << 3, + PageOverlay = 1 << 4 +}; +} // namespace MainThreadScrollingReason + +} // namespace blink + +#endif
diff --git a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h index cd2caa70..4a7263d 100644 --- a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h +++ b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h
@@ -64,6 +64,9 @@ void setMode(WebURLRequest::FetchRequestMode); WebURLRequest::FetchRequestMode mode() const; + void setIsMainResourceLoad(bool); + bool isMainResourceLoad() const; + void setCredentialsMode(WebURLRequest::FetchCredentialsMode); WebURLRequest::FetchCredentialsMode credentialsMode() const; @@ -76,6 +79,9 @@ void setFrameType(WebURLRequest::FrameType); WebURLRequest::FrameType frameType() const; + void setClientId(const WebString&); + WebString clientId() const; + void setIsReload(bool); bool isReload() const;
diff --git a/third_party/WebKit/public/web/WebInputEvent.h b/third_party/WebKit/public/web/WebInputEvent.h index 6ce0fea..92b6347 100644 --- a/third_party/WebKit/public/web/WebInputEvent.h +++ b/third_party/WebKit/public/web/WebInputEvent.h
@@ -456,6 +456,12 @@ class WebGestureEvent : public WebInputEvent { public: + enum ScrollUnits { + PrecisePixels = 0, // generated by high precision devices. + Pixels, // large pixel jump duration; should animate to delta. + Page // page (visible viewport) based scrolling. + }; + int x; int y; int globalX; @@ -502,6 +508,8 @@ // May be redundant with deltaX/deltaY in the first scrollUpdate. float deltaXHint; float deltaYHint; + // Default initialized to ScrollUnits::PrecisePixels. + ScrollUnits deltaHintUnits; // If true, this event will skip hit testing to find a scroll // target and instead just scroll the viewport. bool targetViewport; @@ -520,6 +528,8 @@ bool previousUpdateInSequencePrevented; bool preventPropagation; bool inertial; + // Default initialized to ScrollUnits::PrecisePixels. + ScrollUnits deltaUnits; } scrollUpdate; struct {
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium index 92bdd99..b681fe1 100644 --- a/third_party/crashpad/README.chromium +++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@ Short Name: crashpad URL: https://crashpad.chromium.org/ Version: unknown -Revision: 417097b91fe872404db257532d5126cfd7bfb438 +Revision: 4794225f22583a08732cb9ad4356106013a220f3 License: Apache 2.0 License File: crashpad/LICENSE Security Critical: yes
diff --git a/third_party/crashpad/crashpad/codereview.settings b/third_party/crashpad/crashpad/codereview.settings index c3673e8..3878422 100644 --- a/third_party/crashpad/crashpad/codereview.settings +++ b/third_party/crashpad/crashpad/codereview.settings
@@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -CODE_REVIEW_SERVER: codereview.chromium.org -CC_LIST: crashpad-dev@chromium.org +GERRIT_HOST: True +CODE_REVIEW_SERVER: https://canary-chromium-review.googlesource.com/ VIEW_VC: https://chromium.googlesource.com/crashpad/crashpad/+/ PROJECT: crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.cc b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.cc new file mode 100644 index 0000000..8f444fa --- /dev/null +++ b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.cc
@@ -0,0 +1,53 @@ +// Copyright 2016 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "snapshot/api/module_annotations_win.h" + +#include "snapshot/win/pe_image_annotations_reader.h" +#include "snapshot/win/pe_image_reader.h" +#include "snapshot/win/process_reader_win.h" +#include "util/win/get_module_information.h" + +namespace crashpad { + +bool ReadModuleAnnotations(HANDLE process, + HMODULE module, + std::map<std::string, std::string>* annotations) { + ProcessReaderWin process_reader; + if (!process_reader.Initialize(process, ProcessSuspensionState::kRunning)) + return false; + + MODULEINFO module_info; + if (!CrashpadGetModuleInformation( + process, module, &module_info, sizeof(module_info))) { + PLOG(ERROR) << "CrashpadGetModuleInformation"; + return false; + } + + PEImageReader image_reader; + if (!image_reader.Initialize( + &process_reader, + reinterpret_cast<crashpad::WinVMAddress>(module_info.lpBaseOfDll), + module_info.SizeOfImage, + "")) + return false; + + PEImageAnnotationsReader annotations_reader( + &process_reader, &image_reader, L""); + + *annotations = annotations_reader.SimpleMap(); + return true; +} + +} // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.h b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.h new file mode 100644 index 0000000..e024031 --- /dev/null +++ b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win.h
@@ -0,0 +1,42 @@ +// Copyright 2016 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_ +#define CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_ + +#include <windows.h> + +#include <map> +#include <string> + +namespace crashpad { + +//! \brief Reads the module annotations from another process. +//! +//! \param[in] process The handle to the process that hosts the \a module. +//! Requires PROCESS_QUERY_INFORMATION and PROCESS_VM_READ accesses. +//! \param[in] module The handle to the module from which the \a annotations +//! will be read. This module should be loaded in the target process. +//! \param[out] annotations The map that will be filled with the annotations. +//! Remains unchanged if the function returns 'false'. +//! +//! \return `true` if the annotations could be read succesfully, even if the +//! module doesn't contain any annotations. +bool ReadModuleAnnotations(HANDLE process, + HMODULE module, + std::map<std::string, std::string>* annotations); + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_
diff --git a/third_party/crashpad/crashpad/snapshot/api/module_annotations_win_test.cc b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win_test.cc new file mode 100644 index 0000000..30e880f3 --- /dev/null +++ b/third_party/crashpad/crashpad/snapshot/api/module_annotations_win_test.cc
@@ -0,0 +1,83 @@ +// Copyright 2016 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "snapshot/api/module_annotations_win.h" + +#include "client/crashpad_info.h" +#include "gtest/gtest.h" +#include "test/win/win_multiprocess.h" +#include "util/file/file_io.h" + +namespace crashpad { +namespace test { +namespace { + +class ModuleAnnotationsMultiprocessTest final : public WinMultiprocess { + private: + void WinMultiprocessParent() override { + // Read the child executable module. + HMODULE module = nullptr; + CheckedReadFile(ReadPipeHandle(), &module, sizeof(module)); + + // Reopen the child process with necessary access. + HANDLE process_handle = + OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + FALSE, + GetProcessId(ChildProcess())); + EXPECT_TRUE(process_handle); + + // Read the module annotations in the child process and verify them. + std::map<std::string, std::string> annotations; + ASSERT_TRUE(ReadModuleAnnotations(process_handle, module, &annotations)); + + EXPECT_GE(annotations.size(), 3u); + EXPECT_EQ("value", annotations["#APITEST# key"]); + EXPECT_EQ("y", annotations["#APITEST# x"]); + EXPECT_EQ("", annotations["#APITEST# empty_value"]); + + // Signal the child process to terminate. + char c = ' '; + CheckedWriteFile(WritePipeHandle(), &c, sizeof(c)); + } + + void WinMultiprocessChild() override { + // Set some test annotations. + crashpad::CrashpadInfo* crashpad_info = + crashpad::CrashpadInfo::GetCrashpadInfo(); + + crashpad::SimpleStringDictionary* simple_annotations = + new crashpad::SimpleStringDictionary(); + simple_annotations->SetKeyValue("#APITEST# key", "value"); + simple_annotations->SetKeyValue("#APITEST# x", "y"); + simple_annotations->SetKeyValue("#APITEST# empty_value", ""); + + crashpad_info->set_simple_annotations(simple_annotations); + + // Send the executable module. + HMODULE module = GetModuleHandle(nullptr); + CheckedWriteFile(WritePipeHandle(), &module, sizeof(module)); + + // Wait until a signal from the parent process to terminate. + char c; + CheckedReadFile(ReadPipeHandle(), &c, sizeof(c)); + } +}; + +TEST(ModuleAnnotationsWin, ReadAnnotations) { + WinMultiprocess::Run<ModuleAnnotationsMultiprocessTest>(); +} + +} // namespace +} // namespace test +} // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot.gyp b/third_party/crashpad/crashpad/snapshot/snapshot.gyp index 29711b06..0154495 100644 --- a/third_party/crashpad/crashpad/snapshot/snapshot.gyp +++ b/third_party/crashpad/crashpad/snapshot/snapshot.gyp
@@ -129,5 +129,32 @@ }], ] }, + { + 'variables': { + 'conditions': [ + ['OS == "win"', { + 'snapshot_api_target_type%': 'static_library', + }, { + # There are no source files except on Windows. + 'snapshot_api_target_type%': 'none', + }], + ], + }, + 'target_name': 'crashpad_snapshot_api', + 'type': '<(snapshot_api_target_type)', + 'dependencies': [ + 'crashpad_snapshot', + '../compat/compat.gyp:crashpad_compat', + '../third_party/mini_chromium/mini_chromium.gyp:base', + '../util/util.gyp:crashpad_util', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'api/module_annotations_win.cc', + 'api/module_annotations_win.h', + ], + }, ], }
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp index 51274e6c..9bfcf8b3 100644 --- a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp +++ b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
@@ -54,6 +54,7 @@ 'dependencies': [ 'crashpad_snapshot_test_module', 'snapshot.gyp:crashpad_snapshot', + 'snapshot.gyp:crashpad_snapshot_api', '../client/client.gyp:crashpad_client', '../compat/compat.gyp:crashpad_compat', '../test/test.gyp:crashpad_test', @@ -68,6 +69,7 @@ 'sources': [ 'cpu_context_test.cc', 'crashpad_info_client_options_test.cc', + 'api/module_annotations_win_test.cc', 'mac/cpu_context_mac_test.cc', 'mac/mach_o_image_annotations_reader_test.cc', 'mac/mach_o_image_reader_test.cc',
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc index 9bdf124..523a449 100644 --- a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc +++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc
@@ -31,7 +31,6 @@ #include "snapshot/win/process_reader_win.h" #include "test/paths.h" #include "test/win/child_launcher.h" -#include "test/win/win_multiprocess.h" #include "util/file/file_io.h" #include "util/win/process_info.h"
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc index 46795cfb..704b659 100644 --- a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc +++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc
@@ -22,7 +22,7 @@ #include "gtest/gtest.h" #include "snapshot/win/process_reader_win.h" #include "test/errors.h" -#include "util/win/get_function.h" +#include "util/win/get_module_information.h" #include "util/win/module_version.h" #include "util/win/process_info.h" @@ -32,15 +32,6 @@ namespace test { namespace { -BOOL CrashpadGetModuleInformation(HANDLE process, - HMODULE module, - MODULEINFO* module_info, - DWORD cb) { - static const auto get_module_information = - GET_FUNCTION_REQUIRED(L"psapi.dll", ::GetModuleInformation); - return get_module_information(process, module, module_info, cb); -} - TEST(PEImageReader, DebugDirectory) { PEImageReader pe_image_reader; ProcessReaderWin process_reader;
diff --git a/third_party/crashpad/crashpad/util/util.gyp b/third_party/crashpad/crashpad/util/util.gyp index 6d0090f4..4819490 100644 --- a/third_party/crashpad/crashpad/util/util.gyp +++ b/third_party/crashpad/crashpad/util/util.gyp
@@ -166,6 +166,8 @@ 'win/exception_handler_server.h', 'win/get_function.cc', 'win/get_function.h', + 'win/get_module_information.cc', + 'win/get_module_information.h', 'win/handle.cc', 'win/handle.h', 'win/module_version.cc',
diff --git a/third_party/crashpad/crashpad/util/win/get_module_information.cc b/third_party/crashpad/crashpad/util/win/get_module_information.cc new file mode 100644 index 0000000..1a9fd0c --- /dev/null +++ b/third_party/crashpad/crashpad/util/win/get_module_information.cc
@@ -0,0 +1,30 @@ +// Copyright 2016 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/win/get_module_information.h" + +#include "util/win/get_function.h" + +namespace crashpad { + +BOOL CrashpadGetModuleInformation(HANDLE process, + HMODULE module, + MODULEINFO* module_info, + DWORD cb) { + static const auto get_module_information = + GET_FUNCTION_REQUIRED(L"psapi.dll", GetModuleInformation); + return get_module_information(process, module, module_info, cb); +} + +} // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/win/get_module_information.h b/third_party/crashpad/crashpad/util/win/get_module_information.h new file mode 100644 index 0000000..c7d1cf1 --- /dev/null +++ b/third_party/crashpad/crashpad/util/win/get_module_information.h
@@ -0,0 +1,33 @@ +// Copyright 2016 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_WIN_GET_MODULE_INFORMATION_H_ +#define CRASHPAD_UTIL_WIN_GET_MODULE_INFORMATION_H_ + +#include <windows.h> + +#define PSAPI_VERSION 1 +#include <psapi.h> + +namespace crashpad { + +//! \brief Proxy function for `GetModuleInformation()`. +BOOL CrashpadGetModuleInformation(HANDLE process, + HMODULE module, + MODULEINFO* module_info, + DWORD cb); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_WIN_GET_MODULE_INFORMATION_H_
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium index c64f9b01..34a565f 100644 --- a/third_party/libjingle/README.chromium +++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@ Name: libjingle URL: http://www.webrtc.org Version: unknown -Revision: 11250 +Revision: 11290 License: BSD License File: source/talk/COPYING Security Critical: yes
diff --git a/third_party/ots/INSTALL b/third_party/ots/INSTALL index da35254..419a2a8 100644 --- a/third_party/ots/INSTALL +++ b/third_party/ots/INSTALL
@@ -31,3 +31,22 @@ $ pacman -S autoconf automake pkg-config gcc make zlib-devel 3. Follow the general build instructions above. + +Developer build instructions: + + 1. If you would like to see the source code lines related to reported + errors, then run make with: + + $ make CXXFLAGS=-DOTS_DEBUG + + For example, + + $ ./ot-sanitise ~/fonts/ofl/merriweathersans/MerriweatherSans-Bold.ttf + ERROR at src/layout.cc:100 (ParseScriptTable) + ERROR: Layout: DFLT table doesn't satisfy the spec. for script tag DFLT + ERROR at src/layout.cc:1247 (ParseScriptListTable) + ERROR: Layout: Failed to parse script table 0 + ERROR at src/gsub.cc:642 (ots_gsub_parse) + ERROR: GSUB: Failed to parse script list table + ERROR at src/ots.cc:669 (ProcessGeneric) + Failed to sanitise file!
diff --git a/third_party/ots/Makefile.am b/third_party/ots/Makefile.am index cde62aa..b1ea71c 100644 --- a/third_party/ots/Makefile.am +++ b/third_party/ots/Makefile.am
@@ -124,7 +124,6 @@ third_party/brotli/dec/decode.c \ third_party/brotli/dec/decode.h \ third_party/brotli/dec/dictionary.h \ - third_party/brotli/dec/dictionary.c \ third_party/brotli/dec/huffman.c \ third_party/brotli/dec/huffman.h \ third_party/brotli/dec/port.h \
diff --git a/third_party/ots/README.chromium b/third_party/ots/README.chromium index a520efdf..60dbf4c 100644 --- a/third_party/ots/README.chromium +++ b/third_party/ots/README.chromium
@@ -1,6 +1,6 @@ Name: OTS (OpenType Sanitizer) URL: https://github.com/khaledhosny/ots.git -Version: 99a3b7ff8fb241e0f68a25a41726cc3421d1f9bf +Version: 8ade3d16fbb0273e7f828191b4ad37b3819ce302 Security Critical: yes License: BSD
diff --git a/third_party/ots/configure.ac b/third_party/ots/configure.ac index 23ac941..9f67dec 100644 --- a/third_party/ots/configure.ac +++ b/third_party/ots/configure.ac
@@ -1,5 +1,5 @@ AC_INIT([OTS], - [5.0.0], + [5.0.1], [https://github.com/khaledhosny/ots/issues], [ots], [https://github.com/khaledhosny/ots])
diff --git a/third_party/ots/src/cmap.cc b/third_party/ots/src/cmap.cc index 3ee201185..cbb5f3c3 100644 --- a/third_party/ots/src/cmap.cc +++ b/third_party/ots/src/cmap.cc
@@ -282,7 +282,7 @@ if (!subtable.ReadU32(&num_groups)) { return OTS_FAILURE_MSG("can't read number of format 12 subtable groups"); } - if (num_groups == 0 || subtable.remaining() < num_groups * 12) { + if (num_groups == 0 || subtable.remaining() / 12 < num_groups) { return OTS_FAILURE_MSG("Bad format 12 subtable group count %d", num_groups); } @@ -356,7 +356,7 @@ // We limit the number of groups in the same way as in 3.10.12 tables. See // the comment there in - if (num_groups == 0 || subtable.remaining() < num_groups * 12) { + if (num_groups == 0 || subtable.remaining() / 12 < num_groups) { return OTS_FAILURE_MSG("Bad format 13 subtable group count %d", num_groups); } @@ -464,7 +464,7 @@ if (!subtable.ReadU32(&num_ranges)) { return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i); } - if (num_ranges == 0 || subtable.remaining() < num_ranges * 4) { + if (num_ranges == 0 || subtable.remaining() / 4 < num_ranges) { return OTS_FAILURE_MSG("Bad number of ranges (%d) in record %d", num_ranges, i); } @@ -498,7 +498,7 @@ if (!subtable.ReadU32(&num_mappings)) { return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i); } - if (num_mappings == 0 || subtable.remaining() < num_mappings * 5) { + if (num_mappings == 0 || subtable.remaining() / 5 < num_mappings) { return OTS_FAILURE_MSG("Bad number of mappings (%d) in variation selector record %d", num_mappings, i); }
diff --git a/third_party/ots/src/layout.cc b/third_party/ots/src/layout.cc index e4f8070..1d87b53 100644 --- a/third_party/ots/src/layout.cc +++ b/third_party/ots/src/layout.cc
@@ -95,9 +95,14 @@ // The spec requires a script table for 'DFLT' tag must contain non-NULL // |offset_default_lang_sys| and |lang_sys_count| == 0 - if (tag == kScriptTableTagDflt && - (offset_default_lang_sys == 0 || lang_sys_count != 0)) { - return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %c%c%c%c", OTS_UNTAG(tag)); + // https://www.microsoft.com/typography/otspec/chapter2.htm + if (tag == kScriptTableTagDflt) { + if (offset_default_lang_sys == 0) { + return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. DefaultLangSys is NULL"); + } + if (lang_sys_count != 0) { + return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. LangSysCount is not zero: %d", lang_sys_count); + } } const unsigned lang_sys_record_end =
diff --git a/tools/android/loading/device_setup.py b/tools/android/loading/device_setup.py index 24becb7..4d5d40b 100644 --- a/tools/android/loading/device_setup.py +++ b/tools/android/loading/device_setup.py
@@ -17,17 +17,21 @@ from pylib import constants from pylib import flag_changer +import devtools_monitor + DEVTOOLS_PORT = 9222 DEVTOOLS_HOSTNAME = 'localhost' +DEFAULT_CHROME_PACKAGE = 'chrome' @contextlib.contextmanager -def FlagChanger(device, command_line_path, new_flags): - """Changes the flags in a context, restores them afterwards. +def FlagReplacer(device, command_line_path, new_flags): + """Replaces chrome flags in a context, restores them afterwards. Args: - device: Device to target, from DeviceUtils. + device: Device to target, from DeviceUtils. Can be None, in which case this + context manager is a no-op. command_line_path: Full path to the command-line file. - new_flags: Flags to add. + new_flags: Flags to replace. """ # If we're logging requests from a local desktop chrome instance there is no # device. @@ -35,7 +39,7 @@ yield return changer = flag_changer.FlagChanger(device, command_line_path) - changer.AddFlags(new_flags) + changer.ReplaceFlags(new_flags) try: yield finally: @@ -63,28 +67,30 @@ device.KillAll(package_info.package, quiet=True) -def SetUpAndExecute(device, package, fn): - """Start logging process. +@contextlib.contextmanager +def DeviceConnection(device, + package=DEFAULT_CHROME_PACKAGE, + hostname=DEVTOOLS_HOSTNAME, + port=DEVTOOLS_PORT): + """Context for starting recording on a device. - Sets up any device and tracing appropriately and then executes the core - logging function. + Sets up and restores any device and tracing appropriately Args: - device: Android device, or None for a local run. + device: Android device, or None for a local run (in which case chrome needs + to have been started with --remote-debugging-port=XXX). package: the key for chrome package info. - fn: the function to execute that launches chrome and performs the - appropriate instrumentation, see _Log*Internal(). Returns: - As fn() returns. + A context manager type which evaluates to a DevToolsConnection. """ package_info = constants.PACKAGE_INFO[package] command_line_path = '/data/local/chrome-command-line' new_flags = ['--enable-test-events', - '--remote-debugging-port=%d' % DEVTOOLS_PORT] + '--remote-debugging-port=%d' % port] if device: _SetUpDevice(device, package_info) - with FlagChanger(device, command_line_path, new_flags): + with FlagReplacer(device, command_line_path, new_flags): if device: start_intent = intent.Intent( package=package_info.package, activity=package_info.activity, @@ -92,6 +98,25 @@ device.StartActivity(start_intent, blocking=True) time.sleep(2) # If no device, we don't care about chrome startup so skip the about page. - with ForwardPort(device, 'tcp:%d' % DEVTOOLS_PORT, + with ForwardPort(device, 'tcp:%d' % port, 'localabstract:chrome_devtools_remote'): - return fn() + yield devtools_monitor.DevToolsConnection(hostname, port) + + +def SetUpAndExecute(device, package, fn): + """Start logging process. + + Wrapper for DeviceConnection for those functionally inclined. + + Args: + device: Android device, or None for a local run. + package: the key for chrome package info. + fn: the function to execute that launches chrome and performs the + appropriate instrumentation. The function will receive a + DevToolsConnection as its sole parameter. + + Returns: + As fn() returns. + """ + with DeviceConnection(device, package) as connection: + return fn(connection)
diff --git a/tools/android/loading/devtools_monitor.py b/tools/android/loading/devtools_monitor.py index fc652d2..5e8470ba 100644 --- a/tools/android/loading/devtools_monitor.py +++ b/tools/android/loading/devtools_monitor.py
@@ -24,9 +24,62 @@ logging.warning("DevToolsConnectionException: " + message) +# Taken from telemetry.internal.backends.chrome_inspector.tracing_backend. +# TODO(mattcary): combine this with the above and export? +class _StreamReader(object): + def __init__(self, inspector, stream_handle): + self._inspector_websocket = inspector + self._handle = stream_handle + self._callback = None + self._data = None + + def Read(self, callback): + # Do not allow the instance of this class to be reused, as + # we only read data sequentially at the moment, so a stream + # can only be read once. + assert not self._callback + self._data = [] + self._callback = callback + self._ReadChunkFromStream() + # Queue one extra read ahead to avoid latency. + self._ReadChunkFromStream() + + def _ReadChunkFromStream(self): + # Limit max block size to avoid fragmenting memory in sock.recv(), + # (see https://github.com/liris/websocket-client/issues/163 for details) + req = {'method': 'IO.read', 'params': { + 'handle': self._handle, 'size': 32768}} + self._inspector_websocket.AsyncRequest(req, self._GotChunkFromStream) + + def _GotChunkFromStream(self, response): + # Quietly discard responses from reads queued ahead after EOF. + if self._data is None: + return + if 'error' in response: + raise DevToolsConnectionException( + 'Reading trace failed: %s' % response['error']['message']) + result = response['result'] + self._data.append(result['data']) + if not result.get('eof', False): + self._ReadChunkFromStream() + return + req = {'method': 'IO.close', 'params': {'handle': self._handle}} + self._inspector_websocket.SendAndIgnoreResponse(req) + trace_string = ''.join(self._data) + self._data = None + self._callback(trace_string) + + class DevToolsConnection(object): """Handles the communication with a DevTools server. """ + TRACING_DOMAIN = 'Tracing' + TRACING_END_METHOD = 'Tracing.end' + TRACING_DATA_METHOD = 'Tracing.dataCollected' + TRACING_DONE_EVENT = 'Tracing.tracingComplete' + TRACING_STREAM_EVENT = 'Tracing.tracingComplete' # Same as TRACING_DONE. + TRACING_TIMEOUT = 300 + def __init__(self, hostname, port): """Initializes the connection with a DevTools server. @@ -35,8 +88,11 @@ port: port number. """ self._ws = self._Connect(hostname, port) - self._listeners = {} + self._event_listeners = {} + self._domain_listeners = {} self._domains_to_enable = set() + self._tearing_down_tracing = False + self._set_up = False self._please_stop = False def RegisterListener(self, name, listener): @@ -45,12 +101,16 @@ Also takes care of enabling the relevant domain before starting monitoring. Args: - name: (str) Event the listener wants to listen to, e.g. - Network.requestWillBeSent. + name: (str) Domain or event the listener wants to listen to, e.g. + "Network.requestWillBeSent" or "Tracing". listener: (Listener) listener instance. """ - domain = name[:name.index('.')] - self._listeners[name] = listener + if '.' in name: + domain = name[:name.index('.')] + self._event_listeners[name] = listener + else: + domain = name + self._domain_listeners[domain] = listener self._domains_to_enable.add(domain) def UnregisterListener(self, listener): @@ -59,10 +119,14 @@ Args: listener: (Listener) listener to unregister. """ - keys = [k for (k, v) in self._listeners if v is listener] + keys = ([k for k, l in self._event_listeners if l is listener] + + [k for k, l in self._domain_listeners if l is listener]) assert keys, "Removing non-existent listener" for key in keys: - del(self._listeners[key]) + if key in self._event_listeners: + del(self._event_listeners[key]) + if key in self._domain_listeners: + del(self._domain_listeners[key]) def SyncRequest(self, method, params=None): """Issues a synchronous request to the DevTools server. @@ -91,41 +155,103 @@ request['params'] = params self._ws.SendAndIgnoreResponse(request) + def SyncRequestNoResponse(self, method, params=None): + """As SyncRequest, but asserts that no meaningful response was received. + + Args: + method: (str) Method. + params: (dict) Optional parameters to the request. + """ + result = self.SyncRequest(method, params) + if 'error' in result or ('result' in result and + result['result']): + raise DevToolsConnectionException( + 'Unexpected response for %s: %s' % (method, result)) + def SetUpMonitoring(self): for domain in self._domains_to_enable: self._ws.RegisterDomain(domain, self._OnDataReceived) - self.SyncRequest('%s.enable' % domain) + if domain != self.TRACING_DOMAIN: + self.SyncRequestNoResponse('%s.enable' % domain) + # Tracing setup must be done by the tracing track to control filtering + # and output. + self._tearing_down_tracing = False + self._set_up = True def StartMonitoring(self): """Starts monitoring. DevToolsConnection.SetUpMonitoring() has to be called first. """ - while not self._please_stop: - try: - self._ws.DispatchNotifications() - except websocket.WebSocketTimeoutException: - break - if not self._please_stop: - logging.warning('Monitoring stopped on a timeout.') + assert self._set_up, 'DevToolsConnection.SetUpMonitoring not called.' + self._Dispatch() self._TearDownMonitoring() def StopMonitoring(self): """Stops the monitoring.""" self._please_stop = True + def _Dispatch(self, kind='Monitoring', timeout=10): + self._please_stop = False + while not self._please_stop: + try: + self._ws.DispatchNotifications(timeout=timeout) + except websocket.WebSocketTimeoutException: + break + if not self._please_stop: + logging.warning('%s stopped on a timeout.' % kind) + def _TearDownMonitoring(self): + if self.TRACING_DOMAIN in self._domains_to_enable: + logging.info('Fetching tracing') + self.SyncRequestNoResponse(self.TRACING_END_METHOD) + self._tearing_down_tracing = True + self._Dispatch(kind='Tracing', timeout=self.TRACING_TIMEOUT) for domain in self._domains_to_enable: - self.SyncRequest('%s.disable' % domain) + if domain != self.TRACING_DOMAIN: + self.SyncRequest('%s.disable' % domain) self._ws.UnregisterDomain(domain) self._domains_to_enable.clear() - self._listeners.clear() + self._domain_listeners.clear() + self._event_listeners.clear() def _OnDataReceived(self, msg): - method = msg.get('method', None) - if method not in self._listeners: + if 'method' not in msg: + raise DevToolsConnectionException('Malformed message: %s' % msg) + method = msg['method'] + domain = method[:method.index('.')] + + if self._tearing_down_tracing and method == self.TRACING_STREAM_EVENT: + stream_handle = msg.get('params', {}).get('stream') + if not stream_handle: + self._tearing_down_tracing = False + self.StopMonitoring() + # Fall through to regular dispatching. + else: + _StreamReader(self._ws, stream_handle).Read(self._TracingStreamDone) + # Skip regular dispatching. + return + + if (method not in self._event_listeners and + domain not in self._domain_listeners): return - self._listeners[method].Handle(method, msg) + if method in self._event_listeners: + self._event_listeners[method].Handle(method, msg) + if domain in self._domain_listeners: + self._domain_listeners[domain].Handle(method, msg) + if self._tearing_down_tracing and method == self.TRACING_DONE_EVENT: + self._tearing_down_tracing = False + self.StopMonitoring() + + def _TracingStreamDone(self, data): + tracing_events = json.loads(data) + for evt in tracing_events: + self._OnDataReceived({'method': self.TRACING_DATA_METHOD, + 'params': {'value': [evt]}}) + if self._please_stop: + break + self._tearing_down_tracing = False + self.StopMonitoring() @classmethod def _GetWebSocketUrl(cls, hostname, port):
diff --git a/tools/android/loading/page_track.py b/tools/android/loading/page_track.py new file mode 100644 index 0000000..bb289db --- /dev/null +++ b/tools/android/loading/page_track.py
@@ -0,0 +1,62 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import devtools_monitor + + +class PageTrack(devtools_monitor.Track): + """Records the events from the page track.""" + _METHODS = ('Page.frameStartedLoading', 'Page.frameStoppedLoading', + 'Page.frameAttached') + def __init__(self, connection): + super(PageTrack, self).__init__(connection) + self._connection = connection + self._events = [] + self._pending_frames = set() + self._known_frames = set() + self._main_frame_id = None + if self._connection: + for method in PageTrack._METHODS: + self._connection.RegisterListener(method, self) + + def Handle(self, method, msg): + assert method in PageTrack._METHODS + params = msg['params'] + frame_id = params['frameId'] + should_stop = False + event = {'method': method, 'frame_id': frame_id} + if method == 'Page.frameStartedLoading': + if self._main_frame_id is None: + self._main_frame_id = params['frameId'] + self._pending_frames.add(frame_id) + self._known_frames.add(frame_id) + elif method == 'Page.frameStoppedLoading': + assert frame_id in self._pending_frames + self._pending_frames.remove(frame_id) + if frame_id == self._main_frame_id: + should_stop = True + elif method == 'Page.frameAttached': + self._known_frames.add(frame_id) + parent_frame = params['parentFrameId'] + assert parent_frame in self._known_frames + event['parent_frame_id'] = parent_frame + self._events.append(event) + if should_stop and self._connection: + self._connection.StopMonitoring() + + def GetEvents(self): + #TODO(lizeb): Add more checks here (child frame stops loading before parent, + #for instance). + return self._events + + def ToJsonDict(self): + return {'events': [event for event in self._events]} + + @classmethod + def FromJsonDict(cls, json_dict): + assert 'events' in json_dict + result = PageTrack(None) + events = [event for event in json_dict['events']] + result._events = events + return result
diff --git a/tools/android/loading/page_track_unittest.py b/tools/android/loading/page_track_unittest.py new file mode 100644 index 0000000..6757a01 --- /dev/null +++ b/tools/android/loading/page_track_unittest.py
@@ -0,0 +1,58 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +import devtools_monitor +from page_track import PageTrack + +class MockDevToolsConnection(object): + def __init__(self): + self.stop_has_been_called = False + + def RegisterListener(self, name, listener): + pass + + def StopMonitoring(self): + self.stop_has_been_called = True + + +class PageTrackTest(unittest.TestCase): + _EVENTS = [{'method': 'Page.frameStartedLoading', + 'params': {'frameId': '1234.1'}}, + {'method': 'Page.frameAttached', + 'params': {'frameId': '1234.12', 'parentFrameId': '1234.1'}}, + {'method': 'Page.frameStartedLoading', + 'params': {'frameId': '1234.12'}}, + {'method': 'Page.frameStoppedLoading', + 'params': {'frameId': '1234.12'}}, + {'method': 'Page.frameStoppedLoading', + 'params': {'frameId': '1234.1'}}] + def testAsksMonitoringToStop(self): + devtools_connection = MockDevToolsConnection() + page_track = PageTrack(devtools_connection) + for msg in PageTrackTest._EVENTS[:-1]: + page_track.Handle(msg['method'], msg) + self.assertFalse(devtools_connection.stop_has_been_called) + msg = PageTrackTest._EVENTS[-1] + page_track.Handle(msg['method'], msg) + self.assertTrue(devtools_connection.stop_has_been_called) + + def testUnknownParent(self): + page_track = PageTrack(None) + msg = {'method': 'Page.frameAttached', + 'params': {'frameId': '1234.12', 'parentFrameId': '1234.1'}} + with self.assertRaises(AssertionError): + page_track.Handle(msg['method'], msg) + + def testStopsLoadingUnknownFrame(self): + page_track = PageTrack(None) + msg = {'method': 'Page.frameStoppedLoading', + 'params': {'frameId': '1234.12'}} + with self.assertRaises(AssertionError): + page_track.Handle(msg['method'], msg) + + +if __name__ == '__main__': + unittest.main()
diff --git a/tools/android/loading/request_track.py b/tools/android/loading/request_track.py index de3fd115..08e15880 100644 --- a/tools/android/loading/request_track.py +++ b/tools/android/loading/request_track.py
@@ -104,6 +104,17 @@ setattr(result, k, v) return result + def GetContentType(self): + """Returns the content type, or None.""" + content_type = self.response_headers.get('Content-Type', None) + if not content_type or ';' not in content_type: + return content_type + else: + return content_type[:content_type.index(';')] + + def IsDataRequest(self): + return self.protocol == 'data' + # For testing. def __eq__(self, o): return self.__dict__ == o.__dict__
diff --git a/tools/android/loading/request_track_unittest.py b/tools/android/loading/request_track_unittest.py index 459e2de..1e9403b2 100644 --- a/tools/android/loading/request_track_unittest.py +++ b/tools/android/loading/request_track_unittest.py
@@ -8,6 +8,17 @@ from request_track import (Request, RequestTrack, _TimingFromDict) +class RequestTestCase(unittest.TestCase): + def testContentType(self): + r = Request() + r.response_headers = {} + self.assertEquals(None, r.GetContentType()) + r.response_headers = {'Content-Type': 'application/javascript'} + self.assertEquals('application/javascript', r.GetContentType()) + r.response_headers = {'Content-Type': 'application/javascript;bla'} + self.assertEquals('application/javascript', r.GetContentType()) + + class RequestTrackTestCase(unittest.TestCase): _REQUEST_WILL_BE_SENT = { 'method': 'Network.requestWillBeSent',
diff --git a/tools/android/loading/trace_recorder.py b/tools/android/loading/trace_recorder.py index 6e638c4..0b96225 100755 --- a/tools/android/loading/trace_recorder.py +++ b/tools/android/loading/trace_recorder.py
@@ -19,46 +19,7 @@ import device_setup import devtools_monitor - - -class PageTrack(devtools_monitor.Track): - """Records the events from the page track.""" - def __init__(self, connection): - super(PageTrack, self).__init__() - self._connection = connection - self._events = [] - self._main_frame_id = None - if self._connection: - self._connection.RegisterListener('Page.frameStartedLoading', self) - self._connection.RegisterListener('Page.frameStoppedLoading', self) - - def Handle(self, method, msg): - params = msg['params'] - frame_id = params['frameId'] - should_stop = False - if method == 'Page.frameStartedLoading' and self._main_frame_id is None: - self._main_frame_id = params['frameId'] - elif (method == 'Page.frameStoppedLoading' - and params['frameId'] == self._main_frame_id): - should_stop = True - self._events.append((method, frame_id)) - if should_stop: - self._connection.StopMonitoring() - - def GetEvents(self): - return self._events - - def ToJsonDict(self): - return {'events': [event for event in self._events]} - - @classmethod - def FromJsonDict(cls, json_dict): - assert 'events' in json_dict - result = PageTrack(None) - events = [event for event in json_dict['events']] - result._events = events - return result - +import page_track class AndroidTraceRecorder(object): """Records a loading trace.""" @@ -67,11 +28,9 @@ self.devtools_connection = None self.page_track = None - def Go(self): - self.devtools_connection = devtools_monitor.DevToolsConnection( - device_setup.DEVTOOLS_HOSTNAME, device_setup.DEVTOOLS_PORT) - self.page_track = PageTrack(self.devtools_connection) - + def Go(self, connection): + self.devtools_connection = connection + self.page_track = page_track.PageTrack(self.devtools_connection) self.devtools_connection.SetUpMonitoring() self.devtools_connection.SendAndIgnoreResponse( 'Page.navigate', {'url': self.url})
diff --git a/tools/android/loading/trace_to_chrome_trace.py b/tools/android/loading/trace_to_chrome_trace.py new file mode 100755 index 0000000..998614f3 --- /dev/null +++ b/tools/android/loading/trace_to_chrome_trace.py
@@ -0,0 +1,23 @@ +#! /usr/bin/python +# 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. + +"""Convert trace output for Chrome. + +Take the tracing track output from tracing_driver.py to a zip'd json that can be +loading by chrome devtools tracing. +""" + +import argparse +import gzip +import json + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('input') + parser.add_argument('output') + args = parser.parse_args() + with gzip.GzipFile(args.output, 'w') as output_f, file(args.input) as input_f: + events = json.load(input_f) + json.dump({'traceEvents': events, 'metadata': {}}, output_f)
diff --git a/tools/android/loading/tracing.py b/tools/android/loading/tracing.py new file mode 100644 index 0000000..83ad38c1 --- /dev/null +++ b/tools/android/loading/tracing.py
@@ -0,0 +1,38 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Monitor tracing events on chrome via chrome remote debugging.""" + +import devtools_monitor + +class TracingTrack(devtools_monitor.Track): + def __init__(self, connection, categories=None, fetch_stream=False): + """Initialize this TracingTrack. + + Args: + connection: a DevToolsConnection. + categories: None, or a string, or list of strings, of tracing categories + to filter. + + fetch_stream: if true, use a websocket stream to fetch tracing data rather + than dataCollected events. It appears based on very limited testing that + a stream is slower than the default reporting as dataCollected events. + """ + super(TracingTrack, self).__init__(connection) + connection.RegisterListener('Tracing.dataCollected', self) + params = {} + if categories: + params['categories'] = (categories if type(categories) is str + else ','.join(categories)) + if fetch_stream: + params['transferMode'] = 'ReturnAsStream' + + connection.SyncRequestNoResponse('Tracing.start', params) + self._events = [] + + def Handle(self, method, event): + self._events.append(event) + + def GetEvents(self): + return self._events
diff --git a/tools/android/loading/tracing_driver.py b/tools/android/loading/tracing_driver.py new file mode 100755 index 0000000..c62e870 --- /dev/null +++ b/tools/android/loading/tracing_driver.py
@@ -0,0 +1,49 @@ +#! /usr/bin/python +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Drive TracingConnection""" + +import argparse +import json +import logging +import os.path +import sys + +_SRC_DIR = os.path.abspath(os.path.join( + os.path.dirname(__file__), '..', '..', '..')) + +sys.path.append(os.path.join(_SRC_DIR, 'third_party', 'catapult', 'devil')) +from devil.android import device_utils + +sys.path.append(os.path.join(_SRC_DIR, 'build', 'android')) +import device_setup +import page_track +import tracing + + +def main(): + logging.basicConfig(level=logging.INFO) + parser = argparse.ArgumentParser() + parser.add_argument('--url', required=True) + parser.add_argument('--output', required=True) + args = parser.parse_args() + url = args.url + if not url.startswith('http'): + url = 'http://' + url + device = device_utils.DeviceUtils.HealthyDevices()[0] + with file(args.output, 'w') as output, \ + file(args.output + '.page', 'w') as page_output, \ + device_setup.DeviceConnection(device) as connection: + track = tracing.TracingTrack(connection, fetch_stream=False) + page = page_track.PageTrack(connection) + connection.SetUpMonitoring() + connection.SendAndIgnoreResponse('Page.navigate', {'url': url}) + connection.StartMonitoring() + json.dump(page.GetEvents(), page_output, sort_keys=True, indent=2) + json.dump(track.GetEvents(), output, sort_keys=True, indent=2) + + +if __name__ == '__main__': + main()
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index ef6ca07..b57259f 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -26,7 +26,7 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://code.google.com/p/chromium/wiki/UpdatingClang # Reverting problematic clang rolls is safe, though. -CLANG_REVISION = '255169' +CLANG_REVISION = '257953' use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ if use_head_revision: @@ -65,7 +65,7 @@ STAMP_FILE = os.path.normpath( os.path.join(LLVM_DIR, '..', 'llvm-build', 'cr_build_revision')) BINUTILS_DIR = os.path.join(THIRD_PARTY_DIR, 'binutils') -VERSION = '3.8.0' +VERSION = '3.9.0' ANDROID_NDK_DIR = os.path.join( CHROMIUM_DIR, 'third_party', 'android_tools', 'ndk') @@ -597,6 +597,8 @@ elif sys.platform.startswith('linux'): RunCommand(['strip', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')]) + # TODO(thakis): Check that `clang --version` matches VERSION. + # Do an out-of-tree build of compiler-rt. # On Windows, this is used to get the 32-bit ASan run-time. # TODO(hans): Remove once the regular build above produces this. @@ -787,11 +789,6 @@ print 'Skipping Clang update (make_clang_dir= was set in GYP_DEFINES).' return 0 - if use_head_revision: - # TODO(hans): Remove after the next roll. - global VERSION - VERSION = '3.9.0' - global CLANG_REVISION, PACKAGE_VERSION if args.print_revision: if use_head_revision:
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 45c6a84..999559c 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -32763,11 +32763,16 @@ </summary> </histogram> -<histogram name="PasswordManager.SyncCredentialFiltered" enum="Boolean"> +<histogram name="PasswordManager.SyncCredentialFiltered" + enum="CredentialFilteredType"> <owner>gcasto@chromium.org</owner> <owner>vabr@chromium.org</owner> <summary> - If the sync credential was removed from autofill consideration. + This histogram is reported for those forms on accounts.google.com, on which + Chrome is forced by Finch/flags during autofilling to remove sync + credentials from password store results. It reports true if sync credentials + were indeed removed from the store results, and false if there were no sync + credentials in the results to begin with. </summary> </histogram> @@ -39207,6 +39212,28 @@ </summary> </histogram> +<histogram name="Renderer4.MainThreadGestureScrollReason" + enum="MainThreadScrollingReason"> + <owner>tdresser@chromium.org</owner> + <summary> + Ideally we'd always scroll on the impl thread, but there are a variety of + situations where we need to scroll on main. We should try to drive these + down. For every gesture, we record whether or not the scroll occurred on the + main thread, and if it did, what the reason was. + </summary> +</histogram> + +<histogram name="Renderer4.MainThreadWheelScrollReason" + enum="MainThreadScrollingReason"> + <owner>tdresser@chromium.org</owner> + <summary> + Ideally we'd always scroll on the impl thread, but there are a variety of + situations where we need to scroll on main. We should try to drive these + down. For every wheel tick, we record whether or not the the scroll occurred + on the main thread, and if it did, what the reason was. + </summary> +</histogram> + <histogram name="Renderer4.pixelCountCulled_Draw" units="NormalizedPixels"> <owner>wiltzius@chromium.org</owner> <summary> @@ -51188,8 +51215,8 @@ </histogram> <histogram name="TryScroll.SlowScroll" enum="ScrollThread"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> - <summary>Whether the scroll is executed on main thread.</summary> + <owner>tdresser@chromium.org</owner> + <summary>Whether a scroll is executed on main thread.</summary> </histogram> <histogram name="UMA.ActualLogUploadInterval" units="minutes"> @@ -59225,6 +59252,9 @@ <int value="7011" label="SBOX_FATAL_MITIGATION"/> <int value="7012" label="SBOX_FATAL_MEMORY_EXCEEDED"/> <int value="7013" label="SBOX_FATAL_WARMUP"/> + <int value="36862" label="Crashpad_FailedToCaptureProcess"/> + <int value="36863" label="Crashpad_HandlerDidNotRespond"/> + <int value="85436397" label="Crashpad_SimulatedCrash"/> <int value="529697949" label="CPP_EH_EXCEPTION"/> <int value="533692099" label="STATUS_GUARD_PAGE_VIOLATION"/> <int value="1073740791" label="STATUS_STACK_BUFFER_OVERRUN"/> @@ -59258,6 +59288,11 @@ <int value="2147483646" label="STATUS_DATATYPE_MISALIGNMENT"/> </enum> +<enum name="CredentialFilteredType" type="int"> + <int value="0" label="No sync credentials present"/> + <int value="1" label="Sync credentials were removed"/> +</enum> + <enum name="CrosBeamformingDeviceState" type="int"> <int value="0" label="Default enabled"/> <int value="1" label="User enabled"/> @@ -69955,6 +69990,22 @@ <int value="1" label="cache-control: no-store"/> </enum> +<enum name="MainThreadScrollingReason" type="int"> + <int value="0" label="Not scrolling on main"/> + <int value="1" label="Background attachment fixed"/> + <int value="2" label="Non layer viewport constrained"/> + <int value="3" label="Threaded scrolling disabled"/> + <int value="4" label="Scrollbar scrolling"/> + <int value="5" label="Page overlay"/> + <int value="6" label="Non-fast scrollable region"/> + <int value="7" label="Event handlers"/> + <int value="8" label="Failed hit test"/> + <int value="9" label="No scrolling layer"/> + <int value="10" label="Not scrollable"/> + <int value="11" label="Continuing main thread scroll"/> + <int value="12" label="Non-invertible transform"/> +</enum> + <enum name="MakeChromeDefaultResult" type="int"> <int value="0" label="Chrome made default"/> <int value="1" label="Dialog closed without explicit choice"/> @@ -80701,6 +80752,8 @@ <int value="-1073740777" label="0xC0000417 - STATUS_INVALID_CRUNTIME_PARAMETER"/> <int value="-805306369" label="0xCFFFFFFF - Hung browser killed."/> + <int value="-36863" label="0xFFFF7001 - Crashpad kCrashExitCodeNoDump."/> + <int value="-36862" label="0xFFFF7002 - Crashpad kFailedTerminationCode."/> <int value="0" label="content::RESULT_CODE_NORMAL_EXIT"/> <int value="1" label="content::RESULT_CODE_KILLED"/> <int value="2" label="content::RESULT_CODE_HUNG"/> @@ -80733,6 +80786,7 @@ <int value="29" label="chrome::RESULT_CODE_ACTION_DISALLOWED_BY_POLICY"/> <int value="30" label="chrome::RESULT_CODE_INVALID_SANDBOX_STATE"/> <int value="259" label="0x103 - STILL_ACTIVE."/> + <int value="85436397" label="0x517a7ed - Crashpad simulated exception"/> <int value="1073807364" label="0x40010004 - DBG_TERMINATE_PROCESS"/> </enum>
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt index eae9dcb..fd1d3a5 100644 --- a/tools/valgrind/drmemory/suppressions_full.txt +++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -2103,8 +2103,6 @@ content.dll!content::RenderWidgetHostImpl::SetIsLoading content.dll!content::RenderFrameHostManager::SetIsLoading content.dll!content::WebContentsImpl::SetIsLoading -content.dll!content::WebContentsImpl::DidStopLoading -content.dll!content::FrameTreeNode::DidStopLoading HANDLE LEAK name=bug_571554_a
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt index 73d9fa0e..4deeac34 100644 --- a/tools/valgrind/memcheck/suppressions.txt +++ b/tools/valgrind/memcheck/suppressions.txt
@@ -935,7 +935,7 @@ fun:_ZN14GpuProcessHost4InitEv } { - bug_67261 + bug_67261a Memcheck:Leak fun:_Znw* ... @@ -944,6 +944,16 @@ fun:_ZN8appcache16AppCacheDatabase22PrepareCachedStatementERKN3sql11StatementIDEPKcPNS1_9StatementE } { + bug_67261b + Memcheck:Leak + fun:_Znw* + fun:_ZN3sql10Connection18GetUniqueStatementEPKc + fun:_ZN3sql10Connection18GetCachedStatementERKNS_11StatementIDEPKc + fun:_ZN3sql9MetaTable19PrepareGetStatementEPNS_9StatementEPKc + fun:_ZN3sql9MetaTable8GetValueEPKcPi + fun:_ZN7storage13QuotaDatabase28IsOriginDatabaseBootstrappedEv +} +{ bug_67553 Memcheck:Leak fun:_Znw*
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn index 6f112e67..dfe5349 100644 --- a/ui/aura/BUILD.gn +++ b/ui/aura/BUILD.gn
@@ -68,8 +68,6 @@ "layout_manager.h", "mus/mus_util.cc", "mus/mus_util.h", - "remote_window_tree_host_win.cc", - "remote_window_tree_host_win.h", "scoped_window_targeter.cc", "scoped_window_targeter.h", "window.cc",
diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp index 12230e2..e338d3a 100644 --- a/ui/aura/aura.gyp +++ b/ui/aura/aura.gyp
@@ -88,8 +88,6 @@ 'input_state_lookup_win.h', 'layout_manager.cc', 'layout_manager.h', - 'remote_window_tree_host_win.cc', - 'remote_window_tree_host_win.h', 'scoped_window_targeter.cc', 'scoped_window_targeter.h', 'window.cc',
diff --git a/ui/aura/remote_window_tree_host_win.cc b/ui/aura/remote_window_tree_host_win.cc deleted file mode 100644 index a303d98..0000000 --- a/ui/aura/remote_window_tree_host_win.cc +++ /dev/null
@@ -1,522 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/remote_window_tree_host_win.h" - -#include <windows.h> -#include <stddef.h> - -#include <algorithm> - -#include "base/message_loop/message_loop.h" -#include "ipc/ipc_message.h" -#include "ipc/ipc_sender.h" -#include "ui/aura/client/cursor_client.h" -#include "ui/aura/window_event_dispatcher.h" -#include "ui/aura/window_property.h" -#include "ui/base/cursor/cursor_loader_win.h" -#include "ui/base/ime/composition_text.h" -#include "ui/base/ime/input_method.h" -#include "ui/base/ime/remote_input_method_win.h" -#include "ui/base/ime/text_input_client.h" -#include "ui/base/view_prop.h" -#include "ui/events/event_utils.h" -#include "ui/events/keycodes/keyboard_code_conversion_win.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/win/dpi.h" -#include "ui/metro_viewer/metro_viewer_messages.h" - -namespace aura { - -namespace { - -const char* kWindowTreeHostWinKey = "__AURA_REMOTE_WINDOW_TREE_HOST_WIN__"; - -// Sets the keystate for the virtual key passed in to down or up. -void SetKeyState(uint8_t* key_states, - bool key_down, - uint32_t virtual_key_code) { - DCHECK(key_states); - - if (key_down) - key_states[virtual_key_code] |= 0x80; - else - key_states[virtual_key_code] &= 0x7F; -} - -// Sets the keyboard states for the Shift/Control/Alt/Caps lock keys. -void SetVirtualKeyStates(uint32_t flags) { - uint8_t keyboard_state[256] = {0}; - ::GetKeyboardState(keyboard_state); - - SetKeyState(keyboard_state, !!(flags & ui::EF_SHIFT_DOWN), VK_SHIFT); - SetKeyState(keyboard_state, !!(flags & ui::EF_CONTROL_DOWN), VK_CONTROL); - SetKeyState(keyboard_state, !!(flags & ui::EF_ALT_DOWN), VK_MENU); - SetKeyState(keyboard_state, !!(flags & ui::EF_CAPS_LOCK_ON), VK_CAPITAL); - SetKeyState(keyboard_state, !!(flags & ui::EF_LEFT_MOUSE_BUTTON), VK_LBUTTON); - SetKeyState(keyboard_state, !!(flags & ui::EF_RIGHT_MOUSE_BUTTON), - VK_RBUTTON); - SetKeyState(keyboard_state, !!(flags & ui::EF_MIDDLE_MOUSE_BUTTON), - VK_MBUTTON); - - ::SetKeyboardState(keyboard_state); -} - -void FillCompositionText( - const base::string16& text, - int32_t selection_start, - int32_t selection_end, - const std::vector<metro_viewer::UnderlineInfo>& underlines, - ui::CompositionText* composition_text) { - composition_text->Clear(); - composition_text->text = text; - composition_text->selection.set_start(selection_start); - composition_text->selection.set_end(selection_end); - composition_text->underlines.resize(underlines.size()); - for (size_t i = 0; i < underlines.size(); ++i) { - composition_text->underlines[i].start_offset = underlines[i].start_offset; - composition_text->underlines[i].end_offset = underlines[i].end_offset; - composition_text->underlines[i].color = SK_ColorBLACK; - composition_text->underlines[i].thick = underlines[i].thick; - composition_text->underlines[i].background_color = SK_ColorTRANSPARENT; - } -} - -} // namespace - -RemoteWindowTreeHostWin* g_instance = NULL; - -// static -RemoteWindowTreeHostWin* RemoteWindowTreeHostWin::Instance() { - return g_instance; -} - -RemoteWindowTreeHostWin::RemoteWindowTreeHostWin() - : remote_window_(NULL), - host_(NULL), - ignore_mouse_moves_until_set_cursor_ack_(0), - event_flags_(0), - window_size_(GetSystemMetrics(SM_CXSCREEN), - GetSystemMetrics(SM_CYSCREEN)) { - CHECK(!g_instance); - g_instance = this; - prop_.reset(new ui::ViewProp(NULL, kWindowTreeHostWinKey, this)); - CreateCompositor(); - OnAcceleratedWidgetAvailable(); -} - -RemoteWindowTreeHostWin::~RemoteWindowTreeHostWin() { - DestroyCompositor(); - DestroyDispatcher(); - DCHECK_EQ(g_instance, this); - g_instance = NULL; -} - -// static -bool RemoteWindowTreeHostWin::IsValid() { - return Instance()->remote_window_ != NULL; -} - -void RemoteWindowTreeHostWin::SetRemoteWindowHandle(HWND remote_window) { - remote_window_ = remote_window; -} - -void RemoteWindowTreeHostWin::Connected(IPC::Sender* host) { - CHECK(host_ == NULL); - DCHECK(remote_window_); - host_ = host; - // Recreate the compositor for the target surface represented by the - // remote_window HWND. - CreateCompositor(); - OnAcceleratedWidgetAvailable(); - InitCompositor(); -} - -void RemoteWindowTreeHostWin::Disconnected() { - // Don't CHECK here, Disconnected is called on a channel error which can - // happen before we're successfully Connected. - if (!host_) - return; - ui::RemoteInputMethodPrivateWin* remote_input_method_private = - GetRemoteInputMethodPrivate(); - if (remote_input_method_private) - remote_input_method_private->SetRemoteDelegate(NULL); - host_ = NULL; - remote_window_ = NULL; -} - -bool RemoteWindowTreeHostWin::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(RemoteWindowTreeHostWin, message) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseMoved, OnMouseMoved) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseButton, OnMouseButton) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyDown, OnKeyDown) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyUp, OnKeyUp) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_Character, OnChar) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowActivated, - OnWindowActivated) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_EdgeGesture, OnEdgeGesture) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchDown, - OnTouchDown) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchUp, - OnTouchUp) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchMoved, - OnTouchMoved) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPosAck, - OnSetCursorPosAck) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCandidatePopupChanged, - OnImeCandidatePopupChanged) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCompositionChanged, - OnImeCompositionChanged) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextCommitted, - OnImeTextCommitted) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeInputSourceChanged, - OnImeInputSourceChanged) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void RemoteWindowTreeHostWin::HandleOpenURLOnDesktop( - const base::FilePath& shortcut, - const base::string16& url) { - if (!host_) - return; - host_->Send(new MetroViewerHostMsg_OpenURLOnDesktop(shortcut, url)); -} - -void RemoteWindowTreeHostWin::HandleWindowSizeChanged(uint32_t width, - uint32_t height) { - SetBounds(gfx::Rect(0, 0, width, height)); -} - -bool RemoteWindowTreeHostWin::IsForegroundWindow() { - return ::GetForegroundWindow() == remote_window_; -} - -Window* RemoteWindowTreeHostWin::GetAshWindow() { - return window(); -} - -ui::EventSource* RemoteWindowTreeHostWin::GetEventSource() { - return this; -} - -gfx::AcceleratedWidget RemoteWindowTreeHostWin::GetAcceleratedWidget() { - if (remote_window_) - return remote_window_; - // Getting here should only happen for ash_unittests.exe and related code. - return ::GetDesktopWindow(); -} - -void RemoteWindowTreeHostWin::ShowImpl() { - ui::RemoteInputMethodPrivateWin* remote_input_method_private = - GetRemoteInputMethodPrivate(); - if (remote_input_method_private) - remote_input_method_private->SetRemoteDelegate(this); -} - -void RemoteWindowTreeHostWin::HideImpl() { - NOTIMPLEMENTED(); -} - -gfx::Rect RemoteWindowTreeHostWin::GetBounds() const { - return gfx::Rect(window_size_); -} - -void RemoteWindowTreeHostWin::SetBounds(const gfx::Rect& bounds) { - window_size_ = bounds.size(); - OnHostResized(bounds.size()); -} - -gfx::Point RemoteWindowTreeHostWin::GetLocationOnNativeScreen() const { - return gfx::Point(0, 0); -} - -void RemoteWindowTreeHostWin::SetCapture() { -} - -void RemoteWindowTreeHostWin::ReleaseCapture() { -} - -void RemoteWindowTreeHostWin::SetCursorNative(gfx::NativeCursor native_cursor) { - if (!host_) - return; - host_->Send( - new MetroViewerHostMsg_SetCursor(uint64_t(native_cursor.platform()))); -} - -void RemoteWindowTreeHostWin::MoveCursorToNative(const gfx::Point& location) { - VLOG(1) << "In MoveCursorTo: " << location.x() << ", " << location.y(); - if (!host_) - return; - - // This function can be called in cases like when the mouse cursor is - // restricted within a viewport (For e.g. LockCursor) which assumes that - // subsequent mouse moves would be received starting with the new cursor - // coordinates. This is a challenge for Windows ASH for the reasons - // outlined below. - // Other cases which don't expect this behavior should continue to work - // without issues. - - // The mouse events are received by the viewer process and sent to the - // browser. If we invoke the SetCursor API here we continue to receive - // mouse messages from the viewer which were posted before the SetCursor - // API executes which messes up the state in the browser. To workaround - // this we invoke the SetCursor API in the viewer process and ignore - // mouse messages until we received an ACK from the viewer indicating that - // the SetCursor operation completed. - ignore_mouse_moves_until_set_cursor_ack_++; - VLOG(1) << "In MoveCursorTo. Sending IPC"; - host_->Send(new MetroViewerHostMsg_SetCursorPos(location.x(), location.y())); -} - -void RemoteWindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) { - NOTIMPLEMENTED(); -} - -void RemoteWindowTreeHostWin::CancelComposition() { - if (!host_) - return; - host_->Send(new MetroViewerHostMsg_ImeCancelComposition); -} - -void RemoteWindowTreeHostWin::OnTextInputClientUpdated( - const std::vector<int32_t>& input_scopes, - const std::vector<gfx::Rect>& composition_character_bounds) { - if (!host_) - return; - std::vector<metro_viewer::CharacterBounds> character_bounds; - for (size_t i = 0; i < composition_character_bounds.size(); ++i) { - const gfx::Rect& rect = composition_character_bounds[i]; - metro_viewer::CharacterBounds bounds; - bounds.left = rect.x(); - bounds.top = rect.y(); - bounds.right = rect.right(); - bounds.bottom = rect.bottom(); - character_bounds.push_back(bounds); - } - host_->Send(new MetroViewerHostMsg_ImeTextInputClientUpdated( - input_scopes, character_bounds)); -} - -gfx::Point PointFromNativeEvent(int32_t x, int32_t y) { - static float scale_factor = gfx::GetDPIScale(); - gfx::Point result( x * scale_factor, y * scale_factor); - return result; -} - -void RemoteWindowTreeHostWin::OnMouseMoved(int32_t x, - int32_t y, - int32_t flags) { - if (ignore_mouse_moves_until_set_cursor_ack_) - return; - - gfx::Point location = PointFromNativeEvent(x, y); - ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location, - ui::EventTimeForNow(), flags, 0); - SendEventToProcessor(&event); -} - -void RemoteWindowTreeHostWin::OnMouseButton( - const MetroViewerHostMsg_MouseButtonParams& params) { - gfx::Point location = PointFromNativeEvent(params.x, params.y); - ui::MouseEvent mouse_event( - params.event_type, location, location, ui::EventTimeForNow(), - static_cast<int>(params.flags), static_cast<int>(params.changed_button)); - - SetEventFlags(params.flags | key_event_flags()); - if (params.event_type == ui::ET_MOUSEWHEEL) { - int x_offset = params.is_horizontal_wheel ? params.extra : 0; - int y_offset = !params.is_horizontal_wheel ? params.extra : 0; - ui::MouseWheelEvent wheel_event(mouse_event, x_offset, y_offset); - SendEventToProcessor(&wheel_event); - } else if (params.event_type == ui::ET_MOUSE_PRESSED) { - // TODO(shrikant): Ideally modify code in event.cc by adding automatic - // tracking of double clicks in synthetic MouseEvent constructor code. - // Non-synthetic MouseEvent constructor code does automatically track - // this. Need to use some caution while modifying synthetic constructor - // as many tests and other code paths depend on it and apparently - // specifically depend on non implicit tracking of previous mouse event. - if (last_mouse_click_event_ && - ui::MouseEvent::IsRepeatedClickEvent(mouse_event, - *last_mouse_click_event_)) { - mouse_event.SetClickCount(2); - } else { - mouse_event.SetClickCount(1); - } - last_mouse_click_event_ .reset(new ui::MouseEvent(mouse_event)); - SendEventToProcessor(&mouse_event); - } else { - SendEventToProcessor(&mouse_event); - } -} - -void RemoteWindowTreeHostWin::OnKeyDown(uint32_t vkey, - uint32_t repeat_count, - uint32_t scan_code, - uint32_t flags) { - DispatchKeyboardMessage(ui::ET_KEY_PRESSED, vkey, repeat_count, scan_code, - flags, false); -} - -void RemoteWindowTreeHostWin::OnKeyUp(uint32_t vkey, - uint32_t repeat_count, - uint32_t scan_code, - uint32_t flags) { - DispatchKeyboardMessage(ui::ET_KEY_RELEASED, vkey, repeat_count, scan_code, - flags, false); -} - -void RemoteWindowTreeHostWin::OnChar(uint32_t key_code, - uint32_t repeat_count, - uint32_t scan_code, - uint32_t flags) { - DispatchKeyboardMessage(ui::ET_KEY_PRESSED, key_code, repeat_count, - scan_code, flags, true); -} - -void RemoteWindowTreeHostWin::OnWindowActivated(bool repaint) { - OnHostActivated(); - if (repaint && compositor()) - compositor()->ScheduleFullRedraw(); -} - -void RemoteWindowTreeHostWin::OnEdgeGesture() { - ui::GestureEvent event( - 0, - 0, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_WIN8_EDGE_SWIPE)); - SendEventToProcessor(&event); -} - -void RemoteWindowTreeHostWin::OnTouchDown(int32_t x, - int32_t y, - uint64_t timestamp, - uint32_t pointer_id) { - gfx::Point location = PointFromNativeEvent(x, y); - ui::TouchEvent event(ui::ET_TOUCH_PRESSED, - location, - pointer_id, - base::TimeDelta::FromMicroseconds(timestamp)); - SendEventToProcessor(&event); -} - -void RemoteWindowTreeHostWin::OnTouchUp(int32_t x, - int32_t y, - uint64_t timestamp, - uint32_t pointer_id) { - gfx::Point location = PointFromNativeEvent(x, y); - ui::TouchEvent event(ui::ET_TOUCH_RELEASED, - location, - pointer_id, - base::TimeDelta::FromMicroseconds(timestamp)); - SendEventToProcessor(&event); -} - -void RemoteWindowTreeHostWin::OnTouchMoved(int32_t x, - int32_t y, - uint64_t timestamp, - uint32_t pointer_id) { - gfx::Point location = PointFromNativeEvent(x, y); - ui::TouchEvent event(ui::ET_TOUCH_MOVED, - location, - pointer_id, - base::TimeDelta::FromMicroseconds(timestamp)); - SendEventToProcessor(&event); -} - -void RemoteWindowTreeHostWin::OnSetCursorPosAck() { - DCHECK_GT(ignore_mouse_moves_until_set_cursor_ack_, 0); - ignore_mouse_moves_until_set_cursor_ack_--; -} - -ui::RemoteInputMethodPrivateWin* -RemoteWindowTreeHostWin::GetRemoteInputMethodPrivate() { - return ui::RemoteInputMethodPrivateWin::Get(GetInputMethod()); -} - -void RemoteWindowTreeHostWin::OnImeCandidatePopupChanged(bool visible) { - ui::RemoteInputMethodPrivateWin* remote_input_method_private = - GetRemoteInputMethodPrivate(); - if (!remote_input_method_private) - return; - remote_input_method_private->OnCandidatePopupChanged(visible); -} - -void RemoteWindowTreeHostWin::OnImeCompositionChanged( - const base::string16& text, - int32_t selection_start, - int32_t selection_end, - const std::vector<metro_viewer::UnderlineInfo>& underlines) { - ui::RemoteInputMethodPrivateWin* remote_input_method_private = - GetRemoteInputMethodPrivate(); - if (!remote_input_method_private) - return; - ui::CompositionText composition_text; - FillCompositionText( - text, selection_start, selection_end, underlines, &composition_text); - remote_input_method_private->OnCompositionChanged(composition_text); -} - -void RemoteWindowTreeHostWin::OnImeTextCommitted(const base::string16& text) { - ui::RemoteInputMethodPrivateWin* remote_input_method_private = - GetRemoteInputMethodPrivate(); - if (!remote_input_method_private) - return; - remote_input_method_private->OnTextCommitted(text); -} - -void RemoteWindowTreeHostWin::OnImeInputSourceChanged(uint16_t language_id, - bool is_ime) { - ui::RemoteInputMethodPrivateWin* remote_input_method_private = - GetRemoteInputMethodPrivate(); - if (!remote_input_method_private) - return; - remote_input_method_private->OnInputSourceChanged(language_id, is_ime); -} - -void RemoteWindowTreeHostWin::DispatchKeyboardMessage(ui::EventType type, - uint32_t vkey, - uint32_t repeat_count, - uint32_t scan_code, - uint32_t flags, - bool is_character) { - SetEventFlags(flags | mouse_event_flags()); - if (base::MessageLoop::current()->IsNested()) { - int index = (flags & ui::EF_ALT_DOWN) ? 1 : 0; - const int char_message[] = {WM_CHAR, WM_SYSCHAR}; - const int keydown_message[] = {WM_KEYDOWN, WM_SYSKEYDOWN}; - const int keyup_message[] = {WM_KEYUP, WM_SYSKEYUP}; - uint32_t message = - is_character ? char_message[index] - : (type == ui::ET_KEY_PRESSED ? keydown_message[index] - : keyup_message[index]); - ::PostThreadMessage(::GetCurrentThreadId(), - message, - vkey, - repeat_count | scan_code >> 15); - } else if (is_character) { - ui::KeyEvent event(static_cast<base::char16>(vkey), - ui::KeyboardCodeForWindowsKeyCode(vkey), - flags); - SendEventToProcessor(&event); - } else { - ui::KeyEvent event(type, - ui::KeyboardCodeForWindowsKeyCode(vkey), - flags); - SendEventToProcessor(&event); - } -} - -void RemoteWindowTreeHostWin::SetEventFlags(uint32_t flags) { - if (flags == event_flags_) - return; - event_flags_ = flags; - SetVirtualKeyStates(event_flags_); -} - -} // namespace aura
diff --git a/ui/aura/remote_window_tree_host_win.h b/ui/aura/remote_window_tree_host_win.h deleted file mode 100644 index 4614fd6e..0000000 --- a/ui/aura/remote_window_tree_host_win.h +++ /dev/null
@@ -1,197 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_ -#define UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_ - -#include <stdint.h> - -#include <vector> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/strings/string16.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/ime/remote_input_method_delegate_win.h" -#include "ui/events/event.h" -#include "ui/events/event_constants.h" -#include "ui/events/event_source.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/metro_viewer/ime_types.h" - -struct MetroViewerHostMsg_MouseButtonParams; - -namespace base { -class FilePath; -} - -namespace ui { -class RemoteInputMethodPrivateWin; -class ViewProp; -} - -namespace IPC { -class Message; -class Sender; -} - -namespace aura { - -// WindowTreeHost implementaton that receives events from a different -// process. In the case of Windows this is the Windows 8 (aka Metro) -// frontend process, which forwards input events to this class. -class AURA_EXPORT RemoteWindowTreeHostWin - : public WindowTreeHost, - public ui::internal::RemoteInputMethodDelegateWin { - public: - // Returns the current RemoteWindowTreeHostWin. This does *not* create a - // RemoteWindowTreeHostWin. - static RemoteWindowTreeHostWin* Instance(); - - // Returns true if there is a RemoteWindowTreeHostWin and it has a valid - // HWND. A return value of false typically indicates we're not in metro mode. - static bool IsValid(); - - // Sets the handle to the remote window. The |remote_window| is the actual - // window owned by the viewer process. Call this before Connected() for some - // customers like input method initialization which needs the handle. - void SetRemoteWindowHandle(HWND remote_window); - HWND remote_window() { return remote_window_; } - - // The |host| can be used when we need to send a message to it. - void Connected(IPC::Sender* host); - // Called when the remote process has closed its IPC connection. - void Disconnected(); - - // Called when we have a message from the remote process. - bool OnMessageReceived(const IPC::Message& message); - - void HandleOpenURLOnDesktop(const base::FilePath& shortcut, - const base::string16& url); - - void HandleWindowSizeChanged(uint32_t width, uint32_t height); - - // Returns the active ASH root window. - Window* GetAshWindow(); - - // Returns true if the remote window is the foreground window according to the - // OS. - bool IsForegroundWindow(); - - protected: - RemoteWindowTreeHostWin(); - ~RemoteWindowTreeHostWin() override; - - private: - // IPC message handing methods: - void OnMouseMoved(int32_t x, int32_t y, int32_t flags); - void OnMouseButton(const MetroViewerHostMsg_MouseButtonParams& params); - void OnKeyDown(uint32_t vkey, - uint32_t repeat_count, - uint32_t scan_code, - uint32_t flags); - void OnKeyUp(uint32_t vkey, - uint32_t repeat_count, - uint32_t scan_code, - uint32_t flags); - void OnChar(uint32_t key_code, - uint32_t repeat_count, - uint32_t scan_code, - uint32_t flags); - void OnWindowActivated(bool repaint); - void OnEdgeGesture(); - void OnTouchDown(int32_t x, - int32_t y, - uint64_t timestamp, - uint32_t pointer_id); - void OnTouchUp(int32_t x, int32_t y, uint64_t timestamp, uint32_t pointer_id); - void OnTouchMoved(int32_t x, - int32_t y, - uint64_t timestamp, - uint32_t pointer_id); - void OnSetCursorPosAck(); - - // For Input Method support: - ui::RemoteInputMethodPrivateWin* GetRemoteInputMethodPrivate(); - void OnImeCandidatePopupChanged(bool visible); - void OnImeCompositionChanged( - const base::string16& text, - int32_t selection_start, - int32_t selection_end, - const std::vector<metro_viewer::UnderlineInfo>& underlines); - void OnImeTextCommitted(const base::string16& text); - void OnImeInputSourceChanged(uint16_t language_id, bool is_ime); - - // WindowTreeHost overrides: - ui::EventSource* GetEventSource() override; - gfx::AcceleratedWidget GetAcceleratedWidget() override; - void ShowImpl() override; - void HideImpl() override; - gfx::Rect GetBounds() const override; - void SetBounds(const gfx::Rect& bounds) override; - gfx::Point GetLocationOnNativeScreen() const override; - void SetCapture() override; - void ReleaseCapture() override; - void SetCursorNative(gfx::NativeCursor cursor) override; - void MoveCursorToNative(const gfx::Point& location) override; - void OnCursorVisibilityChangedNative(bool show) override; - - // ui::internal::RemoteInputMethodDelegateWin overrides: - void CancelComposition() override; - void OnTextInputClientUpdated( - const std::vector<int32_t>& input_scopes, - const std::vector<gfx::Rect>& composition_character_bounds) override; - - // Helper function to dispatch a keyboard message to the desired target. - // The default target is the WindowEventDispatcher. For nested message loop - // invocations we post a synthetic keyboard message directly into the message - // loop. The dispatcher for the nested loop would then decide how this - // message is routed. - void DispatchKeyboardMessage(ui::EventType type, - uint32_t vkey, - uint32_t repeat_count, - uint32_t scan_code, - uint32_t flags, - bool is_character); - - // Sets the event flags. |flags| is a bitmask of EventFlags. If there is a - // change the system virtual key state is updated as well. This way if chrome - // queries for key state it matches that of event being dispatched. - void SetEventFlags(uint32_t flags); - - uint32_t mouse_event_flags() const { - return event_flags_ & (ui::EF_LEFT_MOUSE_BUTTON | - ui::EF_MIDDLE_MOUSE_BUTTON | - ui::EF_RIGHT_MOUSE_BUTTON); - } - - uint32_t key_event_flags() const { - return event_flags_ & (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | - ui::EF_ALT_DOWN | ui::EF_CAPS_LOCK_ON); - } - - HWND remote_window_; - IPC::Sender* host_; - scoped_ptr<ui::ViewProp> prop_; - - // Incremented if we need to ignore mouse messages until the SetCursorPos - // operation is acked by the viewer. - int ignore_mouse_moves_until_set_cursor_ack_; - - // Tracking last click event for synthetically generated mouse events. - scoped_ptr<ui::MouseEvent> last_mouse_click_event_; - - // State of the keyboard/mouse at the time of the last input event. See - // description of SetEventFlags(). - uint32_t event_flags_; - - // Current size of this root window. - gfx::Size window_size_; - - DISALLOW_COPY_AND_ASSIGN(RemoteWindowTreeHostWin); -}; - -} // namespace aura - -#endif // UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index 6190b065..e2fa018 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn
@@ -743,7 +743,6 @@ "ime/composition_text_unittest.cc", "ime/input_method_base_unittest.cc", "ime/input_method_chromeos_unittest.cc", - "ime/remote_input_method_win_unittest.cc", "ime/win/imm32_manager_unittest.cc", "ime/win/tsf_input_scope_unittest.cc", ]
diff --git a/ui/base/ime/BUILD.gn b/ui/base/ime/BUILD.gn index f729482..9cf4606b 100644 --- a/ui/base/ime/BUILD.gn +++ b/ui/base/ime/BUILD.gn
@@ -83,9 +83,6 @@ "linux/linux_input_method_context_factory.h", "mock_input_method.cc", "mock_input_method.h", - "remote_input_method_delegate_win.h", - "remote_input_method_win.cc", - "remote_input_method_win.h", "text_input_client.cc", "text_input_client.h", "text_input_type.h",
diff --git a/ui/base/ime/input_method_factory.cc b/ui/base/ime/input_method_factory.cc index dd9d31a..1fda6daa 100644 --- a/ui/base/ime/input_method_factory.cc +++ b/ui/base/ime/input_method_factory.cc
@@ -11,7 +11,6 @@ #include "ui/base/ime/input_method_chromeos.h" #elif defined(OS_WIN) #include "ui/base/ime/input_method_win.h" -#include "ui/base/ime/remote_input_method_win.h" #elif defined(OS_MACOSX) #include "ui/base/ime/input_method_mac.h" #elif defined(USE_AURA) && defined(OS_LINUX) && defined(USE_X11) && \ @@ -53,8 +52,6 @@ #if defined(OS_CHROMEOS) return make_scoped_ptr(new InputMethodChromeOS(delegate)); #elif defined(OS_WIN) - if (IsRemoteInputMethodWinRequired(widget)) - return CreateRemoteInputMethodWin(delegate); return make_scoped_ptr(new InputMethodWin(delegate, widget)); #elif defined(OS_MACOSX) return make_scoped_ptr(new InputMethodMac(delegate));
diff --git a/ui/base/ime/remote_input_method_delegate_win.h b/ui/base/ime/remote_input_method_delegate_win.h deleted file mode 100644 index a172c7b5..0000000 --- a/ui/base/ime/remote_input_method_delegate_win.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_BASE_IME_REMOTE_INPUT_METHOD_DELEGATE_WIN_H_ -#define UI_BASE_IME_REMOTE_INPUT_METHOD_DELEGATE_WIN_H_ - -#include <stdint.h> - -#include <vector> - -#include "ui/base/ime/ui_base_ime_export.h" -#include "ui/gfx/geometry/rect.h" - -namespace ui { -namespace internal { - -// An interface implemented by the object to forward events that should be -// handled by the IME which is running in the remote metro_driver process. -class UI_BASE_IME_EXPORT RemoteInputMethodDelegateWin { - public: - virtual ~RemoteInputMethodDelegateWin() {} - - // Notifies that composition should be canceled (if any). - virtual void CancelComposition() = 0; - - // Notifies that properties of the focused TextInputClient is changed. - // Note that an empty |input_scopes| represents that TextInputType is - // TEXT_INPUT_TYPE_NONE. - // Caveats: |input_scopes| is defined as std::vector<int32_t> rather than - // std::vector<InputScope> because the wire format of IPC message - // MetroViewerHostMsg_ImeTextInputClientUpdated uses std::vector<int32_t> to - // avoid dependency on <InputScope.h> header. - virtual void OnTextInputClientUpdated( - const std::vector<int32_t>& input_scopes, - const std::vector<gfx::Rect>& composition_character_bounds) = 0; -}; - -} // namespace internal -} // namespace ui - -#endif // UI_BASE_IME_REMOTE_INPUT_METHOD_DELEGATE_WIN_H_
diff --git a/ui/base/ime/remote_input_method_win.cc b/ui/base/ime/remote_input_method_win.cc deleted file mode 100644 index 27d242a..0000000 --- a/ui/base/ime/remote_input_method_win.cc +++ /dev/null
@@ -1,385 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/base/ime/remote_input_method_win.h" - -#include <stddef.h> -#include <stdint.h> - -#include "base/command_line.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/scoped_handle.h" -#include "ui/base/ime/input_method.h" -#include "ui/base/ime/input_method_delegate.h" -#include "ui/base/ime/input_method_observer.h" -#include "ui/base/ime/remote_input_method_delegate_win.h" -#include "ui/base/ime/text_input_client.h" -#include "ui/base/ime/win/tsf_input_scope.h" -#include "ui/base/ui_base_switches.h" -#include "ui/events/event.h" -#include "ui/events/event_utils.h" -#include "ui/gfx/geometry/rect.h" - -namespace ui { -namespace { - -const LANGID kFallbackLangID = - MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT); - -InputMethod* g_public_interface_ = NULL; -RemoteInputMethodPrivateWin* g_private_interface_ = NULL; - -void RegisterInstance(InputMethod* public_interface, - RemoteInputMethodPrivateWin* private_interface) { - CHECK(g_public_interface_ == NULL) - << "Only one instance is supported at the same time"; - CHECK(g_private_interface_ == NULL) - << "Only one instance is supported at the same time"; - g_public_interface_ = public_interface; - g_private_interface_ = private_interface; -} - -RemoteInputMethodPrivateWin* GetPrivate(InputMethod* public_interface) { - if (g_public_interface_ != public_interface) - return NULL; - return g_private_interface_; -} - -void UnregisterInstance(InputMethod* public_interface) { - RemoteInputMethodPrivateWin* private_interface = GetPrivate(public_interface); - if (g_public_interface_ == public_interface && - g_private_interface_ == private_interface) { - g_public_interface_ = NULL; - g_private_interface_ = NULL; - } -} - -std::string GetLocaleString(LCID Locale_id, LCTYPE locale_type) { - wchar_t buffer[16] = {}; - - //|chars_written| includes NUL terminator. - const int chars_written = - GetLocaleInfo(Locale_id, locale_type, buffer, arraysize(buffer)); - if (chars_written <= 1 || static_cast<int>(arraysize(buffer)) < chars_written) - return std::string(); - std::string result; - base::WideToUTF8(buffer, chars_written - 1, &result); - return result; -} - -std::vector<int32_t> GetInputScopesAsInt(TextInputType text_input_type, - TextInputMode text_input_mode) { - std::vector<int32_t> result; - // An empty vector represents |text_input_type| is TEXT_INPUT_TYPE_NONE. - if (text_input_type == TEXT_INPUT_TYPE_NONE) - return result; - - const std::vector<InputScope>& input_scopes = - tsf_inputscope::GetInputScopes(text_input_type, text_input_mode); - result.reserve(input_scopes.size()); - for (size_t i = 0; i < input_scopes.size(); ++i) - result.push_back(static_cast<int32_t>(input_scopes[i])); - return result; -} - -std::vector<gfx::Rect> GetCompositionCharacterBounds( - const TextInputClient* client) { - if (!client) - return std::vector<gfx::Rect>(); - - std::vector<gfx::Rect> bounds; - if (client->HasCompositionText()) { - gfx::Range range; - if (client->GetCompositionTextRange(&range)) { - for (uint32_t i = 0; i < range.length(); ++i) { - gfx::Rect rect; - if (!client->GetCompositionCharacterBounds(i, &rect)) - break; - bounds.push_back(rect); - } - } - } - - // Use the caret bounds as a fallback if no composition character bounds is - // available. One typical use case is PPAPI Flash, which does not support - // GetCompositionCharacterBounds at all. crbug.com/133472 - if (bounds.empty()) - bounds.push_back(client->GetCaretBounds()); - return bounds; -} - -class RemoteInputMethodWin : public InputMethod, - public RemoteInputMethodPrivateWin { - public: - explicit RemoteInputMethodWin(internal::InputMethodDelegate* delegate) - : delegate_(delegate), - remote_delegate_(NULL), - text_input_client_(NULL), - is_candidate_popup_open_(false), - is_ime_(false), - langid_(kFallbackLangID) { - RegisterInstance(this, this); - } - - ~RemoteInputMethodWin() override { - FOR_EACH_OBSERVER(InputMethodObserver, - observer_list_, - OnInputMethodDestroyed(this)); - UnregisterInstance(this); - } - - private: - // Overridden from InputMethod: - void SetDelegate(internal::InputMethodDelegate* delegate) override { - delegate_ = delegate; - } - - void OnFocus() override {} - - void OnBlur() override {} - - bool OnUntranslatedIMEMessage(const base::NativeEvent& event, - NativeEventResult* result) override { - return false; - } - - void SetFocusedTextInputClient(TextInputClient* client) override { - std::vector<int32_t> prev_input_scopes; - std::swap(input_scopes_, prev_input_scopes); - std::vector<gfx::Rect> prev_bounds; - std::swap(composition_character_bounds_, prev_bounds); - if (client) { - input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(), - client->GetTextInputMode()); - composition_character_bounds_ = GetCompositionCharacterBounds(client); - } - - const bool text_input_client_changed = text_input_client_ != client; - text_input_client_ = client; - if (text_input_client_changed) { - FOR_EACH_OBSERVER(InputMethodObserver, - observer_list_, - OnTextInputStateChanged(client)); - } - - if (!remote_delegate_ || (prev_input_scopes == input_scopes_ && - prev_bounds == composition_character_bounds_)) - return; - remote_delegate_->OnTextInputClientUpdated(input_scopes_, - composition_character_bounds_); - } - - void DetachTextInputClient(TextInputClient* client) override { - if (text_input_client_ != client) - return; - SetFocusedTextInputClient(NULL); - } - - TextInputClient* GetTextInputClient() const override { - return text_input_client_; - } - - void DispatchKeyEvent(ui::KeyEvent* event) override { - if (event->HasNativeEvent()) { - const base::NativeEvent& native_key_event = event->native_event(); - if (native_key_event.message == WM_CHAR && text_input_client_) { - text_input_client_->InsertChar(*event); - event->StopPropagation(); - } - return; - } - - if (event->is_char()) { - if (text_input_client_) { - text_input_client_->InsertChar(*event); - } - event->StopPropagation(); - return; - } - if (delegate_) - ignore_result(delegate_->DispatchKeyEventPostIME(event)); - } - - void OnTextInputTypeChanged(const TextInputClient* client) override { - if (!text_input_client_ || text_input_client_ != client) - return; - std::vector<int32_t> prev_input_scopes; - std::swap(input_scopes_, prev_input_scopes); - input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(), - client->GetTextInputMode()); - if (input_scopes_ != prev_input_scopes && remote_delegate_) { - remote_delegate_->OnTextInputClientUpdated( - input_scopes_, composition_character_bounds_); - } - } - - void OnCaretBoundsChanged(const TextInputClient* client) override { - if (!text_input_client_ || text_input_client_ != client) - return; - std::vector<gfx::Rect> prev_rects; - std::swap(composition_character_bounds_, prev_rects); - composition_character_bounds_ = GetCompositionCharacterBounds(client); - if (composition_character_bounds_ != prev_rects && remote_delegate_) { - remote_delegate_->OnTextInputClientUpdated( - input_scopes_, composition_character_bounds_); - } - } - - void CancelComposition(const TextInputClient* client) override { - if (CanSendRemoteNotification(client)) - remote_delegate_->CancelComposition(); - } - - void OnInputLocaleChanged() override {} - - std::string GetInputLocale() override { - const LCID locale_id = MAKELCID(langid_, SORT_DEFAULT); - std::string language = - GetLocaleString(locale_id, LOCALE_SISO639LANGNAME); - if (SUBLANGID(langid_) == SUBLANG_NEUTRAL || language.empty()) - return language; - const std::string& region = - GetLocaleString(locale_id, LOCALE_SISO3166CTRYNAME); - if (region.empty()) - return language; - return language.append(1, '-').append(region); - } - - TextInputType GetTextInputType() const override { - return text_input_client_ ? text_input_client_->GetTextInputType() - : TEXT_INPUT_TYPE_NONE; - } - - TextInputMode GetTextInputMode() const override { - return text_input_client_ ? text_input_client_->GetTextInputMode() - : TEXT_INPUT_MODE_DEFAULT; - } - - int GetTextInputFlags() const override { - return text_input_client_ ? text_input_client_->GetTextInputFlags() - : 0; - } - - bool CanComposeInline() const override { - return text_input_client_ ? text_input_client_->CanComposeInline() : true; - } - - bool IsCandidatePopupOpen() const override { - return is_candidate_popup_open_; - } - - void ShowImeIfNeeded() override {} - - void AddObserver(InputMethodObserver* observer) override { - observer_list_.AddObserver(observer); - } - - void RemoveObserver(InputMethodObserver* observer) override { - observer_list_.RemoveObserver(observer); - } - - // Overridden from RemoteInputMethodPrivateWin: - void SetRemoteDelegate( - internal::RemoteInputMethodDelegateWin* delegate) override { - remote_delegate_ = delegate; - - // Sync initial state. - if (remote_delegate_) { - remote_delegate_->OnTextInputClientUpdated( - input_scopes_, composition_character_bounds_); - } - } - - void OnCandidatePopupChanged(bool visible) override { - is_candidate_popup_open_ = visible; - } - - void OnInputSourceChanged(LANGID langid, bool /*is_ime*/) override { - // Note: Currently |is_ime| is not utilized yet. - const bool changed = (langid_ != langid); - langid_ = langid; - if (changed && GetTextInputClient()) - GetTextInputClient()->OnInputMethodChanged(); - } - - void OnCompositionChanged(const CompositionText& composition_text) override { - if (!text_input_client_) - return; - text_input_client_->SetCompositionText(composition_text); - } - - void OnTextCommitted(const base::string16& text) override { - if (!text_input_client_) - return; - if (text_input_client_->GetTextInputType() == TEXT_INPUT_TYPE_NONE) { - // According to the comment in text_input_client.h, - // TextInputClient::InsertText should never be called when the - // text input type is TEXT_INPUT_TYPE_NONE. - - for (size_t i = 0; i < text.size(); ++i) { - ui::KeyEvent char_event(text[i], static_cast<ui::KeyboardCode>(text[i]), - ui::EF_NONE); - text_input_client_->InsertChar(char_event); - } - return; - } - text_input_client_->InsertText(text); - } - - bool CanSendRemoteNotification( - const TextInputClient* text_input_client) const { - return text_input_client_ && - text_input_client_ == text_input_client && - remote_delegate_; - } - - base::ObserverList<InputMethodObserver> observer_list_; - - internal::InputMethodDelegate* delegate_; - internal::RemoteInputMethodDelegateWin* remote_delegate_; - - TextInputClient* text_input_client_; - std::vector<int32_t> input_scopes_; - std::vector<gfx::Rect> composition_character_bounds_; - bool is_candidate_popup_open_; - bool is_ime_; - LANGID langid_; - - DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodWin); -}; - -} // namespace - -bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget) { - // If the remote input method is already registered then don't do it again. - if (ui::g_public_interface_ && ui::g_private_interface_) - return false; - - DWORD process_id = 0; - if (GetWindowThreadProcessId(widget, &process_id) == 0) - return false; - base::win::ScopedHandle process_handle(::OpenProcess( - PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id)); - if (!process_handle.IsValid()) - return false; - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kViewerConnect); -} - -RemoteInputMethodPrivateWin::RemoteInputMethodPrivateWin() {} - -scoped_ptr<InputMethod> CreateRemoteInputMethodWin( - internal::InputMethodDelegate* delegate) { - return make_scoped_ptr(new RemoteInputMethodWin(delegate)); -} - -// static -RemoteInputMethodPrivateWin* RemoteInputMethodPrivateWin::Get( - InputMethod* input_method) { - return GetPrivate(input_method); -} - -} // namespace ui
diff --git a/ui/base/ime/remote_input_method_win.h b/ui/base/ime/remote_input_method_win.h deleted file mode 100644 index a1725b32..0000000 --- a/ui/base/ime/remote_input_method_win.h +++ /dev/null
@@ -1,100 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_BASE_IME_REMOTE_INPUT_METHOD_WIN_H_ -#define UI_BASE_IME_REMOTE_INPUT_METHOD_WIN_H_ - -#include <Windows.h> - -#include <string> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string16.h" -#include "ui/base/ime/ui_base_ime_export.h" -#include "ui/gfx/native_widget_types.h" - -namespace ui { -namespace internal { -class InputMethodDelegate; -class RemoteInputMethodDelegateWin; -} // namespace internal - -class InputMethod; -struct CompositionText; - -// RemoteInputMethodWin is a special implementation of ui::InputMethod that -// works as a proxy of an IME handler running in the metro_driver process. -// RemoteInputMethodWin works as follows. -// - Any action to RemoteInputMethodWin should be delegated to the -// metro_driver process via RemoteInputMethodDelegateWin. -// - Data retrieval from RemoteInputMethodPrivateWin is implemented with -// data cache. Whenever the IME state in the metro_driver process is changed, -// RemoteWindowTreeHostWin, which receives IPCs from metro_driver process, -// will call RemoteInputMethodPrivateWin::OnCandidatePopupChanged and/or -// RemoteInputMethodPrivateWin::OnInputSourceChanged accordingly so that -// the state cache should be updated. -// - Some IPC messages that represent actions to TextInputClient should be -// delegated to RemoteInputMethodPrivateWin so that RemoteInputMethodWin can -// work as a real proxy. - -// Returns true if |widget| requires RemoteInputMethodWin. -bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget); - -// Returns the public interface of RemoteInputMethodWin. -// Caveats: Currently only one instance of RemoteInputMethodWin is able to run -// at the same time. -UI_BASE_IME_EXPORT scoped_ptr<InputMethod> CreateRemoteInputMethodWin( - internal::InputMethodDelegate* delegate); - -// Private interface of RemoteInputMethodWin. -class UI_BASE_IME_EXPORT RemoteInputMethodPrivateWin { - public: - RemoteInputMethodPrivateWin(); - - // Returns the private interface of RemoteInputMethodWin when and only when - // |input_method| is instanciated via CreateRemoteInputMethodWin. Caller does - // not take the ownership of the returned object. - // As you might notice, this is yet another reinplementation of dynamic_cast - // or IUnknown::QueryInterface. - static RemoteInputMethodPrivateWin* Get(InputMethod* input_method); - - // Installs RemoteInputMethodDelegateWin delegate. Set NULL to |delegate| to - // unregister. - virtual void SetRemoteDelegate( - internal::RemoteInputMethodDelegateWin* delegate) = 0; - - // Updates internal cache so that subsequent calls of - // RemoteInputMethodWin::IsCandidatePopupOpen can return the correct value - // based on remote IME activities in the metro_driver process. - virtual void OnCandidatePopupChanged(bool visible) = 0; - - // Updates internal cache so that subsequent calls of - // RemoteInputMethodWin::GetInputLocale can return the correct values based on - // remote IME activities in the metro_driver process. - virtual void OnInputSourceChanged(LANGID langid, bool is_ime) = 0; - - // Handles composition-update events occurred in the metro_driver process. - // Caveats: This method is designed to be used only with - // metro_driver::TextService. In other words, there is no garantee that this - // method works a wrapper to call ui::TextInputClient::SetCompositionText. - virtual void OnCompositionChanged( - const CompositionText& composition_text) = 0; - - // Handles text-commit events occurred in the metro_driver process. - // Caveats: This method is designed to be used only with - // metro_driver::TextService. In other words, there is no garantee that this - // method works a wrapper to call ui::TextInputClient::InsertText. In fact, - // this method may call ui::TextInputClient::InsertChar when the text input - // type of the focused text input client is TEXT_INPUT_TYPE_NONE. - virtual void OnTextCommitted(const base::string16& text) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodPrivateWin); -}; - -} // namespace ui - -#endif // UI_BASE_IME_REMOTE_INPUT_METHOD_WIN_H_
diff --git a/ui/base/ime/remote_input_method_win_unittest.cc b/ui/base/ime/remote_input_method_win_unittest.cc deleted file mode 100644 index 2d15919..0000000 --- a/ui/base/ime/remote_input_method_win_unittest.cc +++ /dev/null
@@ -1,831 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/base/ime/remote_input_method_win.h" - -#include <InputScope.h> -#include <stddef.h> -#include <stdint.h> - -#include <vector> - -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/scoped_observer.h" -#include "base/strings/string16.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/ime/composition_text.h" -#include "ui/base/ime/dummy_text_input_client.h" -#include "ui/base/ime/input_method.h" -#include "ui/base/ime/input_method_delegate.h" -#include "ui/base/ime/input_method_observer.h" -#include "ui/base/ime/remote_input_method_delegate_win.h" -#include "ui/events/event.h" - -namespace ui { -namespace { - -class MockTextInputClient : public DummyTextInputClient { - public: - MockTextInputClient() - : text_input_type_(TEXT_INPUT_TYPE_NONE), - text_input_mode_(TEXT_INPUT_MODE_DEFAULT), - call_count_set_composition_text_(0), - call_count_insert_char_(0), - call_count_insert_text_(0), - emulate_pepper_flash_(false) { - } - - size_t call_count_set_composition_text() const { - return call_count_set_composition_text_; - } - const base::string16& inserted_text() const { - return inserted_text_; - } - size_t call_count_insert_char() const { - return call_count_insert_char_; - } - size_t call_count_insert_text() const { - return call_count_insert_text_; - } - void Reset() { - text_input_type_ = TEXT_INPUT_TYPE_NONE; - text_input_mode_ = TEXT_INPUT_MODE_DEFAULT; - call_count_set_composition_text_ = 0; - inserted_text_.clear(); - call_count_insert_char_ = 0; - call_count_insert_text_ = 0; - caret_bounds_ = gfx::Rect(); - composition_character_bounds_.clear(); - emulate_pepper_flash_ = false; - } - void set_text_input_type(ui::TextInputType type) { - text_input_type_ = type; - } - void set_text_input_mode(ui::TextInputMode mode) { - text_input_mode_ = mode; - } - void set_caret_bounds(const gfx::Rect& caret_bounds) { - caret_bounds_ = caret_bounds; - } - void set_composition_character_bounds( - const std::vector<gfx::Rect>& composition_character_bounds) { - composition_character_bounds_ = composition_character_bounds; - } - void set_emulate_pepper_flash(bool enabled) { - emulate_pepper_flash_ = enabled; - } - - private: - // Overriden from DummyTextInputClient. - void SetCompositionText(const ui::CompositionText& composition) override { - ++call_count_set_composition_text_; - } - void InsertChar(const ui::KeyEvent& event) override { - inserted_text_.append(1, event.GetCharacter()); - ++call_count_insert_char_; - } - void InsertText(const base::string16& text) override { - inserted_text_.append(text); - ++call_count_insert_text_; - } - ui::TextInputType GetTextInputType() const override { - return text_input_type_; - } - ui::TextInputMode GetTextInputMode() const override { - return text_input_mode_; - } - gfx::Rect GetCaretBounds() const override { return caret_bounds_; } - bool GetCompositionCharacterBounds(uint32_t index, - gfx::Rect* rect) const override { - // Emulate the situation of crbug.com/328237. - if (emulate_pepper_flash_) - return false; - if (!rect || composition_character_bounds_.size() <= index) - return false; - *rect = composition_character_bounds_[index]; - return true; - } - bool HasCompositionText() const override { - return !composition_character_bounds_.empty(); - } - bool GetCompositionTextRange(gfx::Range* range) const override { - if (composition_character_bounds_.empty()) - return false; - *range = gfx::Range(0, composition_character_bounds_.size()); - return true; - } - - ui::TextInputType text_input_type_; - ui::TextInputMode text_input_mode_; - gfx::Rect caret_bounds_; - std::vector<gfx::Rect> composition_character_bounds_; - base::string16 inserted_text_; - size_t call_count_set_composition_text_; - size_t call_count_insert_char_; - size_t call_count_insert_text_; - bool emulate_pepper_flash_; - DISALLOW_COPY_AND_ASSIGN(MockTextInputClient); -}; - -class MockInputMethodDelegate : public internal::InputMethodDelegate { - public: - MockInputMethodDelegate() {} - - const std::vector<ui::KeyboardCode>& fabricated_key_events() const { - return fabricated_key_events_; - } - void Reset() { - fabricated_key_events_.clear(); - } - - private: - ui::EventDispatchDetails DispatchKeyEventPostIME( - ui::KeyEvent* event) override { - EXPECT_FALSE(event->HasNativeEvent()); - fabricated_key_events_.push_back(event->key_code()); - event->SetHandled(); - return ui::EventDispatchDetails(); - } - - std::vector<ui::KeyboardCode> fabricated_key_events_; - DISALLOW_COPY_AND_ASSIGN(MockInputMethodDelegate); -}; - -class MockRemoteInputMethodDelegateWin - : public internal::RemoteInputMethodDelegateWin { - public: - MockRemoteInputMethodDelegateWin() - : cancel_composition_called_(false), - text_input_client_updated_called_(false) { - } - - bool cancel_composition_called() const { - return cancel_composition_called_; - } - bool text_input_client_updated_called() const { - return text_input_client_updated_called_; - } - const std::vector<int32_t>& input_scopes() const { return input_scopes_; } - const std::vector<gfx::Rect>& composition_character_bounds() const { - return composition_character_bounds_; - } - void Reset() { - cancel_composition_called_ = false; - text_input_client_updated_called_ = false; - input_scopes_.clear(); - composition_character_bounds_.clear(); - } - - private: - void CancelComposition() override { cancel_composition_called_ = true; } - - void OnTextInputClientUpdated( - const std::vector<int32_t>& input_scopes, - const std::vector<gfx::Rect>& composition_character_bounds) override { - text_input_client_updated_called_ = true; - input_scopes_ = input_scopes; - composition_character_bounds_ = composition_character_bounds; - } - - bool cancel_composition_called_; - bool text_input_client_updated_called_; - std::vector<int32_t> input_scopes_; - std::vector<gfx::Rect> composition_character_bounds_; - DISALLOW_COPY_AND_ASSIGN(MockRemoteInputMethodDelegateWin); -}; - -class MockInputMethodObserver : public InputMethodObserver { - public: - MockInputMethodObserver() - : on_text_input_state_changed_(0), - on_input_method_destroyed_changed_(0) { - } - ~MockInputMethodObserver() override {} - void Reset() { - on_text_input_state_changed_ = 0; - on_input_method_destroyed_changed_ = 0; - } - size_t on_text_input_state_changed() const { - return on_text_input_state_changed_; - } - size_t on_input_method_destroyed_changed() const { - return on_input_method_destroyed_changed_; - } - - private: - // Overriden from InputMethodObserver. - void OnTextInputTypeChanged(const TextInputClient* client) override {} - void OnFocus() override {} - void OnBlur() override {} - void OnCaretBoundsChanged(const TextInputClient* client) override {} - void OnTextInputStateChanged(const TextInputClient* client) override { - ++on_text_input_state_changed_; - } - void OnInputMethodDestroyed(const InputMethod* client) override { - ++on_input_method_destroyed_changed_; - } - void OnShowImeIfNeeded() override {} - - size_t on_text_input_state_changed_; - size_t on_input_method_destroyed_changed_; - DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver); -}; - -typedef ScopedObserver<InputMethod, InputMethodObserver> - InputMethodScopedObserver; - -TEST(RemoteInputMethodWinTest, RemoteInputMethodPrivateWin) { - InputMethod* other_ptr = static_cast<InputMethod*>(NULL) + 1; - - // Use typed NULL to make EXPECT_NE happy until nullptr becomes available. - RemoteInputMethodPrivateWin* kNull = - static_cast<RemoteInputMethodPrivateWin*>(NULL); - EXPECT_EQ(kNull, RemoteInputMethodPrivateWin::Get(other_ptr)); - - MockInputMethodDelegate delegate_; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - EXPECT_NE(kNull, RemoteInputMethodPrivateWin::Get(input_method.get())); - - InputMethod* dangling_ptr = input_method.get(); - input_method.reset(NULL); - EXPECT_EQ(kNull, RemoteInputMethodPrivateWin::Get(dangling_ptr)); -} - -TEST(RemoteInputMethodWinTest, OnInputSourceChanged) { - MockInputMethodDelegate delegate_; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - - private_ptr->OnInputSourceChanged( - MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), true); - EXPECT_EQ("ja-JP", input_method->GetInputLocale()); - - private_ptr->OnInputSourceChanged( - MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_QATAR), true); - EXPECT_EQ("ar-QA", input_method->GetInputLocale()); -} - -TEST(RemoteInputMethodWinTest, OnCandidatePopupChanged) { - MockInputMethodDelegate delegate_; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - - // Initial value - EXPECT_FALSE(input_method->IsCandidatePopupOpen()); - - // RemoteInputMethodWin::OnCandidatePopupChanged can be called even when the - // focused text input client is NULL. - ASSERT_TRUE(input_method->GetTextInputClient() == NULL); - private_ptr->OnCandidatePopupChanged(false); - private_ptr->OnCandidatePopupChanged(true); - - MockTextInputClient mock_text_input_client; - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - mock_text_input_client.Reset(); - - private_ptr->OnCandidatePopupChanged(true); - EXPECT_TRUE(input_method->IsCandidatePopupOpen()); - - private_ptr->OnCandidatePopupChanged(false); - EXPECT_FALSE(input_method->IsCandidatePopupOpen()); -} - -TEST(RemoteInputMethodWinTest, CancelComposition) { - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - // This must not cause a crash. - input_method->CancelComposition(&mock_text_input_client); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - input_method->CancelComposition(&mock_text_input_client); - EXPECT_FALSE(mock_remote_delegate.cancel_composition_called()); - - input_method->SetFocusedTextInputClient(&mock_text_input_client); - input_method->CancelComposition(&mock_text_input_client); - EXPECT_TRUE(mock_remote_delegate.cancel_composition_called()); -} - -TEST(RemoteInputMethodWinTest, SetFocusedTextInputClient) { - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20)); - mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL); - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - // Initial state must be synced. - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - ASSERT_EQ(1u, mock_remote_delegate.composition_character_bounds().size()); - EXPECT_EQ(gfx::Rect(10, 0, 10, 20), - mock_remote_delegate.composition_character_bounds()[0]); - ASSERT_EQ(1u, mock_remote_delegate.input_scopes().size()); - EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]); - - // State must be cleared by SetFocusedTextInputClient(NULL). - mock_remote_delegate.Reset(); - input_method->SetFocusedTextInputClient(NULL); - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - EXPECT_TRUE(mock_remote_delegate.composition_character_bounds().empty()); - EXPECT_TRUE(mock_remote_delegate.input_scopes().empty()); -} - -TEST(RemoteInputMethodWinTest, DetachTextInputClient) { - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20)); - mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL); - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - // Initial state must be synced. - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - ASSERT_EQ(1u, mock_remote_delegate.composition_character_bounds().size()); - EXPECT_EQ(gfx::Rect(10, 0, 10, 20), - mock_remote_delegate.composition_character_bounds()[0]); - ASSERT_EQ(1u, mock_remote_delegate.input_scopes().size()); - EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]); - - // State must be cleared by DetachTextInputClient - mock_remote_delegate.Reset(); - input_method->DetachTextInputClient(&mock_text_input_client); - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - EXPECT_TRUE(mock_remote_delegate.composition_character_bounds().empty()); - EXPECT_TRUE(mock_remote_delegate.input_scopes().empty()); -} - -TEST(RemoteInputMethodWinTest, OnCaretBoundsChanged) { - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - // This must not cause a crash. - input_method->OnCaretBoundsChanged(&mock_text_input_client); - - mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20)); - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - // Initial state must be synced. - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - ASSERT_EQ(1u, mock_remote_delegate.composition_character_bounds().size()); - EXPECT_EQ(gfx::Rect(10, 0, 10, 20), - mock_remote_delegate.composition_character_bounds()[0]); - - // Redundant OnCaretBoundsChanged must be ignored. - mock_remote_delegate.Reset(); - input_method->OnCaretBoundsChanged(&mock_text_input_client); - EXPECT_FALSE(mock_remote_delegate.text_input_client_updated_called()); - - // Check OnCaretBoundsChanged is handled. (w/o composition) - mock_remote_delegate.Reset(); - mock_text_input_client.Reset(); - mock_text_input_client.set_caret_bounds(gfx::Rect(10, 20, 30, 40)); - input_method->OnCaretBoundsChanged(&mock_text_input_client); - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - ASSERT_EQ(1u, mock_remote_delegate.composition_character_bounds().size()); - EXPECT_EQ(gfx::Rect(10, 20, 30, 40), - mock_remote_delegate.composition_character_bounds()[0]); - - // Check OnCaretBoundsChanged is handled. (w/ composition) - { - mock_remote_delegate.Reset(); - mock_text_input_client.Reset(); - - std::vector<gfx::Rect> bounds; - bounds.push_back(gfx::Rect(10, 20, 30, 40)); - bounds.push_back(gfx::Rect(40, 30, 20, 10)); - mock_text_input_client.set_composition_character_bounds(bounds); - input_method->OnCaretBoundsChanged(&mock_text_input_client); - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - EXPECT_EQ(bounds, mock_remote_delegate.composition_character_bounds()); - } -} - -// Test case against crbug.com/328237. -TEST(RemoteInputMethodWinTest, OnCaretBoundsChangedForPepperFlash) { - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - mock_remote_delegate.Reset(); - mock_text_input_client.Reset(); - mock_text_input_client.set_emulate_pepper_flash(true); - - std::vector<gfx::Rect> caret_bounds; - caret_bounds.push_back(gfx::Rect(5, 15, 25, 35)); - mock_text_input_client.set_caret_bounds(caret_bounds[0]); - - std::vector<gfx::Rect> composition_bounds; - composition_bounds.push_back(gfx::Rect(10, 20, 30, 40)); - composition_bounds.push_back(gfx::Rect(40, 30, 20, 10)); - mock_text_input_client.set_composition_character_bounds(composition_bounds); - input_method->OnCaretBoundsChanged(&mock_text_input_client); - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - // The caret bounds must be used when - // TextInputClient::GetCompositionCharacterBounds failed. - EXPECT_EQ(caret_bounds, mock_remote_delegate.composition_character_bounds()); -} - -TEST(RemoteInputMethodWinTest, OnTextInputTypeChanged) { - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - // This must not cause a crash. - input_method->OnCaretBoundsChanged(&mock_text_input_client); - - mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL); - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - // Initial state must be synced. - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - ASSERT_EQ(1u, mock_remote_delegate.input_scopes().size()); - EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]); - - // Check TEXT_INPUT_TYPE_NONE is handled. - mock_remote_delegate.Reset(); - mock_text_input_client.Reset(); - mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_NONE); - mock_text_input_client.set_text_input_mode(ui::TEXT_INPUT_MODE_KATAKANA); - input_method->OnTextInputTypeChanged(&mock_text_input_client); - EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called()); - EXPECT_TRUE(mock_remote_delegate.input_scopes().empty()); - - // Redundant OnTextInputTypeChanged must be ignored. - mock_remote_delegate.Reset(); - input_method->OnTextInputTypeChanged(&mock_text_input_client); - EXPECT_FALSE(mock_remote_delegate.text_input_client_updated_called()); - - mock_remote_delegate.Reset(); - mock_text_input_client.Reset(); - mock_text_input_client.set_caret_bounds(gfx::Rect(10, 20, 30, 40)); - input_method->OnCaretBoundsChanged(&mock_text_input_client); -} - -TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeKeyEvent) { - // Basically RemoteInputMethodWin does not handle native keydown event. - - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - const MSG wm_keydown = { NULL, WM_KEYDOWN, ui::VKEY_A }; - ui::KeyEvent new_keydown(wm_keydown); - ui::KeyEvent native_keydown(new_keydown); - - // This must not cause a crash. - input_method->DispatchKeyEvent(&native_keydown); - EXPECT_FALSE(native_keydown.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - EXPECT_TRUE(delegate_.fabricated_key_events().empty()); - delegate_.Reset(); - mock_text_input_client.Reset(); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - // TextInputClient is not focused yet here. - native_keydown = new_keydown; - input_method->DispatchKeyEvent(&native_keydown); - EXPECT_FALSE(native_keydown.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - EXPECT_TRUE(delegate_.fabricated_key_events().empty()); - delegate_.Reset(); - mock_text_input_client.Reset(); - - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - // TextInputClient is now focused here. - native_keydown = new_keydown; - input_method->DispatchKeyEvent(&native_keydown); - EXPECT_FALSE(native_keydown.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - EXPECT_TRUE(delegate_.fabricated_key_events().empty()); - delegate_.Reset(); - mock_text_input_client.Reset(); -} - -TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeCharEvent) { - // RemoteInputMethodWin handles native char event if possible. - - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - const MSG wm_char = { NULL, WM_CHAR, 'A', 0 }; - ui::KeyEvent new_char(wm_char); - ui::KeyEvent native_char(new_char); - - // This must not cause a crash. - input_method->DispatchKeyEvent(&native_char); - EXPECT_FALSE(native_char.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - EXPECT_TRUE(delegate_.fabricated_key_events().empty()); - delegate_.Reset(); - mock_text_input_client.Reset(); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - // TextInputClient is not focused yet here. - native_char = new_char; - input_method->DispatchKeyEvent(&native_char); - EXPECT_FALSE(native_char.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - EXPECT_TRUE(delegate_.fabricated_key_events().empty()); - delegate_.Reset(); - mock_text_input_client.Reset(); - - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - // TextInputClient is now focused here. - native_char = new_char; - input_method->DispatchKeyEvent(&native_char); - EXPECT_TRUE(native_char.handled()); - EXPECT_EQ(L"A", mock_text_input_client.inserted_text()); - EXPECT_TRUE(delegate_.fabricated_key_events().empty()); - delegate_.Reset(); - mock_text_input_client.Reset(); -} - -TEST(RemoteInputMethodWinTest, DispatchKeyEvent_FabricatedKeyDown) { - // Fabricated non-char event will be delegated to - // InputMethodDelegate::DispatchFabricatedKeyEventPostIME as long as the - // delegate is installed. - - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - ui::KeyEvent new_keydown(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE); - new_keydown.set_character(L'A'); - ui::KeyEvent fabricated_keydown(new_keydown); - - // This must not cause a crash. - input_method->DispatchKeyEvent(&fabricated_keydown); - EXPECT_TRUE(fabricated_keydown.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - ASSERT_EQ(1u, delegate_.fabricated_key_events().size()); - EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]); - delegate_.Reset(); - mock_text_input_client.Reset(); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - // TextInputClient is not focused yet here. - fabricated_keydown = new_keydown; - input_method->DispatchKeyEvent(&fabricated_keydown); - EXPECT_TRUE(fabricated_keydown.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - ASSERT_EQ(1u, delegate_.fabricated_key_events().size()); - EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]); - delegate_.Reset(); - mock_text_input_client.Reset(); - - input_method->SetFocusedTextInputClient(&mock_text_input_client); - // TextInputClient is now focused here. - fabricated_keydown = new_keydown; - input_method->DispatchKeyEvent(&fabricated_keydown); - EXPECT_TRUE(fabricated_keydown.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - ASSERT_EQ(1u, delegate_.fabricated_key_events().size()); - EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]); - delegate_.Reset(); - mock_text_input_client.Reset(); - - input_method->SetDelegate(NULL); - // RemoteInputMethodDelegateWin is no longer set here. - fabricated_keydown = new_keydown; - input_method->DispatchKeyEvent(&fabricated_keydown); - EXPECT_FALSE(fabricated_keydown.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); -} - -TEST(RemoteInputMethodWinTest, DispatchKeyEvent_FabricatedChar) { - // Note: RemoteInputMethodWin::DispatchKeyEvent should always return true - // for fabricated character events. - - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - ui::KeyEvent new_char(L'A', ui::VKEY_A, ui::EF_NONE); - ui::KeyEvent fabricated_char(new_char); - - // This must not cause a crash. - input_method->DispatchKeyEvent(&fabricated_char); - EXPECT_TRUE(fabricated_char.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - EXPECT_TRUE(delegate_.fabricated_key_events().empty()); - delegate_.Reset(); - mock_text_input_client.Reset(); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - // TextInputClient is not focused yet here. - fabricated_char = new_char; - input_method->DispatchKeyEvent(&fabricated_char); - EXPECT_TRUE(fabricated_char.handled()); - EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); - EXPECT_TRUE(delegate_.fabricated_key_events().empty()); - delegate_.Reset(); - mock_text_input_client.Reset(); - - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - // TextInputClient is now focused here. - fabricated_char = new_char; - input_method->DispatchKeyEvent(&fabricated_char); - EXPECT_TRUE(fabricated_char.handled()); - EXPECT_EQ(L"A", mock_text_input_client.inserted_text()); - EXPECT_TRUE(delegate_.fabricated_key_events().empty()); - delegate_.Reset(); - mock_text_input_client.Reset(); -} - -TEST(RemoteInputMethodWinTest, OnCompositionChanged) { - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - CompositionText composition_text; - - // TextInputClient is not focused yet here. - - private_ptr->OnCompositionChanged(composition_text); - EXPECT_EQ(0u, mock_text_input_client.call_count_set_composition_text()); - delegate_.Reset(); - mock_text_input_client.Reset(); - - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - // TextInputClient is now focused here. - - private_ptr->OnCompositionChanged(composition_text); - EXPECT_EQ(1u, mock_text_input_client.call_count_set_composition_text()); - delegate_.Reset(); - mock_text_input_client.Reset(); -} - -TEST(RemoteInputMethodWinTest, OnTextCommitted) { - MockInputMethodDelegate delegate_; - MockTextInputClient mock_text_input_client; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - - RemoteInputMethodPrivateWin* private_ptr = - RemoteInputMethodPrivateWin::Get(input_method.get()); - ASSERT_TRUE(private_ptr != NULL); - MockRemoteInputMethodDelegateWin mock_remote_delegate; - private_ptr->SetRemoteDelegate(&mock_remote_delegate); - - base::string16 committed_text = L"Hello"; - - // TextInputClient is not focused yet here. - - mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_TEXT); - private_ptr->OnTextCommitted(committed_text); - EXPECT_EQ(0u, mock_text_input_client.call_count_insert_char()); - EXPECT_EQ(0u, mock_text_input_client.call_count_insert_text()); - EXPECT_EQ(L"", mock_text_input_client.inserted_text()); - delegate_.Reset(); - mock_text_input_client.Reset(); - - input_method->SetFocusedTextInputClient(&mock_text_input_client); - - // TextInputClient is now focused here. - - mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_TEXT); - private_ptr->OnTextCommitted(committed_text); - EXPECT_EQ(0u, mock_text_input_client.call_count_insert_char()); - EXPECT_EQ(1u, mock_text_input_client.call_count_insert_text()); - EXPECT_EQ(committed_text, mock_text_input_client.inserted_text()); - delegate_.Reset(); - mock_text_input_client.Reset(); - - // When TextInputType is TEXT_INPUT_TYPE_NONE, TextInputClient::InsertText - // should not be used. - mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_NONE); - private_ptr->OnTextCommitted(committed_text); - EXPECT_EQ(committed_text.size(), - mock_text_input_client.call_count_insert_char()); - EXPECT_EQ(0u, mock_text_input_client.call_count_insert_text()); - EXPECT_EQ(committed_text, mock_text_input_client.inserted_text()); - delegate_.Reset(); - mock_text_input_client.Reset(); -} - -TEST(RemoteInputMethodWinTest, OnTextInputStateChanged_Observer) { - DummyTextInputClient text_input_client; - DummyTextInputClient text_input_client_the_other; - - MockInputMethodObserver input_method_observer; - MockInputMethodDelegate delegate_; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - InputMethodScopedObserver scoped_observer(&input_method_observer); - scoped_observer.Add(input_method.get()); - - input_method->SetFocusedTextInputClient(&text_input_client); - ASSERT_EQ(&text_input_client, input_method->GetTextInputClient()); - EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed()); - input_method_observer.Reset(); - - input_method->SetFocusedTextInputClient(&text_input_client); - ASSERT_EQ(&text_input_client, input_method->GetTextInputClient()); - EXPECT_EQ(0u, input_method_observer.on_text_input_state_changed()); - input_method_observer.Reset(); - - input_method->SetFocusedTextInputClient(&text_input_client_the_other); - ASSERT_EQ(&text_input_client_the_other, input_method->GetTextInputClient()); - EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed()); - input_method_observer.Reset(); - - input_method->DetachTextInputClient(&text_input_client_the_other); - ASSERT_TRUE(input_method->GetTextInputClient() == NULL); - EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed()); - input_method_observer.Reset(); -} - -TEST(RemoteInputMethodWinTest, OnInputMethodDestroyed_Observer) { - DummyTextInputClient text_input_client; - DummyTextInputClient text_input_client_the_other; - - MockInputMethodObserver input_method_observer; - InputMethodScopedObserver scoped_observer(&input_method_observer); - - MockInputMethodDelegate delegate_; - scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); - input_method->AddObserver(&input_method_observer); - - EXPECT_EQ(0u, input_method_observer.on_input_method_destroyed_changed()); - input_method.reset(); - EXPECT_EQ(1u, input_method_observer.on_input_method_destroyed_changed()); -} - -} // namespace -} // namespace ui
diff --git a/ui/base/ime/ui_base_ime.gyp b/ui/base/ime/ui_base_ime.gyp index 3b5b137..9c3eb388 100644 --- a/ui/base/ime/ui_base_ime.gyp +++ b/ui/base/ime/ui_base_ime.gyp
@@ -105,9 +105,6 @@ 'linux/linux_input_method_context_factory.h', 'mock_input_method.cc', 'mock_input_method.h', - 'remote_input_method_delegate_win.h', - 'remote_input_method_win.cc', - 'remote_input_method_win.h', 'text_input_client.cc', 'text_input_client.h', 'text_input_type.h',
diff --git a/ui/base/ui_base_tests.gyp b/ui/base/ui_base_tests.gyp index 483b5ae..46ecb92 100644 --- a/ui/base/ui_base_tests.gyp +++ b/ui/base/ui_base_tests.gyp
@@ -77,7 +77,6 @@ 'ime/composition_text_util_pango_unittest.cc', 'ime/input_method_base_unittest.cc', 'ime/input_method_chromeos_unittest.cc', - 'ime/remote_input_method_win_unittest.cc', 'ime/win/imm32_manager_unittest.cc', 'ime/win/tsf_input_scope_unittest.cc', 'models/list_model_unittest.cc',
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn index ff3d4d3f..293a0c9 100644 --- a/ui/compositor/BUILD.gn +++ b/ui/compositor/BUILD.gn
@@ -48,6 +48,7 @@ "layer_delegate.h", "layer_owner.cc", "layer_owner.h", + "layer_threaded_animation_delegate.h", "layer_tree_owner.cc", "layer_tree_owner.h", "layer_type.h",
diff --git a/ui/compositor/compositor.gyp b/ui/compositor/compositor.gyp index 4ab5b0c..0e65659 100644 --- a/ui/compositor/compositor.gyp +++ b/ui/compositor/compositor.gyp
@@ -66,6 +66,7 @@ 'layer_delegate.h', 'layer_owner.cc', 'layer_owner.h', + 'layer_threaded_animation_delegate.h', 'layer_tree_owner.cc', 'layer_tree_owner.h', 'layer_type.h',
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index e5569d0f..89a1d262 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc
@@ -529,6 +529,13 @@ SetLayerBackgroundFilters(); } +bool Layer::HasPendingThreadedAnimationsForTesting() const { + if (UILayerSettings().use_compositor_animation_timelines) + return animator_->HasPendingThreadedAnimationsForTesting(); + else + return !pending_threaded_animations_.empty(); +} + void Layer::SwitchCCLayerForTest() { scoped_refptr<cc::Layer> new_layer = cc::PictureLayer::Create(UILayerSettings(), this); @@ -973,15 +980,11 @@ void Layer::AddThreadedAnimation(scoped_ptr<cc::Animation> animation) { DCHECK(cc_layer_); + DCHECK(!UILayerSettings().use_compositor_animation_timelines); // Until this layer has a compositor (and hence cc_layer_ has a // LayerTreeHost), addAnimation will fail. if (GetCompositor()) { - if (UILayerSettings().use_compositor_animation_timelines) { - DCHECK(animator_); - animator_->AddThreadedAnimation(std::move(animation)); - } else { - cc_layer_->AddAnimation(std::move(animation)); - } + cc_layer_->AddAnimation(std::move(animation)); } else { pending_threaded_animations_.push_back(std::move(animation)); } @@ -989,13 +992,9 @@ void Layer::RemoveThreadedAnimation(int animation_id) { DCHECK(cc_layer_); + DCHECK(!UILayerSettings().use_compositor_animation_timelines); if (pending_threaded_animations_.size() == 0) { - if (UILayerSettings().use_compositor_animation_timelines) { - DCHECK(animator_); - animator_->RemoveThreadedAnimation(animation_id); - } else { - cc_layer_->RemoveAnimation(animation_id); - } + cc_layer_->RemoveAnimation(animation_id); return; } @@ -1018,15 +1017,23 @@ return cc_layer_; } -void Layer::SendPendingThreadedAnimations() { - for (auto& animation : pending_threaded_animations_) { - if (UILayerSettings().use_compositor_animation_timelines) { - DCHECK(animator_); - animator_->AddThreadedAnimation(std::move(animation)); - } else { - cc_layer_->AddAnimation(std::move(animation)); - } +LayerThreadedAnimationDelegate* Layer::GetThreadedAnimationDelegate() { + if (UILayerSettings().use_compositor_animation_timelines) { + DCHECK(animator_); + return animator_.get(); + } else { + return this; } +} + +void Layer::SendPendingThreadedAnimations() { + if (UILayerSettings().use_compositor_animation_timelines) { + DCHECK(pending_threaded_animations_.empty()); + return; + } + + for (auto& animation : pending_threaded_animations_) + cc_layer_->AddAnimation(std::move(animation)); pending_threaded_animations_.clear(); for (auto* child : children_)
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h index 689cf39a..f573d8e3 100644 --- a/ui/compositor/layer.h +++ b/ui/compositor/layer.h
@@ -27,6 +27,7 @@ #include "ui/compositor/compositor.h" #include "ui/compositor/layer_animation_delegate.h" #include "ui/compositor/layer_delegate.h" +#include "ui/compositor/layer_threaded_animation_delegate.h" #include "ui/compositor/layer_type.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/image/image_skia.h" @@ -67,6 +68,7 @@ // NULL, but the children are not deleted. class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate, + public LayerThreadedAnimationDelegate, NON_EXPORTED_BASE(public cc::ContentLayerClient), NON_EXPORTED_BASE(public cc::TextureLayerClient), NON_EXPORTED_BASE(public cc::LayerClient) { @@ -373,9 +375,7 @@ cc::Layer* layer) override; // Whether this layer has animations waiting to get sent to its cc::Layer. - bool HasPendingThreadedAnimations() { - return pending_threaded_animations_.size() != 0; - } + bool HasPendingThreadedAnimationsForTesting() const; // Triggers a call to SwitchToLayer. void SwitchCCLayerForTest(); @@ -409,10 +409,13 @@ float GetGrayscaleForAnimation() const override; SkColor GetColorForAnimation() const override; float GetDeviceScaleFactor() const override; + cc::Layer* GetCcLayer() const override; + LayerThreadedAnimationDelegate* GetThreadedAnimationDelegate() override; + LayerAnimatorCollection* GetLayerAnimatorCollection() override; + + // Implementation of LayerThreadedAnimationDelegate. void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) override; void RemoveThreadedAnimation(int animation_id) override; - LayerAnimatorCollection* GetLayerAnimatorCollection() override; - cc::Layer* GetCcLayer() const override; // Creates a corresponding composited layer for |type_|. void CreateCcLayer();
diff --git a/ui/compositor/layer_animation_delegate.h b/ui/compositor/layer_animation_delegate.h index e1ec62451..b1db0b30 100644 --- a/ui/compositor/layer_animation_delegate.h +++ b/ui/compositor/layer_animation_delegate.h
@@ -5,8 +5,6 @@ #ifndef UI_COMPOSITOR_LAYER_ANIMATION_DELEGATE_H_ #define UI_COMPOSITOR_LAYER_ANIMATION_DELEGATE_H_ -#include "base/memory/scoped_ptr.h" -#include "cc/animation/animation.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/compositor/compositor_export.h" #include "ui/gfx/geometry/rect.h" @@ -19,6 +17,7 @@ namespace ui { class LayerAnimatorCollection; +class LayerThreadedAnimationDelegate; // Layer animations interact with the layers using this interface. class COMPOSITOR_EXPORT LayerAnimationDelegate { @@ -39,14 +38,9 @@ virtual float GetGrayscaleForAnimation() const = 0; virtual SkColor GetColorForAnimation() const = 0; virtual float GetDeviceScaleFactor() const = 0; - - // TODO(loyso): Extract these 3 methods as a separate - // LayerThreadedAnimationDelegate. - virtual void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) = 0; - virtual void RemoveThreadedAnimation(int animation_id) = 0; virtual cc::Layer* GetCcLayer() const = 0; - virtual LayerAnimatorCollection* GetLayerAnimatorCollection() = 0; + virtual LayerThreadedAnimationDelegate* GetThreadedAnimationDelegate() = 0; protected: virtual ~LayerAnimationDelegate() {}
diff --git a/ui/compositor/layer_animation_element.cc b/ui/compositor/layer_animation_element.cc index 5e0f558..29aa7fa 100644 --- a/ui/compositor/layer_animation_element.cc +++ b/ui/compositor/layer_animation_element.cc
@@ -344,7 +344,10 @@ return false; if (Started() && IsThreaded()) { - delegate->RemoveThreadedAnimation(animation_id()); + LayerThreadedAnimationDelegate* threaded = + delegate->GetThreadedAnimationDelegate(); + DCHECK(threaded); + threaded->RemoveThreadedAnimation(animation_id()); } OnEnd(delegate); @@ -353,7 +356,10 @@ void OnAbort(LayerAnimationDelegate* delegate) override { if (delegate && Started() && IsThreaded()) { - delegate->RemoveThreadedAnimation(animation_id()); + LayerThreadedAnimationDelegate* threaded = + delegate->GetThreadedAnimationDelegate(); + DCHECK(threaded); + threaded->RemoveThreadedAnimation(animation_id()); } } @@ -366,7 +372,11 @@ set_effective_start_time(base::TimeTicks()); scoped_ptr<cc::Animation> animation = CreateCCAnimation(); animation->set_needs_synchronized_start_time(true); - delegate->AddThreadedAnimation(std::move(animation)); + + LayerThreadedAnimationDelegate* threaded = + delegate->GetThreadedAnimationDelegate(); + DCHECK(threaded); + threaded->AddThreadedAnimation(std::move(animation)); } virtual void OnEnd(LayerAnimationDelegate* delegate) = 0;
diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc index 60a37f6..08d8e11 100644 --- a/ui/compositor/layer_animator.cc +++ b/ui/compositor/layer_animator.cc
@@ -211,6 +211,11 @@ animation_player_->RemoveAnimation(animation_id); } +bool LayerAnimator::HasPendingThreadedAnimationsForTesting() const { + DCHECK(animation_player_); + return animation_player_->has_pending_animations_for_testing(); +} + void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) { scoped_refptr<LayerAnimator> retain(this); OnScheduled(animation);
diff --git a/ui/compositor/layer_animator.h b/ui/compositor/layer_animator.h index a0f5e92..6fc1878 100644 --- a/ui/compositor/layer_animator.h +++ b/ui/compositor/layer_animator.h
@@ -18,6 +18,7 @@ #include "cc/animation/layer_animation_event_observer.h" #include "ui/compositor/compositor_export.h" #include "ui/compositor/layer_animation_element.h" +#include "ui/compositor/layer_threaded_animation_delegate.h" #include "ui/gfx/animation/tween.h" namespace cc { @@ -53,6 +54,7 @@ // must guarantee that |this| is valid. class COMPOSITOR_EXPORT LayerAnimator : public base::RefCounted<LayerAnimator>, + public LayerThreadedAnimationDelegate, NON_EXPORTED_BASE(public cc::LayerAnimationEventObserver) { public: enum PreemptionStrategy { @@ -117,10 +119,8 @@ // Detach AnimationPlayer from Layer and AnimationTimeline void ResetCompositor(Compositor* compositor); - // TODO(loyso): Rework it as an implementation for - // LayerThreadedAnimationDelegate and make it private. - void AddThreadedAnimation(scoped_ptr<cc::Animation> animation); - void RemoveThreadedAnimation(int animation_id); + // Whether this animator has animations waiting to get sent to cc::LAC. + bool HasPendingThreadedAnimationsForTesting() const; // Sets the animation preemption strategy. This determines the behaviour if // a property is set during an animation. The default is @@ -339,6 +339,10 @@ // LayerAnimationEventObserver void OnAnimationStarted(const cc::AnimationEvent& event) override; + // Implementation of LayerThreadedAnimationDelegate. + void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) override; + void RemoveThreadedAnimation(int animation_id) override; + void AttachLayerToAnimationPlayer(int layer_id); void DetachLayerFromAnimationPlayer();
diff --git a/ui/compositor/layer_threaded_animation_delegate.h b/ui/compositor/layer_threaded_animation_delegate.h new file mode 100644 index 0000000..b921077e --- /dev/null +++ b/ui/compositor/layer_threaded_animation_delegate.h
@@ -0,0 +1,26 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_COMPOSITOR_LAYER_THREADED_ANIMATION_DELEGATE_H_ +#define UI_COMPOSITOR_LAYER_THREADED_ANIMATION_DELEGATE_H_ + +#include "base/memory/scoped_ptr.h" +#include "cc/animation/animation.h" +#include "ui/compositor/compositor_export.h" + +namespace ui { + +// Attach CC animations using this interface. +class COMPOSITOR_EXPORT LayerThreadedAnimationDelegate { + public: + virtual void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) = 0; + virtual void RemoveThreadedAnimation(int animation_id) = 0; + + protected: + virtual ~LayerThreadedAnimationDelegate() {} +}; + +} // namespace ui + +#endif // UI_COMPOSITOR_LAYER_THREADED_ANIMATION_DELEGATE_H_
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc index 70581b6..d9f5a7a0 100644 --- a/ui/compositor/layer_unittest.cc +++ b/ui/compositor/layer_unittest.cc
@@ -1605,41 +1605,41 @@ l1->SetAnimator(LayerAnimator::CreateImplicitAnimator()); l2->SetAnimator(LayerAnimator::CreateImplicitAnimator()); - EXPECT_FALSE(l1->HasPendingThreadedAnimations()); + EXPECT_FALSE(l1->HasPendingThreadedAnimationsForTesting()); // Trigger a threaded animation. l1->SetOpacity(0.5f); - EXPECT_TRUE(l1->HasPendingThreadedAnimations()); + EXPECT_TRUE(l1->HasPendingThreadedAnimationsForTesting()); // Ensure we can remove a pending threaded animation. l1->GetAnimator()->StopAnimating(); - EXPECT_FALSE(l1->HasPendingThreadedAnimations()); + EXPECT_FALSE(l1->HasPendingThreadedAnimationsForTesting()); // Trigger another threaded animation. l1->SetOpacity(0.2f); - EXPECT_TRUE(l1->HasPendingThreadedAnimations()); + EXPECT_TRUE(l1->HasPendingThreadedAnimationsForTesting()); root->Add(l1.get()); GetCompositor()->SetRootLayer(root.get()); // Now that l1 is part of a tree, it should have dispatched the pending // animation. - EXPECT_FALSE(l1->HasPendingThreadedAnimations()); + EXPECT_FALSE(l1->HasPendingThreadedAnimationsForTesting()); // Ensure that l1 no longer holds on to animations. l1->SetOpacity(0.1f); - EXPECT_FALSE(l1->HasPendingThreadedAnimations()); + EXPECT_FALSE(l1->HasPendingThreadedAnimationsForTesting()); // Ensure that adding a layer to an existing tree causes its pending // animations to get dispatched. l2->SetOpacity(0.5f); - EXPECT_TRUE(l2->HasPendingThreadedAnimations()); + EXPECT_TRUE(l2->HasPendingThreadedAnimationsForTesting()); l1->Add(l2.get()); - EXPECT_FALSE(l2->HasPendingThreadedAnimations()); + EXPECT_FALSE(l2->HasPendingThreadedAnimationsForTesting()); } // Tests that in-progress threaded animations complete when a Layer's
diff --git a/ui/compositor/test/test_layer_animation_delegate.cc b/ui/compositor/test/test_layer_animation_delegate.cc index 140e81ea..980e3978 100644 --- a/ui/compositor/test/test_layer_animation_delegate.cc +++ b/ui/compositor/test/test_layer_animation_delegate.cc
@@ -7,6 +7,10 @@ namespace ui { +TestLayerThreadedAnimationDelegate::TestLayerThreadedAnimationDelegate() {} + +TestLayerThreadedAnimationDelegate::~TestLayerThreadedAnimationDelegate() {} + TestLayerAnimationDelegate::TestLayerAnimationDelegate() : opacity_(1.0f), visibility_(true), @@ -94,13 +98,6 @@ return 1.0f; } -void TestLayerAnimationDelegate::AddThreadedAnimation( - scoped_ptr<cc::Animation> animation) { -} - -void TestLayerAnimationDelegate::RemoveThreadedAnimation(int animation_id) { -} - LayerAnimatorCollection* TestLayerAnimationDelegate::GetLayerAnimatorCollection() { return NULL; @@ -110,8 +107,19 @@ return cc_layer_.get(); } +LayerThreadedAnimationDelegate* +TestLayerAnimationDelegate::GetThreadedAnimationDelegate() { + return &threaded_delegate_; +} + void TestLayerAnimationDelegate::CreateCcLayer() { cc_layer_ = cc::Layer::Create(ui::Layer::UILayerSettings()); } +void TestLayerThreadedAnimationDelegate::AddThreadedAnimation( + scoped_ptr<cc::Animation> animation) {} + +void TestLayerThreadedAnimationDelegate::RemoveThreadedAnimation( + int animation_id) {} + } // namespace ui
diff --git a/ui/compositor/test/test_layer_animation_delegate.h b/ui/compositor/test/test_layer_animation_delegate.h index f06f054..ef4215835 100644 --- a/ui/compositor/test/test_layer_animation_delegate.h +++ b/ui/compositor/test/test_layer_animation_delegate.h
@@ -8,11 +8,23 @@ #include "base/compiler_specific.h" #include "cc/layers/layer.h" #include "ui/compositor/layer_animation_delegate.h" +#include "ui/compositor/layer_threaded_animation_delegate.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/transform.h" namespace ui { +class TestLayerThreadedAnimationDelegate + : public LayerThreadedAnimationDelegate { + public: + TestLayerThreadedAnimationDelegate(); + ~TestLayerThreadedAnimationDelegate() override; + + // Implementation of LayerThreadedAnimationDelegate + void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) override; + void RemoveThreadedAnimation(int animation_id) override; +}; + class TestLayerAnimationDelegate : public LayerAnimationDelegate { public: TestLayerAnimationDelegate(); @@ -36,14 +48,15 @@ float GetGrayscaleForAnimation() const override; SkColor GetColorForAnimation() const override; float GetDeviceScaleFactor() const override; - void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) override; - void RemoveThreadedAnimation(int animation_id) override; LayerAnimatorCollection* GetLayerAnimatorCollection() override; cc::Layer* GetCcLayer() const override; + LayerThreadedAnimationDelegate* GetThreadedAnimationDelegate() override; private: void CreateCcLayer(); + TestLayerThreadedAnimationDelegate threaded_delegate_; + gfx::Rect bounds_; gfx::Transform transform_; float opacity_;
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc index b0b76596..8511af6 100644 --- a/ui/events/blink/input_handler_proxy.cc +++ b/ui/events/blink/input_handler_proxy.cc
@@ -359,6 +359,51 @@ return DID_NOT_HANDLE; } +void RecordMainThreadScrollingReasons( + WebInputEvent::Type type, + cc::InputHandler::MainThreadScrollingReason reasons) { + static const char* kGestureHistogramName = + "Renderer4.MainThreadGestureScrollReason"; + static const char* kWheelHistogramName = + "Renderer4.MainThreadWheelScrollReason"; + + DCHECK(type == WebInputEvent::GestureScrollBegin || + type == WebInputEvent::MouseWheel); + + if (type != WebInputEvent::GestureScrollBegin && + type != WebInputEvent::MouseWheel) { + return; + } + + if (reasons == cc::InputHandler::NOT_SCROLLING_ON_MAIN) { + if (type == WebInputEvent::GestureScrollBegin) { + UMA_HISTOGRAM_ENUMERATION( + kGestureHistogramName, cc::InputHandler::NOT_SCROLLING_ON_MAIN, + cc::InputHandler::MainThreadScrollingReasonCount); + } else { + UMA_HISTOGRAM_ENUMERATION( + kWheelHistogramName, cc::InputHandler::NOT_SCROLLING_ON_MAIN, + cc::InputHandler::MainThreadScrollingReasonCount); + } + } + + for (int i = 0; i < cc::InputHandler::MainThreadScrollingReasonCount - 1; + ++i) { + unsigned val = 1 << i; + if (reasons & val) { + if (type == WebInputEvent::GestureScrollBegin) { + UMA_HISTOGRAM_ENUMERATION( + kGestureHistogramName, i + 1, + cc::InputHandler::MainThreadScrollingReasonCount); + } else { + UMA_HISTOGRAM_ENUMERATION( + kWheelHistogramName, i + 1, + cc::InputHandler::MainThreadScrollingReasonCount); + } + } + } +} + bool InputHandlerProxy::ShouldAnimate( const blink::WebMouseWheelEvent& event) const { #if defined(OS_MACOSX) @@ -396,8 +441,12 @@ cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollAnimated(gfx::Point(wheel_event.x, wheel_event.y), scroll_delta); - switch (scroll_status) { - case cc::InputHandler::SCROLL_STARTED: + + RecordMainThreadScrollingReasons( + wheel_event.type, scroll_status.main_thread_scrolling_reasons); + + switch (scroll_status.thread) { + case cc::InputHandler::SCROLL_ON_IMPL_THREAD: result = DID_HANDLE; break; case cc::InputHandler::SCROLL_IGNORED: @@ -410,11 +459,14 @@ } else { cc::ScrollState scroll_state_begin(0, 0, wheel_event.x, wheel_event.y, 0, 0, true, false, false); - cc::InputHandler::ScrollStatus scroll_status = - input_handler_->ScrollBegin(&scroll_state_begin, - cc::InputHandler::WHEEL); - switch (scroll_status) { - case cc::InputHandler::SCROLL_STARTED: { + cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollBegin( + &scroll_state_begin, cc::InputHandler::WHEEL); + + RecordMainThreadScrollingReasons( + wheel_event.type, scroll_status.main_thread_scrolling_reasons); + + switch (scroll_status.thread) { + case cc::InputHandler::SCROLL_ON_IMPL_THREAD: { TRACE_EVENT_INSTANT2("input", "InputHandlerProxy::handle_input wheel scroll", TRACE_EVENT_SCOPE_THREAD, "deltaX", @@ -487,10 +539,14 @@ input_handler_->ScrollBegin(&scroll_state, cc::InputHandler::GESTURE); } UMA_HISTOGRAM_ENUMERATION("Renderer4.CompositorScrollHitTestResult", - scroll_status, + scroll_status.thread, cc::InputHandler::ScrollStatusCount); - switch (scroll_status) { - case cc::InputHandler::SCROLL_STARTED: + + RecordMainThreadScrollingReasons(gesture_event.type, + scroll_status.main_thread_scrolling_reasons); + + switch (scroll_status.thread) { + case cc::InputHandler::SCROLL_ON_IMPL_THREAD: TRACE_EVENT_INSTANT0("input", "InputHandlerProxy::handle_input gesture scroll", TRACE_EVENT_SCOPE_THREAD); @@ -542,8 +598,9 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureFlingStart( const WebGestureEvent& gesture_event) { cc::ScrollState scroll_state = CreateScrollStateForGesture(gesture_event); - cc::InputHandler::ScrollStatus scroll_status = - cc::InputHandler::SCROLL_ON_MAIN_THREAD; + cc::InputHandler::ScrollStatus scroll_status; + scroll_status.main_thread_scrolling_reasons = + cc::InputHandler::NOT_SCROLLING_ON_MAIN; switch (gesture_event.sourceDevice) { case blink::WebGestureDeviceTouchpad: if (gesture_event.data.flingStart.targetViewport) { @@ -555,10 +612,13 @@ } break; case blink::WebGestureDeviceTouchscreen: - if (!gesture_scroll_on_impl_thread_) - scroll_status = cc::InputHandler::SCROLL_ON_MAIN_THREAD; - else + if (!gesture_scroll_on_impl_thread_) { + scroll_status.thread = cc::InputHandler::SCROLL_ON_MAIN_THREAD; + scroll_status.main_thread_scrolling_reasons = + cc::InputHandler::CONTINUING_MAIN_THREAD_SCROLL; + } else { scroll_status = input_handler_->FlingScrollBegin(); + } break; case blink::WebGestureDeviceUninitialized: NOTREACHED(); @@ -569,8 +629,8 @@ expect_scroll_update_end_ = false; #endif - switch (scroll_status) { - case cc::InputHandler::SCROLL_STARTED: { + switch (scroll_status.thread) { + case cc::InputHandler::SCROLL_ON_IMPL_THREAD: { if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad) { scroll_state.set_is_ending(true); input_handler_->ScrollEnd(&scroll_state);
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc index ccf24f4..3beb7e86 100644 --- a/ui/events/blink/input_handler_proxy_unittest.cc +++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -242,6 +242,18 @@ return point; } +const cc::InputHandler::ScrollStatus kImplThreadScrollState( + cc::InputHandler::SCROLL_ON_IMPL_THREAD, + cc::InputHandler::NOT_SCROLLING_ON_MAIN); + +const cc::InputHandler::ScrollStatus kMainThreadScrollState( + cc::InputHandler::SCROLL_ON_MAIN_THREAD, + cc::InputHandler::EVENT_HANDLERS); + +const cc::InputHandler::ScrollStatus kScrollIgnoredScrollState( + cc::InputHandler::SCROLL_IGNORED, + cc::InputHandler::NOT_SCROLLABLE); + } // namespace class InputHandlerProxyTest @@ -321,7 +333,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = source_device; EXPECT_EQ(expected_disposition_, @@ -330,7 +342,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); gesture_ = @@ -404,7 +416,7 @@ // Smooth scroll because hasPreciseScrollingDeltas is set to false. wheel.hasPreciseScrollingDeltas = false; EXPECT_CALL(mock_input_handler_, ScrollAnimated(::testing::_, ::testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); VERIFY_AND_RESET_MOCKS(); @@ -412,7 +424,7 @@ // No smooth scroll because hasPreciseScrollingDeltas is set to true. wheel.hasPreciseScrollingDeltas = true; EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollBy(::testing::_)) .WillOnce(testing::Return(scroll_result_did_scroll_)); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); @@ -433,7 +445,7 @@ wheel.type = WebInputEvent::MouseWheel; EXPECT_CALL(mock_input_handler_, ScrollAnimated(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED)); + .WillOnce(testing::Return(kScrollIgnoredScrollState)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); VERIFY_AND_RESET_MOCKS(); @@ -445,7 +457,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; EXPECT_EQ(expected_disposition_,input_handler_->HandleInputEvent(gesture_)); @@ -492,7 +504,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); + .WillOnce(testing::Return(kMainThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -524,7 +536,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED)); + .WillOnce(testing::Return(kScrollIgnoredScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -544,7 +556,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, RootScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.data.scrollBegin.targetViewport = true; @@ -640,7 +652,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); + .WillOnce(testing::Return(kMainThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -717,7 +729,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); @@ -740,7 +752,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); + .WillOnce(testing::Return(kMainThreadScrollState)); gesture_.type = WebInputEvent::GestureFlingStart; gesture_.sourceDevice = blink::WebGestureDeviceTouchpad; @@ -764,7 +776,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED)); + .WillOnce(testing::Return(kScrollIgnoredScrollState)); gesture_.type = WebInputEvent::GestureFlingStart; gesture_.sourceDevice = blink::WebGestureDeviceTouchpad; @@ -801,7 +813,7 @@ modifiers); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -822,7 +834,7 @@ // The second call should start scrolling in the -X direction. EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL( mock_input_handler_, ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0)))) @@ -839,7 +851,7 @@ // rest of the fling can be // transferred to the main thread. EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); + .WillOnce(testing::Return(kMainThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)).Times(0); // Expected wheel fling animation parameters: @@ -907,7 +919,7 @@ modifiers); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -926,7 +938,7 @@ // The second call should start scrolling in the -X direction. EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL( mock_input_handler_, ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0)))) @@ -943,7 +955,8 @@ // rest of the fling can be // transferred to the main thread. EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); + .WillOnce(testing::Return(kMainThreadScrollState)); + EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)).Times(0); @@ -1007,7 +1020,7 @@ modifiers); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); expected_disposition_ = InputHandlerProxy::DID_HANDLE; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1026,7 +1039,7 @@ // Tick the second fling once normally. EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL( mock_input_handler_, ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)))) @@ -1039,7 +1052,7 @@ // Then abort the second fling. EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); + .WillOnce(testing::Return(kMainThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)).Times(0); @@ -1072,7 +1085,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1080,7 +1093,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); gesture_.type = WebInputEvent::GestureFlingStart; @@ -1106,7 +1119,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); + .WillOnce(testing::Return(kMainThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1133,7 +1146,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; @@ -1145,7 +1158,7 @@ // Flings ignored by the InputHandler should be dropped, signalling the end // of the touch scroll sequence. EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED)); + .WillOnce(testing::Return(kScrollIgnoredScrollState)); gesture_.type = WebInputEvent::GestureFlingStart; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; @@ -1157,7 +1170,7 @@ // GestureFlingCancel, as the original GestureFlingStart was dropped. expected_disposition_ = InputHandlerProxy::DID_HANDLE; EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1171,7 +1184,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; @@ -1193,7 +1206,7 @@ modifiers); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); VERIFY_AND_RESET_MOCKS(); @@ -1232,7 +1245,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; @@ -1256,7 +1269,7 @@ modifiers); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); VERIFY_AND_RESET_MOCKS(); @@ -1288,7 +1301,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; @@ -1315,7 +1328,7 @@ gesture_.modifiers = modifiers; EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); VERIFY_AND_RESET_MOCKS(); @@ -1353,7 +1366,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1378,7 +1391,7 @@ modifiers); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); // |gesture_scroll_on_impl_thread_| should still be true after @@ -1426,7 +1439,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1448,7 +1461,7 @@ fling_point, fling_global_point, modifiers); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); // |gesture_scroll_on_impl_thread_| should still be true after @@ -1461,7 +1474,7 @@ // result, this scroll begin will cancel the previous fling. EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1484,7 +1497,7 @@ gesture_.data.flingStart.velocityX = fling_delta.x; gesture_.data.flingStart.velocityY = fling_delta.y; EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1498,7 +1511,7 @@ // The second animate starts scrolling in the positive X and Y directions. EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL( mock_input_handler_, ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0)))) @@ -1517,7 +1530,7 @@ overscroll.accumulated_root_overscroll = gfx::Vector2dF(0, 100); overscroll.unused_scroll_delta = gfx::Vector2dF(0, 10); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL( mock_input_handler_, ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0)))) @@ -1538,7 +1551,7 @@ // The next call to animate will no longer scroll vertically. EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL( mock_input_handler_, ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Eq(0)))) @@ -1555,7 +1568,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; @@ -1579,7 +1592,7 @@ modifiers); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); VERIFY_AND_RESET_MOCKS(); @@ -1636,7 +1649,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1649,7 +1662,7 @@ gesture_.data.flingStart.velocityX = fling_delta.x; gesture_.data.flingStart.velocityY = fling_delta.y; EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); VERIFY_AND_RESET_MOCKS(); @@ -1790,7 +1803,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -1811,7 +1824,7 @@ gesture_.data.flingStart.velocityX = fling_delta.x; gesture_.data.flingStart.velocityY = fling_delta.y; EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); @@ -1842,7 +1855,7 @@ VERIFY_AND_RESET_MOCKS(); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); gesture_.type = WebInputEvent::GestureScrollBegin; gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; @@ -1866,7 +1879,7 @@ modifiers); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); VERIFY_AND_RESET_MOCKS(); @@ -2051,7 +2064,7 @@ .WillOnce(testing::Return(false)); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); time += dt; gesture_.timeStampSeconds = InSecondsF(time); @@ -2092,7 +2105,7 @@ time += base::TimeDelta::FromMilliseconds(100); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); Animate(time); VERIFY_AND_RESET_MOCKS(); @@ -2137,7 +2150,7 @@ gesture_.data.scrollUpdate.deltaY = -40; EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)) .WillOnce(testing::Return(scroll_result_did_scroll_)); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); @@ -2220,7 +2233,7 @@ gesture_.data.scrollUpdate.deltaX = -fling_delta.x; EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Eq(fling_delta.x)))) @@ -2327,7 +2340,7 @@ .WillOnce(testing::Return(scroll_result_did_not_scroll_)); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); Animate(time); VERIFY_AND_RESET_MOCKS(); @@ -2377,7 +2390,7 @@ gesture_.data.flingStart.velocityY = fling_delta.y; EXPECT_SET_NEEDS_ANIMATE_INPUT(1); EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); + .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)); EXPECT_EQ(InputHandlerProxy::DID_HANDLE, input_handler_->HandleInputEvent(gesture_));
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni index c5855dfe..7f75f2d 100644 --- a/ui/ozone/ozone.gni +++ b/ui/ozone/ozone.gni
@@ -3,10 +3,11 @@ # found in the LICENSE file. import("//build/config/chromecast_build.gni") +import("//build/config/ui.gni") declare_args() { # Select platforms automatically. Turn this off for manual control. - ozone_auto_platforms = true + ozone_auto_platforms = use_ozone # This enables memory-mapped access to accelerated graphics buffers via the # VGEM ("virtual GEM") driver. This is currently only available on Chrome OS @@ -61,3 +62,8 @@ } } } + +assert(use_ozone || !(ozone_platform_caca || ozone_platform_cast || + ozone_platform_egltest || ozone_platform_gbm || + ozone_platform_ozonex || ozone_platform_headless), + "Must set use_ozone to select ozone platforms")
diff --git a/ui/shell_dialogs/BUILD.gn b/ui/shell_dialogs/BUILD.gn index 4ecd64c..01afac9a 100644 --- a/ui/shell_dialogs/BUILD.gn +++ b/ui/shell_dialogs/BUILD.gn
@@ -70,10 +70,6 @@ "select_file_dialog_auraandroid.h", ] } - - if (is_win) { - deps += [ "//win8:metro_viewer" ] - } } test("shell_dialogs_unittests") {
diff --git a/ui/shell_dialogs/select_file_dialog_win.cc b/ui/shell_dialogs/select_file_dialog_win.cc index 40215a34..4cd8896b 100644 --- a/ui/shell_dialogs/select_file_dialog_win.cc +++ b/ui/shell_dialogs/select_file_dialog_win.cc
@@ -30,7 +30,6 @@ #include "ui/shell_dialogs/base_shell_dialog_win.h" #include "ui/shell_dialogs/shell_dialogs_delegate.h" #include "ui/strings/grit/ui_strings.h" -#include "win8/viewer/metro_viewer_process_host.h" namespace { @@ -328,59 +327,6 @@ void* params) { has_multiple_file_type_choices_ = file_types ? file_types->extensions.size() > 1 : true; - // If the owning_window passed in is in metro then we need to forward the - // file open/save operations to metro. - if (GetShellDialogsDelegate() && - GetShellDialogsDelegate()->IsWindowInMetro(owning_window)) { - if (type == SELECT_SAVEAS_FILE) { - win8::MetroViewerProcessHost::HandleSaveFile( - title, - default_path, - GetFilterForFileTypes(file_types), - file_type_index, - default_extension, - base::Bind(&ui::SelectFileDialog::Listener::FileSelected, - base::Unretained(listener_)), - base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled, - base::Unretained(listener_))); - return; - } else if (type == SELECT_OPEN_FILE) { - win8::MetroViewerProcessHost::HandleOpenFile( - title, - default_path, - GetFilterForFileTypes(file_types), - base::Bind(&ui::SelectFileDialog::Listener::FileSelected, - base::Unretained(listener_)), - base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled, - base::Unretained(listener_))); - return; - } else if (type == SELECT_OPEN_MULTI_FILE) { - win8::MetroViewerProcessHost::HandleOpenMultipleFiles( - title, - default_path, - GetFilterForFileTypes(file_types), - base::Bind(&ui::SelectFileDialog::Listener::MultiFilesSelected, - base::Unretained(listener_)), - base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled, - base::Unretained(listener_))); - return; - } else if (type == SELECT_FOLDER || type == SELECT_UPLOAD_FOLDER) { - base::string16 title_string = title; - if (type == SELECT_UPLOAD_FOLDER && title_string.empty()) { - // If it's for uploading don't use default dialog title to - // make sure we clearly tell it's for uploading. - title_string = l10n_util::GetStringUTF16( - IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE); - } - win8::MetroViewerProcessHost::HandleSelectFolder( - title_string, - base::Bind(&ui::SelectFileDialog::Listener::FileSelected, - base::Unretained(listener_)), - base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled, - base::Unretained(listener_))); - return; - } - } HWND owner = owning_window && owning_window->GetRootWindow() ? owning_window->GetHost()->GetAcceleratedWidget() : NULL;
diff --git a/ui/shell_dialogs/shell_dialogs.gyp b/ui/shell_dialogs/shell_dialogs.gyp index 0d541fc..2329f8f 100644 --- a/ui/shell_dialogs/shell_dialogs.gyp +++ b/ui/shell_dialogs/shell_dialogs.gyp
@@ -74,13 +74,6 @@ }, } ], - ['OS=="win"', - { - 'dependencies': [ - '../../win8/win8.gyp:metro_viewer', - ], - } - ], ], }, # target_name: shell_dialogs {
diff --git a/win8/BUILD.gn b/win8/BUILD.gn index fb43d2d..7b36f33 100644 --- a/win8/BUILD.gn +++ b/win8/BUILD.gn
@@ -2,31 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -source_set("metro_viewer_constants") { - sources = [ - "viewer/metro_viewer_constants.cc", - "viewer/metro_viewer_constants.h", - ] -} - -component("metro_viewer") { - sources = [ - "viewer/metro_viewer_process_host.cc", - "viewer/metro_viewer_process_host.h", - ] - - defines = [ "METRO_VIEWER_IMPLEMENTATION" ] - - deps = [ - ":metro_viewer_constants", - "//base", - "//ipc", - "//ui/aura", - "//ui/gfx", - "//ui/metro_viewer", - ] -} - source_set("test_support_win8") { sources = [ "test/open_with_dialog_async.cc",
diff --git a/win8/delegate_execute/BUILD.gn b/win8/delegate_execute/BUILD.gn index 8309dc66..4b7d911 100644 --- a/win8/delegate_execute/BUILD.gn +++ b/win8/delegate_execute/BUILD.gn
@@ -50,10 +50,6 @@ "//ui/gfx/geometry", ] - if (use_aura) { - public_deps += [ "//win8:metro_viewer_constants" ] - } - if (is_chrome_branded) { public_deps += [ "//google_update" ] }
diff --git a/win8/delegate_execute/command_execute_impl.cc b/win8/delegate_execute/command_execute_impl.cc index 236f862..2711336b 100644 --- a/win8/delegate_execute/command_execute_impl.cc +++ b/win8/delegate_execute/command_execute_impl.cc
@@ -32,7 +32,6 @@ #include "ui/gfx/win/dpi.h" #include "win8/delegate_execute/chrome_util.h" #include "win8/delegate_execute/delegate_execute_util.h" -#include "win8/viewer/metro_viewer_constants.h" namespace { // Helper function to retrieve the url from IShellItem interface passed in. @@ -219,18 +218,8 @@ return E_FAIL; } - EC_HOST_UI_MODE mode = GetLaunchMode(); - *pahe = (mode == ECHUIM_DESKTOP) ? AHE_DESKTOP : AHE_IMMERSIVE; - - // If we're going to return AHE_IMMERSIVE, then both the browser process and - // the metro viewer need to launch and connect before the user can start - // browsing. However we must not launch the metro viewer until we get a - // call to CommandExecuteImpl::Execute(). If we wait until then to launch - // the browser process as well, it will appear laggy while they connect to - // each other, so we pre-launch the browser process now. - if (*pahe == AHE_IMMERSIVE && verb_ != win8::kMetroViewerConnectVerb) { - LaunchChromeBrowserProcess(); - } + // TODO(scottmg): Can all go eventually https://crbug.com/558054. + *pahe = AHE_DESKTOP; return S_OK; }
diff --git a/win8/delegate_execute/delegate_execute.gyp b/win8/delegate_execute/delegate_execute.gyp index 8dcd71f..b863dc56 100644 --- a/win8/delegate_execute/delegate_execute.gyp +++ b/win8/delegate_execute/delegate_execute.gyp
@@ -73,11 +73,6 @@ }, }, 'conditions': [ - ['use_aura==1', { - 'dependencies': [ - '../win8.gyp:metro_viewer_constants', - ], - }], ['branding!="Chrome"', { 'dependencies!': [ '../../google_update/google_update.gyp:google_update',
diff --git a/win8/metro_driver/BUILD.gn b/win8/metro_driver/BUILD.gn index 68c9a90f..fc666901 100644 --- a/win8/metro_driver/BUILD.gn +++ b/win8/metro_driver/BUILD.gn
@@ -10,9 +10,6 @@ sources = [ "display_properties.cc", "display_properties.h", - "metro_driver.cc", - "metro_driver.h", - "metro_driver_win7.cc", "stdafx.h", "winrt_utils.cc", "winrt_utils.h", @@ -36,17 +33,12 @@ if (use_aura) { sources += [ - "chrome_app_view_ash.cc", - "chrome_app_view_ash.h", "direct3d_helper.cc", "direct3d_helper.h", - "file_picker_ash.cc", - "file_picker_ash.h", ] deps += [ "//ui/events:gesture_detection", - "//win8:metro_viewer_constants", "//win8/metro_driver/ime", ] } else { @@ -57,8 +49,6 @@ "chrome_url_launch_handler.h", "devices_handler.cc", "devices_handler.h", - "file_picker.cc", - "file_picker.h", "metro_dialog_box.cc", "metro_dialog_box.h", "print_document_source.cc",
diff --git a/win8/metro_driver/chrome_app_view_ash.cc b/win8/metro_driver/chrome_app_view_ash.cc deleted file mode 100644 index 01f9ba23..0000000 --- a/win8/metro_driver/chrome_app_view_ash.cc +++ /dev/null
@@ -1,1464 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "win8/metro_driver/stdafx.h" -#include "win8/metro_driver/chrome_app_view_ash.h" - -#include <corewindow.h> -#include <shellapi.h> -#include <stdint.h> -#include <windows.foundation.h> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "base/single_thread_task_runner.h" -#include "base/win/windows_version.h" -#include "chrome/common/chrome_switches.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_sender.h" -#include "ui/events/gesture_detection/motion_event.h" -#include "ui/events/win/system_event_state_lookup.h" -#include "ui/gfx/geometry/point_conversions.h" -#include "ui/gfx/win/dpi.h" -#include "ui/metro_viewer/metro_viewer_messages.h" -#include "win8/metro_driver/file_picker_ash.h" -#include "win8/metro_driver/ime/ime_popup_monitor.h" -#include "win8/metro_driver/ime/input_source.h" -#include "win8/metro_driver/ime/text_service.h" -#include "win8/metro_driver/metro_driver.h" -#include "win8/metro_driver/winrt_utils.h" -#include "win8/viewer/metro_viewer_constants.h" - -typedef winfoundtn::ITypedEventHandler< - winapp::Core::CoreApplicationView*, - winapp::Activation::IActivatedEventArgs*> ActivatedHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::PointerEventArgs*> PointerEventHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::KeyEventArgs*> KeyEventHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreDispatcher*, - winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::CharacterReceivedEventArgs*> CharEventHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::WindowActivatedEventArgs*> WindowActivatedHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Input::EdgeGesture*, - winui::Input::EdgeGestureEventArgs*> EdgeEventHandler; - -// This function is exported by chrome.exe. -typedef int (__cdecl *BreakpadExceptionHandler)(EXCEPTION_POINTERS* info); - -// Global information used across the metro driver. -struct Globals { - winapp::Activation::ApplicationExecutionState previous_state; - winapp::Core::ICoreApplicationExit* app_exit; - BreakpadExceptionHandler breakpad_exception_handler; -} globals; - -extern float GetModernUIScale(); - -namespace { - -enum KeyModifier { - NONE, - SHIFT = 1, - CONTROL = 2, - ALT = 4 -}; - -const int kChromeChannelPollTimerMs = 100; - -// Helper function to send keystrokes via the SendInput function. -// mnemonic_char: The keystroke to be sent. -// modifiers: Combination with Alt, Ctrl, Shift, etc. -void SendKeySequence( - WORD mnemonic_char, KeyModifier modifiers) { - INPUT keys[4] = {}; // Keyboard events - int key_count = 0; // Number of generated events - - if (modifiers & SHIFT) { - keys[key_count].type = INPUT_KEYBOARD; - keys[key_count].ki.wVk = VK_SHIFT; - keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0); - key_count++; - } - - if (modifiers & CONTROL) { - keys[key_count].type = INPUT_KEYBOARD; - keys[key_count].ki.wVk = VK_CONTROL; - keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0); - key_count++; - } - - if (modifiers & ALT) { - keys[key_count].type = INPUT_KEYBOARD; - keys[key_count].ki.wVk = VK_MENU; - keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0); - key_count++; - } - - keys[key_count].type = INPUT_KEYBOARD; - keys[key_count].ki.wVk = mnemonic_char; - keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0); - key_count++; - - bool should_sleep = key_count > 1; - - // Send key downs. - for (int i = 0; i < key_count; i++) { - SendInput(1, &keys[ i ], sizeof(keys[0])); - keys[i].ki.dwFlags |= KEYEVENTF_KEYUP; - if (should_sleep) - Sleep(10); - } - - // Now send key ups in reverse order. - for (int i = key_count; i; i--) { - SendInput(1, &keys[ i - 1 ], sizeof(keys[0])); - if (should_sleep) - Sleep(10); - } -} - -class ChromeChannelListener : public IPC::Listener { - public: - ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view) - : ui_task_runner_(ui_loop->task_runner()), app_view_(app_view) {} - - bool OnMessageReceived(const IPC::Message& message) override { - IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop, - OnActivateDesktop) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MetroExit, OnMetroExit) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop, - OnOpenURLOnDesktop) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen, - OnDisplayFileOpenDialog) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs, - OnDisplayFileSaveAsDialog) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder, - OnDisplayFolderPicker) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCancelComposition, - OnImeCancelComposition) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextInputClientUpdated, - OnImeTextInputClientChanged) - IPC_MESSAGE_UNHANDLED(__debugbreak()) - IPC_END_MESSAGE_MAP() - return true; - } - - void OnChannelError() override { - DVLOG(1) << "Channel error. Exiting."; - ui_task_runner_->PostTask( - FROM_HERE, - base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_), - TERMINATE_USING_KEY_SEQUENCE)); - - // In early Windows 8 versions the code above sometimes fails so we call - // it a second time with a NULL window which just calls Exit(). - ui_task_runner_->PostDelayedTask( - FROM_HERE, - base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_), - TERMINATE_USING_PROCESS_EXIT), - base::TimeDelta::FromMilliseconds(100)); - } - - private: - void OnActivateDesktop(const base::FilePath& shortcut, bool ash_exit) { - ui_task_runner_->PostTask( - FROM_HERE, base::Bind(&ChromeAppViewAsh::OnActivateDesktop, - base::Unretained(app_view_), shortcut, ash_exit)); - } - - void OnMetroExit() { - ui_task_runner_->PostTask( - FROM_HERE, - base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_), - TERMINATE_USING_KEY_SEQUENCE)); - } - - void OnOpenURLOnDesktop(const base::FilePath& shortcut, - const base::string16& url) { - ui_task_runner_->PostTask( - FROM_HERE, base::Bind(&ChromeAppViewAsh::OnOpenURLOnDesktop, - base::Unretained(app_view_), shortcut, url)); - } - - void OnSetCursor(int64_t cursor) { - ui_task_runner_->PostTask( - FROM_HERE, - base::Bind(&ChromeAppViewAsh::OnSetCursor, base::Unretained(app_view_), - reinterpret_cast<HCURSOR>(cursor))); - } - - void OnDisplayFileOpenDialog(const base::string16& title, - const base::string16& filter, - const base::FilePath& default_path, - bool allow_multiple_files) { - ui_task_runner_->PostTask( - FROM_HERE, base::Bind(&ChromeAppViewAsh::OnDisplayFileOpenDialog, - base::Unretained(app_view_), title, filter, - default_path, allow_multiple_files)); - } - - void OnDisplayFileSaveAsDialog( - const MetroViewerHostMsg_SaveAsDialogParams& params) { - ui_task_runner_->PostTask( - FROM_HERE, base::Bind(&ChromeAppViewAsh::OnDisplayFileSaveAsDialog, - base::Unretained(app_view_), params)); - } - - void OnDisplayFolderPicker(const base::string16& title) { - ui_task_runner_->PostTask( - FROM_HERE, base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker, - base::Unretained(app_view_), title)); - } - - void OnSetCursorPos(int x, int y) { - VLOG(1) << "In IPC OnSetCursorPos: " << x << ", " << y; - ui_task_runner_->PostTask(FROM_HERE, - base::Bind(&ChromeAppViewAsh::OnSetCursorPos, - base::Unretained(app_view_), x, y)); - } - - void OnImeCancelComposition() { - ui_task_runner_->PostTask( - FROM_HERE, base::Bind(&ChromeAppViewAsh::OnImeCancelComposition, - base::Unretained(app_view_))); - } - - void OnImeTextInputClientChanged( - const std::vector<int32_t>& input_scopes, - const std::vector<metro_viewer::CharacterBounds>& character_bounds) { - ui_task_runner_->PostTask( - FROM_HERE, base::Bind(&ChromeAppViewAsh::OnImeUpdateTextInputClient, - base::Unretained(app_view_), input_scopes, - character_bounds)); - } - - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; - ChromeAppViewAsh* app_view_; -}; - -void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) { - // We're entering a nested message loop, let's allow dispatching - // tasks while we're in there. - base::MessageLoop::current()->SetNestableTasksAllowed(true); - - // Enter main core message loop. There are several ways to exit it - // Nicely: - // 1 - User action like ALT-F4. - // 2 - Calling ICoreApplicationExit::Exit(). - // 3- Posting WM_CLOSE to the core window. - dispatcher->ProcessEvents( - winui::Core::CoreProcessEventsOption - ::CoreProcessEventsOption_ProcessUntilQuit); - - // Wind down the thread's chrome message loop. - base::MessageLoop::current()->QuitWhenIdle(); -} - -// Helper to return the state of the shift/control/alt keys. -uint32_t GetKeyboardEventFlags() { - uint32_t flags = 0; - if (ui::win::IsShiftPressed()) - flags |= ui::EF_SHIFT_DOWN; - if (ui::win::IsCtrlPressed()) - flags |= ui::EF_CONTROL_DOWN; - if (ui::win::IsAltPressed()) - flags |= ui::EF_ALT_DOWN; - return flags; -} - -bool LaunchChromeBrowserProcess(const wchar_t* additional_parameters, - winapp::Activation::IActivatedEventArgs* args) { - if (args) { - DVLOG(1) << __FUNCTION__ << ":" << ::GetCommandLineW(); - winapp::Activation::ActivationKind activation_kind; - CheckHR(args->get_Kind(&activation_kind)); - - DVLOG(1) << __FUNCTION__ << ", activation_kind=" << activation_kind; - - if (activation_kind == winapp::Activation::ActivationKind_Launch) { - mswr::ComPtr<winapp::Activation::ILaunchActivatedEventArgs> launch_args; - if (args->QueryInterface( - winapp::Activation::IID_ILaunchActivatedEventArgs, - &launch_args) == S_OK) { - DVLOG(1) << "Activate: ActivationKind_Launch"; - mswrw::HString launch_args_str; - launch_args->get_Arguments(launch_args_str.GetAddressOf()); - base::string16 actual_launch_args( - MakeStdWString(launch_args_str.Get())); - if (actual_launch_args == win8::kMetroViewerConnectVerb) { - DVLOG(1) << __FUNCTION__ << "Not launching chrome server"; - return true; - } - } - } - } - - DVLOG(1) << "Launching chrome server"; - base::FilePath chrome_exe_path; - - if (!PathService::Get(base::FILE_EXE, &chrome_exe_path)) - return false; - - base::string16 parameters = L"--silent-launch --connect-to-metro-viewer "; - if (additional_parameters) - parameters += additional_parameters; - - SHELLEXECUTEINFO sei = { sizeof(sei) }; - sei.nShow = SW_SHOWNORMAL; - sei.lpFile = chrome_exe_path.value().c_str(); - sei.lpDirectory = L""; - sei.lpParameters = parameters.c_str(); - ::ShellExecuteEx(&sei); - return true; -} - -} // namespace - -// This class helps decoding the pointer properties of an event. -class ChromeAppViewAsh::PointerInfoHandler { - public: - PointerInfoHandler(float metro_dpi_scale, float win32_dpi_scale) - : x_(0), - y_(0), - wheel_delta_(0), - pointer_id_(0), - update_kind_(winui::Input::PointerUpdateKind_Other), - timestamp_(0), - mouse_down_flags_(0), - is_horizontal_wheel_(0), - metro_dpi_scale_(metro_dpi_scale), - win32_dpi_scale_(win32_dpi_scale) {} - - HRESULT Init(winui::Core::IPointerEventArgs* args) { - HRESULT hr = args->get_CurrentPoint(&pointer_point_); - if (FAILED(hr)) - return hr; - - winfoundtn::Point point; - hr = pointer_point_->get_Position(&point); - if (FAILED(hr)) - return hr; - - mswr::ComPtr<winui::Input::IPointerPointProperties> properties; - hr = pointer_point_->get_Properties(&properties); - if (FAILED(hr)) - return hr; - - hr = properties->get_PointerUpdateKind(&update_kind_); - if (FAILED(hr)) - return hr; - - hr = properties->get_MouseWheelDelta(&wheel_delta_); - if (FAILED(hr)) - return hr; - - is_horizontal_wheel_ = 0; - properties->get_IsHorizontalMouseWheel(&is_horizontal_wheel_); - - // The input coordinates are in DIP based on the metro scale factor. - // We want to convert it to DIP based on the win32 scale factor. - // We scale the point by the metro scale factor and then scale down - // via the win32 scale factor which achieves the needful. - gfx::Point dip_point_metro(point.X, point.Y); - gfx::Point scaled_point_metro = - gfx::ScaleToCeiledPoint(dip_point_metro, metro_dpi_scale_); - gfx::Point dip_point_win32 = - gfx::ScaleToCeiledPoint(scaled_point_metro, 1.0 / win32_dpi_scale_); - x_ = dip_point_win32.x(); - y_ = dip_point_win32.y(); - - pointer_point_->get_Timestamp(×tamp_); - pointer_point_->get_PointerId(&pointer_id_); - // Map the OS touch event id to a range allowed by the gesture recognizer. - if (IsTouch()) - pointer_id_ %= ui::MotionEvent::MAX_TOUCH_POINT_COUNT; - - boolean left_button_state; - hr = properties->get_IsLeftButtonPressed(&left_button_state); - if (FAILED(hr)) - return hr; - if (left_button_state) - mouse_down_flags_ |= ui::EF_LEFT_MOUSE_BUTTON; - - boolean right_button_state; - hr = properties->get_IsRightButtonPressed(&right_button_state); - if (FAILED(hr)) - return hr; - if (right_button_state) - mouse_down_flags_ |= ui::EF_RIGHT_MOUSE_BUTTON; - - boolean middle_button_state; - hr = properties->get_IsMiddleButtonPressed(&middle_button_state); - if (FAILED(hr)) - return hr; - if (middle_button_state) - mouse_down_flags_ |= ui::EF_MIDDLE_MOUSE_BUTTON; - - return S_OK; - } - - bool IsType(windevs::Input::PointerDeviceType type) const { - mswr::ComPtr<windevs::Input::IPointerDevice> pointer_device; - CheckHR(pointer_point_->get_PointerDevice(&pointer_device)); - windevs::Input::PointerDeviceType device_type; - CheckHR(pointer_device->get_PointerDeviceType(&device_type)); - return (device_type == type); - } - - bool IsMouse() const { - return IsType(windevs::Input::PointerDeviceType_Mouse); - } - - bool IsTouch() const { - return IsType(windevs::Input::PointerDeviceType_Touch); - } - - int32_t wheel_delta() const { return wheel_delta_; } - - // Identifies the button that changed. - ui::EventFlags changed_button() const { - switch (update_kind_) { - case winui::Input::PointerUpdateKind_LeftButtonPressed: - return ui::EF_LEFT_MOUSE_BUTTON; - case winui::Input::PointerUpdateKind_LeftButtonReleased: - return ui::EF_LEFT_MOUSE_BUTTON; - case winui::Input::PointerUpdateKind_RightButtonPressed: - return ui::EF_RIGHT_MOUSE_BUTTON; - case winui::Input::PointerUpdateKind_RightButtonReleased: - return ui::EF_RIGHT_MOUSE_BUTTON; - case winui::Input::PointerUpdateKind_MiddleButtonPressed: - return ui::EF_MIDDLE_MOUSE_BUTTON; - case winui::Input::PointerUpdateKind_MiddleButtonReleased: - return ui::EF_MIDDLE_MOUSE_BUTTON; - default: - return ui::EF_NONE; - } - } - - uint32_t mouse_down_flags() const { return mouse_down_flags_; } - - int x() const { return x_; } - int y() const { return y_; } - - uint32_t pointer_id() const { return pointer_id_; } - - uint64_t timestamp() const { return timestamp_; } - - winui::Input::PointerUpdateKind update_kind() const { return update_kind_; } - - bool is_horizontal_wheel() const { return !!is_horizontal_wheel_; } - - private: - int x_; - int y_; - int wheel_delta_; - uint32_t pointer_id_; - winui::Input::PointerUpdateKind update_kind_; - mswr::ComPtr<winui::Input::IPointerPoint> pointer_point_; - uint64_t timestamp_; - - // Bitmask of ui::EventFlags corresponding to the buttons that are currently - // down. - uint32_t mouse_down_flags_; - - // Set to true for a horizontal wheel message. - boolean is_horizontal_wheel_; - - // The metro device scale factor as reported by the winrt interfaces. - float metro_dpi_scale_; - // The win32 dpi scale which is queried via GetDeviceCaps. Please refer to - // ui/gfx/win/dpi.cc for more information. - float win32_dpi_scale_; - - DISALLOW_COPY_AND_ASSIGN(PointerInfoHandler); -}; - -ChromeAppViewAsh::ChromeAppViewAsh() - : mouse_down_flags_(ui::EF_NONE), - ui_channel_(nullptr), - core_window_hwnd_(NULL), - metro_dpi_scale_(0), - win32_dpi_scale_(0), - last_cursor_(NULL), - channel_listener_(NULL) { - DVLOG(1) << __FUNCTION__; - globals.previous_state = - winapp::Activation::ApplicationExecutionState_NotRunning; -} - -ChromeAppViewAsh::~ChromeAppViewAsh() { - DVLOG(1) << __FUNCTION__; -} - -IFACEMETHODIMP -ChromeAppViewAsh::Initialize(winapp::Core::ICoreApplicationView* view) { - view_ = view; - DVLOG(1) << __FUNCTION__; - HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>( - this, &ChromeAppViewAsh::OnActivate).Get(), - &activated_token_); - CheckHR(hr); - return hr; -} - -IFACEMETHODIMP -ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) { - window_ = window; - DVLOG(1) << __FUNCTION__; - - // Retrieve the native window handle via the interop layer. - mswr::ComPtr<ICoreWindowInterop> interop; - HRESULT hr = window->QueryInterface(interop.GetAddressOf()); - CheckHR(hr); - hr = interop->get_WindowHandle(&core_window_hwnd_); - CheckHR(hr); - - text_service_ = metro_driver::CreateTextService(this, core_window_hwnd_); - - hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>( - this, &ChromeAppViewAsh::OnSizeChanged).Get(), - &sizechange_token_); - CheckHR(hr); - - // Register for pointer and keyboard notifications. We forward - // them to the browser process via IPC. - hr = window_->add_PointerMoved(mswr::Callback<PointerEventHandler>( - this, &ChromeAppViewAsh::OnPointerMoved).Get(), - &pointermoved_token_); - CheckHR(hr); - - hr = window_->add_PointerPressed(mswr::Callback<PointerEventHandler>( - this, &ChromeAppViewAsh::OnPointerPressed).Get(), - &pointerpressed_token_); - CheckHR(hr); - - hr = window_->add_PointerReleased(mswr::Callback<PointerEventHandler>( - this, &ChromeAppViewAsh::OnPointerReleased).Get(), - &pointerreleased_token_); - CheckHR(hr); - - hr = window_->add_KeyDown(mswr::Callback<KeyEventHandler>( - this, &ChromeAppViewAsh::OnKeyDown).Get(), - &keydown_token_); - CheckHR(hr); - - hr = window_->add_KeyUp(mswr::Callback<KeyEventHandler>( - this, &ChromeAppViewAsh::OnKeyUp).Get(), - &keyup_token_); - CheckHR(hr); - - mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher; - hr = window_->get_Dispatcher(dispatcher.GetAddressOf()); - CheckHR(hr, "Get Dispatcher failed."); - - mswr::ComPtr<winui::Core::ICoreAcceleratorKeys> accelerator_keys; - hr = dispatcher.CopyTo(__uuidof(winui::Core::ICoreAcceleratorKeys), - reinterpret_cast<void**>( - accelerator_keys.GetAddressOf())); - CheckHR(hr, "QI for ICoreAcceleratorKeys failed."); - hr = accelerator_keys->add_AcceleratorKeyActivated( - mswr::Callback<AcceleratorKeyEventHandler>( - this, &ChromeAppViewAsh::OnAcceleratorKeyDown).Get(), - &accel_keydown_token_); - CheckHR(hr); - - hr = window_->add_PointerWheelChanged(mswr::Callback<PointerEventHandler>( - this, &ChromeAppViewAsh::OnWheel).Get(), - &wheel_token_); - CheckHR(hr); - - hr = window_->add_CharacterReceived(mswr::Callback<CharEventHandler>( - this, &ChromeAppViewAsh::OnCharacterReceived).Get(), - &character_received_token_); - CheckHR(hr); - - hr = window_->add_Activated(mswr::Callback<WindowActivatedHandler>( - this, &ChromeAppViewAsh::OnWindowActivated).Get(), - &window_activated_token_); - CheckHR(hr); - - if (base::win::GetVersion() >= base::win::VERSION_WIN8) { - // Register for edge gesture notifications only for Windows 8 and above. - mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics; - hr = winrt_utils::CreateActivationFactory( - RuntimeClass_Windows_UI_Input_EdgeGesture, - edge_gesture_statics.GetAddressOf()); - CheckHR(hr); - - mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture; - hr = edge_gesture_statics->GetForCurrentView(&edge_gesture); - CheckHR(hr); - - hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>( - this, &ChromeAppViewAsh::OnEdgeGestureCompleted).Get(), - &edgeevent_token_); - CheckHR(hr); - } - - // By initializing the direct 3D swap chain with the corewindow - // we can now directly blit to it from the browser process. - direct3d_helper_.Initialize(window); - DVLOG(1) << "Initialized Direct3D."; - - // On Windows 8+ the WinRT interface IDisplayProperties which we use to get - // device scale factor does not return the correct values in metro mode. - // To workaround this we retrieve the device scale factor via the win32 way - // and scale input coordinates accordingly to pass them in DIP to chrome. - // TODO(ananta). Investigate and fix. - metro_dpi_scale_ = GetModernUIScale(); - win32_dpi_scale_ = gfx::GetDPIScale(); - DVLOG(1) << "Metro Scale is " << metro_dpi_scale_; - DVLOG(1) << "Win32 Scale is " << win32_dpi_scale_; - return S_OK; -} - -IFACEMETHODIMP -ChromeAppViewAsh::Load(HSTRING entryPoint) { - // On Win7 |entryPoint| is NULL. - DVLOG(1) << __FUNCTION__; - return S_OK; -} - -IFACEMETHODIMP -ChromeAppViewAsh::Run() { - DVLOG(1) << __FUNCTION__; - mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher; - HRESULT hr = window_->get_Dispatcher(dispatcher.GetAddressOf()); - CheckHR(hr, "Dispatcher failed."); - - // Create the IPC channel IO thread. It needs to out-live the ChannelProxy. - io_thread_.reset(new base::Thread("metro_IO_thread")); - base::Thread::Options options; - options.message_loop_type = base::MessageLoop::TYPE_IO; - io_thread_->StartWithOptions(options); - - ChromeChannelListener ui_channel_listener(&ui_loop_, this); - channel_listener_ = &ui_channel_listener; - - // We can't do anything until the Chrome browser IPC channel is initialized. - // Lazy initialization in a timer. - ui_loop_.PostDelayedTask(FROM_HERE, - base::Bind(base::IgnoreResult(&ChromeAppViewAsh::StartChromeOSMode), - base::Unretained(this)), - base::TimeDelta::FromMilliseconds(kChromeChannelPollTimerMs)); - - // Post the task that'll do the inner Metro message pumping to it. - ui_loop_.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get())); - ui_loop_.Run(); - - io_thread_.reset(NULL); - ui_channel_.reset(NULL); - channel_listener_ = NULL; - - DVLOG(0) << "ProcessEvents done, hr=" << hr; - return hr; -} - -IFACEMETHODIMP -ChromeAppViewAsh::Uninitialize() { - DVLOG(1) << __FUNCTION__; - metro_driver::RemoveImePopupObserver(this); - input_source_.reset(); - text_service_.reset(); - window_ = nullptr; - view_ = nullptr; - core_window_hwnd_ = NULL; - return S_OK; -} - -// static -HRESULT ChromeAppViewAsh::Unsnap() { - mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics; - HRESULT hr = winrt_utils::CreateActivationFactory( - RuntimeClass_Windows_UI_ViewManagement_ApplicationView, - view_statics.GetAddressOf()); - CheckHR(hr); - - winui::ViewManagement::ApplicationViewState state = - winui::ViewManagement::ApplicationViewState_FullScreenLandscape; - hr = view_statics->get_Value(&state); - CheckHR(hr); - - if (state == winui::ViewManagement::ApplicationViewState_Snapped) { - boolean success = FALSE; - hr = view_statics->TryUnsnap(&success); - - if (FAILED(hr) || !success) { - LOG(ERROR) << "Failed to unsnap. Error 0x" << hr; - if (SUCCEEDED(hr)) - hr = E_UNEXPECTED; - } - } - return hr; -} - -void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path, - bool ash_exit) { - DVLOG(1) << "ChannelAppViewAsh::OnActivateDesktop\n"; - - if (ash_exit) { - // As we are the top level window, the exiting is done async so we manage - // to execute the entire function including the final Send(). - OnMetroExit(TERMINATE_USING_KEY_SEQUENCE); - } - - // We are just executing delegate_execute here without parameters. Assumption - // here is that this process will be reused by shell when asking for - // IExecuteCommand interface. - - // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE - // and place it metro.h or similar accessible file from all code code paths - // using this function. - SHELLEXECUTEINFO sei = { sizeof(sei) }; - sei.fMask = SEE_MASK_FLAG_LOG_USAGE; - sei.nShow = SW_SHOWNORMAL; - sei.lpFile = file_path.value().c_str(); - sei.lpParameters = NULL; - if (!ash_exit) - sei.fMask |= SEE_MASK_NOCLOSEPROCESS; - ::ShellExecuteExW(&sei); - if (!ash_exit) { - ::TerminateProcess(sei.hProcess, 0); - ::CloseHandle(sei.hProcess); - } -} - -void ChromeAppViewAsh::OnOpenURLOnDesktop(const base::FilePath& shortcut, - const base::string16& url) { - base::FilePath::StringType file = shortcut.value(); - SHELLEXECUTEINFO sei = { sizeof(sei) }; - sei.fMask = SEE_MASK_FLAG_LOG_USAGE; - sei.nShow = SW_SHOWNORMAL; - sei.lpFile = file.c_str(); - sei.lpDirectory = L""; - sei.lpParameters = url.c_str(); - ShellExecuteEx(&sei); -} - -void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor) { - ::SetCursor(cursor); - last_cursor_ = cursor; -} - -void ChromeAppViewAsh::OnDisplayFileOpenDialog( - const base::string16& title, - const base::string16& filter, - const base::FilePath& default_path, - bool allow_multiple_files) { - DVLOG(1) << __FUNCTION__; - - // The OpenFilePickerSession instance is deleted when we receive a - // callback from the OpenFilePickerSession class about the completion of the - // operation. - FilePickerSessionBase* file_picker_ = - new OpenFilePickerSession(this, - title, - filter, - default_path, - allow_multiple_files); - file_picker_->Run(); -} - -void ChromeAppViewAsh::OnDisplayFileSaveAsDialog( - const MetroViewerHostMsg_SaveAsDialogParams& params) { - DVLOG(1) << __FUNCTION__; - - // The SaveFilePickerSession instance is deleted when we receive a - // callback from the SaveFilePickerSession class about the completion of the - // operation. - FilePickerSessionBase* file_picker_ = - new SaveFilePickerSession(this, params); - file_picker_->Run(); -} - -void ChromeAppViewAsh::OnDisplayFolderPicker(const base::string16& title) { - DVLOG(1) << __FUNCTION__; - // The FolderPickerSession instance is deleted when we receive a - // callback from the FolderPickerSession class about the completion of the - // operation. - FilePickerSessionBase* file_picker_ = new FolderPickerSession(this, title); - file_picker_->Run(); -} - -void ChromeAppViewAsh::OnSetCursorPos(int x, int y) { - if (ui_channel_) { - ::SetCursorPos(x, y); - DVLOG(1) << "In UI OnSetCursorPos: " << x << ", " << y; - ui_channel_->Send(new MetroViewerHostMsg_SetCursorPosAck()); - // Generate a fake mouse move which matches the SetCursor coordinates as - // the browser expects to receive a mouse move for these coordinates. - // It is not clear why we don't receive a real mouse move in response to - // the SetCursorPos calll above. - ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(x, y, 0)); - } -} - -void ChromeAppViewAsh::OnOpenFileCompleted( - OpenFilePickerSession* open_file_picker, - bool success) { - DVLOG(1) << __FUNCTION__; - DVLOG(1) << "Success: " << success; - if (ui_channel_) { - if (open_file_picker->allow_multi_select()) { - ui_channel_->Send(new MetroViewerHostMsg_MultiFileOpenDone( - success, open_file_picker->filenames())); - } else { - ui_channel_->Send(new MetroViewerHostMsg_FileOpenDone( - success, base::FilePath(open_file_picker->result()))); - } - } - delete open_file_picker; -} - -void ChromeAppViewAsh::OnSaveFileCompleted( - SaveFilePickerSession* save_file_picker, - bool success) { - DVLOG(1) << __FUNCTION__; - DVLOG(1) << "Success: " << success; - if (ui_channel_) { - ui_channel_->Send(new MetroViewerHostMsg_FileSaveAsDone( - success, - base::FilePath(save_file_picker->result()), - save_file_picker->filter_index())); - } - delete save_file_picker; -} - -void ChromeAppViewAsh::OnFolderPickerCompleted( - FolderPickerSession* folder_picker, - bool success) { - DVLOG(1) << __FUNCTION__; - DVLOG(1) << "Success: " << success; - if (ui_channel_) { - ui_channel_->Send(new MetroViewerHostMsg_SelectFolderDone( - success, - base::FilePath(folder_picker->result()))); - } - delete folder_picker; -} - -void ChromeAppViewAsh::OnImeCancelComposition() { - if (!text_service_) - return; - text_service_->CancelComposition(); -} - -void ChromeAppViewAsh::OnImeUpdateTextInputClient( - const std::vector<int32_t>& input_scopes, - const std::vector<metro_viewer::CharacterBounds>& character_bounds) { - if (!text_service_) - return; - text_service_->OnDocumentChanged(input_scopes, character_bounds); -} - -void ChromeAppViewAsh::OnImePopupChanged(ImePopupObserver::EventType event) { - if (!ui_channel_) - return; - switch (event) { - case ImePopupObserver::kPopupShown: - ui_channel_->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(true)); - return; - case ImePopupObserver::kPopupHidden: - ui_channel_->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(false)); - return; - case ImePopupObserver::kPopupUpdated: - // TODO(kochi): Support this event for W3C IME API proposal. - // See crbug.com/238585. - return; - default: - NOTREACHED() << "unknown event type: " << event; - return; - } -} - -// Function to Exit metro chrome cleanly. If we are in the foreground -// then we try and exit by sending an Alt+F4 key combination to the core -// window which ensures that the chrome application tile does not show up in -// the running metro apps list on the top left corner. -void ChromeAppViewAsh::OnMetroExit(MetroTerminateMethod method) { - if (base::win::GetVersion() >= base::win::VERSION_WIN8) { - HWND core_window = core_window_hwnd(); - if (method == TERMINATE_USING_KEY_SEQUENCE && core_window != NULL && - core_window == ::GetForegroundWindow()) { - DVLOG(1) << "We are in the foreground. Exiting via Alt F4"; - SendKeySequence(VK_F4, ALT); - if (ui_channel_) - ui_channel_->Close(); - } else { - globals.app_exit->Exit(); - } - } else { - if (ui_channel_) - ui_channel_->Close(); - - HWND core_window = core_window_hwnd(); - ::PostMessage(core_window, WM_CLOSE, 0, 0); - - globals.app_exit->Exit(); - } -} - -void ChromeAppViewAsh::OnInputSourceChanged() { - if (!input_source_) - return; - - DCHECK(ui_channel_); - - LANGID langid = 0; - bool is_ime = false; - if (!input_source_->GetActiveSource(&langid, &is_ime)) { - LOG(ERROR) << "GetActiveSource failed"; - return; - } - ui_channel_->Send(new MetroViewerHostMsg_ImeInputSourceChanged(langid, - is_ime)); -} - -void ChromeAppViewAsh::OnCompositionChanged( - const base::string16& text, - int32_t selection_start, - int32_t selection_end, - const std::vector<metro_viewer::UnderlineInfo>& underlines) { - ui_channel_->Send(new MetroViewerHostMsg_ImeCompositionChanged( - text, selection_start, selection_end, underlines)); -} - -void ChromeAppViewAsh::OnTextCommitted(const base::string16& text) { - ui_channel_->Send(new MetroViewerHostMsg_ImeTextCommitted(text)); -} - -void ChromeAppViewAsh::SendMouseButton(int x, - int y, - int extra, - ui::EventType event_type, - uint32_t flags, - ui::EventFlags changed_button, - bool is_horizontal_wheel) { - if (!ui_channel_) - return; - MetroViewerHostMsg_MouseButtonParams params; - params.x = static_cast<int32_t>(x); - params.y = static_cast<int32_t>(y); - params.extra = static_cast<int32_t>(extra); - params.event_type = event_type; - params.flags = static_cast<int32_t>(flags); - params.changed_button = changed_button; - params.is_horizontal_wheel = is_horizontal_wheel; - ui_channel_->Send(new MetroViewerHostMsg_MouseButton(params)); -} - -void ChromeAppViewAsh::GenerateMouseEventFromMoveIfNecessary( - const PointerInfoHandler& pointer) { - ui::EventType event_type; - // For aura we want the flags to include the button that was released, thus - // we or the old and new. - uint32_t mouse_down_flags = pointer.mouse_down_flags() | mouse_down_flags_; - mouse_down_flags_ = pointer.mouse_down_flags(); - switch (pointer.update_kind()) { - case winui::Input::PointerUpdateKind_LeftButtonPressed: - case winui::Input::PointerUpdateKind_RightButtonPressed: - case winui::Input::PointerUpdateKind_MiddleButtonPressed: - event_type = ui::ET_MOUSE_PRESSED; - break; - case winui::Input::PointerUpdateKind_LeftButtonReleased: - case winui::Input::PointerUpdateKind_RightButtonReleased: - case winui::Input::PointerUpdateKind_MiddleButtonReleased: - event_type = ui::ET_MOUSE_RELEASED; - break; - default: - return; - } - SendMouseButton(pointer.x(), pointer.y(), 0, event_type, - mouse_down_flags | GetKeyboardEventFlags(), - pointer.changed_button(), pointer.is_horizontal_wheel()); -} - -HRESULT ChromeAppViewAsh::OnActivate( - winapp::Core::ICoreApplicationView*, - winapp::Activation::IActivatedEventArgs* args) { - DVLOG(1) << __FUNCTION__; - // Note: If doing more work in this function, you migth need to call - // get_PreviousExecutionState() and skip the work if the result is - // ApplicationExecutionState_Running and globals.previous_state is too. - args->get_PreviousExecutionState(&globals.previous_state); - DVLOG(1) << "Previous Execution State: " << globals.previous_state; - - winapp::Activation::ActivationKind activation_kind; - CheckHR(args->get_Kind(&activation_kind)); - DVLOG(1) << "Activation kind: " << activation_kind; - - if (activation_kind == winapp::Activation::ActivationKind_Search) - HandleSearchRequest(args); - else if (activation_kind == winapp::Activation::ActivationKind_Protocol) - HandleProtocolRequest(args); - else - LaunchChromeBrowserProcess(NULL, args); - // We call ICoreWindow::Activate after the handling for the search/protocol - // requests because Chrome can be launched to handle a search request which - // in turn launches the chrome browser process in desktop mode via - // ShellExecute. If we call ICoreWindow::Activate before this, then - // Windows kills the metro chrome process when it calls ShellExecute. Seems - // to be a bug. - window_->Activate(); - return S_OK; -} - -HRESULT ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow* sender, - winui::Core::IPointerEventArgs* args) { - if (!ui_channel_) - return S_OK; - - PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_); - HRESULT hr = pointer.Init(args); - if (FAILED(hr)) - return hr; - - if (pointer.IsMouse()) { - // If the mouse was moved towards the charms or the OS specific section, - // the cursor may change from what the browser last set. Restore it here. - if (::GetCursor() != last_cursor_) - SetCursor(last_cursor_); - - GenerateMouseEventFromMoveIfNecessary(pointer); - ui_channel_->Send(new MetroViewerHostMsg_MouseMoved( - pointer.x(), - pointer.y(), - mouse_down_flags_ | GetKeyboardEventFlags())); - } else { - DCHECK(pointer.IsTouch()); - ui_channel_->Send(new MetroViewerHostMsg_TouchMoved(pointer.x(), - pointer.y(), - pointer.timestamp(), - pointer.pointer_id())); - } - return S_OK; -} - -// NOTE: From experimentation, it seems like Metro only sends a PointerPressed -// event for the first button pressed and the last button released in a sequence -// of mouse events. -// For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results -// only in PointerPressed(LEFT)/PointerReleased(RIGHT) events. Intermediary -// presses and releases are tracked in OnPointMoved(). -HRESULT ChromeAppViewAsh::OnPointerPressed( - winui::Core::ICoreWindow* sender, - winui::Core::IPointerEventArgs* args) { - if (!ui_channel_) - return S_OK; - - PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_); - HRESULT hr = pointer.Init(args); - if (FAILED(hr)) - return hr; - - if (pointer.IsMouse()) { - mouse_down_flags_ = pointer.mouse_down_flags(); - SendMouseButton(pointer.x(), pointer.y(), 0, ui::ET_MOUSE_PRESSED, - mouse_down_flags_ | GetKeyboardEventFlags(), - pointer.changed_button(), pointer.is_horizontal_wheel()); - } else { - DCHECK(pointer.IsTouch()); - ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(), - pointer.y(), - pointer.timestamp(), - pointer.pointer_id())); - } - return S_OK; -} - -HRESULT ChromeAppViewAsh::OnPointerReleased( - winui::Core::ICoreWindow* sender, - winui::Core::IPointerEventArgs* args) { - if (!ui_channel_) - return S_OK; - - PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_); - HRESULT hr = pointer.Init(args); - if (FAILED(hr)) - return hr; - - if (pointer.IsMouse()) { - mouse_down_flags_ = ui::EF_NONE; - SendMouseButton(pointer.x(), pointer.y(), 0, ui::ET_MOUSE_RELEASED, - static_cast<uint32_t>(pointer.changed_button()) | - GetKeyboardEventFlags(), - pointer.changed_button(), pointer.is_horizontal_wheel()); - } else { - DCHECK(pointer.IsTouch()); - ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(), - pointer.y(), - pointer.timestamp(), - pointer.pointer_id())); - } - return S_OK; -} - -HRESULT ChromeAppViewAsh::OnWheel( - winui::Core::ICoreWindow* sender, - winui::Core::IPointerEventArgs* args) { - if (!ui_channel_) - return S_OK; - - PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_); - HRESULT hr = pointer.Init(args); - if (FAILED(hr)) - return hr; - DCHECK(pointer.IsMouse()); - SendMouseButton(pointer.x(), pointer.y(), pointer.wheel_delta(), - ui::ET_MOUSEWHEEL, GetKeyboardEventFlags(), ui::EF_NONE, - pointer.is_horizontal_wheel()); - return S_OK; -} - -HRESULT ChromeAppViewAsh::OnKeyDown( - winui::Core::ICoreWindow* sender, - winui::Core::IKeyEventArgs* args) { - if (!ui_channel_) - return S_OK; - - winsys::VirtualKey virtual_key; - HRESULT hr = args->get_VirtualKey(&virtual_key); - if (FAILED(hr)) - return hr; - winui::Core::CorePhysicalKeyStatus status; - hr = args->get_KeyStatus(&status); - if (FAILED(hr)) - return hr; - - ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key, - status.RepeatCount, - status.ScanCode, - GetKeyboardEventFlags())); - return S_OK; -} - -HRESULT ChromeAppViewAsh::OnKeyUp( - winui::Core::ICoreWindow* sender, - winui::Core::IKeyEventArgs* args) { - if (!ui_channel_) - return S_OK; - - winsys::VirtualKey virtual_key; - HRESULT hr = args->get_VirtualKey(&virtual_key); - if (FAILED(hr)) - return hr; - winui::Core::CorePhysicalKeyStatus status; - hr = args->get_KeyStatus(&status); - if (FAILED(hr)) - return hr; - - ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key, - status.RepeatCount, - status.ScanCode, - GetKeyboardEventFlags())); - return S_OK; -} - -HRESULT ChromeAppViewAsh::OnAcceleratorKeyDown( - winui::Core::ICoreDispatcher* sender, - winui::Core::IAcceleratorKeyEventArgs* args) { - if (!ui_channel_) - return S_OK; - - winsys::VirtualKey virtual_key; - HRESULT hr = args->get_VirtualKey(&virtual_key); - if (FAILED(hr)) - return hr; - winui::Core::CorePhysicalKeyStatus status; - hr = args->get_KeyStatus(&status); - if (FAILED(hr)) - return hr; - - winui::Core::CoreAcceleratorKeyEventType event_type; - hr = args->get_EventType(&event_type); - if (FAILED(hr)) - return hr; - - uint32_t keyboard_flags = GetKeyboardEventFlags(); - - switch (event_type) { - case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter: - ui_channel_->Send(new MetroViewerHostMsg_Character(virtual_key, - status.RepeatCount, - status.ScanCode, - keyboard_flags)); - break; - - case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown: - // Don't send the Alt + F4 combination to Chrome as this is intended to - // shut the metro environment down. Reason we check for Control here is - // Windows does not shutdown metro if Ctrl is pressed along with Alt F4. - // Other key combinations with Alt F4 shutdown metro. - if ((virtual_key == VK_F4) && ((keyboard_flags & ui::EF_ALT_DOWN) && - !(keyboard_flags & ui::EF_CONTROL_DOWN))) - return S_OK; - // Don't send the EF_ALT_DOWN modifier along with the IPC message for - // the Alt or F10 key. The accelerator for VKEY_MENU is registered - // without modifiers in Chrome for historical reasons. Not sending the - // EF_ALT_DOWN modifier ensures that the accelerator is processed - // correctly. - if (virtual_key == winsys::VirtualKey_Menu) - keyboard_flags &= ~ui::EF_ALT_DOWN; - ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key, - status.RepeatCount, - status.ScanCode, - keyboard_flags)); - break; - - case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp: - ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key, - status.RepeatCount, - status.ScanCode, - keyboard_flags)); - break; - - default: - break; - } - return S_OK; -} - -HRESULT ChromeAppViewAsh::OnCharacterReceived( - winui::Core::ICoreWindow* sender, - winui::Core::ICharacterReceivedEventArgs* args) { - if (!ui_channel_) - return S_OK; - - unsigned int char_code = 0; - HRESULT hr = args->get_KeyCode(&char_code); - if (FAILED(hr)) - return hr; - - winui::Core::CorePhysicalKeyStatus status; - hr = args->get_KeyStatus(&status); - if (FAILED(hr)) - return hr; - - ui_channel_->Send(new MetroViewerHostMsg_Character(char_code, - status.RepeatCount, - status.ScanCode, - GetKeyboardEventFlags())); - return S_OK; -} - -HRESULT ChromeAppViewAsh::OnWindowActivated( - winui::Core::ICoreWindow* sender, - winui::Core::IWindowActivatedEventArgs* args) { - if (!ui_channel_) - return S_OK; - - if (args) { - winui::Core::CoreWindowActivationState state; - HRESULT hr = args->get_WindowActivationState(&state); - if (FAILED(hr)) - return hr; - - // Treat both full activation (Ash was reopened from the Start Screen or - // from any other Metro entry point in Windows) and pointer activation - // (user clicked back in Ash after using another app on another monitor) - // the same. - if (state == winui::Core::CoreWindowActivationState_CodeActivated || - state == winui::Core::CoreWindowActivationState_PointerActivated) { - ui_channel_->Send(new MetroViewerHostMsg_WindowActivated(false)); - } - } else { - // On Windows 7, we force a repaint when the window is activated. - ui_channel_->Send(new MetroViewerHostMsg_WindowActivated(true)); - } - if (text_service_) - text_service_->OnWindowActivated(); - return S_OK; -} - -HRESULT ChromeAppViewAsh::HandleSearchRequest( - winapp::Activation::IActivatedEventArgs* args) { - mswr::ComPtr<winapp::Activation::ISearchActivatedEventArgs> search_args; - CheckHR(args->QueryInterface( - winapp::Activation::IID_ISearchActivatedEventArgs, &search_args)); - - if (!ui_channel_) { - DVLOG(1) << "Launched to handle search request"; - LaunchChromeBrowserProcess(L"--windows8-search", args); - } - - mswrw::HString search_string; - CheckHR(search_args->get_QueryText(search_string.GetAddressOf())); - base::string16 search_text(MakeStdWString(search_string.Get())); - - ui_loop_.PostTask(FROM_HERE, - base::Bind(&ChromeAppViewAsh::OnSearchRequest, - base::Unretained(this), - search_text)); - return S_OK; -} - -HRESULT ChromeAppViewAsh::HandleProtocolRequest( - winapp::Activation::IActivatedEventArgs* args) { - DVLOG(1) << __FUNCTION__; - if (!ui_channel_) - DVLOG(1) << "Launched to handle url request"; - - mswr::ComPtr<winapp::Activation::IProtocolActivatedEventArgs> - protocol_args; - CheckHR(args->QueryInterface( - winapp::Activation::IID_IProtocolActivatedEventArgs, - &protocol_args)); - - mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri; - protocol_args->get_Uri(&uri); - mswrw::HString url; - uri->get_AbsoluteUri(url.GetAddressOf()); - base::string16 actual_url(MakeStdWString(url.Get())); - DVLOG(1) << "Received url request: " << actual_url; - - ui_loop_.PostTask(FROM_HERE, - base::Bind(&ChromeAppViewAsh::OnNavigateToUrl, - base::Unretained(this), - actual_url)); - return S_OK; -} - -HRESULT ChromeAppViewAsh::OnEdgeGestureCompleted( - winui::Input::IEdgeGesture* gesture, - winui::Input::IEdgeGestureEventArgs* args) { - if (ui_channel_) - ui_channel_->Send(new MetroViewerHostMsg_EdgeGesture()); - return S_OK; -} - -void ChromeAppViewAsh::OnSearchRequest(const base::string16& search_string) { - if (ui_channel_) - ui_channel_->Send(new MetroViewerHostMsg_SearchRequest(search_string)); -} - -void ChromeAppViewAsh::OnNavigateToUrl(const base::string16& url) { - if (ui_channel_) - ui_channel_->Send(new MetroViewerHostMsg_OpenURL(url)); -} - -HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender, - winui::Core::IWindowSizeChangedEventArgs* args) { - if (!window_ || !ui_channel_) { - return S_OK; - } - - // winui::Core::IWindowSizeChangedEventArgs args->Size appears to return - // scaled values under HiDPI. We will instead use GetWindowRect() which - // should always return values in Pixels. - RECT rect = {0}; - ::GetWindowRect(core_window_hwnd_, &rect); - - uint32_t cx = static_cast<uint32_t>(rect.right - rect.left); - uint32_t cy = static_cast<uint32_t>(rect.bottom - rect.top); - - DVLOG(1) << "Window size changed: width=" << cx << ", height=" << cy; - ui_channel_->Send(new MetroViewerHostMsg_WindowSizeChanged(cx, cy)); - return S_OK; -} - -void ChromeAppViewAsh::StartChromeOSMode() { - static int ms_elapsed = 0; - - if (!IPC::Channel::IsNamedServerInitialized( - win8::kMetroViewerIPCChannelName) && ms_elapsed < 10000) { - ms_elapsed += 100; - ui_loop_.PostDelayedTask(FROM_HERE, - base::Bind(base::IgnoreResult(&ChromeAppViewAsh::StartChromeOSMode), - base::Unretained(this)), - base::TimeDelta::FromMilliseconds(kChromeChannelPollTimerMs)); - return; - } - - if (!IPC::Channel::IsNamedServerInitialized( - win8::kMetroViewerIPCChannelName)) { - DVLOG(1) << "Failed to connect to chrome channel : " - << win8::kMetroViewerIPCChannelName; - DVLOG(1) << "Exiting. Elapsed time :" << ms_elapsed; - PostMessage(core_window_hwnd_, WM_CLOSE, 0, 0); - return; - } - - DVLOG(1) << "Found channel : " << win8::kMetroViewerIPCChannelName; - - DCHECK(channel_listener_); - - // In Aura mode we create an IPC channel to the browser, then ask it to - // connect to us. - ui_channel_ = - IPC::ChannelProxy::Create(win8::kMetroViewerIPCChannelName, - IPC::Channel::MODE_NAMED_CLIENT, - channel_listener_, - io_thread_->task_runner()); - DVLOG(1) << "Created channel proxy"; - - // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the - // browser will use D3D from the browser process to present to our Window. - ui_channel_->Send(new MetroViewerHostMsg_SetTargetSurface( - gfx::NativeViewId(core_window_hwnd_), - win32_dpi_scale_)); - DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_; - - // Send an initial size message so that the Ash root window host gets sized - // correctly. - RECT rect = {0}; - ::GetWindowRect(core_window_hwnd_, &rect); - ui_channel_->Send( - new MetroViewerHostMsg_WindowSizeChanged(rect.right - rect.left, - rect.bottom - rect.top)); - - input_source_ = metro_driver::InputSource::Create(); - if (input_source_) { - input_source_->AddObserver(this); - // Send an initial input source. - OnInputSourceChanged(); - } - - // Start receiving IME popup window notifications. - metro_driver::AddImePopupObserver(this); - - DVLOG(1) << "Channel setup complete"; -} - -/////////////////////////////////////////////////////////////////////////////// - -ChromeAppViewFactory::ChromeAppViewFactory( - winapp::Core::ICoreApplication* icore_app) { - mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app); - mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit; - CheckHR(core_app.As(&app_exit)); - globals.app_exit = app_exit.Detach(); -} - -IFACEMETHODIMP -ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) { - *view = mswr::Make<ChromeAppViewAsh>().Detach(); - return (*view) ? S_OK : E_OUTOFMEMORY; -}
diff --git a/win8/metro_driver/chrome_app_view_ash.h b/win8/metro_driver/chrome_app_view_ash.h deleted file mode 100644 index ffe1d7e..0000000 --- a/win8/metro_driver/chrome_app_view_ash.h +++ /dev/null
@@ -1,262 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WIN8_METRO_DRIVER_CHROME_APP_VIEW_ASH_H_ -#define WIN8_METRO_DRIVER_CHROME_APP_VIEW_ASH_H_ - -#include <stdint.h> -#include <windows.applicationmodel.core.h> -#include <windows.ui.core.h> -#include <windows.ui.input.h> -#include <windows.ui.viewmanagement.h> - -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/string16.h" -#include "base/threading/thread.h" -#include "ipc/ipc_listener.h" -#include "ui/events/event_constants.h" -#include "win8/metro_driver/direct3d_helper.h" -#include "win8/metro_driver/ime/ime_popup_observer.h" -#include "win8/metro_driver/ime/input_source_observer.h" -#include "win8/metro_driver/ime/text_service_delegate.h" - -namespace base { -class FilePath; -} - -namespace IPC { -class Listener; -class ChannelProxy; -} - -namespace metro_driver { -class InputSource; -class TextService; -} - -namespace metro_viewer { -struct CharacterBounds; -struct UnderlineInfo; -} - -class OpenFilePickerSession; -class SaveFilePickerSession; -class FolderPickerSession; -class FilePickerSessionBase; - -struct MetroViewerHostMsg_SaveAsDialogParams; - -enum MetroTerminateMethod { - TERMINATE_USING_KEY_SEQUENCE = 1, - TERMINATE_USING_PROCESS_EXIT = 2, -}; - -class ChromeAppViewAsh - : public mswr::RuntimeClass<winapp::Core::IFrameworkView>, - public metro_driver::ImePopupObserver, - public metro_driver::InputSourceObserver, - public metro_driver::TextServiceDelegate { - public: - ChromeAppViewAsh(); - ~ChromeAppViewAsh() override; - - // IViewProvider overrides. - IFACEMETHOD(Initialize)(winapp::Core::ICoreApplicationView* view) override; - IFACEMETHOD(SetWindow)(winui::Core::ICoreWindow* window) override; - IFACEMETHOD(Load)(HSTRING entryPoint) override; - IFACEMETHOD(Run)() override; - IFACEMETHOD(Uninitialize)() override; - - // Helper function to unsnap the chrome metro app if it is snapped. - // Returns S_OK on success. - static HRESULT Unsnap(); - - void OnActivateDesktop(const base::FilePath& file_path, bool ash_exit); - void OnOpenURLOnDesktop(const base::FilePath& shortcut, - const base::string16& url); - void OnSetCursor(HCURSOR cursor); - void OnDisplayFileOpenDialog(const base::string16& title, - const base::string16& filter, - const base::FilePath& default_path, - bool allow_multiple_files); - void OnDisplayFileSaveAsDialog( - const MetroViewerHostMsg_SaveAsDialogParams& params); - void OnDisplayFolderPicker(const base::string16& title); - void OnSetCursorPos(int x, int y); - - // This function is invoked when the open file operation completes. The - // result of the operation is passed in along with the OpenFilePickerSession - // instance which is deleted after we read the required information from - // the OpenFilePickerSession class. - void OnOpenFileCompleted(OpenFilePickerSession* open_file_picker, - bool success); - - // This function is invoked when the save file operation completes. The - // result of the operation is passed in along with the SaveFilePickerSession - // instance which is deleted after we read the required information from - // the SaveFilePickerSession class. - void OnSaveFileCompleted(SaveFilePickerSession* save_file_picker, - bool success); - - // This function is invoked when the folder picker operation completes. The - // result of the operation is passed in along with the FolderPickerSession - // instance which is deleted after we read the required information from - // the FolderPickerSession class. - void OnFolderPickerCompleted(FolderPickerSession* folder_picker, - bool success); - - void OnImeCancelComposition(); - void OnImeUpdateTextInputClient( - const std::vector<int32_t>& input_scopes, - const std::vector<metro_viewer::CharacterBounds>& character_bounds); - - void OnMetroExit(MetroTerminateMethod method); - - HWND core_window_hwnd() const { return core_window_hwnd_; } - - - private: - class PointerInfoHandler; - - // ImePopupObserver overrides. - void OnImePopupChanged(ImePopupObserver::EventType event) override; - - // InputSourceObserver overrides. - void OnInputSourceChanged() override; - - // TextServiceDelegate overrides. - void OnCompositionChanged( - const base::string16& text, - int32_t selection_start, - int32_t selection_end, - const std::vector<metro_viewer::UnderlineInfo>& underlines) override; - void OnTextCommitted(const base::string16& text) override; - - // Convenience for sending a MetroViewerHostMsg_MouseButton with the specified - // parameters. - void SendMouseButton(int x, - int y, - int extra, - ui::EventType event_type, - uint32_t flags, - ui::EventFlags changed_button, - bool is_horizontal_wheel); - - // Win8 only generates a mouse press for the initial button that goes down and - // a release when the last button is released. Any intermediary presses (or - // releases) do not result in a new press/release event. Instead a move is - // generated with the winui::Input::PointerUpdateKind identifying what - // changed. This function generates the necessary intermediary events (as - // necessary). - void GenerateMouseEventFromMoveIfNecessary(const PointerInfoHandler& pointer); - - HRESULT OnActivate(winapp::Core::ICoreApplicationView* view, - winapp::Activation::IActivatedEventArgs* args); - - HRESULT OnPointerMoved(winui::Core::ICoreWindow* sender, - winui::Core::IPointerEventArgs* args); - - HRESULT OnPointerPressed(winui::Core::ICoreWindow* sender, - winui::Core::IPointerEventArgs* args); - - HRESULT OnPointerReleased(winui::Core::ICoreWindow* sender, - winui::Core::IPointerEventArgs* args); - - HRESULT OnWheel(winui::Core::ICoreWindow* sender, - winui::Core::IPointerEventArgs* args); - - HRESULT OnKeyDown(winui::Core::ICoreWindow* sender, - winui::Core::IKeyEventArgs* args); - - HRESULT OnKeyUp(winui::Core::ICoreWindow* sender, - winui::Core::IKeyEventArgs* args); - - // Invoked for system keys like Alt, etc. - HRESULT OnAcceleratorKeyDown(winui::Core::ICoreDispatcher* sender, - winui::Core::IAcceleratorKeyEventArgs* args); - - HRESULT OnCharacterReceived(winui::Core::ICoreWindow* sender, - winui::Core::ICharacterReceivedEventArgs* args); - - HRESULT OnWindowActivated(winui::Core::ICoreWindow* sender, - winui::Core::IWindowActivatedEventArgs* args); - - // Helper to handle search requests received via the search charm in ASH. - HRESULT HandleSearchRequest(winapp::Activation::IActivatedEventArgs* args); - // Helper to handle http/https url requests in ASH. - HRESULT HandleProtocolRequest(winapp::Activation::IActivatedEventArgs* args); - - HRESULT OnEdgeGestureCompleted(winui::Input::IEdgeGesture* gesture, - winui::Input::IEdgeGestureEventArgs* args); - - // Tasks posted to the UI thread to initiate the search/url navigation - // requests. - void OnSearchRequest(const base::string16& search_string); - void OnNavigateToUrl(const base::string16& url); - - HRESULT OnSizeChanged(winui::Core::ICoreWindow* sender, - winui::Core::IWindowSizeChangedEventArgs* args); - - // This function checks if the Chrome browser channel is initialized. If yes - // then it goes ahead and starts up the viewer in Chrome OS mode. If not it - // posts a delayed task and checks again. It does this for a duration of 10 - // seconds and then bails. - void StartChromeOSMode(); - - mswr::ComPtr<winui::Core::ICoreWindow> window_; - mswr::ComPtr<winapp::Core::ICoreApplicationView> view_; - EventRegistrationToken activated_token_; - EventRegistrationToken pointermoved_token_; - EventRegistrationToken pointerpressed_token_; - EventRegistrationToken pointerreleased_token_; - EventRegistrationToken wheel_token_; - EventRegistrationToken keydown_token_; - EventRegistrationToken keyup_token_; - EventRegistrationToken character_received_token_; - EventRegistrationToken accel_keydown_token_; - EventRegistrationToken accel_keyup_token_; - EventRegistrationToken window_activated_token_; - EventRegistrationToken sizechange_token_; - EventRegistrationToken edgeevent_token_; - - // Keep state about which button is currently down, if any, as PointerMoved - // events do not contain that state, but Ash's MouseEvents need it. Value is - // as a bitmask of ui::EventFlags. - uint32_t mouse_down_flags_; - - // Set the D3D swap chain and nothing else. - metro_driver::Direct3DHelper direct3d_helper_; - - // The IPC channel IO thread. - scoped_ptr<base::Thread> io_thread_; - - // The channel to Chrome, in particular to the MetroViewerProcessHost. - scoped_ptr<IPC::ChannelProxy> ui_channel_; - - // The actual window behind the view surface. - HWND core_window_hwnd_; - - // UI message loop to allow message passing into this thread. - base::MessageLoopForUI ui_loop_; - - // For IME support. - scoped_ptr<metro_driver::InputSource> input_source_; - scoped_ptr<metro_driver::TextService> text_service_; - - // The metro device scale factor as reported by the winrt interfaces. - float metro_dpi_scale_; - // The win32 dpi scale which is queried via GetDeviceCaps. Please refer to - // ui/gfx/win/dpi.cc for more information. - float win32_dpi_scale_; - - // The cursor set by the chroem browser process. - HCURSOR last_cursor_; - - // Pointer to the channel listener for the channel between the viewer and - // the browser. - IPC::Listener* channel_listener_; -}; - -#endif // WIN8_METRO_DRIVER_CHROME_APP_VIEW_ASH_H_
diff --git a/win8/metro_driver/file_picker.cc b/win8/metro_driver/file_picker.cc deleted file mode 100644 index 708b338c..0000000 --- a/win8/metro_driver/file_picker.cc +++ /dev/null
@@ -1,622 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "stdafx.h" -#include "win8/metro_driver/file_picker.h" - -#include <stddef.h> -#include <stdint.h> -#include <windows.storage.pickers.h> - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/string_util.h" -#include "base/synchronization/waitable_event.h" -#include "base/win/metro.h" -#include "base/win/scoped_comptr.h" -#include "win8/metro_driver/chrome_app_view.h" -#include "win8/metro_driver/winrt_utils.h" - -namespace { - -namespace winstorage = ABI::Windows::Storage; -typedef winfoundtn::Collections::IVector<HSTRING> StringVectorItf; - -// TODO(siggi): Complete this implementation and move it to a common place. -class StringVectorImpl : public mswr::RuntimeClass<StringVectorItf> { - public: - ~StringVectorImpl() { - std::for_each(strings_.begin(), strings_.end(), ::WindowsDeleteString); - } - - HRESULT RuntimeClassInitialize(const std::vector<base::string16>& list) { - for (size_t i = 0; i < list.size(); ++i) - strings_.push_back(MakeHString(list[i])); - - return S_OK; - } - - // IVector<HSTRING> implementation. - STDMETHOD(GetAt)(unsigned index, HSTRING* item) { - if (index >= strings_.size()) - return E_INVALIDARG; - - return ::WindowsDuplicateString(strings_[index], item); - } - STDMETHOD(get_Size)(unsigned *size) { - if (strings_.size() > UINT_MAX) - return E_UNEXPECTED; - *size = static_cast<unsigned>(strings_.size()); - return S_OK; - } - STDMETHOD(GetView)(winfoundtn::Collections::IVectorView<HSTRING> **view) { - return E_NOTIMPL; - } - STDMETHOD(IndexOf)(HSTRING value, unsigned *index, boolean *found) { - return E_NOTIMPL; - } - - // write methods - STDMETHOD(SetAt)(unsigned index, HSTRING item) { - return E_NOTIMPL; - } - STDMETHOD(InsertAt)(unsigned index, HSTRING item) { - return E_NOTIMPL; - } - STDMETHOD(RemoveAt)(unsigned index) { - return E_NOTIMPL; - } - STDMETHOD(Append)(HSTRING item) { - return E_NOTIMPL; - } - STDMETHOD(RemoveAtEnd)() { - return E_NOTIMPL; - } - STDMETHOD(Clear)() { - return E_NOTIMPL; - } - - private: - std::vector<HSTRING> strings_; -}; - -class FilePickerSessionBase { - public: - // Creates a file picker for open_file_name. - explicit FilePickerSessionBase(OPENFILENAME* open_file_name); - - // Runs the picker, returns true on success. - bool Run(); - - protected: - // Creates, configures and starts a file picker. - // If the HRESULT returned is a failure code the file picker has not started, - // so no callbacks should be expected. - virtual HRESULT StartFilePicker() = 0; - - // The parameters to our picker. - OPENFILENAME* open_file_name_; - // The event Run waits on. - base::WaitableEvent event_; - // True iff a file picker has successfully finished. - bool success_; - - private: - // Initiate a file picker, must be called on the metro dispatcher's thread. - void DoFilePicker(); - - DISALLOW_COPY_AND_ASSIGN(FilePickerSessionBase); -}; - -class OpenFilePickerSession : public FilePickerSessionBase { - public: - explicit OpenFilePickerSession(OPENFILENAME* open_file_name); - - private: - HRESULT StartFilePicker() override; - - typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*> - SingleFileAsyncOp; - typedef winfoundtn::Collections::IVectorView< - winstorage::StorageFile*> StorageFileVectorCollection; - typedef winfoundtn::IAsyncOperation<StorageFileVectorCollection*> - MultiFileAsyncOp; - - // Called asynchronously when a single file picker is done. - HRESULT SinglePickerDone(SingleFileAsyncOp* async, AsyncStatus status); - - // Called asynchronously when a multi file picker is done. - HRESULT MultiPickerDone(MultiFileAsyncOp* async, AsyncStatus status); - - // Composes a multi-file result string suitable for returning to a - // from a storage file collection. - static HRESULT ComposeMultiFileResult(StorageFileVectorCollection* files, - base::string16* result); - private: - DISALLOW_COPY_AND_ASSIGN(OpenFilePickerSession); -}; - -class SaveFilePickerSession : public FilePickerSessionBase { - public: - explicit SaveFilePickerSession(OPENFILENAME* open_file_name); - - private: - HRESULT StartFilePicker() override; - - typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*> - SaveFileAsyncOp; - - // Called asynchronously when the save file picker is done. - HRESULT FilePickerDone(SaveFileAsyncOp* async, AsyncStatus status); -}; - -FilePickerSessionBase::FilePickerSessionBase(OPENFILENAME* open_file_name) - : open_file_name_(open_file_name), - event_(true, false), - success_(false) { -} - -bool FilePickerSessionBase::Run() { - DCHECK(globals.appview_msg_loop != NULL); - - // Post the picker request over to the metro thread. - bool posted = globals.appview_msg_loop->PostTask(FROM_HERE, - base::Bind(&FilePickerSessionBase::DoFilePicker, base::Unretained(this))); - if (!posted) - return false; - - // Wait for the file picker to complete. - event_.Wait(); - - return success_; -} - -void FilePickerSessionBase::DoFilePicker() { - // The file picker will fail if spawned from a snapped application, - // so let's attempt to unsnap first if we're in that state. - HRESULT hr = ChromeAppView::Unsnap(); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to unsnap for file picker, error 0x" << hr; - } - - if (SUCCEEDED(hr)) - hr = StartFilePicker(); - - if (FAILED(hr)) { - LOG(ERROR) << "Failed to start file picker, error 0x" - << std::hex << hr; - - event_.Signal(); - } -} - -OpenFilePickerSession::OpenFilePickerSession(OPENFILENAME* open_file_name) - : FilePickerSessionBase(open_file_name) { -} - -HRESULT OpenFilePickerSession::SinglePickerDone(SingleFileAsyncOp* async, - AsyncStatus status) { - if (status == Completed) { - mswr::ComPtr<winstorage::IStorageFile> file; - HRESULT hr = async->GetResults(file.GetAddressOf()); - - if (file) { - mswr::ComPtr<winstorage::IStorageItem> storage_item; - if (SUCCEEDED(hr)) - hr = file.As(&storage_item); - - mswrw::HString file_path; - if (SUCCEEDED(hr)) - hr = storage_item->get_Path(file_path.GetAddressOf()); - - if (SUCCEEDED(hr)) { - UINT32 path_len = 0; - const wchar_t* path_str = - ::WindowsGetStringRawBuffer(file_path.Get(), &path_len); - - // If the selected file name is longer than the supplied buffer, - // we return false as per GetOpenFileName documentation. - if (path_len < open_file_name_->nMaxFile) { - base::wcslcpy(open_file_name_->lpstrFile, - path_str, - open_file_name_->nMaxFile); - success_ = true; - } - } - } else { - LOG(ERROR) << "NULL IStorageItem"; - } - } else { - LOG(ERROR) << "Unexpected async status " << static_cast<int>(status); - } - - event_.Signal(); - - return S_OK; -} - -HRESULT OpenFilePickerSession::MultiPickerDone(MultiFileAsyncOp* async, - AsyncStatus status) { - if (status == Completed) { - mswr::ComPtr<StorageFileVectorCollection> files; - HRESULT hr = async->GetResults(files.GetAddressOf()); - - if (files) { - base::string16 result; - if (SUCCEEDED(hr)) - hr = ComposeMultiFileResult(files.Get(), &result); - - if (SUCCEEDED(hr)) { - if (result.size() + 1 < open_file_name_->nMaxFile) { - // Because the result has embedded nulls, we must memcpy. - memcpy(open_file_name_->lpstrFile, - result.c_str(), - (result.size() + 1) * sizeof(result[0])); - success_ = true; - } - } - } else { - LOG(ERROR) << "NULL StorageFileVectorCollection"; - } - } else { - LOG(ERROR) << "Unexpected async status " << static_cast<int>(status); - } - - event_.Signal(); - - return S_OK; -} - -HRESULT OpenFilePickerSession::StartFilePicker() { - DCHECK(globals.appview_msg_loop->BelongsToCurrentThread()); - DCHECK(open_file_name_ != NULL); - - mswrw::HStringReference class_name( - RuntimeClass_Windows_Storage_Pickers_FileOpenPicker); - - // Create the file picker. - mswr::ComPtr<winstorage::Pickers::IFileOpenPicker> picker; - HRESULT hr = ::Windows::Foundation::ActivateInstance( - class_name.Get(), picker.GetAddressOf()); - CheckHR(hr); - - // Set the file type filter - mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter; - hr = picker->get_FileTypeFilter(filter.GetAddressOf()); - if (FAILED(hr)) - return hr; - - if (open_file_name_->lpstrFilter == NULL) { - hr = filter->Append(mswrw::HStringReference(L"*").Get()); - if (FAILED(hr)) - return hr; - } else { - // The filter is a concatenation of zero terminated string pairs, - // where each pair is {description, extension}. The concatenation ends - // with a zero length string - e.g. a double zero terminator. - const wchar_t* walk = open_file_name_->lpstrFilter; - while (*walk != L'\0') { - // Walk past the description. - walk += wcslen(walk) + 1; - - // We should have an extension, but bail on malformed filters. - if (*walk == L'\0') - break; - - // There can be a single extension, or a list of semicolon-separated ones. - std::vector<base::string16> extensions_win32_style = base::SplitString( - walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - - // Metro wants suffixes only, not patterns. - mswrw::HString extension; - for (size_t i = 0; i < extensions_win32_style.size(); ++i) { - if (extensions_win32_style[i] == L"*.*") { - // The wildcard filter is "*" for Metro. The string "*.*" produces - // an "invalid parameter" error. - hr = extension.Set(L"*"); - } else { - // Metro wants suffixes only, not patterns. - base::string16 ext = - base::FilePath(extensions_win32_style[i]).Extension(); - if ((ext.size() < 2) || - (ext.find_first_of(L"*?") != base::string16::npos)) { - continue; - } - hr = extension.Set(ext.c_str()); - } - if (SUCCEEDED(hr)) - hr = filter->Append(extension.Get()); - if (FAILED(hr)) - return hr; - } - - // Walk past the extension. - walk += wcslen(walk) + 1; - } - } - - // Spin up a single or multi picker as appropriate. - if (open_file_name_->Flags & OFN_ALLOWMULTISELECT) { - mswr::ComPtr<MultiFileAsyncOp> completion; - hr = picker->PickMultipleFilesAsync(&completion); - if (FAILED(hr)) - return hr; - - // Create the callback method. - typedef winfoundtn::IAsyncOperationCompletedHandler< - StorageFileVectorCollection*> HandlerDoneType; - mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( - this, &OpenFilePickerSession::MultiPickerDone)); - DCHECK(handler.Get() != NULL); - hr = completion->put_Completed(handler.Get()); - - return hr; - } else { - mswr::ComPtr<SingleFileAsyncOp> completion; - hr = picker->PickSingleFileAsync(&completion); - if (FAILED(hr)) - return hr; - - // Create the callback method. - typedef winfoundtn::IAsyncOperationCompletedHandler< - winstorage::StorageFile*> HandlerDoneType; - mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( - this, &OpenFilePickerSession::SinglePickerDone)); - DCHECK(handler.Get() != NULL); - hr = completion->put_Completed(handler.Get()); - - return hr; - } -} - -HRESULT OpenFilePickerSession::ComposeMultiFileResult( - StorageFileVectorCollection* files, base::string16* result) { - DCHECK(files != NULL); - DCHECK(result != NULL); - - // Empty the output string. - result->clear(); - - unsigned int num_files = 0; - HRESULT hr = files->get_Size(&num_files); - if (FAILED(hr)) - return hr; - - // Make sure we return an error on an empty collection. - if (num_files == 0) { - DLOG(ERROR) << "Empty collection on input."; - return E_UNEXPECTED; - } - - // This stores the base path that should be the parent of all the files. - base::FilePath base_path; - - // Iterate through the collection and append the file paths to the result. - for (unsigned int i = 0; i < num_files; ++i) { - mswr::ComPtr<winstorage::IStorageFile> file; - hr = files->GetAt(i, file.GetAddressOf()); - if (FAILED(hr)) - return hr; - - mswr::ComPtr<winstorage::IStorageItem> storage_item; - hr = file.As(&storage_item); - if (FAILED(hr)) - return hr; - - mswrw::HString file_path_str; - hr = storage_item->get_Path(file_path_str.GetAddressOf()); - if (FAILED(hr)) - return hr; - - base::FilePath file_path(MakeStdWString(file_path_str.Get())); - if (base_path.empty()) { - DCHECK(result->empty()); - base_path = file_path.DirName(); - - // Append the path, including the terminating zero. - // We do this only for the first file. - result->append(base_path.value().c_str(), base_path.value().size() + 1); - } - DCHECK(!result->empty()); - DCHECK(!base_path.empty()); - DCHECK(base_path == file_path.DirName()); - - // Append the base name, including the terminating zero. - base::FilePath base_name = file_path.BaseName(); - result->append(base_name.value().c_str(), base_name.value().size() + 1); - } - - DCHECK(!result->empty()); - - return S_OK; -} - -SaveFilePickerSession::SaveFilePickerSession(OPENFILENAME* open_file_name) - : FilePickerSessionBase(open_file_name) { -} - -HRESULT SaveFilePickerSession::StartFilePicker() { - DCHECK(globals.appview_msg_loop->BelongsToCurrentThread()); - DCHECK(open_file_name_ != NULL); - - mswrw::HStringReference class_name( - RuntimeClass_Windows_Storage_Pickers_FileSavePicker); - - // Create the file picker. - mswr::ComPtr<winstorage::Pickers::IFileSavePicker> picker; - HRESULT hr = ::Windows::Foundation::ActivateInstance( - class_name.Get(), picker.GetAddressOf()); - CheckHR(hr); - - typedef winfoundtn::Collections::IMap<HSTRING, StringVectorItf*> - StringVectorMap; - mswr::ComPtr<StringVectorMap> choices; - hr = picker->get_FileTypeChoices(choices.GetAddressOf()); - if (FAILED(hr)) - return hr; - - if (open_file_name_->lpstrFilter) { - // The filter is a concatenation of zero terminated string pairs, - // where each pair is {description, extension list}. The concatenation ends - // with a zero length string - e.g. a double zero terminator. - const wchar_t* walk = open_file_name_->lpstrFilter; - while (*walk != L'\0') { - mswrw::HString description; - hr = description.Set(walk); - if (FAILED(hr)) - return hr; - - // Walk past the description. - walk += wcslen(walk) + 1; - - // We should have an extension, but bail on malformed filters. - if (*walk == L'\0') - break; - - // There can be a single extension, or a list of semicolon-separated ones. - std::vector<base::string16> extensions_win32_style = base::SplitString( - walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - - // Metro wants suffixes only, not patterns. Also, metro does not support - // the all files ("*") pattern in the save picker. - std::vector<base::string16> extensions; - for (size_t i = 0; i < extensions_win32_style.size(); ++i) { - base::string16 ext = - base::FilePath(extensions_win32_style[i]).Extension(); - if ((ext.size() < 2) || - (ext.find_first_of(L"*?") != base::string16::npos)) - continue; - extensions.push_back(ext); - } - - if (!extensions.empty()) { - // Convert to a Metro collection class. - mswr::ComPtr<StringVectorItf> list; - hr = mswr::MakeAndInitialize<StringVectorImpl>( - list.GetAddressOf(), extensions); - if (FAILED(hr)) - return hr; - - // Finally set the filter. - boolean replaced = FALSE; - hr = choices->Insert(description.Get(), list.Get(), &replaced); - if (FAILED(hr)) - return hr; - DCHECK_EQ(FALSE, replaced); - } - - // Walk past the extension(s). - walk += wcslen(walk) + 1; - } - } - - // The save picker requires at least one choice. Callers are strongly advised - // to provide sensible choices. If none were given, fallback to .dat. - uint32_t num_choices = 0; - hr = choices->get_Size(&num_choices); - if (FAILED(hr)) - return hr; - - if (num_choices == 0) { - mswrw::HString description; - // TODO(grt): Get a properly translated string. This can't be done from - // within metro_driver. Consider preprocessing the filter list in Chrome - // land to ensure it has this entry if all others are patterns. In that - // case, this whole block of code can be removed. - hr = description.Set(L"Data File"); - if (FAILED(hr)) - return hr; - - mswr::ComPtr<StringVectorItf> list; - hr = mswr::MakeAndInitialize<StringVectorImpl>( - list.GetAddressOf(), std::vector<base::string16>(1, L".dat")); - if (FAILED(hr)) - return hr; - - boolean replaced = FALSE; - hr = choices->Insert(description.Get(), list.Get(), &replaced); - if (FAILED(hr)) - return hr; - DCHECK_EQ(FALSE, replaced); - } - - if (open_file_name_->lpstrFile != NULL) { - hr = picker->put_SuggestedFileName( - mswrw::HStringReference( - const_cast<const wchar_t*>(open_file_name_->lpstrFile)).Get()); - if (FAILED(hr)) - return hr; - } - - mswr::ComPtr<SaveFileAsyncOp> completion; - hr = picker->PickSaveFileAsync(&completion); - if (FAILED(hr)) - return hr; - - // Create the callback method. - typedef winfoundtn::IAsyncOperationCompletedHandler< - winstorage::StorageFile*> HandlerDoneType; - mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( - this, &SaveFilePickerSession::FilePickerDone)); - DCHECK(handler.Get() != NULL); - hr = completion->put_Completed(handler.Get()); - - return hr; -} - -HRESULT SaveFilePickerSession::FilePickerDone(SaveFileAsyncOp* async, - AsyncStatus status) { - if (status == Completed) { - mswr::ComPtr<winstorage::IStorageFile> file; - HRESULT hr = async->GetResults(file.GetAddressOf()); - - if (file) { - mswr::ComPtr<winstorage::IStorageItem> storage_item; - if (SUCCEEDED(hr)) - hr = file.As(&storage_item); - - mswrw::HString file_path; - if (SUCCEEDED(hr)) - hr = storage_item->get_Path(file_path.GetAddressOf()); - - if (SUCCEEDED(hr)) { - base::string16 path_str = MakeStdWString(file_path.Get()); - - // If the selected file name is longer than the supplied buffer, - // we return false as per GetOpenFileName documentation. - if (path_str.size() < open_file_name_->nMaxFile) { - base::wcslcpy(open_file_name_->lpstrFile, - path_str.c_str(), - open_file_name_->nMaxFile); - success_ = true; - } - } - } else { - LOG(ERROR) << "NULL IStorageItem"; - } - } else { - LOG(ERROR) << "Unexpected async status " << static_cast<int>(status); - } - - event_.Signal(); - - return S_OK; -} - -} // namespace - -BOOL MetroGetOpenFileName(OPENFILENAME* open_file_name) { - OpenFilePickerSession session(open_file_name); - - return session.Run(); -} - -BOOL MetroGetSaveFileName(OPENFILENAME* open_file_name) { - SaveFilePickerSession session(open_file_name); - - return session.Run(); -}
diff --git a/win8/metro_driver/file_picker.h b/win8/metro_driver/file_picker.h deleted file mode 100644 index ef56cb39..0000000 --- a/win8/metro_driver/file_picker.h +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_H_ -#define CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_H_ - -#include <commdlg.h> - -// This function behaves similarly to GetOpenFileName, except it uses a -// Metro file picker to pick a single or multiple file names. -extern "C" __declspec(dllexport) -BOOL MetroGetOpenFileName(OPENFILENAME* open_file_name); - -extern "C" __declspec(dllexport) -BOOL MetroGetSaveFileName(OPENFILENAME* open_file_name); - -#endif // CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_H_ -
diff --git a/win8/metro_driver/file_picker_ash.cc b/win8/metro_driver/file_picker_ash.cc deleted file mode 100644 index 31e699d..0000000 --- a/win8/metro_driver/file_picker_ash.cc +++ /dev/null
@@ -1,619 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <stddef.h> -#include <stdint.h> - -#include "stdafx.h" -#include "win8/metro_driver/file_picker_ash.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/synchronization/waitable_event.h" -#include "base/win/scoped_comptr.h" -#include "ui/metro_viewer/metro_viewer_messages.h" -#include "win8/metro_driver/chrome_app_view_ash.h" -#include "win8/metro_driver/winrt_utils.h" - -namespace { - -typedef winfoundtn::Collections::IVector<HSTRING> StringVectorItf; - -// TODO(siggi): Complete this implementation and move it to a common place. -class StringVectorImpl : public mswr::RuntimeClass<StringVectorItf> { - public: - ~StringVectorImpl() override { - std::for_each(strings_.begin(), strings_.end(), ::WindowsDeleteString); - } - - HRESULT RuntimeClassInitialize(const std::vector<base::string16>& list) { - for (size_t i = 0; i < list.size(); ++i) - strings_.push_back(MakeHString(list[i])); - - return S_OK; - } - - // IVector<HSTRING> implementation. - STDMETHOD(GetAt)(unsigned index, HSTRING* item) override { - if (index >= strings_.size()) - return E_INVALIDARG; - - return ::WindowsDuplicateString(strings_[index], item); - } - STDMETHOD(get_Size)(unsigned* size) override { - if (strings_.size() > UINT_MAX) - return E_UNEXPECTED; - *size = static_cast<unsigned>(strings_.size()); - return S_OK; - } - STDMETHOD(GetView)( - winfoundtn::Collections::IVectorView<HSTRING>** view) override { - return E_NOTIMPL; - } - STDMETHOD(IndexOf)(HSTRING value, unsigned* index, boolean* found) override { - return E_NOTIMPL; - } - - // write methods - STDMETHOD(SetAt)(unsigned index, HSTRING item) override { return E_NOTIMPL; } - STDMETHOD(InsertAt)(unsigned index, HSTRING item) override { - return E_NOTIMPL; - } - STDMETHOD(RemoveAt)(unsigned index) override { return E_NOTIMPL; } - STDMETHOD(Append)(HSTRING item) override { return E_NOTIMPL; } - STDMETHOD(RemoveAtEnd)() override { return E_NOTIMPL; } - STDMETHOD(Clear)() override { return E_NOTIMPL; } - - private: - std::vector<HSTRING> strings_; -}; - -} // namespace - -FilePickerSessionBase::~FilePickerSessionBase() { -} - -bool FilePickerSessionBase::Run() { - if (!DoFilePicker()) - return false; - return success_; -} - -FilePickerSessionBase::FilePickerSessionBase(ChromeAppViewAsh* app_view, - const base::string16& title, - const base::string16& filter, - const base::FilePath& default_path) - : success_(false), - title_(title), - filter_(filter), - default_path_(default_path), - app_view_(app_view) { -} - -bool FilePickerSessionBase::DoFilePicker() { - // The file picker will fail if spawned from a snapped application, - // so let's attempt to unsnap first if we're in that state. - HRESULT hr = ChromeAppViewAsh::Unsnap(); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to unsnap for file picker, error 0x" << hr; - return false; - } - hr = StartFilePicker(); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to start file picker, error 0x" - << std::hex << hr; - return false; - } - return true; -} - -OpenFilePickerSession::OpenFilePickerSession( - ChromeAppViewAsh* app_view, - const base::string16& title, - const base::string16& filter, - const base::FilePath& default_path, - bool allow_multi_select) - : FilePickerSessionBase(app_view, title, filter, default_path), - allow_multi_select_(allow_multi_select) { -} - -OpenFilePickerSession::~OpenFilePickerSession() { -} - -HRESULT OpenFilePickerSession::SinglePickerDone(SingleFileAsyncOp* async, - AsyncStatus status) { - if (status == Completed) { - mswr::ComPtr<winstorage::IStorageFile> file; - HRESULT hr = async->GetResults(file.GetAddressOf()); - - if (file) { - mswr::ComPtr<winstorage::IStorageItem> storage_item; - if (SUCCEEDED(hr)) - hr = file.As(&storage_item); - - mswrw::HString file_path; - if (SUCCEEDED(hr)) - hr = storage_item->get_Path(file_path.GetAddressOf()); - - if (SUCCEEDED(hr)) { - UINT32 path_len = 0; - const wchar_t* path_str = - ::WindowsGetStringRawBuffer(file_path.Get(), &path_len); - - result_ = path_str; - success_ = true; - } - } else { - LOG(ERROR) << "NULL IStorageItem"; - } - } else { - LOG(ERROR) << "Unexpected async status " << static_cast<int>(status); - } - app_view_->OnOpenFileCompleted(this, success_); - return S_OK; -} - -HRESULT OpenFilePickerSession::MultiPickerDone(MultiFileAsyncOp* async, - AsyncStatus status) { - if (status == Completed) { - mswr::ComPtr<StorageFileVectorCollection> files; - HRESULT hr = async->GetResults(files.GetAddressOf()); - - if (files) { - base::string16 result; - if (SUCCEEDED(hr)) - hr = ComposeMultiFileResult(files.Get(), &result); - - if (SUCCEEDED(hr)) { - success_ = true; - // The code below has been copied from the - // SelectFileDialogImpl::RunOpenMultiFileDialog function in - // select_file_dialog_win.cc. - // TODO(ananta) - // Consolidate this into a common place. - const wchar_t* selection = result.c_str(); - std::vector<base::FilePath> files; - - while (*selection) { // Empty string indicates end of list. - files.push_back(base::FilePath(selection)); - // Skip over filename and null-terminator. - selection += files.back().value().length() + 1; - } - if (files.empty()) { - success_ = false; - } else if (files.size() == 1) { - // When there is one file, it contains the path and filename. - filenames_ = files; - } else if (files.size() > 1) { - // Otherwise, the first string is the path, and the remainder are - // filenames. - std::vector<base::FilePath>::iterator path = files.begin(); - for (std::vector<base::FilePath>::iterator file = path + 1; - file != files.end(); ++file) { - filenames_.push_back(path->Append(*file)); - } - } - } - } else { - LOG(ERROR) << "NULL StorageFileVectorCollection"; - } - } else { - LOG(ERROR) << "Unexpected async status " << static_cast<int>(status); - } - app_view_->OnOpenFileCompleted(this, success_); - return S_OK; -} - -HRESULT OpenFilePickerSession::StartFilePicker() { - mswrw::HStringReference class_name( - RuntimeClass_Windows_Storage_Pickers_FileOpenPicker); - - // Create the file picker. - mswr::ComPtr<winstorage::Pickers::IFileOpenPicker> picker; - HRESULT hr = ::Windows::Foundation::ActivateInstance( - class_name.Get(), picker.GetAddressOf()); - CheckHR(hr); - - // Set the file type filter - mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter; - hr = picker->get_FileTypeFilter(filter.GetAddressOf()); - if (FAILED(hr)) - return hr; - - if (filter_.empty()) { - hr = filter->Append(mswrw::HStringReference(L"*").Get()); - if (FAILED(hr)) - return hr; - } else { - // The filter is a concatenation of zero terminated string pairs, - // where each pair is {description, extension}. The concatenation ends - // with a zero length string - e.g. a double zero terminator. - const wchar_t* walk = filter_.c_str(); - while (*walk != L'\0') { - // Walk past the description. - walk += wcslen(walk) + 1; - - // We should have an extension, but bail on malformed filters. - if (*walk == L'\0') - break; - - // There can be a single extension, or a list of semicolon-separated ones. - std::vector<base::string16> extensions_win32_style = base::SplitString( - walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - - // Metro wants suffixes only, not patterns. - mswrw::HString extension; - for (size_t i = 0; i < extensions_win32_style.size(); ++i) { - if (extensions_win32_style[i] == L"*.*") { - // The wildcard filter is "*" for Metro. The string "*.*" produces - // an "invalid parameter" error. - hr = extension.Set(L"*"); - } else { - // Metro wants suffixes only, not patterns. - base::string16 ext = - base::FilePath(extensions_win32_style[i]).Extension(); - if ((ext.size() < 2) || - (ext.find_first_of(L"*?") != base::string16::npos)) { - continue; - } - hr = extension.Set(ext.c_str()); - } - if (SUCCEEDED(hr)) - hr = filter->Append(extension.Get()); - if (FAILED(hr)) - return hr; - } - - // Walk past the extension. - walk += wcslen(walk) + 1; - } - } - - // Spin up a single or multi picker as appropriate. - if (allow_multi_select_) { - mswr::ComPtr<MultiFileAsyncOp> completion; - hr = picker->PickMultipleFilesAsync(&completion); - if (FAILED(hr)) - return hr; - - // Create the callback method. - typedef winfoundtn::IAsyncOperationCompletedHandler< - StorageFileVectorCollection*> HandlerDoneType; - mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( - this, &OpenFilePickerSession::MultiPickerDone)); - DCHECK(handler.Get() != NULL); - hr = completion->put_Completed(handler.Get()); - - return hr; - } else { - mswr::ComPtr<SingleFileAsyncOp> completion; - hr = picker->PickSingleFileAsync(&completion); - if (FAILED(hr)) - return hr; - - // Create the callback method. - typedef winfoundtn::IAsyncOperationCompletedHandler< - winstorage::StorageFile*> HandlerDoneType; - mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( - this, &OpenFilePickerSession::SinglePickerDone)); - DCHECK(handler.Get() != NULL); - hr = completion->put_Completed(handler.Get()); - - return hr; - } -} - -HRESULT OpenFilePickerSession::ComposeMultiFileResult( - StorageFileVectorCollection* files, base::string16* result) { - DCHECK(files != NULL); - DCHECK(result != NULL); - - // Empty the output string. - result->clear(); - - unsigned int num_files = 0; - HRESULT hr = files->get_Size(&num_files); - if (FAILED(hr)) - return hr; - - // Make sure we return an error on an empty collection. - if (num_files == 0) { - DLOG(ERROR) << "Empty collection on input."; - return E_UNEXPECTED; - } - - // This stores the base path that should be the parent of all the files. - base::FilePath base_path; - - // Iterate through the collection and append the file paths to the result. - for (unsigned int i = 0; i < num_files; ++i) { - mswr::ComPtr<winstorage::IStorageFile> file; - hr = files->GetAt(i, file.GetAddressOf()); - if (FAILED(hr)) - return hr; - - mswr::ComPtr<winstorage::IStorageItem> storage_item; - hr = file.As(&storage_item); - if (FAILED(hr)) - return hr; - - mswrw::HString file_path_str; - hr = storage_item->get_Path(file_path_str.GetAddressOf()); - if (FAILED(hr)) - return hr; - - base::FilePath file_path(MakeStdWString(file_path_str.Get())); - if (base_path.empty()) { - DCHECK(result->empty()); - base_path = file_path.DirName(); - - // Append the path, including the terminating zero. - // We do this only for the first file. - result->append(base_path.value().c_str(), base_path.value().size() + 1); - } - DCHECK(!result->empty()); - DCHECK(!base_path.empty()); - DCHECK(base_path == file_path.DirName()); - - // Append the base name, including the terminating zero. - base::FilePath base_name = file_path.BaseName(); - result->append(base_name.value().c_str(), base_name.value().size() + 1); - } - - DCHECK(!result->empty()); - - return S_OK; -} - -SaveFilePickerSession::SaveFilePickerSession( - ChromeAppViewAsh* app_view, - const MetroViewerHostMsg_SaveAsDialogParams& params) - : FilePickerSessionBase(app_view, - params.title, - params.filter, - params.suggested_name), - filter_index_(params.filter_index) { -} - -int SaveFilePickerSession::filter_index() const { - // TODO(ananta) - // Add support for returning the correct filter index. This does not work in - // regular Chrome metro on trunk as well. - // BUG: https://code.google.com/p/chromium/issues/detail?id=172704 - return filter_index_; -} - -HRESULT SaveFilePickerSession::StartFilePicker() { - mswrw::HStringReference class_name( - RuntimeClass_Windows_Storage_Pickers_FileSavePicker); - - // Create the file picker. - mswr::ComPtr<winstorage::Pickers::IFileSavePicker> picker; - HRESULT hr = ::Windows::Foundation::ActivateInstance( - class_name.Get(), picker.GetAddressOf()); - CheckHR(hr); - - typedef winfoundtn::Collections::IMap<HSTRING, StringVectorItf*> - StringVectorMap; - mswr::ComPtr<StringVectorMap> choices; - hr = picker->get_FileTypeChoices(choices.GetAddressOf()); - if (FAILED(hr)) - return hr; - - if (!filter_.empty()) { - // The filter is a concatenation of zero terminated string pairs, - // where each pair is {description, extension list}. The concatenation ends - // with a zero length string - e.g. a double zero terminator. - const wchar_t* walk = filter_.c_str(); - while (*walk != L'\0') { - mswrw::HString description; - hr = description.Set(walk); - if (FAILED(hr)) - return hr; - - // Walk past the description. - walk += wcslen(walk) + 1; - - // We should have an extension, but bail on malformed filters. - if (*walk == L'\0') - break; - - // There can be a single extension, or a list of semicolon-separated ones. - std::vector<base::string16> extensions_win32_style = base::SplitString( - walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - - // Metro wants suffixes only, not patterns. Also, metro does not support - // the all files ("*") pattern in the save picker. - std::vector<base::string16> extensions; - for (size_t i = 0; i < extensions_win32_style.size(); ++i) { - base::string16 ext = - base::FilePath(extensions_win32_style[i]).Extension(); - if ((ext.size() < 2) || - (ext.find_first_of(L"*?") != base::string16::npos)) - continue; - extensions.push_back(ext); - } - - if (!extensions.empty()) { - // Convert to a Metro collection class. - mswr::ComPtr<StringVectorItf> list; - hr = mswr::MakeAndInitialize<StringVectorImpl>( - list.GetAddressOf(), extensions); - if (FAILED(hr)) - return hr; - - // Finally set the filter. - boolean replaced = FALSE; - hr = choices->Insert(description.Get(), list.Get(), &replaced); - if (FAILED(hr)) - return hr; - DCHECK_EQ(FALSE, replaced); - } - - // Walk past the extension(s). - walk += wcslen(walk) + 1; - } - } - - // The save picker requires at least one choice. Callers are strongly advised - // to provide sensible choices. If none were given, fallback to .dat. - uint32_t num_choices = 0; - hr = choices->get_Size(&num_choices); - if (FAILED(hr)) - return hr; - - if (num_choices == 0) { - mswrw::HString description; - // TODO(grt): Get a properly translated string. This can't be done from - // within metro_driver. Consider preprocessing the filter list in Chrome - // land to ensure it has this entry if all others are patterns. In that - // case, this whole block of code can be removed. - hr = description.Set(L"Data File"); - if (FAILED(hr)) - return hr; - - mswr::ComPtr<StringVectorItf> list; - hr = mswr::MakeAndInitialize<StringVectorImpl>( - list.GetAddressOf(), std::vector<base::string16>(1, L".dat")); - if (FAILED(hr)) - return hr; - - boolean replaced = FALSE; - hr = choices->Insert(description.Get(), list.Get(), &replaced); - if (FAILED(hr)) - return hr; - DCHECK_EQ(FALSE, replaced); - } - - if (!default_path_.empty()) { - base::string16 file_part = default_path_.BaseName().value(); - // If the suggested_name is a root directory, then don't set it as the - // suggested name. - if (file_part.size() == 1 && file_part[0] == L'\\') - file_part.clear(); - hr = picker->put_SuggestedFileName( - mswrw::HStringReference(file_part.c_str()).Get()); - if (FAILED(hr)) - return hr; - } - - mswr::ComPtr<SaveFileAsyncOp> completion; - hr = picker->PickSaveFileAsync(&completion); - if (FAILED(hr)) - return hr; - - // Create the callback method. - typedef winfoundtn::IAsyncOperationCompletedHandler< - winstorage::StorageFile*> HandlerDoneType; - mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( - this, &SaveFilePickerSession::FilePickerDone)); - DCHECK(handler.Get() != NULL); - hr = completion->put_Completed(handler.Get()); - - return hr; -} - -HRESULT SaveFilePickerSession::FilePickerDone(SaveFileAsyncOp* async, - AsyncStatus status) { - if (status == Completed) { - mswr::ComPtr<winstorage::IStorageFile> file; - HRESULT hr = async->GetResults(file.GetAddressOf()); - - if (file) { - mswr::ComPtr<winstorage::IStorageItem> storage_item; - if (SUCCEEDED(hr)) - hr = file.As(&storage_item); - - mswrw::HString file_path; - if (SUCCEEDED(hr)) - hr = storage_item->get_Path(file_path.GetAddressOf()); - - if (SUCCEEDED(hr)) { - base::string16 path_str = MakeStdWString(file_path.Get()); - result_ = path_str; - success_ = true; - } - } else { - LOG(ERROR) << "NULL IStorageItem"; - } - } else { - LOG(ERROR) << "Unexpected async status " << static_cast<int>(status); - } - app_view_->OnSaveFileCompleted(this, success_); - return S_OK; -} - -FolderPickerSession::FolderPickerSession(ChromeAppViewAsh* app_view, - const base::string16& title) - : FilePickerSessionBase(app_view, title, L"", base::FilePath()) { -} - -HRESULT FolderPickerSession::StartFilePicker() { - mswrw::HStringReference class_name( - RuntimeClass_Windows_Storage_Pickers_FolderPicker); - - // Create the folder picker. - mswr::ComPtr<winstorage::Pickers::IFolderPicker> picker; - HRESULT hr = ::Windows::Foundation::ActivateInstance( - class_name.Get(), picker.GetAddressOf()); - CheckHR(hr); - - // Set the file type filter - mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter; - hr = picker->get_FileTypeFilter(filter.GetAddressOf()); - if (FAILED(hr)) - return hr; - - hr = filter->Append(mswrw::HStringReference(L"*").Get()); - if (FAILED(hr)) - return hr; - - mswr::ComPtr<FolderPickerAsyncOp> completion; - hr = picker->PickSingleFolderAsync(&completion); - if (FAILED(hr)) - return hr; - - // Create the callback method. - typedef winfoundtn::IAsyncOperationCompletedHandler< - winstorage::StorageFolder*> HandlerDoneType; - mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( - this, &FolderPickerSession::FolderPickerDone)); - DCHECK(handler.Get() != NULL); - hr = completion->put_Completed(handler.Get()); - return hr; -} - -HRESULT FolderPickerSession::FolderPickerDone(FolderPickerAsyncOp* async, - AsyncStatus status) { - if (status == Completed) { - mswr::ComPtr<winstorage::IStorageFolder> folder; - HRESULT hr = async->GetResults(folder.GetAddressOf()); - - if (folder) { - mswr::ComPtr<winstorage::IStorageItem> storage_item; - if (SUCCEEDED(hr)) - hr = folder.As(&storage_item); - - mswrw::HString file_path; - if (SUCCEEDED(hr)) - hr = storage_item->get_Path(file_path.GetAddressOf()); - - if (SUCCEEDED(hr)) { - base::string16 path_str = MakeStdWString(file_path.Get()); - result_ = path_str; - success_ = true; - } - } else { - LOG(ERROR) << "NULL IStorageItem"; - } - } else { - LOG(ERROR) << "Unexpected async status " << static_cast<int>(status); - } - app_view_->OnFolderPickerCompleted(this, success_); - return S_OK; -} -
diff --git a/win8/metro_driver/file_picker_ash.h b/win8/metro_driver/file_picker_ash.h deleted file mode 100644 index 5d41a83..0000000 --- a/win8/metro_driver/file_picker_ash.h +++ /dev/null
@@ -1,157 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_ASH_H_ -#define CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_ASH_H_ - -#include <vector> - -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/strings/string16.h" - -class ChromeAppViewAsh; -struct MetroViewerHostMsg_SaveAsDialogParams; - -namespace base { -class FilePath; -} - -// Base class for the file pickers. -class FilePickerSessionBase { - public: - virtual ~FilePickerSessionBase(); - - // Runs the picker, returns true on success. - bool Run(); - - const base::string16& result() const { return result_; } - - bool success() const { return success_; } - - protected: - // Creates a file picker for open_file_name. - FilePickerSessionBase(ChromeAppViewAsh* app_view, - const base::string16& title, - const base::string16& filter, - const base::FilePath& default_path); - - // Creates, configures and starts a file picker. - // If the HRESULT returned is a failure code the file picker has not started, - // so no callbacks should be expected. - virtual HRESULT StartFilePicker() = 0; - - // True iff a file picker has successfully finished. - bool success_; - - // The title of the file picker. - base::string16 title_; - - // The file type filter. - base::string16 filter_; - - // The starting directory/file name. - base::FilePath default_path_; - - // Pointer to the ChromeAppViewAsh instance. We notify the ChromeAppViewAsh - // instance when the file open/save operations complete. - ChromeAppViewAsh* app_view_; - - base::string16 result_; - - private: - // Initiate a file picker, must be called on the main metro thread. - // Returns true on success. - bool DoFilePicker(); - - DISALLOW_COPY_AND_ASSIGN(FilePickerSessionBase); -}; - -// Provides functionality to display the open file/multiple open file pickers -// metro dialog. -class OpenFilePickerSession : public FilePickerSessionBase { - public: - OpenFilePickerSession(ChromeAppViewAsh* app_view, - const base::string16& title, - const base::string16& filter, - const base::FilePath& default_path, - bool allow_multi_select); - ~OpenFilePickerSession() override; - - const std::vector<base::FilePath>& filenames() const { - return filenames_; - } - - bool allow_multi_select() const { return allow_multi_select_; } - - private: - HRESULT StartFilePicker() override; - - typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*> - SingleFileAsyncOp; - typedef winfoundtn::Collections::IVectorView< - winstorage::StorageFile*> StorageFileVectorCollection; - typedef winfoundtn::IAsyncOperation<StorageFileVectorCollection*> - MultiFileAsyncOp; - - // Called asynchronously when a single file picker is done. - HRESULT SinglePickerDone(SingleFileAsyncOp* async, AsyncStatus status); - - // Called asynchronously when a multi file picker is done. - HRESULT MultiPickerDone(MultiFileAsyncOp* async, AsyncStatus status); - - // Composes a multi-file result string suitable for returning to a - // from a storage file collection. - static HRESULT ComposeMultiFileResult(StorageFileVectorCollection* files, - base::string16* result); - - // True if the multi file picker is to be displayed. - bool allow_multi_select_; - // If multi select is true then this member contains the list of filenames - // to be returned back. - std::vector<base::FilePath> filenames_; - - DISALLOW_COPY_AND_ASSIGN(OpenFilePickerSession); -}; - -// Provides functionality to display the save file picker. -class SaveFilePickerSession : public FilePickerSessionBase { - public: - SaveFilePickerSession(ChromeAppViewAsh* app_view, - const MetroViewerHostMsg_SaveAsDialogParams& params); - - int filter_index() const; - - private: - HRESULT StartFilePicker() override; - - typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*> SaveFileAsyncOp; - - // Called asynchronously when the save file picker is done. - HRESULT FilePickerDone(SaveFileAsyncOp* async, AsyncStatus status); - - int filter_index_; - - DISALLOW_COPY_AND_ASSIGN(SaveFilePickerSession); -}; - -// Provides functionality to display the folder picker. -class FolderPickerSession : public FilePickerSessionBase { - public: - FolderPickerSession(ChromeAppViewAsh* app_view, const base::string16& title); - - private: - HRESULT StartFilePicker() override; - - typedef winfoundtn::IAsyncOperation<winstorage::StorageFolder*> - FolderPickerAsyncOp; - - // Called asynchronously when the folder picker is done. - HRESULT FolderPickerDone(FolderPickerAsyncOp* async, AsyncStatus status); - - DISALLOW_COPY_AND_ASSIGN(FolderPickerSession); -}; - -#endif // CHROME_BROWSER_UI_METRO_DRIVER_FILE_PICKER_ASH_H_ -
diff --git a/win8/metro_driver/metro_driver.cc b/win8/metro_driver/metro_driver.cc deleted file mode 100644 index 650b238..0000000 --- a/win8/metro_driver/metro_driver.cc +++ /dev/null
@@ -1,135 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "stdafx.h" -#include "win8/metro_driver/metro_driver.h" - -#include <roerrorapi.h> -#include <shobjidl.h> - -#include "base/at_exit.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/logging_win.h" -#include "base/win/scoped_comptr.h" -#include "base/win/windows_version.h" -#include "win8/metro_driver/winrt_utils.h" - -namespace { - -#if !defined(NDEBUG) -LONG WINAPI ErrorReportingHandler(EXCEPTION_POINTERS* ex_info) { - // See roerrorapi.h for a description of the - // exception codes and parameters. - DWORD code = ex_info->ExceptionRecord->ExceptionCode; - ULONG_PTR* info = ex_info->ExceptionRecord->ExceptionInformation; - if (code == EXCEPTION_RO_ORIGINATEERROR) { - base::string16 msg(reinterpret_cast<wchar_t*>(info[2]), info[1]); - LOG(ERROR) << "VEH: Metro error 0x" << std::hex << info[0] << ": " << msg; - } else if (code == EXCEPTION_RO_TRANSFORMERROR) { - base::string16 msg(reinterpret_cast<wchar_t*>(info[3]), info[2]); - LOG(ERROR) << "VEH: Metro old error 0x" << std::hex << info[0] - << " new error 0x" << info[1] << ": " << msg; - } - - return EXCEPTION_CONTINUE_SEARCH; -} -#endif - -void SetMetroReportingFlags() { -#if !defined(NDEBUG) - // Set the error reporting flags to always raise an exception, - // which is then processed by our vectored exception handling - // above to log the error message. - winfoundtn::Diagnostics::SetErrorReportingFlags( - winfoundtn::Diagnostics::UseSetErrorInfo | - winfoundtn::Diagnostics::ForceExceptions); -#endif -} - -// TODO(robertshield): This GUID is hard-coded in a bunch of places that -// don't allow explicit includes. Find a single place for it to live. -// {7FE69228-633E-4f06-80C1-527FEA23E3A7} -const GUID kChromeTraceProviderName = { - 0x7fe69228, 0x633e, 0x4f06, - { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } }; - -} // namespace - -#if !defined(COMPONENT_BUILD) -// Required for base initialization. -// TODO(siggi): This should be handled better, as this way our at exit -// registrations will run under the loader's lock. However, -// once metro_driver is merged into Chrome.dll, this will go away anyhow. -base::AtExitManager at_exit; -#endif - -mswr::ComPtr<winapp::Core::ICoreApplication> InitWindows8() { - SetMetroReportingFlags(); - HRESULT hr = ::Windows::Foundation::Initialize(RO_INIT_MULTITHREADED); - if (FAILED(hr)) - CHECK(false); - mswr::ComPtr<winapp::Core::ICoreApplication> core_app; - hr = winrt_utils::CreateActivationFactory( - RuntimeClass_Windows_ApplicationModel_Core_CoreApplication, - core_app.GetAddressOf()); - if (FAILED(hr)) - CHECK(false); - return core_app; -} - -mswr::ComPtr<winapp::Core::ICoreApplication> InitWindows7(); - -extern "C" __declspec(dllexport) -int InitMetro() { - // Metro mode or its emulation is not supported in Vista or XP. - if (base::win::GetVersion() < base::win::VERSION_WIN7) - return 1; - // Initialize the command line. - base::CommandLine::Init(0, NULL); - // Initialize the logging system. - logging::LoggingSettings settings; - settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; - logging::InitLogging(settings); -#if defined(NDEBUG) - logging::SetMinLogLevel(logging::LOG_ERROR); -#else - logging::SetMinLogLevel(logging::LOG_VERBOSE); - HANDLE registration = - ::AddVectoredExceptionHandler(TRUE, ErrorReportingHandler); -#endif - // Enable trace control and transport through event tracing for Windows. - logging::LogEventProvider::Initialize(kChromeTraceProviderName); - DVLOG(1) << "InitMetro"; - - // OS specific initialization. - mswr::ComPtr<winapp::Core::ICoreApplication> core_app; - if (base::win::GetVersion() < base::win::VERSION_WIN8) - core_app = InitWindows7(); - else - core_app = InitWindows8(); - - auto view_factory = mswr::Make<ChromeAppViewFactory>(core_app.Get()); - HRESULT hr = core_app->Run(view_factory.Get()); - DVLOG(1) << "exiting InitMetro, hr=" << hr; - -#if !defined(NDEBUG) - ::RemoveVectoredExceptionHandler(registration); -#endif - return hr; -} - -// Activates the application known by |app_id|. Returns, among other things, -// E_APPLICATION_NOT_REGISTERED if |app_id| identifies Chrome and Chrome is not -// the default browser. -extern "C" __declspec(dllexport) -HRESULT ActivateApplication(const wchar_t* app_id) { - base::win::ScopedComPtr<IApplicationActivationManager> activator; - HRESULT hr = activator.CreateInstance(CLSID_ApplicationActivationManager); - if (SUCCEEDED(hr)) { - DWORD pid = 0; - hr = activator->ActivateApplication(app_id, L"", AO_NONE, &pid); - } - return hr; -}
diff --git a/win8/metro_driver/metro_driver.gyp b/win8/metro_driver/metro_driver.gyp index caa5ab5..a6f9afa 100644 --- a/win8/metro_driver/metro_driver.gyp +++ b/win8/metro_driver/metro_driver.gyp
@@ -65,9 +65,6 @@ 'sources': [ 'display_properties.cc', 'display_properties.h', - 'metro_driver.cc', - 'metro_driver.h', - 'metro_driver_win7.cc', 'stdafx.h', 'winrt_utils.cc', 'winrt_utils.h', @@ -75,16 +72,9 @@ ], 'conditions': [ ['use_aura==1', { - 'dependencies': [ - '../win8.gyp:metro_viewer_constants', - ], 'sources': [ - 'chrome_app_view_ash.cc', - 'chrome_app_view_ash.h', 'direct3d_helper.cc', 'direct3d_helper.h', - 'file_picker_ash.cc', - 'file_picker_ash.h', ], 'includes': [ 'ime/ime.gypi', @@ -97,8 +87,6 @@ 'chrome_url_launch_handler.h', 'devices_handler.cc', 'devices_handler.h', - 'file_picker.cc', - 'file_picker.h', 'metro_dialog_box.cc', 'metro_dialog_box.h', 'print_document_source.cc',
diff --git a/win8/metro_driver/metro_driver.h b/win8/metro_driver/metro_driver.h deleted file mode 100644 index da8f1c6..0000000 --- a/win8/metro_driver/metro_driver.h +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WIN8_METRO_DRIVER_METRO_DRIVER_H_ -#define WIN8_METRO_DRIVER_METRO_DRIVER_H_ - -#include "stdafx.h" - -class ChromeAppViewFactory - : public mswr::RuntimeClass<winapp::Core::IFrameworkViewSource> { - public: - ChromeAppViewFactory(winapp::Core::ICoreApplication* icore_app); - IFACEMETHOD(CreateView)(winapp::Core::IFrameworkView** view) override; -}; - -#endif // WIN8_METRO_DRIVER_METRO_DRIVER_H_ \ No newline at end of file
diff --git a/win8/metro_driver/metro_driver_win7.cc b/win8/metro_driver/metro_driver_win7.cc deleted file mode 100644 index 62662f5..0000000 --- a/win8/metro_driver/metro_driver_win7.cc +++ /dev/null
@@ -1,1229 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "stdafx.h" -#include <corewindow.h> -#include <shobjidl.h> -#include <stdint.h> - -#include "base/logging.h" -#include "base/macros.h" -#include "ui/gfx/geometry/safe_integer_conversions.h" -#include "ui/gfx/win/msg_util.h" - -#pragma comment(lib, "shell32.lib") - -EXTERN_C IMAGE_DOS_HEADER __ImageBase; -// Even though we only create a single window, we need to keep this -// count because of the hidden window used by the UI message loop of -// the metro viewer. -int g_window_count = 0; - -const wchar_t kAshWin7AppId[] = L"Google.Chrome.AshWin7.1"; -const wchar_t kAshWin7CoreWindowHandler[] = L"CoreWindowHandler"; -extern float GetModernUIScale(); -LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, - LPARAM lparam); - -HWND CreateMetroTopLevelWindow(const RECT& work_area) { - HINSTANCE hInst = reinterpret_cast<HINSTANCE>(&__ImageBase); - WNDCLASSEXW wcex; - wcex.cbSize = sizeof(wcex); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInst; - wcex.hIcon = LoadIcon(::GetModuleHandle(NULL), L"IDR_MAINFRAME"); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_INACTIVECAPTION+1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = L"Windows.UI.Core.CoreWindow"; - wcex.hIconSm = LoadIcon(::GetModuleHandle(NULL), L"IDR_MAINFRAME"); - - HWND hwnd = ::CreateWindowExW(0, - MAKEINTATOM(::RegisterClassExW(&wcex)), - L"metro_win7", - WS_POPUP | WS_VISIBLE | WS_MINIMIZEBOX, - work_area.top, work_area.left, - work_area.right, work_area.bottom, - NULL, NULL, hInst, NULL); - return hwnd; -} - -typedef winfoundtn::ITypedEventHandler< - winapp::Core::CoreApplicationView*, - winapp::Activation::IActivatedEventArgs*> ActivatedHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::WindowActivatedEventArgs*> WindowActivatedHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::AutomationProviderRequestedEventArgs*> - AutomationProviderHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::CharacterReceivedEventArgs*> CharEventHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::CoreWindowEventArgs*> CoreWindowEventHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::InputEnabledEventArgs*> InputEnabledEventHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::KeyEventArgs*> KeyEventHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::PointerEventArgs*> PointerEventHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::TouchHitTestingEventArgs*> TouchHitTestHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreWindow*, - winui::Core::VisibilityChangedEventArgs*> VisibilityChangedHandler; - -typedef winfoundtn::ITypedEventHandler< - winui::Core::CoreDispatcher*, - winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler; - -// This interface is implemented by classes which handle mouse and keyboard -// input. -class InputHandler { - public: - InputHandler() {} - virtual ~InputHandler() {} - - virtual bool HandleKeyboardMessage(const MSG& msg) = 0; - virtual bool HandleMouseMessage(const MSG& msg) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(InputHandler); -}; - -// This class implements the winrt interfaces corresponding to mouse input. -class MouseEvent : public mswr::RuntimeClass< - winui::Core::IPointerEventArgs, - winui::Input::IPointerPoint, - winui::Input::IPointerPointProperties, - windevs::Input::IPointerDevice> { - public: - MouseEvent(const MSG& msg) - : msg_(msg) { - } - - // IPointerEventArgs implementation. - HRESULT STDMETHODCALLTYPE - get_CurrentPoint(winui::Input::IPointerPoint** point) override { - return QueryInterface(winui::Input::IID_IPointerPoint, - reinterpret_cast<void**>(point)); - } - - HRESULT STDMETHODCALLTYPE - get_KeyModifiers(winsys::VirtualKeyModifiers* modifiers) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE GetIntermediatePoints( - winfoundtn::Collections::IVector<winui::Input::PointerPoint*>** points) - override { - return E_NOTIMPL; - } - - // IPointerPoint implementation. - HRESULT STDMETHODCALLTYPE - get_PointerDevice(windevs::Input::IPointerDevice** pointer_device) override { - return QueryInterface(windevs::Input::IID_IPointerDevice, - reinterpret_cast<void**>(pointer_device)); - } - - HRESULT STDMETHODCALLTYPE get_Position(winfoundtn::Point* position) override { - static float scale = GetModernUIScale(); - // Scale down the points here as they are scaled up on the other side. - position->X = gfx::ToRoundedInt(CR_GET_X_LPARAM(msg_.lParam) / scale); - position->Y = gfx::ToRoundedInt(CR_GET_Y_LPARAM(msg_.lParam) / scale); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE get_PointerId(uint32_t* pointer_id) override { - // TODO(ananta) - // Implement this properly. - *pointer_id = 1; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE get_Timestamp(uint64_t* timestamp) override { - *timestamp = msg_.time; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_Properties(winui::Input::IPointerPointProperties** properties) override { - return QueryInterface(winui::Input::IID_IPointerPointProperties, - reinterpret_cast<void**>(properties)); - } - - HRESULT STDMETHODCALLTYPE - get_RawPosition(winfoundtn::Point* position) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_FrameId(uint32_t* frame_id) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_IsInContact(boolean* in_contact) override { - return E_NOTIMPL; - } - - // IPointerPointProperties implementation. - HRESULT STDMETHODCALLTYPE - get_PointerUpdateKind(winui::Input::PointerUpdateKind* update_kind) override { - // TODO(ananta) - // There is no WM_POINTERUPDATE equivalent on Windows 7. Look into - // equivalents. - if (msg_.message == WM_LBUTTONDOWN) { - *update_kind = winui::Input::PointerUpdateKind_LeftButtonPressed; - } else if (msg_.message == WM_RBUTTONDOWN) { - *update_kind = winui::Input::PointerUpdateKind_RightButtonPressed; - } else if (msg_.message == WM_MBUTTONDOWN) { - *update_kind = winui::Input::PointerUpdateKind_MiddleButtonPressed; - } else if (msg_.message == WM_LBUTTONUP) { - *update_kind = winui::Input::PointerUpdateKind_LeftButtonReleased; - } else if (msg_.message == WM_RBUTTONUP) { - *update_kind = winui::Input::PointerUpdateKind_RightButtonReleased; - } else if (msg_.message == WM_MBUTTONUP) { - *update_kind = winui::Input::PointerUpdateKind_MiddleButtonReleased; - } - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_IsLeftButtonPressed(boolean* left_button_pressed) override { - *left_button_pressed = msg_.wParam & MK_LBUTTON ? true : false; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_IsRightButtonPressed(boolean* right_button_pressed) override { - *right_button_pressed = msg_.wParam & MK_RBUTTON ? true : false; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_IsMiddleButtonPressed(boolean* middle_button_pressed) override { - *middle_button_pressed = msg_.wParam & MK_MBUTTON ? true : false; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_IsHorizontalMouseWheel(boolean* is_horizontal_mouse_wheel) override { - *is_horizontal_mouse_wheel = - (msg_.message == WM_MOUSEHWHEEL) ? true : false; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE get_MouseWheelDelta(int* delta) override { - if (msg_.message == WM_MOUSEWHEEL || msg_.message == WM_MOUSEHWHEEL) { - *delta = GET_WHEEL_DELTA_WPARAM(msg_.wParam); - return S_OK; - } else { - return S_FALSE; - } - } - - HRESULT STDMETHODCALLTYPE get_Pressure(float* pressure) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_IsInverted(boolean* inverted) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_IsEraser(boolean* is_eraser) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_Orientation(float* orientation) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_XTilt(float* x_tilt) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_YTilt(float* y_tilt) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_Twist(float* twist) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_ContactRect(winfoundtn::Rect* rect) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE - get_ContactRectRaw(winfoundtn::Rect* rect) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_TouchConfidence(boolean* confidence) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_IsPrimary(boolean* is_primary) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_IsInRange(boolean* is_in_range) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_IsCanceled(boolean* is_canceled) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE - get_IsBarrelButtonPressed(boolean* is_barrel_button_pressed) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE - get_IsXButton1Pressed(boolean* is_xbutton1_pressed) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE - get_IsXButton2Pressed(boolean* is_xbutton2_pressed) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE HasUsage(uint32_t usage_page, - uint32_t usage_id, - boolean* has_usage) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE GetUsageValue(uint32_t usage_page, - uint32_t usage_id, - int32_t* usage_value) override { - return E_NOTIMPL; - } - - // IPointerDevice implementation. - HRESULT STDMETHODCALLTYPE get_PointerDeviceType( - windevs::Input::PointerDeviceType* device_type) override { - if (msg_.message == WM_TOUCH) { - *device_type = windevs::Input::PointerDeviceType_Touch; - } else { - *device_type = windevs::Input::PointerDeviceType_Mouse; - } - return S_OK; - } - - HRESULT STDMETHODCALLTYPE get_IsIntegrated(boolean* is_integrated) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_MaxContacts(uint32_t* contacts) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE - get_PhysicalDeviceRect(winfoundtn::Rect* rect) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_ScreenRect(winfoundtn::Rect* rect) override { - return E_NOTIMPL; - } - - HRESULT STDMETHODCALLTYPE get_SupportedUsages( - winfoundtn::Collections::IVectorView<windevs::Input::PointerDeviceUsage>** - usages) override { - return E_NOTIMPL; - } - - private: - MSG msg_; - - DISALLOW_COPY_AND_ASSIGN(MouseEvent); -}; - -// This class implements the winrt interfaces needed to support keyboard -// character and system character messages. -class KeyEvent : public mswr::RuntimeClass< - winui::Core::IKeyEventArgs, - winui::Core::ICharacterReceivedEventArgs, - winui::Core::IAcceleratorKeyEventArgs> { - public: - KeyEvent(const MSG& msg) - : msg_(msg) {} - - // IKeyEventArgs implementation. - HRESULT STDMETHODCALLTYPE - get_VirtualKey(winsys::VirtualKey* virtual_key) override { - *virtual_key = static_cast<winsys::VirtualKey>(msg_.wParam); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_KeyStatus(winui::Core::CorePhysicalKeyStatus* key_status) override { - // As per msdn documentation for the keyboard messages. - key_status->RepeatCount = msg_.lParam & 0x0000FFFF; - key_status->ScanCode = (msg_.lParam >> 16) & 0x00FF; - key_status->IsExtendedKey = (msg_.lParam & (1 << 24)); - key_status->IsMenuKeyDown = (msg_.lParam & (1 << 29)); - key_status->WasKeyDown = (msg_.lParam & (1 << 30)); - key_status->IsKeyReleased = (msg_.lParam & (1 << 31)); - return S_OK; - } - - // ICharacterReceivedEventArgs implementation. - HRESULT STDMETHODCALLTYPE get_KeyCode(uint32_t* key_code) override { - *key_code = msg_.wParam; - return S_OK; - } - - // IAcceleratorKeyEventArgs implementation. - HRESULT STDMETHODCALLTYPE - get_EventType(winui::Core::CoreAcceleratorKeyEventType* event_type) override { - if (msg_.message == WM_SYSKEYDOWN) { - *event_type = winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown; - } else if (msg_.message == WM_SYSKEYUP) { - *event_type = winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp; - } else if (msg_.message == WM_SYSCHAR) { - *event_type = winui::Core::CoreAcceleratorKeyEventType_SystemCharacter; - } - return S_OK; - } - - private: - MSG msg_; -}; - -// The following classes are the emulation of the WinRT system as exposed -// to metro applications. There is one application (ICoreApplication) which -// contains a series of Views (ICoreApplicationView) each one of them -// containing a CoreWindow which represents a surface that can drawn to -// and that receives events. -// -// Here is the general dependency hierachy in terms of interfaces: -// -// IFrameworkViewSource --> IFrameworkView -// ^ | -// | | metro app -// --------------------------------------------------------------------- -// | | winRT system -// | v -// ICoreApplication ICoreApplicationView -// | -// v -// ICoreWindow -----> ICoreWindowInterop -// | | -// | | -// v V -// ICoreDispatcher <==> real HWND -// -class CoreDispatcherEmulation : - public mswr::RuntimeClass< - winui::Core::ICoreDispatcher, - winui::Core::ICoreAcceleratorKeys> { - public: - CoreDispatcherEmulation(InputHandler* input_handler) - : input_handler_(input_handler), - accelerator_key_event_handler_(NULL) {} - - // ICoreDispatcher implementation: - HRESULT STDMETHODCALLTYPE get_HasThreadAccess(boolean* value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - ProcessEvents(winui::Core::CoreProcessEventsOption options) override { - // We don't support the other message pump modes. So we basically enter a - // traditional message loop that we only exit a teardown. - if (options != winui::Core::CoreProcessEventsOption_ProcessUntilQuit) - return E_FAIL; - - MSG msg = {0}; - while((::GetMessage(&msg, NULL, 0, 0) != 0) && g_window_count > 0) { - ProcessInputMessage(msg); - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - // TODO(cpu): figure what to do with msg.WParam which we would normally - // return here. - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - RunAsync(winui::Core::CoreDispatcherPriority priority, - winui::Core::IDispatchedHandler* agileCallback, - ABI::Windows::Foundation::IAsyncAction** asyncAction) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - RunIdleAsync(winui::Core::IIdleDispatchedHandler* agileCallback, - winfoundtn::IAsyncAction** asyncAction) override { - return S_OK; - } - - // ICoreAcceleratorKeys implementation: - HRESULT STDMETHODCALLTYPE - add_AcceleratorKeyActivated(AcceleratorKeyEventHandler* handler, - EventRegistrationToken* pCookie) override { - accelerator_key_event_handler_ = handler; - accelerator_key_event_handler_->AddRef(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - remove_AcceleratorKeyActivated(EventRegistrationToken cookie) override { - accelerator_key_event_handler_->Release(); - accelerator_key_event_handler_ = NULL; - return S_OK; - } - - private: - bool ProcessInputMessage(const MSG& msg) { - // Poor man's way of dispatching input events. - bool ret = false; - if (input_handler_) { - if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST)) { - if ((msg.message == WM_SYSKEYDOWN) || (msg.message == WM_SYSKEYUP) || - msg.message == WM_SYSCHAR) { - ret = HandleSystemKeys(msg); - } else { - ret = input_handler_->HandleKeyboardMessage(msg); - } - } else if ((msg.message >= WM_MOUSEFIRST) && - (msg.message <= WM_MOUSELAST)) { - ret = input_handler_->HandleMouseMessage(msg); - } - } - return ret; - } - - bool HandleSystemKeys(const MSG& msg) { - mswr::ComPtr<winui::Core::IAcceleratorKeyEventArgs> event_args; - event_args = mswr::Make<KeyEvent>(msg); - accelerator_key_event_handler_->Invoke(this, event_args.Get()); - return true; - } - - InputHandler* input_handler_; - AcceleratorKeyEventHandler* accelerator_key_event_handler_; -}; - -class CoreWindowEmulation - : public mswr::RuntimeClass< - mswr::RuntimeClassFlags<mswr::WinRtClassicComMix>, - winui::Core::ICoreWindow, ICoreWindowInterop>, - public InputHandler { - public: - CoreWindowEmulation(winapp::Core::IFrameworkView* app_view) - : mouse_moved_handler_(NULL), - mouse_capture_lost_handler_(NULL), - mouse_pressed_handler_(NULL), - mouse_released_handler_(NULL), - mouse_entered_handler_(NULL), - mouse_exited_handler_(NULL), - mouse_wheel_changed_handler_(NULL), - key_down_handler_(NULL), - key_up_handler_(NULL), - character_received_handler_(NULL), - core_hwnd_(NULL), - app_view_(app_view), - window_activated_handler_(NULL) { - dispatcher_ = mswr::Make<CoreDispatcherEmulation>(this); - - // Unless we select our own AppUserModelID the shell might confuse us - // with the app launcher one and we get the wrong taskbar button and icon. - ::SetCurrentProcessExplicitAppUserModelID(kAshWin7AppId); - - RECT work_area = {0}; - ::SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0); - if (::IsDebuggerPresent()) { - work_area.top = 0; - work_area.left = 0; - work_area.right = 1600; - work_area.bottom = 900; - } - - core_hwnd_ = CreateMetroTopLevelWindow(work_area); - ::SetProp(core_hwnd_, kAshWin7CoreWindowHandler, this); - } - - ~CoreWindowEmulation() override { - if (core_hwnd_) { - ::RemoveProp(core_hwnd_, kAshWin7CoreWindowHandler); - ::DestroyWindow(core_hwnd_); - } - } - - // ICoreWindow implementation: - HRESULT STDMETHODCALLTYPE - get_AutomationHostProvider(IInspectable** value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE get_Bounds(winfoundtn::Rect* value) override { - RECT rect; - if (!::GetClientRect(core_hwnd_, &rect)) - return E_FAIL; - value->Width = rect.right; - value->Height = rect.bottom; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_CustomProperties(winfoundtn::Collections::IPropertySet** value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_Dispatcher(winui::Core::ICoreDispatcher** value) override { - return dispatcher_.CopyTo(value); - } - - HRESULT STDMETHODCALLTYPE - get_FlowDirection(winui::Core::CoreWindowFlowDirection* value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - put_FlowDirection(winui::Core::CoreWindowFlowDirection value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE get_IsInputEnabled(boolean* value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE put_IsInputEnabled(boolean value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_PointerCursor(winui::Core::ICoreCursor** value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - put_PointerCursor(winui::Core::ICoreCursor* value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_PointerPosition(winfoundtn::Point* value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE get_Visible(boolean* value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE Activate(void) override { - // After we fire OnActivate on the View, Chrome calls us back here. - return S_OK; - } - - HRESULT STDMETHODCALLTYPE Close(void) override { - ::PostMessage(core_hwnd_, WM_CLOSE, 0, 0); - core_hwnd_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE GetAsyncKeyState( - ABI::Windows::System::VirtualKey virtualKey, - winui::Core::CoreVirtualKeyStates* KeyState) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE GetKeyState( - ABI::Windows::System::VirtualKey virtualKey, - winui::Core::CoreVirtualKeyStates* KeyState) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE ReleasePointerCapture(void) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE SetPointerCapture(void) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_Activated( - WindowActivatedHandler* handler, - EventRegistrationToken* pCookie) override { - window_activated_handler_ = handler; - handler->AddRef(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_Activated( - EventRegistrationToken cookie) override { - window_activated_handler_->Release(); - window_activated_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_AutomationProviderRequested( - AutomationProviderHandler* handler, - EventRegistrationToken* cookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_AutomationProviderRequested( - EventRegistrationToken cookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_CharacterReceived( - CharEventHandler* handler, - EventRegistrationToken* pCookie) override { - character_received_handler_ = handler; - character_received_handler_->AddRef(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_CharacterReceived( - EventRegistrationToken cookie) override { - character_received_handler_->Release(); - character_received_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_Closed( - CoreWindowEventHandler* handler, - EventRegistrationToken* pCookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_Closed( - EventRegistrationToken cookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_InputEnabled( - InputEnabledEventHandler* handler, - EventRegistrationToken* pCookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_InputEnabled( - EventRegistrationToken cookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_KeyDown( - KeyEventHandler* handler, - EventRegistrationToken* pCookie) override { - key_down_handler_ = handler; - key_down_handler_->AddRef(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_KeyDown( - EventRegistrationToken cookie) override { - key_down_handler_->Release(); - key_down_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_KeyUp( - KeyEventHandler* handler, - EventRegistrationToken* pCookie) override { - key_up_handler_ = handler; - key_up_handler_->AddRef(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_KeyUp( - EventRegistrationToken cookie) override { - key_up_handler_->Release(); - key_up_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_PointerCaptureLost( - PointerEventHandler* handler, - EventRegistrationToken* cookie) override { - mouse_capture_lost_handler_ = handler; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_PointerCaptureLost( - EventRegistrationToken cookie) override { - mouse_capture_lost_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_PointerEntered( - PointerEventHandler* handler, - EventRegistrationToken* cookie) override { - mouse_entered_handler_ = handler; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_PointerEntered( - EventRegistrationToken cookie) override { - mouse_entered_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_PointerExited( - PointerEventHandler* handler, - EventRegistrationToken* cookie) override { - mouse_exited_handler_ = handler; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_PointerExited( - EventRegistrationToken cookie) override { - mouse_exited_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_PointerMoved( - PointerEventHandler* handler, - EventRegistrationToken* cookie) override { - mouse_moved_handler_ = handler; - mouse_moved_handler_->AddRef(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_PointerMoved( - EventRegistrationToken cookie) override { - mouse_moved_handler_->Release(); - mouse_moved_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_PointerPressed( - PointerEventHandler* handler, - EventRegistrationToken* cookie) override { - mouse_pressed_handler_ = handler; - mouse_pressed_handler_->AddRef(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_PointerPressed( - EventRegistrationToken cookie) override { - mouse_pressed_handler_->Release(); - mouse_pressed_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_PointerReleased( - PointerEventHandler* handler, - EventRegistrationToken* cookie) override { - mouse_released_handler_ = handler; - mouse_released_handler_->AddRef(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_PointerReleased( - EventRegistrationToken cookie) override { - mouse_released_handler_->Release(); - mouse_released_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_TouchHitTesting( - TouchHitTestHandler* handler, - EventRegistrationToken* pCookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_TouchHitTesting( - EventRegistrationToken cookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_PointerWheelChanged( - PointerEventHandler* handler, - EventRegistrationToken* cookie) override { - mouse_wheel_changed_handler_ = handler; - mouse_wheel_changed_handler_->AddRef(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_PointerWheelChanged( - EventRegistrationToken cookie) override { - mouse_wheel_changed_handler_->Release(); - mouse_wheel_changed_handler_ = NULL; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_SizeChanged( - SizeChangedHandler* handler, - EventRegistrationToken* pCookie) override { - // TODO(cpu): implement this. - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_SizeChanged( - EventRegistrationToken cookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE add_VisibilityChanged( - VisibilityChangedHandler* handler, - EventRegistrationToken* pCookie) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE remove_VisibilityChanged( - EventRegistrationToken cookie) override { - return S_OK; - } - - // ICoreWindowInterop implementation: - HRESULT STDMETHODCALLTYPE get_WindowHandle(HWND* hwnd) override { - if (!core_hwnd_) - return E_FAIL; - *hwnd = core_hwnd_; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE put_MessageHandled(boolean value) override { - return S_OK; - } - - // InputHandler - bool HandleKeyboardMessage(const MSG& msg) override { - switch (msg.message) { - case WM_KEYDOWN: - case WM_KEYUP: { - mswr::ComPtr<winui::Core::IKeyEventArgs> event_args; - event_args = mswr::Make<KeyEvent>(msg); - KeyEventHandler* handler = NULL; - if (msg.message == WM_KEYDOWN) { - handler = key_down_handler_; - } else { - handler = key_up_handler_; - } - handler->Invoke(this, event_args.Get()); - break; - } - - case WM_CHAR: - case WM_DEADCHAR: - case WM_UNICHAR: { - mswr::ComPtr<winui::Core::ICharacterReceivedEventArgs> event_args; - event_args = mswr::Make<KeyEvent>(msg); - character_received_handler_->Invoke(this, event_args.Get()); - break; - } - - default: - return false; - } - return true; - } - - bool HandleMouseMessage(const MSG& msg) override { - PointerEventHandler* handler = NULL; - mswr::ComPtr<winui::Core::IPointerEventArgs> event_args; - event_args = mswr::Make<MouseEvent>(msg); - switch (msg.message) { - case WM_MOUSEMOVE: { - handler = mouse_moved_handler_; - break; - } - case WM_LBUTTONDOWN: { - case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: - handler = mouse_pressed_handler_; - break; - } - - case WM_LBUTTONUP: { - case WM_RBUTTONUP: - case WM_MBUTTONUP: - handler = mouse_released_handler_; - break; - } - - case WM_MOUSEWHEEL: { - case WM_MOUSEHWHEEL: - handler = mouse_wheel_changed_handler_; - break; - } - - default: - return false; - } - DCHECK(handler); - handler->Invoke(this, event_args.Get()); - return true; - } - - void OnWindowActivated() { - if (window_activated_handler_) - window_activated_handler_->Invoke(this, NULL); - } - - private: - PointerEventHandler* mouse_moved_handler_; - PointerEventHandler* mouse_capture_lost_handler_; - PointerEventHandler* mouse_pressed_handler_; - PointerEventHandler* mouse_released_handler_; - PointerEventHandler* mouse_entered_handler_; - PointerEventHandler* mouse_exited_handler_; - PointerEventHandler* mouse_wheel_changed_handler_; - KeyEventHandler* key_down_handler_; - KeyEventHandler* key_up_handler_; - CharEventHandler* character_received_handler_; - HWND core_hwnd_; - mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher_; - mswr::ComPtr<winapp::Core::IFrameworkView> app_view_; - WindowActivatedHandler* window_activated_handler_; -}; - -LRESULT CALLBACK WndProc(HWND hwnd, UINT message, - WPARAM wparam, LPARAM lparam) { - PAINTSTRUCT ps; - HDC hdc; - switch (message) { - case WM_ACTIVATE: { - // HIWORD(wparam) is 1 if the window is minimized. - bool active = (LOWORD(wparam) != WA_INACTIVE) && !HIWORD(wparam); - if (active) { - CoreWindowEmulation* core_window_handler = - reinterpret_cast<CoreWindowEmulation*>( - ::GetProp(hwnd, kAshWin7CoreWindowHandler)); - if (core_window_handler) - core_window_handler->OnWindowActivated(); - } - return ::DefWindowProc(hwnd, message, wparam, lparam); - } - case WM_CREATE: - ++g_window_count; - break; - case WM_PAINT: - hdc = ::BeginPaint(hwnd, &ps); - ::EndPaint(hwnd, &ps); - break; - case WM_CLOSE: - ::DestroyWindow(hwnd); - break; - case WM_DESTROY: - --g_window_count; - if (!g_window_count) - ::PostQuitMessage(0); - break; - // Always allow Chrome to set the cursor. - case WM_SETCURSOR: - return 1; - default: - return ::DefWindowProc(hwnd, message, wparam, lparam); - } - return 0; -} - -class ActivatedEvent - : public mswr::RuntimeClass<winapp::Activation::IActivatedEventArgs> { - public: - ActivatedEvent(winapp::Activation::ActivationKind activation_kind) - : activation_kind_(activation_kind) { - } - - HRESULT STDMETHODCALLTYPE - get_Kind(winapp::Activation::ActivationKind* value) override { - *value = activation_kind_; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE get_PreviousExecutionState( - winapp::Activation::ApplicationExecutionState* value) override { - *value = winapp::Activation::ApplicationExecutionState_ClosedByUser; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_SplashScreen(winapp::Activation::ISplashScreen** value) override { - return E_FAIL; - } - - private: - winapp::Activation::ActivationKind activation_kind_; -}; - -class CoreApplicationViewEmulation - : public mswr::RuntimeClass<winapp::Core::ICoreApplicationView> { - public: - CoreApplicationViewEmulation(winapp::Core::IFrameworkView* app_view) { - core_window_ = mswr::Make<CoreWindowEmulation>(app_view); - } - - HRESULT Activate() { - if (activated_handler_) { - auto ae = mswr::Make<ActivatedEvent>( - winapp::Activation::ActivationKind_File); - return activated_handler_->Invoke(this, ae.Get()); - } else { - return S_OK; - } - } - - HRESULT Close() { - return core_window_->Close(); - } - - // ICoreApplicationView implementation: - HRESULT STDMETHODCALLTYPE - get_CoreWindow(winui::Core::ICoreWindow** value) override { - if (!core_window_) - return E_FAIL; - return core_window_.CopyTo(value); - } - - HRESULT STDMETHODCALLTYPE - add_Activated(ActivatedHandler* handler, - EventRegistrationToken* token) override { - // The real component supports multiple handles but we don't yet. - if (activated_handler_) - return E_FAIL; - activated_handler_ = handler; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - remove_Activated(EventRegistrationToken token) override { - // Chrome never unregisters handlers, so we don't care about it. - return S_OK; - } - - HRESULT STDMETHODCALLTYPE get_IsMain(boolean* value) override { return S_OK; } - - HRESULT STDMETHODCALLTYPE get_IsHosted(boolean* value) override { - return S_OK; - } - - private: - mswr::ComPtr<CoreWindowEmulation> core_window_; - mswr::ComPtr<ActivatedHandler> activated_handler_; -}; - -class CoreApplicationWin7Emulation - : public mswr::RuntimeClass<winapp::Core::ICoreApplication, - winapp::Core::ICoreApplicationExit> { - public: - // ICoreApplication implementation: - - HRESULT STDMETHODCALLTYPE get_Id(HSTRING* value) override { return S_OK; } - - HRESULT STDMETHODCALLTYPE add_Suspending( - winfoundtn::IEventHandler<winapp::SuspendingEventArgs*>* handler, - EventRegistrationToken* token) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - remove_Suspending(EventRegistrationToken token) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - add_Resuming(winfoundtn::IEventHandler<IInspectable*>* handler, - EventRegistrationToken* token) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - remove_Resuming(EventRegistrationToken token) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - get_Properties(winfoundtn::Collections::IPropertySet** value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - GetCurrentView(winapp::Core::ICoreApplicationView** value) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - Run(winapp::Core::IFrameworkViewSource* viewSource) override { - HRESULT hr = viewSource->CreateView(app_view_.GetAddressOf()); - if (FAILED(hr)) - return hr; - view_emulation_ = mswr::Make<CoreApplicationViewEmulation>( - app_view_.Get()); - hr = app_view_->Initialize(view_emulation_.Get()); - if (FAILED(hr)) - return hr; - mswr::ComPtr<winui::Core::ICoreWindow> core_window; - hr = view_emulation_->get_CoreWindow(core_window.GetAddressOf()); - if (FAILED(hr)) - return hr; - hr = app_view_->SetWindow(core_window.Get()); - if (FAILED(hr)) - return hr; - hr = app_view_->Load(NULL); - if (FAILED(hr)) - return hr; - hr = view_emulation_->Activate(); - if (FAILED(hr)) - return hr; - return app_view_->Run(); - } - - HRESULT STDMETHODCALLTYPE RunWithActivationFactories( - winfoundtn::IGetActivationFactory* activationFactoryCallback) override { - return S_OK; - } - - // ICoreApplicationExit implementation: - - HRESULT STDMETHODCALLTYPE Exit(void) override { - return view_emulation_->Close(); - } - - HRESULT STDMETHODCALLTYPE - add_Exiting(winfoundtn::IEventHandler<IInspectable*>* handler, - EventRegistrationToken* token) override { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE - remove_Exiting(EventRegistrationToken token) override { - return S_OK; - } - - private: - mswr::ComPtr<winapp::Core::IFrameworkView> app_view_; - mswr::ComPtr<CoreApplicationViewEmulation> view_emulation_; -}; - - -mswr::ComPtr<winapp::Core::ICoreApplication> InitWindows7() { - HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - if (FAILED(hr)) - CHECK(false); - return mswr::Make<CoreApplicationWin7Emulation>(); -} -
diff --git a/win8/viewer/metro_viewer_constants.cc b/win8/viewer/metro_viewer_constants.cc deleted file mode 100644 index fd54fe4..0000000 --- a/win8/viewer/metro_viewer_constants.cc +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "win8/viewer/metro_viewer_constants.h" - -namespace win8 { - -const char kMetroViewerIPCChannelName[] = "viewer"; - -const wchar_t kMetroViewerConnectVerb[] = L"connect"; - -} // namespace win8
diff --git a/win8/viewer/metro_viewer_constants.h b/win8/viewer/metro_viewer_constants.h deleted file mode 100644 index 560a450..0000000 --- a/win8/viewer/metro_viewer_constants.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WIN8_VIEWER_METRO_VIEWER_CONSTANTS_H_ -#define WIN8_VIEWER_METRO_VIEWER_CONSTANTS_H_ - -namespace win8 { - -// The name of the IPC channel between the browser process and the metro viewer -// process. -extern const char kMetroViewerIPCChannelName[]; - -// Tells the viewer process to simply connect back without needing to launch a -// browser process itself. -extern const wchar_t kMetroViewerConnectVerb[]; - -} // namespace win8 - -#endif // WIN8_VIEWER_METRO_VIEWER_CONSTANTS_H_
diff --git a/win8/viewer/metro_viewer_exports.h b/win8/viewer/metro_viewer_exports.h deleted file mode 100644 index 61ff7d5..0000000 --- a/win8/viewer/metro_viewer_exports.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef METRO_VIEWER_METRO_VIEWER_H_ -#define METRO_VIEWER_METRO_VIEWER_H_ - -#if defined(COMPONENT_BUILD) -#if defined(WIN32) - -#if defined(METRO_VIEWER_IMPLEMENTATION) -#define METRO_VIEWER_EXPORT __declspec(dllexport) -#else -#define METRO_VIEWER_EXPORT __declspec(dllimport) -#endif // defined(METRO_VIEWER_IMPLEMENTATION) - -#else // defined(WIN32) -#if defined(METRO_VIEWER_IMPLEMENTATION) -#define METRO_VIEWER_EXPORT __attribute__((visibility("default"))) -#else -#define METRO_VIEWER_EXPORT -#endif -#endif - -#else // defined(COMPONENT_BUILD) -#define METRO_VIEWER_EXPORT -#endif - -#endif // METRO_VIEWER_METRO_VIEWER_H_
diff --git a/win8/viewer/metro_viewer_process_host.cc b/win8/viewer/metro_viewer_process_host.cc deleted file mode 100644 index a3652410..0000000 --- a/win8/viewer/metro_viewer_process_host.cc +++ /dev/null
@@ -1,346 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "win8/viewer/metro_viewer_process_host.h" - -#include <shlobj.h> -#include <stdint.h> - -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/memory/ref_counted.h" -#include "base/path_service.h" -#include "base/process/process.h" -#include "base/strings/string16.h" -#include "base/synchronization/waitable_event.h" -#include "base/time/time.h" -#include "base/win/scoped_comptr.h" -#include "base/win/windows_version.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_message.h" -#include "ipc/ipc_message_macros.h" -#include "ui/aura/remote_window_tree_host_win.h" -#include "ui/metro_viewer/metro_viewer_messages.h" -#include "win8/viewer/metro_viewer_constants.h" - -namespace { - -const int kViewerProcessConnectionTimeoutSecs = 60; - -} // namespace - -namespace win8 { - -// static -MetroViewerProcessHost* MetroViewerProcessHost::instance_ = NULL; - -MetroViewerProcessHost::InternalMessageFilter::InternalMessageFilter( - MetroViewerProcessHost* owner) - : owner_(owner) { -} - -void MetroViewerProcessHost::InternalMessageFilter::OnChannelConnected( - int32_t peer_pid) { - owner_->NotifyChannelConnected(); -} - -MetroViewerProcessHost::InternalMessageFilter::~InternalMessageFilter() { -} - -MetroViewerProcessHost::MetroViewerProcessHost( - const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) { - DCHECK(!instance_); - instance_ = this; - - channel_ = IPC::ChannelProxy::Create(kMetroViewerIPCChannelName, - IPC::Channel::MODE_NAMED_SERVER, - this, - ipc_task_runner); -} - -MetroViewerProcessHost::~MetroViewerProcessHost() { - if (!channel_) { - instance_ = NULL; - return; - } - - base::ProcessId viewer_process_id = GetViewerProcessId(); - channel_->Close(); - if (message_filter_.get()) { - // Wait for the viewer process to go away. - if (viewer_process_id != base::kNullProcessId) { - base::Process viewer_process = - base::Process::OpenWithAccess( - viewer_process_id, - PROCESS_QUERY_INFORMATION | SYNCHRONIZE); - if (viewer_process.IsValid()) { - int exit_code; - viewer_process.WaitForExit(&exit_code); - } - } - channel_->RemoveFilter(message_filter_.get()); - } - instance_ = NULL; -} - -base::ProcessId MetroViewerProcessHost::GetViewerProcessId() { - if (channel_) - return channel_->GetPeerPID(); - return base::kNullProcessId; -} - -bool MetroViewerProcessHost::LaunchViewerAndWaitForConnection( - const base::string16& app_user_model_id) { - DCHECK_EQ(base::kNullProcessId, channel_->GetPeerPID()); - - channel_connected_event_.reset(new base::WaitableEvent(false, false)); - - message_filter_ = new InternalMessageFilter(this); - channel_->AddFilter(message_filter_.get()); - - if (base::win::GetVersion() >= base::win::VERSION_WIN8) { - base::win::ScopedComPtr<IApplicationActivationManager> activator; - HRESULT hr = activator.CreateInstance(CLSID_ApplicationActivationManager); - if (SUCCEEDED(hr)) { - DWORD pid = 0; - // Use the "connect" verb to - hr = activator->ActivateApplication( - app_user_model_id.c_str(), kMetroViewerConnectVerb, AO_NONE, &pid); - } - - LOG_IF(ERROR, FAILED(hr)) << "Tried and failed to launch Metro Chrome. " - << "hr=" << std::hex << hr; - } else { - // For Windows 7 we need to launch the viewer ourselves. - base::FilePath chrome_path; - if (!PathService::Get(base::DIR_EXE, &chrome_path)) - return false; - // TODO(cpu): launch with "-ServerName:DefaultBrowserServer" - // note that the viewer might try to launch chrome again. - CHECK(false); - } - - // Having launched the viewer process, now we wait for it to connect. - bool success = - channel_connected_event_->TimedWait(base::TimeDelta::FromSeconds( - kViewerProcessConnectionTimeoutSecs)); - channel_connected_event_.reset(); - return success; -} - -bool MetroViewerProcessHost::Send(IPC::Message* msg) { - return channel_->Send(msg); -} - -bool MetroViewerProcessHost::OnMessageReceived( - const IPC::Message& message) { - DCHECK(CalledOnValidThread()); - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(MetroViewerProcessHost, message) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone, - OnFileSaveAsDone) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone, - OnFileOpenDone) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone, - OnMultiFileOpenDone) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURL, OnOpenURL) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SearchRequest, OnHandleSearchRequest) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone, - OnSelectFolderDone) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetTargetSurface, OnSetTargetSurface) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowSizeChanged, - OnWindowSizeChanged) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled ? true : - aura::RemoteWindowTreeHostWin::Instance()->OnMessageReceived(message); -} - -// static -void MetroViewerProcessHost::HandleActivateDesktop( - const base::FilePath& path, - bool ash_exit) { - if (instance_) { - instance_->Send( - new MetroViewerHostMsg_ActivateDesktop(path, ash_exit)); - } -} - -// static -void MetroViewerProcessHost::HandleMetroExit() { - if (instance_) - instance_->Send(new MetroViewerHostMsg_MetroExit()); -} - -// static -void MetroViewerProcessHost::HandleOpenFile( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenFileCompletion& on_success, - const FileSelectionCanceled& on_failure) { - if (instance_) { - instance_->HandleOpenFileImpl(title, default_path, filter, on_success, - on_failure); - } -} - -// static -void MetroViewerProcessHost::HandleOpenMultipleFiles( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenMultipleFilesCompletion& on_success, - const FileSelectionCanceled& on_failure) { - if (instance_) { - instance_->HandleOpenMultipleFilesImpl(title, default_path, filter, - on_success, on_failure); - } -} - -// static -void MetroViewerProcessHost::HandleSaveFile( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - int filter_index, - const base::string16& default_extension, - const SaveFileCompletion& on_success, - const FileSelectionCanceled& on_failure) { - if (instance_) { - instance_->HandleSaveFileImpl(title, default_path, filter, filter_index, - default_extension, on_success, on_failure); - } -} - -// static -void MetroViewerProcessHost::HandleSelectFolder( - const base::string16& title, - const SelectFolderCompletion& on_success, - const FileSelectionCanceled& on_failure) { - if (instance_) - instance_->HandleSelectFolderImpl(title, on_success, on_failure); -} - -void MetroViewerProcessHost::HandleOpenFileImpl( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenFileCompletion& on_success, - const FileSelectionCanceled& on_failure) { - // Can only have one of these operations in flight. - DCHECK(file_open_completion_callback_.is_null()); - DCHECK(failure_callback_.is_null()); - - file_open_completion_callback_ = on_success; - failure_callback_ = on_failure; - - Send(new MetroViewerHostMsg_DisplayFileOpen(title, filter, default_path, - false)); -} - -void MetroViewerProcessHost::HandleOpenMultipleFilesImpl( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenMultipleFilesCompletion& on_success, - const FileSelectionCanceled& on_failure) { - // Can only have one of these operations in flight. - DCHECK(multi_file_open_completion_callback_.is_null()); - DCHECK(failure_callback_.is_null()); - multi_file_open_completion_callback_ = on_success; - failure_callback_ = on_failure; - - Send(new MetroViewerHostMsg_DisplayFileOpen(title, filter, default_path, - true)); -} - -void MetroViewerProcessHost::HandleSaveFileImpl( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - int filter_index, - const base::string16& default_extension, - const SaveFileCompletion& on_success, - const FileSelectionCanceled& on_failure) { - MetroViewerHostMsg_SaveAsDialogParams params; - params.title = title; - params.default_extension = default_extension; - params.filter = filter; - params.filter_index = filter_index; - params.suggested_name = default_path; - - // Can only have one of these operations in flight. - DCHECK(file_saveas_completion_callback_.is_null()); - DCHECK(failure_callback_.is_null()); - file_saveas_completion_callback_ = on_success; - failure_callback_ = on_failure; - - Send(new MetroViewerHostMsg_DisplayFileSaveAs(params)); -} - -void MetroViewerProcessHost::HandleSelectFolderImpl( - const base::string16& title, - const SelectFolderCompletion& on_success, - const FileSelectionCanceled& on_failure) { - // Can only have one of these operations in flight. - DCHECK(select_folder_completion_callback_.is_null()); - DCHECK(failure_callback_.is_null()); - select_folder_completion_callback_ = on_success; - failure_callback_ = on_failure; - - Send(new MetroViewerHostMsg_DisplaySelectFolder(title)); -} - -void MetroViewerProcessHost::NotifyChannelConnected() { - if (channel_connected_event_) - channel_connected_event_->Signal(); -} - -void MetroViewerProcessHost::OnFileSaveAsDone(bool success, - const base::FilePath& filename, - int filter_index) { - if (success) - file_saveas_completion_callback_.Run(filename, filter_index, NULL); - else - failure_callback_.Run(NULL); - file_saveas_completion_callback_.Reset(); - failure_callback_.Reset(); -} - - -void MetroViewerProcessHost::OnFileOpenDone(bool success, - const base::FilePath& filename) { - if (success) - file_open_completion_callback_.Run(base::FilePath(filename), 0, NULL); - else - failure_callback_.Run(NULL); - file_open_completion_callback_.Reset(); - failure_callback_.Reset(); -} - -void MetroViewerProcessHost::OnMultiFileOpenDone( - bool success, - const std::vector<base::FilePath>& files) { - if (success) - multi_file_open_completion_callback_.Run(files, NULL); - else - failure_callback_.Run(NULL); - multi_file_open_completion_callback_.Reset(); - failure_callback_.Reset(); -} - -void MetroViewerProcessHost::OnSelectFolderDone( - bool success, - const base::FilePath& folder) { - if (success) - select_folder_completion_callback_.Run(base::FilePath(folder), 0, NULL); - else - failure_callback_.Run(NULL); - select_folder_completion_callback_.Reset(); - failure_callback_.Reset(); -} - -} // namespace win8
diff --git a/win8/viewer/metro_viewer_process_host.h b/win8/viewer/metro_viewer_process_host.h deleted file mode 100644 index 2b1a56f..0000000 --- a/win8/viewer/metro_viewer_process_host.h +++ /dev/null
@@ -1,221 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WIN8_VIEWER_METRO_VIEWER_PROCESS_HOST_H_ -#define WIN8_VIEWER_METRO_VIEWER_PROCESS_HOST_H_ - -#include <stdint.h> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string16.h" -#include "base/threading/non_thread_safe.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_listener.h" -#include "ipc/ipc_sender.h" -#include "ipc/message_filter.h" -#include "ui/gfx/native_widget_types.h" -#include "win8/viewer/metro_viewer_exports.h" - -namespace base { -class SingleThreadTaskRunner; -class WaitableEvent; -} - -namespace IPC { -class ChannelProxy; -class Message; -} - -namespace win8 { - -// Abstract base class for various Metro viewer process host implementations. -class METRO_VIEWER_EXPORT MetroViewerProcessHost : public IPC::Listener, - public IPC::Sender, - public base::NonThreadSafe { - public: - typedef base::Callback<void(const base::FilePath&, int, void*)> - OpenFileCompletion; - - typedef base::Callback<void(const std::vector<base::FilePath>&, void*)> - OpenMultipleFilesCompletion; - - typedef base::Callback<void(const base::FilePath&, int, void*)> - SaveFileCompletion; - - typedef base::Callback<void(const base::FilePath&, int, void*)> - SelectFolderCompletion; - - typedef base::Callback<void(void*)> FileSelectionCanceled; - - // Initializes a viewer process host to connect to the Metro viewer process - // over IPC. The given task runner correspond to a thread on which - // IPC::Channel is created and used (e.g. IO thread). Instantly connects to - // the viewer process if one is already connected to |ipc_channel_name|; a - // viewer can otherwise be launched synchronously via - // LaunchViewerAndWaitForConnection(). - explicit MetroViewerProcessHost( - const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner); - ~MetroViewerProcessHost() override; - - // Returns the process id of the viewer process if one is connected to this - // host, returns base::kNullProcessId otherwise. - base::ProcessId GetViewerProcessId(); - - // Launches the viewer process associated with the given |app_user_model_id| - // and blocks until that viewer process connects or until a timeout is - // reached. Returns true if the viewer process connects before the timeout is - // reached. NOTE: this assumes that the app referred to by |app_user_model_id| - // is registered as the default browser. - bool LaunchViewerAndWaitForConnection( - const base::string16& app_user_model_id); - - // Handles the activate desktop command for Metro Chrome Ash. The |ash_exit| - // parameter indicates whether the Ash process would be shutdown after - // activating the desktop. - static void HandleActivateDesktop(const base::FilePath& shortcut, - bool ash_exit); - - // Handles the metro exit command. Notifies the metro viewer to shutdown - // gracefully. - static void HandleMetroExit(); - - // Handles the open file operation for Metro Chrome Ash. The on_success - // callback passed in is invoked when we receive the opened file name from - // the metro viewer. The on failure callback is invoked on failure. - static void HandleOpenFile(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenFileCompletion& on_success, - const FileSelectionCanceled& on_failure); - - // Handles the open multiple file operation for Metro Chrome Ash. The - // on_success callback passed in is invoked when we receive the opened file - // names from the metro viewer. The on failure callback is invoked on failure. - static void HandleOpenMultipleFiles( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenMultipleFilesCompletion& on_success, - const FileSelectionCanceled& on_failure); - - // Handles the save file operation for Metro Chrome Ash. The on_success - // callback passed in is invoked when we receive the saved file name from - // the metro viewer. The on failure callback is invoked on failure. - static void HandleSaveFile(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - int filter_index, - const base::string16& default_extension, - const SaveFileCompletion& on_success, - const FileSelectionCanceled& on_failure); - - // Handles the select folder for Metro Chrome Ash. The on_success - // callback passed in is invoked when we receive the folder name from the - // metro viewer. The on failure callback is invoked on failure. - static void HandleSelectFolder(const base::string16& title, - const SelectFolderCompletion& on_success, - const FileSelectionCanceled& on_failure); - - protected: - // IPC::Sender implementation: - bool Send(IPC::Message* msg) override; - - // IPC::Listener implementation: - bool OnMessageReceived(const IPC::Message& message) override; - void OnChannelError() override = 0; - - private: - // The following are the implementation for the corresponding static methods - // above, see them for descriptions. - void HandleOpenFileImpl(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenFileCompletion& on_success, - const FileSelectionCanceled& on_failure); - void HandleOpenMultipleFilesImpl( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenMultipleFilesCompletion& on_success, - const FileSelectionCanceled& on_failure); - void HandleSaveFileImpl(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - int filter_index, - const base::string16& default_extension, - const SaveFileCompletion& on_success, - const FileSelectionCanceled& on_failure); - void HandleSelectFolderImpl(const base::string16& title, - const SelectFolderCompletion& on_success, - const FileSelectionCanceled& on_failure); - - // Called over IPC by the viewer process to tell this host that it should be - // drawing to |target_surface|. - virtual void OnSetTargetSurface(gfx::NativeViewId target_surface, - float device_scale) = 0; - - // Called over IPC by the viewer process to request that the url passed in be - // opened. - virtual void OnOpenURL(const base::string16& url) = 0; - - // Called over IPC by the viewer process to request that the search string - // passed in is passed to the default search provider and a URL navigation be - // performed. - virtual void OnHandleSearchRequest(const base::string16& search_string) = 0; - - // Called over IPC by the viewer process when the window size has changed. - virtual void OnWindowSizeChanged(uint32_t width, uint32_t height) = 0; - - void NotifyChannelConnected(); - - // IPC message handing methods: - void OnFileSaveAsDone(bool success, - const base::FilePath& filename, - int filter_index); - void OnFileOpenDone(bool success, const base::FilePath& filename); - void OnMultiFileOpenDone(bool success, - const std::vector<base::FilePath>& files); - void OnSelectFolderDone(bool success, const base::FilePath& folder); - - // Inner message filter used to handle connection event on the IPC channel - // proxy's background thread. This prevents consumers of - // MetroViewerProcessHost from having to pump messages on their own message - // loop. - class InternalMessageFilter : public IPC::MessageFilter { - public: - InternalMessageFilter(MetroViewerProcessHost* owner); - - // IPC::MessageFilter implementation. - void OnChannelConnected(int32_t peer_pid) override; - - private: - ~InternalMessageFilter() override; - - MetroViewerProcessHost* owner_; - DISALLOW_COPY_AND_ASSIGN(InternalMessageFilter); - }; - - scoped_ptr<IPC::ChannelProxy> channel_; - scoped_ptr<base::WaitableEvent> channel_connected_event_; - scoped_refptr<InternalMessageFilter> message_filter_; - - static MetroViewerProcessHost* instance_; - - // Saved callbacks which inform the caller about the result of the open file/ - // save file/select operations. - OpenFileCompletion file_open_completion_callback_; - OpenMultipleFilesCompletion multi_file_open_completion_callback_; - SaveFileCompletion file_saveas_completion_callback_; - SelectFolderCompletion select_folder_completion_callback_; - FileSelectionCanceled failure_callback_; - - DISALLOW_COPY_AND_ASSIGN(MetroViewerProcessHost); -}; - -} // namespace win8 - -#endif // WIN8_VIEWER_METRO_VIEWER_PROCESS_HOST_H_
diff --git a/win8/win8.gyp b/win8/win8.gyp index 4c68624..8131fa3 100644 --- a/win8/win8.gyp +++ b/win8/win8.gyp
@@ -10,35 +10,6 @@ ], 'targets': [ { - 'target_name': 'metro_viewer_constants', - 'type': 'static_library', - 'include_dirs': [ - '..', - ], - 'sources': [ - 'viewer/metro_viewer_constants.cc', - 'viewer/metro_viewer_constants.h', - ], - }, - { - 'target_name': 'metro_viewer', - 'type': '<(component)', - 'dependencies': [ - '../base/base.gyp:base', - '../ipc/ipc.gyp:ipc', - '../ui/aura/aura.gyp:aura', - '../ui/metro_viewer/metro_viewer.gyp:metro_viewer_messages', - 'metro_viewer_constants' - ], - 'sources': [ - 'viewer/metro_viewer_process_host.cc', - 'viewer/metro_viewer_process_host.h', - ], - 'defines': [ - 'METRO_VIEWER_IMPLEMENTATION', - ], - }, - { 'target_name': 'test_support_win8', 'type': 'static_library', 'dependencies': [