diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-06-27 11:18:24 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-07-03 09:38:30 +0000 |
commit | d94af01c90575348c4e81a418257f254b6f8d225 (patch) | |
tree | 77a26669b33eaa4d46b88b07e17dacc61eba6001 /chromium/ui | |
parent | 5d87695f37678f96492b258bbab36486c59866b4 (diff) | |
download | qtwebengine-chromium-d94af01c90575348c4e81a418257f254b6f8d225.tar.gz |
BASELINE: Update Chromium to 75.0.3770.116
Change-Id: Ifcd5227841577e8ce81a1b7a54c56caba4d85e02
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/ui')
26 files changed, 293 insertions, 250 deletions
diff --git a/chromium/ui/accessibility/ax_position.h b/chromium/ui/accessibility/ax_position.h index 10b0795a6e6..02d5824a260 100644 --- a/chromium/ui/accessibility/ax_position.h +++ b/chromium/ui/accessibility/ax_position.h @@ -639,6 +639,19 @@ class AXPosition { AXPositionInstance parent_position = CreateTextPosition( tree_id, parent_id, parent_offset, parent_affinity); + if (parent_position->IsNullPosition()) { + // Workaround: When the autofill feature populates a text field, it + // doesn't immediately update its value, which causes the text inside + // the user-agent shadow DOM to be different than the text in the text + // field itself. As a result, the parent_offset calculated above might + // appear to be temporarily invalid. + // TODO(nektar): Fix this better by ensuring that the text field's + // hypertext is always kept up to date. + parent_position = + CreateTextPosition(tree_id, parent_id, 0 /* text_offset */, + ax::mojom::TextAffinity::kDownstream); + } + // We check if the parent position has introduced ambiguity as to // whether it refers to the end of the current or the start of the next // line. We do this check by creating the parent position and testing if diff --git a/chromium/ui/base/ime/init/input_method_factory.cc b/chromium/ui/base/ime/init/input_method_factory.cc index 51d7f7ff545..15147aa7045 100644 --- a/chromium/ui/base/ime/init/input_method_factory.cc +++ b/chromium/ui/base/ime/init/input_method_factory.cc @@ -61,7 +61,7 @@ std::unique_ptr<InputMethod> CreateInputMethod( return std::make_unique<InputMethodChromeOS>(delegate); #elif defined(OS_WIN) if (base::FeatureList::IsEnabled(features::kTSFImeSupport) && - base::win::GetVersion() > base::win::VERSION_WIN7) { + base::win::GetVersion() >= base::win::VERSION_WIN10_RS2) { return std::make_unique<InputMethodWinTSF>(delegate, widget); } return std::make_unique<InputMethodWinImm32>(delegate, widget); diff --git a/chromium/ui/base/ime/win/input_method_win_tsf.cc b/chromium/ui/base/ime/win/input_method_win_tsf.cc index 5eff60756ee..972945e6b00 100644 --- a/chromium/ui/base/ime/win/input_method_win_tsf.cc +++ b/chromium/ui/base/ime/win/input_method_win_tsf.cc @@ -129,6 +129,14 @@ void InputMethodWinTSF::DetachTextInputClient(TextInputClient* client) { ui::TSFBridge::GetInstance()->RemoveFocusedClient(client); } +bool InputMethodWinTSF::IsInputLocaleCJK() const { + if (!ui::TSFBridge::GetInstance()) { + return false; + } + + return ui::TSFBridge::GetInstance()->IsInputLanguageCJK(); +} + bool InputMethodWinTSF::IsCandidatePopupOpen() const { return tsf_event_observer_->IsCandidatePopupOpen(); } diff --git a/chromium/ui/base/ime/win/input_method_win_tsf.h b/chromium/ui/base/ime/win/input_method_win_tsf.h index b04867d627b..9fcf170142b 100644 --- a/chromium/ui/base/ime/win/input_method_win_tsf.h +++ b/chromium/ui/base/ime/win/input_method_win_tsf.h @@ -33,6 +33,7 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) InputMethodWinTSF void OnCaretBoundsChanged(const TextInputClient* client) override; void CancelComposition(const TextInputClient* client) override; void DetachTextInputClient(TextInputClient* client) override; + bool IsInputLocaleCJK() const override; bool IsCandidatePopupOpen() const override; // Overridden from InputMethodBase: diff --git a/chromium/ui/base/ime/win/tsf_bridge.cc b/chromium/ui/base/ime/win/tsf_bridge.cc index fa78d5c973a..e70f1b91517 100644 --- a/chromium/ui/base/ime/win/tsf_bridge.cc +++ b/chromium/ui/base/ime/win/tsf_bridge.cc @@ -42,6 +42,7 @@ class TSFBridgeImpl : public TSFBridge { void RemoveFocusedClient(TextInputClient* client) override; void SetInputMethodDelegate(internal::InputMethodDelegate* delegate) override; void RemoveInputMethodDelegate() override; + bool IsInputLanguageCJK() override; Microsoft::WRL::ComPtr<ITfThreadMgr> GetThreadManager() override; TextInputClient* GetFocusedTextInputClient() const override; @@ -109,6 +110,10 @@ class TSFBridgeImpl : public TSFBridge { // An ITfThreadMgr object to be used in focus and document management. Microsoft::WRL::ComPtr<ITfThreadMgr> thread_manager_; + // An ITfInputProcessorProfiles object to be used to get current language + // locale profile. + Microsoft::WRL::ComPtr<ITfInputProcessorProfiles> input_processor_profiles_; + // A map from TextInputType to an editable document for TSF. We use multiple // TSF documents that have different InputScopes and TSF attributes based on // the TextInputType associated with the target document. For a TextInputType @@ -172,6 +177,13 @@ bool TSFBridgeImpl::Initialize() { return false; } + if (FAILED(::CoCreateInstance(CLSID_TF_InputProcessorProfiles, nullptr, + CLSCTX_ALL, + IID_PPV_ARGS(&input_processor_profiles_)))) { + DVLOG(1) << "Failed to create InputProcessorProfiles instance."; + return false; + } + if (FAILED(::CoCreateInstance(CLSID_TF_ThreadMgr, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&thread_manager_)))) { DVLOG(1) << "Failed to create ThreadManager instance."; @@ -332,6 +344,17 @@ void TSFBridgeImpl::RemoveInputMethodDelegate() { } } +bool TSFBridgeImpl::IsInputLanguageCJK() { + LANGID lang_locale; + if (SUCCEEDED(input_processor_profiles_->GetCurrentLanguage(&lang_locale))) { + lang_locale = PRIMARYLANGID(lang_locale); + return lang_locale == LANG_CHINESE || lang_locale == LANG_JAPANESE || + lang_locale == LANG_KOREAN; + } else { + return false; + } +} + TextInputClient* TSFBridgeImpl::GetFocusedTextInputClient() const { return client_; } @@ -429,6 +452,8 @@ bool TSFBridgeImpl::InitializeDocumentMapInternal() { tsf_document_map_[input_type].text_store = text_store; tsf_document_map_[input_type].document_manager = document_manager; tsf_document_map_[input_type].cookie = cookie; + if (text_store) + text_store->OnContextInitialized(context.Get()); } return true; } diff --git a/chromium/ui/base/ime/win/tsf_bridge.h b/chromium/ui/base/ime/win/tsf_bridge.h index 2fbc7bf5fcc..0082f521f1b 100644 --- a/chromium/ui/base/ime/win/tsf_bridge.h +++ b/chromium/ui/base/ime/win/tsf_bridge.h @@ -82,6 +82,9 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFBridge { // Remove InputMethodDelegate instance from TSFTextStore when not in focus. virtual void RemoveInputMethodDelegate() = 0; + // Returns whether the system's input language is CJK. + virtual bool IsInputLanguageCJK() = 0; + // Obtains current thread manager. virtual Microsoft::WRL::ComPtr<ITfThreadMgr> GetThreadManager() = 0; diff --git a/chromium/ui/base/ime/win/tsf_text_store.cc b/chromium/ui/base/ime/win/tsf_text_store.cc index 5e846168ab2..b82b3e2e93c 100644 --- a/chromium/ui/base/ime/win/tsf_text_store.cc +++ b/chromium/ui/base/ime/win/tsf_text_store.cc @@ -849,6 +849,7 @@ STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context, if (SUCCEEDED( context_composition->EnumCompositions(&enum_composition_view))) { Microsoft::WRL::ComPtr<ITfCompositionView> composition_view; + bool has_composition = false; if (enum_composition_view->Next(1, &composition_view, nullptr) == S_OK) { Microsoft::WRL::ComPtr<ITfRange> range; if (SUCCEEDED(composition_view->GetRange(&range))) { @@ -857,14 +858,21 @@ STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context, LONG start = 0; LONG length = 0; if (SUCCEEDED(range_acp->GetExtent(&start, &length))) { - composition_start_ = start; - has_composition_range_ = true; - composition_range_.set_start(start); - composition_range_.set_end(start + length); + // We should only consider it as a valid composition if the + // composition range is not collapsed (length > 0). + if (length > 0) { + has_composition = true; + composition_start_ = start; + has_composition_range_ = true; + composition_range_.set_start(start); + composition_range_.set_end(start + length); + } } } } - } else { + } + + if (!has_composition) { composition_start_ = selection_.start(); if (has_composition_range_) { has_composition_range_ = false; @@ -986,6 +994,19 @@ bool TSFTextStore::GetCompositionStatus( return true; } +bool TSFTextStore::TerminateComposition() { + if (context_ && has_composition_range_) { + Microsoft::WRL::ComPtr<ITfContextOwnerCompositionServices> service; + + if (SUCCEEDED(context_->QueryInterface(IID_PPV_ARGS(&service)))) { + service->TerminateComposition(nullptr); + return true; + } + } + + return false; +} + void TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded() { if (!text_input_client_) return; @@ -1094,6 +1115,10 @@ void TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded() { } } +void TSFTextStore::OnContextInitialized(ITfContext* context) { + context_ = context; +} + void TSFTextStore::SetFocusedTextInputClient( HWND focused_window, TextInputClient* text_input_client) { @@ -1119,39 +1144,17 @@ void TSFTextStore::RemoveInputMethodDelegate() { } bool TSFTextStore::CancelComposition() { - // If there is an on-going document lock, we must not edit the text. - if (edit_flag_) - return false; - - if (string_pending_insertion_.empty()) - return true; - - // Unlike ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0) in IMM32, TSF does - // not have a dedicated method to cancel composition. However, CUAS actually - // has a protocol conversion from CPS_CANCEL into TSF operations. According - // to the observations on Windows 7, TIPs are expected to cancel composition - // when an on-going composition text is replaced with an empty string. So - // we use the same operation to cancel composition here to minimize the risk - // of potential compatibility issues. - - previous_composition_string_.clear(); - previous_composition_start_ = 0; - previous_composition_selection_range_ = gfx::Range::InvalidRange(); - const size_t previous_buffer_size = string_buffer_document_.size(); - string_pending_insertion_.clear(); - composition_start_ = selection_.start(); - if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) - text_store_acp_sink_->OnSelectionChange(); - if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) - text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); - if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { - TS_TEXTCHANGE textChange = {}; - textChange.acpStart = 0; - textChange.acpOldEnd = previous_buffer_size; - textChange.acpNewEnd = 0; - text_store_acp_sink_->OnTextChange(0, &textChange); - } - return true; + // This method should correspond to + // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0) + // in IMM32 hence calling falling back to |ConfirmComposition()| is not + // technically correct, because |ConfirmComposition()| corresponds to + // |CPS_COMPLETE| rather than |CPS_CANCEL|. + // However in Chromium it seems that |InputMethod::CancelComposition()| + // might have already committed composing text despite its name. + // TODO(IME): Check other platforms to see if |CancelComposition()| is + // actually working or not. + + return ConfirmComposition(); } bool TSFTextStore::ConfirmComposition() { @@ -1165,28 +1168,13 @@ bool TSFTextStore::ConfirmComposition() { if (!text_input_client_) return false; - // See the comment in TSFTextStore::CancelComposition. - // This logic is based on the observation about how to emulate - // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_COMPLETE, 0) by CUAS. - previous_composition_string_.clear(); previous_composition_start_ = 0; previous_composition_selection_range_ = gfx::Range::InvalidRange(); - const size_t previous_buffer_size = string_buffer_document_.size(); string_pending_insertion_.clear(); - composition_start_ = selection_.start(); - if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE) - text_store_acp_sink_->OnSelectionChange(); - if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE) - text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0); - if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) { - TS_TEXTCHANGE textChange = {}; - textChange.acpStart = 0; - textChange.acpOldEnd = previous_buffer_size; - textChange.acpNewEnd = 0; - text_store_acp_sink_->OnTextChange(0, &textChange); - } - return true; + composition_start_ = selection_.end(); + + return TerminateComposition(); } void TSFTextStore::SendOnLayoutChange() { diff --git a/chromium/ui/base/ime/win/tsf_text_store.h b/chromium/ui/base/ime/win/tsf_text_store.h index 2605a96a462..4eed8c08e81 100644 --- a/chromium/ui/base/ime/win/tsf_text_store.h +++ b/chromium/ui/base/ime/win/tsf_text_store.h @@ -234,6 +234,10 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore STDMETHOD(OnKeyTraceUp) (WPARAM wParam, LPARAM lParam) override; + // Called after |TSFBridgeImpl::CreateDocumentManager| to tell that the + // text-store is successfully associated with a Context. + void OnContextInitialized(ITfContext* context); + // Sets currently focused TextInputClient. void SetFocusedTextInputClient(HWND focused_window, TextInputClient* text_input_client); @@ -259,6 +263,9 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore friend class TSFTextStoreTest; friend class TSFTextStoreTestCallback; + // Terminate an active composition for this text store. + bool TerminateComposition(); + // Compare our cached text buffer and selection with the up-to-date // text buffer and selection from TextInputClient. We also update // cached text buffer and selection with the new version. Then notify @@ -413,6 +420,7 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore // attributes of the composition string. Microsoft::WRL::ComPtr<ITfCategoryMgr> category_manager_; Microsoft::WRL::ComPtr<ITfDisplayAttributeMgr> display_attribute_manager_; + Microsoft::WRL::ComPtr<ITfContext> context_; DISALLOW_COPY_AND_ASSIGN(TSFTextStore); }; diff --git a/chromium/ui/gl/gl_surface_egl.cc b/chromium/ui/gl/gl_surface_egl.cc index 3322a274fdd..c73f28ae479 100644 --- a/chromium/ui/gl/gl_surface_egl.cc +++ b/chromium/ui/gl/gl_surface_egl.cc @@ -1475,6 +1475,15 @@ bool NativeViewGLSurfaceEGL::GetFrameTimestampInfoIfAvailable( // reporting purpose. std::vector<EGLnsecsANDROID> egl_timestamps(supported_egl_timestamps_.size(), EGL_TIMESTAMP_INVALID_ANDROID); + + // TODO(vikassoni): File a driver bug for eglGetFrameTimestampsANDROID(). + // See https://bugs.chromium.org/p/chromium/issues/detail?id=966638. + // As per the spec, the driver is expected to return a valid timestamp from + // the call eglGetFrameTimestampsANDROID() when its not + // EGL_TIMESTAMP_PENDING_ANDROID or EGL_TIMESTAMP_INVALID_ANDROID. But + // currently some buggy drivers an invalid timestamp 0. + // This is currentlt handled in chrome for by setting the presentation time to + // TimeTicks::Now() (snapped to the next vsync) instead of 0. if ((frame_id < 0) || !eglGetFrameTimestampsANDROID( GetDisplay(), surface_, frame_id, @@ -1502,7 +1511,6 @@ bool NativeViewGLSurfaceEGL::GetFrameTimestampInfoIfAvailable( base::TimeDelta::FromNanoseconds(presentation_time_ns); *presentation_flags = presentation_flags_; } - DCHECK(!presentation_time->is_null()); return true; } diff --git a/chromium/ui/gl/gl_surface_presentation_helper.cc b/chromium/ui/gl/gl_surface_presentation_helper.cc index e7bcd1a5b79..f7e6ae113b2 100644 --- a/chromium/ui/gl/gl_surface_presentation_helper.cc +++ b/chromium/ui/gl/gl_surface_presentation_helper.cc @@ -70,8 +70,24 @@ bool GLSurfacePresentationHelper::GetFrameTimestampInfoIfAvailable( DCHECK(frame.timer || frame.fence || egl_timestamp_client_); if (egl_timestamp_client_) { - return egl_timestamp_client_->GetFrameTimestampInfoIfAvailable( + bool result = egl_timestamp_client_->GetFrameTimestampInfoIfAvailable( timestamp, interval, flags, frame.frame_id); + + // Workaround null timestamp by setting it to TimeTicks::Now() snapped to + // the next vsync interval. See + // https://bugs.chromium.org/p/chromium/issues/detail?id=966638 for more + // details. + if (result && timestamp->is_null()) { + *timestamp = base::TimeTicks::Now(); + *interval = vsync_interval_; + *flags = 0; + if (!vsync_interval_.is_zero()) { + *timestamp = + timestamp->SnappedToNextTick(vsync_timebase_, vsync_interval_); + *flags = gfx::PresentationFeedback::kVSync; + } + } + return result; } else if (frame.timer) { if (!frame.timer->IsAvailable()) return false; diff --git a/chromium/ui/message_center/views/message_popup_view.cc b/chromium/ui/message_center/views/message_popup_view.cc index dc37ecaee14..a4e333c54c4 100644 --- a/chromium/ui/message_center/views/message_popup_view.cc +++ b/chromium/ui/message_center/views/message_popup_view.cc @@ -113,11 +113,11 @@ void MessagePopupView::AutoCollapse() { void MessagePopupView::Show() { views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); + params.keep_on_top = true; +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) // Make the widget explicitly activatable as TYPE_POPUP is not activatable by // default but we need focus for the inline reply textarea. params.activatable = views::Widget::InitParams::ACTIVATABLE_YES; - params.keep_on_top = true; -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) params.opacity = views::Widget::InitParams::OPAQUE_WINDOW; #else params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; diff --git a/chromium/ui/message_center/views/notification_view_md.cc b/chromium/ui/message_center/views/notification_view_md.cc index a81e70dd50e..5349bc34e5b 100644 --- a/chromium/ui/message_center/views/notification_view_md.cc +++ b/chromium/ui/message_center/views/notification_view_md.cc @@ -715,7 +715,12 @@ void NotificationViewMD::ButtonPressed(views::Button* sender, if (sender == header_row_) { if (IsExpandable() && content_row_->visible()) { SetManuallyExpandedOrCollapsed(true); + auto weak_ptr = weak_ptr_factory_.GetWeakPtr(); ToggleExpanded(); + // Check |this| is valid before continuing, because ToggleExpanded() might + // cause |this| to be deleted. + if (!weak_ptr) + return; Layout(); SchedulePaint(); } @@ -1216,6 +1221,8 @@ void NotificationViewMD::UpdateViewForExpandedState(bool expanded) { } void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) { + if (!settings_row_) + return; bool inline_settings_visible = !settings_row_->visible(); bool disable_notification = settings_row_->visible() && block_all_button_->checked(); @@ -1229,7 +1236,16 @@ void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) { dont_block_button_->SetChecked(true); SetSettingMode(inline_settings_visible); - SetExpanded(!inline_settings_visible); + + // Grab a weak pointer before calling SetExpanded() as it might cause |this| + // to be deleted. + { + auto weak_ptr = weak_ptr_factory_.GetWeakPtr(); + SetExpanded(!inline_settings_visible); + if (!weak_ptr) + return; + } + PreferredSizeChanged(); if (inline_settings_visible) diff --git a/chromium/ui/message_center/views/notification_view_md.h b/chromium/ui/message_center/views/notification_view_md.h index cc16a88d3b6..ef732236360 100644 --- a/chromium/ui/message_center/views/notification_view_md.h +++ b/chromium/ui/message_center/views/notification_view_md.h @@ -325,6 +325,8 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD base::TimeTicks last_mouse_pressed_timestamp_; + base::WeakPtrFactory<NotificationViewMD> weak_ptr_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(NotificationViewMD); }; diff --git a/chromium/ui/message_center/views/notification_view_md_unittest.cc b/chromium/ui/message_center/views/notification_view_md_unittest.cc index 248c85270b9..37baaff9219 100644 --- a/chromium/ui/message_center/views/notification_view_md_unittest.cc +++ b/chromium/ui/message_center/views/notification_view_md_unittest.cc @@ -139,6 +139,11 @@ class NotificationViewMDTest void InkDropAnimationStarted() override; void InkDropRippleAnimationEnded(views::InkDropState ink_drop_state) override; + void set_delete_on_preferred_size_changed( + bool delete_on_preferred_size_changed) { + delete_on_preferred_size_changed_ = delete_on_preferred_size_changed; + } + void set_delete_on_notification_removed(bool delete_on_notification_removed) { delete_on_notification_removed_ = delete_on_notification_removed; } @@ -165,6 +170,7 @@ class NotificationViewMDTest views::View* GetCloseButton(); bool ink_drop_stopped_ = false; + bool delete_on_preferred_size_changed_ = false; bool delete_on_notification_removed_ = false; std::set<std::string> removed_ids_; scoped_refptr<NotificationTestDelegate> delegate_; @@ -211,7 +217,8 @@ void NotificationViewMDTest::SetUp() { void NotificationViewMDTest::TearDown() { MessageCenter::Get()->RemoveObserver(this); - DCHECK(notification_view_ || delete_on_notification_removed_); + DCHECK(notification_view_ || delete_on_preferred_size_changed_ || + delete_on_notification_removed_); if (notification_view_) { notification_view_->SetInkDropMode(MessageView::InkDropMode::OFF); notification_view_->RemoveObserver(this); @@ -225,6 +232,11 @@ void NotificationViewMDTest::TearDown() { void NotificationViewMDTest::OnViewPreferredSizeChanged( views::View* observed_view) { EXPECT_EQ(observed_view, notification_view()); + if (delete_on_preferred_size_changed_) { + widget()->CloseNow(); + notification_view_.reset(); + return; + } widget()->SetSize(notification_view()->GetPreferredSize()); } @@ -1198,6 +1210,23 @@ TEST_F(NotificationViewMDTest, TestClickExpanded) { EXPECT_TRUE(delegate_->clicked()); } +TEST_F(NotificationViewMDTest, TestDeleteOnToggleExpanded) { + std::unique_ptr<Notification> notification = CreateSimpleNotification(); + notification->set_type(NotificationType::NOTIFICATION_TYPE_SIMPLE); + notification->set_title(base::string16()); + notification->set_message(base::ASCIIToUTF16( + "consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore " + "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud " + "exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.")); + UpdateNotificationViews(*notification); + EXPECT_FALSE(notification_view()->expanded_); + + // The view can be deleted by PreferredSizeChanged(). https://crbug.com/918933 + set_delete_on_preferred_size_changed(true); + notification_view()->ButtonPressed(notification_view()->header_row_, + DummyEvent()); +} + TEST_F(NotificationViewMDTest, TestDeleteOnDisableNotification) { std::unique_ptr<Notification> notification = CreateSimpleNotification(); notification->set_type(NOTIFICATION_TYPE_SIMPLE); diff --git a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb index 86f757e9ce2..359508adff5 100644 --- a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb +++ b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb @@ -57,7 +57,7 @@ <translation id="2583543531130364912">Calibrar a touchscreen</translation> <translation id="2666092431469916601">Parte superior</translation> <translation id="2701330563083355633">Compartilhada por <ph name="DEVICE_NAME" /></translation> -<translation id="2743387203779672305">Copiar para a área de trabalho</translation> +<translation id="2743387203779672305">Copiar para área de transferência</translation> <translation id="2803313416453193357">Abrir pasta</translation> <translation id="2824719307700604149">{YEARS,plural, =1{1 ano atrás}one{# ano atrás}other{# anos atrás}}</translation> <translation id="2907671656515444832">{DAYS,plural, =1{em 1 d}one{em # d}other{em # d}}</translation> @@ -205,7 +205,7 @@ <translation id="8772073294905169192">{HOURS,plural, =1{1 h}one{# h}other{# h}}</translation> <translation id="8798099450830957504">Padrão</translation> <translation id="8806053966018712535">Pasta <ph name="FOLDER_NAME" /></translation> -<translation id="883911313571074303">Fazer anotações na imagem</translation> +<translation id="883911313571074303">Nota na imagem</translation> <translation id="8841375032071747811">Botão "Voltar"</translation> <translation id="8876215549894133151">Formato:</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_ta.xtb b/chromium/ui/strings/translations/ui_strings_ta.xtb index 7635aa901dd..40df691828e 100644 --- a/chromium/ui/strings/translations/ui_strings_ta.xtb +++ b/chromium/ui/strings/translations/ui_strings_ta.xtb @@ -72,7 +72,7 @@ <translation id="3234408098842461169">கீழ்நோக்கிய அம்பு</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 நாள்}other{# நாட்கள்}}</translation> <translation id="335581015389089642">பேச்சு</translation> -<translation id="3443810440409579745">பகிர்ந்த தாவல் பெறப்பட்டது.</translation> +<translation id="3443810440409579745">தாவல் பகிரப்பட்டுள்ளது.</translation> <translation id="3479552764303398839">இப்பொழுது இல்லை</translation> <translation id="348799646910989694">ஷெல்ஃப் தானாகவே மறைக்கப்படும்</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 நாள் உள்ளது}other{# நாட்கள் உள்ளன}}</translation> diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc index fb8e820175a..443003518ef 100644 --- a/chromium/ui/views/win/hwnd_message_handler.cc +++ b/chromium/ui/views/win/hwnd_message_handler.cc @@ -3023,15 +3023,17 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypeTouch(UINT message, event.latency()->AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, event_time, 1); - if (event_type == ui::ET_TOUCH_RELEASED) - id_generator_.ReleaseNumber(pointer_id); - // There are cases where the code handling the message destroys the // window, so use the weak ptr to check if destruction occurred or not. base::WeakPtr<HWNDMessageHandler> ref(msg_handler_weak_factory_.GetWeakPtr()); delegate_->HandleTouchEvent(&event); if (ref) { + // Release the pointer id only when |HWNDMessageHandler| and |id_generator_| + // are not destroyed. + if (event_type == ui::ET_TOUCH_RELEASED) + id_generator_.ReleaseNumber(pointer_id); + // Mark touch released events handled. These will usually turn into tap // gestures, and doing this avoids propagating the event to other windows. if (delegate_->GetFrameMode() == FrameMode::SYSTEM_DRAWN) { diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html index 8cce94f0cb6..78c43b68ce7 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html @@ -31,12 +31,14 @@ padding: 0 32px; } </style> - <iron-pages attr-for-selected="is" + <iron-pages id="ironPages" + attr-for-selected="is" selected="[[visiblePageName]]" selected-item="{{visiblePage_}}"> <template is="dom-if" if="[[shouldPasswordPageBeIncluded_(delegate)]]" restamp> - <password-page auth-token="{{authToken_}}" + <password-page class="ui-page" + auth-token="{{authToken_}}" forward-button-disabled="{{passwordPageForwardButtonDisabled_}}" password-field-valid="{{passwordFieldValid}}" on-user-submitted-password="onUserSubmittedPassword_"> @@ -44,17 +46,18 @@ </template> <template is="dom-if" if="[[shouldSetupSucceededPageBeIncluded_(delegate)]]" restamp> - <setup-succeeded-page></setup-succeeded-page> + <setup-succeeded-page class="ui-page"></setup-succeeded-page> </template> - <start-setup-page devices="[[devices_]]" + <start-setup-page class="ui-page" + devices="[[devices_]]" selected-device-id="{{selectedDeviceId_}}" delegate="[[delegate]]"> </start-setup-page> </iron-pages> <div class="flex"></div> - <button-bar forward-button-hidden="[[!forwardButtonText]]" - backward-button-hidden="[[!backwardButtonText]]" - cancel-button-hidden="[[!cancelButtonText]]"> + <button-bar forward-button-hidden="[[!forwardButtonTextId]]" + backward-button-hidden="[[!backwardButtonTextId]]" + cancel-button-hidden="[[!cancelButtonTextId]]"> <slot name="backward-button" slot="backward-button"></slot> <slot name="cancel-button" slot="cancel-button"></slot> <slot name="forward-button" slot="forward-button"></slot> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js index e97849f453a..8545122a83a 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js @@ -27,12 +27,12 @@ cr.define('multidevice_setup', function() { delegate: Object, /** - * Text to be shown on the forward navigation button. + * ID of loadTimeData string to be shown on the forward navigation button. * @type {string|undefined} */ - forwardButtonText: { + forwardButtonTextId: { type: String, - computed: 'getForwardButtonText_(visiblePage_)', + computed: 'getForwardButtonTextId_(visiblePage_)', notify: true, }, @@ -45,22 +45,23 @@ cr.define('multidevice_setup', function() { }, /** - * Text to be shown on the cancel button. + * ID of loadTimeData string to be shown on the cancel button. * @type {string|undefined} */ - cancelButtonText: { + cancelButtonTextId: { type: String, - computed: 'getCancelButtonText_(visiblePage_)', + computed: 'getCancelButtonTextId_(visiblePage_)', notify: true, }, /** - * Text to be shown on the backward navigation button. + * ID of loadTimeData string to be shown on the backward navigation + * button. * @type {string|undefined} */ - backwardButtonText: { + backwardButtonTextId: { type: String, - computed: 'getBackwardButtonText_(visiblePage_)', + computed: 'getBackwardButtonTextId_(visiblePage_)', notify: true, }, @@ -142,6 +143,11 @@ cr.define('multidevice_setup', function() { this.initializeSetupFlow.bind(this)); }, + updateLocalizedContent: function() { + this.$.ironPages.querySelectorAll('.ui-page') + .forEach(page => page.i18nUpdateLocale()); + }, + initializeSetupFlow: function() { this.mojoInterfaceProvider_.getMojoServiceProxy() .getEligibleHostDevices() @@ -240,15 +246,16 @@ cr.define('multidevice_setup', function() { }, /** - * @return {string|undefined} The forward button text, which is undefined - * if no button should be displayed. + * @return {string|undefined} The ID of loadTimeData string for the + * forward button text, which is undefined if no button should be + * displayed. * @private */ - getForwardButtonText_: function() { + getForwardButtonTextId_: function() { if (!this.visiblePage_) { return undefined; } - return this.visiblePage_.forwardButtonText; + return this.visiblePage_.forwardButtonTextId; }, /** @@ -261,27 +268,29 @@ cr.define('multidevice_setup', function() { }, /** - * @return {string|undefined} The cancel button text, which is undefined - * if no button should be displayed. + * @return {string|undefined} The ID of loadTimeData string for the + * cancel button text, which is undefined if no button should be + * displayed. * @private */ - getCancelButtonText_: function() { + getCancelButtonTextId_: function() { if (!this.visiblePage_) { return undefined; } - return this.visiblePage_.cancelButtonText; + return this.visiblePage_.cancelButtonTextId; }, /** - * @return {string|undefined} The backward button text, which is undefined - * if no button should be displayed. + * @return {string|undefined} The ID of loadTimeData string for the + * backward button text, which is undefined if no button should be + * displayed. * @private */ - getBackwardButtonText_: function() { + getBackwardButtonTextId_: function() { if (!this.visiblePage_) { return undefined; } - return this.visiblePage_.backwardButtonText; + return this.visiblePage_.backwardButtonTextId; }, /** diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html index b5c52c0f573..a12f238a09f 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html @@ -18,7 +18,7 @@ #profile-photo { border-radius: 50%; height: 20px; - margin-right: 8px; + margin-inline-end: 8px; width: 20px; } @@ -28,16 +28,17 @@ width: 560px; } </style> - <ui-page header-text="[[headerText]]" icon-name="google-g"> + <ui-page header-text="[[i18nDynamic(locale, 'passwordPageHeader')]]" + icon-name="google-g"> <div id="content-container" slot="additional-content"> <div id="user-info-container"> <img id="profile-photo" src="[[profilePhotoUrl_]]"></img> <span id="email">[[email_]]</span> </div> <cr-input id="passwordInput" type="password" - placeholder="[[i18n('enterPassword')]]" + placeholder="[[i18nDynamic(locale, 'enterPassword')]]" invalid="[[passwordInvalid_]]" - error-message="[[i18n('wrongPassword')]]" + error-message="[[i18nDynamic(locale, 'wrongPassword')]]" value="{{inputValue_}}" aria-disabled="false" on-keypress="onInputKeypress_" diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.js index 80b4f756870..8f73387796a 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.js @@ -41,12 +41,6 @@ Polymer({ value: 'back', }, - /** Overridden from UiPageContainerBehavior. */ - headerId: { - type: String, - value: 'passwordPageHeader', - }, - /** * Authentication token; retrieved using the quickUnlockPrivate API. * @type {string} diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html index a899610a5d0..0606e528b0c 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html @@ -23,8 +23,9 @@ width: 416px; } </style> - <ui-page header-text="[[headerText]]" icon-name="google-g"> - <span slot="message" inner-h-t-m-l="[[messageHtml]]"></span> + <ui-page header-text="[[i18nDynamic(locale, 'setupSucceededPageHeader')]]" + icon-name="google-g"> + <span slot="message" inner-h-t-m-l="[[getMessageHtml_()]]"></span> <div id="page-icon-container" slot="additional-content"> <div id="page-icon"></div> </div> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.js index e9c4eac1bc1..a679e6d30e4 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.js @@ -13,23 +13,9 @@ Polymer({ type: String, value: 'done', }, - - /** Overridden from UiPageContainerBehavior. */ - headerId: { - type: String, - value: 'setupSucceededPageHeader', - }, - - /** Overridden from UiPageContainerBehavior. */ - messageId: { - type: String, - value: 'setupSucceededPageMessage', - }, }, - behaviors: [ - UiPageContainerBehavior, - ], + behaviors: [UiPageContainerBehavior], /** @private {?multidevice_setup.BrowserProxy} */ browserProxy_: null, @@ -50,9 +36,17 @@ Polymer({ this.fire('setup-exited'); }, + /** @private */ + getMessageHtml_: function() { + const validNodeFn = (node, value) => node.tagName == 'A'; + return this.i18nAdvanced( + 'setupSucceededPageMessage', + {attrs: {'id': validNodeFn, 'href': validNodeFn}}); + }, + /** @override */ ready: function() { - let linkElement = this.$$('#settings-link'); + const linkElement = this.$$('#settings-link'); linkElement.setAttribute('href', '#'); linkElement.addEventListener('click', () => this.onSettingsLinkClicked_()); }, diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html index a410816bbf7..be220226a6a 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html @@ -5,7 +5,6 @@ <link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/ui_page.html"> <link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html"> <link rel="import" href="chrome://resources/html/cr.html"> -<link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> @@ -47,8 +46,8 @@ #feature-details-container { @apply --layout-vertical; @apply --layout-center-justified; - border-left: 1px solid rgb(218, 220, 224); - padding-left: 24px; + border-inline-start: 1px solid rgb(218, 220, 224); + padding-inline-start: 24px; } #feature-details-container-header { @@ -70,17 +69,24 @@ } .feature-detail span { - margin-left: 8px; + margin-inline-start: 8px; } #footnote { color: var(--paper-grey-600); margin-top: 12px; } + + #multidevice-summary-message a { + display: inline-block; + } </style> - <ui-page header-text="[[headerText]]" icon-name="google-g"> - <span slot="message" id="multidevice-summary-message" inner-h-t-m-l="[[messageHtml]]"></span> + <ui-page header-text="[[i18nDynamic(locale, 'startSetupPageHeader')]]" + icon-name="google-g"> + <span slot="message" id="multidevice-summary-message" inner-h-t-m-l= + "[[i18nAdvancedDynamic_(locale, 'startSetupPageMessage')]]"> + </span> <div slot="additional-content"> <div id="selector-and-details-container"> <div id="deviceSelectionContainer" class="flex"> @@ -107,26 +113,33 @@ </div> <div id="feature-details-container" class="flex"> <div id="feature-details-container-header"> - [[i18n('startSetupPageFeatureListHeader')]] + [[i18nDynamic(locale, 'startSetupPageFeatureListHeader')]] </div> <div class="feature-detail"> <iron-icon icon="multidevice-setup-icons-20:messages"></iron-icon> <span id="awm-summary-message" inner-h-t-m-l=" - [[i18nAdvanced('startSetupPageFeatureListAwm')]]"> + [[i18nAdvancedDynamic_( + locale, 'startSetupPageFeatureListAwm')]]"> </span> </div> <div class="feature-detail"> <iron-icon icon="multidevice-setup-icons-20:downloads"> </iron-icon> - <span>[[i18n('startSetupPageFeatureListInstallApps')]]</span> + <span> + [[i18nDynamic(locale, 'startSetupPageFeatureListInstallApps')]] + </span> </div> <div class="feature-detail"> <iron-icon icon="multidevice-setup-icons-20:features"></iron-icon> - <span>[[i18n('startSetupPageFeatureListAddFeatures')]]</span> + <span> + [[i18nDynamic(locale, 'startSetupPageFeatureListAddFeatures')]] + </span> </div> </div> </div> - <div id="footnote">[[i18n('startSetupPageFootnote')]]</div> + <div id="footnote"> + [[i18nAdvancedDynamic_(locale, 'startSetupPageFootnote')]] + </div> </div> </ui-page> </template> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js index f5445d942e0..b85f3724ecc 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js @@ -18,18 +18,6 @@ Polymer({ computed: 'getCancelButtonTextId_(delegate)', }, - /** Overridden from UiPageContainerBehavior. */ - headerId: { - type: String, - value: 'startSetupPageHeader', - }, - - /** Overridden from UiPageContainerBehavior. */ - messageId: { - type: String, - value: 'startSetupPageMessage', - }, - /** * Array of objects representing all potential MultiDevice hosts. * @@ -63,7 +51,6 @@ Polymer({ behaviors: [ UiPageContainerBehavior, - I18nBehavior, WebUIListenerBehavior, ], @@ -79,7 +66,7 @@ Polymer({ // The "Learn More" links are inside a grdp string, so we cannot actually // add an onclick handler directly to the html. Instead, grab the two and // manaully add onclick handlers. - let helpArticleLinks = [ + const helpArticleLinks = [ this.$$('#multidevice-summary-message a'), this.$$('#awm-summary-message a') ]; @@ -153,4 +140,17 @@ Polymer({ onDeviceDropdownSelectionChanged_: function() { this.selectedDeviceId = this.$.deviceDropdown.value; }, + + /** + * Wrapper for i18nAdvanced for binding to location updates in OOBE. + * @param {string} locale The language code (e.g. en, es) for the current + * display language for CrOS. As with I18nBehavior.i18nDynamic(), the + * parameter is not used directly but is provided to allow HTML binding + * without passing an unexpected argument to I18nBehavior.i18nAdvanced(). + * @param {string} textId The loadTimeData ID of the string to be translated. + * @private + */ + i18nAdvancedDynamic_: function(locale, textId) { + return this.i18nAdvanced(textId); + }, }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js index cb31b5170dc..35a578ca0e4 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js @@ -6,102 +6,28 @@ const UiPageContainerBehaviorImpl = { properties: { /** - * ID for forward button label, which must be translated for display. - * - * Undefined if the visible page has no forward-navigation button. - * + * ID of loadTimeData string for forward button label, which must be + * translated for display. Undefined if the visible page has no + * forward-navigation button. * @type {string|undefined} */ forwardButtonTextId: String, /** - * ID for cancel button label, which must be translated for display. - * - * Undefined if the visible page has no cancel button. - * + * ID of loadTimeData string for cancel button label, which must be + * translated for display. Undefined if the visible page has no + * cancel button. * @type {string|undefined} */ cancelButtonTextId: String, /** - * ID for backward button label, which must be translated for display. - * - * Undefined if the visible page has no backward-navigation button. - * + * ID of loadTimeData string for backward button label, which must be + * translated for display. Undefined if the visible page has no + * backward-navigation button. * @type {string|undefined} */ backwardButtonTextId: String, - - /** - * ID for text of main UI Page heading. - * - * @type {string} - */ - headerId: String, - - /** - * ID for text of main UI Page message body. - * - * @type {string} - */ - messageId: String, - - /** - * Translated text to display on the forward-naviation button. - * - * Undefined if the visible page has no forward-navigation button. - * - * @type {string|undefined} - */ - forwardButtonText: { - type: String, - computed: 'computeLocalizedText_(forwardButtonTextId)', - }, - - /** - * Translated text to display on the cancel button. - * - * Undefined if the visible page has no cancel button. - * - * @type {string|undefined} - */ - cancelButtonText: { - type: String, - computed: 'computeLocalizedText_(cancelButtonTextId)', - }, - - /** - * Translated text to display on the backward-naviation button. - * - * Undefined if the visible page has no backward-navigation button. - * - * @type {string|undefined} - */ - backwardButtonText: { - type: String, - computed: 'computeLocalizedText_(backwardButtonTextId)', - }, - - /** - * Translated text of main UI Page heading. - * - * @type {string|undefined} - */ - headerText: { - type: String, - computed: 'computeLocalizedText_(headerId)', - }, - - /** - * Translated text of main UI Page heading. In general this can include - * some markup. - * - * @type {string|undefined} - */ - messageHtml: { - type: String, - computed: 'computeLocalizedText_(messageId)', - }, }, /** @@ -116,23 +42,6 @@ const UiPageContainerBehaviorImpl = { resolve(true /* canNavigate */); }); }, - - /** - * @param {string} textId Key for the localized string to appear on a - * button. - * @return {string|undefined} The localized string corresponding to the key - * textId. Return value is undefined if textId is not a key - * for any localized string. Note: this includes the case in which - * textId is undefined. - * @private - */ - computeLocalizedText_: function(textId) { - if (!this.i18nExists(textId)) { - return; - } - - return loadTimeData.getString(textId); - }, }; /** @polymerBehavior */ |